diff --git a/Archive/Examples/IfNormalization/WithoutAesop.lean b/Archive/Examples/IfNormalization/WithoutAesop.lean index 79cda7b878191..d497e0d6f32ac 100644 --- a/Archive/Examples/IfNormalization/WithoutAesop.lean +++ b/Archive/Examples/IfNormalization/WithoutAesop.lean @@ -92,21 +92,21 @@ def normalize' (l : AList (fun _ : ℕ => Bool)) : · simp_all · have := ht₃ v have := he₃ v - simp_all? says simp_all only [Option.elim, ne_eq, normalized, Bool.and_eq_true, + simp_all? says simp_all only [Option.elim, normalized, Bool.and_eq_true, Bool.not_eq_true', AList.lookup_insert, imp_false] obtain ⟨⟨⟨tn, tc⟩, tr⟩, td⟩ := ht₂ split <;> rename_i h' · subst h' simp_all - · simp_all? says simp_all only [ne_eq, hasNestedIf, Bool.or_self, hasConstantIf, - and_self, hasRedundantIf, Bool.or_false, beq_eq_false_iff_ne, not_false_eq_true, + · simp_all? says simp_all only [hasNestedIf, Bool.or_self, hasConstantIf, and_self, + hasRedundantIf, Bool.or_false, beq_eq_false_iff_ne, ne_eq, not_false_eq_true, disjoint, List.disjoint, decide_True, Bool.and_self] · have := ht₃ w have := he₃ w by_cases h : w = v · subst h; simp_all - · simp_all? says simp_all only [Option.elim, ne_eq, normalized, Bool.and_eq_true, - Bool.not_eq_true', not_false_eq_true, AList.lookup_insert_ne] + · simp_all? says simp_all only [Option.elim, normalized, Bool.and_eq_true, + Bool.not_eq_true', ne_eq, not_false_eq_true, AList.lookup_insert_ne] obtain ⟨⟨⟨en, ec⟩, er⟩, ed⟩ := he₂ split at b <;> rename_i h' · subst h'; simp_all diff --git a/Archive/Wiedijk100Theorems/BallotProblem.lean b/Archive/Wiedijk100Theorems/BallotProblem.lean index f7a5a95024821..c4a2464181f5b 100644 --- a/Archive/Wiedijk100Theorems/BallotProblem.lean +++ b/Archive/Wiedijk100Theorems/BallotProblem.lean @@ -72,6 +72,7 @@ def countedSequence (p q : ℕ) : Set (List ℤ) := {l | l.count 1 = p ∧ l.count (-1) = q ∧ ∀ x ∈ l, x = (1 : ℤ) ∨ x = -1} #align ballot.counted_sequence Ballot.countedSequence +open scoped List in /-- An alternative definition of `countedSequence` that uses `List.Perm`. -/ theorem mem_countedSequence_iff_perm {p q l} : l ∈ countedSequence p q ↔ l ~ List.replicate p (1 : ℤ) ++ List.replicate q (-1) := by diff --git a/Archive/Wiedijk100Theorems/Partition.lean b/Archive/Wiedijk100Theorems/Partition.lean index 86d7b199ac1b5..a5fade0004020 100644 --- a/Archive/Wiedijk100Theorems/Partition.lean +++ b/Archive/Wiedijk100Theorems/Partition.lean @@ -384,19 +384,11 @@ theorem partialOddGF_prop [Field α] (n m : ℕ) : α) = coeff α n (partialOddGF m) := by rw [partialOddGF] - -- Porting note: `convert` timeouts. Please revert to `convert` when the performance of `convert` - -- is improved. - refine Eq.trans ?_ - (Eq.trans (partialGF_prop α n ((range m).map mkOdd) ?_ (fun _ => Set.univ) fun _ _ => trivial) - (Eq.symm ?_)) + convert partialGF_prop α n + ((range m).map mkOdd) _ (fun _ => Set.univ) (fun _ _ => trivial) using 2 · congr simp only [true_and_iff, forall_const, Set.mem_univ] - · intro i - rw [mem_map] - rintro ⟨a, -, rfl⟩ - exact Nat.succ_pos _ - · congr 1 - rw [Finset.prod_map] + · rw [Finset.prod_map] simp_rw [num_series'] congr! 2 with x ext k @@ -406,6 +398,10 @@ theorem partialOddGF_prop [Field α] (n m : ℕ) : apply mul_comm rintro ⟨a_w, -, rfl⟩ apply Dvd.intro_left a_w rfl + · intro i + rw [mem_map] + rintro ⟨a, -, rfl⟩ + exact Nat.succ_pos _ #align theorems_100.partial_odd_gf_prop Theorems100.partialOddGF_prop /-- If m is big enough, the partial product's coefficient counts the number of odd partitions -/ @@ -438,23 +434,20 @@ theorem partialDistinctGF_prop [CommSemiring α] (n m : ℕ) : α) = coeff α n (partialDistinctGF m) := by rw [partialDistinctGF] - -- Porting note: `convert` timeouts. Please revert to `convert` when the performance of `convert` - -- is improved. - refine Eq.trans ?_ - (Eq.trans (partialGF_prop α n ((range m).map ⟨Nat.succ, Nat.succ_injective⟩) ?_ - (fun _ => {0, 1}) fun _ _ => Or.inl rfl) (Eq.symm ?_)) + convert partialGF_prop α n + ((range m).map ⟨Nat.succ, Nat.succ_injective⟩) _ (fun _ => {0, 1}) (fun _ _ => Or.inl rfl) + using 2 · congr congr! with p rw [Multiset.nodup_iff_count_le_one] congr! with i rcases Multiset.count i p.parts with (_ | _ | ms) <;> simp + · simp_rw [Finset.prod_map, two_series] + congr with i + simp [Set.image_pair] · simp only [mem_map, Function.Embedding.coeFn_mk] rintro i ⟨_, _, rfl⟩ apply Nat.succ_pos - · congr 1 - simp_rw [Finset.prod_map, two_series] - congr with i - simp [Set.image_pair] #align theorems_100.partial_distinct_gf_prop Theorems100.partialDistinctGF_prop /-- If m is big enough, the partial product's coefficient counts the number of distinct partitions diff --git a/Cache/IO.lean b/Cache/IO.lean index ecd7a54a5f443..d93c88eb09d46 100644 --- a/Cache/IO.lean +++ b/Cache/IO.lean @@ -70,7 +70,7 @@ def CURLBIN := /-- leantar version at https://github.com/digama0/leangz -/ def LEANTARVERSION := - "0.1.9" + "0.1.10" def EXE := if System.Platform.isWindows then ".exe" else "" @@ -361,4 +361,16 @@ def cleanCache (keep : Lean.RBTree FilePath compare := default) : IO Unit := do for path in ← getFilesWithExtension CACHEDIR "ltar" do if !keep.contains path then IO.FS.removeFile path +/-- Prints the LTAR file and embedded comments (in particular, the mathlib commit that built the +file) regarding the files with specified paths. -/ +def lookup (hashMap : HashMap) (paths : List FilePath) : IO Unit := do + let mut err := false + for path in paths do + let some hash := hashMap.find? path | err := true + let ltar := CACHEDIR / hash.asLTar + IO.println s!"{path}: {ltar}" + for line in (← runCmd (← getLeanTar) #["-k", ltar.toString]).splitOn "\n" |>.dropLast do + println! " comment: {line}" + if err then IO.Process.exit 1 + end Cache.IO diff --git a/Cache/Main.lean b/Cache/Main.lean index 810c1a00127c9..92d7fa943bbe6 100644 --- a/Cache/Main.lean +++ b/Cache/Main.lean @@ -20,6 +20,7 @@ Commands: unpack! Decompress linked already downloaded files (no skipping) clean Delete non-linked files clean! Delete everything on the local cache + lookup Show information about cache files for the given lean files # Privilege required put Run 'mk' then upload linked files missing on the server @@ -59,7 +60,7 @@ def curlArgs : List String := ["get", "get!", "get-", "put", "put!", "commit", "commit!"] def leanTarArgs : List String := - ["get", "get!", "pack", "pack!", "unpack"] + ["get", "get!", "pack", "pack!", "unpack", "lookup"] open Cache IO Hashing Requests System in def main (args : List String) : IO Unit := do @@ -102,4 +103,5 @@ def main (args : List String) : IO Unit := do if !(← isGitStatusClean) then IO.println "Please commit your changes first" return else commit hashMap true (← getToken) | ["collect"] => IO.println "TODO" + | "lookup" :: args => lookup hashMap (toPaths args) | _ => println help diff --git a/Mathlib.lean b/Mathlib.lean index e269572f2aa67..a572fae282fe2 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -155,6 +155,9 @@ import Mathlib.Algebra.FreeAlgebra import Mathlib.Algebra.FreeMonoid.Basic import Mathlib.Algebra.FreeMonoid.Count import Mathlib.Algebra.FreeNonUnitalNonAssocAlgebra +import Mathlib.Algebra.Function.Finite +import Mathlib.Algebra.Function.Indicator +import Mathlib.Algebra.Function.Support import Mathlib.Algebra.GCDMonoid.Basic import Mathlib.Algebra.GCDMonoid.Div import Mathlib.Algebra.GCDMonoid.Finset @@ -267,7 +270,6 @@ import Mathlib.Algebra.Homology.ShortExact.Abelian import Mathlib.Algebra.Homology.ShortExact.Preadditive import Mathlib.Algebra.Homology.Single import Mathlib.Algebra.Homology.SingleHomology -import Mathlib.Algebra.IndicatorFunction import Mathlib.Algebra.Invertible.Basic import Mathlib.Algebra.Invertible.Defs import Mathlib.Algebra.Invertible.GroupWithZero @@ -308,6 +310,7 @@ import Mathlib.Algebra.Module.Basic import Mathlib.Algebra.Module.BigOperators import Mathlib.Algebra.Module.Bimodule import Mathlib.Algebra.Module.DedekindDomain +import Mathlib.Algebra.Module.DirectLimitAndTensorProduct import Mathlib.Algebra.Module.Equiv import Mathlib.Algebra.Module.GradedModule import Mathlib.Algebra.Module.Hom @@ -414,6 +417,7 @@ import Mathlib.Algebra.Order.Sub.Canonical import Mathlib.Algebra.Order.Sub.Defs import Mathlib.Algebra.Order.Sub.Prod import Mathlib.Algebra.Order.Sub.WithTop +import Mathlib.Algebra.Order.Support import Mathlib.Algebra.Order.ToIntervalMod import Mathlib.Algebra.Order.UpperLower import Mathlib.Algebra.Order.WithZero @@ -475,7 +479,6 @@ import Mathlib.Algebra.Star.SelfAdjoint import Mathlib.Algebra.Star.StarAlgHom import Mathlib.Algebra.Star.Subalgebra import Mathlib.Algebra.Star.Unitary -import Mathlib.Algebra.Support import Mathlib.Algebra.Symmetrized import Mathlib.Algebra.TrivSqZeroExt import Mathlib.Algebra.Tropical.Basic @@ -1328,6 +1331,7 @@ import Mathlib.Combinatorics.Quiver.Push import Mathlib.Combinatorics.Quiver.SingleObj import Mathlib.Combinatorics.Quiver.Subquiver import Mathlib.Combinatorics.Quiver.Symmetric +import Mathlib.Combinatorics.Schnirelmann import Mathlib.Combinatorics.SetFamily.CauchyDavenport import Mathlib.Combinatorics.SetFamily.Compression.Down import Mathlib.Combinatorics.SetFamily.Compression.UV @@ -1513,6 +1517,7 @@ import Mathlib.Data.Finset.Pairwise import Mathlib.Data.Finset.Pi import Mathlib.Data.Finset.PiInduction import Mathlib.Data.Finset.Pointwise +import Mathlib.Data.Finset.Pointwise.Interval import Mathlib.Data.Finset.Powerset import Mathlib.Data.Finset.Preimage import Mathlib.Data.Finset.Prod @@ -1606,6 +1611,7 @@ import Mathlib.Data.LazyList.Basic import Mathlib.Data.List.AList import Mathlib.Data.List.Basic import Mathlib.Data.List.BigOperators.Basic +import Mathlib.Data.List.BigOperators.Defs import Mathlib.Data.List.BigOperators.Lemmas import Mathlib.Data.List.Card import Mathlib.Data.List.Chain @@ -1673,6 +1679,7 @@ import Mathlib.Data.Matrix.Rank import Mathlib.Data.Matrix.Reflection import Mathlib.Data.Matrix.RowCol import Mathlib.Data.Matroid.Basic +import Mathlib.Data.Matroid.Dual import Mathlib.Data.Matroid.IndepAxioms import Mathlib.Data.Matroid.Init import Mathlib.Data.Multiset.Antidiagonal @@ -2000,7 +2007,9 @@ import Mathlib.Data.ZMod.Algebra import Mathlib.Data.ZMod.Basic import Mathlib.Data.ZMod.Coprime import Mathlib.Data.ZMod.Defs +import Mathlib.Data.ZMod.Factorial import Mathlib.Data.ZMod.IntUnitsPower +import Mathlib.Data.ZMod.Module import Mathlib.Data.ZMod.Parity import Mathlib.Data.ZMod.Quotient import Mathlib.Data.ZMod.Units @@ -2327,6 +2336,7 @@ import Mathlib.LinearAlgebra.Basis.Bilinear import Mathlib.LinearAlgebra.Basis.Flag import Mathlib.LinearAlgebra.Basis.VectorSpace import Mathlib.LinearAlgebra.BilinearForm.Basic +import Mathlib.LinearAlgebra.BilinearForm.DualLattice import Mathlib.LinearAlgebra.BilinearForm.Hom import Mathlib.LinearAlgebra.BilinearForm.Orthogonal import Mathlib.LinearAlgebra.BilinearForm.Properties @@ -2361,6 +2371,7 @@ import Mathlib.LinearAlgebra.ExteriorAlgebra.Basic import Mathlib.LinearAlgebra.ExteriorAlgebra.Grading import Mathlib.LinearAlgebra.ExteriorAlgebra.OfAlternating import Mathlib.LinearAlgebra.FiniteDimensional +import Mathlib.LinearAlgebra.FiniteSpan import Mathlib.LinearAlgebra.Finrank import Mathlib.LinearAlgebra.Finsupp import Mathlib.LinearAlgebra.FinsuppVectorSpace @@ -2450,6 +2461,7 @@ import Mathlib.LinearAlgebra.QuadraticForm.TensorProduct.Isometries import Mathlib.LinearAlgebra.Quotient import Mathlib.LinearAlgebra.QuotientPi import Mathlib.LinearAlgebra.Ray +import Mathlib.LinearAlgebra.Reflection import Mathlib.LinearAlgebra.SModEq import Mathlib.LinearAlgebra.SesquilinearForm import Mathlib.LinearAlgebra.Span @@ -2484,9 +2496,9 @@ import Mathlib.Logic.Equiv.Fin import Mathlib.Logic.Equiv.Fintype import Mathlib.Logic.Equiv.Functor import Mathlib.Logic.Equiv.List -import Mathlib.Logic.Equiv.LocalEquiv import Mathlib.Logic.Equiv.Nat import Mathlib.Logic.Equiv.Option +import Mathlib.Logic.Equiv.PartialEquiv import Mathlib.Logic.Equiv.Set import Mathlib.Logic.Equiv.TransferInstance import Mathlib.Logic.Function.Basic @@ -3580,11 +3592,10 @@ import Mathlib.Topology.Instances.RealVectorSpace import Mathlib.Topology.Instances.Sign import Mathlib.Topology.Instances.TrivSqZeroExt import Mathlib.Topology.Irreducible -import Mathlib.Topology.IsLocallyHomeomorph +import Mathlib.Topology.IsLocalHomeomorph import Mathlib.Topology.List import Mathlib.Topology.LocalAtTarget import Mathlib.Topology.LocalExtr -import Mathlib.Topology.LocalHomeomorph import Mathlib.Topology.LocallyConstant.Algebra import Mathlib.Topology.LocallyConstant.Basic import Mathlib.Topology.LocallyFinite @@ -3642,6 +3653,7 @@ import Mathlib.Topology.Order.Priestley import Mathlib.Topology.Order.ScottTopology import Mathlib.Topology.Order.UpperLowerSetTopology import Mathlib.Topology.Partial +import Mathlib.Topology.PartialHomeomorph import Mathlib.Topology.PartitionOfUnity import Mathlib.Topology.Perfect import Mathlib.Topology.ProperMap diff --git a/Mathlib/Algebra/Algebra/Spectrum.lean b/Mathlib/Algebra/Algebra/Spectrum.lean index b15d4feb0db28..28d98b217aaca 100644 --- a/Mathlib/Algebra/Algebra/Spectrum.lean +++ b/Mathlib/Algebra/Algebra/Spectrum.lean @@ -119,10 +119,17 @@ theorem zero_mem_iff {a : A} : (0 : R) ∈ σ a ↔ ¬IsUnit a := by rw [mem_iff, map_zero, zero_sub, IsUnit.neg_iff] #align spectrum.zero_mem_iff spectrum.zero_mem_iff +alias ⟨not_isUnit_of_zero_mem, zero_mem⟩ := spectrum.zero_mem_iff + theorem zero_not_mem_iff {a : A} : (0 : R) ∉ σ a ↔ IsUnit a := by rw [zero_mem_iff, Classical.not_not] #align spectrum.zero_not_mem_iff spectrum.zero_not_mem_iff +alias ⟨isUnit_of_zero_not_mem, zero_not_mem⟩ := spectrum.zero_not_mem_iff + +lemma subset_singleton_zero_compl {a : A} (ha : IsUnit a) : spectrum R a ⊆ {0}ᶜ := + Set.subset_compl_singleton_iff.mpr <| spectrum.zero_not_mem R ha + variable {R} theorem mem_resolventSet_of_left_right_inverse {r : R} {a b c : A} (h₁ : (↑ₐ r - a) * b = 1) diff --git a/Mathlib/Algebra/BigOperators/Basic.lean b/Mathlib/Algebra/BigOperators/Basic.lean index 9507b0e7a177b..7162439d9775c 100644 --- a/Mathlib/Algebra/BigOperators/Basic.lean +++ b/Mathlib/Algebra/BigOperators/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl -/ import Mathlib.Algebra.BigOperators.Multiset.Lemmas +import Mathlib.Algebra.Function.Indicator import Mathlib.Algebra.Group.Equiv.Basic import Mathlib.Algebra.Group.Pi import Mathlib.Algebra.GroupPower.Lemmas @@ -49,7 +50,7 @@ universe u v w variable {ι : Type*} {β : Type u} {α : Type v} {γ : Type w} -open Fin +open Fin Function namespace Finset @@ -769,7 +770,7 @@ theorem prod_filter_of_ne {p : α → Prop} [DecidablePred p] (hp : ∀ x ∈ s, -- If we use `[DecidableEq β]` here, some rewrites fail because they find a wrong `Decidable` -- instance first; `{∀ x, Decidable (f x ≠ 1)}` doesn't work with `rw ← prod_filter_ne_one` @[to_additive] -theorem prod_filter_ne_one [∀ x, Decidable (f x ≠ 1)] : +theorem prod_filter_ne_one (s : Finset α) [∀ x, Decidable (f x ≠ 1)] : ∏ x in s.filter fun x => f x ≠ 1, f x = ∏ x in s, f x := prod_filter_of_ne fun _ _ => id #align finset.prod_filter_ne_one Finset.prod_filter_ne_one @@ -1145,6 +1146,90 @@ theorem prod_pi_mulSingle {β : α → Type*} [DecidableEq α] [∀ a, CommMonoi prod_dite_eq _ _ _ #align finset.prod_pi_mul_single Finset.prod_pi_mulSingle +@[to_additive] +lemma mulSupport_prod (s : Finset ι) (f : ι → α → β) : + mulSupport (fun x ↦ ∏ i in s, f i x) ⊆ ⋃ i ∈ s, mulSupport (f i) := by + simp only [mulSupport_subset_iff', Set.mem_iUnion, not_exists, nmem_mulSupport] + exact fun x ↦ prod_eq_one +#align function.mul_support_prod Finset.mulSupport_prod +#align function.support_sum Finset.support_sum + +section indicator +open Set +variable {κ : Type*} + +/-- Consider a product of `g i (f i)` over a finset. Suppose `g` is a function such as +`n ↦ (· ^ n)`, which maps a second argument of `1` to `1`. Then if `f` is replaced by the +corresponding multiplicative indicator function, the finset may be replaced by a possibly larger +finset without changing the value of the product. -/ +@[to_additive "Consider a sum of `g i (f i)` over a finset. Suppose `g` is a function such as +`n ↦ (n • ·)`, which maps a second argument of `0` to `0` (or a weighted sum of `f i * h i` or +`f i • h i`, where `f` gives the weights that are multiplied by some other function `h`). Then if +`f` is replaced by the corresponding indicator function, the finset may be replaced by a possibly +larger finset without changing the value of the sum."] +lemma prod_mulIndicator_subset_of_eq_one [One α] (f : ι → α) (g : ι → α → β) {s t : Finset ι} + (h : s ⊆ t) (hg : ∀ a, g a 1 = 1) : + ∏ i in t, g i (mulIndicator ↑s f i) = ∏ i in s, g i (f i) := by + calc + _ = ∏ i in s, g i (mulIndicator ↑s f i) := by rw [prod_subset h fun i _ hn ↦ by simp [hn, hg]] + -- Porting note: This did not use to need the implicit argument + _ = _ := prod_congr rfl fun i hi ↦ congr_arg _ $ mulIndicator_of_mem (α := ι) hi f +#align set.prod_mul_indicator_subset_of_eq_one Finset.prod_mulIndicator_subset_of_eq_one +#align set.sum_indicator_subset_of_eq_zero Finset.sum_indicator_subset_of_eq_zero + +/-- Taking the product of an indicator function over a possibly larger finset is the same as +taking the original function over the original finset. -/ +@[to_additive "Summing an indicator function over a possibly larger `Finset` is the same as summing + the original function over the original finset."] +lemma prod_mulIndicator_subset (f : ι → β) {s t : Finset ι} (h : s ⊆ t) : + ∏ i in t, mulIndicator (↑s) f i = ∏ i in s, f i := + prod_mulIndicator_subset_of_eq_one _ (fun _ ↦ id) h fun _ ↦ rfl +#align set.prod_mul_indicator_subset Finset.prod_mulIndicator_subset +#align set.sum_indicator_subset Finset.sum_indicator_subset + +@[to_additive] +lemma prod_mulIndicator_eq_prod_filter (s : Finset ι) (f : ι → κ → β) (t : ι → Set κ) (g : ι → κ) + [DecidablePred fun i ↦ g i ∈ t i] : + ∏ i in s, mulIndicator (t i) (f i) (g i) = ∏ i in s.filter fun i ↦ g i ∈ t i, f i (g i) := by + refine (prod_filter_mul_prod_filter_not s (fun i ↦ g i ∈ t i) _).symm.trans $ + Eq.trans (congr_arg₂ (· * ·) ?_ ?_) (mul_one _) + · exact prod_congr rfl fun x hx ↦ mulIndicator_of_mem (mem_filter.1 hx).2 _ + · exact prod_eq_one fun x hx ↦ mulIndicator_of_not_mem (mem_filter.1 hx).2 _ +#align finset.prod_mul_indicator_eq_prod_filter Finset.prod_mulIndicator_eq_prod_filter +#align finset.sum_indicator_eq_sum_filter Finset.sum_indicator_eq_sum_filter + +@[to_additive] +lemma mulIndicator_prod (s : Finset ι) (t : Set κ) (f : ι → κ → β) : + mulIndicator t (∏ i in s, f i) = ∏ i in s, mulIndicator t (f i) := + map_prod (mulIndicatorHom _ _) _ _ +#align set.mul_indicator_finset_prod Finset.mulIndicator_prod +#align set.indicator_finset_sum Finset.indicator_sum + +variable {κ : Type*} +@[to_additive] +lemma mulIndicator_biUnion (s : Finset ι) (t : ι → Set κ) {f : κ → β} : + ((s : Set ι).PairwiseDisjoint t) → + mulIndicator (⋃ i ∈ s, t i) f = fun a ↦ ∏ i in s, mulIndicator (t i) f a := by + classical + refine Finset.induction_on s (by simp) fun i s hi ih hs ↦ funext fun j ↦ ?_ + rw [prod_insert hi, set_biUnion_insert, mulIndicator_union_of_not_mem_inter, + ih (hs.subset $ subset_insert _ _)] + simp only [not_exists, exists_prop, mem_iUnion, mem_inter_iff, not_and] + exact fun hji i' hi' hji' ↦ (ne_of_mem_of_not_mem hi' hi).symm $ + hs.elim_set (mem_insert_self _ _) (mem_insert_of_mem hi') _ hji hji' +#align set.mul_indicator_finset_bUnion Finset.mulIndicator_biUnion +#align set.indicator_finset_bUnion Finset.indicator_biUnion + +@[to_additive] +lemma mulIndicator_biUnion_apply (s : Finset ι) (t : ι → Set κ) {f : κ → β} + (h : (s : Set ι).PairwiseDisjoint t) (x : κ) : + mulIndicator (⋃ i ∈ s, t i) f x = ∏ i in s, mulIndicator (t i) f x := by + rw [mulIndicator_biUnion s t h] +#align set.mul_indicator_finset_bUnion_apply Finset.mulIndicator_biUnion_apply +#align set.indicator_finset_bUnion_apply Finset.indicator_biUnion_apply + +end indicator + @[to_additive] theorem prod_bij_ne_one {s : Finset α} {t : Finset γ} {f : α → β} {g : γ → β} (i : ∀ a ∈ s, f a ≠ 1 → γ) (hi : ∀ a h₁ h₂, i a h₁ h₂ ∈ t) @@ -1153,11 +1238,11 @@ theorem prod_bij_ne_one {s : Finset α} {t : Finset γ} {f : α → β} {g : γ ∏ x in s, f x = ∏ x in t, g x := by classical calc - ∏ x in s, f x = ∏ x in s.filter fun x => f x ≠ 1, f x := prod_filter_ne_one.symm + ∏ x in s, f x = ∏ x in s.filter fun x => f x ≠ 1, f x := by rw [prod_filter_ne_one] _ = ∏ x in t.filter fun x => g x ≠ 1, g x := prod_bij (fun a ha => i a (mem_filter.mp ha).1 $ by simpa using (mem_filter.mp ha).2) ?_ ?_ ?_ ?_ - _ = ∏ x in t, g x := prod_filter_ne_one + _ = ∏ x in t, g x := prod_filter_ne_one _ · intros a ha refine' (mem_filter.mp ha).elim _ intros h₁ h₂ @@ -1951,6 +2036,11 @@ theorem prod_boole {s : Finset α} {p : α → Prop} [DecidablePred p] : rw [if_neg hq] #align finset.prod_boole Finset.prod_boole +lemma support_prod_subset (s : Finset ι) (f : ι → α → β) : + support (fun x ↦ ∏ i in s, f i x) ⊆ ⋂ i ∈ s, support (f i) := + fun _ hx ↦ Set.mem_iInter₂.2 fun _ hi H ↦ hx $ prod_eq_zero hi H +#align function.support_prod_subset Finset.support_prod_subset + variable [Nontrivial β] [NoZeroDivisors β] theorem prod_eq_zero_iff : ∏ x in s, f x = 0 ↔ ∃ a ∈ s, f a = 0 := by @@ -1965,6 +2055,11 @@ theorem prod_ne_zero_iff : ∏ x in s, f x ≠ 0 ↔ ∀ a ∈ s, f a ≠ 0 := b push_neg; rfl #align finset.prod_ne_zero_iff Finset.prod_ne_zero_iff +lemma support_prod (s : Finset ι) (f : ι → α → β) : + support (fun x ↦ ∏ i in s, f i x) = ⋂ i ∈ s, support (f i) := + Set.ext fun x ↦ by simp [support, prod_eq_zero_iff] +#align function.support_prod Finset.support_prod + end ProdEqZero @[to_additive] diff --git a/Mathlib/Algebra/BigOperators/Finprod.lean b/Mathlib/Algebra/BigOperators/Finprod.lean index d1f416789aa34..de4c32ff727b3 100644 --- a/Mathlib/Algebra/BigOperators/Finprod.lean +++ b/Mathlib/Algebra/BigOperators/Finprod.lean @@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kexing Ying, Kevin Buzzard, Yury Kudryashov -/ import Mathlib.Algebra.BigOperators.Order -import Mathlib.Algebra.IndicatorFunction +import Mathlib.Algebra.Function.Finite +import Mathlib.Algebra.Module.Basic #align_import algebra.big_operators.finprod from "leanprover-community/mathlib"@"d6fad0e5bf2d6f48da9175d25c3dc5706b3834ce" diff --git a/Mathlib/Algebra/Category/Ring/Basic.lean b/Mathlib/Algebra/Category/Ring/Basic.lean index 0b9edc9da11c7..a2bfc229e5ca6 100644 --- a/Mathlib/Algebra/Category/Ring/Basic.lean +++ b/Mathlib/Algebra/Category/Ring/Basic.lean @@ -371,7 +371,7 @@ Ring equivalence are isomorphisms in category of commutative semirings -/ @[simps] def _root_.RingEquiv.toCommSemiRingCatIso [CommSemiring X] [CommSemiring Y] (e : X ≃+* Y) : - SemiRingCat.of X ≅ SemiRingCat.of Y where + CommSemiRingCat.of X ≅ CommSemiRingCat.of Y where hom := e.toRingHom inv := e.symm.toRingHom diff --git a/Mathlib/Algebra/CharZero/Lemmas.lean b/Mathlib/Algebra/CharZero/Lemmas.lean index f00289473dca3..f00f06e0726b4 100644 --- a/Mathlib/Algebra/CharZero/Lemmas.lean +++ b/Mathlib/Algebra/CharZero/Lemmas.lean @@ -3,8 +3,9 @@ Copyright (c) 2014 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ -import Mathlib.Data.Nat.Cast.Field +import Mathlib.Algebra.Function.Support import Mathlib.Algebra.GroupPower.Lemmas +import Mathlib.Data.Nat.Cast.Field #align_import algebra.char_zero.lemmas from "leanprover-community/mathlib"@"acee671f47b8e7972a1eb6f4eed74b4b3abce829" @@ -21,6 +22,8 @@ with `1`. * Characteristic zero implies that the additive monoid is infinite. -/ +open Function Set + namespace Nat variable {R : Type*} [AddMonoidWithOne R] [CharZero R] @@ -49,9 +52,8 @@ theorem cast_div_charZero {k : Type*} [DivisionSemiring k] [CharZero k] {m n : end Nat -section - -variable (M : Type*) [AddMonoidWithOne M] [CharZero M] +section AddMonoidWithOne +variable {α M : Type*} [AddMonoidWithOne M] [CharZero M] {n : ℕ} instance CharZero.NeZero.two : NeZero (2 : M) := ⟨by @@ -59,7 +61,18 @@ instance CharZero.NeZero.two : NeZero (2 : M) := rwa [Nat.cast_two] at this⟩ #align char_zero.ne_zero.two CharZero.NeZero.two -end +namespace Function + +lemma support_nat_cast (hn : n ≠ 0) : support (n : α → M) = univ := + support_const <| Nat.cast_ne_zero.2 hn +#align function.support_nat_cast Function.support_nat_cast + +lemma mulSupport_nat_cast (hn : n ≠ 1) : mulSupport (n : α → M) = univ := + mulSupport_const <| Nat.cast_ne_one.2 hn +#align function.mul_support_nat_cast Function.mulSupport_nat_cast + +end Function +end AddMonoidWithOne section diff --git a/Mathlib/Algebra/FreeMonoid/Basic.lean b/Mathlib/Algebra/FreeMonoid/Basic.lean index 5bf5621de114f..7a3dc6acda31e 100644 --- a/Mathlib/Algebra/FreeMonoid/Basic.lean +++ b/Mathlib/Algebra/FreeMonoid/Basic.lean @@ -350,4 +350,11 @@ theorem map_id : map (@id α) = MonoidHom.id (FreeMonoid α) := hom_eq fun _ ↦ #align free_monoid.map_id FreeMonoid.map_id #align free_add_monoid.map_id FreeAddMonoid.map_id +/-- The only invertible element of the free monoid is 1; this instance enables `units_eq_one`. -/ +@[to_additive] +instance uniqueUnits : Unique (FreeMonoid α)ˣ where + uniq u := Units.ext <| toList.injective <| + have : toList u.val ++ toList u.inv = [] := FunLike.congr_arg toList u.val_inv + (List.append_eq_nil.mp this).1 + end FreeMonoid diff --git a/Mathlib/Algebra/Function/Finite.lean b/Mathlib/Algebra/Function/Finite.lean new file mode 100644 index 0000000000000..d49be59964f91 --- /dev/null +++ b/Mathlib/Algebra/Function/Finite.lean @@ -0,0 +1,23 @@ +/- +Copyright (c) 2021 Oliver Nash. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Oliver Nash +-/ +import Mathlib.Algebra.Function.Support +import Mathlib.Data.Set.Finite + +/-! +# Finiteness of support +-/ + +namespace Function +variable {α β γ : Type*} [One γ] + +@[to_additive (attr := simp)] +lemma mulSupport_along_fiber_finite_of_finite (f : α × β → γ) (a : α) (h : (mulSupport f).Finite) : + (mulSupport fun b ↦ f (a, b)).Finite := + (h.image Prod.snd).subset (mulSupport_along_fiber_subset f a) +#align function.mul_support_along_fiber_finite_of_finite Function.mulSupport_along_fiber_finite_of_finite +#align function.support_along_fiber_finite_of_finite Function.support_along_fiber_finite_of_finite + +end Function diff --git a/Mathlib/Algebra/IndicatorFunction.lean b/Mathlib/Algebra/Function/Indicator.lean similarity index 65% rename from Mathlib/Algebra/IndicatorFunction.lean rename to Mathlib/Algebra/Function/Indicator.lean index ad96c463add33..d526c432bf782 100644 --- a/Mathlib/Algebra/IndicatorFunction.lean +++ b/Mathlib/Algebra/Function/Indicator.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Zhouhang Zhou. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Zhouhang Zhou -/ -import Mathlib.Algebra.Support +import Mathlib.Algebra.Function.Support #align_import algebra.indicator_function from "leanprover-community/mathlib"@"2445c98ae4b87eabebdde552593519b9b6dc350c" @@ -30,8 +30,6 @@ arguments. This is in contrast with the design of `Pi.single` or `Set.piecewise` indicator, characteristic -/ -open BigOperators - open Function variable {α β ι M N : Type*} @@ -475,58 +473,6 @@ noncomputable def mulIndicatorHom {α} (M) [MulOneClass M] (s : Set α) : (α end Monoid -section DistribMulAction - -variable {A : Type*} [AddMonoid A] [Monoid M] [DistribMulAction M A] - -theorem indicator_smul_apply (s : Set α) (r : α → M) (f : α → A) (x : α) : - indicator s (fun x => r x • f x) x = r x • indicator s f x := by - dsimp only [indicator] - split_ifs - exacts [rfl, (smul_zero (r x)).symm] -#align set.indicator_smul_apply Set.indicator_smul_apply - -theorem indicator_smul (s : Set α) (r : α → M) (f : α → A) : - (indicator s fun x : α => r x • f x) = fun x : α => r x • indicator s f x := - funext <| indicator_smul_apply s r f -#align set.indicator_smul Set.indicator_smul - -theorem indicator_const_smul_apply (s : Set α) (r : M) (f : α → A) (x : α) : - indicator s (fun x => r • f x) x = r • indicator s f x := - indicator_smul_apply s (fun _ => r) f x -#align set.indicator_const_smul_apply Set.indicator_const_smul_apply - -theorem indicator_const_smul (s : Set α) (r : M) (f : α → A) : - (indicator s fun x : α => r • f x) = fun x : α => r • indicator s f x := - funext <| indicator_const_smul_apply s r f -#align set.indicator_const_smul Set.indicator_const_smul - -end DistribMulAction - -section SMulWithZero - -variable {A : Type*} [Zero A] [Zero M] [SMulWithZero M A] - -theorem indicator_smul_apply_left (s : Set α) (r : α → M) (f : α → A) (x : α) : - indicator s (fun x => r x • f x) x = indicator s r x • f x := by - dsimp only [indicator] - split_ifs - exacts [rfl, (zero_smul _ (f x)).symm] - -theorem indicator_smul_left (s : Set α) (r : α → M) (f : α → A) : - (indicator s fun x : α => r x • f x) = fun x : α => indicator s r x • f x := - funext <| indicator_smul_apply_left s r f - -theorem indicator_smul_const_apply (s : Set α) (r : α → M) (a : A) (x : α) : - indicator s (fun x => r x • a) x = indicator s r x • a := - indicator_smul_apply_left s r (fun _ => a) x - -theorem indicator_smul_const (s : Set α) (r : α → M) (a : A) : - (indicator s fun x : α => r x • a) = fun x : α => indicator s r x • a := - funext <| indicator_smul_const_apply s r a - -end SMulWithZero - section Group variable {G : Type*} [Group G] {s t : Set α} {f g : α → G} {a : α} @@ -594,111 +540,6 @@ theorem apply_mulIndicator_symmDiff {g : G → β} (hg : ∀ x, g x⁻¹ = g x) end Group -theorem abs_indicator_symmDiff {G : Type*} [LinearOrderedAddCommGroup G] - (s t : Set α) (f : α → G) (x : α) : - |indicator (s ∆ t) f x| = |indicator s f x - indicator t f x| := - apply_indicator_symmDiff abs_neg s t f x - -section CommMonoid - -variable [CommMonoid M] - -/-- Consider a product of `g i (f i)` over a `Finset`. Suppose `g` is a -function such as `Pow`, which maps a second argument of `1` to -`1`. Then if `f` is replaced by the corresponding multiplicative indicator -function, the `Finset` may be replaced by a possibly larger `Finset` -without changing the value of the sum. -/ -@[to_additive] -theorem prod_mulIndicator_subset_of_eq_one [One N] (f : α → N) (g : α → N → M) {s t : Finset α} - (h : s ⊆ t) (hg : ∀ a, g a 1 = 1) : - (∏ i in s, g i (f i)) = ∏ i in t, g i (mulIndicator (↑s) f i) := by - rw [← Finset.prod_subset h _] - · apply Finset.prod_congr rfl - intro i hi - congr - symm - -- Porting note: This did not use to need the implicit argument - exact mulIndicator_of_mem (α := α) hi f - · refine' fun i _ hn => _ - convert hg i - -- Porting note: This did not use to need the implicit argument - exact mulIndicator_of_not_mem (α := α) hn f -#align set.prod_mul_indicator_subset_of_eq_one Set.prod_mulIndicator_subset_of_eq_one -#align set.sum_indicator_subset_of_eq_zero Set.sum_indicator_subset_of_eq_zero - -/-- Consider a sum of `g i (f i)` over a `Finset`. Suppose `g` is a -function such as multiplication, which maps a second argument of 0 to -0. (A typical use case would be a weighted sum of `f i * h i` or `f i • h i`, -where `f` gives the weights that are multiplied by some other -function `h`.) Then if `f` is replaced by the corresponding indicator -function, the `Finset` may be replaced by a possibly larger `Finset` -without changing the value of the sum. -/ -add_decl_doc Set.sum_indicator_subset_of_eq_zero - -/-- Taking the product of an indicator function over a possibly larger `Finset` is the same as -taking the original function over the original `Finset`. -/ -@[to_additive - "Summing an indicator function over a possibly larger `Finset` is the same as summing - the original function over the original `finset`."] -theorem prod_mulIndicator_subset (f : α → M) {s t : Finset α} (h : s ⊆ t) : - ∏ i in s, f i = ∏ i in t, mulIndicator (↑s) f i := - prod_mulIndicator_subset_of_eq_one _ (fun _ b => b) h fun _ => rfl -#align set.prod_mul_indicator_subset Set.prod_mulIndicator_subset -#align set.sum_indicator_subset Set.sum_indicator_subset - -@[to_additive] -theorem _root_.Finset.prod_mulIndicator_eq_prod_filter (s : Finset ι) (f : ι → α → M) - (t : ι → Set α) (g : ι → α) [DecidablePred fun i => g i ∈ t i] : - (∏ i in s, mulIndicator (t i) (f i) (g i)) = ∏ i in s.filter fun i => g i ∈ t i, f i (g i) := by - refine' (Finset.prod_filter_mul_prod_filter_not s (fun i => g i ∈ t i) _).symm.trans _ - refine' Eq.trans _ (mul_one _) - exact - congr_arg₂ (· * ·) - (Finset.prod_congr rfl fun x hx => mulIndicator_of_mem (Finset.mem_filter.1 hx).2 _) - (Finset.prod_eq_one fun x hx => mulIndicator_of_not_mem (Finset.mem_filter.1 hx).2 _) -#align finset.prod_mul_indicator_eq_prod_filter Finset.prod_mulIndicator_eq_prod_filter -#align finset.sum_indicator_eq_sum_filter Finset.sum_indicator_eq_sum_filter - -@[to_additive] -theorem mulIndicator_finset_prod (I : Finset ι) (s : Set α) (f : ι → α → M) : - mulIndicator s (∏ i in I, f i) = ∏ i in I, mulIndicator s (f i) := - map_prod (mulIndicatorHom M s) _ _ -#align set.mul_indicator_finset_prod Set.mulIndicator_finset_prod -#align set.indicator_finset_sum Set.indicator_finset_sum - -@[to_additive] -theorem mulIndicator_finset_biUnion (I : Finset ι) (s : ι → Set α) {f : α → M} : - (∀ i ∈ I, ∀ j ∈ I, i ≠ j → Disjoint (s i) (s j)) → - mulIndicator (⋃ i ∈ I, s i) f = fun a => ∏ i in I, mulIndicator (s i) f a := by - classical - refine' Finset.induction_on I _ _ - · intro - funext - simp - intro a I haI ih hI - funext - rw [Finset.prod_insert haI, Finset.set_biUnion_insert, mulIndicator_union_of_not_mem_inter, - ih _] - · intro i hi j hj hij - exact hI i (Finset.mem_insert_of_mem hi) j (Finset.mem_insert_of_mem hj) hij - simp only [not_exists, exists_prop, mem_iUnion, mem_inter_iff, not_and] - intro hx a' ha' - refine' - disjoint_left.1 (hI a (Finset.mem_insert_self _ _) a' (Finset.mem_insert_of_mem ha') _) hx - exact (ne_of_mem_of_not_mem ha' haI).symm -#align set.mul_indicator_finset_bUnion Set.mulIndicator_finset_biUnion -#align set.indicator_finset_bUnion Set.indicator_finset_biUnion - -@[to_additive] -theorem mulIndicator_finset_biUnion_apply (I : Finset ι) (s : ι → Set α) {f : α → M} - (h : ∀ i ∈ I, ∀ j ∈ I, i ≠ j → Disjoint (s i) (s j)) (x : α) : - mulIndicator (⋃ i ∈ I, s i) f x = ∏ i in I, mulIndicator (s i) f x := by - rw [Set.mulIndicator_finset_biUnion I s h] -#align set.mul_indicator_finset_bUnion_apply Set.mulIndicator_finset_biUnion_apply -#align set.indicator_finset_bUnion_apply Set.indicator_finset_biUnion_apply - -end CommMonoid - section MulZeroClass variable [MulZeroClass M] {s t : Set α} {f g : α → M} {a : α} @@ -773,170 +614,6 @@ theorem indicator_one_inj {U V : Set α} (h : indicator U (1 : α → M) = indic end MulZeroOneClass -section Order - -variable [One M] {s t : Set α} {f g : α → M} {a : α} {y : M} - -section - -variable [LE M] - -@[to_additive] -theorem mulIndicator_apply_le' (hfg : a ∈ s → f a ≤ y) (hg : a ∉ s → 1 ≤ y) : - mulIndicator s f a ≤ y := by - by_cases ha : a ∈ s - · simpa [ha] using hfg ha - · simpa [ha] using hg ha -#align set.mul_indicator_apply_le' Set.mulIndicator_apply_le' -#align set.indicator_apply_le' Set.indicator_apply_le' - -/- ./././Mathport/Syntax/Translate/Basic.lean:632:2: -warning: expanding binder collection (a «expr ∉ » s) -/ -@[to_additive] -theorem mulIndicator_le' (hfg : ∀ a ∈ s, f a ≤ g a) (hg : ∀ (a) (_ : a ∉ s), 1 ≤ g a) : - mulIndicator s f ≤ g := fun _ => mulIndicator_apply_le' (hfg _) (hg _) -#align set.mul_indicator_le' Set.mulIndicator_le' -#align set.indicator_le' Set.indicator_le' - -@[to_additive] -theorem le_mulIndicator_apply {y} (hfg : a ∈ s → y ≤ g a) (hf : a ∉ s → y ≤ 1) : - y ≤ mulIndicator s g a := - @mulIndicator_apply_le' α Mᵒᵈ ‹_› _ _ _ _ _ hfg hf -#align set.le_mul_indicator_apply Set.le_mulIndicator_apply -#align set.le_indicator_apply Set.le_indicator_apply - -@[to_additive] -theorem le_mulIndicator (hfg : ∀ a ∈ s, f a ≤ g a) (hf : ∀ (a) (_ : a ∉ s), f a ≤ 1) : - f ≤ mulIndicator s g := fun _ => le_mulIndicator_apply (hfg _) (hf _) -#align set.le_mul_indicator Set.le_mulIndicator -#align set.le_indicator Set.le_indicator - -end - -variable [Preorder M] - -@[to_additive indicator_apply_nonneg] -theorem one_le_mulIndicator_apply (h : a ∈ s → 1 ≤ f a) : 1 ≤ mulIndicator s f a := - le_mulIndicator_apply h fun _ => le_rfl -#align set.one_le_mul_indicator_apply Set.one_le_mulIndicator_apply -#align set.indicator_apply_nonneg Set.indicator_apply_nonneg - -@[to_additive indicator_nonneg] -theorem one_le_mulIndicator (h : ∀ a ∈ s, 1 ≤ f a) (a : α) : 1 ≤ mulIndicator s f a := - one_le_mulIndicator_apply (h a) -#align set.one_le_mul_indicator Set.one_le_mulIndicator -#align set.indicator_nonneg Set.indicator_nonneg - -@[to_additive] -theorem mulIndicator_apply_le_one (h : a ∈ s → f a ≤ 1) : mulIndicator s f a ≤ 1 := - mulIndicator_apply_le' h fun _ => le_rfl -#align set.mul_indicator_apply_le_one Set.mulIndicator_apply_le_one -#align set.indicator_apply_nonpos Set.indicator_apply_nonpos - -@[to_additive] -theorem mulIndicator_le_one (h : ∀ a ∈ s, f a ≤ 1) (a : α) : mulIndicator s f a ≤ 1 := - mulIndicator_apply_le_one (h a) -#align set.mul_indicator_le_one Set.mulIndicator_le_one -#align set.indicator_nonpos Set.indicator_nonpos - -@[to_additive] -theorem mulIndicator_le_mulIndicator (h : f a ≤ g a) : mulIndicator s f a ≤ mulIndicator s g a := - mulIndicator_rel_mulIndicator le_rfl fun _ => h -#align set.mul_indicator_le_mul_indicator Set.mulIndicator_le_mulIndicator -#align set.indicator_le_indicator Set.indicator_le_indicator - -attribute [mono] mulIndicator_le_mulIndicator indicator_le_indicator - -@[to_additive] -theorem mulIndicator_le_mulIndicator_of_subset (h : s ⊆ t) (hf : ∀ a, 1 ≤ f a) (a : α) : - mulIndicator s f a ≤ mulIndicator t f a := - mulIndicator_apply_le' - (fun ha => le_mulIndicator_apply (fun _ => le_rfl) fun hat => (hat <| h ha).elim) fun _ => - one_le_mulIndicator_apply fun _ => hf _ -#align set.mul_indicator_le_mul_indicator_of_subset Set.mulIndicator_le_mulIndicator_of_subset -#align set.indicator_le_indicator_of_subset Set.indicator_le_indicator_of_subset - -@[to_additive] -theorem mulIndicator_le_self' (hf : ∀ (x) (_ : x ∉ s), 1 ≤ f x) : mulIndicator s f ≤ f := - mulIndicator_le' (fun _ _ => le_rfl) hf -#align set.mul_indicator_le_self' Set.mulIndicator_le_self' -#align set.indicator_le_self' Set.indicator_le_self' - -@[to_additive] -theorem mulIndicator_iUnion_apply {ι : Sort*} {M : Type*} [CompleteLattice M] [One M] - (h1 : (⊥ : M) = 1) (s : ι → Set α) (f : α → M) (x : α) : - mulIndicator (⋃ i, s i) f x = ⨆ i, mulIndicator (s i) f x := by - by_cases hx : x ∈ ⋃ i, s i - · rw [mulIndicator_of_mem hx] - rw [mem_iUnion] at hx - refine' le_antisymm _ (iSup_le fun i => mulIndicator_le_self' (fun x _ => h1 ▸ bot_le) x) - rcases hx with ⟨i, hi⟩ - exact le_iSup_of_le i (ge_of_eq <| mulIndicator_of_mem hi _) - · rw [mulIndicator_of_not_mem hx] - simp only [mem_iUnion, not_exists] at hx - simp [hx, ← h1] -#align set.mul_indicator_Union_apply Set.mulIndicator_iUnion_apply -#align set.indicator_Union_apply Set.indicator_iUnion_apply - -@[to_additive] lemma mulIndicator_iInter_apply {ι : Sort*} {M : Type*} [Nonempty ι] - [CompleteLattice M] [One M] (h1 : (⊥ : M) = 1) (s : ι → Set α) (f : α → M) (x : α) : - mulIndicator (⋂ i, s i) f x = ⨅ i, mulIndicator (s i) f x := by - by_cases hx : x ∈ ⋂ i, s i - · rw [mulIndicator_of_mem hx] - rw [mem_iInter] at hx - refine le_antisymm ?_ (by simp only [mulIndicator_of_mem (hx _), ciInf_const, le_refl]) - exact le_iInf (fun j ↦ by simp only [mulIndicator_of_mem (hx j), le_refl]) - · rw [mulIndicator_of_not_mem hx] - simp only [mem_iInter, not_exists, not_forall] at hx - rcases hx with ⟨j, hj⟩ - refine le_antisymm (by simp only [← h1, le_iInf_iff, bot_le, forall_const]) ?_ - simpa [mulIndicator_of_not_mem hj] using (iInf_le (fun i ↦ (s i).mulIndicator f) j) x - -end Order - -section CanonicallyOrderedCommMonoid - -variable [CanonicallyOrderedCommMonoid M] - -@[to_additive] -theorem mulIndicator_le_self (s : Set α) (f : α → M) : mulIndicator s f ≤ f := - mulIndicator_le_self' fun _ _ => one_le _ -#align set.mul_indicator_le_self Set.mulIndicator_le_self -#align set.indicator_le_self Set.indicator_le_self - -@[to_additive] -theorem mulIndicator_apply_le {a : α} {s : Set α} {f g : α → M} (hfg : a ∈ s → f a ≤ g a) : - mulIndicator s f a ≤ g a := - mulIndicator_apply_le' hfg fun _ => one_le _ -#align set.mul_indicator_apply_le Set.mulIndicator_apply_le -#align set.indicator_apply_le Set.indicator_apply_le - -@[to_additive] -theorem mulIndicator_le {s : Set α} {f g : α → M} (hfg : ∀ a ∈ s, f a ≤ g a) : - mulIndicator s f ≤ g := - mulIndicator_le' hfg fun _ _ => one_le _ -#align set.mul_indicator_le Set.mulIndicator_le -#align set.indicator_le Set.indicator_le - -end CanonicallyOrderedCommMonoid - -theorem indicator_le_indicator_nonneg {β} [LinearOrder β] [Zero β] (s : Set α) (f : α → β) : - s.indicator f ≤ { x | 0 ≤ f x }.indicator f := by - intro x - classical - simp_rw [indicator_apply] - split_ifs with h_1 h_2 h_3 - · exact le_rfl - · exact (not_le.mp h_2).le - · exact h_3 - · exact le_rfl -#align set.indicator_le_indicator_nonneg Set.indicator_le_indicator_nonneg - -theorem indicator_nonpos_le_indicator {β} [LinearOrder β] [Zero β] (s : Set α) (f : α → β) : - { x | f x ≤ 0 }.indicator f ≤ s.indicator f := - @indicator_le_indicator_nonneg α βᵒᵈ _ _ s f -#align set.indicator_nonpos_le_indicator Set.indicator_nonpos_le_indicator - end Set @[to_additive] diff --git a/Mathlib/Algebra/Support.lean b/Mathlib/Algebra/Function/Support.lean similarity index 73% rename from Mathlib/Algebra/Support.lean rename to Mathlib/Algebra/Function/Support.lean index 308a352935383..dab474ff28353 100644 --- a/Mathlib/Algebra/Support.lean +++ b/Mathlib/Algebra/Function/Support.lean @@ -3,13 +3,8 @@ Copyright (c) 2020 Yury Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ -import Mathlib.Order.ConditionallyCompleteLattice.Basic -import Mathlib.Data.Set.Finite -import Mathlib.Algebra.BigOperators.Basic -import Mathlib.Algebra.Group.Prod import Mathlib.Algebra.Group.Pi -import Mathlib.Algebra.Module.Basic -import Mathlib.GroupTheory.GroupAction.Pi +import Mathlib.Algebra.Group.Prod import Mathlib.Order.Cover #align_import algebra.support from "leanprover-community/mathlib"@"29cb56a7b35f72758b05a30490e1f10bd62c35c1" @@ -24,8 +19,6 @@ We also define `Function.mulSupport f = {x | f x ≠ 1}`. open Set -open BigOperators - namespace Function variable {α β A B M N P R S G M₀ G₀ : Type*} {ι : Sort*} @@ -174,51 +167,6 @@ theorem mulSupport_binop_subset (op : M → N → P) (op1 : op 1 1 = 1) (f : α #align function.mul_support_binop_subset Function.mulSupport_binop_subset #align function.support_binop_subset Function.support_binop_subset -@[to_additive] -theorem mulSupport_sup [SemilatticeSup M] (f g : α → M) : - (mulSupport fun x => f x ⊔ g x) ⊆ mulSupport f ∪ mulSupport g := - mulSupport_binop_subset (· ⊔ ·) sup_idem f g -#align function.mul_support_sup Function.mulSupport_sup -#align function.support_sup Function.support_sup - -@[to_additive] -theorem mulSupport_inf [SemilatticeInf M] (f g : α → M) : - (mulSupport fun x => f x ⊓ g x) ⊆ mulSupport f ∪ mulSupport g := - mulSupport_binop_subset (· ⊓ ·) inf_idem f g -#align function.mul_support_inf Function.mulSupport_inf -#align function.support_inf Function.support_inf - -@[to_additive] -theorem mulSupport_max [LinearOrder M] (f g : α → M) : - (mulSupport fun x => max (f x) (g x)) ⊆ mulSupport f ∪ mulSupport g := - mulSupport_sup f g -#align function.mul_support_max Function.mulSupport_max -#align function.support_max Function.support_max - -@[to_additive] -theorem mulSupport_min [LinearOrder M] (f g : α → M) : - (mulSupport fun x => min (f x) (g x)) ⊆ mulSupport f ∪ mulSupport g := - mulSupport_inf f g -#align function.mul_support_min Function.mulSupport_min -#align function.support_min Function.support_min - -@[to_additive] -theorem mulSupport_iSup [ConditionallyCompleteLattice M] [Nonempty ι] (f : ι → α → M) : - (mulSupport fun x => ⨆ i, f i x) ⊆ ⋃ i, mulSupport (f i) := by - rw [mulSupport_subset_iff'] - simp only [mem_iUnion, not_exists, nmem_mulSupport] - intro x hx - simp only [hx, ciSup_const] -#align function.mul_support_supr Function.mulSupport_iSup -#align function.support_supr Function.support_iSup - -@[to_additive] -theorem mulSupport_iInf [ConditionallyCompleteLattice M] [Nonempty ι] (f : ι → α → M) : - (mulSupport fun x => ⨅ i, f i x) ⊆ ⋃ i, mulSupport (f i) := - @mulSupport_iSup _ Mᵒᵈ ι ⟨(1 : M)⟩ _ _ f -#align function.mul_support_infi Function.mulSupport_iInf -#align function.support_infi Function.support_iInf - @[to_additive] theorem mulSupport_comp_subset {g : M → N} (hg : g 1 = 1) (f : α → M) : mulSupport (g ∘ f) ⊆ mulSupport f := fun x => mt fun h => by simp only [(· ∘ ·), *] @@ -273,13 +221,6 @@ theorem mulSupport_along_fiber_subset (f : α × β → M) (a : α) : #align function.mul_support_along_fiber_subset Function.mulSupport_along_fiber_subset #align function.support_along_fiber_subset Function.support_along_fiber_subset -@[to_additive (attr := simp)] -theorem mulSupport_along_fiber_finite_of_finite (f : α × β → M) (a : α) - (h : (mulSupport f).Finite) : (mulSupport fun b => f (a, b)).Finite := - (h.image Prod.snd).subset (mulSupport_along_fiber_subset f a) -#align function.mul_support_along_fiber_finite_of_finite Function.mulSupport_along_fiber_finite_of_finite -#align function.support_along_fiber_finite_of_finite Function.support_along_fiber_finite_of_finite - end One @[to_additive] @@ -344,43 +285,9 @@ theorem mulSupport_zero : mulSupport (0 : α → R) = univ := end ZeroOne -section AddMonoidWithOne - -variable [AddMonoidWithOne R] [CharZero R] {n : ℕ} - -theorem support_nat_cast (hn : n ≠ 0) : support (n : α → R) = univ := - support_const <| Nat.cast_ne_zero.2 hn -#align function.support_nat_cast Function.support_nat_cast - -theorem mulSupport_nat_cast (hn : n ≠ 1) : mulSupport (n : α → R) = univ := - mulSupport_const <| Nat.cast_ne_one.2 hn -#align function.mul_support_nat_cast Function.mulSupport_nat_cast - -end AddMonoidWithOne - -section AddGroupWithOne - -variable [AddGroupWithOne R] [CharZero R] {n : ℤ} - -theorem support_int_cast (hn : n ≠ 0) : support (n : α → R) = univ := - support_const <| Int.cast_ne_zero.2 hn -#align function.support_int_cast Function.support_int_cast - -theorem mulSupport_int_cast (hn : n ≠ 1) : mulSupport (n : α → R) = univ := - mulSupport_const <| Int.cast_ne_one.2 hn -#align function.mul_support_int_cast Function.mulSupport_int_cast - -end AddGroupWithOne - -theorem support_smul [Zero R] [Zero M] [SMulWithZero R M] [NoZeroSMulDivisors R M] (f : α → R) - (g : α → M) : support (f • g) = support f ∩ support g := - ext fun _ => smul_ne_zero_iff -#align function.support_smul Function.support_smul - @[simp] theorem support_mul [MulZeroClass R] [NoZeroDivisors R] (f g : α → R) : - (support fun x => f x * g x) = support f ∩ support g := - support_smul f g + (support fun x => f x * g x) = support f ∩ support g := ext fun x ↦ by simp [not_or] #align function.support_mul Function.support_mul --@[simp] Porting note: removing simp, bad lemma LHS not in normal form @@ -393,20 +300,6 @@ theorem support_mul_subset_right [MulZeroClass R] (f g : α → R) : (support fun x => f x * g x) ⊆ support g := fun x hfg hg => hfg <| by simp only [hg, mul_zero] #align function.support_mul_subset_right Function.support_mul_subset_right -theorem support_smul_subset_right [AddMonoid A] [Monoid B] [DistribMulAction B A] (b : B) - (f : α → A) : support (b • f) ⊆ support f := fun x hbf hf => - hbf <| by rw [Pi.smul_apply, hf, smul_zero] -#align function.support_smul_subset_right Function.support_smul_subset_right - -theorem support_smul_subset_left [Zero M] [Zero β] [SMulWithZero M β] (f : α → M) (g : α → β) : - support (f • g) ⊆ support f := fun x hfg hf => hfg <| by rw [Pi.smul_apply', hf, zero_smul] -#align function.support_smul_subset_left Function.support_smul_subset_left - -theorem support_const_smul_of_ne_zero [Semiring R] [AddCommMonoid M] [Module R M] - [NoZeroSMulDivisors R M] (c : R) (g : α → M) (hc : c ≠ 0) : support (c • g) = support g := - ext fun x => by simp only [hc, mem_support, Pi.smul_apply, Ne.def, smul_eq_zero, false_or_iff] -#align function.support_const_smul_of_ne_zero Function.support_const_smul_of_ne_zero - @[simp] theorem support_inv [GroupWithZero G₀] (f : α → G₀) : (support fun x => (f x)⁻¹) = support f := Set.ext fun _ => not_congr inv_eq_zero @@ -417,26 +310,6 @@ theorem support_div [GroupWithZero G₀] (f g : α → G₀) : (support fun x => f x / g x) = support f ∩ support g := by simp [div_eq_mul_inv] #align function.support_div Function.support_div -@[to_additive] -theorem mulSupport_prod [CommMonoid M] (s : Finset α) (f : α → β → M) : - (mulSupport fun x => ∏ i in s, f i x) ⊆ ⋃ i ∈ s, mulSupport (f i) := by - rw [mulSupport_subset_iff'] - simp only [mem_iUnion, not_exists, nmem_mulSupport] - exact fun x => Finset.prod_eq_one -#align function.mul_support_prod Function.mulSupport_prod -#align function.support_sum Function.support_sum - -theorem support_prod_subset [CommMonoidWithZero A] (s : Finset α) (f : α → β → A) : - (support fun x => ∏ i in s, f i x) ⊆ ⋂ i ∈ s, support (f i) := fun _ hx => - mem_iInter₂.2 fun _ hi H => hx <| Finset.prod_eq_zero hi H -#align function.support_prod_subset Function.support_prod_subset - -theorem support_prod [CommMonoidWithZero A] [NoZeroDivisors A] [Nontrivial A] (s : Finset α) - (f : α → β → A) : (support fun x => ∏ i in s, f i x) = ⋂ i ∈ s, support (f i) := - Set.ext fun x => by - simp [support, Ne.def, Finset.prod_eq_zero_iff, mem_setOf_eq, Set.mem_iInter, not_exists] -#align function.support_prod Function.support_prod - theorem mulSupport_one_add [One R] [AddLeftCancelMonoid R] (f : α → R) : (mulSupport fun x => 1 + f x) = support f := Set.ext fun _ => not_congr add_right_eq_self diff --git a/Mathlib/Algebra/GroupPower/Basic.lean b/Mathlib/Algebra/GroupPower/Basic.lean index 97c39c40e6bc3..75eb3a4b5a381 100644 --- a/Mathlib/Algebra/GroupPower/Basic.lean +++ b/Mathlib/Algebra/GroupPower/Basic.lean @@ -245,6 +245,10 @@ theorem dvd_pow_self (a : M) {n : ℕ} (hn : n ≠ 0) : a ∣ a ^ n := end Monoid +lemma eq_zero_or_one_of_sq_eq_self [CancelMonoidWithZero M] {x : M} (hx : x ^ 2 = x) : + x = 0 ∨ x = 1 := + or_iff_not_imp_left.mpr (mul_left_injective₀ · <| by simpa [sq] using hx) + /-! ### Commutative (additive) monoid -/ diff --git a/Mathlib/Algebra/Module/Basic.lean b/Mathlib/Algebra/Module/Basic.lean index 5a8740d2d3001..a86cdda448120 100644 --- a/Mathlib/Algebra/Module/Basic.lean +++ b/Mathlib/Algebra/Module/Basic.lean @@ -3,12 +3,14 @@ Copyright (c) 2015 Nathaniel Thomas. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Nathaniel Thomas, Jeremy Avigad, Johannes Hölzl, Mario Carneiro -/ -import Mathlib.Algebra.SMulWithZero import Mathlib.Algebra.Field.Defs +import Mathlib.Algebra.Function.Indicator +import Mathlib.Algebra.SMulWithZero import Mathlib.Data.Int.Units import Mathlib.Data.Rat.Defs import Mathlib.Data.Rat.Basic import Mathlib.GroupTheory.GroupAction.Group +import Mathlib.GroupTheory.GroupAction.Pi import Mathlib.Tactic.Abel #align_import algebra.module.basic from "leanprover-community/mathlib"@"30413fc89f202a090a54d78e540963ed3de0056e" @@ -40,8 +42,7 @@ to use a canonical `Module` typeclass throughout. semimodule, module, vector space -/ - -open Function +open Function Set universe u v @@ -682,6 +683,22 @@ theorem smul_left_injective {x : M} (hx : x ≠ 0) : Function.Injective fun c : end SMulInjective +instance [NoZeroSMulDivisors ℤ M] : NoZeroSMulDivisors ℕ M := + ⟨fun {c x} hcx ↦ by rwa [nsmul_eq_smul_cast ℤ c x, smul_eq_zero, Nat.cast_eq_zero] at hcx⟩ + +variable (R M) + +theorem NoZeroSMulDivisors.int_of_charZero [CharZero R] : NoZeroSMulDivisors ℤ M := + ⟨fun {z x} h ↦ by simpa [← smul_one_smul R z x] using h⟩ + +/-- Only a ring of characteristic zero can can have a non-trivial module without additive or +scalar torsion. -/ +theorem CharZero.of_noZeroSMulDivisors [Nontrivial M] [NoZeroSMulDivisors ℤ M] : CharZero R := by + refine ⟨fun {n m h} ↦ ?_⟩ + obtain ⟨x, hx⟩ := exists_ne (0 : M) + replace h : (n : ℤ) • x = (m : ℤ) • x := by simp [zsmul_eq_smul_cast R, h] + simpa using smul_left_injective ℤ hx h + end Module section GroupWithZero @@ -719,4 +736,78 @@ theorem Int.smul_one_eq_coe {R : Type*} [Ring R] (m : ℤ) : m • (1 : R) = ↑ rw [zsmul_eq_mul, mul_one] #align int.smul_one_eq_coe Int.smul_one_eq_coe +namespace Function + +lemma support_smul_subset_left [Zero R] [Zero M] [SMulWithZero R M] (f : α → R) (g : α → M) : + support (f • g) ⊆ support f := fun x hfg hf ↦ hfg $ by rw [Pi.smul_apply', hf, zero_smul] +#align function.support_smul_subset_left Function.support_smul_subset_left + +lemma support_const_smul_of_ne_zero [Zero R] [Zero M] [SMulWithZero R M] [NoZeroSMulDivisors R M] + (c : R) (g : α → M) (hc : c ≠ 0) : support (c • g) = support g := + ext fun x ↦ by simp only [hc, mem_support, Pi.smul_apply, Ne.def, smul_eq_zero, false_or_iff] +#align function.support_const_smul_of_ne_zero Function.support_const_smul_of_ne_zero + +lemma support_smul [Zero R] [Zero M] [SMulWithZero R M] [NoZeroSMulDivisors R M] (f : α → R) + (g : α → M) : support (f • g) = support f ∩ support g := + ext fun _ => smul_ne_zero_iff +#align function.support_smul Function.support_smul + +lemma support_smul_subset_right [Zero M] [SMulZeroClass R M] (a : R) (f : α → M) : + support (a • f) ⊆ support f := fun x hbf hf => + hbf <| by rw [Pi.smul_apply, hf, smul_zero] +#align function.support_smul_subset_right Function.support_smul_subset_right + +end Function + +namespace Set +section SMulZeroClass +variable [Zero R] [Zero M] [SMulZeroClass R M] + +lemma indicator_smul_apply (s : Set α) (r : α → R) (f : α → M) (a : α) : + indicator s (fun a ↦ r a • f a) a = r a • indicator s f a := by + dsimp only [indicator] + split_ifs + exacts [rfl, (smul_zero (r a)).symm] +#align set.indicator_smul_apply Set.indicator_smul_apply + +lemma indicator_smul (s : Set α) (r : α → R) (f : α → M) : + indicator s (fun a ↦ r a • f a) = fun a ↦ r a • indicator s f a := + funext $ indicator_smul_apply s r f +#align set.indicator_smul Set.indicator_smul + +lemma indicator_const_smul_apply (s : Set α) (r : R) (f : α → M) (a : α) : + indicator s (r • f ·) a = r • indicator s f a := + indicator_smul_apply s (fun _ ↦ r) f a +#align set.indicator_const_smul_apply Set.indicator_const_smul_apply + +lemma indicator_const_smul (s : Set α) (r : R) (f : α → M) : + indicator s (r • f ·) = (r • indicator s f ·) := + funext $ indicator_const_smul_apply s r f +#align set.indicator_const_smul Set.indicator_const_smul + +end SMulZeroClass + +section SMulWithZero +variable [Zero R] [Zero M] [SMulWithZero R M] + +lemma indicator_smul_apply_left (s : Set α) (r : α → R) (f : α → M) (a : α) : + indicator s (fun a ↦ r a • f a) a = indicator s r a • f a := by + dsimp only [indicator] + split_ifs + exacts [rfl, (zero_smul _ (f a)).symm] + +lemma indicator_smul_left (s : Set α) (r : α → R) (f : α → M) : + indicator s (fun a ↦ r a • f a) = fun a ↦ indicator s r a • f a := + funext $ indicator_smul_apply_left _ _ _ + +lemma indicator_smul_const_apply (s : Set α) (r : α → R) (m : M) (a : α) : + indicator s (r · • m) a = indicator s r a • m := indicator_smul_apply_left _ _ _ _ + +lemma indicator_smul_const (s : Set α) (r : α → R) (m : M) : + indicator s (r · • m) = (indicator s r · • m) := + funext $ indicator_smul_const_apply _ _ _ + +end SMulWithZero +end Set + assert_not_exists Multiset diff --git a/Mathlib/Algebra/Module/DirectLimitAndTensorProduct.lean b/Mathlib/Algebra/Module/DirectLimitAndTensorProduct.lean new file mode 100644 index 0000000000000..18dffd407253d --- /dev/null +++ b/Mathlib/Algebra/Module/DirectLimitAndTensorProduct.lean @@ -0,0 +1,112 @@ +/- +Copyright (c) 2023 Jujian Zhang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jujian Zhang +-/ + +import Mathlib.Algebra.DirectLimit + +/-! +# Tensor product and direct limits commute with each other. + +Given a family of `R`-modules `Gᵢ` with a family of compatible `R`-linear maps `fᵢⱼ : Gᵢ → Gⱼ` for +every `i ≤ j` and another `R`-module `M`, we have `(limᵢ Gᵢ) ⊗ M` and `lim (Gᵢ ⊗ M)` are isomorphic +as `R`-modules. + +## Main definitions: + +* `TensorProduct.directLimitLeft : DirectLimit G f ⊗[R] M ≃ₗ[R] DirectLimit (G · ⊗[R] M) (f ▷ M)` +* `TensorProduct.directLimitRight : M ⊗[R] DirectLimit G f ≃ₗ[R] DirectLimit (M ⊗[R] G ·) (M ◁ f)` + +-/ + +open TensorProduct Module Module.DirectLimit + +variable {R : Type*} [CommRing R] +variable {ι : Type*} +variable [DecidableEq ι] [Preorder ι] +variable {G : ι → Type*} + +variable [∀ i, AddCommGroup (G i)] [∀ i, Module R (G i)] + +variable (f : ∀ i j, i ≤ j → G i →ₗ[R] G j) +variable (M : Type*) [AddCommGroup M] [Module R M] + +-- alluding to the notation in `CategoryTheory.Monoidal` +local notation M " ◁ " f => fun i j h ↦ LinearMap.lTensor M (f _ _ h) +local notation f " ▷ " N => fun i j h ↦ LinearMap.rTensor N (f _ _ h) + +namespace TensorProduct + +/-- +the map `limᵢ (Gᵢ ⊗ M) → (limᵢ Gᵢ) ⊗ M` induced by the family of maps `Gᵢ ⊗ M → (limᵢ Gᵢ) ⊗ M` +given by `gᵢ ⊗ m ↦ [gᵢ] ⊗ m`. +-/ +noncomputable def fromDirectLimit : + DirectLimit (G · ⊗[R] M) (f ▷ M) →ₗ[R] DirectLimit G f ⊗[R] M := + DirectLimit.lift _ _ _ _ (fun _ ↦ (of _ _ _ _ _).rTensor M) + fun _ _ _ x ↦ by refine' x.induction_on _ _ _ <;> aesop + +variable {M} in +@[simp] lemma fromDirectLimit_of_tmul {i : ι} (g : G i) (m : M) : + fromDirectLimit f M (of _ _ _ _ i (g ⊗ₜ m)) = (of _ _ _ f i g) ⊗ₜ m := + lift_of (G := (G · ⊗[R] M)) _ _ (g ⊗ₜ m) + +/-- +the map `(limᵢ Gᵢ) ⊗ M → limᵢ (Gᵢ ⊗ M)` from the bilinear map `limᵢ Gᵢ → M → limᵢ (Gᵢ ⊗ M)` given +by the family of maps `Gᵢ → M → limᵢ (Gᵢ ⊗ M)` where `gᵢ ↦ m ↦ [gᵢ ⊗ m]` + +-/ +noncomputable def toDirectLimit : DirectLimit G f ⊗[R] M →ₗ[R] DirectLimit (G · ⊗[R] M) (f ▷ M) := + TensorProduct.lift <| DirectLimit.lift _ _ _ _ + (fun i ↦ + (TensorProduct.mk R _ _).compr₂ (of R ι _ (fun _i _j h ↦ (f _ _ h).rTensor M) i)) + fun _ _ _ g ↦ FunLike.ext _ _ (of_f (G := (G · ⊗[R] M)) (x := g ⊗ₜ ·)) + +variable {M} in +@[simp] lemma toDirectLimit_tmul_of + {i : ι} (g : G i) (m : M) : + (toDirectLimit f M <| (of _ _ G f i g) ⊗ₜ m) = (of _ _ _ _ i (g ⊗ₜ m)) := by + rw [toDirectLimit, lift.tmul, lift_of] + rfl + +variable [IsDirected ι (· ≤ ·)] + +/-- +`limᵢ (Gᵢ ⊗ M)` and `(limᵢ Gᵢ) ⊗ M` are isomorphic as modules +-/ +noncomputable def directLimitLeft : + DirectLimit G f ⊗[R] M ≃ₗ[R] DirectLimit (G · ⊗[R] M) (f ▷ M) := by + refine LinearEquiv.ofLinear (toDirectLimit f M) (fromDirectLimit f M) ?_ ?_ + <;> cases isEmpty_or_nonempty ι + · ext; apply Subsingleton.elim + · refine FunLike.ext _ _ fun x ↦ x.induction_on fun i g ↦ g.induction_on ?_ ?_ ?_ <;> aesop + · ext; apply Subsingleton.elim + · exact ext (FunLike.ext _ _ fun g ↦ FunLike.ext _ _ fun _ ↦ g.induction_on <| by aesop) + +@[simp] lemma directLimitLeft_tmul_of {i : ι} (g : G i) (m : M) : + directLimitLeft f M (of _ _ _ _ _ g ⊗ₜ m) = of _ _ _ (f ▷ M) _ (g ⊗ₜ m) := + toDirectLimit_tmul_of f g m + +@[simp] lemma directLimitLeft_symm_of_tmul {i : ι} (g : G i) (m : M) : + (directLimitLeft f M).symm (of _ _ _ _ _ (g ⊗ₜ m)) = of _ _ _ f _ g ⊗ₜ m := + fromDirectLimit_of_tmul f g m + +/-- +`M ⊗ (limᵢ Gᵢ)` and `limᵢ (M ⊗ Gᵢ)` are isomorphic as modules +-/ +noncomputable def directLimitRight : + M ⊗[R] DirectLimit G f ≃ₗ[R] DirectLimit (M ⊗[R] G ·) (M ◁ f) := + TensorProduct.comm _ _ _ ≪≫ₗ directLimitLeft f M ≪≫ₗ + Module.DirectLimit.congr (fun i ↦ TensorProduct.comm _ _ _) + (fun i j h ↦ TensorProduct.ext <| FunLike.ext _ _ <| by aesop) + +@[simp] lemma directLimitRight_tmul_of {i : ι} (m : M) (g : G i): + directLimitRight f M (m ⊗ₜ of _ _ _ _ _ g) = of _ _ _ _ i (m ⊗ₜ g) := by + simp [directLimitRight, congr_apply_of] + +@[simp] lemma directLimitRight_symm_of_tmul {i : ι} (m : M) (g : G i) : + (directLimitRight f M).symm (of _ _ _ _ _ (m ⊗ₜ g)) = m ⊗ₜ of _ _ _ f _ g := by + simp [directLimitRight, congr_symm_apply_of] + +end TensorProduct diff --git a/Mathlib/Algebra/Module/Equiv.lean b/Mathlib/Algebra/Module/Equiv.lean index 03c3042fb8c9c..988bc8f5ced38 100644 --- a/Mathlib/Algebra/Module/Equiv.lean +++ b/Mathlib/Algebra/Module/Equiv.lean @@ -342,11 +342,11 @@ def trans #align linear_equiv.trans LinearEquiv.trans /-- The notation `e₁ ≪≫ₗ e₂` denotes the composition of the linear equivalences `e₁` and `e₂`. -/ -infixl:80 " ≪≫ₗ " => +notation3:80 (name := transNotation) e₁:80 " ≪≫ₗ " e₂:81 => @LinearEquiv.trans _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ (RingHom.id _) (RingHom.id _) (RingHom.id _) (RingHom.id _) (RingHom.id _) (RingHom.id _) RingHomCompTriple.ids RingHomCompTriple.ids RingHomInvPair.ids RingHomInvPair.ids RingHomInvPair.ids RingHomInvPair.ids RingHomInvPair.ids - RingHomInvPair.ids + RingHomInvPair.ids e₁ e₂ variable {e₁₂} {e₂₃} @@ -659,6 +659,21 @@ instance automorphismGroup : Group (M ≃ₗ[R] M) where mul_left_inv f := ext <| f.left_inv #align linear_equiv.automorphism_group LinearEquiv.automorphismGroup +@[simp] +lemma coe_one : ↑(1 : M ≃ₗ[R] M) = id := rfl + +@[simp] +lemma coe_toLinearMap_one : (↑(1 : M ≃ₗ[R] M) : M →ₗ[R] M) = LinearMap.id := rfl + +@[simp] +lemma coe_toLinearMap_mul {e₁ e₂ : M ≃ₗ[R] M} : + (↑(e₁ * e₂) : M →ₗ[R] M) = (e₁ : M →ₗ[R] M) * (e₂ : M →ₗ[R] M) := by + rfl + +theorem coe_pow (e : M ≃ₗ[R] M) (n : ℕ) : ⇑(e ^ n) = e^[n] := hom_coe_pow _ rfl (fun _ _ ↦ rfl) _ _ + +theorem pow_apply (e : M ≃ₗ[R] M) (n : ℕ) (m : M) : (e ^ n) m = e^[n] m := congr_fun (coe_pow e n) m + /-- Restriction from `R`-linear automorphisms of `M` to `R`-linear endomorphisms of `M`, promoted to a monoid hom. -/ @[simps] diff --git a/Mathlib/Algebra/Module/LinearMap.lean b/Mathlib/Algebra/Module/LinearMap.lean index bf1e3186147f9..07f886c18f078 100644 --- a/Mathlib/Algebra/Module/LinearMap.lean +++ b/Mathlib/Algebra/Module/LinearMap.lean @@ -550,12 +550,11 @@ def comp : M₁ →ₛₗ[σ₁₃] M₃ where map_smul' r x := by simp only [Function.comp_apply, map_smulₛₗ, RingHomCompTriple.comp_apply] #align linear_map.comp LinearMap.comp -set_option quotPrecheck false in -- Porting note: error message suggested to do this /-- `∘ₗ` is notation for composition of two linear (not semilinear!) maps into a linear map. This is useful when Lean is struggling to infer the `RingHomCompTriple` instance. -/ -infixr:80 " ∘ₗ " => +notation3:80 (name := compNotation) f:81 " ∘ₗ " g:80 => @LinearMap.comp _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ (RingHom.id _) (RingHom.id _) (RingHom.id _) - RingHomCompTriple.ids + RingHomCompTriple.ids f g theorem comp_apply (x : M₁) : f.comp g x = f (g x) := rfl @@ -1376,6 +1375,22 @@ theorem smulRight_apply (f : M₁ →ₗ[R] S) (x : M) (c : M₁) : smulRight f rfl #align linear_map.smul_right_apply LinearMap.smulRight_apply +@[simp] +lemma smulRight_zero (f : M₁ →ₗ[R] S) : f.smulRight (0 : M) = 0 := by ext; simp + +@[simp] +lemma zero_smulRight (x : M) : (0 : M₁ →ₗ[R] S).smulRight x = 0 := by ext; simp + +@[simp] +lemma smulRight_apply_eq_zero_iff {f : M₁ →ₗ[R] S} {x : M} [NoZeroSMulDivisors S M] : + f.smulRight x = 0 ↔ f = 0 ∨ x = 0 := by + rcases eq_or_ne x 0 with rfl | hx; simp + refine ⟨fun h ↦ Or.inl ?_, fun h ↦ by simp [h.resolve_right hx]⟩ + ext v + replace h : f v • x = 0 := by simpa only [LinearMap.zero_apply] using LinearMap.congr_fun h v + rw [smul_eq_zero] at h + tauto + end SMulRight end AddCommMonoid diff --git a/Mathlib/Algebra/Module/Submodule/Map.lean b/Mathlib/Algebra/Module/Submodule/Map.lean index 974269f74ffb7..e49158181b800 100644 --- a/Mathlib/Algebra/Module/Submodule/Map.lean +++ b/Mathlib/Algebra/Module/Submodule/Map.lean @@ -619,3 +619,23 @@ def compatibleMaps : Submodule R (N →ₗ[R] N₂) where #align submodule.compatible_maps Submodule.compatibleMaps end Submodule + +namespace LinearMap + +variable [Semiring R] [AddCommMonoid M] [AddCommMonoid M₁] [Module R M] [Module R M₁] + +/-- A linear map between two modules restricts to a linear map from any submodule p of the +domain onto the image of that submodule. + +This is the linear version of `AddMonoidHom.addSubmonoidMap` and `AddMonoidHom.addSubgroupMap`.-/ +def submoduleMap (f : M →ₗ[R] M₁) (p : Submodule R M) : p →ₗ[R] p.map f := + f.restrict fun x hx ↦ Submodule.mem_map.mpr ⟨x, hx, rfl⟩ + +@[simp] +theorem submoduleMap_coe_apply (f : M →ₗ[R] M₁) {p : Submodule R M} (x : p) : + ↑(f.submoduleMap p x) = f x := rfl + +theorem submoduleMap_surjective (f : M →ₗ[R] M₁) (p : Submodule R M) : + Function.Surjective (f.submoduleMap p) := f.toAddMonoidHom.addSubmonoidMap_surjective _ + +end LinearMap diff --git a/Mathlib/Algebra/MonoidAlgebra/Basic.lean b/Mathlib/Algebra/MonoidAlgebra/Basic.lean index 55b89da97b872..d6b68a8aef7b7 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Basic.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Basic.lean @@ -906,15 +906,14 @@ theorem lift_symm_apply (F : MonoidAlgebra k G →ₐ[k] A) (x : G) : rfl #align monoid_algebra.lift_symm_apply MonoidAlgebra.lift_symm_apply -theorem lift_of (F : G →* A) (x) : lift k G A F (of k G x) = F x := by - rw [of_apply, ← lift_symm_apply, Equiv.symm_apply_apply] -#align monoid_algebra.lift_of MonoidAlgebra.lift_of - @[simp] theorem lift_single (F : G →* A) (a b) : lift k G A F (single a b) = b • F a := by rw [lift_def, liftNC_single, Algebra.smul_def, AddMonoidHom.coe_coe] #align monoid_algebra.lift_single MonoidAlgebra.lift_single +theorem lift_of (F : G →* A) (x) : lift k G A F (of k G x) = F x := by simp +#align monoid_algebra.lift_of MonoidAlgebra.lift_of + theorem lift_unique' (F : MonoidAlgebra k G →ₐ[k] A) : F = lift k G A ((F : MonoidAlgebra k G →* A).comp (of k G)) := ((lift k G A).apply_symm_apply F).symm @@ -1626,12 +1625,11 @@ theorem of'_apply (a : G) : of' k G a = single a 1 := rfl #align add_monoid_algebra.of'_apply AddMonoidAlgebra.of'_apply -theorem of'_eq_of [AddZeroClass G] (a : G) : of' k G a = of k G a := - rfl +theorem of'_eq_of [AddZeroClass G] (a : G) : of' k G a = of k G (.ofAdd a) := rfl #align add_monoid_algebra.of'_eq_of AddMonoidAlgebra.of'_eq_of -theorem of_injective [Nontrivial k] [AddZeroClass G] : Function.Injective (of k G) := fun a b h => - by simpa using (single_eq_single_iff _ _ _ _).mp h +theorem of_injective [Nontrivial k] [AddZeroClass G] : Function.Injective (of k G) := + MonoidAlgebra.of_injective #align add_monoid_algebra.of_injective AddMonoidAlgebra.of_injective /-- `Finsupp.single` as a `MonoidHom` from the product type into the additive monoid algebra. @@ -2005,15 +2003,19 @@ theorem lift_symm_apply (F : k[G] →ₐ[k] A) (x : Multiplicative G) : #align add_monoid_algebra.lift_symm_apply AddMonoidAlgebra.lift_symm_apply theorem lift_of (F : Multiplicative G →* A) (x : Multiplicative G) : - lift k G A F (of k G x) = F x := by rw [of_apply, ← lift_symm_apply, Equiv.symm_apply_apply] + lift k G A F (of k G x) = F x := MonoidAlgebra.lift_of F x #align add_monoid_algebra.lift_of AddMonoidAlgebra.lift_of @[simp] theorem lift_single (F : Multiplicative G →* A) (a b) : - lift k G A F (single a b) = b • F (Multiplicative.ofAdd a) := by - rw [lift_def, liftNC_single, Algebra.smul_def, AddMonoidHom.coe_coe] + lift k G A F (single a b) = b • F (Multiplicative.ofAdd a) := + MonoidAlgebra.lift_single F (.ofAdd a) b #align add_monoid_algebra.lift_single AddMonoidAlgebra.lift_single +lemma lift_of' (F : Multiplicative G →* A) (x : G) : + lift k G A F (of' k G x) = F (Multiplicative.ofAdd x) := + lift_of F x + theorem lift_unique' (F : k[G] →ₐ[k] A) : F = lift k G A ((F : k[G] →* A).comp (of k G)) := ((lift k G A).apply_symm_apply F).symm diff --git a/Mathlib/Algebra/Order/Ring/Defs.lean b/Mathlib/Algebra/Order/Ring/Defs.lean index 71ce0ad9ca0aa..a2db8c247eec6 100644 --- a/Mathlib/Algebra/Order/Ring/Defs.lean +++ b/Mathlib/Algebra/Order/Ring/Defs.lean @@ -100,13 +100,12 @@ immediate predecessors and what conditions are added to each of them. - `StrictOrderedRing` & totality of the order - `LinearOrderedSemiring` & additive inverses - `LinearOrderedAddCommGroup` & multiplication & `*` respects `<` - - `Domain` & linear order structure + - `Ring` & `IsDomain` & linear order structure * `LinearOrderedCommRing` - `StrictOrderedCommRing` & totality of the order - `LinearOrderedRing` & commutativity of multiplication - `LinearOrderedCommSemiring` & additive inverses - - `IsDomain` & linear order structure - + - `CommRing` & `IsDomain` & linear order structure -/ open Function diff --git a/Mathlib/Algebra/Order/Support.lean b/Mathlib/Algebra/Order/Support.lean new file mode 100644 index 0000000000000..28ea061c38512 --- /dev/null +++ b/Mathlib/Algebra/Order/Support.lean @@ -0,0 +1,242 @@ +/- +Copyright (c) 2020 Yury Kudryashov. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yury Kudryashov +-/ +import Mathlib.Algebra.Function.Indicator +import Mathlib.Algebra.Order.Group.Abs +import Mathlib.Algebra.Order.Monoid.Canonical.Defs +import Mathlib.Order.ConditionallyCompleteLattice.Basic + +/-! +# Support of a function in an order + +This file relates the support of a function to order constructions. +-/ + +open Set + +variable {ι : Sort*} {α β M : Type*} + +namespace Function +variable [One M] + +@[to_additive] +lemma mulSupport_sup [SemilatticeSup M] (f g : α → M) : + mulSupport (fun x ↦ f x ⊔ g x) ⊆ mulSupport f ∪ mulSupport g := + mulSupport_binop_subset (· ⊔ ·) sup_idem f g +#align function.mul_support_sup Function.mulSupport_sup +#align function.support_sup Function.support_sup + +@[to_additive] +lemma mulSupport_inf [SemilatticeInf M] (f g : α → M) : + mulSupport (fun x ↦ f x ⊓ g x) ⊆ mulSupport f ∪ mulSupport g := + mulSupport_binop_subset (· ⊓ ·) inf_idem f g +#align function.mul_support_inf Function.mulSupport_inf +#align function.support_inf Function.support_inf + +@[to_additive] +lemma mulSupport_max [LinearOrder M] (f g : α → M) : + mulSupport (fun x ↦ max (f x) (g x)) ⊆ mulSupport f ∪ mulSupport g := mulSupport_sup f g +#align function.mul_support_max Function.mulSupport_max +#align function.support_max Function.support_max + +@[to_additive] +lemma mulSupport_min [LinearOrder M] (f g : α → M) : + mulSupport (fun x ↦ min (f x) (g x)) ⊆ mulSupport f ∪ mulSupport g := mulSupport_inf f g +#align function.mul_support_min Function.mulSupport_min +#align function.support_min Function.support_min + +@[to_additive] +lemma mulSupport_iSup [ConditionallyCompleteLattice M] [Nonempty ι] (f : ι → α → M) : + mulSupport (fun x ↦ ⨆ i, f i x) ⊆ ⋃ i, mulSupport (f i) := by + simp only [mulSupport_subset_iff', mem_iUnion, not_exists, nmem_mulSupport] + intro x hx + simp only [hx, ciSup_const] +#align function.mul_support_supr Function.mulSupport_iSup +#align function.support_supr Function.support_iSup + +@[to_additive] +lemma mulSupport_iInf [ConditionallyCompleteLattice M] [Nonempty ι] (f : ι → α → M) : + mulSupport (fun x ↦ ⨅ i, f i x) ⊆ ⋃ i, mulSupport (f i) := mulSupport_iSup (M := Mᵒᵈ) f +#align function.mul_support_infi Function.mulSupport_iInf +#align function.support_infi Function.support_iInf + +end Function + +namespace Set + +section LE +variable [LE M] [One M] {s t : Set α} {f g : α → M} {a : α} {y : M} + +@[to_additive] +lemma mulIndicator_apply_le' (hfg : a ∈ s → f a ≤ y) (hg : a ∉ s → 1 ≤ y) : + mulIndicator s f a ≤ y := by + by_cases ha : a ∈ s + · simpa [ha] using hfg ha + · simpa [ha] using hg ha +#align set.mul_indicator_apply_le' Set.mulIndicator_apply_le' +#align set.indicator_apply_le' Set.indicator_apply_le' + +@[to_additive] +lemma mulIndicator_le' (hfg : ∀ a ∈ s, f a ≤ g a) (hg : ∀ a, a ∉ s → 1 ≤ g a) : + mulIndicator s f ≤ g := fun _ ↦ mulIndicator_apply_le' (hfg _) (hg _) +#align set.mul_indicator_le' Set.mulIndicator_le' +#align set.indicator_le' Set.indicator_le' + +@[to_additive] +lemma le_mulIndicator_apply (hfg : a ∈ s → y ≤ g a) (hf : a ∉ s → y ≤ 1) : + y ≤ mulIndicator s g a := mulIndicator_apply_le' (M := Mᵒᵈ) hfg hf +#align set.le_mul_indicator_apply Set.le_mulIndicator_apply +#align set.le_indicator_apply Set.le_indicator_apply + +@[to_additive] +lemma le_mulIndicator (hfg : ∀ a ∈ s, f a ≤ g a) (hf : ∀ (a) (_ : a ∉ s), f a ≤ 1) : + f ≤ mulIndicator s g := fun _ ↦ le_mulIndicator_apply (hfg _) (hf _) +#align set.le_mul_indicator Set.le_mulIndicator +#align set.le_indicator Set.le_indicator + +end LE + +section Preorder +variable [Preorder M] [One M] {s t : Set α} {f g : α → M} {a : α} {y : M} + +@[to_additive indicator_apply_nonneg] +lemma one_le_mulIndicator_apply (h : a ∈ s → 1 ≤ f a) : 1 ≤ mulIndicator s f a := + le_mulIndicator_apply h fun _ ↦ le_rfl +#align set.one_le_mul_indicator_apply Set.one_le_mulIndicator_apply +#align set.indicator_apply_nonneg Set.indicator_apply_nonneg + +@[to_additive indicator_nonneg] +lemma one_le_mulIndicator (h : ∀ a ∈ s, 1 ≤ f a) (a : α) : 1 ≤ mulIndicator s f a := + one_le_mulIndicator_apply (h a) +#align set.one_le_mul_indicator Set.one_le_mulIndicator +#align set.indicator_nonneg Set.indicator_nonneg + +@[to_additive] +lemma mulIndicator_apply_le_one (h : a ∈ s → f a ≤ 1) : mulIndicator s f a ≤ 1 := + mulIndicator_apply_le' h fun _ ↦ le_rfl +#align set.mul_indicator_apply_le_one Set.mulIndicator_apply_le_one +#align set.indicator_apply_nonpos Set.indicator_apply_nonpos + +@[to_additive] +lemma mulIndicator_le_one (h : ∀ a ∈ s, f a ≤ 1) (a : α) : mulIndicator s f a ≤ 1 := + mulIndicator_apply_le_one (h a) +#align set.mul_indicator_le_one Set.mulIndicator_le_one +#align set.indicator_nonpos Set.indicator_nonpos + +@[to_additive] +lemma mulIndicator_le_mulIndicator (h : f a ≤ g a) : mulIndicator s f a ≤ mulIndicator s g a := + mulIndicator_rel_mulIndicator le_rfl fun _ ↦ h +#align set.mul_indicator_le_mul_indicator Set.mulIndicator_le_mulIndicator +#align set.indicator_le_indicator Set.indicator_le_indicator + +attribute [mono] mulIndicator_le_mulIndicator indicator_le_indicator + +@[to_additive] +lemma mulIndicator_le_mulIndicator_of_subset (h : s ⊆ t) (hf : ∀ a, 1 ≤ f a) (a : α) : + mulIndicator s f a ≤ mulIndicator t f a := + mulIndicator_apply_le' + (fun ha ↦ le_mulIndicator_apply (fun _ ↦ le_rfl) fun hat ↦ (hat <| h ha).elim) fun _ ↦ + one_le_mulIndicator_apply fun _ ↦ hf _ +#align set.mul_indicator_le_mul_indicator_of_subset Set.mulIndicator_le_mulIndicator_of_subset +#align set.indicator_le_indicator_of_subset Set.indicator_le_indicator_of_subset + +@[to_additive] +lemma mulIndicator_le_self' (hf : ∀ (x) (_ : x ∉ s), 1 ≤ f x) : mulIndicator s f ≤ f := + mulIndicator_le' (fun _ _ ↦ le_rfl) hf +#align set.mul_indicator_le_self' Set.mulIndicator_le_self' +#align set.indicator_le_self' Set.indicator_le_self' + +end Preorder + +section LinearOrder +variable [Zero M] [LinearOrder M] + +lemma indicator_le_indicator_nonneg (s : Set α) (f : α → M) : + s.indicator f ≤ {a | 0 ≤ f a}.indicator f := by + intro a + classical + simp_rw [indicator_apply] + split_ifs + exacts [le_rfl, (not_le.1 ‹_›).le, ‹_›, le_rfl] +#align set.indicator_le_indicator_nonneg Set.indicator_le_indicator_nonneg + +lemma indicator_nonpos_le_indicator (s : Set α) (f : α → M) : + {a | f a ≤ 0}.indicator f ≤ s.indicator f := + indicator_le_indicator_nonneg (M := Mᵒᵈ) _ _ +#align set.indicator_nonpos_le_indicator Set.indicator_nonpos_le_indicator + +end LinearOrder + +section CompleteLattice +variable [CompleteLattice M] [One M] {s t : Set α} {f g : α → M} {a : α} {y : M} + +@[to_additive] +lemma mulIndicator_iUnion_apply (h1 : (⊥ : M) = 1) (s : ι → Set α) (f : α → M) (x : α) : + mulIndicator (⋃ i, s i) f x = ⨆ i, mulIndicator (s i) f x := by + by_cases hx : x ∈ ⋃ i, s i + · rw [mulIndicator_of_mem hx] + rw [mem_iUnion] at hx + refine' le_antisymm _ (iSup_le fun i ↦ mulIndicator_le_self' (fun x _ ↦ h1 ▸ bot_le) x) + rcases hx with ⟨i, hi⟩ + exact le_iSup_of_le i (ge_of_eq <| mulIndicator_of_mem hi _) + · rw [mulIndicator_of_not_mem hx] + simp only [mem_iUnion, not_exists] at hx + simp [hx, ← h1] +#align set.mul_indicator_Union_apply Set.mulIndicator_iUnion_apply +#align set.indicator_Union_apply Set.indicator_iUnion_apply + +variable [Nonempty ι] + +@[to_additive] +lemma mulIndicator_iInter_apply (h1 : (⊥ : M) = 1) (s : ι → Set α) (f : α → M) (x : α) : + mulIndicator (⋂ i, s i) f x = ⨅ i, mulIndicator (s i) f x := by + by_cases hx : x ∈ ⋂ i, s i + · rw [mulIndicator_of_mem hx] + rw [mem_iInter] at hx + refine le_antisymm ?_ (by simp only [mulIndicator_of_mem (hx _), ciInf_const, le_refl]) + exact le_iInf (fun j ↦ by simp only [mulIndicator_of_mem (hx j), le_refl]) + · rw [mulIndicator_of_not_mem hx] + simp only [mem_iInter, not_exists, not_forall] at hx + rcases hx with ⟨j, hj⟩ + refine le_antisymm (by simp only [← h1, le_iInf_iff, bot_le, forall_const]) ?_ + simpa [mulIndicator_of_not_mem hj] using (iInf_le (fun i ↦ (s i).mulIndicator f) j) x + +end CompleteLattice + +section CanonicallyOrderedCommMonoid + +variable [CanonicallyOrderedCommMonoid M] + +@[to_additive] +lemma mulIndicator_le_self (s : Set α) (f : α → M) : mulIndicator s f ≤ f := + mulIndicator_le_self' fun _ _ ↦ one_le _ +#align set.mul_indicator_le_self Set.mulIndicator_le_self +#align set.indicator_le_self Set.indicator_le_self + +@[to_additive] +lemma mulIndicator_apply_le {a : α} {s : Set α} {f g : α → M} (hfg : a ∈ s → f a ≤ g a) : + mulIndicator s f a ≤ g a := + mulIndicator_apply_le' hfg fun _ ↦ one_le _ +#align set.mul_indicator_apply_le Set.mulIndicator_apply_le +#align set.indicator_apply_le Set.indicator_apply_le + +@[to_additive] +lemma mulIndicator_le {s : Set α} {f g : α → M} (hfg : ∀ a ∈ s, f a ≤ g a) : + mulIndicator s f ≤ g := + mulIndicator_le' hfg fun _ _ ↦ one_le _ +#align set.mul_indicator_le Set.mulIndicator_le +#align set.indicator_le Set.indicator_le + +end CanonicallyOrderedCommMonoid + +section LinearOrderedAddCommGroup +variable [LinearOrderedAddCommGroup M] + +lemma abs_indicator_symmDiff (s t : Set α) (f : α → M) (x : α) : + |indicator (s ∆ t) f x| = |indicator s f x - indicator t f x| := + apply_indicator_symmDiff abs_neg s t f x + +end LinearOrderedAddCommGroup +end Set diff --git a/Mathlib/Algebra/Star/Basic.lean b/Mathlib/Algebra/Star/Basic.lean index 6ba1b26626cd9..b139858543a93 100644 --- a/Mathlib/Algebra/Star/Basic.lean +++ b/Mathlib/Algebra/Star/Basic.lean @@ -488,9 +488,9 @@ export StarModule (star_smul) attribute [simp] star_smul /-- A commutative star monoid is a star module over itself via `Monoid.toMulAction`. -/ -instance StarSemigroup.to_starModule [CommMonoid R] [StarMul R] : StarModule R R := +instance StarMul.toStarModule [CommMonoid R] [StarMul R] : StarModule R R := ⟨star_mul'⟩ -#align star_semigroup.to_star_module StarSemigroup.to_starModule +#align star_semigroup.to_star_module StarMul.toStarModule namespace RingHomInvPair diff --git a/Mathlib/Algebra/Star/StarAlgHom.lean b/Mathlib/Algebra/Star/StarAlgHom.lean index 8a9b7b3362da8..d7c8a3c477c70 100644 --- a/Mathlib/Algebra/Star/StarAlgHom.lean +++ b/Mathlib/Algebra/Star/StarAlgHom.lean @@ -450,6 +450,14 @@ theorem coe_id : ⇑(StarAlgHom.id R A) = id := rfl #align star_alg_hom.coe_id StarAlgHom.coe_id +/-- `algebraMap R A` as a `StarAlgHom` when `A` is a star algebra over `R`. -/ +@[simps] +def ofId (R A : Type*) [CommSemiring R] [StarRing R] [Semiring A] [StarMul A] + [Algebra R A] [StarModule R A] : R →⋆ₐ[R] A := + { Algebra.ofId R A with + toFun := algebraMap R A + map_star' := by simp [Algebra.algebraMap_eq_smul_one] } + end instance : Inhabited (A →⋆ₐ[R] A) := diff --git a/Mathlib/Analysis/Asymptotics/Asymptotics.lean b/Mathlib/Analysis/Asymptotics/Asymptotics.lean index 4a4494c843e03..4a6ecf09d8d13 100644 --- a/Mathlib/Analysis/Asymptotics/Asymptotics.lean +++ b/Mathlib/Analysis/Asymptotics/Asymptotics.lean @@ -6,7 +6,7 @@ Authors: Jeremy Avigad, Yury Kudryashov import Mathlib.Analysis.Normed.Group.InfiniteSum import Mathlib.Analysis.NormedSpace.Basic import Mathlib.Topology.Algebra.Order.LiminfLimsup -import Mathlib.Topology.LocalHomeomorph +import Mathlib.Topology.PartialHomeomorph #align_import analysis.asymptotics.asymptotics from "leanprover-community/mathlib"@"f2ce6086713c78a7f880485f7917ea547a215982" @@ -2233,14 +2233,14 @@ lemma Asymptotics.IsBigO.comp_summable_norm {ι E F : Type*} summable_of_isBigO hg <| hf.norm_norm.comp_tendsto <| tendsto_zero_iff_norm_tendsto_zero.2 hg.tendsto_cofinite_zero -namespace LocalHomeomorph +namespace PartialHomeomorph variable {α : Type*} {β : Type*} [TopologicalSpace α] [TopologicalSpace β] variable {E : Type*} [Norm E] {F : Type*} [Norm F] -/-- Transfer `IsBigOWith` over a `LocalHomeomorph`. -/ -theorem isBigOWith_congr (e : LocalHomeomorph α β) {b : β} (hb : b ∈ e.target) {f : β → E} +/-- Transfer `IsBigOWith` over a `PartialHomeomorph`. -/ +theorem isBigOWith_congr (e : PartialHomeomorph α β) {b : β} (hb : b ∈ e.target) {f : β → E} {g : β → F} {C : ℝ} : IsBigOWith C (𝓝 b) f g ↔ IsBigOWith C (𝓝 (e.symm b)) (f ∘ e) (g ∘ e) := ⟨fun h => h.comp_tendsto <| by @@ -2251,25 +2251,25 @@ theorem isBigOWith_congr (e : LocalHomeomorph α β) {b : β} (hb : b ∈ e.targ ((e.eventually_right_inverse hb).mono fun x hx => congr_arg f hx) ((e.eventually_right_inverse hb).mono fun x hx => congr_arg g hx)⟩ set_option linter.uppercaseLean3 false in -#align local_homeomorph.is_O_with_congr LocalHomeomorph.isBigOWith_congr +#align local_homeomorph.is_O_with_congr PartialHomeomorph.isBigOWith_congr -/-- Transfer `IsBigO` over a `LocalHomeomorph`. -/ -theorem isBigO_congr (e : LocalHomeomorph α β) {b : β} (hb : b ∈ e.target) {f : β → E} {g : β → F} : - f =O[𝓝 b] g ↔ (f ∘ e) =O[𝓝 (e.symm b)] (g ∘ e) := by +/-- Transfer `IsBigO` over a `PartialHomeomorph`. -/ +theorem isBigO_congr (e : PartialHomeomorph α β) {b : β} (hb : b ∈ e.target) {f : β → E} + {g : β → F} : f =O[𝓝 b] g ↔ (f ∘ e) =O[𝓝 (e.symm b)] (g ∘ e) := by simp only [IsBigO_def] exact exists_congr fun C => e.isBigOWith_congr hb set_option linter.uppercaseLean3 false in -#align local_homeomorph.is_O_congr LocalHomeomorph.isBigO_congr +#align local_homeomorph.is_O_congr PartialHomeomorph.isBigO_congr -/-- Transfer `IsLittleO` over a `LocalHomeomorph`. -/ -theorem isLittleO_congr (e : LocalHomeomorph α β) {b : β} (hb : b ∈ e.target) {f : β → E} +/-- Transfer `IsLittleO` over a `PartialHomeomorph`. -/ +theorem isLittleO_congr (e : PartialHomeomorph α β) {b : β} (hb : b ∈ e.target) {f : β → E} {g : β → F} : f =o[𝓝 b] g ↔ (f ∘ e) =o[𝓝 (e.symm b)] (g ∘ e) := by simp only [IsLittleO_def] exact forall₂_congr fun c _hc => e.isBigOWith_congr hb set_option linter.uppercaseLean3 false in -#align local_homeomorph.is_o_congr LocalHomeomorph.isLittleO_congr +#align local_homeomorph.is_o_congr PartialHomeomorph.isLittleO_congr -end LocalHomeomorph +end PartialHomeomorph namespace Homeomorph @@ -2282,7 +2282,7 @@ open Asymptotics /-- Transfer `IsBigOWith` over a `Homeomorph`. -/ theorem isBigOWith_congr (e : α ≃ₜ β) {b : β} {f : β → E} {g : β → F} {C : ℝ} : IsBigOWith C (𝓝 b) f g ↔ IsBigOWith C (𝓝 (e.symm b)) (f ∘ e) (g ∘ e) := - e.toLocalHomeomorph.isBigOWith_congr trivial + e.toPartialHomeomorph.isBigOWith_congr trivial set_option linter.uppercaseLean3 false in #align homeomorph.is_O_with_congr Homeomorph.isBigOWith_congr diff --git a/Mathlib/Analysis/Calculus/ContDiff/Basic.lean b/Mathlib/Analysis/Calculus/ContDiff/Basic.lean index 4bb803f9be188..c26ff10cf451b 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/Basic.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/Basic.lean @@ -1810,7 +1810,7 @@ then `f.symm` is `n` times continuously differentiable at the point `a`. This is one of the easy parts of the inverse function theorem: it assumes that we already have an inverse function. -/ -theorem LocalHomeomorph.contDiffAt_symm [CompleteSpace E] (f : LocalHomeomorph E F) +theorem PartialHomeomorph.contDiffAt_symm [CompleteSpace E] (f : PartialHomeomorph E F) {f₀' : E ≃L[𝕜] F} {a : F} (ha : a ∈ f.target) (hf₀' : HasFDerivAt f (f₀' : E →L[𝕜] F) (f.symm a)) (hf : ContDiffAt 𝕜 n f (f.symm a)) : ContDiffAt 𝕜 n f.symm a := by @@ -1855,7 +1855,7 @@ theorem LocalHomeomorph.contDiffAt_symm [CompleteSpace E] (f : LocalHomeomorph E · refine' contDiffAt_top.mpr _ intro n exact Itop n (contDiffAt_top.mp hf n) -#align local_homeomorph.cont_diff_at_symm LocalHomeomorph.contDiffAt_symm +#align local_homeomorph.cont_diff_at_symm PartialHomeomorph.contDiffAt_symm /-- If `f` is an `n` times continuously differentiable homeomorphism, and if the derivative of `f` at each point is a continuous linear equivalence, @@ -1867,7 +1867,7 @@ theorem Homeomorph.contDiff_symm [CompleteSpace E] (f : E ≃ₜ F) {f₀' : E (hf₀' : ∀ a, HasFDerivAt f (f₀' a : E →L[𝕜] F) a) (hf : ContDiff 𝕜 n (f : E → F)) : ContDiff 𝕜 n (f.symm : F → E) := contDiff_iff_contDiffAt.2 fun x => - f.toLocalHomeomorph.contDiffAt_symm (mem_univ x) (hf₀' _) hf.contDiffAt + f.toPartialHomeomorph.contDiffAt_symm (mem_univ x) (hf₀' _) hf.contDiffAt #align homeomorph.cont_diff_symm Homeomorph.contDiff_symm /-- Let `f` be a local homeomorphism of a nontrivially normed field, let `a` be a point in its @@ -1876,11 +1876,11 @@ target. if `f` is `n` times continuously differentiable at `f.symm a`, and if th This is one of the easy parts of the inverse function theorem: it assumes that we already have an inverse function. -/ -theorem LocalHomeomorph.contDiffAt_symm_deriv [CompleteSpace 𝕜] (f : LocalHomeomorph 𝕜 𝕜) +theorem PartialHomeomorph.contDiffAt_symm_deriv [CompleteSpace 𝕜] (f : PartialHomeomorph 𝕜 𝕜) {f₀' a : 𝕜} (h₀ : f₀' ≠ 0) (ha : a ∈ f.target) (hf₀' : HasDerivAt f f₀' (f.symm a)) (hf : ContDiffAt 𝕜 n f (f.symm a)) : ContDiffAt 𝕜 n f.symm a := f.contDiffAt_symm ha (hf₀'.hasFDerivAt_equiv h₀) hf -#align local_homeomorph.cont_diff_at_symm_deriv LocalHomeomorph.contDiffAt_symm_deriv +#align local_homeomorph.cont_diff_at_symm_deriv PartialHomeomorph.contDiffAt_symm_deriv /-- Let `f` be an `n` times continuously differentiable homeomorphism of a nontrivially normed field. Suppose that the derivative of `f` is never equal to zero. Then `f.symm` is `n` times @@ -1892,10 +1892,10 @@ theorem Homeomorph.contDiff_symm_deriv [CompleteSpace 𝕜] (f : 𝕜 ≃ₜ (h₀ : ∀ x, f' x ≠ 0) (hf' : ∀ x, HasDerivAt f (f' x) x) (hf : ContDiff 𝕜 n (f : 𝕜 → 𝕜)) : ContDiff 𝕜 n (f.symm : 𝕜 → 𝕜) := contDiff_iff_contDiffAt.2 fun x => - f.toLocalHomeomorph.contDiffAt_symm_deriv (h₀ _) (mem_univ x) (hf' _) hf.contDiffAt + f.toPartialHomeomorph.contDiffAt_symm_deriv (h₀ _) (mem_univ x) (hf' _) hf.contDiffAt #align homeomorph.cont_diff_symm_deriv Homeomorph.contDiff_symm_deriv -namespace LocalHomeomorph +namespace PartialHomeomorph variable (𝕜) @@ -1906,7 +1906,7 @@ such that `f` is `C^n` at `x` and `f.symm` is `C^n` at `y`. Note that `n` is a natural number, not `∞`, because the set of points of `C^∞`-smoothness of `f` is not guaranteed to be open. -/ @[simps! apply symm_apply source target] -def restrContDiff (f : LocalHomeomorph E F) (n : ℕ) : LocalHomeomorph E F := +def restrContDiff (f : PartialHomeomorph E F) (n : ℕ) : PartialHomeomorph E F := haveI H : f.IsImage {x | ContDiffAt 𝕜 n f x ∧ ContDiffAt 𝕜 n f.symm (f x)} {y | ContDiffAt 𝕜 n f.symm y ∧ ContDiffAt 𝕜 n f (f.symm y)} := fun x hx ↦ by simp [hx, and_comm] @@ -1914,13 +1914,13 @@ def restrContDiff (f : LocalHomeomorph E F) (n : ℕ) : LocalHomeomorph E F := inter_mem (f.open_source.mem_nhds hxs) <| hxf.eventually.and <| f.continuousAt hxs hxf'.eventually -lemma contDiffOn_restrContDiff_source (f : LocalHomeomorph E F) (n : ℕ) : +lemma contDiffOn_restrContDiff_source (f : PartialHomeomorph E F) (n : ℕ) : ContDiffOn 𝕜 n f (f.restrContDiff 𝕜 n).source := fun _x hx ↦ hx.2.1.contDiffWithinAt -lemma contDiffOn_restrContDiff_target (f : LocalHomeomorph E F) (n : ℕ) : +lemma contDiffOn_restrContDiff_target (f : PartialHomeomorph E F) (n : ℕ) : ContDiffOn 𝕜 n f.symm (f.restrContDiff 𝕜 n).target := fun _x hx ↦ hx.2.1.contDiffWithinAt -end LocalHomeomorph +end PartialHomeomorph end FunctionInverse diff --git a/Mathlib/Analysis/Calculus/Deriv/Inverse.lean b/Mathlib/Analysis/Calculus/Deriv/Inverse.lean index 71ad5b48850ef..aefe0e88c592e 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Inverse.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Inverse.lean @@ -76,11 +76,11 @@ at `a` in the strict sense. This is one of the easy parts of the inverse function theorem: it assumes that we already have an inverse function. -/ -theorem LocalHomeomorph.hasStrictDerivAt_symm (f : LocalHomeomorph 𝕜 𝕜) {a f' : 𝕜} +theorem PartialHomeomorph.hasStrictDerivAt_symm (f : PartialHomeomorph 𝕜 𝕜) {a f' : 𝕜} (ha : a ∈ f.target) (hf' : f' ≠ 0) (htff' : HasStrictDerivAt f f' (f.symm a)) : HasStrictDerivAt f.symm f'⁻¹ a := htff'.of_local_left_inverse (f.symm.continuousAt ha) hf' (f.eventually_right_inverse ha) -#align local_homeomorph.has_strict_deriv_at_symm LocalHomeomorph.hasStrictDerivAt_symm +#align local_homeomorph.has_strict_deriv_at_symm PartialHomeomorph.hasStrictDerivAt_symm /-- If `f (g y) = y` for `y` in some neighborhood of `a`, `g` is continuous at `a`, and `f` has an invertible derivative `f'` at `g a`, then `g` has the derivative `f'⁻¹` at `a`. @@ -98,10 +98,10 @@ nonzero derivative `f'` at `f.symm a`, then `f.symm` has the derivative `f'⁻¹ This is one of the easy parts of the inverse function theorem: it assumes that we already have an inverse function. -/ -theorem LocalHomeomorph.hasDerivAt_symm (f : LocalHomeomorph 𝕜 𝕜) {a f' : 𝕜} (ha : a ∈ f.target) +theorem PartialHomeomorph.hasDerivAt_symm (f : PartialHomeomorph 𝕜 𝕜) {a f' : 𝕜} (ha : a ∈ f.target) (hf' : f' ≠ 0) (htff' : HasDerivAt f f' (f.symm a)) : HasDerivAt f.symm f'⁻¹ a := htff'.of_local_left_inverse (f.symm.continuousAt ha) hf' (f.eventually_right_inverse ha) -#align local_homeomorph.has_deriv_at_symm LocalHomeomorph.hasDerivAt_symm +#align local_homeomorph.has_deriv_at_symm PartialHomeomorph.hasDerivAt_symm theorem HasDerivAt.eventually_ne (h : HasDerivAt f f' x) (hf' : f' ≠ 0) : ∀ᶠ z in 𝓝[≠] x, f z ≠ f x := diff --git a/Mathlib/Analysis/Calculus/FDeriv/Equiv.lean b/Mathlib/Analysis/Calculus/FDeriv/Equiv.lean index 14255476d5640..257012e267825 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Equiv.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Equiv.lean @@ -410,22 +410,22 @@ the derivative `f'⁻¹` at `a`. This is one of the easy parts of the inverse function theorem: it assumes that we already have an inverse function. -/ -theorem LocalHomeomorph.hasStrictFDerivAt_symm (f : LocalHomeomorph E F) {f' : E ≃L[𝕜] F} {a : F} - (ha : a ∈ f.target) (htff' : HasStrictFDerivAt f (f' : E →L[𝕜] F) (f.symm a)) : +theorem PartialHomeomorph.hasStrictFDerivAt_symm (f : PartialHomeomorph E F) {f' : E ≃L[𝕜] F} + {a : F} (ha : a ∈ f.target) (htff' : HasStrictFDerivAt f (f' : E →L[𝕜] F) (f.symm a)) : HasStrictFDerivAt f.symm (f'.symm : F →L[𝕜] E) a := htff'.of_local_left_inverse (f.symm.continuousAt ha) (f.eventually_right_inverse ha) -#align local_homeomorph.has_strict_fderiv_at_symm LocalHomeomorph.hasStrictFDerivAt_symm +#align local_homeomorph.has_strict_fderiv_at_symm PartialHomeomorph.hasStrictFDerivAt_symm /-- If `f` is a local homeomorphism defined on a neighbourhood of `f.symm a`, and `f` has an invertible derivative `f'` at `f.symm a`, then `f.symm` has the derivative `f'⁻¹` at `a`. This is one of the easy parts of the inverse function theorem: it assumes that we already have an inverse function. -/ -theorem LocalHomeomorph.hasFDerivAt_symm (f : LocalHomeomorph E F) {f' : E ≃L[𝕜] F} {a : F} +theorem PartialHomeomorph.hasFDerivAt_symm (f : PartialHomeomorph E F) {f' : E ≃L[𝕜] F} {a : F} (ha : a ∈ f.target) (htff' : HasFDerivAt f (f' : E →L[𝕜] F) (f.symm a)) : HasFDerivAt f.symm (f'.symm : F →L[𝕜] E) a := htff'.of_local_left_inverse (f.symm.continuousAt ha) (f.eventually_right_inverse ha) -#align local_homeomorph.has_fderiv_at_symm LocalHomeomorph.hasFDerivAt_symm +#align local_homeomorph.has_fderiv_at_symm PartialHomeomorph.hasFDerivAt_symm theorem HasFDerivWithinAt.eventually_ne (h : HasFDerivWithinAt f f' s x) (hf' : ∃ C, ∀ z, ‖z‖ ≤ C * ‖f' z‖) : ∀ᶠ z in 𝓝[s \ {x}] x, f z ≠ f x := by diff --git a/Mathlib/Analysis/Calculus/Implicit.lean b/Mathlib/Analysis/Calculus/Implicit.lean index e8a14eb50237d..42f6618ccd1a1 100644 --- a/Mathlib/Analysis/Calculus/Implicit.lean +++ b/Mathlib/Analysis/Calculus/Implicit.lean @@ -143,35 +143,35 @@ protected theorem hasStrictFDerivAt : at `a`, their derivatives `f'`, `g'` are surjective, and the kernels of these derivatives are complementary subspaces of `E`, then `x ↦ (f x, g x)` defines a local homeomorphism between `E` and `F × G`. In particular, `{x | f x = f a}` is locally homeomorphic to `G`. -/ -def toLocalHomeomorph : LocalHomeomorph E (F × G) := - φ.hasStrictFDerivAt.toLocalHomeomorph _ -#align implicit_function_data.to_local_homeomorph ImplicitFunctionData.toLocalHomeomorph +def toPartialHomeomorph : PartialHomeomorph E (F × G) := + φ.hasStrictFDerivAt.toPartialHomeomorph _ +#align implicit_function_data.to_local_homeomorph ImplicitFunctionData.toPartialHomeomorph /-- Implicit function theorem. If `f : E → F` and `g : E → G` are two maps strictly differentiable at `a`, their derivatives `f'`, `g'` are surjective, and the kernels of these derivatives are complementary subspaces of `E`, then `implicitFunction` is the unique (germ of a) map `φ : F → G → E` such that `f (φ y z) = y` and `g (φ y z) = z`. -/ def implicitFunction : F → G → E := - Function.curry <| φ.toLocalHomeomorph.symm + Function.curry <| φ.toPartialHomeomorph.symm #align implicit_function_data.implicit_function ImplicitFunctionData.implicitFunction @[simp] -theorem toLocalHomeomorph_coe : ⇑φ.toLocalHomeomorph = φ.prodFun := +theorem toPartialHomeomorph_coe : ⇑φ.toPartialHomeomorph = φ.prodFun := rfl -#align implicit_function_data.to_local_homeomorph_coe ImplicitFunctionData.toLocalHomeomorph_coe +#align implicit_function_data.to_local_homeomorph_coe ImplicitFunctionData.toPartialHomeomorph_coe -theorem toLocalHomeomorph_apply (x : E) : φ.toLocalHomeomorph x = (φ.leftFun x, φ.rightFun x) := +theorem toPartialHomeomorph_apply (x : E) : φ.toPartialHomeomorph x = (φ.leftFun x, φ.rightFun x) := rfl -#align implicit_function_data.to_local_homeomorph_apply ImplicitFunctionData.toLocalHomeomorph_apply +#align implicit_function_data.to_local_homeomorph_apply ImplicitFunctionData.toPartialHomeomorph_apply -theorem pt_mem_toLocalHomeomorph_source : φ.pt ∈ φ.toLocalHomeomorph.source := - φ.hasStrictFDerivAt.mem_toLocalHomeomorph_source -#align implicit_function_data.pt_mem_to_local_homeomorph_source ImplicitFunctionData.pt_mem_toLocalHomeomorph_source +theorem pt_mem_toPartialHomeomorph_source : φ.pt ∈ φ.toPartialHomeomorph.source := + φ.hasStrictFDerivAt.mem_toPartialHomeomorph_source +#align implicit_function_data.pt_mem_to_local_homeomorph_source ImplicitFunctionData.pt_mem_toPartialHomeomorph_source -theorem map_pt_mem_toLocalHomeomorph_target : - (φ.leftFun φ.pt, φ.rightFun φ.pt) ∈ φ.toLocalHomeomorph.target := - φ.toLocalHomeomorph.map_source <| φ.pt_mem_toLocalHomeomorph_source -#align implicit_function_data.map_pt_mem_to_local_homeomorph_target ImplicitFunctionData.map_pt_mem_toLocalHomeomorph_target +theorem map_pt_mem_toPartialHomeomorph_target : + (φ.leftFun φ.pt, φ.rightFun φ.pt) ∈ φ.toPartialHomeomorph.target := + φ.toPartialHomeomorph.map_source <| φ.pt_mem_toPartialHomeomorph_source +#align implicit_function_data.map_pt_mem_to_local_homeomorph_target ImplicitFunctionData.map_pt_mem_toPartialHomeomorph_target theorem prod_map_implicitFunction : ∀ᶠ p : F × G in 𝓝 (φ.prodFun φ.pt), φ.prodFun (φ.implicitFunction p.1 p.2) = p := @@ -262,10 +262,10 @@ def implicitFunctionDataOfComplemented (hf : HasStrictFDerivAt f f' a) (hf' : ra /-- A local homeomorphism between `E` and `F × f'.ker` sending level surfaces of `f` to vertical subspaces. -/ -def implicitToLocalHomeomorphOfComplemented (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) - (hker : (ker f').ClosedComplemented) : LocalHomeomorph E (F × ker f') := - (implicitFunctionDataOfComplemented f f' hf hf' hker).toLocalHomeomorph -#align has_strict_fderiv_at.implicit_to_local_homeomorph_of_complemented HasStrictFDerivAt.implicitToLocalHomeomorphOfComplemented +def implicitToPartialHomeomorphOfComplemented (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) + (hker : (ker f').ClosedComplemented) : PartialHomeomorph E (F × ker f') := + (implicitFunctionDataOfComplemented f f' hf hf' hker).toPartialHomeomorph +#align has_strict_fderiv_at.implicit_to_local_homeomorph_of_complemented HasStrictFDerivAt.implicitToPartialHomeomorphOfComplemented /-- Implicit function `g` defined by `f (g z y) = z`. -/ def implicitFunctionOfComplemented (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) @@ -276,55 +276,55 @@ def implicitFunctionOfComplemented (hf : HasStrictFDerivAt f f' a) (hf' : range end Defs @[simp] -theorem implicitToLocalHomeomorphOfComplemented_fst (hf : HasStrictFDerivAt f f' a) +theorem implicitToPartialHomeomorphOfComplemented_fst (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) (hker : (ker f').ClosedComplemented) (x : E) : - (hf.implicitToLocalHomeomorphOfComplemented f f' hf' hker x).fst = f x := + (hf.implicitToPartialHomeomorphOfComplemented f f' hf' hker x).fst = f x := rfl -#align has_strict_fderiv_at.implicit_to_local_homeomorph_of_complemented_fst HasStrictFDerivAt.implicitToLocalHomeomorphOfComplemented_fst +#align has_strict_fderiv_at.implicit_to_local_homeomorph_of_complemented_fst HasStrictFDerivAt.implicitToPartialHomeomorphOfComplemented_fst -theorem implicitToLocalHomeomorphOfComplemented_apply (hf : HasStrictFDerivAt f f' a) +theorem implicitToPartialHomeomorphOfComplemented_apply (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) (hker : (ker f').ClosedComplemented) (y : E) : - hf.implicitToLocalHomeomorphOfComplemented f f' hf' hker y = + hf.implicitToPartialHomeomorphOfComplemented f f' hf' hker y = (f y, Classical.choose hker (y - a)) := rfl -#align has_strict_fderiv_at.implicit_to_local_homeomorph_of_complemented_apply HasStrictFDerivAt.implicitToLocalHomeomorphOfComplemented_apply +#align has_strict_fderiv_at.implicit_to_local_homeomorph_of_complemented_apply HasStrictFDerivAt.implicitToPartialHomeomorphOfComplemented_apply @[simp] -theorem implicitToLocalHomeomorphOfComplemented_apply_ker (hf : HasStrictFDerivAt f f' a) +theorem implicitToPartialHomeomorphOfComplemented_apply_ker (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) (hker : (ker f').ClosedComplemented) (y : ker f') : - hf.implicitToLocalHomeomorphOfComplemented f f' hf' hker (y + a) = (f (y + a), y) := by - simp only [implicitToLocalHomeomorphOfComplemented_apply, add_sub_cancel, + hf.implicitToPartialHomeomorphOfComplemented f f' hf' hker (y + a) = (f (y + a), y) := by + simp only [implicitToPartialHomeomorphOfComplemented_apply, add_sub_cancel, Classical.choose_spec hker] -#align has_strict_fderiv_at.implicit_to_local_homeomorph_of_complemented_apply_ker HasStrictFDerivAt.implicitToLocalHomeomorphOfComplemented_apply_ker +#align has_strict_fderiv_at.implicit_to_local_homeomorph_of_complemented_apply_ker HasStrictFDerivAt.implicitToPartialHomeomorphOfComplemented_apply_ker @[simp] -theorem implicitToLocalHomeomorphOfComplemented_self (hf : HasStrictFDerivAt f f' a) +theorem implicitToPartialHomeomorphOfComplemented_self (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) (hker : (ker f').ClosedComplemented) : - hf.implicitToLocalHomeomorphOfComplemented f f' hf' hker a = (f a, 0) := by - simp [hf.implicitToLocalHomeomorphOfComplemented_apply] -#align has_strict_fderiv_at.implicit_to_local_homeomorph_of_complemented_self HasStrictFDerivAt.implicitToLocalHomeomorphOfComplemented_self + hf.implicitToPartialHomeomorphOfComplemented f f' hf' hker a = (f a, 0) := by + simp [hf.implicitToPartialHomeomorphOfComplemented_apply] +#align has_strict_fderiv_at.implicit_to_local_homeomorph_of_complemented_self HasStrictFDerivAt.implicitToPartialHomeomorphOfComplemented_self -theorem mem_implicitToLocalHomeomorphOfComplemented_source (hf : HasStrictFDerivAt f f' a) +theorem mem_implicitToPartialHomeomorphOfComplemented_source (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) (hker : (ker f').ClosedComplemented) : - a ∈ (hf.implicitToLocalHomeomorphOfComplemented f f' hf' hker).source := - ImplicitFunctionData.pt_mem_toLocalHomeomorph_source _ -#align has_strict_fderiv_at.mem_implicit_to_local_homeomorph_of_complemented_source HasStrictFDerivAt.mem_implicitToLocalHomeomorphOfComplemented_source + a ∈ (hf.implicitToPartialHomeomorphOfComplemented f f' hf' hker).source := + ImplicitFunctionData.pt_mem_toPartialHomeomorph_source _ +#align has_strict_fderiv_at.mem_implicit_to_local_homeomorph_of_complemented_source HasStrictFDerivAt.mem_implicitToPartialHomeomorphOfComplemented_source -theorem mem_implicitToLocalHomeomorphOfComplemented_target (hf : HasStrictFDerivAt f f' a) +theorem mem_implicitToPartialHomeomorphOfComplemented_target (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) (hker : (ker f').ClosedComplemented) : - (f a, (0 : ker f')) ∈ (hf.implicitToLocalHomeomorphOfComplemented f f' hf' hker).target := by - simpa only [implicitToLocalHomeomorphOfComplemented_self] using - (hf.implicitToLocalHomeomorphOfComplemented f f' hf' hker).map_source <| - hf.mem_implicitToLocalHomeomorphOfComplemented_source hf' hker -#align has_strict_fderiv_at.mem_implicit_to_local_homeomorph_of_complemented_target HasStrictFDerivAt.mem_implicitToLocalHomeomorphOfComplemented_target + (f a, (0 : ker f')) ∈ (hf.implicitToPartialHomeomorphOfComplemented f f' hf' hker).target := by + simpa only [implicitToPartialHomeomorphOfComplemented_self] using + (hf.implicitToPartialHomeomorphOfComplemented f f' hf' hker).map_source <| + hf.mem_implicitToPartialHomeomorphOfComplemented_source hf' hker +#align has_strict_fderiv_at.mem_implicit_to_local_homeomorph_of_complemented_target HasStrictFDerivAt.mem_implicitToPartialHomeomorphOfComplemented_target /-- `HasStrictFDerivAt.implicitFunctionOfComplemented` sends `(z, y)` to a point in `f ⁻¹' z`. -/ theorem map_implicitFunctionOfComplemented_eq (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) (hker : (ker f').ClosedComplemented) : ∀ᶠ p : F × ker f' in 𝓝 (f a, 0), f (hf.implicitFunctionOfComplemented f f' hf' hker p.1 p.2) = p.1 := - ((hf.implicitToLocalHomeomorphOfComplemented f f' hf' hker).eventually_right_inverse <| - hf.mem_implicitToLocalHomeomorphOfComplemented_target hf' hker).mono + ((hf.implicitToPartialHomeomorphOfComplemented f f' hf' hker).eventually_right_inverse <| + hf.mem_implicitToPartialHomeomorphOfComplemented_target hf' hker).mono fun ⟨_, _⟩ h => congr_arg Prod.fst h #align has_strict_fderiv_at.map_implicit_function_of_complemented_eq HasStrictFDerivAt.map_implicitFunctionOfComplemented_eq @@ -333,7 +333,7 @@ theorem map_implicitFunctionOfComplemented_eq (hf : HasStrictFDerivAt f f' a) (h theorem eq_implicitFunctionOfComplemented (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) (hker : (ker f').ClosedComplemented) : ∀ᶠ x in 𝓝 a, hf.implicitFunctionOfComplemented f f' hf' hker (f x) - (hf.implicitToLocalHomeomorphOfComplemented f f' hf' hker x).snd = x := + (hf.implicitToPartialHomeomorphOfComplemented f f' hf' hker x).snd = x := (implicitFunctionDataOfComplemented f f' hf hf' hker).implicitFunction_apply_image #align has_strict_fderiv_at.eq_implicit_function_of_complemented HasStrictFDerivAt.eq_implicitFunctionOfComplemented @@ -341,9 +341,9 @@ theorem eq_implicitFunctionOfComplemented (hf : HasStrictFDerivAt f f' a) (hf' : theorem implicitFunctionOfComplemented_apply_image (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) (hker : (ker f').ClosedComplemented) : hf.implicitFunctionOfComplemented f f' hf' hker (f a) 0 = a := by - simpa only [implicitToLocalHomeomorphOfComplemented_self] using - (hf.implicitToLocalHomeomorphOfComplemented f f' hf' hker).left_inv - (hf.mem_implicitToLocalHomeomorphOfComplemented_source hf' hker) + simpa only [implicitToPartialHomeomorphOfComplemented_self] using + (hf.implicitToPartialHomeomorphOfComplemented f f' hf' hker).left_inv + (hf.mem_implicitToPartialHomeomorphOfComplemented_source hf' hker) #align has_strict_fderiv_at.implicit_function_of_complemented_apply_image HasStrictFDerivAt.implicitFunctionOfComplemented_apply_image theorem to_implicitFunctionOfComplemented (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) @@ -393,60 +393,60 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] [CompleteSpace 𝕜] {E : /-- Given a map `f : E → F` to a finite dimensional space with a surjective derivative `f'`, returns a local homeomorphism between `E` and `F × ker f'`. -/ -def implicitToLocalHomeomorph (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) : - LocalHomeomorph E (F × ker f') := +def implicitToPartialHomeomorph (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) : + PartialHomeomorph E (F × ker f') := haveI := FiniteDimensional.complete 𝕜 F - hf.implicitToLocalHomeomorphOfComplemented f f' hf' + hf.implicitToPartialHomeomorphOfComplemented f f' hf' f'.ker_closedComplemented_of_finiteDimensional_range -#align has_strict_fderiv_at.implicit_to_local_homeomorph HasStrictFDerivAt.implicitToLocalHomeomorph +#align has_strict_fderiv_at.implicit_to_local_homeomorph HasStrictFDerivAt.implicitToPartialHomeomorph /-- Implicit function `g` defined by `f (g z y) = z`. -/ def implicitFunction (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) : F → ker f' → E := - Function.curry <| (hf.implicitToLocalHomeomorph f f' hf').symm + Function.curry <| (hf.implicitToPartialHomeomorph f f' hf').symm #align has_strict_fderiv_at.implicit_function HasStrictFDerivAt.implicitFunction variable {f f'} @[simp] -theorem implicitToLocalHomeomorph_fst (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) (x : E) : - (hf.implicitToLocalHomeomorph f f' hf' x).fst = f x := +theorem implicitToPartialHomeomorph_fst (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) + (x : E) : (hf.implicitToPartialHomeomorph f f' hf' x).fst = f x := rfl -#align has_strict_fderiv_at.implicit_to_local_homeomorph_fst HasStrictFDerivAt.implicitToLocalHomeomorph_fst +#align has_strict_fderiv_at.implicit_to_local_homeomorph_fst HasStrictFDerivAt.implicitToPartialHomeomorph_fst @[simp] -theorem implicitToLocalHomeomorph_apply_ker (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) - (y : ker f') : hf.implicitToLocalHomeomorph f f' hf' (y + a) = (f (y + a), y) := +theorem implicitToPartialHomeomorph_apply_ker (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) + (y : ker f') : hf.implicitToPartialHomeomorph f f' hf' (y + a) = (f (y + a), y) := -- porting note: had to add `haveI` (here and below) haveI := FiniteDimensional.complete 𝕜 F - implicitToLocalHomeomorphOfComplemented_apply_ker .. -#align has_strict_fderiv_at.implicit_to_local_homeomorph_apply_ker HasStrictFDerivAt.implicitToLocalHomeomorph_apply_ker + implicitToPartialHomeomorphOfComplemented_apply_ker .. +#align has_strict_fderiv_at.implicit_to_local_homeomorph_apply_ker HasStrictFDerivAt.implicitToPartialHomeomorph_apply_ker @[simp] -theorem implicitToLocalHomeomorph_self (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) : - hf.implicitToLocalHomeomorph f f' hf' a = (f a, 0) := +theorem implicitToPartialHomeomorph_self (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) : + hf.implicitToPartialHomeomorph f f' hf' a = (f a, 0) := haveI := FiniteDimensional.complete 𝕜 F - implicitToLocalHomeomorphOfComplemented_self .. -#align has_strict_fderiv_at.implicit_to_local_homeomorph_self HasStrictFDerivAt.implicitToLocalHomeomorph_self + implicitToPartialHomeomorphOfComplemented_self .. +#align has_strict_fderiv_at.implicit_to_local_homeomorph_self HasStrictFDerivAt.implicitToPartialHomeomorph_self -theorem mem_implicitToLocalHomeomorph_source (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) : - a ∈ (hf.implicitToLocalHomeomorph f f' hf').source := +theorem mem_implicitToPartialHomeomorph_source (hf : HasStrictFDerivAt f f' a) + (hf' : range f' = ⊤) : a ∈ (hf.implicitToPartialHomeomorph f f' hf').source := haveI := FiniteDimensional.complete 𝕜 F - ImplicitFunctionData.pt_mem_toLocalHomeomorph_source _ -#align has_strict_fderiv_at.mem_implicit_to_local_homeomorph_source HasStrictFDerivAt.mem_implicitToLocalHomeomorph_source + ImplicitFunctionData.pt_mem_toPartialHomeomorph_source _ +#align has_strict_fderiv_at.mem_implicit_to_local_homeomorph_source HasStrictFDerivAt.mem_implicitToPartialHomeomorph_source -theorem mem_implicitToLocalHomeomorph_target (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) : - (f a, (0 : ker f')) ∈ (hf.implicitToLocalHomeomorph f f' hf').target := +theorem mem_implicitToPartialHomeomorph_target (hf : HasStrictFDerivAt f f' a) + (hf' : range f' = ⊤) : (f a, (0 : ker f')) ∈ (hf.implicitToPartialHomeomorph f f' hf').target := haveI := FiniteDimensional.complete 𝕜 F - mem_implicitToLocalHomeomorphOfComplemented_target .. -#align has_strict_fderiv_at.mem_implicit_to_local_homeomorph_target HasStrictFDerivAt.mem_implicitToLocalHomeomorph_target + mem_implicitToPartialHomeomorphOfComplemented_target .. +#align has_strict_fderiv_at.mem_implicit_to_local_homeomorph_target HasStrictFDerivAt.mem_implicitToPartialHomeomorph_target theorem tendsto_implicitFunction (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) {α : Type*} {l : Filter α} {g₁ : α → F} {g₂ : α → ker f'} (h₁ : Tendsto g₁ l (𝓝 <| f a)) (h₂ : Tendsto g₂ l (𝓝 0)) : Tendsto (fun t => hf.implicitFunction f f' hf' (g₁ t) (g₂ t)) l (𝓝 a) := by - refine' ((hf.implicitToLocalHomeomorph f f' hf').tendsto_symm - (hf.mem_implicitToLocalHomeomorph_source hf')).comp _ - rw [implicitToLocalHomeomorph_self] + refine' ((hf.implicitToPartialHomeomorph f f' hf').tendsto_symm + (hf.mem_implicitToPartialHomeomorph_source hf')).comp _ + rw [implicitToPartialHomeomorph_self] exact h₁.prod_mk_nhds h₂ #align has_strict_fderiv_at.tendsto_implicit_function HasStrictFDerivAt.tendsto_implicitFunction @@ -471,7 +471,7 @@ theorem implicitFunction_apply_image (hf : HasStrictFDerivAt f f' a) (hf' : rang of some point. -/ theorem eq_implicitFunction (hf : HasStrictFDerivAt f f' a) (hf' : range f' = ⊤) : ∀ᶠ x in 𝓝 a, - hf.implicitFunction f f' hf' (f x) (hf.implicitToLocalHomeomorph f f' hf' x).snd = x := + hf.implicitFunction f f' hf' (f x) (hf.implicitToPartialHomeomorph f f' hf' x).snd = x := haveI := FiniteDimensional.complete 𝕜 F eq_implicitFunctionOfComplemented .. #align has_strict_fderiv_at.eq_implicit_function HasStrictFDerivAt.eq_implicitFunction diff --git a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean index 73d03a40bf415..7841016f61168 100644 --- a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean +++ b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean @@ -16,11 +16,14 @@ behave like `f a + f' (x - a)` near each `a ∈ s`. When `f'` is onto, we show that `f` is locally onto. When `f'` is a continuous linear equiv, we show that `f` is a homeomorphism -between `s` and `f '' s`. More precisely, we define `ApproximatesLinearOn.toLocalHomeomorph` to -be a `LocalHomeomorph` with `toFun = f`, `source = s`, and `target = f '' s`. +between `s` and `f '' s`. More precisely, we define `ApproximatesLinearOn.toPartialHomeomorph` to +be a `PartialHomeomorph` with `toFun = f`, `source = s`, and `target = f '' s`. +between `s` and `f '' s`. More precisely, we define `ApproximatesLinearOn.toPartialHomeomorph` to +be a `PartialHomeomorph` with `toFun = f`, `source = s`, and `target = f '' s`. Maps of this type naturally appear in the proof of the inverse function theorem (see next section), -and `ApproximatesLinearOn.toLocalHomeomorph` will imply that the locally inverse function +and `ApproximatesLinearOn.toPartialHomeomorph` will imply that the locally inverse function +and `ApproximatesLinearOn.toPartialHomeomorph` will imply that the locally inverse function exists. We define this auxiliary notion to split the proof of the inverse function theorem into small @@ -353,27 +356,28 @@ protected theorem surjective [CompleteSpace E] (hf : ApproximatesLinearOn f (f' #align approximates_linear_on.surjective ApproximatesLinearOn.surjective /-- A map approximating a linear equivalence on a set defines a local equivalence on this set. -Should not be used outside of this file, because it is superseded by `toLocalHomeomorph` below. +Should not be used outside of this file, because it is superseded by `toPartialHomeomorph` below. This is a first step towards the inverse function. -/ -def toLocalEquiv (hf : ApproximatesLinearOn f (f' : E →L[𝕜] F) s c) - (hc : Subsingleton E ∨ c < N⁻¹) : LocalEquiv E F := - (hf.injOn hc).toLocalEquiv _ _ -#align approximates_linear_on.to_local_equiv ApproximatesLinearOn.toLocalEquiv +def toPartialEquiv (hf : ApproximatesLinearOn f (f' : E →L[𝕜] F) s c) + (hc : Subsingleton E ∨ c < N⁻¹) : PartialEquiv E F := + (hf.injOn hc).toPartialEquiv _ _ +#align approximates_linear_on.to_local_equiv ApproximatesLinearOn.toPartialEquiv -/-- The inverse function is continuous on `f '' s`. Use properties of `LocalHomeomorph` instead. -/ +/-- The inverse function is continuous on `f '' s`. +Use properties of `PartialHomeomorph` instead. -/ theorem inverse_continuousOn (hf : ApproximatesLinearOn f (f' : E →L[𝕜] F) s c) - (hc : Subsingleton E ∨ c < N⁻¹) : ContinuousOn (hf.toLocalEquiv hc).symm (f '' s) := by + (hc : Subsingleton E ∨ c < N⁻¹) : ContinuousOn (hf.toPartialEquiv hc).symm (f '' s) := by apply continuousOn_iff_continuous_restrict.2 - refine' ((hf.antilipschitz hc).to_rightInvOn' _ (hf.toLocalEquiv hc).right_inv').continuous - exact fun x hx => (hf.toLocalEquiv hc).map_target hx + refine' ((hf.antilipschitz hc).to_rightInvOn' _ (hf.toPartialEquiv hc).right_inv').continuous + exact fun x hx => (hf.toPartialEquiv hc).map_target hx #align approximates_linear_on.inverse_continuous_on ApproximatesLinearOn.inverse_continuousOn /-- The inverse function is approximated linearly on `f '' s` by `f'.symm`. -/ theorem to_inv (hf : ApproximatesLinearOn f (f' : E →L[𝕜] F) s c) (hc : Subsingleton E ∨ c < N⁻¹) : - ApproximatesLinearOn (hf.toLocalEquiv hc).symm (f'.symm : F →L[𝕜] E) (f '' s) + ApproximatesLinearOn (hf.toPartialEquiv hc).symm (f'.symm : F →L[𝕜] E) (f '' s) (N * (N⁻¹ - c)⁻¹ * c) := fun x hx y hy ↦ by - set A := hf.toLocalEquiv hc + set A := hf.toPartialEquiv hc have Af : ∀ z, A z = f z := fun z => rfl rcases (mem_image _ _ _).1 hx with ⟨x', x's, rfl⟩ rcases (mem_image _ _ _).1 hy with ⟨y', y's, rfl⟩ @@ -400,41 +404,42 @@ variable (f s) /-- Given a function `f` that approximates a linear equivalence on an open set `s`, returns a local homeomorph with `toFun = f` and `source = s`. -/ -def toLocalHomeomorph (hf : ApproximatesLinearOn f (f' : E →L[𝕜] F) s c) - (hc : Subsingleton E ∨ c < N⁻¹) (hs : IsOpen s) : LocalHomeomorph E F where - toLocalEquiv := hf.toLocalEquiv hc +def toPartialHomeomorph (hf : ApproximatesLinearOn f (f' : E →L[𝕜] F) s c) + (hc : Subsingleton E ∨ c < N⁻¹) (hs : IsOpen s) : PartialHomeomorph E F where + toPartialEquiv := hf.toPartialEquiv hc open_source := hs open_target := hf.open_image f'.toNonlinearRightInverse hs <| by rwa [f'.toEquiv.subsingleton_congr] at hc continuousOn_toFun := hf.continuousOn continuousOn_invFun := hf.inverse_continuousOn hc -#align approximates_linear_on.to_local_homeomorph ApproximatesLinearOn.toLocalHomeomorph +#align approximates_linear_on.to_local_homeomorph ApproximatesLinearOn.toPartialHomeomorph @[simp] -theorem toLocalHomeomorph_coe (hf : ApproximatesLinearOn f (f' : E →L[𝕜] F) s c) +theorem toPartialHomeomorph_coe (hf : ApproximatesLinearOn f (f' : E →L[𝕜] F) s c) (hc : Subsingleton E ∨ c < N⁻¹) (hs : IsOpen s) : - (hf.toLocalHomeomorph f s hc hs : E → F) = f := + (hf.toPartialHomeomorph f s hc hs : E → F) = f := rfl -#align approximates_linear_on.to_local_homeomorph_coe ApproximatesLinearOn.toLocalHomeomorph_coe +#align approximates_linear_on.to_local_homeomorph_coe ApproximatesLinearOn.toPartialHomeomorph_coe @[simp] -theorem toLocalHomeomorph_source (hf : ApproximatesLinearOn f (f' : E →L[𝕜] F) s c) - (hc : Subsingleton E ∨ c < N⁻¹) (hs : IsOpen s) : (hf.toLocalHomeomorph f s hc hs).source = s := +theorem toPartialHomeomorph_source (hf : ApproximatesLinearOn f (f' : E →L[𝕜] F) s c) + (hc : Subsingleton E ∨ c < N⁻¹) (hs : IsOpen s) : + (hf.toPartialHomeomorph f s hc hs).source = s := rfl -#align approximates_linear_on.to_local_homeomorph_source ApproximatesLinearOn.toLocalHomeomorph_source +#align approximates_linear_on.to_local_homeomorph_source ApproximatesLinearOn.toPartialHomeomorph_source @[simp] -theorem toLocalHomeomorph_target (hf : ApproximatesLinearOn f (f' : E →L[𝕜] F) s c) +theorem toPartialHomeomorph_target (hf : ApproximatesLinearOn f (f' : E →L[𝕜] F) s c) (hc : Subsingleton E ∨ c < N⁻¹) (hs : IsOpen s) : - (hf.toLocalHomeomorph f s hc hs).target = f '' s := + (hf.toPartialHomeomorph f s hc hs).target = f '' s := rfl -#align approximates_linear_on.to_local_homeomorph_target ApproximatesLinearOn.toLocalHomeomorph_target +#align approximates_linear_on.to_local_homeomorph_target ApproximatesLinearOn.toPartialHomeomorph_target /-- A function `f` that approximates a linear equivalence on the whole space is a homeomorphism. -/ def toHomeomorph (hf : ApproximatesLinearOn f (f' : E →L[𝕜] F) univ c) (hc : Subsingleton E ∨ c < N⁻¹) : E ≃ₜ F := by - refine' (hf.toLocalHomeomorph _ _ hc isOpen_univ).toHomeomorphOfSourceEqUnivTargetEqUniv rfl _ - rw [toLocalHomeomorph_target, image_univ, range_iff_surjective] + refine' (hf.toPartialHomeomorph _ _ hc isOpen_univ).toHomeomorphOfSourceEqUnivTargetEqUniv rfl _ + rw [toPartialHomeomorph_target, image_univ, range_iff_surjective] exact hf.surjective hc #align approximates_linear_on.to_homeomorph ApproximatesLinearOn.toHomeomorph @@ -442,7 +447,7 @@ end theorem closedBall_subset_target (hf : ApproximatesLinearOn f (f' : E →L[𝕜] F) s c) (hc : Subsingleton E ∨ c < N⁻¹) (hs : IsOpen s) {b : E} (ε0 : 0 ≤ ε) (hε : closedBall b ε ⊆ s) : - closedBall (f b) ((N⁻¹ - c) * ε) ⊆ (hf.toLocalHomeomorph f s hc hs).target := + closedBall (f b) ((N⁻¹ - c) * ε) ⊆ (hf.toPartialHomeomorph f s hc hs).target := (hf.surjOn_closedBall_of_nonlinearRightInverse f'.toNonlinearRightInverse ε0 hε).mono hε Subset.rfl #align approximates_linear_on.closed_ball_subset_target ApproximatesLinearOn.closedBall_subset_target diff --git a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ContDiff.lean b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ContDiff.lean index d3d57f77ac0c3..5561a84ba4f0d 100644 --- a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ContDiff.lean +++ b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ContDiff.lean @@ -25,32 +25,32 @@ variable {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕂 F] variable [CompleteSpace E] (f : E → F) {f' : E ≃L[𝕂] F} {a : E} /-- Given a `ContDiff` function over `𝕂` (which is `ℝ` or `ℂ`) with an invertible -derivative at `a`, returns a `LocalHomeomorph` with `to_fun = f` and `a ∈ source`. -/ -def toLocalHomeomorph {n : ℕ∞} (hf : ContDiffAt 𝕂 n f a) (hf' : HasFDerivAt f (f' : E →L[𝕂] F) a) - (hn : 1 ≤ n) : LocalHomeomorph E F := - (hf.hasStrictFDerivAt' hf' hn).toLocalHomeomorph f -#align cont_diff_at.to_local_homeomorph ContDiffAt.toLocalHomeomorph +derivative at `a`, returns a `PartialHomeomorph` with `to_fun = f` and `a ∈ source`. -/ +def toPartialHomeomorph {n : ℕ∞} (hf : ContDiffAt 𝕂 n f a) (hf' : HasFDerivAt f (f' : E →L[𝕂] F) a) + (hn : 1 ≤ n) : PartialHomeomorph E F := + (hf.hasStrictFDerivAt' hf' hn).toPartialHomeomorph f +#align cont_diff_at.to_local_homeomorph ContDiffAt.toPartialHomeomorph variable {f} @[simp] -theorem toLocalHomeomorph_coe {n : ℕ∞} (hf : ContDiffAt 𝕂 n f a) +theorem toPartialHomeomorph_coe {n : ℕ∞} (hf : ContDiffAt 𝕂 n f a) (hf' : HasFDerivAt f (f' : E →L[𝕂] F) a) (hn : 1 ≤ n) : - (hf.toLocalHomeomorph f hf' hn : E → F) = f := + (hf.toPartialHomeomorph f hf' hn : E → F) = f := rfl -#align cont_diff_at.to_local_homeomorph_coe ContDiffAt.toLocalHomeomorph_coe +#align cont_diff_at.to_local_homeomorph_coe ContDiffAt.toPartialHomeomorph_coe -theorem mem_toLocalHomeomorph_source {n : ℕ∞} (hf : ContDiffAt 𝕂 n f a) +theorem mem_toPartialHomeomorph_source {n : ℕ∞} (hf : ContDiffAt 𝕂 n f a) (hf' : HasFDerivAt f (f' : E →L[𝕂] F) a) (hn : 1 ≤ n) : - a ∈ (hf.toLocalHomeomorph f hf' hn).source := - (hf.hasStrictFDerivAt' hf' hn).mem_toLocalHomeomorph_source -#align cont_diff_at.mem_to_local_homeomorph_source ContDiffAt.mem_toLocalHomeomorph_source + a ∈ (hf.toPartialHomeomorph f hf' hn).source := + (hf.hasStrictFDerivAt' hf' hn).mem_toPartialHomeomorph_source +#align cont_diff_at.mem_to_local_homeomorph_source ContDiffAt.mem_toPartialHomeomorph_source -theorem image_mem_toLocalHomeomorph_target {n : ℕ∞} (hf : ContDiffAt 𝕂 n f a) +theorem image_mem_toPartialHomeomorph_target {n : ℕ∞} (hf : ContDiffAt 𝕂 n f a) (hf' : HasFDerivAt f (f' : E →L[𝕂] F) a) (hn : 1 ≤ n) : - f a ∈ (hf.toLocalHomeomorph f hf' hn).target := - (hf.hasStrictFDerivAt' hf' hn).image_mem_toLocalHomeomorph_target -#align cont_diff_at.image_mem_to_local_homeomorph_target ContDiffAt.image_mem_toLocalHomeomorph_target + f a ∈ (hf.toPartialHomeomorph f hf' hn).target := + (hf.hasStrictFDerivAt' hf' hn).image_mem_toPartialHomeomorph_target +#align cont_diff_at.image_mem_to_local_homeomorph_target ContDiffAt.image_mem_toPartialHomeomorph_target /-- Given a `ContDiff` function over `𝕂` (which is `ℝ` or `ℂ`) with an invertible derivative at `a`, returns a function that is locally inverse to `f`. -/ @@ -65,14 +65,14 @@ theorem localInverse_apply_image {n : ℕ∞} (hf : ContDiffAt 𝕂 n f a) #align cont_diff_at.local_inverse_apply_image ContDiffAt.localInverse_apply_image /-- Given a `ContDiff` function over `𝕂` (which is `ℝ` or `ℂ`) with an invertible derivative -at `a`, the inverse function (produced by `ContDiff.toLocalHomeomorph`) is +at `a`, the inverse function (produced by `ContDiff.toPartialHomeomorph`) is also `ContDiff`. -/ theorem to_localInverse {n : ℕ∞} (hf : ContDiffAt 𝕂 n f a) (hf' : HasFDerivAt f (f' : E →L[𝕂] F) a) (hn : 1 ≤ n) : ContDiffAt 𝕂 n (hf.localInverse hf' hn) (f a) := by have := hf.localInverse_apply_image hf' hn - apply (hf.toLocalHomeomorph f hf' hn).contDiffAt_symm - (image_mem_toLocalHomeomorph_target hf hf' hn) + apply (hf.toPartialHomeomorph f hf' hn).contDiffAt_symm + (image_mem_toPartialHomeomorph_target hf hf' hn) · convert hf' · convert hf #align cont_diff_at.to_local_inverse ContDiffAt.to_localInverse diff --git a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/FDeriv.lean b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/FDeriv.lean index 890db86a1b653..247015e779ac1 100644 --- a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/FDeriv.lean +++ b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/FDeriv.lean @@ -15,12 +15,12 @@ In this file we prove the inverse function theorem. It says that if a map `f : E has an invertible strict derivative `f'` at `a`, then it is locally invertible, and the inverse function has derivative `f' ⁻¹`. -We define `HasStrictFDerivAt.toLocalHomeomorph` that repacks a function `f` -with a `hf : HasStrictFDerivAt f f' a`, `f' : E ≃L[𝕜] F`, into a `LocalHomeomorph`. -The `toFun` of this `LocalHomeomorph` is defeq to `f`, so one can apply theorems -about `LocalHomeomorph` to `hf.toLocalHomeomorph f`, and get statements about `f`. +We define `HasStrictFDerivAt.toPartialHomeomorph` that repacks a function `f` +with a `hf : HasStrictFDerivAt f f' a`, `f' : E ≃L[𝕜] F`, into a `PartialHomeomorph`. +The `toFun` of this `PartialHomeomorph` is defeq to `f`, so one can apply theorems +about `PartialHomeomorph` to `hf.toPartialHomeomorph f`, and get statements about `f`. -Then we define `HasStrictFDerivAt.localInverse` to be the `invFun` of this `LocalHomeomorph`, +Then we define `HasStrictFDerivAt.localInverse` to be the `invFun` of this `PartialHomeomorph`, and prove two versions of the inverse function theorem: * `HasStrictFDerivAt.to_localInverse`: if `f` has an invertible derivative `f'` at `a` in the @@ -69,7 +69,7 @@ open ContinuousLinearMap (id) Let `f : E → F` be a map defined on a complete vector space `E`. Assume that `f` has an invertible derivative `f' : E ≃L[𝕜] F` at `a : E` in the strict sense. Then `f` approximates `f'` in the sense of `ApproximatesLinearOn` on an open neighborhood -of `a`, and we can apply `ApproximatesLinearOn.toLocalHomeomorph` to construct the inverse +of `a`, and we can apply `ApproximatesLinearOn.toPartialHomeomorph` to construct the inverse function. -/ namespace HasStrictFDerivAt @@ -115,39 +115,39 @@ theorem approximates_deriv_on_open_nhds (hf : HasStrictFDerivAt f (f' : E →L[ variable (f) -/-- Given a function with an invertible strict derivative at `a`, returns a `LocalHomeomorph` +/-- Given a function with an invertible strict derivative at `a`, returns a `PartialHomeomorph` with `to_fun = f` and `a ∈ source`. This is a part of the inverse function theorem. The other part `HasStrictFDerivAt.to_localInverse` states that the inverse function -of this `LocalHomeomorph` has derivative `f'.symm`. -/ -def toLocalHomeomorph (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : LocalHomeomorph E F := - ApproximatesLinearOn.toLocalHomeomorph f (Classical.choose hf.approximates_deriv_on_open_nhds) +of this `PartialHomeomorph` has derivative `f'.symm`. -/ +def toPartialHomeomorph (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : PartialHomeomorph E F := + ApproximatesLinearOn.toPartialHomeomorph f (Classical.choose hf.approximates_deriv_on_open_nhds) (Classical.choose_spec hf.approximates_deriv_on_open_nhds).2.2 (f'.subsingleton_or_nnnorm_symm_pos.imp id fun hf' => NNReal.half_lt_self <| ne_of_gt <| inv_pos.2 hf') (Classical.choose_spec hf.approximates_deriv_on_open_nhds).2.1 -#align has_strict_fderiv_at.to_local_homeomorph HasStrictFDerivAt.toLocalHomeomorph +#align has_strict_fderiv_at.to_local_homeomorph HasStrictFDerivAt.toPartialHomeomorph variable {f} @[simp] -theorem toLocalHomeomorph_coe (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : - (hf.toLocalHomeomorph f : E → F) = f := +theorem toPartialHomeomorph_coe (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : + (hf.toPartialHomeomorph f : E → F) = f := rfl -#align has_strict_fderiv_at.to_local_homeomorph_coe HasStrictFDerivAt.toLocalHomeomorph_coe +#align has_strict_fderiv_at.to_local_homeomorph_coe HasStrictFDerivAt.toPartialHomeomorph_coe -theorem mem_toLocalHomeomorph_source (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : - a ∈ (hf.toLocalHomeomorph f).source := +theorem mem_toPartialHomeomorph_source (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : + a ∈ (hf.toPartialHomeomorph f).source := (Classical.choose_spec hf.approximates_deriv_on_open_nhds).1 -#align has_strict_fderiv_at.mem_to_local_homeomorph_source HasStrictFDerivAt.mem_toLocalHomeomorph_source +#align has_strict_fderiv_at.mem_to_local_homeomorph_source HasStrictFDerivAt.mem_toPartialHomeomorph_source -theorem image_mem_toLocalHomeomorph_target (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : - f a ∈ (hf.toLocalHomeomorph f).target := - (hf.toLocalHomeomorph f).map_source hf.mem_toLocalHomeomorph_source -#align has_strict_fderiv_at.image_mem_to_local_homeomorph_target HasStrictFDerivAt.image_mem_toLocalHomeomorph_target +theorem image_mem_toPartialHomeomorph_target (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : + f a ∈ (hf.toPartialHomeomorph f).target := + (hf.toPartialHomeomorph f).map_source hf.mem_toPartialHomeomorph_source +#align has_strict_fderiv_at.image_mem_to_local_homeomorph_target HasStrictFDerivAt.image_mem_toPartialHomeomorph_target theorem map_nhds_eq_of_equiv (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : map f (𝓝 a) = 𝓝 (f a) := - (hf.toLocalHomeomorph f).map_nhds_eq hf.mem_toLocalHomeomorph_source + (hf.toPartialHomeomorph f).map_nhds_eq hf.mem_toPartialHomeomorph_source #align has_strict_fderiv_at.map_nhds_eq_of_equiv HasStrictFDerivAt.map_nhds_eq_of_equiv variable (f f' a) @@ -155,19 +155,19 @@ variable (f f' a) /-- Given a function `f` with an invertible derivative, returns a function that is locally inverse to `f`. -/ def localInverse (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : F → E := - (hf.toLocalHomeomorph f).symm + (hf.toPartialHomeomorph f).symm #align has_strict_fderiv_at.local_inverse HasStrictFDerivAt.localInverse variable {f f' a} theorem localInverse_def (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : - hf.localInverse f _ _ = (hf.toLocalHomeomorph f).symm := + hf.localInverse f _ _ = (hf.toPartialHomeomorph f).symm := rfl #align has_strict_fderiv_at.local_inverse_def HasStrictFDerivAt.localInverse_def theorem eventually_left_inverse (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : ∀ᶠ x in 𝓝 a, hf.localInverse f f' a (f x) = x := - (hf.toLocalHomeomorph f).eventually_left_inverse hf.mem_toLocalHomeomorph_source + (hf.toPartialHomeomorph f).eventually_left_inverse hf.mem_toPartialHomeomorph_source #align has_strict_fderiv_at.eventually_left_inverse HasStrictFDerivAt.eventually_left_inverse @[simp] @@ -178,30 +178,30 @@ theorem localInverse_apply_image (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) theorem eventually_right_inverse (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : ∀ᶠ y in 𝓝 (f a), f (hf.localInverse f f' a y) = y := - (hf.toLocalHomeomorph f).eventually_right_inverse' hf.mem_toLocalHomeomorph_source + (hf.toPartialHomeomorph f).eventually_right_inverse' hf.mem_toPartialHomeomorph_source #align has_strict_fderiv_at.eventually_right_inverse HasStrictFDerivAt.eventually_right_inverse theorem localInverse_continuousAt (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : ContinuousAt (hf.localInverse f f' a) (f a) := - (hf.toLocalHomeomorph f).continuousAt_symm hf.image_mem_toLocalHomeomorph_target + (hf.toPartialHomeomorph f).continuousAt_symm hf.image_mem_toPartialHomeomorph_target #align has_strict_fderiv_at.local_inverse_continuous_at HasStrictFDerivAt.localInverse_continuousAt theorem localInverse_tendsto (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : Tendsto (hf.localInverse f f' a) (𝓝 <| f a) (𝓝 a) := - (hf.toLocalHomeomorph f).tendsto_symm hf.mem_toLocalHomeomorph_source + (hf.toPartialHomeomorph f).tendsto_symm hf.mem_toPartialHomeomorph_source #align has_strict_fderiv_at.local_inverse_tendsto HasStrictFDerivAt.localInverse_tendsto theorem localInverse_unique (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) {g : F → E} (hg : ∀ᶠ x in 𝓝 a, g (f x) = x) : ∀ᶠ y in 𝓝 (f a), g y = localInverse f f' a hf y := eventuallyEq_of_left_inv_of_right_inv hg hf.eventually_right_inverse <| - (hf.toLocalHomeomorph f).tendsto_symm hf.mem_toLocalHomeomorph_source + (hf.toPartialHomeomorph f).tendsto_symm hf.mem_toPartialHomeomorph_source #align has_strict_fderiv_at.local_inverse_unique HasStrictFDerivAt.localInverse_unique /-- If `f` has an invertible derivative `f'` at `a` in the sense of strict differentiability `(hf)`, then the inverse function `hf.localInverse f` has derivative `f'.symm` at `f a`. -/ theorem to_localInverse (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : HasStrictFDerivAt (hf.localInverse f f' a) (f'.symm : F →L[𝕜] E) (f a) := - (hf.toLocalHomeomorph f).hasStrictFDerivAt_symm hf.image_mem_toLocalHomeomorph_target <| by + (hf.toPartialHomeomorph f).hasStrictFDerivAt_symm hf.image_mem_toPartialHomeomorph_target <| by simpa [← localInverse_def] using hf #align has_strict_fderiv_at.to_local_inverse HasStrictFDerivAt.to_localInverse diff --git a/Mathlib/Analysis/Convex/Jensen.lean b/Mathlib/Analysis/Convex/Jensen.lean index bf6da4db1a85c..bbfd6cae48d3c 100644 --- a/Mathlib/Analysis/Convex/Jensen.lean +++ b/Mathlib/Analysis/Convex/Jensen.lean @@ -5,6 +5,7 @@ Authors: Alexander Bentkamp, Yury Kudriashov -/ import Mathlib.Analysis.Convex.Combination import Mathlib.Analysis.Convex.Function +import Mathlib.Tactic.FieldSimp #align_import analysis.convex.jensen from "leanprover-community/mathlib"@"bfad3f455b388fbcc14c49d0cac884f774f14d20" @@ -21,8 +22,12 @@ Jensen's inequalities: convex combination of points under a convex function is less than the convex combination of the images. * `ConcaveOn.le_map_centerMass`, `ConcaveOn.le_map_sum`: Concave Jensen's inequality. +* `StrictConvexOn.map_sum_lt`: Convex strict Jensen inequality. +* `StrictConcaveOn.lt_map_sum`: Concave strict Jensen inequality. As corollaries, we get: +* `StrictConvexOn.map_sum_eq_iff`: Equality case of the convex Jensen inequality. +* `StrictConcaveOn.map_sum_eq_iff`: Equality case of the concave Jensen inequality. * `ConvexOn.exists_ge_of_mem_convexHull`: Maximum principle for convex functions. * `ConcaveOn.exists_le_of_mem_convexHull`: Minimum principle for concave functions. -/ @@ -40,7 +45,7 @@ variable {𝕜 E F β ι : Type*} section Jensen variable [LinearOrderedField 𝕜] [AddCommGroup E] [OrderedAddCommGroup β] [Module 𝕜 E] [Module 𝕜 β] - [OrderedSMul 𝕜 β] {s : Set E} {f : E → β} {t : Finset ι} {w : ι → 𝕜} {p : ι → E} + [OrderedSMul 𝕜 β] {s : Set E} {f : E → β} {t : Finset ι} {w : ι → 𝕜} {p : ι → E} {v : 𝕜} {q : E} /-- Convex **Jensen's inequality**, `Finset.centerMass` version. -/ theorem ConvexOn.map_centerMass_le (hf : ConvexOn 𝕜 s f) (h₀ : ∀ i ∈ t, 0 ≤ w i) @@ -73,6 +78,168 @@ theorem ConcaveOn.le_map_sum (hf : ConcaveOn 𝕜 s f) (h₀ : ∀ i ∈ t, 0 ConvexOn.map_sum_le (β := βᵒᵈ) hf h₀ h₁ hmem #align concave_on.le_map_sum ConcaveOn.le_map_sum +/-- Convex **Jensen's inequality** where an element plays a distinguished role. -/ +lemma ConvexOn.map_add_sum_le (hf : ConvexOn 𝕜 s f) (h₀ : ∀ i ∈ t, 0 ≤ w i) + (h₁ : v + ∑ i in t, w i = 1) (hmem : ∀ i ∈ t, p i ∈ s) (hv : 0 ≤ v) (hq : q ∈ s) : + f (v • q + ∑ i in t, w i • p i) ≤ v • f q + ∑ i in t, w i • f (p i) := by + let W j := Option.elim j v w + let P j := Option.elim j q p + have : f (∑ j in insertNone t, W j • P j) ≤ ∑ j in insertNone t, W j • f (P j) := + hf.map_sum_le (forall_mem_insertNone.2 ⟨hv, h₀⟩) (by simpa using h₁) + (forall_mem_insertNone.2 ⟨hq, hmem⟩) + simpa using this + +/-- Concave **Jensen's inequality** where an element plays a distinguished role. -/ +lemma ConcaveOn.map_add_sum_le (hf : ConcaveOn 𝕜 s f) (h₀ : ∀ i ∈ t, 0 ≤ w i) + (h₁ : v + ∑ i in t, w i = 1) (hmem : ∀ i ∈ t, p i ∈ s) (hv : 0 ≤ v) (hq : q ∈ s) : + v • f q + ∑ i in t, w i • f (p i) ≤ f (v • q + ∑ i in t, w i • p i) := + hf.dual.map_add_sum_le h₀ h₁ hmem hv hq + +/-! ### Strict Jensen inequality -/ + +/-- Convex **strict Jensen inequality**. + +If the function is strictly convex, the weights are strictly positive and the indexed family of +points is non-constant, then Jensen's inequality is strict. + +See also `StrictConvexOn.map_sum_eq_iff`. -/ +lemma StrictConvexOn.map_sum_lt (hf : StrictConvexOn 𝕜 s f) (h₀ : ∀ i ∈ t, 0 < w i) + (h₁ : ∑ i in t, w i = 1) (hmem : ∀ i ∈ t, p i ∈ s) (hp : ∃ j ∈ t, ∃ k ∈ t, p j ≠ p k) : + f (∑ i in t, w i • p i) < ∑ i in t, w i • f (p i) := by + classical + obtain ⟨j, hj, k, hk, hjk⟩ := hp + -- We replace `t` by `t \ {j, k}` + have : k ∈ t.erase j := mem_erase.2 ⟨ne_of_apply_ne _ hjk.symm, hk⟩ + let u := (t.erase j).erase k + have hj : j ∉ u := by simp + have hk : k ∉ u := by simp + have ht : t = (u.cons k hk).cons j (mem_cons.not.2 $ not_or_intro (ne_of_apply_ne _ hjk) hj) + · simp [insert_erase this, insert_erase ‹j ∈ t›, *] + clear_value u + subst ht + simp only [sum_cons] + have := h₀ j $ by simp + have := h₀ k $ by simp + let c := w j + w k + have hc : w j / c + w k / c = 1 := by field_simp + have hcj : c * (w j / c) = w j := by field_simp; ring + have hck : c * (w k / c) = w k := by field_simp; ring + calc f (w j • p j + (w k • p k + ∑ x in u, w x • p x)) + _ = f (c • ((w j / c) • p j + (w k / c) • p k) + ∑ x in u, w x • p x) := by + rw [smul_add, ← mul_smul, ← mul_smul, hcj, hck, add_assoc] + _ ≤ c • f ((w j / c) • p j + (w k / c) • p k) + ∑ x in u, w x • f (p x) := + -- apply the usual Jensen's inequality wrt the weighted average of the two distinguished + -- points and all the other points + hf.convexOn.map_add_sum_le (fun i hi ↦ (h₀ _ $ by simp [hi]).le) + (by simpa [-cons_eq_insert, ← add_assoc] using h₁) + (forall_of_forall_cons $ forall_of_forall_cons hmem) (by positivity) $ by + refine hf.1 (hmem _ $ by simp) (hmem _ $ by simp) ?_ ?_ hc <;> positivity + _ < c • ((w j / c) • f (p j) + (w k / c) • f (p k)) + ∑ x in u, w x • f (p x) := by + -- then apply the definition of strict convexity for the two distinguished points + gcongr; refine hf.2 (hmem _ $ by simp) (hmem _ $ by simp) hjk ?_ ?_ hc <;> positivity + _ = (w j • f (p j) + w k • f (p k)) + ∑ x in u, w x • f (p x) := by + rw [smul_add, ← mul_smul, ← mul_smul, hcj, hck] + _ = w j • f (p j) + (w k • f (p k) + ∑ x in u, w x • f (p x)) := by abel_nf + +/-- Concave **strict Jensen inequality**. + +If the function is strictly concave, the weights are strictly positive and the indexed family of +points is non-constant, then Jensen's inequality is strict. + +See also `StrictConcaveOn.map_sum_eq_iff`. -/ +lemma StrictConcaveOn.lt_map_sum (hf : StrictConcaveOn 𝕜 s f) (h₀ : ∀ i ∈ t, 0 < w i) + (h₁ : ∑ i in t, w i = 1) (hmem : ∀ i ∈ t, p i ∈ s) (hp : ∃ j ∈ t, ∃ k ∈ t, p j ≠ p k) : + ∑ i in t, w i • f (p i) < f (∑ i in t, w i • p i) := hf.dual.map_sum_lt h₀ h₁ hmem hp + +/-! ### Equality case of Jensen's inequality -/ + +/-- A form of the **equality case of Jensen's equality**. + +For a strictly convex function `f` and positive weights `w`, if +`f (∑ i in t, w i • p i) = ∑ i in t, w i • f (p i)`, then the points `p` are all equal. + +See also `StrictConvexOn.map_sum_eq_iff`. -/ +lemma StrictConvexOn.eq_of_le_map_sum (hf : StrictConvexOn 𝕜 s f) (h₀ : ∀ i ∈ t, 0 < w i) + (h₁ : ∑ i in t, w i = 1) (hmem : ∀ i ∈ t, p i ∈ s) + (h_eq : ∑ i in t, w i • f (p i) ≤ f (∑ i in t, w i • p i)) : + ∀ ⦃j⦄, j ∈ t → ∀ ⦃k⦄, k ∈ t → p j = p k := by + by_contra!; exact h_eq.not_lt $ hf.map_sum_lt h₀ h₁ hmem this + +/-- A form of the **equality case of Jensen's equality**. + +For a strictly concave function `f` and positive weights `w`, if +`f (∑ i in t, w i • p i) = ∑ i in t, w i • f (p i)`, then the points `p` are all equal. + +See also `StrictConcaveOn.map_sum_eq_iff`. -/ +lemma StrictConcaveOn.eq_of_map_sum_eq (hf : StrictConcaveOn 𝕜 s f) (h₀ : ∀ i ∈ t, 0 < w i) + (h₁ : ∑ i in t, w i = 1) (hmem : ∀ i ∈ t, p i ∈ s) + (h_eq : f (∑ i in t, w i • p i) ≤ ∑ i in t, w i • f (p i)) : + ∀ ⦃j⦄, j ∈ t → ∀ ⦃k⦄, k ∈ t → p j = p k := by + by_contra!; exact h_eq.not_lt $ hf.lt_map_sum h₀ h₁ hmem this + +/-- Canonical form of the **equality case of Jensen's equality**. + +For a strictly convex function `f` and positive weights `w`, we have +`f (∑ i in t, w i • p i) = ∑ i in t, w i • f (p i)` if and only if the points `p` are all equal +(and in fact all equal to their center of mass wrt `w`). -/ +lemma StrictConvexOn.map_sum_eq_iff {w : ι → 𝕜} {p : ι → E} (hf : StrictConvexOn 𝕜 s f) + (h₀ : ∀ i ∈ t, 0 < w i) (h₁ : ∑ i in t, w i = 1) (hmem : ∀ i ∈ t, p i ∈ s) : + f (∑ i in t, w i • p i) = ∑ i in t, w i • f (p i) ↔ ∀ j ∈ t, p j = ∑ i in t, w i • p i := by + constructor + · obtain rfl | ⟨i₀, hi₀⟩ := t.eq_empty_or_nonempty + · simp + intro h_eq i hi + have H : ∀ j ∈ t, p j = p i₀ := by + intro j hj + apply hf.eq_of_le_map_sum h₀ h₁ hmem h_eq.ge hj hi₀ + calc p i = p i₀ := by rw [H _ hi] + _ = (1:𝕜) • p i₀ := by simp + _ = (∑ j in t, w j) • p i₀ := by rw [h₁] + _ = ∑ j in t, (w j • p i₀) := by rw [sum_smul] + _ = ∑ j in t, (w j • p j) := by congr! 2 with j hj; rw [← H _ hj] + · intro h + have H : ∀ j ∈ t, w j • f (p j) = w j • f (∑ i in t, w i • p i) := by + intro j hj + simp [h j hj] + rw [sum_congr rfl H, ← sum_smul, h₁, one_smul] + +/-- Canonical form of the **equality case of Jensen's equality**. + +For a strictly concave function `f` and positive weights `w`, we have +`f (∑ i in t, w i • p i) = ∑ i in t, w i • f (p i)` if and only if the points `p` are all equal +(and in fact all equal to their center of mass wrt `w`). -/ +lemma StrictConcaveOn.map_sum_eq_iff (hf : StrictConcaveOn 𝕜 s f) (h₀ : ∀ i ∈ t, 0 < w i) + (h₁ : ∑ i in t, w i = 1) (hmem : ∀ i ∈ t, p i ∈ s) : + f (∑ i in t, w i • p i) = ∑ i in t, w i • f (p i) ↔ ∀ j ∈ t, p j = ∑ i in t, w i • p i := by + simpa using hf.neg.map_sum_eq_iff h₀ h₁ hmem + +/-- Canonical form of the **equality case of Jensen's equality**. + +For a strictly convex function `f` and nonnegative weights `w`, we have +`f (∑ i in t, w i • p i) = ∑ i in t, w i • f (p i)` if and only if the points `p` with nonzero +weight are all equal (and in fact all equal to their center of mass wrt `w`). -/ +lemma StrictConvexOn.map_sum_eq_iff' (hf : StrictConvexOn 𝕜 s f) (h₀ : ∀ i ∈ t, 0 ≤ w i) + (h₁ : ∑ i in t, w i = 1) (hmem : ∀ i ∈ t, p i ∈ s) : + f (∑ i in t, w i • p i) = ∑ i in t, w i • f (p i) ↔ + ∀ j ∈ t, w j ≠ 0 → p j = ∑ i in t, w i • p i := by + have hw (i) (_ : i ∈ t) : w i • p i ≠ 0 → w i ≠ 0 := by aesop + have hw' (i) (_ : i ∈ t) : w i • f (p i) ≠ 0 → w i ≠ 0 := by aesop + rw [← sum_filter_of_ne hw, ← sum_filter_of_ne hw', hf.map_sum_eq_iff] + · simp + · simp (config := { contextual := true }) [(h₀ _ _).gt_iff_ne] + · rwa [sum_filter_ne_zero] + · simp (config := { contextual := true }) [hmem _ _] + +/-- Canonical form of the **equality case of Jensen's equality**. + +For a strictly concave function `f` and nonnegative weights `w`, we have +`f (∑ i in t, w i • p i) = ∑ i in t, w i • f (p i)` if and only if the points `p` with nonzero +weight are all equal (and in fact all equal to their center of mass wrt `w`). -/ +lemma StrictConcaveOn.map_sum_eq_iff' (hf : StrictConcaveOn 𝕜 s f) (h₀ : ∀ i ∈ t, 0 ≤ w i) + (h₁ : ∑ i in t, w i = 1) (hmem : ∀ i ∈ t, p i ∈ s) : + f (∑ i in t, w i • p i) = ∑ i in t, w i • f (p i) ↔ + ∀ j ∈ t, w j ≠ 0 → p j = ∑ i in t, w i • p i := hf.dual.map_sum_eq_iff' h₀ h₁ hmem + end Jensen /-! ### Maximum principle -/ @@ -111,7 +278,7 @@ theorem ConvexOn.exists_ge_of_centerMass (h : ConvexOn 𝕜 s f) (hw₀ : ∀ i have hw' : (0 : 𝕜) < ∑ i in filter (fun i => w i ≠ 0) t, w i := by rwa [sum_filter_ne_zero] refine' exists_le_of_sum_le (nonempty_of_sum_ne_zero hw'.ne') _ rw [← sum_smul, ← smul_le_smul_iff_of_pos (inv_pos.2 hw'), inv_smul_smul₀ hw'.ne', ← - Finset.centerMass, Finset.centerMass_filter_ne_zero] + centerMass, centerMass_filter_ne_zero] exact h.map_centerMass_le hw₀ hw₁ hp #align convex_on.exists_ge_of_center_mass ConvexOn.exists_ge_of_centerMass diff --git a/Mathlib/Analysis/InnerProductSpace/Calculus.lean b/Mathlib/Analysis/InnerProductSpace/Calculus.lean index 6aac288bcb92f..f50f72439632c 100644 --- a/Mathlib/Analysis/InnerProductSpace/Calculus.lean +++ b/Mathlib/Analysis/InnerProductSpace/Calculus.lean @@ -377,13 +377,13 @@ open Metric hiding mem_nhds_iff variable {n : ℕ∞} {E : Type*} [NormedAddCommGroup E] [InnerProductSpace ℝ E] -theorem LocalHomeomorph.contDiff_univUnitBall : ContDiff ℝ n (univUnitBall : E → E) := by +theorem PartialHomeomorph.contDiff_univUnitBall : ContDiff ℝ n (univUnitBall : E → E) := by suffices ContDiff ℝ n fun x : E => (1 + ‖x‖ ^ 2 : ℝ).sqrt⁻¹ from this.smul contDiff_id have h : ∀ x : E, (0 : ℝ) < (1 : ℝ) + ‖x‖ ^ 2 := fun x => by positivity refine' ContDiff.inv _ fun x => Real.sqrt_ne_zero'.mpr (h x) exact (contDiff_const.add <| contDiff_norm_sq ℝ).sqrt fun x => (h x).ne' -theorem LocalHomeomorph.contDiffOn_univUnitBall_symm : +theorem PartialHomeomorph.contDiffOn_univUnitBall_symm : ContDiffOn ℝ n univUnitBall.symm (ball (0 : E) 1) := fun y hy ↦ by apply ContDiffAt.contDiffWithinAt suffices ContDiffAt ℝ n (fun y : E => (1 - ‖y‖ ^ 2 : ℝ).sqrt⁻¹) y from this.smul contDiffAt_id @@ -394,17 +394,17 @@ theorem LocalHomeomorph.contDiffOn_univUnitBall_symm : exact contDiffAt_const.sub (contDiff_norm_sq ℝ).contDiffAt theorem Homeomorph.contDiff_unitBall : ContDiff ℝ n fun x : E => (unitBall x : E) := - LocalHomeomorph.contDiff_univUnitBall + PartialHomeomorph.contDiff_univUnitBall #align cont_diff_homeomorph_unit_ball Homeomorph.contDiff_unitBall -@[deprecated LocalHomeomorph.contDiffOn_univUnitBall_symm] +@[deprecated PartialHomeomorph.contDiffOn_univUnitBall_symm] theorem Homeomorph.contDiffOn_unitBall_symm {f : E → E} (h : ∀ (y) (hy : y ∈ ball (0 : E) 1), f y = Homeomorph.unitBall.symm ⟨y, hy⟩) : ContDiffOn ℝ n f <| ball 0 1 := - LocalHomeomorph.contDiffOn_univUnitBall_symm.congr h + PartialHomeomorph.contDiffOn_univUnitBall_symm.congr h #align cont_diff_on_homeomorph_unit_ball_symm Homeomorph.contDiffOn_unitBall_symm -namespace LocalHomeomorph +namespace PartialHomeomorph variable {c : E} {r : ℝ} @@ -424,9 +424,9 @@ theorem contDiffOn_univBall_symm : unfold univBall; split_ifs with h · refine contDiffOn_univUnitBall_symm.comp (contDiff_unitBallBall_symm h).contDiffOn ?_ rw [← unitBallBall_source c r h, ← unitBallBall_target c r h] - apply LocalHomeomorph.symm_mapsTo + apply PartialHomeomorph.symm_mapsTo · exact contDiffOn_id.sub contDiffOn_const -end LocalHomeomorph +end PartialHomeomorph end DiffeomorphUnitBall diff --git a/Mathlib/Analysis/InnerProductSpace/TwoDim.lean b/Mathlib/Analysis/InnerProductSpace/TwoDim.lean index b958530fc5c7e..d1a8ee6492fe2 100644 --- a/Mathlib/Analysis/InnerProductSpace/TwoDim.lean +++ b/Mathlib/Analysis/InnerProductSpace/TwoDim.lean @@ -526,7 +526,7 @@ theorem kahler_neg_orientation (x y : E) : (-o).kahler x y = conj (o.kahler x y) theorem kahler_mul (a x y : E) : o.kahler x a * o.kahler a y = ‖a‖ ^ 2 * o.kahler x y := by trans ((‖a‖ ^ 2 :) : ℂ) * o.kahler x y - · ext + · apply Complex.ext · simp only [o.kahler_apply_apply, Complex.add_im, Complex.add_re, Complex.I_im, Complex.I_re, Complex.mul_im, Complex.mul_re, Complex.ofReal_im, Complex.ofReal_re, Complex.real_smul] rw [real_inner_comm a x, o.areaForm_swap x a] @@ -622,7 +622,7 @@ protected theorem rightAngleRotation (z : ℂ) : @[simp] protected theorem kahler (w z : ℂ) : Complex.orientation.kahler w z = conj w * z := by rw [Orientation.kahler_apply_apply] - ext1 <;> simp + apply Complex.ext <;> simp #align complex.kahler Complex.kahler end Complex diff --git a/Mathlib/Analysis/NormedSpace/HomeomorphBall.lean b/Mathlib/Analysis/NormedSpace/HomeomorphBall.lean index 3c4d74839ae28..eaf3d6f95a0ab 100644 --- a/Mathlib/Analysis/NormedSpace/HomeomorphBall.lean +++ b/Mathlib/Analysis/NormedSpace/HomeomorphBall.lean @@ -3,7 +3,7 @@ Copyright (c) 2021 Yury Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov, Oliver Nash -/ -import Mathlib.Topology.LocalHomeomorph +import Mathlib.Topology.PartialHomeomorph import Mathlib.Analysis.NormedSpace.AddTorsor import Mathlib.Analysis.NormedSpace.Pointwise @@ -17,14 +17,14 @@ In this file we show that a real (semi)normed vector space is homeomorphic to th We formalize it in two ways: - as a `Homeomorph`, see `Homeomorph.unitBall`; -- as a `LocalHomeomorph` with `source = Set.univ` and `target = Metric.ball (0 : E) 1`. +- as a `PartialHomeomorph` with `source = Set.univ` and `target = Metric.ball (0 : E) 1`. While the former approach is more natural, the latter approach provides us with a globally defined inverse function which makes it easier to say that this homeomorphism is in fact a diffeomorphism. We also show that the unit ball `Metric.ball (0 : E) 1` is homeomorphic -to a ball of positive radius in an affine space over `E`, see `LocalHomeomorph.unitBallBall`. +to a ball of positive radius in an affine space over `E`, see `PartialHomeomorph.unitBallBall`. ## Tags @@ -39,7 +39,7 @@ noncomputable section /-- Local homeomorphism between a real (semi)normed space and the unit ball. See also `Homeomorph.unitBall`. -/ @[simps (config := .lemmasOnly)] -def LocalHomeomorph.univUnitBall : LocalHomeomorph E E where +def PartialHomeomorph.univUnitBall : PartialHomeomorph E E where toFun x := (1 + ‖x‖ ^ 2).sqrt⁻¹ • x invFun y := (1 - ‖(y : E)‖ ^ 2).sqrt⁻¹ • (y : E) source := univ @@ -73,12 +73,12 @@ def LocalHomeomorph.univUnitBall : LocalHomeomorph E E where (continuousOn_const.sub (continuous_norm.continuousOn.pow _)).sqrt this) continuousOn_id @[simp] -theorem LocalHomeomorph.univUnitBall_apply_zero : univUnitBall (0 : E) = 0 := by - simp [LocalHomeomorph.univUnitBall_apply] +theorem PartialHomeomorph.univUnitBall_apply_zero : univUnitBall (0 : E) = 0 := by + simp [PartialHomeomorph.univUnitBall_apply] @[simp] -theorem LocalHomeomorph.univUnitBall_symm_apply_zero : univUnitBall.symm (0 : E) = 0 := by - simp [LocalHomeomorph.univUnitBall_symm_apply] +theorem PartialHomeomorph.univUnitBall_symm_apply_zero : univUnitBall.symm (0 : E) = 0 := by + simp [PartialHomeomorph.univUnitBall_symm_apply] /-- A (semi) normed real vector space is homeomorphic to the unit ball in the same space. This homeomorphism sends `x : E` to `(1 + ‖x‖²)^(- ½) • x`. @@ -86,41 +86,41 @@ This homeomorphism sends `x : E` to `(1 + ‖x‖²)^(- ½) • x`. In many cases the actual implementation is not important, so we don't mark the projection lemmas `Homeomorph.unitBall_apply_coe` and `Homeomorph.unitBall_symm_apply` as `@[simp]`. -See also `Homeomorph.contDiff_unitBall` and `LocalHomeomorph.contDiffOn_unitBall_symm` +See also `Homeomorph.contDiff_unitBall` and `PartialHomeomorph.contDiffOn_unitBall_symm` for smoothness properties that hold when `E` is an inner-product space. -/ @[simps! (config := .lemmasOnly)] def Homeomorph.unitBall : E ≃ₜ ball (0 : E) 1 := - (Homeomorph.Set.univ _).symm.trans LocalHomeomorph.univUnitBall.toHomeomorphSourceTarget + (Homeomorph.Set.univ _).symm.trans PartialHomeomorph.univUnitBall.toHomeomorphSourceTarget #align homeomorph_unit_ball Homeomorph.unitBall @[simp] theorem Homeomorph.coe_unitBall_apply_zero : (Homeomorph.unitBall (0 : E) : E) = 0 := - LocalHomeomorph.univUnitBall_apply_zero + PartialHomeomorph.univUnitBall_apply_zero #align coe_homeomorph_unit_ball_apply_zero Homeomorph.coe_unitBall_apply_zero variable {P : Type*} [PseudoMetricSpace P] [NormedAddTorsor E P] -namespace LocalHomeomorph +namespace PartialHomeomorph /-- Affine homeomorphism `(r • · +ᵥ c)` between a normed space and an add torsor over this space, -interpreted as a `LocalHomeomorph` between `Metric.ball 0 1` and `Metric.ball c r`. -/ +interpreted as a `PartialHomeomorph` between `Metric.ball 0 1` and `Metric.ball c r`. -/ @[simps!] -def unitBallBall (c : P) (r : ℝ) (hr : 0 < r) : LocalHomeomorph E P := +def unitBallBall (c : P) (r : ℝ) (hr : 0 < r) : PartialHomeomorph E P := ((Homeomorph.smulOfNeZero r hr.ne').trans - (IsometryEquiv.vaddConst c).toHomeomorph).toLocalHomeomorphOfImageEq + (IsometryEquiv.vaddConst c).toHomeomorph).toPartialHomeomorphOfImageEq (ball 0 1) isOpen_ball (ball c r) <| by change (IsometryEquiv.vaddConst c) ∘ (r • ·) '' ball (0 : E) 1 = ball c r rw [image_comp, image_smul, smul_unitBall hr.ne', IsometryEquiv.image_ball] simp [abs_of_pos hr] -/-- If `r > 0`, then `LocalHomeomorph.univBall c r` is a smooth local homeomorphism +/-- If `r > 0`, then `PartialHomeomorph.univBall c r` is a smooth local homeomorphism with `source = Set.univ` and `target = Metric.ball c r`. Otherwise, it is the translation by `c`. -Thus in all cases, it sends `0` to `c`, see `LocalHomeomorph.univBall_apply_zero`. -/ -def univBall (c : P) (r : ℝ) : LocalHomeomorph E P := +Thus in all cases, it sends `0` to `c`, see `PartialHomeomorph.univBall_apply_zero`. -/ +def univBall (c : P) (r : ℝ) : PartialHomeomorph E P := if h : 0 < r then univUnitBall.trans' (unitBallBall c r h) rfl - else (IsometryEquiv.vaddConst c).toHomeomorph.toLocalHomeomorph + else (IsometryEquiv.vaddConst c).toHomeomorph.toPartialHomeomorph @[simp] theorem univBall_source (c : P) (r : ℝ) : (univBall c r).source = univ := by diff --git a/Mathlib/Analysis/NormedSpace/IndicatorFunction.lean b/Mathlib/Analysis/NormedSpace/IndicatorFunction.lean index 7d8a04dedb73a..bc94ee7c2ac89 100644 --- a/Mathlib/Analysis/NormedSpace/IndicatorFunction.lean +++ b/Mathlib/Analysis/NormedSpace/IndicatorFunction.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Zhouhang Zhou, Yury Kudryashov -/ import Mathlib.Analysis.Normed.Group.Basic -import Mathlib.Algebra.IndicatorFunction +import Mathlib.Algebra.Order.Support #align_import analysis.normed_space.indicator_function from "leanprover-community/mathlib"@"17ef379e997badd73e5eabb4d38f11919ab3c4b3" diff --git a/Mathlib/Analysis/NormedSpace/SphereNormEquiv.lean b/Mathlib/Analysis/NormedSpace/SphereNormEquiv.lean index 3f60ef42c5c43..a259dbaa0ee8b 100644 --- a/Mathlib/Analysis/NormedSpace/SphereNormEquiv.lean +++ b/Mathlib/Analysis/NormedSpace/SphereNormEquiv.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Analysis.NormedSpace.Basic -import Mathlib.Topology.LocalHomeomorph +import Mathlib.Topology.PartialHomeomorph /-! # Homeomorphism between a normed space and sphere times `(0, +∞)` diff --git a/Mathlib/Analysis/SpecialFunctions/Arsinh.lean b/Mathlib/Analysis/SpecialFunctions/Arsinh.lean index 46ff37e5dd4db..6dc3283b72965 100644 --- a/Mathlib/Analysis/SpecialFunctions/Arsinh.lean +++ b/Mathlib/Analysis/SpecialFunctions/Arsinh.lean @@ -177,7 +177,7 @@ theorem arsinh_neg_iff : arsinh x < 0 ↔ x < 0 := #align real.arsinh_neg_iff Real.arsinh_neg_iff theorem hasStrictDerivAt_arsinh (x : ℝ) : HasStrictDerivAt arsinh (sqrt (1 + x ^ 2))⁻¹ x := by - convert sinhHomeomorph.toLocalHomeomorph.hasStrictDerivAt_symm (mem_univ x) (cosh_pos _).ne' + convert sinhHomeomorph.toPartialHomeomorph.hasStrictDerivAt_symm (mem_univ x) (cosh_pos _).ne' (hasStrictDerivAt_sinh _) using 2 exact (cosh_arsinh _).symm #align real.has_strict_deriv_at_arsinh Real.hasStrictDerivAt_arsinh diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean b/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean index d025ad19a7cca..5f325e53e83ac 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean @@ -58,7 +58,7 @@ theorem abs_mul_exp_arg_mul_I (x : ℂ) : ↑(abs x) * exp (arg x * I) = x := by rcases eq_or_ne x 0 with (rfl | hx) · simp · have : abs x ≠ 0 := abs.ne_zero hx - ext <;> field_simp [sin_arg, cos_arg hx, this, mul_comm (abs x)] + apply Complex.ext <;> field_simp [sin_arg, cos_arg hx, this, mul_comm (abs x)] set_option linter.uppercaseLean3 false in #align complex.abs_mul_exp_arg_mul_I Complex.abs_mul_exp_arg_mul_I diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/Circle.lean b/Mathlib/Analysis/SpecialFunctions/Complex/Circle.lean index dd3485214f5a1..687fe7258d91e 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/Circle.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/Circle.lean @@ -12,8 +12,8 @@ import Mathlib.Analysis.SpecialFunctions.Complex.Log # Maps on the unit circle In this file we prove some basic lemmas about `expMapCircle` and the restriction of `Complex.arg` -to the unit circle. These two maps define a local equivalence between `circle` and `ℝ`, see -`circle.argLocalEquiv` and `circle.argEquiv`, that sends the whole circle to `(-π, π]`. +to the unit circle. These two maps define a partial equivalence between `circle` and `ℝ`, see +`circle.argPartialEquiv` and `circle.argEquiv`, that sends the whole circle to `(-π, π]`. -/ @@ -45,10 +45,10 @@ theorem expMapCircle_arg (z : circle) : expMapCircle (arg z) = z := namespace circle -/-- `Complex.arg ∘ (↑)` and `expMapCircle` define a local equivalence between `circle` and `ℝ` +/-- `Complex.arg ∘ (↑)` and `expMapCircle` define a partial equivalence between `circle` and `ℝ` with `source = Set.univ` and `target = Set.Ioc (-π) π`. -/ @[simps (config := .asFn)] -noncomputable def argLocalEquiv : LocalEquiv circle ℝ where +noncomputable def argPartialEquiv : PartialEquiv circle ℝ where toFun := arg ∘ (↑) invFun := expMapCircle source := univ @@ -57,15 +57,15 @@ noncomputable def argLocalEquiv : LocalEquiv circle ℝ where map_target' := mapsTo_univ _ _ left_inv' z _ := expMapCircle_arg z right_inv' _ hx := arg_expMapCircle hx.1 hx.2 -#align circle.arg_local_equiv circle.argLocalEquiv +#align circle.arg_local_equiv circle.argPartialEquiv /-- `Complex.arg` and `expMapCircle` define an equivalence between `circle` and `(-π, π]`. -/ @[simps (config := .asFn)] noncomputable def argEquiv : circle ≃ Ioc (-π) π where toFun z := ⟨arg z, neg_pi_lt_arg _, arg_le_pi _⟩ invFun := expMapCircle ∘ (↑) - left_inv _ := argLocalEquiv.left_inv trivial - right_inv x := Subtype.ext <| argLocalEquiv.right_inv x.2 + left_inv _ := argPartialEquiv.left_inv trivial + right_inv x := Subtype.ext <| argPartialEquiv.right_inv x.2 #align circle.arg_equiv circle.argEquiv end circle @@ -75,11 +75,11 @@ theorem leftInverse_expMapCircle_arg : LeftInverse expMapCircle (arg ∘ (↑)) #align left_inverse_exp_map_circle_arg leftInverse_expMapCircle_arg theorem invOn_arg_expMapCircle : InvOn (arg ∘ (↑)) expMapCircle (Ioc (-π) π) univ := - circle.argLocalEquiv.symm.invOn + circle.argPartialEquiv.symm.invOn #align inv_on_arg_exp_map_circle invOn_arg_expMapCircle theorem surjOn_expMapCircle_neg_pi_pi : SurjOn expMapCircle (Ioc (-π) π) univ := - circle.argLocalEquiv.symm.surjOn + circle.argPartialEquiv.symm.surjOn #align surj_on_exp_map_circle_neg_pi_pi surjOn_expMapCircle_neg_pi_pi theorem expMapCircle_eq_expMapCircle {x y : ℝ} : diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/LogDeriv.lean b/Mathlib/Analysis/SpecialFunctions/Complex/LogDeriv.lean index b9384e448ab32..fc9706d537e53 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/LogDeriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/LogDeriv.lean @@ -25,11 +25,11 @@ theorem isOpenMap_exp : IsOpenMap exp := open_map_of_strict_deriv hasStrictDerivAt_exp exp_ne_zero #align complex.is_open_map_exp Complex.isOpenMap_exp -/-- `Complex.exp` as a `LocalHomeomorph` with `source = {z | -π < im z < π}` and +/-- `Complex.exp` as a `PartialHomeomorph` with `source = {z | -π < im z < π}` and `target = {z | 0 < re z} ∪ {z | im z ≠ 0}`. This definition is used to prove that `Complex.log` is complex differentiable at all points but the negative real semi-axis. -/ -noncomputable def expLocalHomeomorph : LocalHomeomorph ℂ ℂ := - LocalHomeomorph.ofContinuousOpen +noncomputable def expPartialHomeomorph : PartialHomeomorph ℂ ℂ := + PartialHomeomorph.ofContinuousOpen { toFun := exp invFun := log source := {z : ℂ | z.im ∈ Ioo (-π) π} @@ -48,11 +48,11 @@ noncomputable def expLocalHomeomorph : LocalHomeomorph ℂ ℂ := left_inv' := fun x hx => log_exp hx.1 (le_of_lt hx.2) right_inv' := fun x hx => exp_log <| by rintro rfl; simp [lt_irrefl] at hx } continuous_exp.continuousOn isOpenMap_exp (isOpen_Ioo.preimage continuous_im) -#align complex.exp_local_homeomorph Complex.expLocalHomeomorph +#align complex.exp_local_homeomorph Complex.expPartialHomeomorph theorem hasStrictDerivAt_log {x : ℂ} (h : 0 < x.re ∨ x.im ≠ 0) : HasStrictDerivAt log x⁻¹ x := have h0 : x ≠ 0 := by rintro rfl; simp [lt_irrefl] at h - expLocalHomeomorph.hasStrictDerivAt_symm h h0 <| by + expPartialHomeomorph.hasStrictDerivAt_symm h h0 <| by simpa [exp_log h0] using hasStrictDerivAt_exp (log x) #align complex.has_strict_deriv_at_log Complex.hasStrictDerivAt_log @@ -62,7 +62,7 @@ theorem hasStrictFDerivAt_log_real {x : ℂ} (h : 0 < x.re ∨ x.im ≠ 0) : #align complex.has_strict_fderiv_at_log_real Complex.hasStrictFDerivAt_log_real theorem contDiffAt_log {x : ℂ} (h : 0 < x.re ∨ x.im ≠ 0) {n : ℕ∞} : ContDiffAt ℂ n log x := - expLocalHomeomorph.contDiffAt_symm_deriv (exp_ne_zero <| log x) h (hasDerivAt_exp _) + expPartialHomeomorph.contDiffAt_symm_deriv (exp_ne_zero <| log x) h (hasDerivAt_exp _) contDiff_exp.contDiffAt #align complex.cont_diff_at_log Complex.contDiffAt_log @@ -148,4 +148,3 @@ theorem Differentiable.clog {f : E → ℂ} (h₁ : Differentiable ℂ f) #align differentiable.clog Differentiable.clog end LogDeriv - diff --git a/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean b/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean index dadb276935031..80db011c91c89 100644 --- a/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean +++ b/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean @@ -28,7 +28,7 @@ open scoped Real Topology /-- The polar coordinates local homeomorphism in `ℝ^2`, mapping `(r cos θ, r sin θ)` to `(r, θ)`. It is a homeomorphism between `ℝ^2 - (-∞, 0]` and `(0, +∞) × (-π, π)`. -/ @[simps] -def polarCoord : LocalHomeomorph (ℝ × ℝ) (ℝ × ℝ) where +def polarCoord : PartialHomeomorph (ℝ × ℝ) (ℝ × ℝ) where toFun q := (Real.sqrt (q.1 ^ 2 + q.2 ^ 2), Complex.arg (Complex.equivRealProd.symm q)) invFun p := (p.1 * cos p.2, p.1 * sin p.2) source := {q | 0 < q.1} ∪ {q | q.2 ≠ 0} @@ -160,8 +160,8 @@ open scoped Real /-- The polar coordinates local homeomorphism in `ℂ`, mapping `r (cos θ + I * sin θ)` to `(r, θ)`. It is a homeomorphism between `ℂ - ℝ≤0` and `(0, +∞) × (-π, π)`. -/ -protected noncomputable def polarCoord : LocalHomeomorph ℂ (ℝ × ℝ) := - equivRealProdClm.toHomeomorph.toLocalHomeomorph.trans polarCoord +protected noncomputable def polarCoord : PartialHomeomorph ℂ (ℝ × ℝ) := + equivRealProdClm.toHomeomorph.toPartialHomeomorph.trans polarCoord protected theorem polarCoord_apply (a : ℂ) : Complex.polarCoord a = (Complex.abs a, Complex.arg a) := by diff --git a/Mathlib/Analysis/SpecialFunctions/Sqrt.lean b/Mathlib/Analysis/SpecialFunctions/Sqrt.lean index 23fb378c841d7..dda00db3ac55d 100644 --- a/Mathlib/Analysis/SpecialFunctions/Sqrt.lean +++ b/Mathlib/Analysis/SpecialFunctions/Sqrt.lean @@ -28,7 +28,7 @@ namespace Real /-- Local homeomorph between `(0, +∞)` and `(0, +∞)` with `toFun = (· ^ 2)` and `invFun = Real.sqrt`. -/ -noncomputable def sqLocalHomeomorph : LocalHomeomorph ℝ ℝ where +noncomputable def sqPartialHomeomorph : PartialHomeomorph ℝ ℝ where toFun x := x ^ 2 invFun := sqrt source := Ioi 0 @@ -41,7 +41,7 @@ noncomputable def sqLocalHomeomorph : LocalHomeomorph ℝ ℝ where open_target := isOpen_Ioi continuousOn_toFun := (continuous_pow 2).continuousOn continuousOn_invFun := continuousOn_id.sqrt -#align real.sq_local_homeomorph Real.sqLocalHomeomorph +#align real.sq_local_homeomorph Real.sqPartialHomeomorph theorem deriv_sqrt_aux {x : ℝ} (hx : x ≠ 0) : HasStrictDerivAt sqrt (1 / (2 * sqrt x)) x ∧ ∀ n, ContDiffAt ℝ n sqrt x := by @@ -53,8 +53,8 @@ theorem deriv_sqrt_aux {x : ℝ} (hx : x ≠ 0) : contDiffAt_const.congr_of_eventuallyEq this⟩ · have : ↑2 * sqrt x ^ (2 - 1) ≠ 0 := by simp [(sqrt_pos.2 hx).ne', @two_ne_zero ℝ] constructor - · simpa using sqLocalHomeomorph.hasStrictDerivAt_symm hx this (hasStrictDerivAt_pow 2 _) - · exact fun n => sqLocalHomeomorph.contDiffAt_symm_deriv this hx (hasDerivAt_pow 2 (sqrt x)) + · simpa using sqPartialHomeomorph.hasStrictDerivAt_symm hx this (hasStrictDerivAt_pow 2 _) + · exact fun n => sqPartialHomeomorph.contDiffAt_symm_deriv this hx (hasDerivAt_pow 2 (sqrt x)) (contDiffAt_id.pow 2) #align real.deriv_sqrt_aux Real.deriv_sqrt_aux diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean index bd7d6df676705..eedb24944e24c 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean @@ -11,7 +11,7 @@ import Mathlib.Analysis.SpecialFunctions.Trigonometric.Complex # The `arctan` function. Inequalities, derivatives, -and `Real.tan` as a `LocalHomeomorph` between `(-(π / 2), π / 2)` and the whole line. +and `Real.tan` as a `PartialHomeomorph` between `(-(π / 2), π / 2)` and the whole line. -/ @@ -209,8 +209,8 @@ theorem continuousAt_arctan {x : ℝ} : ContinuousAt arctan x := continuous_arctan.continuousAt #align real.continuous_at_arctan Real.continuousAt_arctan -/-- `Real.tan` as a `LocalHomeomorph` between `(-(π / 2), π / 2)` and the whole line. -/ -def tanLocalHomeomorph : LocalHomeomorph ℝ ℝ where +/-- `Real.tan` as a `PartialHomeomorph` between `(-(π / 2), π / 2)` and the whole line. -/ +def tanPartialHomeomorph : PartialHomeomorph ℝ ℝ where toFun := tan invFun := arctan source := Ioo (-(π / 2)) (π / 2) @@ -223,16 +223,16 @@ def tanLocalHomeomorph : LocalHomeomorph ℝ ℝ where open_target := isOpen_univ continuousOn_toFun := continuousOn_tan_Ioo continuousOn_invFun := continuous_arctan.continuousOn -#align real.tan_local_homeomorph Real.tanLocalHomeomorph +#align real.tan_local_homeomorph Real.tanPartialHomeomorph @[simp] -theorem coe_tanLocalHomeomorph : ⇑tanLocalHomeomorph = tan := +theorem coe_tanPartialHomeomorph : ⇑tanPartialHomeomorph = tan := rfl -#align real.coe_tan_local_homeomorph Real.coe_tanLocalHomeomorph +#align real.coe_tan_local_homeomorph Real.coe_tanPartialHomeomorph @[simp] -theorem coe_tanLocalHomeomorph_symm : ⇑tanLocalHomeomorph.symm = arctan := +theorem coe_tanPartialHomeomorph_symm : ⇑tanPartialHomeomorph.symm = arctan := rfl -#align real.coe_tan_local_homeomorph_symm Real.coe_tanLocalHomeomorph_symm +#align real.coe_tan_local_homeomorph_symm Real.coe_tanPartialHomeomorph_symm end Real diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/ArctanDeriv.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/ArctanDeriv.lean index d2798e45a2854..4f017ca41a53e 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/ArctanDeriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/ArctanDeriv.lean @@ -82,7 +82,7 @@ theorem differentiableAt_tan_of_mem_Ioo {x : ℝ} (h : x ∈ Ioo (-(π / 2) : theorem hasStrictDerivAt_arctan (x : ℝ) : HasStrictDerivAt arctan (1 / (1 + x ^ 2)) x := by have A : cos (arctan x) ≠ 0 := (cos_arctan_pos x).ne' simpa [cos_sq_arctan] using - tanLocalHomeomorph.hasStrictDerivAt_symm trivial (by simpa) (hasStrictDerivAt_tan A) + tanPartialHomeomorph.hasStrictDerivAt_symm trivial (by simpa) (hasStrictDerivAt_tan A) #align real.has_strict_deriv_at_arctan Real.hasStrictDerivAt_arctan theorem hasDerivAt_arctan (x : ℝ) : HasDerivAt arctan (1 / (1 + x ^ 2)) x := @@ -105,7 +105,7 @@ theorem deriv_arctan : deriv arctan = fun (x : ℝ) => 1 / (1 + x ^ 2) := theorem contDiff_arctan {n : ℕ∞} : ContDiff ℝ n arctan := contDiff_iff_contDiffAt.2 fun x => have : cos (arctan x) ≠ 0 := (cos_arctan_pos x).ne' - tanLocalHomeomorph.contDiffAt_symm_deriv (by simpa) trivial (hasDerivAt_tan this) + tanPartialHomeomorph.contDiffAt_symm_deriv (by simpa) trivial (hasDerivAt_tan this) (contDiffAt_tan.2 this) #align real.cont_diff_arctan Real.contDiff_arctan diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Inverse.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Inverse.lean index 7a57e3523fd64..a13666b448a01 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Inverse.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Inverse.lean @@ -278,9 +278,9 @@ theorem mapsTo_sin_Ioo : MapsTo sin (Ioo (-(π / 2)) (π / 2)) (Ioo (-1) 1) := f rwa [mem_Ioo, ← arcsin_lt_pi_div_two, ← neg_pi_div_two_lt_arcsin, arcsin_sin h.1.le h.2.le] #align real.maps_to_sin_Ioo Real.mapsTo_sin_Ioo -/-- `Real.sin` as a `LocalHomeomorph` between `(-π / 2, π / 2)` and `(-1, 1)`. -/ +/-- `Real.sin` as a `PartialHomeomorph` between `(-π / 2, π / 2)` and `(-1, 1)`. -/ @[simp] -def sinLocalHomeomorph : LocalHomeomorph ℝ ℝ where +def sinPartialHomeomorph : PartialHomeomorph ℝ ℝ where toFun := sin invFun := arcsin source := Ioo (-(π / 2)) (π / 2) @@ -293,7 +293,7 @@ def sinLocalHomeomorph : LocalHomeomorph ℝ ℝ where open_target := isOpen_Ioo continuousOn_toFun := continuous_sin.continuousOn continuousOn_invFun := continuous_arcsin.continuousOn -#align real.sin_local_homeomorph Real.sinLocalHomeomorph +#align real.sin_local_homeomorph Real.sinPartialHomeomorph theorem cos_arcsin_nonneg (x : ℝ) : 0 ≤ cos (arcsin x) := cos_nonneg_of_mem_Icc ⟨neg_pi_div_two_le_arcsin _, arcsin_le_pi_div_two _⟩ diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/InverseDeriv.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/InverseDeriv.lean index 3617da9898c2d..a4c3b44502c5e 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/InverseDeriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/InverseDeriv.lean @@ -39,8 +39,8 @@ theorem deriv_arcsin_aux {x : ℝ} (h₁ : x ≠ -1) (h₂ : x ≠ 1) : cases' h₂.lt_or_lt with h₂ h₂ · have : 0 < sqrt (1 - x ^ 2) := sqrt_pos.2 (by nlinarith [h₁, h₂]) simp only [← cos_arcsin, one_div] at this ⊢ - exact ⟨sinLocalHomeomorph.hasStrictDerivAt_symm ⟨h₁, h₂⟩ this.ne' (hasStrictDerivAt_sin _), - sinLocalHomeomorph.contDiffAt_symm_deriv this.ne' ⟨h₁, h₂⟩ (hasDerivAt_sin _) + exact ⟨sinPartialHomeomorph.hasStrictDerivAt_symm ⟨h₁, h₂⟩ this.ne' (hasStrictDerivAt_sin _), + sinPartialHomeomorph.contDiffAt_symm_deriv this.ne' ⟨h₁, h₂⟩ (hasDerivAt_sin _) contDiff_sin.contDiffAt⟩ · have : 1 - x ^ 2 < 0 := by nlinarith [h₂] rw [sqrt_eq_zero'.2 this.le, div_zero] diff --git a/Mathlib/CategoryTheory/Monoidal/Preadditive.lean b/Mathlib/CategoryTheory/Monoidal/Preadditive.lean index 2cd3cb0892697..de09694784229 100644 --- a/Mathlib/CategoryTheory/Monoidal/Preadditive.lean +++ b/Mathlib/CategoryTheory/Monoidal/Preadditive.lean @@ -283,9 +283,8 @@ theorem leftDistributor_ext_left {J : Type} [Fintype J] {X Y : C} {f : J → C} apply (cancel_epi (leftDistributor X f).inv).mp ext simp? [leftDistributor_inv, Preadditive.comp_sum_assoc, biproduct.ι_π_assoc, dite_comp] says - simp only [leftDistributor_inv, Preadditive.comp_sum_assoc, ne_eq, biproduct.ι_π_assoc, - dite_comp, zero_comp, Finset.sum_dite_eq, Finset.mem_univ, eqToHom_refl, Category.id_comp, - ite_true] + simp only [leftDistributor_inv, Preadditive.comp_sum_assoc, biproduct.ι_π_assoc, dite_comp, + zero_comp, Finset.sum_dite_eq, Finset.mem_univ, eqToHom_refl, Category.id_comp, ite_true] apply w @[ext] @@ -295,7 +294,7 @@ theorem leftDistributor_ext_right {J : Type} [Fintype J] {X Y : C} {f : J → C} ext simp? [leftDistributor_hom, Preadditive.sum_comp, Preadditive.comp_sum_assoc, biproduct.ι_π, comp_dite] says - simp only [leftDistributor_hom, Category.assoc, Preadditive.sum_comp, ne_eq, biproduct.ι_π, + simp only [leftDistributor_hom, Category.assoc, Preadditive.sum_comp, biproduct.ι_π, comp_dite, comp_zero, Finset.sum_dite_eq', Finset.mem_univ, eqToHom_refl, Category.comp_id, ite_true] apply w @@ -327,7 +326,7 @@ theorem rightDistributor_ext_left {J : Type} [Fintype J] apply (cancel_epi (rightDistributor f X).inv).mp ext simp? [rightDistributor_inv, Preadditive.comp_sum_assoc, biproduct.ι_π_assoc, dite_comp] says - simp only [rightDistributor_inv, Preadditive.comp_sum_assoc, ne_eq, biproduct.ι_π_assoc, + simp only [rightDistributor_inv, Preadditive.comp_sum_assoc, biproduct.ι_π_assoc, dite_comp, zero_comp, Finset.sum_dite_eq, Finset.mem_univ, eqToHom_refl, Category.id_comp, ite_true] apply w @@ -340,7 +339,7 @@ theorem rightDistributor_ext_right {J : Type} [Fintype J] ext simp? [rightDistributor_hom, Preadditive.sum_comp, Preadditive.comp_sum_assoc, biproduct.ι_π, comp_dite] says - simp only [rightDistributor_hom, Category.assoc, Preadditive.sum_comp, ne_eq, biproduct.ι_π, + simp only [rightDistributor_hom, Category.assoc, Preadditive.sum_comp, biproduct.ι_π, comp_dite, comp_zero, Finset.sum_dite_eq', Finset.mem_univ, eqToHom_refl, Category.comp_id, ite_true] apply w diff --git a/Mathlib/Combinatorics/Schnirelmann.lean b/Mathlib/Combinatorics/Schnirelmann.lean new file mode 100644 index 0000000000000..1ee1ab2176b1c --- /dev/null +++ b/Mathlib/Combinatorics/Schnirelmann.lean @@ -0,0 +1,266 @@ +/- +Copyright (c) 2023 Bhavik Mehta. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yaël Dillies, Bhavik Mehta, Doga Can Sertbas +-/ +import Mathlib.Data.Nat.Interval +import Mathlib.Data.Nat.Parity +import Mathlib.Data.Real.Archimedean + +/-! +# Schnirelmann density + +We define the Schnirelmann density of a set `A` of natural numbers as +$inf_{n > 0} |A ∩ {1,...,n}| / n$. As this density is very sensitive to changes in small values, +we must exclude `0` from the infimum, and from the intersection. + +## Main statements + +* Simple bounds on the Schnirelmann density, that it is between 0 and 1 are given in + `schnirelmannDensity_nonneg` and `schnirelmannDensity_le_one`. +* `schnirelmannDensity_le_of_not_mem`: If `k ∉ A`, the density can be easily upper-bounded by + `1 - k⁻¹` + +## Implementation notes + +Despite the definition being noncomputable, we include a decidable instance argument, since this +makes the definition easier to use in explicit cases. +Further, we use `Finset.Ioc` rather than a set intersection since the set is finite by construction, +which reduces the proof obligations later that would arise with `Nat.card`. + +## TODO +* Give other calculations of the density, for example powers and their sumsets. +* Define other densities like the lower and upper asymptotic density, and the natural density, + and show how these relate to the Schnirelmann density. +* Show that if the sum of two densities is at least one, the sumset covers the positive naturals. +* Prove Schnirelmann's theorem and Mann's theorem on the subadditivity of this density. + +## References + +* [Ruzsa, Imre, *Sumsets and structure*][ruzsa2009] +-/ + +open Finset + +/-- The Schnirelmann density is defined as the infimum of |A ∩ {1, ..., n}| / n as n ranges over +the positive naturals. -/ +noncomputable def schnirelmannDensity (A : Set ℕ) [DecidablePred (· ∈ A)] : ℝ := + ⨅ n : {n : ℕ // 0 < n}, ((Ioc (0 : ℕ) n).filter (· ∈ A)).card / n + +section + +variable {A : Set ℕ} [DecidablePred (· ∈ A)] + +lemma schnirelmannDensity_nonneg : 0 ≤ schnirelmannDensity A := + Real.iInf_nonneg (fun _ => by positivity) + +lemma schnirelmannDensity_le_div {n : ℕ} (hn : n ≠ 0) : + schnirelmannDensity A ≤ ((Ioc 0 n).filter (· ∈ A)).card / n := + ciInf_le ⟨0, fun _ ⟨_, hx⟩ => hx ▸ by positivity⟩ (⟨n, hn.bot_lt⟩ : {n : ℕ // 0 < n}) + +/-- +For any natural `n`, the Schnirelmann density multiplied by `n` is bounded by `|A ∩ {1, ..., n}|`. +Note this property fails for the natural density. +-/ +lemma schnirelmannDensity_mul_le_card_filter {n : ℕ} : + schnirelmannDensity A * n ≤ ((Ioc 0 n).filter (· ∈ A)).card := by + rcases eq_or_ne n 0 with rfl | hn + · simp + exact (le_div_iff (by positivity)).1 (schnirelmannDensity_le_div hn) + +/-- +To show the Schnirelmann density is upper bounded by `x`, it suffices to show +`|A ∩ {1, ..., n}| / n ≤ x`, for any chosen positive value of `n`. + +We provide `n` explicitly here to make this lemma more easily usable in `apply` or `refine`. +This lemma is analogous to `ciInf_le_of_le`. +-/ +lemma schnirelmannDensity_le_of_le {x : ℝ} (n : ℕ) (hn : n ≠ 0) + (hx : ((Ioc 0 n).filter (· ∈ A)).card / n ≤ x) : schnirelmannDensity A ≤ x := + (schnirelmannDensity_le_div hn).trans hx + +lemma schnirelmannDensity_le_one : schnirelmannDensity A ≤ 1 := + schnirelmannDensity_le_of_le 1 one_ne_zero <| + by rw [Nat.cast_one, div_one, Nat.cast_le_one]; exact card_filter_le _ _ + +/-- +If `k` is omitted from the set, its Schnirelmann density is upper bounded by `1 - k⁻¹`. +-/ +lemma schnirelmannDensity_le_of_not_mem {k : ℕ} (hk : k ∉ A) : + schnirelmannDensity A ≤ 1 - (k⁻¹ : ℝ) := by + rcases k.eq_zero_or_pos with rfl | hk' + · simpa using schnirelmannDensity_le_one + apply schnirelmannDensity_le_of_le k hk'.ne' + rw [← one_div, one_sub_div (Nat.cast_pos.2 hk').ne'] + apply div_le_div_of_le (Nat.cast_nonneg _) + rw [← Nat.cast_pred hk', Nat.cast_le] + suffices : (Ioc 0 k).filter (· ∈ A) ⊆ Ioo 0 k; exact (card_le_of_subset this).trans_eq (by simp) + rw [← Ioo_insert_right hk', filter_insert, if_neg hk] + exact filter_subset _ _ + +/-- The Schnirelmann density of a set not containing `1` is `0`. -/ +lemma schnirelmannDensity_eq_zero_of_one_not_mem (h : 1 ∉ A) : schnirelmannDensity A = 0 := + ((schnirelmannDensity_le_of_not_mem h).trans (by simp)).antisymm schnirelmannDensity_nonneg + +/-- The Schnirelmann density is increasing with the set. -/ +lemma schnirelmannDensity_le_of_subset {B : Set ℕ} [DecidablePred (· ∈ B)] (h : A ⊆ B) : + schnirelmannDensity A ≤ schnirelmannDensity B := + ciInf_mono ⟨0, fun _ ⟨_, hx⟩ => hx ▸ by positivity⟩ fun _ => div_le_div_of_le (by positivity) <| + Nat.cast_le.2 <| card_le_of_subset <| monotone_filter_right _ h + +/-- The Schnirelmann density of `A` is `1` if and only if `A` contains all the positive naturals. -/ +lemma schnirelmannDensity_eq_one_iff : schnirelmannDensity A = 1 ↔ {0}ᶜ ⊆ A := by + rw [le_antisymm_iff, and_iff_right schnirelmannDensity_le_one] + constructor + · rw [← not_imp_not, not_le] + simp only [Set.not_subset, forall_exists_index, true_and, and_imp, Set.mem_singleton_iff] + intro x hx hx' + apply (schnirelmannDensity_le_of_not_mem hx').trans_lt + simpa only [one_div, sub_lt_self_iff, inv_pos, Nat.cast_pos, pos_iff_ne_zero] using hx + · intro h + refine le_ciInf fun ⟨n, hn⟩ => ?_ + rw [one_le_div (Nat.cast_pos.2 hn), Nat.cast_le, filter_true_of_mem, Nat.card_Ioc, Nat.sub_zero] + rintro x hx + exact h (mem_Ioc.1 hx).1.ne' + +/-- The Schnirelmann density of `A` containing `0` is `1` if and only if `A` is the naturals. -/ +lemma schnirelmannDensity_eq_one_iff_of_zero_mem (hA : 0 ∈ A) : + schnirelmannDensity A = 1 ↔ A = Set.univ := by + rw [schnirelmannDensity_eq_one_iff] + constructor + · refine fun h => Set.eq_univ_of_forall fun x => ?_ + rcases eq_or_ne x 0 with rfl | hx + · exact hA + · exact h hx + · rintro rfl + exact Set.subset_univ {0}ᶜ + +lemma le_schnirelmannDensity_iff {x : ℝ} : + x ≤ schnirelmannDensity A ↔ ∀ n : ℕ, 0 < n → x ≤ ((Ioc 0 n).filter (· ∈ A)).card / n := + (le_ciInf_iff ⟨0, fun _ ⟨_, hx⟩ => hx ▸ by positivity⟩).trans Subtype.forall + +lemma schnirelmannDensity_lt_iff {x : ℝ} : + schnirelmannDensity A < x ↔ ∃ n : ℕ, 0 < n ∧ ((Ioc 0 n).filter (· ∈ A)).card / n < x := + by rw [← not_le, le_schnirelmannDensity_iff]; simp + +lemma schnirelmannDensity_le_iff_forall {x : ℝ} : + schnirelmannDensity A ≤ x ↔ + ∀ ε : ℝ, 0 < ε → ∃ n : ℕ, 0 < n ∧ ((Ioc 0 n).filter (· ∈ A)).card / n < x + ε := by + rw [le_iff_forall_pos_lt_add] + simp only [schnirelmannDensity_lt_iff] + +lemma schnirelmannDensity_congr' {B : Set ℕ} [DecidablePred (· ∈ B)] + (h : ∀ n > 0, n ∈ A ↔ n ∈ B) : schnirelmannDensity A = schnirelmannDensity B := + by rw [schnirelmannDensity, schnirelmannDensity]; congr; ext ⟨n, hn⟩; congr 3; ext x; aesop + +/-- The Schnirelmann density is unaffected by adding `0`. -/ +@[simp] lemma schnirelmannDensity_insert_zero [DecidablePred (· ∈ insert 0 A)] : + schnirelmannDensity (insert 0 A) = schnirelmannDensity A := + schnirelmannDensity_congr' (by aesop) + +/-- The Schnirelmann density is unaffected by removing `0`. -/ +lemma schnirelmannDensity_diff_singleton_zero [DecidablePred (· ∈ A \ {0})] : + schnirelmannDensity (A \ {0}) = schnirelmannDensity A := + schnirelmannDensity_congr' (by aesop) + +lemma schnirelmannDensity_congr {B : Set ℕ} [DecidablePred (· ∈ B)] (h : A = B) : + schnirelmannDensity A = schnirelmannDensity B := + schnirelmannDensity_congr' (by aesop) + +/-- +If the Schnirelmann density is `0`, there is a positive natural for which +`|A ∩ {1, ..., n}| / n < ε`, for any positive `ε`. +Note this cannot be improved to `∃ᶠ n : ℕ in atTop`, as can be seen by `A = {1}ᶜ`. +-/ +lemma exists_of_schnirelmannDensity_eq_zero {ε : ℝ} (hε : 0 < ε) (hA : schnirelmannDensity A = 0) : + ∃ n, 0 < n ∧ ((Ioc 0 n).filter (· ∈ A)).card / n < ε := by + by_contra! h + rw [← le_schnirelmannDensity_iff] at h + linarith + +end + +@[simp] lemma schnirelmannDensity_empty : schnirelmannDensity ∅ = 0 := + schnirelmannDensity_eq_zero_of_one_not_mem (by simp) + +/-- The Schnirelmann density of any finset is `0`. -/ +lemma schnirelmannDensity_finset (A : Finset ℕ) : schnirelmannDensity A = 0 := by + refine le_antisymm ?_ schnirelmannDensity_nonneg + simp only [schnirelmannDensity_le_iff_forall, zero_add] + intro ε hε + wlog hε₁ : ε ≤ 1 generalizing ε + · obtain ⟨n, hn, hn'⟩ := this 1 zero_lt_one le_rfl + exact ⟨n, hn, hn'.trans_le (le_of_not_le hε₁)⟩ + let n : ℕ := ⌊A.card / ε⌋₊ + 1 + have hn : 0 < n := Nat.succ_pos _ + use n, hn + rw [div_lt_iff (Nat.cast_pos.2 hn), ← div_lt_iff' hε, Nat.cast_add_one] + exact (Nat.lt_floor_add_one _).trans_le' <| div_le_div_of_le hε.le <| Nat.cast_le.2 <| + card_le_of_subset <| by simp [subset_iff] + +/-- The Schnirelmann density of any finite set is `0`. -/ +lemma schnirelmannDensity_finite {A : Set ℕ} [DecidablePred (· ∈ A)] (hA : A.Finite) : + schnirelmannDensity A = 0 := by simpa using schnirelmannDensity_finset hA.toFinset + +@[simp] lemma schnirelmannDensity_univ : schnirelmannDensity Set.univ = 1 := + (schnirelmannDensity_eq_one_iff_of_zero_mem (by simp)).2 (by simp) + +lemma schnirelmannDensity_setOf_even : schnirelmannDensity (setOf Even) = 0 := + schnirelmannDensity_eq_zero_of_one_not_mem $ by simp + +lemma schnirelmannDensity_setOf_prime : schnirelmannDensity (setOf Nat.Prime) = 0 := + schnirelmannDensity_eq_zero_of_one_not_mem $ by simp [Nat.not_prime_one] + +/-- +The Schnirelmann density of the set of naturals which are `1 mod m` is `m⁻¹`, for any `m ≠ 1`. + +Note that if `m = 1`, this set is empty. +-/ +lemma schnirelmannDensity_setOf_mod_eq_one {m : ℕ} (hm : m ≠ 1) : + schnirelmannDensity {n | n % m = 1} = (m⁻¹ : ℝ) := by + rcases m.eq_zero_or_pos with rfl | hm' + · simp only [Nat.cast_zero, inv_zero] + refine schnirelmannDensity_finite ?_ + simp + apply le_antisymm (schnirelmannDensity_le_of_le m hm'.ne' _) _ + · rw [← one_div] + apply div_le_div_of_le (Nat.cast_nonneg _) + simp only [Set.mem_setOf_eq, Nat.cast_le_one, card_le_one_iff_subset_singleton, subset_iff, + mem_filter, mem_Ioc, mem_singleton, and_imp] + use 1 + intro x _ hxm h + rcases eq_or_lt_of_le hxm with rfl | hxm' + · simp at h + rwa [Nat.mod_eq_of_lt hxm'] at h + rw [le_schnirelmannDensity_iff] + intro n hn + simp only [Set.mem_setOf_eq] + have : (Icc 0 ((n - 1) / m)).image (· * m + 1) ⊆ (Ioc 0 n).filter (· % m = 1) + · simp only [subset_iff, mem_image, forall_exists_index, mem_filter, mem_Ioc, mem_Icc, and_imp] + rintro _ y _ hy' rfl + have hm : 2 ≤ m := hm.lt_of_le' hm' + simp only [Nat.mul_add_mod', Nat.mod_eq_of_lt hm, add_pos_iff, or_true, and_true, true_and, + ← Nat.le_sub_iff_add_le hn, zero_lt_one] + exact Nat.mul_le_of_le_div _ _ _ hy' + rw [le_div_iff (Nat.cast_pos.2 hn), mul_comm, ← div_eq_mul_inv] + apply (Nat.cast_le.2 (card_le_of_subset this)).trans' + rw [card_image_of_injective, Nat.card_Icc, Nat.sub_zero, div_le_iff (Nat.cast_pos.2 hm'), + ← Nat.cast_mul, Nat.cast_le, add_one_mul (α := ℕ)] + · have := @Nat.lt_div_mul_add n.pred m hm' + rwa [← Nat.succ_le, Nat.succ_pred hn.ne'] at this + intro a b + simp [hm'.ne'] + +lemma schnirelmannDensity_setOf_modeq_one {m : ℕ} : + schnirelmannDensity {n | n ≡ 1 [MOD m]} = (m⁻¹ : ℝ) := by + rcases eq_or_ne m 1 with rfl | hm + · simp [Nat.modEq_one] + rw [← schnirelmannDensity_setOf_mod_eq_one hm] + apply schnirelmannDensity_congr + ext n + simp only [Set.mem_setOf_eq, Nat.ModEq, Nat.one_mod_of_ne_one hm] + +lemma schnirelmannDensity_setOf_Odd : schnirelmannDensity (setOf Odd) = 2⁻¹ := by + have h : setOf Odd = {n | n % 2 = 1} := Set.ext fun _ => Nat.odd_iff + simp only [h] + rw [schnirelmannDensity_setOf_mod_eq_one (by norm_num1), Nat.cast_two] diff --git a/Mathlib/Combinatorics/SetFamily/Shadow.lean b/Mathlib/Combinatorics/SetFamily/Shadow.lean index f91991311ea2c..f1a348f3241c2 100644 --- a/Mathlib/Combinatorics/SetFamily/Shadow.lean +++ b/Mathlib/Combinatorics/SetFamily/Shadow.lean @@ -211,7 +211,7 @@ theorem upShadow_monotone : Monotone (upShadow : Finset (Finset α) → Finset ( /-- `t` is in the upper shadow of `𝒜` iff there is a `s ∈ 𝒜` from which we can remove one element to get `t`. -/ -lemma mem_upShadow_iff : t ∈ ∂⁺ 𝒜 ↔ ∃ s ∈ 𝒜, ∃ a, a ∉ s ∧ insert a s = t := by +lemma mem_upShadow_iff : t ∈ ∂⁺ 𝒜 ↔ ∃ s ∈ 𝒜, ∃ a ∉ s, insert a s = t := by simp_rw [upShadow, mem_sup, mem_image, mem_compl] #align finset.mem_up_shadow_iff Finset.mem_upShadow_iff diff --git a/Mathlib/Control/Random.lean b/Mathlib/Control/Random.lean index 4464d65c97046..1ebd61c4d1d9e 100644 --- a/Mathlib/Control/Random.lean +++ b/Mathlib/Control/Random.lean @@ -11,6 +11,7 @@ import Mathlib.Control.ULiftable import Mathlib.Data.Fin.Basic import Mathlib.Data.Nat.Basic import Mathlib.Order.ULift +import Mathlib.Logic.Equiv.Functor #align_import control.random from "leanprover-community/mathlib"@"fdc286cc6967a012f41b87f76dcd2797b53152af" @@ -22,12 +23,13 @@ defining objects that can be created randomly. ## Main definitions -* `Rand` and `RandG` monad for computations guided by randomness; +* `RandT` and `RandGT` monad transformers for computations guided by randomness; +* `Rand` and `RandG` monads as special cases of the above * `Random` class for objects that can be generated randomly; * `random` to generate one object; * `BoundedRandom` class for objects that can be generated randomly inside a range; * `randomR` to generate one object inside a range; -* `IO.runRand` to run a randomized computation inside the `IO` monad; +* `IO.runRand` to run a randomized computation inside any monad that has access to `stdGenRef`. ## References @@ -37,37 +39,49 @@ defining objects that can be created randomly. set_option autoImplicit true -/-- A monad to generate random objects using the generic generator type `g` -/ -abbrev RandG (g : Type) := StateM (ULift g) +/-- A monad transformer to generate random objects using the generic generator type `g` -/ +abbrev RandGT (g : Type) := StateT (ULift g) +/-- A monad to generate random objects using the generator type `g`. -/ +abbrev RandG (g : Type) := RandGT g Id -/-- A monad to generate random objects using the generator type `Rng` -/ -abbrev Rand (α : Type u) := RandG StdGen α +/-- A monad transformer to generate random objects using the generator type `StdGen`. +`RandT m α` should be thought of a random value in `m α`. -/ +abbrev RandT := RandGT StdGen -/-- `Random α` gives us machinery to generate values of type `α` -/ -class Random (α : Type u) where - random [RandomGen g] : RandG g α +/-- A monad to generate random objects using the generator type `StdGen`. -/ +abbrev Rand := RandG StdGen -/-- `BoundedRandom α` gives us machinery to generate values of type `α` between certain bounds -/ -class BoundedRandom (α : Type u) [Preorder α] where - randomR {g : Type} (lo hi : α) (h : lo ≤ hi) [RandomGen g] : RandG g {a // lo ≤ a ∧ a ≤ hi} +instance [MonadLift m n] : MonadLiftT (RandGT g m) (RandGT g n) where + monadLift x := fun s => x s + +/-- `Random m α` gives us machinery to generate values of type `α` in the monad `m`. + +Note that `m` is a parameter as some types may only be sampleable with access to a certain monad. -/ +class Random (m) (α : Type u) where + random [RandomGen g] : RandGT g m α + +/-- `BoundedRandom m α` gives us machinery to generate values of type `α` between certain bounds in +the monad `m`. -/ +class BoundedRandom (m) (α : Type u) [Preorder α] where + randomR {g : Type} (lo hi : α) (h : lo ≤ hi) [RandomGen g] : RandGT g m {a // lo ≤ a ∧ a ≤ hi} namespace Rand /-- Generate one more `Nat` -/ - def next [RandomGen g] : RandG g Nat := do + def next [RandomGen g] [Monad m] : RandGT g m Nat := do let rng := (← get).down let (res, new) := RandomGen.next rng set (ULift.up new) pure res /-- Create a new random number generator distinct from the one stored in the state -/ - def split {g : Type} [RandomGen g] : RandG g g := do + def split {g : Type} [RandomGen g] [Monad m] : RandGT g m g := do let rng := (← get).down let (r1, r2) := RandomGen.split rng set (ULift.up r1) pure r2 /-- Get the range of Nat that can be generated by the generator `g` -/ - def range {g : Type} [RandomGen g] : RandG g (Nat × Nat) := do + def range {g : Type} [RandomGen g] [Monad m] : RandGT g m (Nat × Nat) := do let rng := (← get).down pure <| RandomGen.range rng end Rand @@ -76,39 +90,42 @@ namespace Random open Rand +variable [Monad m] + /-- Generate a random value of type `α`. -/ -def rand (α : Type u) [Random α] [RandomGen g] : RandG g α := Random.random +def rand (α : Type u) [Random m α] [RandomGen g] : RandGT g m α := Random.random /-- Generate a random value of type `α` between `x` and `y` inclusive. -/ -def randBound (α : Type u) [Preorder α] [BoundedRandom α] (lo hi : α) (h : lo ≤ hi) [RandomGen g] : - RandG g {a // lo ≤ a ∧ a ≤ hi} := - BoundedRandom.randomR lo hi h +def randBound (α : Type u) + [Preorder α] [BoundedRandom m α] (lo hi : α) (h : lo ≤ hi) [RandomGen g] : + RandGT g m {a // lo ≤ a ∧ a ≤ hi} := + (BoundedRandom.randomR lo hi h : RandGT g _ _) -def randFin {n : Nat} [RandomGen g] : RandG g (Fin n.succ) := - λ ⟨g⟩ => randNat g 0 n.succ |>.map Fin.ofNat ULift.up +def randFin {n : Nat} [RandomGen g] : RandGT g m (Fin n.succ) := + λ ⟨g⟩ => pure <| randNat g 0 n.succ |>.map Fin.ofNat ULift.up -instance {n : Nat} : Random (Fin n.succ) where +instance {n : Nat} : Random m (Fin n.succ) where random := randFin -def randBool [RandomGen g] : RandG g Bool := +def randBool [RandomGen g] : RandGT g m Bool := return (← rand (Fin 2)) == 1 -instance : Random Bool where +instance : Random m Bool where random := randBool -instance {α : Type u} [Random α] : Random (ULift.{v} α) where - random {g} := ULiftable.up (random : RandG g α) +instance {α : Type u} [ULiftable m m'] [Random m α] : Random m' (ULift.{v} α) where + random := ULiftable.up random -instance : BoundedRandom Nat where - randomR := λ lo hi h _ => do +instance : BoundedRandom m Nat where + randomR lo hi h _ := do let z ← rand (Fin (hi - lo).succ) pure ⟨ lo + z.val, Nat.le_add_right _ _, Nat.add_le_of_le_sub' h (Nat.le_of_succ_le_succ z.isLt) ⟩ -instance : BoundedRandom Int where - randomR := λ lo hi h _ => do +instance : BoundedRandom m Int where + randomR lo hi h _ := do let ⟨z, _, h2⟩ ← randBound Nat 0 (Int.natAbs $ hi - lo) (Nat.zero_le _) pure ⟨ z + lo, @@ -117,32 +134,40 @@ instance : BoundedRandom Int where (Int.ofNat_le.mpr h2) (le_of_eq $ Int.ofNat_natAbs_eq_of_nonneg _ $ Int.sub_nonneg_of_le h)⟩ -instance {n : Nat} : BoundedRandom (Fin n) where - randomR := λ lo hi h _ => do +instance {n : Nat} : BoundedRandom m (Fin n) where + randomR lo hi h _ := do let ⟨r, h1, h2⟩ ← randBound Nat lo.val hi.val h pure ⟨⟨r, Nat.lt_of_le_of_lt h2 hi.isLt⟩, h1, h2⟩ -instance {α : Type u} [Preorder α] [BoundedRandom α] : BoundedRandom (ULift.{v} α) where - randomR {g} lo hi h := do - let ⟨v⟩ - ← (ULiftable.up (BoundedRandom.randomR lo.down hi.down h : RandG g _) : RandG g (ULift.{v} _)) - pure ⟨ULift.up v.val, v.prop⟩ +instance {α : Type u} [Preorder α] [ULiftable m m'] [BoundedRandom m α] [Monad m'] : + BoundedRandom m' (ULift.{v} α) where + randomR lo hi h := do + let ⟨x⟩ ← ULiftable.up.{v} (BoundedRandom.randomR lo.down hi.down h) + pure ⟨ULift.up x.val, x.prop⟩ end Random -/-- Computes a `Rand α` using the global `stdGenRef` as RNG. - Note that: - - `stdGenRef` is not necessarily properly seeded on program startup - as of now and will therefore be deterministic. - - `stdGenRef` is not thread local, hence two threads accessing it - at the same time will get the exact same generator. +namespace IO + +variable {m : Type* → Type*} {m₀ : Type → Type} +variable [Monad m] [MonadLiftT (ST RealWorld) m₀] [ULiftable m₀ m] + +/-- +Computes a `RandT m α` using the global `stdGenRef` as RNG. + +Note that: +- `stdGenRef` is not necessarily properly seeded on program startup + as of now and will therefore be deterministic. +- `stdGenRef` is not thread local, hence two threads accessing it + at the same time will get the exact same generator. -/ -def IO.runRand (cmd : Rand α) : BaseIO α := do - let stdGen ← stdGenRef.get - let rng := ULift.up stdGen - let (res, new) := Id.run <| StateT.run cmd rng - stdGenRef.set new.down +def runRand (cmd : RandT m α) : m α := do + let stdGen ← ULiftable.up (stdGenRef.get : m₀ _) + let (res, new) ← StateT.run cmd stdGen + let _ ← ULiftable.up (stdGenRef.set new.down : m₀ _) pure res -def IO.runRandWith (seed : Nat) (cmd : Rand α) : BaseIO α := do - pure $ (cmd.run (ULift.up $ mkStdGen seed)).1 +def runRandWith (seed : Nat) (cmd : RandT m α) : m α := do + pure $ (← cmd.run (ULift.up $ mkStdGen seed)).1 + +end IO diff --git a/Mathlib/Control/ULiftable.lean b/Mathlib/Control/ULiftable.lean index 4bfb808859727..66106bd06cfa9 100644 --- a/Mathlib/Control/ULiftable.lean +++ b/Mathlib/Control/ULiftable.lean @@ -37,20 +37,26 @@ universe polymorphism functor -/ -universe u₀ u₁ v₀ v₁ v₂ w w₀ w₁ +universe v u₀ u₁ v₀ v₁ v₂ w w₀ w₁ variable {s : Type u₀} {s' : Type u₁} {r r' w w' : Type*} /-- Given a universe polymorphic type family `M.{u} : Type u₁ → Type u₂`, this class convert between instantiations, from -`M.{u} : Type u₁ → Type u₂` to `M.{v} : Type v₁ → Type v₂` and back -/ -class ULiftable (f : Type u₀ → Type u₁) (g : Type v₀ → Type v₁) where +`M.{u} : Type u₁ → Type u₂` to `M.{v} : Type v₁ → Type v₂` and back. + +`f` is an outParam, because `g` can almost always be inferred from the current monad. +At any rate, the lift should be unique, as the intent is to only lift the same constants with +different universe parameters. -/ +class ULiftable (f : outParam (Type u₀ → Type u₁)) (g : Type v₀ → Type v₁) where congr {α β} : α ≃ β → f α ≃ g β #align uliftable ULiftable namespace ULiftable -instance symm (f : Type u₀ → Type u₁) (g : Type v₀ → Type v₁) [ULiftable f g] : ULiftable g f where +/-- Not an instance as it is incompatible with `outParam`. In practice it seems not to be needed +anyway. -/ +abbrev symm (f : Type u₀ → Type u₁) (g : Type v₀ → Type v₁) [ULiftable f g] : ULiftable g f where congr e := (ULiftable.congr e.symm).symm instance refl (f : Type u₀ → Type u₁) [Functor f] [LawfulFunctor f] : ULiftable f f where @@ -58,19 +64,19 @@ instance refl (f : Type u₀ → Type u₁) [Functor f] [LawfulFunctor f] : ULif example : ULiftable IO IO := inferInstance -/-- The most common practical use `ULiftable` (together with `down`), this function takes +/-- The most common practical use `ULiftable` (together with `down`), the function `up.{v}` takes `x : M.{u} α` and lifts it to `M.{max u v} (ULift.{v} α)` -/ @[reducible] -def up {f : Type u₀ → Type u₁} {g : Type max u₀ v₀ → Type v₁} [ULiftable f g] {α} : - f α → g (ULift.{v₀} α) := +def up {f : Type u₀ → Type u₁} {g : Type max u₀ v → Type v₁} [ULiftable f g] {α} : + f α → g (ULift.{v} α) := (ULiftable.congr Equiv.ulift.symm).toFun #align uliftable.up ULiftable.up -/-- The most common practical use of `ULiftable` (together with `up`), this function takes +/-- The most common practical use of `ULiftable` (together with `up`), the function `down.{v}` takes `x : M.{max u v} (ULift.{v} α)` and lowers it to `M.{u} α` -/ @[reducible] -def down {f : Type u₀ → Type u₁} {g : Type max u₀ v₀ → Type v₁} [ULiftable f g] {α} : - g (ULift.{v₀} α) → f α := +def down {f : Type u₀ → Type u₁} {g : Type max u₀ v → Type v₁} [ULiftable f g] {α} : + g (ULift.{v} α) → f α := (ULiftable.congr Equiv.ulift.symm).invFun #align uliftable.down ULiftable.down @@ -83,7 +89,7 @@ def adaptUp (F : Type v₀ → Type v₁) (G : Type max v₀ u₀ → Type u₁) /-- convenient shortcut to avoid manipulating `ULift` -/ def adaptDown {F : Type max u₀ v₀ → Type u₁} {G : Type v₀ → Type v₁} [L : ULiftable G F] [Monad F] {α β} (x : F α) (f : α → G β) : G β := - @down.{v₀, v₁, max u₀ v₀} G F L β <| x >>= @up.{v₀, v₁, max u₀ v₀} G F L β ∘ f + @down.{max u₀ v₀} G F L β <| x >>= @up.{max u₀ v₀} G F L β ∘ f #align uliftable.adapt_down ULiftable.adaptDown /-- map function that moves up universes -/ diff --git a/Mathlib/Data/Complex/Basic.lean b/Mathlib/Data/Complex/Basic.lean index cc157a5435623..f93455b764cda 100644 --- a/Mathlib/Data/Complex/Basic.lean +++ b/Mathlib/Data/Complex/Basic.lean @@ -51,11 +51,13 @@ theorem eta : ∀ z : ℂ, Complex.mk z.re z.im = z | ⟨_, _⟩ => rfl #align complex.eta Complex.eta -@[ext] +-- We only mark this lemma with `ext` *locally* to avoid it applying whenever terms of `ℂ` appear. theorem ext : ∀ {z w : ℂ}, z.re = w.re → z.im = w.im → z = w | ⟨_, _⟩, ⟨_, _⟩, rfl, rfl => rfl #align complex.ext Complex.ext +attribute [local ext] Complex.ext + theorem ext_iff {z w : ℂ} : z = w ↔ z.re = w.re ∧ z.im = w.im := ⟨fun H => by simp [H], fun h => ext h.1 h.2⟩ #align complex.ext_iff Complex.ext_iff diff --git a/Mathlib/Data/Complex/Exponential.lean b/Mathlib/Data/Complex/Exponential.lean index e3ca019eeea19..eb88a2a8a4df1 100644 --- a/Mathlib/Data/Complex/Exponential.lean +++ b/Mathlib/Data/Complex/Exponential.lean @@ -839,7 +839,7 @@ theorem sin_mul_I : sin (x * I) = sinh x * I := by ring_nf simp rw [← neg_neg (sinh x), ← h] - ext <;> simp + apply Complex.ext <;> simp set_option linter.uppercaseLean3 false in #align complex.sin_mul_I Complex.sin_mul_I diff --git a/Mathlib/Data/Complex/Module.lean b/Mathlib/Data/Complex/Module.lean index 3de9c46099c40..293aa9c307443 100644 --- a/Mathlib/Data/Complex/Module.lean +++ b/Mathlib/Data/Complex/Module.lean @@ -50,6 +50,8 @@ open ComplexConjugate variable {R : Type*} {S : Type*} +attribute [local ext] Complex.ext + -- Test that the `SMul ℚ ℂ` instance is correct. example : (Complex.instSMulRealComplex : SMul ℚ ℂ) = (Algebra.toSMul : SMul ℚ ℂ) := rfl diff --git a/Mathlib/Data/Complex/Order.lean b/Mathlib/Data/Complex/Order.lean index 909ad6a5162ac..f5b8f6e368754 100644 --- a/Mathlib/Data/Complex/Order.lean +++ b/Mathlib/Data/Complex/Order.lean @@ -97,7 +97,7 @@ theorem not_lt_zero_iff {z : ℂ} : ¬z < 0 ↔ 0 ≤ z.re ∨ z.im ≠ 0 := #align complex.not_lt_zero_iff Complex.not_lt_zero_iff theorem eq_re_of_ofReal_le {r : ℝ} {z : ℂ} (hz : (r : ℂ) ≤ z) : z = z.re := by - ext + apply Complex.ext rfl simp only [← (Complex.le_def.1 hz).2, Complex.zero_im, Complex.ofReal_im] #align complex.eq_re_of_real_le Complex.eq_re_of_ofReal_le diff --git a/Mathlib/Data/Finite/Card.lean b/Mathlib/Data/Finite/Card.lean index 036aa5758eaff..901503f4944ec 100644 --- a/Mathlib/Data/Finite/Card.lean +++ b/Mathlib/Data/Finite/Card.lean @@ -213,4 +213,23 @@ theorem card_union_le (s t : Set α) : Nat.card (↥(s ∪ t)) ≤ Nat.card s + · exact Nat.card_eq_zero_of_infinite.trans_le (zero_le _) #align set.card_union_le Set.card_union_le +namespace Finite + +variable {s t : Set α} (ht : t.Finite) + +theorem card_lt_card (hsub : s ⊂ t) : Nat.card s < Nat.card t := by + have : Fintype t := Finite.fintype ht + have : Fintype s := Finite.fintype (subset ht (subset_of_ssubset hsub)) + simp only [Nat.card_eq_fintype_card] + exact Set.card_lt_card hsub + +theorem eq_of_subset_of_card_le (hsub : s ⊆ t) (hcard : Nat.card t ≤ Nat.card s) : s = t := + (eq_or_ssubset_of_subset hsub).elim id fun h ↦ absurd hcard <| not_le_of_lt <| ht.card_lt_card h + +theorem equiv_image_eq_iff_subset (e : α ≃ α) (hs : s.Finite) : e '' s = s ↔ e '' s ⊆ s := + ⟨fun h ↦ by rw [h], fun h ↦ hs.eq_of_subset_of_card_le h <| + ge_of_eq (Nat.card_congr (e.image s).symm)⟩ + +end Finite + end Set diff --git a/Mathlib/Data/Finset/Basic.lean b/Mathlib/Data/Finset/Basic.lean index a124cd8b11ea1..edbb46ab77321 100644 --- a/Mathlib/Data/Finset/Basic.lean +++ b/Mathlib/Data/Finset/Basic.lean @@ -1230,7 +1230,7 @@ theorem insert_inj_on (s : Finset α) : Set.InjOn (fun a => insert a s) sᶜ := (insert_inj h).1 #align finset.insert_inj_on Finset.insert_inj_on -theorem ssubset_iff : s ⊂ t ↔ ∃ a, a ∉ s ∧insert a s ⊆ t := mod_cast @Set.ssubset_iff_insert α s t +theorem ssubset_iff : s ⊂ t ↔ ∃ a ∉ s, insert a s ⊆ t := mod_cast @Set.ssubset_iff_insert α s t #align finset.ssubset_iff Finset.ssubset_iff theorem ssubset_insert (h : a ∉ s) : s ⊂ insert a s := @@ -3369,7 +3369,7 @@ theorem toFinset_surjective : Surjective (toFinset : List α → Finset α) := f #align list.to_finset_surjective List.toFinset_surjective theorem toFinset_eq_iff_perm_dedup : l.toFinset = l'.toFinset ↔ l.dedup ~ l'.dedup := by - simp [Finset.ext_iff, perm_ext (nodup_dedup _) (nodup_dedup _)] + simp [Finset.ext_iff, perm_ext_iff_of_nodup (nodup_dedup _) (nodup_dedup _)] #align list.to_finset_eq_iff_perm_dedup List.toFinset_eq_iff_perm_dedup theorem toFinset.ext_iff {a b : List α} : a.toFinset = b.toFinset ↔ ∀ x, x ∈ a ↔ x ∈ b := by @@ -3500,11 +3500,13 @@ theorem exists_list_nodup_eq [DecidableEq α] (s : Finset α) : ⟨s.toList, s.nodup_toList, s.toList_toFinset⟩ #align finset.exists_list_nodup_eq Finset.exists_list_nodup_eq +open scoped List in theorem toList_cons {a : α} {s : Finset α} (h : a ∉ s) : (cons a s h).toList ~ a :: s.toList := - (List.perm_ext (nodup_toList _) (by simp [h, nodup_toList s])).2 fun x => by + (List.perm_ext_iff_of_nodup (nodup_toList _) (by simp [h, nodup_toList s])).2 fun x => by simp only [List.mem_cons, Finset.mem_toList, Finset.mem_cons] #align finset.to_list_cons Finset.toList_cons +open scoped List in theorem toList_insert [DecidableEq α] {a : α} {s : Finset α} (h : a ∉ s) : (insert a s).toList ~ a :: s.toList := cons_eq_insert _ _ h ▸ toList_cons _ diff --git a/Mathlib/Data/Finset/Grade.lean b/Mathlib/Data/Finset/Grade.lean index 0f7af39df6de2..e9582a76958d0 100644 --- a/Mathlib/Data/Finset/Grade.lean +++ b/Mathlib/Data/Finset/Grade.lean @@ -104,13 +104,13 @@ lemma covby_insert (ha : a ∉ s) : s ⋖ insert a s := @[simp] lemma erase_covby (ha : a ∈ s) : s.erase a ⋖ s := ⟨erase_ssubset ha, (erase_wcovby _ _).2⟩ -lemma _root_.Covby.exists_finset_insert (h : s ⋖ t) : ∃ a, a ∉ s ∧ insert a s = t := by +lemma _root_.Covby.exists_finset_insert (h : s ⋖ t) : ∃ a ∉ s, insert a s = t := by simpa using h.exists_finset_cons lemma _root_.Covby.exists_finset_erase (h : s ⋖ t) : ∃ a ∈ t, t.erase a = s := by simpa only [← coe_inj, coe_erase] using h.finset_coe.exists_set_sdiff_singleton -lemma covby_iff_exists_insert : s ⋖ t ↔ ∃ a, a ∉ s ∧ insert a s = t := by +lemma covby_iff_exists_insert : s ⋖ t ↔ ∃ a ∉ s, insert a s = t := by simp only [← coe_covby_coe, Set.covby_iff_exists_insert, ← coe_inj, coe_insert, mem_coe] lemma covby_iff_card_sdiff_eq_one : t ⋖ s ↔ t ⊆ s ∧ (s \ t).card = 1 := by diff --git a/Mathlib/Data/Finset/Option.lean b/Mathlib/Data/Finset/Option.lean index 453a2483a5e66..c2b0bb17da494 100644 --- a/Mathlib/Data/Finset/Option.lean +++ b/Mathlib/Data/Finset/Option.lean @@ -72,6 +72,9 @@ theorem mem_insertNone {s : Finset α} : ∀ {o : Option α}, o ∈ insertNone s | some a => Multiset.mem_cons.trans <| by simp #align finset.mem_insert_none Finset.mem_insertNone +lemma forall_mem_insertNone {s : Finset α} {p : Option α → Prop} : + (∀ a ∈ insertNone s, p a) ↔ p none ∧ ∀ a ∈ s, p a := by simp [Option.forall] + theorem some_mem_insertNone {s : Finset α} {a : α} : some a ∈ insertNone s ↔ a ∈ s := by simp #align finset.some_mem_insert_none Finset.some_mem_insertNone @@ -95,6 +98,9 @@ theorem mem_eraseNone {s : Finset (Option α)} {x : α} : x ∈ eraseNone s ↔ simp [eraseNone] #align finset.mem_erase_none Finset.mem_eraseNone +lemma forall_mem_eraseNone {s : Finset (Option α)} {p : Option α → Prop} : + (∀ a ∈ eraseNone s, p a) ↔ ∀ a : α, (a : Option α) ∈ s → p a := by simp [Option.forall] + theorem eraseNone_eq_biUnion [DecidableEq α] (s : Finset (Option α)) : eraseNone s = s.biUnion Option.toFinset := by ext diff --git a/Mathlib/Data/Finset/Pointwise/Interval.lean b/Mathlib/Data/Finset/Pointwise/Interval.lean new file mode 100644 index 0000000000000..d7870a6744107 --- /dev/null +++ b/Mathlib/Data/Finset/Pointwise/Interval.lean @@ -0,0 +1,95 @@ +/- +Copyright (c) 2023 Eric Wieser. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Eric Wieser +-/ +import Mathlib.Data.Finset.Pointwise +import Mathlib.Data.Finset.Interval +import Mathlib.Data.Set.Pointwise.Interval + + +/-! # Pointwise operations on intervals + +This should be kept in sync with `Mathlib/Data/Set/Pointwise/Interval.lean`. +-/ + +variable {α : Type*} + +namespace Finset + +open scoped Pointwise + +/-! ### Binary pointwise operations + +Note that the subset operations below only cover the cases with the largest possible intervals on +the LHS: to conclude that `Ioo a b * Ioo c d ⊆ Ioo (a * c) (c * d)`, you can use monotonicity of `*` +and `Finset.Ico_mul_Ioc_subset`. + +TODO: repeat these lemmas for the generality of `mul_le_mul` (which assumes nonnegativity), which +the unprimed names have been reserved for +-/ + +section ContravariantLE + +variable [Mul α] [Preorder α] [DecidableEq α] +variable [CovariantClass α α (· * ·) (· ≤ ·)] [CovariantClass α α (Function.swap HMul.hMul) LE.le] + +@[to_additive Icc_add_Icc_subset] +theorem Icc_mul_Icc_subset' [LocallyFiniteOrder α] (a b c d : α) : + Icc a b * Icc c d ⊆ Icc (a * c) (b * d) := + Finset.coe_subset.mp <| by simpa using Set.Icc_mul_Icc_subset' _ _ _ _ + +@[to_additive Iic_add_Iic_subset] +theorem Iic_mul_Iic_subset' [LocallyFiniteOrderBot α] (a b : α) : Iic a * Iic b ⊆ Iic (a * b) := + Finset.coe_subset.mp <| by simpa using Set.Iic_mul_Iic_subset' _ _ + +@[to_additive Ici_add_Ici_subset] +theorem Ici_mul_Ici_subset' [LocallyFiniteOrderTop α] (a b : α) : Ici a * Ici b ⊆ Ici (a * b) := + Finset.coe_subset.mp <| by simpa using Set.Ici_mul_Ici_subset' _ _ + +end ContravariantLE + +section ContravariantLT + +variable [Mul α] [PartialOrder α] [DecidableEq α] +variable [CovariantClass α α (· * ·) (· < ·)] [CovariantClass α α (Function.swap HMul.hMul) LT.lt] + +@[to_additive Icc_add_Ico_subset] +theorem Icc_mul_Ico_subset' [LocallyFiniteOrder α] (a b c d : α) : + Icc a b * Ico c d ⊆ Ico (a * c) (b * d) := + Finset.coe_subset.mp <| by simpa using Set.Icc_mul_Ico_subset' _ _ _ _ + +@[to_additive Ico_add_Icc_subset] +theorem Ico_mul_Icc_subset' [LocallyFiniteOrder α] (a b c d : α) : + Ico a b * Icc c d ⊆ Ico (a * c) (b * d) := + Finset.coe_subset.mp <| by simpa using Set.Ico_mul_Icc_subset' _ _ _ _ + +@[to_additive Ioc_add_Ico_subset] +theorem Ioc_mul_Ico_subset' [LocallyFiniteOrder α] (a b c d : α) : + Ioc a b * Ico c d ⊆ Ioo (a * c) (b * d) := + Finset.coe_subset.mp <| by simpa using Set.Ioc_mul_Ico_subset' _ _ _ _ + +@[to_additive Ico_add_Ioc_subset] +theorem Ico_mul_Ioc_subset' [LocallyFiniteOrder α] (a b c d : α) : + Ico a b * Ioc c d ⊆ Ioo (a * c) (b * d) := + Finset.coe_subset.mp <| by simpa using Set.Ico_mul_Ioc_subset' _ _ _ _ + +@[to_additive Iic_add_Iio_subset] +theorem Iic_mul_Iio_subset' [LocallyFiniteOrderBot α] (a b : α) : Iic a * Iio b ⊆ Iio (a * b) := + Finset.coe_subset.mp <| by simpa using Set.Iic_mul_Iio_subset' _ _ + +@[to_additive Iio_add_Iic_subset] +theorem Iio_mul_Iic_subset' [LocallyFiniteOrderBot α] (a b : α) : Iio a * Iic b ⊆ Iio (a * b) := + Finset.coe_subset.mp <| by simpa using Set.Iio_mul_Iic_subset' _ _ + +@[to_additive Ioi_add_Ici_subset] +theorem Ioi_mul_Ici_subset' [LocallyFiniteOrderTop α] (a b : α) : Ioi a * Ici b ⊆ Ioi (a * b) := + Finset.coe_subset.mp <| by simpa using Set.Ioi_mul_Ici_subset' _ _ + +@[to_additive Ici_add_Ioi_subset] +theorem Ici_mul_Ioi_subset' [LocallyFiniteOrderTop α] (a b : α) : Ici a * Ioi b ⊆ Ioi (a * b) := + Finset.coe_subset.mp <| by simpa using Set.Ici_mul_Ioi_subset' _ _ + +end ContravariantLT + +end Finset diff --git a/Mathlib/Data/Finset/Sigma.lean b/Mathlib/Data/Finset/Sigma.lean index cb6b7427db699..d0dced048e5b1 100644 --- a/Mathlib/Data/Finset/Sigma.lean +++ b/Mathlib/Data/Finset/Sigma.lean @@ -52,7 +52,7 @@ theorem mem_sigma {a : Σi, α i} : a ∈ s.sigma t ↔ a.1 ∈ s ∧ a.2 ∈ t @[simp, norm_cast] theorem coe_sigma (s : Finset ι) (t : ∀ i, Finset (α i)) : - (s.sigma t : Set (Σi, α i)) = (s : Set ι).Sigma fun i => (t i : Set (α i)) := + (s.sigma t : Set (Σ i, α i)) = (s : Set ι).sigma fun i ↦ (t i : Set (α i)) := Set.ext fun _ => mem_sigma #align finset.coe_sigma Finset.coe_sigma diff --git a/Mathlib/Data/Finset/Sort.lean b/Mathlib/Data/Finset/Sort.lean index b83b95db7ae78..3665e174537b0 100644 --- a/Mathlib/Data/Finset/Sort.lean +++ b/Mathlib/Data/Finset/Sort.lean @@ -74,6 +74,7 @@ theorem sort_singleton (a : α) : sort r {a} = [a] := Multiset.sort_singleton r a #align finset.sort_singleton Finset.sort_singleton +open scoped List in theorem sort_perm_toList (s : Finset α) : sort r s ~ s.toList := by rw [← Multiset.coe_eq_coe] simp only [coe_toList, sort_eq] diff --git a/Mathlib/Data/Finsupp/BigOperators.lean b/Mathlib/Data/Finsupp/BigOperators.lean index 278ef2717fe90..fe21c6fd43723 100644 --- a/Mathlib/Data/Finsupp/BigOperators.lean +++ b/Mathlib/Data/Finsupp/BigOperators.lean @@ -107,7 +107,7 @@ theorem Multiset.support_sum_eq [AddCommMonoid M] (s : Multiset (ι →₀ M)) simp only [quot_mk_to_coe'', coe_map, sup_coe, ge_iff_le, Finset.le_eq_subset, Finset.sup_eq_union, Finset.bot_eq_empty, List.foldr_map] · simp only [Multiset.quot_mk_to_coe'', Multiset.coe_map, Multiset.coe_eq_coe] at hl - exact hl.symm.pairwise hd fun _ _ h ↦ _root_.Disjoint.symm h + exact hl.symm.pairwise hd fun h ↦ _root_.Disjoint.symm h #align multiset.support_sum_eq Multiset.support_sum_eq theorem Finset.support_sum_eq [AddCommMonoid M] (s : Finset (ι →₀ M)) diff --git a/Mathlib/Data/Finsupp/Defs.lean b/Mathlib/Data/Finsupp/Defs.lean index 1c85fc688c704..aa394fb687f5c 100644 --- a/Mathlib/Data/Finsupp/Defs.lean +++ b/Mathlib/Data/Finsupp/Defs.lean @@ -3,7 +3,8 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Scott Morrison -/ -import Mathlib.Algebra.IndicatorFunction +import Mathlib.Algebra.BigOperators.Basic +import Mathlib.Data.Set.Finite import Mathlib.GroupTheory.Submonoid.Basic #align_import data.finsupp.defs from "leanprover-community/mathlib"@"842328d9df7e96fd90fc424e115679c15fb23a71" diff --git a/Mathlib/Data/Finsupp/Pointwise.lean b/Mathlib/Data/Finsupp/Pointwise.lean index 0e5fa531a6821..ca9d3b4b08ab0 100644 --- a/Mathlib/Data/Finsupp/Pointwise.lean +++ b/Mathlib/Data/Finsupp/Pointwise.lean @@ -3,8 +3,9 @@ Copyright (c) 2020 Scott Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Scott Morrison -/ -import Mathlib.Data.Finsupp.Defs +import Mathlib.Algebra.Module.Basic import Mathlib.Algebra.Ring.Pi +import Mathlib.Data.Finsupp.Defs #align_import data.finsupp.pointwise from "leanprover-community/mathlib"@"f7fc89d5d5ff1db2d1242c7bb0e9062ce47ef47c" diff --git a/Mathlib/Data/Fintype/Card.lean b/Mathlib/Data/Fintype/Card.lean index dd578060bf36f..312325eea6653 100644 --- a/Mathlib/Data/Fintype/Card.lean +++ b/Mathlib/Data/Fintype/Card.lean @@ -1109,28 +1109,19 @@ private noncomputable def natEmbeddingAux (α : Type*) [Infinite α] : ℕ → ((Multiset.range n).pmap (fun m (hm : m < n) => natEmbeddingAux _ m) fun _ => Multiset.mem_range.1).toFinset) --- Porting note: new theorem, to work around missing `wlog` -private theorem natEmbeddingAux_injective_aux (α : Type*) [Infinite α] (m n : ℕ) - (h : Infinite.natEmbeddingAux α m = Infinite.natEmbeddingAux α n) (hmn : m < n) : m = n := by - letI := Classical.decEq α - exfalso - refine' - (Classical.choose_spec - (exists_not_mem_finset - ((Multiset.range n).pmap (fun m (_hm : m < n) => natEmbeddingAux α m) fun _ => - Multiset.mem_range.1).toFinset)) - _ - refine' Multiset.mem_toFinset.2 (Multiset.mem_pmap.2 ⟨m, Multiset.mem_range.2 hmn, _⟩) - rw [h, natEmbeddingAux] - private theorem natEmbeddingAux_injective (α : Type*) [Infinite α] : Function.Injective (natEmbeddingAux α) := by rintro m n h letI := Classical.decEq α - rcases lt_trichotomy m n with hmn | rfl | hnm - · apply natEmbeddingAux_injective_aux α m n h hmn - · rfl - · apply (natEmbeddingAux_injective_aux α n m h.symm hnm).symm + wlog hmlen : m ≤ n generalizing m n + · exact (this h.symm $ le_of_not_le hmlen).symm + by_contra hmn + have hmn : m < n := lt_of_le_of_ne hmlen hmn + refine (Classical.choose_spec (exists_not_mem_finset + ((Multiset.range n).pmap (λ m (_ : m < n) => natEmbeddingAux α m) + (fun _ => Multiset.mem_range.1)).toFinset)) ?_ + refine Multiset.mem_toFinset.2 (Multiset.mem_pmap.2 ⟨m, Multiset.mem_range.2 hmn, ?_⟩) + rw [h, natEmbeddingAux] /-- Embedding of `ℕ` into an infinite type. -/ noncomputable def natEmbedding (α : Type*) [Infinite α] : ℕ ↪ α := diff --git a/Mathlib/Data/Fintype/Prod.lean b/Mathlib/Data/Fintype/Prod.lean index ea8a912e8a7ab..a4db59e985088 100644 --- a/Mathlib/Data/Fintype/Prod.lean +++ b/Mathlib/Data/Fintype/Prod.lean @@ -44,12 +44,17 @@ end Set instance instFintypeProd (α β : Type*) [Fintype α] [Fintype β] : Fintype (α × β) := ⟨univ ×ˢ univ, fun ⟨a, b⟩ => by simp⟩ -@[simp] -theorem Finset.univ_product_univ {α β : Type*} [Fintype α] [Fintype β] : - (univ : Finset α) ×ˢ (univ : Finset β) = univ := - rfl +namespace Finset +variable [Fintype α] [Fintype β] {s : Finset α} {t : Finset β} + +@[simp] lemma univ_product_univ : univ ×ˢ univ = (univ : Finset (α × β)) := rfl #align finset.univ_product_univ Finset.univ_product_univ +@[simp] lemma product_eq_univ [Nonempty α] [Nonempty β] : s ×ˢ t = univ ↔ s = univ ∧ t = univ := by + simp [eq_univ_iff_forall, forall_and] + +end Finset + @[simp] theorem Fintype.card_prod (α β : Type*) [Fintype α] [Fintype β] : Fintype.card (α × β) = Fintype.card α * Fintype.card β := diff --git a/Mathlib/Data/Int/Basic.lean b/Mathlib/Data/Int/Basic.lean index 698e503bec8d3..be0dd2169bc10 100644 --- a/Mathlib/Data/Int/Basic.lean +++ b/Mathlib/Data/Int/Basic.lean @@ -140,9 +140,6 @@ theorem sign_coe_add_one (n : ℕ) : Int.sign (n + 1) = 1 := rfl #align int.sign_coe_add_one Int.sign_coe_add_one -@[simp] -theorem sign_negSucc (n : ℕ) : Int.sign -[n+1] = -1 := - rfl #align int.sign_neg_succ_of_nat Int.sign_negSucc /-! ### succ and pred -/ diff --git a/Mathlib/Data/Int/CharZero.lean b/Mathlib/Data/Int/CharZero.lean index fa9fb66cfdc73..b4c716548800c 100644 --- a/Mathlib/Data/Int/CharZero.lean +++ b/Mathlib/Data/Int/CharZero.lean @@ -3,6 +3,7 @@ Copyright (c) 2017 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ +import Mathlib.Algebra.Function.Support import Mathlib.Data.Int.Cast.Field #align_import data.int.char_zero from "leanprover-community/mathlib"@"29cb56a7b35f72758b05a30490e1f10bd62c35c1" @@ -12,10 +13,9 @@ import Mathlib.Data.Int.Cast.Field -/ +open Nat Set -variable {α : Type*} - -open Nat +variable {α β : Type*} namespace Int @@ -72,3 +72,16 @@ theorem RingHom.injective_int {α : Type*} [NonAssocRing α] (f : ℤ →+* α) Function.Injective f := Subsingleton.elim (Int.castRingHom _) f ▸ Int.cast_injective #align ring_hom.injective_int RingHom.injective_int + +namespace Function +variable [AddGroupWithOne β] [CharZero β] {n : ℤ} + +lemma support_int_cast (hn : n ≠ 0) : support (n : α → β) = univ := + support_const $ Int.cast_ne_zero.2 hn +#align function.support_int_cast Function.support_int_cast + +lemma mulSupport_int_cast (hn : n ≠ 1) : mulSupport (n : α → β) = univ := + mulSupport_const $ Int.cast_ne_one.2 hn +#align function.mul_support_int_cast Function.mulSupport_int_cast + +end Function diff --git a/Mathlib/Data/List/Basic.lean b/Mathlib/Data/List/Basic.lean index 9ad454e15f2a5..f13b3ff8ff6af 100644 --- a/Mathlib/Data/List/Basic.lean +++ b/Mathlib/Data/List/Basic.lean @@ -4243,15 +4243,6 @@ instance (p : α → Prop) [DecidablePred p] : DecidablePred (Forall p) := fun _ end Forall -/-! ### Retroattributes - -The list definitions happen earlier than `to_additive`, so here we tag the few multiplicative -definitions that couldn't be tagged earlier. --/ - -attribute [to_additive existing] List.prod -- `List.sum` -attribute [to_additive existing] alternatingProd -- `List.alternatingSum` - /-! ### Miscellaneous lemmas -/ theorem getLast_reverse {l : List α} (hl : l.reverse ≠ []) diff --git a/Mathlib/Data/List/BigOperators/Basic.lean b/Mathlib/Data/List/BigOperators/Basic.lean index 0e16729b630e4..3f9dd02a8f11d 100644 --- a/Mathlib/Data/List/BigOperators/Basic.lean +++ b/Mathlib/Data/List/BigOperators/Basic.lean @@ -3,6 +3,7 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Floris van Doorn, Sébastien Gouëzel, Alex J. Best -/ +import Mathlib.Data.List.BigOperators.Defs import Mathlib.Data.Int.Order.Basic import Mathlib.Data.List.Forall2 @@ -13,10 +14,9 @@ import Mathlib.Data.List.Forall2 This file provides basic results about `List.prod`, `List.sum`, which calculate the product and sum of elements of a list and `List.alternating_prod`, `List.alternating_sum`, their alternating -counterparts. These are defined in [`Data.List.Defs`](./Defs). +counterparts. These are defined in [`Data.List.BigOperators.Defs`](./Defs). -/ - variable {ι α M N P M₀ G R : Type*} namespace List @@ -104,6 +104,13 @@ theorem prod_hom_rel (l : List ι) {r : M → N → Prop} {f : ι → M} {g : ι #align list.prod_hom_rel List.prod_hom_rel #align list.sum_hom_rel List.sum_hom_rel +@[to_additive] +theorem rel_prod {R : M → N → Prop} (h : R 1 1) (hf : (R ⇒ R ⇒ R) (· * ·) (· * ·)) : + (Forall₂ R ⇒ R) prod prod := + rel_foldl hf h +#align list.rel_prod List.rel_prod +#align list.rel_sum List.rel_sum + @[to_additive] theorem prod_hom (l : List M) {F : Type*} [MonoidHomClass F M N] (f : F) : (l.map f).prod = f l.prod := by diff --git a/Mathlib/Data/List/BigOperators/Defs.lean b/Mathlib/Data/List/BigOperators/Defs.lean new file mode 100644 index 0000000000000..8eb866901171d --- /dev/null +++ b/Mathlib/Data/List/BigOperators/Defs.lean @@ -0,0 +1,42 @@ +/- +Copyright (c) 2014 Parikshit Khanna. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Mario Carneiro +-/ +import Mathlib.Data.List.Defs +import Mathlib.Algebra.Group.Defs + +#align_import data.list.defs from "leanprover-community/mathlib"@"d2d8742b0c21426362a9dacebc6005db895ca963" + +/-! +## Products and sums over lists + +-/ + +namespace List + +/-- Product of a list. + +`List.prod [a, b, c] = ((1 * a) * b) * c` -/ +@[to_additive "Sum of a list.\n\n`List.sum [a, b, c] = ((0 + a) + b) + c`"] +def prod {α} [Mul α] [One α] : List α → α := + foldl (· * ·) 1 +#align list.prod List.prod +#align list.sum List.sum + +/-- The alternating sum of a list. -/ +def alternatingSum {G : Type*} [Zero G] [Add G] [Neg G] : List G → G + | [] => 0 + | g :: [] => g + | g :: h :: t => g + -h + alternatingSum t +#align list.alternating_sum List.alternatingSum + +/-- The alternating product of a list. -/ +@[to_additive existing] +def alternatingProd {G : Type*} [One G] [Mul G] [Inv G] : List G → G + | [] => 1 + | g :: [] => g + | g :: h :: t => g * h⁻¹ * alternatingProd t +#align list.alternating_prod List.alternatingProd + +end List diff --git a/Mathlib/Data/List/Defs.lean b/Mathlib/Data/List/Defs.lean index 4acee6ce4f8da..b318571705e5b 100644 --- a/Mathlib/Data/List/Defs.lean +++ b/Mathlib/Data/List/Defs.lean @@ -3,9 +3,8 @@ Copyright (c) 2014 Parikshit Khanna. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Mario Carneiro -/ -import Mathlib.Algebra.Group.Defs +import Mathlib.Init.Data.Nat.Notation import Mathlib.Control.Functor -import Mathlib.Data.Nat.Basic import Mathlib.Logic.Basic import Mathlib.Data.SProd import Mathlib.Util.CompileInductive @@ -74,37 +73,6 @@ def takeI [Inhabited α] (n : Nat) (l : List α) : List α := #align list.take_while List.takeWhile #align list.scanl List.scanl #align list.scanr List.scanr - -/-- Product of a list. - - `List.prod [a, b, c] = ((1 * a) * b) * c` -/ -def prod [Mul α] [One α] : List α → α := - foldl (· * ·) 1 -#align list.prod List.prod - --- Later this will be tagged with `to_additive`, but this can't be done yet because of imports. --- dependencies. -/-- Sum of a list. - - `List.sum [a, b, c] = ((0 + a) + b) + c` -/ -def sum [Add α] [Zero α] : List α → α := - foldl (· + ·) 0 -#align list.sum List.sum - -/-- The alternating sum of a list. -/ -def alternatingSum {G : Type*} [Zero G] [Add G] [Neg G] : List G → G - | [] => 0 - | g :: [] => g - | g :: h :: t => g + -h + alternatingSum t -#align list.alternating_sum List.alternatingSum - -/-- The alternating product of a list. -/ -def alternatingProd {G : Type*} [One G] [Mul G] [Inv G] : List G → G - | [] => 1 - | g :: [] => g - | g :: h :: t => g * h⁻¹ * alternatingProd t -#align list.alternating_prod List.alternatingProd - #align list.partition_map List.partitionMap #align list.find List.find? diff --git a/Mathlib/Data/List/FinRange.lean b/Mathlib/Data/List/FinRange.lean index f39ee2d5a3648..d7705ebaa3aa8 100644 --- a/Mathlib/Data/List/FinRange.lean +++ b/Mathlib/Data/List/FinRange.lean @@ -78,7 +78,7 @@ open List theorem Equiv.Perm.map_finRange_perm {n : ℕ} (σ : Equiv.Perm (Fin n)) : map σ (finRange n) ~ finRange n := by - rw [perm_ext ((nodup_finRange n).map σ.injective) <| nodup_finRange n] + rw [perm_ext_iff_of_nodup ((nodup_finRange n).map σ.injective) <| nodup_finRange n] simpa [mem_map, mem_finRange, true_and_iff, iff_true_iff] using σ.surjective #align equiv.perm.map_fin_range_perm Equiv.Perm.map_finRange_perm diff --git a/Mathlib/Data/List/Forall2.lean b/Mathlib/Data/List/Forall2.lean index 364778c1aa3e3..a69cd1833cd61 100644 --- a/Mathlib/Data/List/Forall2.lean +++ b/Mathlib/Data/List/Forall2.lean @@ -309,13 +309,6 @@ theorem rel_filterMap : ((R ⇒ Option.Rel P) ⇒ Forall₂ R ⇒ Forall₂ P) f | _, _, Option.Rel.some h => Forall₂.cons h (rel_filterMap (@hfg) h₂) #align list.rel_filter_map List.rel_filterMap -@[to_additive] -theorem rel_prod [Monoid α] [Monoid β] (h : R 1 1) (hf : (R ⇒ R ⇒ R) (· * ·) (· * ·)) : - (Forall₂ R ⇒ R) prod prod := - rel_foldl hf h -#align list.rel_prod List.rel_prod -#align list.rel_sum List.rel_sum - /-- Given a relation `R`, `sublist_forall₂ r l₁ l₂` indicates that there is a sublist of `l₂` such that `forall₂ r l₁ l₂`. -/ inductive SublistForall₂ (R : α → β → Prop) : List α → List β → Prop diff --git a/Mathlib/Data/List/Perm.lean b/Mathlib/Data/List/Perm.lean index dd7b1cfa8e240..76bd4badd51ca 100644 --- a/Mathlib/Data/List/Perm.lean +++ b/Mathlib/Data/List/Perm.lean @@ -27,13 +27,6 @@ open Nat namespace List variable {α β : Type*} {l l₁ l₂ : List α} {a : α} -/-- `Perm l₁ l₂` or `l₁ ~ l₂` asserts that `l₁` and `l₂` are permutations - of each other. This is defined by induction using pairwise swaps. -/ -inductive Perm : List α → List α → Prop - | nil : Perm [] [] - | cons (x : α) {l₁ l₂ : List α} : Perm l₁ l₂ → Perm (x :: l₁) (x :: l₂) - | swap (x y : α) (l : List α) : Perm (y :: x :: l) (x :: y :: l) - | trans {l₁ l₂ l₃ : List α} : Perm l₁ l₂ → Perm l₂ l₃ → Perm l₁ l₃ #align list.perm List.Perm instance {α : Type*} : Trans (@List.Perm α) (@List.Perm α) List.Perm where @@ -41,61 +34,27 @@ instance {α : Type*} : Trans (@List.Perm α) (@List.Perm α) List.Perm where open Perm (swap) -/-- `Perm l₁ l₂` or `l₁ ~ l₂` asserts that `l₁` and `l₂` are permutations - of each other. This is defined by induction using pairwise swaps. -/ -infixl:50 " ~ " => Perm - -@[simp, refl] -protected theorem Perm.refl : ∀ l : List α, l ~ l - | [] => Perm.nil - | x :: xs => (Perm.refl xs).cons x +attribute [refl] Perm.refl #align list.perm.refl List.Perm.refl lemma perm_rfl : l ~ l := Perm.refl _ -- Porting note: used rec_on in mathlib3; lean4 eqn compiler still doesn't like it -@[symm] -protected theorem Perm.symm {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₂ ~ l₁ := - p.rec - .nil - (fun x _ _ _ r₁ => .cons x r₁) - (fun x y l => .swap y x l) - (fun _ _ r₁ r₂ => .trans r₂ r₁) +attribute [symm] Perm.symm #align list.perm.symm List.Perm.symm -theorem perm_comm {l₁ l₂ : List α} : l₁ ~ l₂ ↔ l₂ ~ l₁ := - ⟨Perm.symm, Perm.symm⟩ #align list.perm_comm List.perm_comm -theorem Perm.swap' (x y : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : y :: x :: l₁ ~ x :: y :: l₂ := - (swap _ _ _).trans ((p.cons _).cons _) #align list.perm.swap' List.Perm.swap' attribute [trans] Perm.trans -theorem Perm.eqv (α) : Equivalence (@Perm α) := - ⟨Perm.refl, Perm.symm, Perm.trans⟩ #align list.perm.eqv List.Perm.eqv ---Porting note: new theorem -theorem Perm.of_eq (h : l₁ = l₂) : l₁ ~ l₂ := - h ▸ Perm.refl l₁ - -instance isSetoid (α) : Setoid (List α) := - Setoid.mk (@Perm α) (Perm.eqv α) #align list.is_setoid List.isSetoid --- Porting note: used rec_on in mathlib3; lean4 eqn compiler still doesn't like it -theorem Perm.mem_iff {a : α} {l₁ l₂ : List α} (p : l₁ ~ l₂) : a ∈ l₁ ↔ a ∈ l₂ := - p.rec - Iff.rfl - (fun _ _ _ _ hs => by simp only [mem_cons, hs]) - (fun _ _ _ => by simp only [mem_cons, or_left_comm]) - (fun _ _ => Iff.trans) #align list.perm.mem_iff List.Perm.mem_iff -theorem Perm.subset {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁ ⊆ l₂ := - fun _ => p.mem_iff.mp #align list.perm.subset List.Perm.subset theorem Perm.subset_congr_left {l₁ l₂ l₃ : List α} (h : l₁ ~ l₂) : l₁ ⊆ l₃ ↔ l₂ ⊆ l₃ := @@ -106,219 +65,66 @@ theorem Perm.subset_congr_right {l₁ l₂ l₃ : List α} (h : l₁ ~ l₂) : l ⟨fun h' => h'.trans h.subset, fun h' => h'.trans h.symm.subset⟩ #align list.perm.subset_congr_right List.Perm.subset_congr_right -theorem Perm.append_right {l₁ l₂ : List α} (t₁ : List α) (p : l₁ ~ l₂) : l₁ ++ t₁ ~ l₂ ++ t₁ := - p.rec - (Perm.refl ([] ++ t₁)) - (fun x _ _ _ r₁ => r₁.cons x) - (fun x y _ => swap x y _) - (fun _ _ r₁ r₂ => r₁.trans r₂) #align list.perm.append_right List.Perm.append_right -theorem Perm.append_left {t₁ t₂ : List α} : ∀ l : List α, t₁ ~ t₂ → l ++ t₁ ~ l ++ t₂ - | [], p => p - | x :: xs, p => (p.append_left xs).cons x #align list.perm.append_left List.Perm.append_left -theorem Perm.append {l₁ l₂ t₁ t₂ : List α} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) : l₁ ++ t₁ ~ l₂ ++ t₂ := - (p₁.append_right t₁).trans (p₂.append_left l₂) #align list.perm.append List.Perm.append -theorem Perm.append_cons (a : α) {h₁ h₂ t₁ t₂ : List α} (p₁ : h₁ ~ h₂) (p₂ : t₁ ~ t₂) : - h₁ ++ a :: t₁ ~ h₂ ++ a :: t₂ := - p₁.append (p₂.cons a) #align list.perm.append_cons List.Perm.append_cons -@[simp] -theorem perm_middle {a : α} : ∀ {l₁ l₂ : List α}, l₁ ++ a :: l₂ ~ a :: (l₁ ++ l₂) - | [], _ => Perm.refl _ - | b :: l₁, l₂ => ((@perm_middle a l₁ l₂).cons _).trans (swap a b _) #align list.perm_middle List.perm_middle -@[simp] -theorem perm_append_singleton (a : α) (l : List α) : l ++ [a] ~ a :: l := - perm_middle.trans <| by rw [append_nil] #align list.perm_append_singleton List.perm_append_singleton -theorem perm_append_comm : ∀ {l₁ l₂ : List α}, l₁ ++ l₂ ~ l₂ ++ l₁ - | [], l₂ => by simp - | a :: t, l₂ => (perm_append_comm.cons _).trans perm_middle.symm #align list.perm_append_comm List.perm_append_comm -theorem concat_perm (l : List α) (a : α) : concat l a ~ a :: l := by simp #align list.concat_perm List.concat_perm -theorem Perm.length_eq {l₁ l₂ : List α} (p : l₁ ~ l₂) : length l₁ = length l₂ := - p.rec - rfl - (fun _x l₁ l₂ _p r => by simp [r]) - (fun _x _y l => by simp) - (fun _p₁ _p₂ r₁ r₂ => Eq.trans r₁ r₂) #align list.perm.length_eq List.Perm.length_eq -theorem Perm.eq_nil {l : List α} (p : l ~ []) : l = [] := - eq_nil_of_length_eq_zero p.length_eq #align list.perm.eq_nil List.Perm.eq_nil -theorem Perm.nil_eq {l : List α} (p : [] ~ l) : [] = l := - p.symm.eq_nil.symm #align list.perm.nil_eq List.Perm.nil_eq -@[simp] -theorem perm_nil {l₁ : List α} : l₁ ~ [] ↔ l₁ = [] := - ⟨fun p => p.eq_nil, fun e => e ▸ Perm.refl _⟩ #align list.perm_nil List.perm_nil -@[simp] -theorem nil_perm {l₁ : List α} : [] ~ l₁ ↔ l₁ = [] := - perm_comm.trans perm_nil #align list.nil_perm List.nil_perm -theorem not_perm_nil_cons (x : α) (l : List α) : ¬[] ~ x :: l - | p => by injection p.symm.eq_nil #align list.not_perm_nil_cons List.not_perm_nil_cons -@[simp] -theorem reverse_perm : ∀ l : List α, reverse l ~ l - | [] => Perm.nil - | a :: l => by - rw [reverse_cons] - exact (perm_append_singleton _ _).trans ((reverse_perm l).cons a) #align list.reverse_perm List.reverse_perm -theorem perm_cons_append_cons {l l₁ l₂ : List α} (a : α) (p : l ~ l₁ ++ l₂) : - a :: l ~ l₁ ++ a :: l₂ := - (p.cons a).trans perm_middle.symm #align list.perm_cons_append_cons List.perm_cons_append_cons -@[simp] -theorem perm_replicate {n : ℕ} {a : α} {l : List α} : - l ~ replicate n a ↔ l = replicate n a := - ⟨fun p => eq_replicate.2 - ⟨p.length_eq.trans <| length_replicate _ _, fun _b m => eq_of_mem_replicate <| p.subset m⟩, - fun h => h ▸ Perm.refl _⟩ #align list.perm_replicate List.perm_replicate -@[simp] -theorem replicate_perm {n : ℕ} {a : α} {l : List α} : - replicate n a ~ l ↔ replicate n a = l := - (perm_comm.trans perm_replicate).trans eq_comm #align list.replicate_perm List.replicate_perm -@[simp] -theorem perm_singleton {a : α} {l : List α} : l ~ [a] ↔ l = [a] := - @perm_replicate α 1 a l #align list.perm_singleton List.perm_singleton -@[simp] -theorem singleton_perm {a : α} {l : List α} : [a] ~ l ↔ [a] = l := - @replicate_perm α 1 a l #align list.singleton_perm List.singleton_perm -alias ⟨Perm.eq_singleton, _⟩ := perm_singleton -alias ⟨Perm.singleton_eq, _⟩ := singleton_perm - -theorem singleton_perm_singleton {a b : α} : [a] ~ [b] ↔ a = b := by simp #align list.singleton_perm_singleton List.singleton_perm_singleton -theorem perm_cons_erase [DecidableEq α] {a : α} {l : List α} (h : a ∈ l) : l ~ a :: l.erase a := - let ⟨_l₁, _l₂, _, e₁, e₂⟩ := exists_erase_eq h - e₂.symm ▸ e₁.symm ▸ perm_middle #align list.perm_cons_erase List.perm_cons_erase -@[elab_as_elim] -theorem perm_induction_on {P : List α → List α → Prop} {l₁ l₂ : List α} (p : l₁ ~ l₂) (h₁ : P [] []) - (h₂ : ∀ x l₁ l₂, l₁ ~ l₂ → P l₁ l₂ → P (x :: l₁) (x :: l₂)) - (h₃ : ∀ x y l₁ l₂, l₁ ~ l₂ → P l₁ l₂ → P (y :: x :: l₁) (x :: y :: l₂)) - (h₄ : ∀ l₁ l₂ l₃, l₁ ~ l₂ → l₂ ~ l₃ → P l₁ l₂ → P l₂ l₃ → P l₁ l₃) : P l₁ l₂ := - have P_refl : ∀ l, P l l := fun l => List.recOn l h₁ fun x xs ih => h₂ x xs xs (Perm.refl xs) ih - p.rec h₁ h₂ (fun x y l => h₃ x y l l (Perm.refl l) (P_refl l)) @h₄ -#align list.perm_induction_on List.perm_induction_onₓ +#align list.perm_induction_on List.Perm.recOnSwap' --- Porting note: TODO figure out why invalid congr --- @[congr] -theorem Perm.filterMap (f : α → Option β) {l₁ l₂ : List α} (p : l₁ ~ l₂) : - filterMap f l₁ ~ filterMap f l₂ := by - induction p with - | nil => simp - | cons x _p IH => - cases h : f x - <;> simp [h, filterMap, IH, Perm.cons] - | swap x y l₂ => - cases hx : f x - <;> cases hy : f y - <;> simp [hx, hy, filterMap, swap] - | trans _p₁ _p₂ IH₁ IH₂ => - exact IH₁.trans IH₂ +-- Porting note: used to be @[congr] #align list.perm.filter_map List.Perm.filterMap --- Porting note: TODO figure out why invalid congr --- @[congr] -theorem Perm.map (f : α → β) {l₁ l₂ : List α} (p : l₁ ~ l₂) : map f l₁ ~ map f l₂ := - filterMap_eq_map f ▸ p.filterMap _ +-- Porting note: used to be @[congr] #align list.perm.map List.Perm.map -theorem Perm.pmap {p : α → Prop} (f : ∀ a, p a → β) {l₁ l₂ : List α} (p : l₁ ~ l₂) {H₁ H₂} : - pmap f l₁ H₁ ~ pmap f l₂ H₂ := by - induction p with - | nil => simp - | cons x _p IH => simp [IH, Perm.cons] - | swap x y => simp [swap] - | trans _p₁ p₂ IH₁ IH₂ => - refine' IH₁.trans IH₂ - exact fun a m => H₂ a (p₂.subset m) #align list.perm.pmap List.Perm.pmap -theorem Perm.filter (p : α → Bool) {l₁ l₂ : List α} (s : l₁ ~ l₂) : - filter p l₁ ~ filter p l₂ := by rw [← filterMap_eq_filter]; apply s.filterMap _ #align list.perm.filter List.Perm.filter -theorem filter_append_perm (p : α → Bool) (l : List α) : - filter p l ++ filter (fun x => ¬p x) l ~ l := by - induction' l with x l ih - · rfl - · by_cases h : p x - · simp only [h, filter_cons_of_pos, filter_cons_of_neg, not_true, not_false_iff, cons_append, - decide_False] - exact ih.cons x - · simp only [h, filter_cons_of_neg, not_false_iff, filter_cons_of_pos, cons_append, - not_false_eq_true, decide_True] - refine' Perm.trans _ (ih.cons x) - exact perm_append_comm.trans (perm_append_comm.cons _) #align list.filter_append_perm List.filter_append_perm -theorem exists_perm_sublist {l₁ l₂ l₂' : List α} (s : l₁ <+ l₂) (p : l₂ ~ l₂') : - ∃ (l₁' : _) (_ : l₁' ~ l₁), l₁' <+ l₂' := by - induction p generalizing l₁ with - | nil => - exact ⟨[], eq_nil_of_sublist_nil s ▸ Perm.refl _, nil_sublist _⟩ - | cons x _ IH => - cases' s with _ _ _ s l₁ _ _ s - · exact - let ⟨l₁', p', s'⟩ := IH s - ⟨l₁', p', s'.cons _⟩ - · exact - let ⟨l₁', p', s'⟩ := IH s - ⟨x :: l₁', p'.cons x, s'.cons₂ _⟩ - | swap x y _ => - cases' s with _ _ _ s l₁ _ _ s <;> cases' s with _ _ _ s l₁ _ _ s - · exact ⟨l₁, Perm.refl _, (s.cons _).cons _⟩ - · exact ⟨x :: l₁, Perm.refl _, (s.cons _).cons₂ _⟩ - · exact ⟨y :: l₁, Perm.refl _, (s.cons₂ _).cons _⟩ - · exact ⟨x :: y :: l₁, Perm.swap _ _ _, (s.cons₂ _).cons₂ _⟩ - | trans _ _ IH₁ IH₂ => - exact - let ⟨m₁, pm, sm⟩ := IH₁ s - let ⟨r₁, pr, sr⟩ := IH₂ sm - ⟨r₁, pr.trans pm, sr⟩ #align list.exists_perm_sublist List.exists_perm_sublist -theorem Perm.sizeOf_eq_sizeOf [SizeOf α] {l₁ l₂ : List α} (h : l₁ ~ l₂) : - sizeOf l₁ = sizeOf l₂ := by - induction h with -- hd l₁ l₂ h₁₂ h_sz₁₂ a b l l₁ l₂ l₃ h₁₂ h₂₃ h_sz₁₂ h_sz₂₃ - | nil => rfl - | cons _ _ h_sz₁₂ => simp [h_sz₁₂] - | swap => simp [add_left_comm] - | trans _ _ h_sz₁₂ h_sz₂₃ => simp [h_sz₁₂, h_sz₂₃] #align list.perm.sizeof_eq_sizeof List.Perm.sizeOf_eq_sizeOf section Rel @@ -387,85 +193,34 @@ end Rel section Subperm -/-- `Subperm l₁ l₂`, denoted `l₁ <+~ l₂`, means that `l₁` is a sublist of - a permutation of `l₂`. This is an analogue of `l₁ ⊆ l₂` which respects - multiplicities of elements, and is used for the `≤` relation on multisets. -/ -def Subperm (l₁ l₂ : List α) : Prop := - ∃ (l : _) (_ : l ~ l₁), l <+ l₂ -#align list.subperm List.Subperm - -/-- `Subperm l₁ l₂`, denoted `l₁ <+~ l₂`, means that `l₁` is a sublist of - a permutation of `l₂`. This is an analogue of `l₁ ⊆ l₂` which respects - multiplicities of elements, and is used for the `≤` relation on multisets. -/ -infixl:50 " <+~ " => Subperm - -theorem nil_subperm {l : List α} : [] <+~ l := - ⟨[], Perm.nil, by simp⟩ #align list.nil_subperm List.nil_subperm -theorem Perm.subperm_left {l l₁ l₂ : List α} (p : l₁ ~ l₂) : l <+~ l₁ ↔ l <+~ l₂ := - suffices ∀ {l₁ l₂ : List α}, l₁ ~ l₂ → l <+~ l₁ → l <+~ l₂ from ⟨this p, this p.symm⟩ - fun p ⟨_u, pu, su⟩ => - let ⟨v, pv, sv⟩ := exists_perm_sublist su p - ⟨v, pv.trans pu, sv⟩ #align list.perm.subperm_left List.Perm.subperm_left -theorem Perm.subperm_right {l₁ l₂ l : List α} (p : l₁ ~ l₂) : l₁ <+~ l ↔ l₂ <+~ l := - ⟨fun ⟨u, pu, su⟩ => ⟨u, pu.trans p, su⟩, fun ⟨u, pu, su⟩ => ⟨u, pu.trans p.symm, su⟩⟩ #align list.perm.subperm_right List.Perm.subperm_right -theorem Sublist.subperm {l₁ l₂ : List α} (s : l₁ <+ l₂) : l₁ <+~ l₂ := - ⟨l₁, Perm.refl _, s⟩ #align list.sublist.subperm List.Sublist.subperm -theorem Perm.subperm {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁ <+~ l₂ := - ⟨l₂, p.symm, Sublist.refl _⟩ #align list.perm.subperm List.Perm.subperm -@[refl] -theorem Subperm.refl (l : List α) : l <+~ l := - (Perm.refl _).subperm +attribute [refl] Subperm.refl #align list.subperm.refl List.Subperm.refl -@[trans] -theorem Subperm.trans {l₁ l₂ l₃ : List α} : l₁ <+~ l₂ → l₂ <+~ l₃ → l₁ <+~ l₃ - | s, ⟨_l₂', p₂, s₂⟩ => - let ⟨l₁', p₁, s₁⟩ := p₂.subperm_left.2 s - ⟨l₁', p₁, s₁.trans s₂⟩ +attribute [trans] Subperm.trans #align list.subperm.trans List.Subperm.trans -theorem Subperm.length_le {l₁ l₂ : List α} : l₁ <+~ l₂ → length l₁ ≤ length l₂ - | ⟨_l, p, s⟩ => p.length_eq ▸ s.length_le #align list.subperm.length_le List.Subperm.length_le -theorem Subperm.perm_of_length_le {l₁ l₂ : List α} : l₁ <+~ l₂ → length l₂ ≤ length l₁ → l₁ ~ l₂ - | ⟨_l, p, s⟩, h => (s.eq_of_length_le <| p.symm.length_eq ▸ h) ▸ p.symm #align list.subperm.perm_of_length_le List.Subperm.perm_of_length_le -theorem Subperm.antisymm {l₁ l₂ : List α} (h₁ : l₁ <+~ l₂) (h₂ : l₂ <+~ l₁) : l₁ ~ l₂ := - h₁.perm_of_length_le h₂.length_le #align list.subperm.antisymm List.Subperm.antisymm -theorem Subperm.subset {l₁ l₂ : List α} : l₁ <+~ l₂ → l₁ ⊆ l₂ - | ⟨_l, p, s⟩ => Subset.trans p.symm.subset s.subset #align list.subperm.subset List.Subperm.subset -theorem Subperm.filter (p : α → Bool) ⦃l l' : List α⦄ (h : l <+~ l') : - filter p l <+~ filter p l' := by - obtain ⟨xs, hp, h⟩ := h - exact ⟨_, hp.filter p, h.filter p⟩ #align list.subperm.filter List.Subperm.filter end Subperm -theorem Sublist.exists_perm_append : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → ∃ l, l₂ ~ l₁ ++ l - | _, _, Sublist.slnil => ⟨nil, Perm.refl _⟩ - | _, _, Sublist.cons a s => - let ⟨l, p⟩ := Sublist.exists_perm_append s - ⟨a :: l, (p.cons a).trans perm_middle.symm⟩ - | _, _, Sublist.cons₂ a s => - let ⟨l, p⟩ := Sublist.exists_perm_append s - ⟨l, p.cons a⟩ #align list.sublist.exists_perm_append List.Sublist.exists_perm_append lemma subperm_iff : l₁ <+~ l₂ ↔ ∃ l, l ~ l₂ ∧ l₁ <+ l := by @@ -474,9 +229,6 @@ lemma subperm_iff : l₁ <+~ l₂ ↔ ∃ l, l ~ l₂ ∧ l₁ <+ l := by obtain ⟨l', h₂⟩ := h₂.exists_perm_append exact ⟨l₁ ++ l', (h₂.trans (h₁.append_right _)).symm, (prefix_append _ _).sublist⟩ -@[simp] lemma singleton_subperm_iff : [a] <+~ l ↔ a ∈ l := - ⟨fun ⟨s, hla, h⟩ ↦ by rwa [perm_singleton.1 hla, singleton_sublist] at h, - fun h ↦ ⟨[a], perm_rfl, singleton_sublist.2 h⟩⟩ #align list.subperm_singleton_iff List.singleton_subperm_iff @[simp] lemma subperm_singleton_iff : l <+~ [a] ↔ l = [] ∨ l = [a] := by @@ -487,58 +239,24 @@ lemma subperm_iff : l₁ <+~ l₂ ↔ ∃ l, l ~ l₂ ∧ l₁ <+ l := by · rintro (rfl | rfl) exacts [nil_subperm, Subperm.refl _] -theorem Perm.countP_eq (p : α → Bool) {l₁ l₂ : List α} (s : l₁ ~ l₂) : - countP p l₁ = countP p l₂ := by - rw [countP_eq_length_filter, countP_eq_length_filter]; exact (s.filter _).length_eq #align list.perm.countp_eq List.Perm.countP_eq -theorem Subperm.countP_le (p : α → Bool) {l₁ l₂ : List α} : - l₁ <+~ l₂ → countP p l₁ ≤ countP p l₂ - | ⟨_l, p', s⟩ => p'.countP_eq p ▸ s.countP_le p #align list.subperm.countp_le List.Subperm.countP_le -theorem Perm.countP_congr (s : l₁ ~ l₂) {p p' : α → Bool} - (hp : ∀ x ∈ l₁, p x ↔ p' x) : l₁.countP p = l₂.countP p' := by - rw [← s.countP_eq p'] - clear s - induction' l₁ with y s hs - · rfl - · simp only [mem_cons, forall_eq_or_imp] at hp - simp only [countP_cons, hs hp.2, hp.1] #align list.perm.countp_congr List.Perm.countP_congr -theorem countP_eq_countP_filter_add (l : List α) (p q : α → Bool) : - l.countP p = (l.filter q).countP p + (l.filter fun a => ¬q a).countP p := by - rw [← countP_append] - exact Perm.countP_eq _ (filter_append_perm _ _).symm #align list.countp_eq_countp_filter_add List.countP_eq_countP_filter_add lemma count_eq_count_filter_add [DecidableEq α] (P : α → Prop) [DecidablePred P] (l : List α) (a : α) : count a l = count a (l.filter P) + count a (l.filter (¬ P ·)) := by convert countP_eq_countP_filter_add l _ P - simp only [decide_eq_true_eq] + simp only [decide_not] -theorem Perm.count_eq [DecidableEq α] {l₁ l₂ : List α} (p : l₁ ~ l₂) (a) : - count a l₁ = count a l₂ := - p.countP_eq _ #align list.perm.count_eq List.Perm.count_eq -theorem Subperm.count_le [DecidableEq α] {l₁ l₂ : List α} (s : l₁ <+~ l₂) (a) : - count a l₁ ≤ count a l₂ := - s.countP_le _ #align list.subperm.count_le List.Subperm.count_le -theorem Perm.foldl_eq' {f : β → α → β} {l₁ l₂ : List α} (p : l₁ ~ l₂) : - (∀ x ∈ l₁, ∀ y ∈ l₁, ∀ (z), f (f z x) y = f (f z y) x) → ∀ b, foldl f b l₁ = foldl f b l₂ := - perm_induction_on p (fun _H b => rfl) - (fun x t₁ t₂ _p r H b => r (fun x hx y hy => H _ (.tail _ hx) _ (.tail _ hy)) _) - (fun x y t₁ t₂ _p r H b => by - simp only [foldl] - rw [H x (.tail _ <| .head _) y (.head _)] - exact r (fun x hx y hy => H _ (.tail _ <| .tail _ hx) _ (.tail _ <| .tail _ hy)) _) - fun t₁ t₂ t₃ p₁ _p₂ r₁ r₂ H b => - Eq.trans (r₁ H b) (r₂ (fun x hx y hy => H _ (p₁.symm.subset hx) _ (p₁.symm.subset hy)) b) #align list.perm.foldl_eq' List.Perm.foldl_eq' theorem Perm.foldl_eq {f : β → α → β} {l₁ l₂ : List α} (rcomm : RightCommutative f) (p : l₁ ~ l₂) : @@ -547,21 +265,15 @@ theorem Perm.foldl_eq {f : β → α → β} {l₁ l₂ : List α} (rcomm : Righ #align list.perm.foldl_eq List.Perm.foldl_eq theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) : - ∀ b, foldr f b l₁ = foldr f b l₂ := - perm_induction_on p (fun b => rfl) (fun x t₁ t₂ _p r b => by simp; rw [r b]) - (fun x y t₁ t₂ _p r b => by simp; rw [lcomm, r b]) fun t₁ t₂ t₃ _p₁ _p₂ r₁ r₂ a => - Eq.trans (r₁ a) (r₂ a) + ∀ b, foldr f b l₁ = foldr f b l₂ := by + intro b + induction p using Perm.recOnSwap' generalizing b + case nil => rfl + case cons r => simp; rw [r b] + case swap' r => simp; rw [lcomm, r b] + case trans r₁ r₂ => exact Eq.trans (r₁ b) (r₂ b) #align list.perm.foldr_eq List.Perm.foldr_eq -theorem Perm.rec_heq {β : List α → Sort*} {f : ∀ a l, β l → β (a :: l)} {b : β []} {l l' : List α} - (hl : Perm l l') (f_congr : ∀ {a l l' b b'}, Perm l l' → HEq b b' → HEq (f a l b) (f a l' b')) - (f_swap : ∀ {a a' l b}, HEq (f a (a' :: l) (f a' l b)) (f a' (a :: l) (f a l b))) : - HEq (@List.rec α β b f l) (@List.rec α β b f l') := by - induction hl - case nil => rfl - case cons a l l' h ih => exact f_congr h ih - case swap a a' l => exact f_swap - case trans l₁ l₂ l₃ _h₁ _h₂ ih₁ ih₂ => exact HEq.trans ih₁ ih₂ #align list.perm.rec_heq List.Perm.rec_heq section @@ -616,71 +328,14 @@ theorem prod_reverse (l : List α) : prod l.reverse = prod l := end CommMonoid -theorem perm_inv_core {a : α} {l₁ l₂ r₁ r₂ : List α} : - l₁ ++ a :: r₁ ~ l₂ ++ a :: r₂ → l₁ ++ r₁ ~ l₂ ++ r₂ := by - generalize e₁ : l₁ ++ a :: r₁ = s₁; generalize e₂ : l₂ ++ a :: r₂ = s₂ - intro p; revert l₁ l₂ r₁ r₂ e₁ e₂; clear l₁ l₂ β - show ∀ _ _ _ _, _ - refine - perm_induction_on p ?_ (fun x t₁ t₂ p IH => ?_) (fun x y t₁ t₂ p IH => ?_) - fun t₁ t₂ t₃ p₁ p₂ IH₁ IH₂ => ?_ - <;> intro l₁ l₂ r₁ r₂ e₁ e₂ - · apply (not_mem_nil a).elim - rw [← e₁] - simp - · cases' l₁ with y l₁ <;> cases' l₂ with z l₂ <;> dsimp at e₁ e₂ <;> injections <;> subst x - · substs t₁ t₂ - exact p - · substs z t₁ t₂ - exact p.trans perm_middle - · substs y t₁ t₂ - exact perm_middle.symm.trans p - · substs z t₁ t₂ - exact (IH _ _ _ _ rfl rfl).cons y - · rcases l₁ with (_ | ⟨y, _ | ⟨z, l₁⟩⟩) <;> rcases l₂ with (_ | ⟨u, _ | ⟨v, l₂⟩⟩) <;> - dsimp at e₁ e₂ <;> injections <;> substs x y - · substs r₁ r₂ - exact p.cons a - · substs r₁ r₂ - exact p.cons u - · substs r₁ v t₂ - exact (p.trans perm_middle).cons u - · substs r₁ r₂ - exact p.cons y - · substs r₁ r₂ y u - exact p.cons a - · substs r₁ u v t₂ - exact ((p.trans perm_middle).cons y).trans (swap _ _ _) - · substs r₂ z t₁ - exact (perm_middle.symm.trans p).cons y - · substs r₂ y z t₁ - exact (swap _ _ _).trans ((perm_middle.symm.trans p).cons u) - · substs u v t₁ t₂ - exact (IH _ _ _ _ rfl rfl).swap' _ _ - · substs t₁ t₃ - have : a ∈ t₂ := p₁.subset (by simp) - rcases mem_split this with ⟨l₂, r₂, e₂⟩ - subst t₂ - exact (IH₁ _ _ _ _ rfl rfl).trans (IH₂ _ _ _ _ rfl rfl) #align list.perm_inv_core List.perm_inv_core -theorem Perm.cons_inv {a : α} {l₁ l₂ : List α} : a :: l₁ ~ a :: l₂ → l₁ ~ l₂ := - @perm_inv_core _ _ [] [] _ _ #align list.perm.cons_inv List.Perm.cons_inv -@[simp] -theorem perm_cons (a : α) {l₁ l₂ : List α} : a :: l₁ ~ a :: l₂ ↔ l₁ ~ l₂ := - ⟨Perm.cons_inv, Perm.cons a⟩ #align list.perm_cons List.perm_cons -theorem perm_append_left_iff {l₁ l₂ : List α} : ∀ l, l ++ l₁ ~ l ++ l₂ ↔ l₁ ~ l₂ - | [] => Iff.rfl - | a :: l => (perm_cons a).trans (perm_append_left_iff l) #align list.perm_append_left_iff List.perm_append_left_iff -theorem perm_append_right_iff {l₁ l₂ : List α} (l) : l₁ ++ l ~ l₂ ++ l ↔ l₁ ~ l₂ := - ⟨fun p => (perm_append_left_iff _).1 <| perm_append_comm.trans <| p.trans perm_append_comm, - Perm.append_right _⟩ #align list.perm_append_right_iff List.perm_append_right_iff theorem perm_option_to_list {o₁ o₂ : Option α} : o₁.toList ~ o₂.toList ↔ o₁ = o₂ := by @@ -691,11 +346,6 @@ theorem perm_option_to_list {o₁ o₂ : Option α} : o₁.toList ~ o₂.toList · exact Option.mem_toList.1 (p.symm.subset <| by simp) #align list.perm_option_to_list List.perm_option_to_list -theorem subperm_cons (a : α) {l₁ l₂ : List α} : a :: l₁ <+~ a :: l₂ ↔ l₁ <+~ l₂ := - ⟨fun ⟨l, p, s⟩ => by - cases' s with _ _ _ s' u _ _ s' - · exact (p.subperm_left.2 <| (sublist_cons _ _).subperm).trans s'.subperm - · exact ⟨u, p.cons_inv, s'⟩, fun ⟨l, p, s⟩ => ⟨a :: l, p.cons a, s.cons₂ _⟩⟩ #align list.subperm_cons List.subperm_cons alias ⟨subperm.of_cons, subperm.cons⟩ := subperm_cons @@ -731,127 +381,45 @@ theorem cons_subperm_of_mem {a : α} {l₁ l₂ : List α} (d₁ : Nodup l₁) ( ⟨b :: t, (p'.cons b).trans <| (swap _ _ _).trans (perm_middle.symm.cons a), s'.cons₂ _⟩ #align list.cons_subperm_of_mem List.cons_subperm_of_mem -theorem subperm_append_left {l₁ l₂ : List α} : ∀ l, l ++ l₁ <+~ l ++ l₂ ↔ l₁ <+~ l₂ - | [] => Iff.rfl - | a :: l => (subperm_cons a).trans (subperm_append_left l) #align list.subperm_append_left List.subperm_append_left -theorem subperm_append_right {l₁ l₂ : List α} (l) : l₁ ++ l <+~ l₂ ++ l ↔ l₁ <+~ l₂ := - (perm_append_comm.subperm_left.trans perm_append_comm.subperm_right).trans (subperm_append_left l) #align list.subperm_append_right List.subperm_append_right -theorem Subperm.exists_of_length_lt {l₁ l₂ : List α} : - l₁ <+~ l₂ → length l₁ < length l₂ → ∃ a, a :: l₁ <+~ l₂ - | ⟨l, p, s⟩, h => by - suffices length l < length l₂ → ∃ a : α, a :: l <+~ l₂ from - (this <| p.symm.length_eq ▸ h).imp fun a => (p.cons a).subperm_right.1 - clear h p l₁ - induction' s with l₁ l₂ a s IH _ _ b _ IH <;> intro h - · cases h - · cases' lt_or_eq_of_le (Nat.le_of_lt_succ h : length l₁ ≤ length l₂) with h h - · exact (IH h).imp fun a s => s.trans (sublist_cons _ _).subperm - · exact ⟨a, s.eq_of_length h ▸ Subperm.refl _⟩ - · exact (IH <| Nat.lt_of_succ_lt_succ h).imp fun a s => - (swap _ _ _).subperm_right.1 <| (subperm_cons _).2 s #align list.subperm.exists_of_length_lt List.Subperm.exists_of_length_lt -protected theorem Nodup.subperm (d : Nodup l₁) (H : l₁ ⊆ l₂) : l₁ <+~ l₂ := by - induction' d with a l₁' h d IH - · exact ⟨nil, Perm.nil, nil_sublist _⟩ - · cases' forall_mem_cons.1 H with H₁ H₂ - simp at h - exact cons_subperm_of_mem d h H₁ (IH H₂) +protected theorem Nodup.subperm (d : Nodup l₁) (H : l₁ ⊆ l₂) : l₁ <+~ l₂ := + subperm_of_subset d H #align list.nodup.subperm List.Nodup.subperm -theorem perm_ext {l₁ l₂ : List α} (d₁ : Nodup l₁) (d₂ : Nodup l₂) : - l₁ ~ l₂ ↔ ∀ a, a ∈ l₁ ↔ a ∈ l₂ := - ⟨fun p _ => p.mem_iff, fun H => - (d₁.subperm fun a => (H a).1).antisymm <| d₂.subperm fun a => (H a).2⟩ -#align list.perm_ext List.perm_ext - -theorem Nodup.sublist_ext {l₁ l₂ l : List α} (d : Nodup l) (s₁ : l₁ <+ l) (s₂ : l₂ <+ l) : - l₁ ~ l₂ ↔ l₁ = l₂ := - ⟨fun h => by - induction' s₂ with l₂ l a s₂ IH l₂ l a _ IH generalizing l₁ - · exact h.eq_nil - · simp at d - cases' s₁ with _ _ _ s₁ l₁ _ _ s₁ - · exact IH d.2 s₁ h - · apply d.1.elim - exact Subperm.subset ⟨_, h.symm, s₂⟩ (mem_cons_self _ _) - · simp at d - cases' s₁ with _ _ _ s₁ l₁ _ _ s₁ - · apply d.1.elim - exact Subperm.subset ⟨_, h, s₁⟩ (mem_cons_self _ _) - · rw [IH d.2 s₁ h.cons_inv], fun h => by rw [h]⟩ -#align list.nodup.sublist_ext List.Nodup.sublist_ext +#align list.perm_ext List.perm_ext_iff_of_nodup + +#align list.nodup.sublist_ext List.Nodup.perm_iff_eq_of_sublist section variable [DecidableEq α] -- attribute [congr] -theorem Perm.erase (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁.erase a ~ l₂.erase a := - if h₁ : a ∈ l₁ then - have h₂ : a ∈ l₂ := p.subset h₁ - Perm.cons_inv <| (perm_cons_erase h₁).symm.trans <| p.trans (perm_cons_erase h₂) - else by - have h₂ : a ∉ l₂ := mt p.mem_iff.2 h₁ - rw [erase_of_not_mem h₁, erase_of_not_mem h₂]; exact p #align list.perm.erase List.Perm.erase -theorem subperm_cons_erase (a : α) (l : List α) : l <+~ a :: l.erase a := by - by_cases h : a ∈ l - · exact (perm_cons_erase h).subperm - · rw [erase_of_not_mem h] - exact (sublist_cons _ _).subperm #align list.subperm_cons_erase List.subperm_cons_erase -theorem erase_subperm (a : α) (l : List α) : l.erase a <+~ l := - (erase_sublist _ _).subperm #align list.erase_subperm List.erase_subperm -theorem Subperm.erase {l₁ l₂ : List α} (a : α) (h : l₁ <+~ l₂) : l₁.erase a <+~ l₂.erase a := - let ⟨l, hp, hs⟩ := h - ⟨l.erase a, hp.erase _, hs.erase _⟩ #align list.subperm.erase List.Subperm.erase -theorem Perm.diff_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂) : l₁.diff t ~ l₂.diff t := by - induction t generalizing l₁ l₂ h <;> simp [*, Perm.erase] #align list.perm.diff_right List.Perm.diff_right -theorem Perm.diff_left (l : List α) {t₁ t₂ : List α} (h : t₁ ~ t₂) : l.diff t₁ = l.diff t₂ := by - induction h generalizing l <;> - first |simp [*, Perm.erase, erase_comm] #align list.perm.diff_left List.Perm.diff_left -theorem Perm.diff {l₁ l₂ t₁ t₂ : List α} (hl : l₁ ~ l₂) (ht : t₁ ~ t₂) : l₁.diff t₁ ~ l₂.diff t₂ := - ht.diff_left l₂ ▸ hl.diff_right _ #align list.perm.diff List.Perm.diff -theorem Subperm.diff_right {l₁ l₂ : List α} (h : l₁ <+~ l₂) (t : List α) : - l₁.diff t <+~ l₂.diff t := by induction t generalizing l₁ l₂ h <;> simp [*, Subperm.erase] #align list.subperm.diff_right List.Subperm.diff_right -theorem erase_cons_subperm_cons_erase (a b : α) (l : List α) : - (a :: l).erase b <+~ a :: l.erase b := by - by_cases h : a = b - · subst b - rw [erase_cons_head] - apply subperm_cons_erase - · rw [erase_cons_tail _ h] #align list.erase_cons_subperm_cons_erase List.erase_cons_subperm_cons_erase -theorem subperm_cons_diff {a : α} : ∀ {l₁ l₂ : List α}, (a :: l₁).diff l₂ <+~ a :: l₁.diff l₂ - | l₁, [] => ⟨a :: l₁, by simp⟩ - | l₁, b :: l₂ => by - simp only [diff_cons] - refine' ((erase_cons_subperm_cons_erase a b l₁).diff_right l₂).trans _ - apply subperm_cons_diff #align list.subperm_cons_diff List.subperm_cons_diff -theorem subset_cons_diff {a : α} {l₁ l₂ : List α} : (a :: l₁).diff l₂ ⊆ a :: l₁.diff l₂ := - subperm_cons_diff.subset #align list.subset_cons_diff List.subset_cons_diff theorem Perm.bagInter_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂) : @@ -881,27 +449,8 @@ theorem Perm.bagInter {l₁ l₂ t₁ t₂ : List α} (hl : l₁ ~ l₂) (ht : t ht.bagInter_left l₂ ▸ hl.bagInter_right _ #align list.perm.bag_inter List.Perm.bagInter -theorem cons_perm_iff_perm_erase {a : α} {l₁ l₂ : List α} : - a :: l₁ ~ l₂ ↔ a ∈ l₂ ∧ l₁ ~ l₂.erase a := - ⟨fun h => - have : a ∈ l₂ := h.subset (mem_cons_self a l₁) - ⟨this, (h.trans <| perm_cons_erase this).cons_inv⟩, - fun ⟨m, h⟩ => (h.cons a).trans (perm_cons_erase m).symm⟩ #align list.cons_perm_iff_perm_erase List.cons_perm_iff_perm_erase -theorem perm_iff_count {l₁ l₂ : List α} : l₁ ~ l₂ ↔ ∀ a, count a l₁ = count a l₂ := - ⟨Perm.count_eq, fun H => by - induction' l₁ with a l₁ IH generalizing l₂ - · cases' l₂ with b l₂ - · rfl - specialize H b - simp at H - contradiction - · have : a ∈ l₂ := count_pos_iff_mem.1 (by rw [← H, count_pos_iff_mem]; simp) - refine' ((IH fun b => _).cons a).trans (perm_cons_erase this).symm - specialize H b - rw [(perm_cons_erase this).count_eq] at H - by_cases h : b = a <;> simpa [h] using H⟩ #align list.perm_iff_count List.perm_iff_count theorem perm_replicate_append_replicate {l : List α} {a b : α} {m n : ℕ} (h : a ≠ b) : @@ -913,61 +462,16 @@ theorem perm_replicate_append_replicate {l : List α} {a b : α} {m n : ℕ} (h not_mem_nil, or_false, or_comm] #align list.perm_replicate_append_replicate List.perm_replicate_append_replicate -theorem Subperm.cons_right {α : Type*} {l l' : List α} (x : α) (h : l <+~ l') : l <+~ x :: l' := - h.trans (sublist_cons x l').subperm #align list.subperm.cons_right List.Subperm.cons_right -/-- The list version of `add_tsub_cancel_of_le` for multisets. -/ -theorem subperm_append_diff_self_of_count_le {l₁ l₂ : List α} - (h : ∀ x ∈ l₁, count x l₁ ≤ count x l₂) : l₁ ++ l₂.diff l₁ ~ l₂ := by - induction' l₁ with hd tl IH generalizing l₂ - · simp - · have : hd ∈ l₂ := by - rw [← count_pos_iff_mem] - exact lt_of_lt_of_le (count_pos_iff_mem.mpr (mem_cons_self _ _)) (h hd (mem_cons_self _ _)) - replace := perm_cons_erase this - refine' Perm.trans _ this.symm - rw [cons_append, diff_cons, perm_cons] - refine' IH fun x hx => _ - specialize h x (mem_cons_of_mem _ hx) - rw [perm_iff_count.mp this] at h - by_cases hx : x = hd - · subst hd - simpa [Nat.succ_le_succ_iff] using h - · simpa [hx] using h #align list.subperm_append_diff_self_of_count_le List.subperm_append_diff_self_of_count_le -/-- The list version of `Multiset.le_iff_count`. -/ -theorem subperm_ext_iff {l₁ l₂ : List α} : l₁ <+~ l₂ ↔ ∀ x ∈ l₁, count x l₁ ≤ count x l₂ := by - refine' ⟨fun h x _ => Subperm.count_le h x, fun h => _⟩ - suffices l₁ <+~ l₂.diff l₁ ++ l₁ by - refine' this.trans (Perm.subperm _) - exact perm_append_comm.trans (subperm_append_diff_self_of_count_le h) - exact (subperm_append_right l₁).mpr nil_subperm #align list.subperm_ext_iff List.subperm_ext_iff -instance decidableSubperm : DecidableRel ((· <+~ ·) : List α → List α → Prop) := fun _ _ => - decidable_of_iff _ List.subperm_ext_iff.symm #align list.decidable_subperm List.decidableSubperm -theorem Subperm.cons_left {l₁ l₂ : List α} (h : l₁ <+~ l₂) (x : α) (hx : count x l₁ < count x l₂) : - x :: l₁ <+~ l₂ := by - rw [subperm_ext_iff] at h ⊢ - intro y hy - by_cases hy' : y = x - · subst x - simpa using Nat.succ_le_of_lt hx - · rw [count_cons_of_ne hy'] - refine' h y _ - simpa [hy'] using hy #align list.subperm.cons_left List.Subperm.cons_left -instance decidablePerm : ∀ l₁ l₂ : List α, Decidable (l₁ ~ l₂) - | [], [] => isTrue <| Perm.refl _ - | [], b :: l₂ => isFalse fun h => by have := h.nil_eq; contradiction - | a :: l₁, l₂ => - haveI := decidablePerm l₁ (l₂.erase a) - decidable_of_iff' _ cons_perm_iff_perm_erase #align list.decidable_perm List.decidablePerm -- @[congr] @@ -977,62 +481,24 @@ theorem Perm.dedup {l₁ l₂ : List α} (p : l₁ ~ l₂) : dedup l₁ ~ dedup #align list.perm.dedup List.Perm.dedup -- attribute [congr] -protected theorem Perm.insert (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁.insert a ~ l₂.insert a := - if h : a ∈ l₁ then by simpa [h, p.subset h] using p - else by simpa [h, mt p.mem_iff.2 h] using p.cons a #align list.perm.insert List.Perm.insert -theorem perm_insert_swap (x y : α) (l : List α) : - List.insert x (List.insert y l) ~ List.insert y (List.insert x l) := by - by_cases xl : x ∈ l <;> by_cases yl : y ∈ l <;> simp [xl, yl] - by_cases xy : x = y; · simp [xy] - simp only [List.insert, Bool.not_eq_true, mem_cons, xy, xl, or_self, ite_false, Ne.symm xy, yl] - constructor #align list.perm_insert_swap List.perm_insert_swap -theorem perm_insertNth {α} (x : α) (l : List α) {n} (h : n ≤ l.length) : - insertNth n x l ~ x :: l := by - induction' l with _ _ l_ih generalizing n - · cases n - rfl - cases h - cases n - · simp [insertNth] - · simp only [insertNth, modifyNthTail] - refine' Perm.trans (Perm.cons _ (l_ih _)) _ - · apply Nat.le_of_succ_le_succ h - · apply Perm.swap #align list.perm_insert_nth List.perm_insertNth -theorem Perm.union_right {l₁ l₂ : List α} (t₁ : List α) (h : l₁ ~ l₂) : - l₁ ∪ t₁ ~ l₂ ∪ t₁ := by - induction' h with a _ _ _ ih _ _ _ _ _ _ _ _ ih_1 ih_2 <;> try simp - · exact ih.insert a - · apply perm_insert_swap - · exact ih_1.trans ih_2 #align list.perm.union_right List.Perm.union_right -theorem Perm.union_left (l : List α) {t₁ t₂ : List α} (h : t₁ ~ t₂) : l ∪ t₁ ~ l ∪ t₂ := by - induction l <;> simp [*, Perm.insert] #align list.perm.union_left List.Perm.union_left -- @[congr] -theorem Perm.union {l₁ l₂ t₁ t₂ : List α} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) : - l₁ ∪ t₁ ~ l₂ ∪ t₂ := - (p₁.union_right t₁).trans (p₂.union_left l₂) #align list.perm.union List.Perm.union -theorem Perm.inter_right {l₁ l₂ : List α} (t₁ : List α) : l₁ ~ l₂ → l₁ ∩ t₁ ~ l₂ ∩ t₁ := - Perm.filter _ #align list.perm.inter_right List.Perm.inter_right -theorem Perm.inter_left (l : List α) {t₁ t₂ : List α} (p : t₁ ~ t₂) : l ∩ t₁ = l ∩ t₂ := - filter_congr' fun a _ => by simpa using p.mem_iff #align list.perm.inter_left List.Perm.inter_left -- @[congr] -theorem Perm.inter {l₁ l₂ t₁ t₂ : List α} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) : l₁ ∩ t₁ ~ l₂ ∩ t₂ := - p₂.inter_left l₂ ▸ p₁.inter_right t₁ #align list.perm.inter List.Perm.inter theorem Perm.inter_append {l t₁ t₂ : List α} (h : Disjoint t₁ t₂) : @@ -1055,50 +521,19 @@ theorem Perm.inter_append {l t₁ t₂ : List α} (h : Disjoint t₁ t₂) : end -theorem Perm.pairwise_iff {R : α → α → Prop} (S : Symmetric R) : - ∀ {l₁ l₂ : List α} (_p : l₁ ~ l₂), Pairwise R l₁ ↔ Pairwise R l₂ := - suffices ∀ {l₁ l₂}, l₁ ~ l₂ → Pairwise R l₁ → Pairwise R l₂ - from fun p => ⟨this p, this p.symm⟩ - @fun l₁ l₂ p d => by - induction' d with a l₁ h _ IH generalizing l₂ - · rw [← p.nil_eq] - constructor - · have : a ∈ l₂ := p.subset (mem_cons_self _ _) - rcases mem_split this with ⟨s₂, t₂, rfl⟩ - have p' := (p.trans perm_middle).cons_inv - refine' (pairwise_middle @S).2 (pairwise_cons.2 ⟨fun b m => _, IH _ p'⟩) - exact h _ (p'.symm.subset m) #align list.perm.pairwise_iff List.Perm.pairwise_iff -theorem Pairwise.perm {R : α → α → Prop} {l l' : List α} (hR : l.Pairwise R) (hl : l ~ l') - (hsymm : Symmetric R) : l'.Pairwise R := - (hl.pairwise_iff hsymm).mp hR #align list.pairwise.perm List.Pairwise.perm -theorem Perm.pairwise {R : α → α → Prop} {l l' : List α} (hl : l ~ l') (hR : l.Pairwise R) - (hsymm : Symmetric R) : l'.Pairwise R := - hR.perm hl hsymm #align list.perm.pairwise List.Perm.pairwise -theorem Perm.nodup_iff {l₁ l₂ : List α} : l₁ ~ l₂ → (Nodup l₁ ↔ Nodup l₂) := - Perm.pairwise_iff <| @Ne.symm α #align list.perm.nodup_iff List.Perm.nodup_iff -theorem Perm.join {l₁ l₂ : List (List α)} (h : l₁ ~ l₂) : l₁.join ~ l₂.join := - Perm.recOn h (Perm.refl _) (fun x xs₁ xs₂ _ ih => ih.append_left x) - (fun x₁ x₂ xs => by simpa only [join, append_assoc] using perm_append_comm.append_right _) - @fun xs₁ xs₂ xs₃ _ _ => Perm.trans #align list.perm.join List.Perm.join -theorem Perm.bind_right {l₁ l₂ : List α} (f : α → List β) (p : l₁ ~ l₂) : l₁.bind f ~ l₂.bind f := - (p.map _).join #align list.perm.bind_right List.Perm.bind_right -theorem Perm.join_congr : - ∀ {l₁ l₂ : List (List α)} (_ : List.Forall₂ (· ~ ·) l₁ l₂), l₁.join ~ l₂.join - | _, _, Forall₂.nil => Perm.refl _ - | _ :: _, _ :: _, Forall₂.cons h₁ h₂ => h₁.append (Perm.join_congr h₂) #align list.perm.join_congr List.Perm.join_congr theorem Perm.bind_left (l : List α) {f g : α → List β} (h : ∀ a ∈ l, f a ~ g a) : @@ -1155,22 +590,17 @@ theorem perm_lookmap (f : α → Option α) {l₁ l₂ : List α} rcases (pairwise_cons.1 H).1 _ (mem_cons.2 (Or.inl rfl)) _ h₂ _ h₁ with ⟨rfl, rfl⟩ exact Perm.refl _ · refine' (IH₁ H).trans (IH₂ ((p₁.pairwise_iff _).1 H)) - exact fun a b h c h₁ d h₂ => (h d h₂ c h₁).imp Eq.symm Eq.symm + intro x y h c hc d hd + rw [@eq_comm _ y, @eq_comm _ c] + apply h d hd c hc #align list.perm_lookmap List.perm_lookmap +@[deprecated Perm.eraseP] theorem Perm.erasep (f : α → Prop) [DecidablePred f] {l₁ l₂ : List α} - (H : Pairwise (fun a b => f a → f b → False) l₁) (p : l₁ ~ l₂) : eraseP f l₁ ~ eraseP f l₂ := by - induction' p with a l₁ l₂ p IH a b l l₁ l₂ l₃ p₁ _ IH₁ IH₂; · simp - · by_cases h : f a - · simp [h, p] - · simp [h] - exact IH (pairwise_cons.1 H).2 - · by_cases h₁ : f a <;> by_cases h₂ : f b <;> simp [h₁, h₂] - · cases (pairwise_cons.1 H).1 _ (mem_cons.2 (Or.inl rfl)) h₂ h₁ - · apply swap - · refine' (IH₁ H).trans (IH₂ ((p₁.pairwise_iff _).1 H)) - exact fun a b h h₁ h₂ => h h₂ h₁ -#align list.perm.erasep List.Perm.erasep + (H : Pairwise (fun a b => f a → f b → False) l₁) (p : l₁ ~ l₂) : + List.eraseP f l₁ ~ List.eraseP f l₂ := + p.eraseP f (by simp [H]) +#align list.perm.erasep List.Perm.eraseP theorem Perm.take_inter {α : Type*} [DecidableEq α] {xs ys : List α} (n : ℕ) (h : xs ~ ys) (h' : ys.Nodup) : xs.take n ~ ys.inter (xs.take n) := by diff --git a/Mathlib/Data/List/Sigma.lean b/Mathlib/Data/List/Sigma.lean index 808f618bdfa94..7b046807123d5 100644 --- a/Mathlib/Data/List/Sigma.lean +++ b/Mathlib/Data/List/Sigma.lean @@ -155,7 +155,7 @@ theorem nodup_enum_map_fst (l : List α) : (l.enum.map Prod.fst).Nodup := by sim theorem mem_ext {l₀ l₁ : List (Sigma β)} (nd₀ : l₀.Nodup) (nd₁ : l₁.Nodup) (h : ∀ x, x ∈ l₀ ↔ x ∈ l₁) : l₀ ~ l₁ := - (perm_ext nd₀ nd₁).2 h + (perm_ext_iff_of_nodup nd₀ nd₁).2 h #align list.mem_ext List.mem_ext variable [DecidableEq α] @@ -476,8 +476,10 @@ theorem NodupKeys.kerase (a : α) : NodupKeys l → (kerase a l).NodupKeys := #align list.nodupkeys.kerase List.NodupKeys.kerase theorem Perm.kerase {a : α} {l₁ l₂ : List (Sigma β)} (nd : l₁.NodupKeys) : - l₁ ~ l₂ → kerase a l₁ ~ kerase a l₂ := - Perm.erasep _ <| (nodupKeys_iff_pairwise.1 nd).imp <| by rintro x y h rfl; exact h + l₁ ~ l₂ → kerase a l₁ ~ kerase a l₂ := by + apply Perm.eraseP + apply (nodupKeys_iff_pairwise.1 nd).imp + intros; simp_all #align list.perm.kerase List.Perm.kerase @[simp] diff --git a/Mathlib/Data/List/Sublists.lean b/Mathlib/Data/List/Sublists.lean index 0953743e0c411..99888346579b1 100644 --- a/Mathlib/Data/List/Sublists.lean +++ b/Mathlib/Data/List/Sublists.lean @@ -413,9 +413,11 @@ theorem sublists'_map (f : α → β) : ∀ (l : List α), --Porting note: moved because it is now used to prove `sublists_cons_perm_append` theorem sublists_perm_sublists' (l : List α) : sublists l ~ sublists' l := by rw [← finRange_map_get l, sublists_map, sublists'_map] - refine' Perm.map _ _ - exact (perm_ext (nodup_sublists.2 (nodup_finRange _)) (nodup_sublists'.2 (nodup_finRange _))).2 - (by simp) + apply Perm.map + apply (perm_ext_iff_of_nodup _ _).mpr + · simp + · exact nodup_sublists.mpr (nodup_finRange _) + · exact (nodup_sublists'.mpr (nodup_finRange _)) #align list.sublists_perm_sublists' List.sublists_perm_sublists' theorem sublists_cons_perm_append (a : α) (l : List α) : diff --git a/Mathlib/Data/Matroid/Basic.lean b/Mathlib/Data/Matroid/Basic.lean index 3a9d959ef955a..c7054c29dc0eb 100644 --- a/Mathlib/Data/Matroid/Basic.lean +++ b/Mathlib/Data/Matroid/Basic.lean @@ -123,8 +123,6 @@ There are a few design decisions worth discussing. with minimal fuss (using default values). The tactic works fairly well, but has room for improvement. Even though the carrier set is written `M.E`, - we mirror common informal practice by referring explicitly to the `ground` set - rather than the notation `E` in lemma names. A related decision is to not have matroids themselves be a typeclass. This would make things be notationally simpler @@ -134,6 +132,20 @@ There are a few design decisions worth discussing. it is normal to explicitly indicate which matroid something is happening in, so our notation mirrors common practice. +### Notation + We use a couple of nonstandard conventions in theorem names that are related to the above. + First, we mirror common informal practice by referring explicitly to the `ground` set rather + than the notation `E`. (Writing `ground` everywhere in a proof term would be unwieldy, and + writing `E` in theorem names would be unnatural to read.) + + Second, because we are typically interested in subsets of the ground set `M.E`, + using `Set.compl` is inconvenient, since `Xᶜ ⊆ M.E` is typically false for `X ⊆ M.E`. + On the other hand (especially when duals arise), it is common to complement + a set `X ⊆ M.E` *within* the ground set, giving `M.E \ X`. + For this reason, we use the term `compl` in theorem names to refer to taking a set difference + with respect to the ground set, rather than a complement within a type. The lemma + `compl_base_dual` is one of the many examples of this. + ## References [1] The standard text on matroid theory diff --git a/Mathlib/Data/Matroid/Dual.lean b/Mathlib/Data/Matroid/Dual.lean new file mode 100644 index 0000000000000..698b6a8d2b7f8 --- /dev/null +++ b/Mathlib/Data/Matroid/Dual.lean @@ -0,0 +1,260 @@ +/- +Copyright (c) 2023 Peter Nelson. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Peter Nelson +-/ +import Mathlib.Data.Matroid.IndepAxioms + +/-! +# Matroid Duality + +For a matroid `M` on ground set `E`, the collection of complements of the bases of `M` is the +collection of bases of another matroid on `E` called the 'dual' of `M`. +The map from `M` to its dual is an involution, interacts nicely with minors, +and preserves many important matroid properties such as representability and connectivity. + +This file defines the dual matroid `M﹡` of `M`, and gives associated API. The definition +is in terms of its independent sets, using `IndepMatroid.matroid`. + +We also define 'Co-independence' (independence in the dual) of a set as a predicate `M.Coindep X`. +This is an abbreviation for `M﹡.Indep X`, but has its own name for the sake of dot notation. + +## Main Definitions + +* `M.Dual`, written `M﹡`, is the matroid in which a set `B` is a base if and only if `B ⊆ M.E` + and `M.E \ B` is a base for `M`. + +* `M.Coindep X` means `M﹡.Indep X`, or equivalently that `X` is contained in `M.E \ B` for some + base `B` of `M`. +-/ + +open Set + +namespace Matroid + +variable {α : Type*} {M : Matroid α} {I B X : Set α} + +section dual + +/-- Given `M : Matroid α`, the `IndepMatroid α` whose independent sets are + the subsets of `M.E` that are disjoint from some base of `M` -/ +@[simps] def dualIndepMatroid (M : Matroid α) : IndepMatroid α where + E := M.E + Indep I := I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B + indep_empty := ⟨empty_subset M.E, M.exists_base.imp (fun B hB ↦ ⟨hB, empty_disjoint _⟩)⟩ + indep_subset := by + rintro I J ⟨hJE, B, hB, hJB⟩ hIJ + exact ⟨hIJ.trans hJE, ⟨B, hB, disjoint_of_subset_left hIJ hJB⟩⟩ + indep_aug := by + rintro I X ⟨hIE, B, hB, hIB⟩ hI_not_max hX_max + have hXE := hX_max.1.1 + have hB' := (base_compl_iff_mem_maximals_disjoint_base hXE).mpr hX_max + + set B' := M.E \ X with hX + have hI := (not_iff_not.mpr (base_compl_iff_mem_maximals_disjoint_base)).mpr hI_not_max + obtain ⟨B'', hB'', hB''₁, hB''₂⟩ := (hB'.indep.diff I).exists_base_subset_union_base hB + rw [← compl_subset_compl, ← hIB.sdiff_eq_right, ← union_diff_distrib, diff_eq, compl_inter, + compl_compl, union_subset_iff, compl_subset_compl] at hB''₂ + + have hssu := (subset_inter (hB''₂.2) hIE).ssubset_of_ne + (by { rintro rfl; apply hI; convert hB''; simp [hB''.subset_ground] }) + + obtain ⟨e, ⟨(heB'' : e ∉ _), heE⟩, heI⟩ := exists_of_ssubset hssu + use e + simp_rw [mem_diff, insert_subset_iff, and_iff_left heI, and_iff_right heE, and_iff_right hIE] + refine' ⟨by_contra (fun heX ↦ heB'' (hB''₁ ⟨_, heI⟩)), ⟨B'', hB'', _⟩⟩ + · rw [hX]; exact ⟨heE, heX⟩ + rw [← union_singleton, disjoint_union_left, disjoint_singleton_left, and_iff_left heB''] + exact disjoint_of_subset_left hB''₂.2 disjoint_compl_left + indep_maximal := by + rintro X - I'⟨hI'E, B, hB, hI'B⟩ hI'X + obtain ⟨I, hI⟩ := M.exists_basis (M.E \ X) + obtain ⟨B', hB', hIB', hB'IB⟩ := hI.indep.exists_base_subset_union_base hB + refine' ⟨(X \ B') ∩ M.E, + ⟨_,subset_inter (subset_diff.mpr _) hI'E, (inter_subset_left _ _).trans (diff_subset _ _)⟩, _⟩ + · simp only [inter_subset_right, true_and] + exact ⟨B', hB', disjoint_of_subset_left (inter_subset_left _ _) disjoint_sdiff_left⟩ + · rw [and_iff_right hI'X] + refine' disjoint_of_subset_right hB'IB _ + rw [disjoint_union_right, and_iff_left hI'B] + exact disjoint_of_subset hI'X hI.subset disjoint_sdiff_right + simp only [mem_setOf_eq, subset_inter_iff, and_imp, forall_exists_index] + intros J hJE B'' hB'' hdj _ hJX hssJ + rw [and_iff_left hJE] + rw [diff_eq, inter_right_comm, ← diff_eq, diff_subset_iff] at hssJ + + have hI' : (B'' ∩ X) ∪ (B' \ X) ⊆ B' + · rw [union_subset_iff, and_iff_left (diff_subset _ _), + ← inter_eq_self_of_subset_left hB''.subset_ground, inter_right_comm, inter_assoc] + + calc _ ⊆ _ := inter_subset_inter_right _ hssJ + _ ⊆ _ := by rw [inter_distrib_left, hdj.symm.inter_eq, union_empty] + _ ⊆ _ := inter_subset_right _ _ + + obtain ⟨B₁,hB₁,hI'B₁,hB₁I⟩ := (hB'.indep.subset hI').exists_base_subset_union_base hB'' + rw [union_comm, ← union_assoc, union_eq_self_of_subset_right (inter_subset_left _ _)] at hB₁I + + have : B₁ = B' + · refine hB₁.eq_of_subset_indep hB'.indep (fun e he ↦ ?_) + refine (hB₁I he).elim (fun heB'' ↦ ?_) (fun h ↦ h.1) + refine (em (e ∈ X)).elim (fun heX ↦ hI' (Or.inl ⟨heB'', heX⟩)) (fun heX ↦ hIB' ?_) + refine hI.mem_of_insert_indep ⟨hB₁.subset_ground he, heX⟩ + (hB₁.indep.subset (insert_subset he ?_)) + refine (subset_union_of_subset_right (subset_diff.mpr ⟨hIB',?_⟩) _).trans hI'B₁ + refine disjoint_of_subset_left hI.subset disjoint_sdiff_left + + subst this + + refine' subset_diff.mpr ⟨hJX, by_contra (fun hne ↦ _)⟩ + obtain ⟨e, heJ, heB'⟩ := not_disjoint_iff.mp hne + obtain (heB'' | ⟨-,heX⟩ ) := hB₁I heB' + · exact hdj.ne_of_mem heJ heB'' rfl + exact heX (hJX heJ) + subset_ground := by tauto + +/-- The dual of a matroid; the bases are the complements (w.r.t `M.E`) of the bases of `M`. -/ +def dual (M : Matroid α) : Matroid α := M.dualIndepMatroid.matroid + +/-- The `﹡` symbol, which denotes matroid duality. + (This is distinct from the usual `*` symbol for multiplication, due to precedence issues. )-/ +postfix:max "﹡" => Matroid.dual + +theorem dual_indep_iff_exists' : (M﹡.Indep I) ↔ I ⊆ M.E ∧ (∃ B, M.Base B ∧ Disjoint I B) := by + simp [dual] + +@[simp] theorem dual_ground : M﹡.E = M.E := rfl + +@[simp] theorem dual_indep_iff_exists (hI : I ⊆ M.E := by aesop_mat) : + M﹡.Indep I ↔ (∃ B, M.Base B ∧ Disjoint I B) := by + rw [dual_indep_iff_exists', and_iff_right hI] + +theorem dual_dep_iff_forall : (M﹡.Dep I) ↔ (∀ B, M.Base B → (I ∩ B).Nonempty) ∧ I ⊆ M.E := by + simp_rw [dep_iff, dual_indep_iff_exists', dual_ground, and_congr_left_iff, not_and, + not_exists, not_and, not_disjoint_iff_nonempty_inter, imp_iff_right_iff, iff_true_intro Or.inl] + +instance dual_finite [M.Finite] : M﹡.Finite := + ⟨M.ground_finite⟩ + +instance dual_nonempty [M.Nonempty] : M﹡.Nonempty := + ⟨M.ground_nonempty⟩ + +@[simp] theorem dual_base_iff (hB : B ⊆ M.E := by aesop_mat) : M﹡.Base B ↔ M.Base (M.E \ B) := by + rw [base_compl_iff_mem_maximals_disjoint_base, base_iff_maximal_indep, dual_indep_iff_exists', + mem_maximals_setOf_iff] + simp [dual_indep_iff_exists'] + +theorem dual_base_iff' : M﹡.Base B ↔ M.Base (M.E \ B) ∧ B ⊆ M.E := + (em (B ⊆ M.E)).elim (fun h ↦ by rw [dual_base_iff, and_iff_left h]) + (fun h ↦ iff_of_false (h ∘ (fun h' ↦ h'.subset_ground)) (h ∘ And.right)) + +theorem setOf_dual_base_eq : {B | M﹡.Base B} = (fun X ↦ M.E \ X) '' {B | M.Base B} := by + ext B + simp only [mem_setOf_eq, mem_image, dual_base_iff'] + refine' ⟨fun h ↦ ⟨_, h.1, diff_diff_cancel_left h.2⟩, + fun ⟨B', hB', h⟩ ↦ ⟨_,h.symm.trans_subset (diff_subset _ _)⟩⟩ + rwa [← h, diff_diff_cancel_left hB'.subset_ground] + +@[simp] theorem dual_dual (M : Matroid α) : M﹡﹡ = M := + eq_of_base_iff_base_forall rfl (fun B (h : B ⊆ M.E) ↦ + by rw [dual_base_iff, dual_base_iff, dual_ground, diff_diff_cancel_left h]) + +theorem dual_involutive : Function.Involutive (dual : Matroid α → Matroid α) := dual_dual + +theorem dual_injective : Function.Injective (dual : Matroid α → Matroid α) := + dual_involutive.injective + +@[simp] theorem dual_inj {M₁ M₂ : Matroid α} : M₁﹡ = M₂﹡ ↔ M₁ = M₂ := + dual_injective.eq_iff + +theorem eq_dual_comm {M₁ M₂ : Matroid α} : M₁ = M₂﹡ ↔ M₂ = M₁﹡ := by + rw [← dual_inj, dual_dual, eq_comm] + +theorem eq_dual_iff_dual_eq {M₁ M₂ : Matroid α} : M₁ = M₂﹡ ↔ M₁﹡ = M₂ := + dual_involutive.eq_iff.symm + +theorem Base.compl_base_of_dual (h : M﹡.Base B) : M.Base (M.E \ B) := + (dual_base_iff'.1 h).1 + +theorem Base.compl_base_dual (h : M.Base B) : M﹡.Base (M.E \ B) := by + rwa [dual_base_iff, diff_diff_cancel_left h.subset_ground] + +theorem Base.compl_inter_basis_of_inter_basis (hB : M.Base B) (hBX : M.Basis (B ∩ X) X) : + M﹡.Basis ((M.E \ B) ∩ (M.E \ X)) (M.E \ X) := by + refine' Indep.basis_of_forall_insert _ (inter_subset_right _ _) (fun e he ↦ _) + · rw [dual_indep_iff_exists] + exact ⟨B, hB, disjoint_of_subset_left (inter_subset_left _ _) disjoint_sdiff_left⟩ + simp only [diff_inter_self_eq_diff, mem_diff, not_and, not_not, imp_iff_right he.1.1] at he + simp_rw [dual_dep_iff_forall, insert_subset_iff, and_iff_right he.1.1, + and_iff_left ((inter_subset_left _ _).trans (diff_subset _ _))] + refine' fun B' hB' ↦ by_contra (fun hem ↦ _) + rw [nonempty_iff_ne_empty, not_ne_iff, ← union_singleton, diff_inter_diff, + inter_distrib_right, union_empty_iff, singleton_inter_eq_empty, diff_eq, + inter_right_comm, inter_eq_self_of_subset_right hB'.subset_ground, ← diff_eq, + diff_eq_empty] at hem + obtain ⟨f, hfb, hBf⟩ := hB.exchange hB' ⟨he.2, hem.2⟩ + + have hi : M.Indep (insert f (B ∩ X)) + · refine' hBf.indep.subset (insert_subset_insert _) + simp_rw [subset_diff, and_iff_right (inter_subset_left _ _), disjoint_singleton_right, + mem_inter_iff, iff_false_intro he.1.2, and_false, not_false_iff] + exact hfb.2 (hBX.mem_of_insert_indep (Or.elim (hem.1 hfb.1) (False.elim ∘ hfb.2) id) hi).1 + +theorem Base.inter_basis_iff_compl_inter_basis_dual (hB : M.Base B) (hX : X ⊆ M.E := by aesop_mat): + M.Basis (B ∩ X) X ↔ M﹡.Basis ((M.E \ B) ∩ (M.E \ X)) (M.E \ X) := by + refine' ⟨hB.compl_inter_basis_of_inter_basis, fun h ↦ _⟩ + simpa [inter_eq_self_of_subset_right hX, inter_eq_self_of_subset_right hB.subset_ground] using + hB.compl_base_dual.compl_inter_basis_of_inter_basis h + +theorem base_iff_dual_base_compl (hB : B ⊆ M.E := by aesop_mat) : + M.Base B ↔ M﹡.Base (M.E \ B) := by + rw [dual_base_iff, diff_diff_cancel_left hB] + +theorem ground_not_base (M : Matroid α) [h : RkPos M﹡] : ¬M.Base M.E := by + rwa [rkPos_iff_empty_not_base, dual_base_iff, diff_empty] at h + +theorem Base.ssubset_ground [h : RkPos M﹡] (hB : M.Base B) : B ⊂ M.E := + hB.subset_ground.ssubset_of_ne (by rintro rfl; exact M.ground_not_base hB) + +theorem Indep.ssubset_ground [h : RkPos M﹡] (hI : M.Indep I) : I ⊂ M.E := by + obtain ⟨B, hB⟩ := hI.exists_base_superset; exact hB.2.trans_ssubset hB.1.ssubset_ground + +/-- A coindependent set of `M` is an independent set of the dual of `M﹡`. we give it a separate + definition to enable dot notation. Which spelling is better depends on context. -/ +abbrev Coindep (M : Matroid α) (I : Set α) : Prop := M﹡.Indep I + +theorem coindep_def : M.Coindep X ↔ M﹡.Indep X := Iff.rfl + +theorem Coindep.indep (hX : M.Coindep X) : M﹡.Indep X := + hX + +@[simp] theorem dual_coindep_iff : M﹡.Coindep X ↔ M.Indep X := by + rw [Coindep, dual_dual] + +theorem Indep.coindep (hI : M.Indep I) : M﹡.Coindep I := + dual_coindep_iff.2 hI + +theorem coindep_iff_exists' : M.Coindep X ↔ (∃ B, M.Base B ∧ B ⊆ M.E \ X) ∧ X ⊆ M.E := by + simp_rw [Coindep, dual_indep_iff_exists', and_comm (a := _ ⊆ _), and_congr_left_iff, subset_diff] + exact fun _ ↦ ⟨fun ⟨B, hB, hXB⟩ ↦ ⟨B, hB, hB.subset_ground, hXB.symm⟩, + fun ⟨B, hB, _, hBX⟩ ↦ ⟨B, hB, hBX.symm⟩⟩ + +theorem coindep_iff_exists (hX : X ⊆ M.E := by aesop_mat) : + M.Coindep X ↔ ∃ B, M.Base B ∧ B ⊆ M.E \ X := by + rw [coindep_iff_exists', and_iff_left hX] + +theorem coindep_iff_subset_compl_base : M.Coindep X ↔ ∃ B, M.Base B ∧ X ⊆ M.E \ B := by + simp_rw [coindep_iff_exists', subset_diff] + exact ⟨fun ⟨⟨B, hB, _, hBX⟩, hX⟩ ↦ ⟨B, hB, hX, hBX.symm⟩, + fun ⟨B, hB, hXE, hXB⟩ ↦ ⟨⟨B, hB, hB.subset_ground, hXB.symm⟩, hXE⟩⟩ + +@[aesop unsafe 10% (rule_sets [Matroid])] +theorem Coindep.subset_ground (hX : M.Coindep X) : X ⊆ M.E := + hX.indep.subset_ground + +theorem Coindep.exists_base_subset_compl (h : M.Coindep X) : ∃ B, M.Base B ∧ B ⊆ M.E \ X := + (coindep_iff_exists h.subset_ground).1 h + +theorem Coindep.exists_subset_compl_base (h : M.Coindep X) : ∃ B, M.Base B ∧ X ⊆ M.E \ B := + coindep_iff_subset_compl_base.1 h + +end dual diff --git a/Mathlib/Data/Matroid/IndepAxioms.lean b/Mathlib/Data/Matroid/IndepAxioms.lean index cfb84204a442d..47dc9fc7bf89c 100644 --- a/Mathlib/Data/Matroid/IndepAxioms.lean +++ b/Mathlib/Data/Matroid/IndepAxioms.lean @@ -44,7 +44,7 @@ made essentially invisible by the simplifier when working with `M`. Because of this setup, we don't define any API for `IndepMatroid`, as it would be a redundant copy of the existing API for `Matroid.Indep`. (In particular, one could define a natural equivalence `e : IndepMatroid α ≃ Matroid α` -with `e.toFun = IndepMatroid.toMatroid`, but this would be pointless, as there is no need +with `e.toFun = IndepMatroid.matroid`, but this would be pointless, as there is no need for the inverse of `e`). ## Main definitions diff --git a/Mathlib/Data/Multiset/Basic.lean b/Mathlib/Data/Multiset/Basic.lean index a528d9c217a86..8d5c273a7e529 100644 --- a/Mathlib/Data/Multiset/Basic.lean +++ b/Mathlib/Data/Multiset/Basic.lean @@ -3099,7 +3099,7 @@ theorem pairwise_coe_iff {r : α → α → Prop} {l : List α} : theorem pairwise_coe_iff_pairwise {r : α → α → Prop} (hr : Symmetric r) {l : List α} : Multiset.Pairwise r l ↔ l.Pairwise r := - Iff.intro (fun ⟨_l', Eq, h⟩ => ((Quotient.exact Eq).pairwise_iff hr).2 h) fun h => ⟨l, rfl, h⟩ + Iff.intro (fun ⟨_l', Eq, h⟩ => ((Quotient.exact Eq).pairwise_iff @hr).2 h) fun h => ⟨l, rfl, h⟩ #align multiset.pairwise_coe_iff_pairwise Multiset.pairwise_coe_iff_pairwise theorem map_set_pairwise {f : α → β} {r : β → β → Prop} {m : Multiset α} diff --git a/Mathlib/Data/Multiset/Nodup.lean b/Mathlib/Data/Multiset/Nodup.lean index 0e7e6e9063c5a..d1418b4021db3 100644 --- a/Mathlib/Data/Multiset/Nodup.lean +++ b/Mathlib/Data/Multiset/Nodup.lean @@ -242,7 +242,7 @@ theorem nodup_bind {s : Multiset α} {t : α → Multiset β} : #align multiset.nodup_bind Multiset.nodup_bind theorem Nodup.ext {s t : Multiset α} : Nodup s → Nodup t → (s = t ↔ ∀ a, a ∈ s ↔ a ∈ t) := - Quotient.inductionOn₂ s t fun _ _ d₁ d₂ => Quotient.eq.trans <| perm_ext d₁ d₂ + Quotient.inductionOn₂ s t fun _ _ d₁ d₂ => Quotient.eq.trans <| perm_ext_iff_of_nodup d₁ d₂ #align multiset.nodup.ext Multiset.Nodup.ext theorem le_iff_subset {s t : Multiset α} : Nodup s → (s ≤ t ↔ s ⊆ t) := diff --git a/Mathlib/Data/Multiset/Powerset.lean b/Mathlib/Data/Multiset/Powerset.lean index 01e0fc4d4bb9f..5e3d047fc5f9b 100644 --- a/Mathlib/Data/Multiset/Powerset.lean +++ b/Mathlib/Data/Multiset/Powerset.lean @@ -322,7 +322,7 @@ theorem nodup_powerset {s : Multiset α} : Nodup (powerset s) ↔ Nodup s := simp only [quot_mk_to_coe, powerset_coe', coe_nodup] refine' (nodup_sublists'.2 h).map_on _ exact fun x sx y sy e => - (h.sublist_ext (mem_sublists'.1 sx) (mem_sublists'.1 sy)).1 (Quotient.exact e)⟩ + (h.perm_iff_eq_of_sublist (mem_sublists'.1 sx) (mem_sublists'.1 sy)).1 (Quotient.exact e)⟩ #align multiset.nodup_powerset Multiset.nodup_powerset alias ⟨Nodup.ofPowerset, Nodup.powerset⟩ := nodup_powerset diff --git a/Mathlib/Data/Multiset/Sym.lean b/Mathlib/Data/Multiset/Sym.lean index 5343f39eab9a2..1da72ce97876b 100644 --- a/Mathlib/Data/Multiset/Sym.lean +++ b/Mathlib/Data/Multiset/Sym.lean @@ -58,6 +58,7 @@ theorem mem_sym2_iff {m : Multiset α} {z : Sym2 α} : protected theorem Nodup.sym2 {m : Multiset α} (h : m.Nodup) : m.sym2.Nodup := m.inductionOn (fun _ h => List.Nodup.sym2 h) h +open scoped List in @[simp, mono] theorem sym2_mono {m m' : Multiset α} (h : m ≤ m') : m.sym2 ≤ m'.sym2 := by refine Quotient.inductionOn₂ m m' (fun xs ys h => ?_) h diff --git a/Mathlib/Data/Nat/Factorization/Basic.lean b/Mathlib/Data/Nat/Factorization/Basic.lean index cab8dcfc1d40a..eb01479ad42c0 100644 --- a/Mathlib/Data/Nat/Factorization/Basic.lean +++ b/Mathlib/Data/Nat/Factorization/Basic.lean @@ -630,7 +630,7 @@ theorem prod_primeFactors_dvd (n : ℕ) : ∏ p in n.primeFactors, p ∣ n := by theorem factorization_gcd {a b : ℕ} (ha_pos : a ≠ 0) (hb_pos : b ≠ 0) : (gcd a b).factorization = a.factorization ⊓ b.factorization := by let dfac := a.factorization ⊓ b.factorization - let d := dfac.prod Nat.pow + let d := dfac.prod (· ^ ·) have dfac_prime : ∀ p : ℕ, p ∈ dfac.support → Prime p := by intro p hp have : p ∈ a.factors ∧ p ∈ b.factors := by simpa using hp diff --git a/Mathlib/Data/Nat/Factors.lean b/Mathlib/Data/Nat/Factors.lean index 81acf4a51e590..6df8f4bd0361b 100644 --- a/Mathlib/Data/Nat/Factors.lean +++ b/Mathlib/Data/Nat/Factors.lean @@ -129,6 +129,7 @@ theorem factors_eq_nil (n : ℕ) : n.factors = [] ↔ n = 0 ∨ n = 1 := by · exact factors_one #align nat.factors_eq_nil Nat.factors_eq_nil +open scoped List in theorem eq_of_perm_factors {a b : ℕ} (ha : a ≠ 0) (hb : b ≠ 0) (h : a.factors ~ b.factors) : a = b := by simpa [prod_factors ha, prod_factors hb] using List.Perm.prod_eq h #align nat.eq_of_perm_factors Nat.eq_of_perm_factors diff --git a/Mathlib/Data/Nat/Order/Basic.lean b/Mathlib/Data/Nat/Order/Basic.lean index 9e0ffc34650d6..bc4d65d56fde4 100644 --- a/Mathlib/Data/Nat/Order/Basic.lean +++ b/Mathlib/Data/Nat/Order/Basic.lean @@ -490,6 +490,9 @@ theorem one_mod (n : ℕ) : 1 % (n + 2) = 1 := Nat.mod_eq_of_lt (add_lt_add_right n.succ_pos 1) #align nat.one_mod Nat.one_mod +theorem one_mod_of_ne_one : ∀ {n : ℕ}, n ≠ 1 → 1 % n = 1 + | 0, _ | (n + 2), _ => by simp + theorem dvd_sub_mod (k : ℕ) : n ∣ k - k % n := ⟨k / n, tsub_eq_of_eq_add_rev (Nat.mod_add_div k n).symm⟩ #align nat.dvd_sub_mod Nat.dvd_sub_mod diff --git a/Mathlib/Data/PEquiv.lean b/Mathlib/Data/PEquiv.lean index df73a60fe81ce..4f4518e8ea511 100644 --- a/Mathlib/Data/PEquiv.lean +++ b/Mathlib/Data/PEquiv.lean @@ -43,7 +43,7 @@ pequiv, partial equivalence universe u v w x /-- A `PEquiv` is a partial equivalence, a representation of a bijection between a subset - of `α` and a subset of `β`. See also `LocalEquiv` for a version that requires `toFun` and + of `α` and a subset of `β`. See also `PartialEquiv` for a version that requires `toFun` and `invFun` to be globally defined functions and has `source` and `target` sets as extra fields. -/ structure PEquiv (α : Type u) (β : Type v) where /-- The underlying partial function of a `PEquiv` -/ @@ -55,7 +55,7 @@ structure PEquiv (α : Type u) (β : Type v) where #align pequiv PEquiv /-- A `PEquiv` is a partial equivalence, a representation of a bijection between a subset - of `α` and a subset of `β`. See also `LocalEquiv` for a version that requires `toFun` and + of `α` and a subset of `β`. See also `PartialEquiv` for a version that requires `toFun` and `invFun` to be globally defined functions and has `source` and `target` sets as extra fields. -/ infixr:25 " ≃. " => PEquiv diff --git a/Mathlib/Data/Polynomial/Splits.lean b/Mathlib/Data/Polynomial/Splits.lean index d891e37afff94..1693baae5ae37 100644 --- a/Mathlib/Data/Polynomial/Splits.lean +++ b/Mathlib/Data/Polynomial/Splits.lean @@ -30,7 +30,7 @@ open BigOperators Polynomial universe u v w -variable {F : Type u} {K : Type v} {L : Type w} +variable {R : Type*} {F : Type u} {K : Type v} {L : Type w} namespace Polynomial @@ -224,7 +224,7 @@ theorem degree_eq_card_roots' {p : K[X]} {i : K →+* L} (p_ne_zero : p.map i end CommRing -variable [Field K] [Field L] [Field F] +variable [CommRing R] [Field K] [Field L] [Field F] variable (i : K →+* L) @@ -329,17 +329,17 @@ theorem roots_map {f : K[X]} (hf : f.Splits <| RingHom.id K) : (f.map i).roots = rw [map_id]).symm #align polynomial.roots_map Polynomial.roots_map -theorem image_rootSet [Algebra F K] [Algebra F L] {p : F[X]} (h : p.Splits (algebraMap F K)) - (f : K →ₐ[F] L) : f '' p.rootSet K = p.rootSet L := by +theorem image_rootSet [Algebra R K] [Algebra R L] {p : R[X]} (h : p.Splits (algebraMap R K)) + (f : K →ₐ[R] L) : f '' p.rootSet K = p.rootSet L := by classical rw [rootSet, ← Finset.coe_image, ← Multiset.toFinset_map, ← f.coe_toRingHom, - ← roots_map _ ((splits_id_iff_splits (algebraMap F K)).mpr h), map_map, f.comp_algebraMap, + ← roots_map _ ((splits_id_iff_splits (algebraMap R K)).mpr h), map_map, f.comp_algebraMap, ← rootSet] #align polynomial.image_root_set Polynomial.image_rootSet -theorem adjoin_rootSet_eq_range [Algebra F K] [Algebra F L] {p : F[X]} - (h : p.Splits (algebraMap F K)) (f : K →ₐ[F] L) : - Algebra.adjoin F (p.rootSet L) = f.range ↔ Algebra.adjoin F (p.rootSet K) = ⊤ := by +theorem adjoin_rootSet_eq_range [Algebra R K] [Algebra R L] {p : R[X]} + (h : p.Splits (algebraMap R K)) (f : K →ₐ[R] L) : + Algebra.adjoin R (p.rootSet L) = f.range ↔ Algebra.adjoin R (p.rootSet K) = ⊤ := by rw [← image_rootSet h f, Algebra.adjoin_image, ← Algebra.map_top] exact (Subalgebra.map_injective f.toRingHom.injective).eq_iff #align polynomial.adjoin_root_set_eq_range Polynomial.adjoin_rootSet_eq_range @@ -370,7 +370,8 @@ theorem eq_X_sub_C_of_splits_of_single_root {x : K} {h : K[X]} (h_splits : Split set_option linter.uppercaseLean3 false in #align polynomial.eq_X_sub_C_of_splits_of_single_root Polynomial.eq_X_sub_C_of_splits_of_single_root -theorem mem_lift_of_splits_of_roots_mem_range (R : Type*) [CommRing R] [Algebra R K] {f : K[X]} +variable (R) in +theorem mem_lift_of_splits_of_roots_mem_range [Algebra R K] {f : K[X]} (hs : f.Splits (RingHom.id K)) (hm : f.Monic) (hr : ∀ a ∈ f.roots, a ∈ (algebraMap R K).range) : f ∈ Polynomial.lifts (algebraMap R K) := by rw [eq_prod_roots_of_monic_of_splits_id hm hs, lifts_iff_liftsRing] @@ -438,14 +439,22 @@ theorem splits_id_of_splits {f : K[X]} (h : Splits i f) (roots_mem_range : ∀ a ∈ (f.map i).roots, a ∈ i.range) : Splits (RingHom.id K) f := splits_of_comp (RingHom.id K) i h roots_mem_range -theorem splits_comp_of_splits (j : L →+* F) {f : K[X]} (h : Splits i f) : Splits (j.comp i) f := by - -- Porting note: was - -- change i with (RingHom.id _).comp i at h - rw [← splits_map_iff] - rw [← RingHom.id_comp i, ← splits_map_iff i] at h - exact splits_of_splits_id _ h +theorem splits_comp_of_splits (i : R →+* K) (j : K →+* L) {f : R[X]} (h : Splits i f) : + Splits (j.comp i) f := + (splits_map_iff i j).mp (splits_of_splits_id _ <| (splits_map_iff i <| .id K).mpr h) #align polynomial.splits_comp_of_splits Polynomial.splits_comp_of_splits +variable [Algebra R K] [Algebra R L] + +theorem splits_of_algHom {f : R[X]} (h : Splits (algebraMap R K) f) (e : K →ₐ[R] L) : + Splits (algebraMap R L) f := by + rw [← e.comp_algebraMap_of_tower R]; exact splits_comp_of_splits _ _ h + +variable (L) in +theorem splits_of_isScalarTower {f : R[X]} [Algebra K L] [IsScalarTower R K L] + (h : Splits (algebraMap R K) f) : Splits (algebraMap R L) f := + splits_of_algHom h (IsScalarTower.toAlgHom R K L) + /-- A polynomial splits if and only if it has as many roots as its degree. -/ theorem splits_iff_card_roots {p : K[X]} : Splits (RingHom.id K) p ↔ Multiset.card p.roots = p.natDegree := by diff --git a/Mathlib/Data/Rat/NNRat.lean b/Mathlib/Data/Rat/NNRat.lean index 7c519d5b27030..ff84ceb139201 100644 --- a/Mathlib/Data/Rat/NNRat.lean +++ b/Mathlib/Data/Rat/NNRat.lean @@ -5,7 +5,6 @@ Authors: Yaël Dillies, Bhavik Mehta -/ import Mathlib.Algebra.Algebra.Basic import Mathlib.Algebra.BigOperators.Order -import Mathlib.Algebra.IndicatorFunction import Mathlib.Algebra.Order.Nonneg.Field import Mathlib.Algebra.Order.Nonneg.Floor diff --git a/Mathlib/Data/Real/NNReal.lean b/Mathlib/Data/Real/NNReal.lean index 8cbed474d2081..09cd022406298 100644 --- a/Mathlib/Data/Real/NNReal.lean +++ b/Mathlib/Data/Real/NNReal.lean @@ -6,7 +6,6 @@ Authors: Johan Commelin import Mathlib.Algebra.Algebra.Basic import Mathlib.Algebra.BigOperators.Order import Mathlib.Algebra.BigOperators.Ring -import Mathlib.Algebra.IndicatorFunction import Mathlib.Algebra.Order.Field.Canonical.Basic import Mathlib.Algebra.Order.Nonneg.Field import Mathlib.Algebra.Order.Nonneg.Floor @@ -278,6 +277,18 @@ instance {A : Type*} [Semiring A] [Algebra ℝ A] : Algebra ℝ≥0 A where smul_def' r x := by simp [← Algebra.smul_def (r : ℝ) x, smul_def] toRingHom := (algebraMap ℝ A).comp (toRealHom : ℝ≥0 →+* ℝ) +instance : StarRing ℝ≥0 where + star := id + star_involutive _ := rfl + star_mul := mul_comm + star_add _ _ := rfl + +instance : TrivialStar ℝ≥0 where + star_trivial _ := rfl + +instance : StarModule ℝ≥0 ℝ where + star_smul := by simp only [star_trivial, eq_self_iff_true, forall_const] + -- verify that the above produces instances we might care about example : Algebra ℝ≥0 ℝ := by infer_instance diff --git a/Mathlib/Data/Set/Basic.lean b/Mathlib/Data/Set/Basic.lean index 1ad29fccbfcd0..6b7d935c34c0b 100644 --- a/Mathlib/Data/Set/Basic.lean +++ b/Mathlib/Data/Set/Basic.lean @@ -1179,7 +1179,7 @@ theorem subset_insert_iff_of_not_mem (ha : a ∉ s) : s ⊆ insert a t ↔ s ⊆ forall₂_congr <| fun _ hb => or_iff_right <| ne_of_mem_of_not_mem hb ha #align set.subset_insert_iff_of_not_mem Set.subset_insert_iff_of_not_mem -theorem ssubset_iff_insert {s t : Set α} : s ⊂ t ↔ ∃ a, a ∉ s ∧ insert a s ⊆ t := by +theorem ssubset_iff_insert {s t : Set α} : s ⊂ t ↔ ∃ a ∉ s, insert a s ⊆ t := by simp only [insert_subset_iff, exists_and_right, ssubset_def, not_subset] aesop #align set.ssubset_iff_insert Set.ssubset_iff_insert diff --git a/Mathlib/Data/Set/Finite.lean b/Mathlib/Data/Set/Finite.lean index f883762ff0cb6..d7ec3228f0c00 100644 --- a/Mathlib/Data/Set/Finite.lean +++ b/Mathlib/Data/Set/Finite.lean @@ -934,6 +934,22 @@ theorem finite_le_nat (n : ℕ) : Set.Finite { i | i ≤ n } := toFinite _ #align set.finite_le_nat Set.finite_le_nat +section MapsTo + +variable {s : Set α} {f : α → α} (hs : s.Finite) (hm : MapsTo f s s) + +theorem Finite.surjOn_iff_bijOn_of_mapsTo : SurjOn f s s ↔ BijOn f s s := by + refine ⟨fun h ↦ ⟨hm, ?_, h⟩, BijOn.surjOn⟩ + have : Finite s := finite_coe_iff.mpr hs + exact hm.restrict_inj.mp (Finite.injective_iff_surjective.mpr <| hm.restrict_surjective_iff.mpr h) + +theorem Finite.injOn_iff_bijOn_of_mapsTo : InjOn f s ↔ BijOn f s s := by + refine ⟨fun h ↦ ⟨hm, h, ?_⟩, BijOn.injOn⟩ + have : Finite s := finite_coe_iff.mpr hs + exact hm.restrict_surjective_iff.mp (Finite.injective_iff_surjective.mp <| hm.restrict_inj.mpr h) + +end MapsTo + section Prod variable {s : Set α} {t : Set β} diff --git a/Mathlib/Data/Set/Function.lean b/Mathlib/Data/Set/Function.lean index 2ac90e7dce7d0..7e4ea6308ce1a 100644 --- a/Mathlib/Data/Set/Function.lean +++ b/Mathlib/Data/Set/Function.lean @@ -372,6 +372,11 @@ theorem MapsTo.val_restrict_apply (h : MapsTo f s t) (x : s) : (h.restrict f s t rfl #align set.maps_to.coe_restrict_apply Set.MapsTo.val_restrict_apply +theorem MapsTo.coe_iterate_restrict {f : α → α} (h : MapsTo f s s) (x : s) (k : ℕ) : + h.restrict^[k] x = f^[k] x := by + induction' k with k ih; · simp + simp only [iterate_succ', comp_apply, val_restrict_apply, ih] + /-- Restricting the domain and then the codomain is the same as `MapsTo.restrict`. -/ @[simp] theorem codRestrict_restrict (h : ∀ x : s, f x ∈ t) : @@ -1004,6 +1009,10 @@ theorem BijOn.image_eq (h : BijOn f s t) : f '' s = t := h.surjOn.image_eq_of_mapsTo h.mapsTo #align set.bij_on.image_eq Set.BijOn.image_eq +lemma _root_.Equiv.image_eq_iff_bijOn (e : α ≃ β) : e '' s = t ↔ BijOn e s t := + ⟨fun h ↦ ⟨(mapsTo_image e s).mono_right h.subset, e.injective.injOn _, h ▸ surjOn_image e s⟩, + BijOn.image_eq⟩ + lemma bijOn_id (s : Set α) : BijOn id s s := ⟨s.mapsTo_id, s.injOn_id, s.surjOn_id⟩ #align set.bij_on_id Set.bijOn_id diff --git a/Mathlib/Data/Set/Image.lean b/Mathlib/Data/Set/Image.lean index 573b58e86369e..dbdcfca9cbaf8 100644 --- a/Mathlib/Data/Set/Image.lean +++ b/Mathlib/Data/Set/Image.lean @@ -290,11 +290,17 @@ theorem image_congr' {f g : α → β} {s : Set α} (h : ∀ x : α, f x = g x) image_congr fun x _ => h x #align set.image_congr' Set.image_congr' +@[gcongr] +lemma image_mono (h : s ⊆ t) : f '' s ⊆ f '' t := by + rintro - ⟨a, ha, rfl⟩; exact mem_image_of_mem f (h ha) + theorem image_comp (f : β → γ) (g : α → β) (a : Set α) : f ∘ g '' a = f '' (g '' a) := Subset.antisymm (ball_image_of_ball fun _ ha => mem_image_of_mem _ <| mem_image_of_mem _ ha) (ball_image_of_ball <| ball_image_of_ball fun _ ha => mem_image_of_mem _ ha) #align set.image_comp Set.image_comp +theorem image_comp_eq {g : β → γ} : image (g ∘ f) = image g ∘ image f := by ext; simp + /-- A variant of `image_comp`, useful for rewriting -/ theorem image_image (g : β → γ) (f : α → β) (s : Set α) : g '' (f '' s) = (fun x => g (f x)) '' s := (image_comp g f s).symm @@ -391,6 +397,9 @@ theorem mem_compl_image [BooleanAlgebra α] (t : α) (S : Set α) : simp [← preimage_compl_eq_image_compl] #align set.mem_compl_image Set.mem_compl_image +@[simp] +theorem image_id_eq : image (id : α → α) = id := by ext; simp + /-- A variant of `image_id` -/ @[simp] theorem image_id' (s : Set α) : (fun x => x) '' s = s := by @@ -401,6 +410,10 @@ theorem image_id' (s : Set α) : (fun x => x) '' s = s := by theorem image_id (s : Set α) : id '' s = s := by simp #align set.image_id Set.image_id +lemma image_iterate_eq {f : α → α} {n : ℕ} : image (f^[n]) = (image f)^[n] := by + induction' n with n ih; · simp + rw [iterate_succ', iterate_succ',← ih, image_comp_eq] + theorem compl_compl_image [BooleanAlgebra α] (S : Set α) : HasCompl.compl '' (HasCompl.compl '' S) = S := by rw [← image_comp, compl_comp_compl, image_id] diff --git a/Mathlib/Data/Set/Pointwise/Interval.lean b/Mathlib/Data/Set/Pointwise/Interval.lean index e2074e9d77692..0f347211555d3 100644 --- a/Mathlib/Data/Set/Pointwise/Interval.lean +++ b/Mathlib/Data/Set/Pointwise/Interval.lean @@ -27,6 +27,93 @@ variable {α : Type*} namespace Set +/-! ### Binary pointwise operations + +Note that the subset operations below only cover the cases with the largest possible intervals on +the LHS: to conclude that `Ioo a b * Ioo c d ⊆ Ioo (a * c) (c * d)`, you can use monotonicity of `*` +and `Set.Ico_mul_Ioc_subset`. + +TODO: repeat these lemmas for the generality of `mul_le_mul` (which assumes nonnegativity), which +the unprimed names have been reserved for +-/ + +section ContravariantLE + +variable [Mul α] [Preorder α] +variable [CovariantClass α α (· * ·) (· ≤ ·)] [CovariantClass α α (Function.swap HMul.hMul) LE.le] + +@[to_additive Icc_add_Icc_subset] +theorem Icc_mul_Icc_subset' (a b c d : α) : Icc a b * Icc c d ⊆ Icc (a * c) (b * d) := by + rintro x ⟨y, z, ⟨hya, hyb⟩, ⟨hzc, hzd⟩, rfl⟩ + exact ⟨mul_le_mul' hya hzc, mul_le_mul' hyb hzd⟩ + +@[to_additive Iic_add_Iic_subset] +theorem Iic_mul_Iic_subset' (a b : α) : Iic a * Iic b ⊆ Iic (a * b) := by + rintro x ⟨y, z, hya, hzb, rfl⟩ + exact mul_le_mul' hya hzb + +@[to_additive Ici_add_Ici_subset] +theorem Ici_mul_Ici_subset' (a b : α) : Ici a * Ici b ⊆ Ici (a * b) := by + rintro x ⟨y, z, hya, hzb, rfl⟩ + exact mul_le_mul' hya hzb + +end ContravariantLE + +section ContravariantLT + +variable [Mul α] [PartialOrder α] +variable [CovariantClass α α (· * ·) (· < ·)] [CovariantClass α α (Function.swap HMul.hMul) LT.lt] + +@[to_additive Icc_add_Ico_subset] +theorem Icc_mul_Ico_subset' (a b c d : α) : Icc a b * Ico c d ⊆ Ico (a * c) (b * d) := by + haveI := covariantClass_le_of_lt + rintro x ⟨y, z, ⟨hya, hyb⟩, ⟨hzc, hzd⟩, rfl⟩ + exact ⟨mul_le_mul' hya hzc, mul_lt_mul_of_le_of_lt hyb hzd⟩ + +@[to_additive Ico_add_Icc_subset] +theorem Ico_mul_Icc_subset' (a b c d : α) : Ico a b * Icc c d ⊆ Ico (a * c) (b * d) := by + haveI := covariantClass_le_of_lt + rintro x ⟨y, z, ⟨hya, hyb⟩, ⟨hzc, hzd⟩, rfl⟩ + exact ⟨mul_le_mul' hya hzc, mul_lt_mul_of_lt_of_le hyb hzd⟩ + +@[to_additive Ioc_add_Ico_subset] +theorem Ioc_mul_Ico_subset' (a b c d : α) : Ioc a b * Ico c d ⊆ Ioo (a * c) (b * d) := by + haveI := covariantClass_le_of_lt + rintro x ⟨y, z, ⟨hya, hyb⟩, ⟨hzc, hzd⟩, rfl⟩ + exact ⟨mul_lt_mul_of_lt_of_le hya hzc, mul_lt_mul_of_le_of_lt hyb hzd⟩ + +@[to_additive Ico_add_Ioc_subset] +theorem Ico_mul_Ioc_subset' (a b c d : α) : Ico a b * Ioc c d ⊆ Ioo (a * c) (b * d) := by + haveI := covariantClass_le_of_lt + rintro x ⟨y, z, ⟨hya, hyb⟩, ⟨hzc, hzd⟩, rfl⟩ + exact ⟨mul_lt_mul_of_le_of_lt hya hzc, mul_lt_mul_of_lt_of_le hyb hzd⟩ + +@[to_additive Iic_add_Iio_subset] +theorem Iic_mul_Iio_subset' (a b : α) : Iic a * Iio b ⊆ Iio (a * b) := by + haveI := covariantClass_le_of_lt + rintro x ⟨y, z, hya, hzb, rfl⟩ + exact mul_lt_mul_of_le_of_lt hya hzb + +@[to_additive Iio_add_Iic_subset] +theorem Iio_mul_Iic_subset' (a b : α) : Iio a * Iic b ⊆ Iio (a * b) := by + haveI := covariantClass_le_of_lt + rintro x ⟨y, z, hya, hzb, rfl⟩ + exact mul_lt_mul_of_lt_of_le hya hzb + +@[to_additive Ioi_add_Ici_subset] +theorem Ioi_mul_Ici_subset' (a b : α) : Ioi a * Ici b ⊆ Ioi (a * b) := by + haveI := covariantClass_le_of_lt + rintro x ⟨y, z, hya, hzb, rfl⟩ + exact mul_lt_mul_of_lt_of_le hya hzb + +@[to_additive Ici_add_Ioi_subset] +theorem Ici_mul_Ioi_subset' (a b : α) : Ici a * Ioi b ⊆ Ioi (a * b) := by + haveI := covariantClass_le_of_lt + rintro x ⟨y, z, hya, hzb, rfl⟩ + exact mul_lt_mul_of_le_of_lt hya hzb + +end ContravariantLT + section OrderedAddCommGroup variable [OrderedAddCommGroup α] (a b c : α) diff --git a/Mathlib/Data/Set/Pointwise/Support.lean b/Mathlib/Data/Set/Pointwise/Support.lean index cc2a1844e6697..c2b47c5a16b45 100644 --- a/Mathlib/Data/Set/Pointwise/Support.lean +++ b/Mathlib/Data/Set/Pointwise/Support.lean @@ -3,8 +3,8 @@ Copyright (c) 2022 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ +import Mathlib.Algebra.Function.Support import Mathlib.Data.Set.Pointwise.SMul -import Mathlib.Algebra.Support #align_import data.set.pointwise.support from "leanprover-community/mathlib"@"f7fc89d5d5ff1db2d1242c7bb0e9062ce47ef47c" diff --git a/Mathlib/Data/Set/Prod.lean b/Mathlib/Data/Set/Prod.lean index dec510141c31d..6d0a7a5afbfb3 100644 --- a/Mathlib/Data/Set/Prod.lean +++ b/Mathlib/Data/Set/Prod.lean @@ -133,6 +133,9 @@ theorem univ_prod {t : Set β} : (univ : Set α) ×ˢ t = Prod.snd ⁻¹' t := b theorem prod_univ {s : Set α} : s ×ˢ (univ : Set β) = Prod.fst ⁻¹' s := by simp [prod_eq] #align set.prod_univ Set.prod_univ +@[simp] lemma prod_eq_univ [Nonempty α] [Nonempty β] : s ×ˢ t = univ ↔ s = univ ∧ t = univ := by + simp [eq_univ_iff_forall, forall_and] + @[simp] theorem singleton_prod : ({a} : Set α) ×ˢ t = Prod.mk a '' t := by ext ⟨x, y⟩ diff --git a/Mathlib/Data/Set/Sigma.lean b/Mathlib/Data/Set/Sigma.lean index 6e99824179ea1..7b77da79645d8 100644 --- a/Mathlib/Data/Set/Sigma.lean +++ b/Mathlib/Data/Set/Sigma.lean @@ -51,62 +51,52 @@ theorem image_sigmaMk_preimage_sigmaMap {β : ι' → Type*} {f : ι → ι'} (h /-- Indexed sum of sets. `s.sigma t` is the set of dependent pairs `⟨i, a⟩` such that `i ∈ s` and `a ∈ t i`.-/ -protected def Sigma (s : Set ι) (t : ∀ i, Set (α i)) : Set (Σi, α i) := - { x | x.1 ∈ s ∧ x.2 ∈ t x.1 } -#align set.sigma Set.Sigma +protected def sigma (s : Set ι) (t : ∀ i, Set (α i)) : Set (Σ i, α i) := {x | x.1 ∈ s ∧ x.2 ∈ t x.1} +#align set.sigma Set.sigma -@[simp] -theorem mem_sigma_iff : x ∈ s.Sigma t ↔ x.1 ∈ s ∧ x.2 ∈ t x.1 := - Iff.rfl +@[simp] theorem mem_sigma_iff : x ∈ s.sigma t ↔ x.1 ∈ s ∧ x.2 ∈ t x.1 := Iff.rfl #align set.mem_sigma_iff Set.mem_sigma_iff -theorem mk_sigma_iff : (⟨i, a⟩ : Σ i, α i) ∈ s.Sigma t ↔ i ∈ s ∧ a ∈ t i := - Iff.rfl +theorem mk_sigma_iff : (⟨i, a⟩ : Σ i, α i) ∈ s.sigma t ↔ i ∈ s ∧ a ∈ t i := Iff.rfl #align set.mk_sigma_iff Set.mk_sigma_iff -theorem mk_mem_sigma (hi : i ∈ s) (ha : a ∈ t i) : (⟨i, a⟩ : Σi, α i) ∈ s.Sigma t := - ⟨hi, ha⟩ +theorem mk_mem_sigma (hi : i ∈ s) (ha : a ∈ t i) : (⟨i, a⟩ : Σ i, α i) ∈ s.sigma t := ⟨hi, ha⟩ #align set.mk_mem_sigma Set.mk_mem_sigma -theorem sigma_mono (hs : s₁ ⊆ s₂) (ht : ∀ i, t₁ i ⊆ t₂ i) : s₁.Sigma t₁ ⊆ s₂.Sigma t₂ := fun _ hx ↦ +theorem sigma_mono (hs : s₁ ⊆ s₂) (ht : ∀ i, t₁ i ⊆ t₂ i) : s₁.sigma t₁ ⊆ s₂.sigma t₂ := fun _ hx ↦ ⟨hs hx.1, ht _ hx.2⟩ #align set.sigma_mono Set.sigma_mono -theorem sigma_subset_iff : s.Sigma t ⊆ u ↔ ∀ ⦃i⦄, i ∈ s → ∀ ⦃a⦄, a ∈ t i → (⟨i, a⟩ : Σi, α i) ∈ u := +theorem sigma_subset_iff : + s.sigma t ⊆ u ↔ ∀ ⦃i⦄, i ∈ s → ∀ ⦃a⦄, a ∈ t i → (⟨i, a⟩ : Σ i, α i) ∈ u := ⟨fun h _ hi _ ha ↦ h <| mk_mem_sigma hi ha, fun h _ ha ↦ h ha.1 ha.2⟩ #align set.sigma_subset_iff Set.sigma_subset_iff -theorem forall_sigma_iff {p : (Σi, α i) → Prop} : - (∀ x ∈ s.Sigma t, p x) ↔ ∀ ⦃i⦄, i ∈ s → ∀ ⦃a⦄, a ∈ t i → p ⟨i, a⟩ := - sigma_subset_iff +theorem forall_sigma_iff {p : (Σ i, α i) → Prop} : + (∀ x ∈ s.sigma t, p x) ↔ ∀ ⦃i⦄, i ∈ s → ∀ ⦃a⦄, a ∈ t i → p ⟨i, a⟩ := sigma_subset_iff #align set.forall_sigma_iff Set.forall_sigma_iff theorem exists_sigma_iff {p : (Σi, α i) → Prop} : - (∃ x ∈ s.Sigma t, p x) ↔ ∃ i ∈ s, ∃ a ∈ t i, p ⟨i, a⟩ := + (∃ x ∈ s.sigma t, p x) ↔ ∃ i ∈ s, ∃ a ∈ t i, p ⟨i, a⟩ := ⟨fun ⟨⟨i, a⟩, ha, h⟩ ↦ ⟨i, ha.1, a, ha.2, h⟩, fun ⟨i, hi, a, ha, h⟩ ↦ ⟨⟨i, a⟩, ⟨hi, ha⟩, h⟩⟩ #align set.exists_sigma_iff Set.exists_sigma_iff -@[simp] -theorem sigma_empty : (s.Sigma fun i ↦ (∅ : Set (α i))) = ∅ := - ext fun _ ↦ and_false_iff _ +@[simp] theorem sigma_empty : s.sigma (fun i ↦ (∅ : Set (α i))) = ∅ := ext fun _ ↦ and_false_iff _ #align set.sigma_empty Set.sigma_empty -@[simp] -theorem empty_sigma : (∅ : Set ι).Sigma t = ∅ := - ext fun _ ↦ false_and_iff _ +@[simp] theorem empty_sigma : (∅ : Set ι).sigma t = ∅ := ext fun _ ↦ false_and_iff _ #align set.empty_sigma Set.empty_sigma -theorem univ_sigma_univ : ((@univ ι).Sigma fun _ ↦ @univ (α i)) = univ := - ext fun _ ↦ true_and_iff _ +theorem univ_sigma_univ : (@univ ι).sigma (fun _ ↦ @univ (α i)) = univ := ext fun _ ↦ true_and_iff _ #align set.univ_sigma_univ Set.univ_sigma_univ @[simp] -theorem sigma_univ : s.Sigma (fun _ ↦ univ : ∀ i, Set (α i)) = Sigma.fst ⁻¹' s := +theorem sigma_univ : s.sigma (fun _ ↦ univ : ∀ i, Set (α i)) = Sigma.fst ⁻¹' s := ext fun _ ↦ and_true_iff _ #align set.sigma_univ Set.sigma_univ @[simp] -theorem singleton_sigma : ({i} : Set ι).Sigma t = Sigma.mk i '' t i := +theorem singleton_sigma : ({i} : Set ι).sigma t = Sigma.mk i '' t i := ext fun x ↦ by constructor · obtain ⟨j, a⟩ := x @@ -118,134 +108,131 @@ theorem singleton_sigma : ({i} : Set ι).Sigma t = Sigma.mk i '' t i := @[simp] theorem sigma_singleton {a : ∀ i, α i} : - (s.Sigma fun i ↦ ({a i} : Set (α i))) = (fun i ↦ Sigma.mk i <| a i) '' s := by + s.sigma (fun i ↦ ({a i} : Set (α i))) = (fun i ↦ Sigma.mk i <| a i) '' s := by ext ⟨x, y⟩ simp [and_left_comm, eq_comm] #align set.sigma_singleton Set.sigma_singleton theorem singleton_sigma_singleton {a : ∀ i, α i} : - (({i} : Set ι).Sigma fun i ↦ ({a i} : Set (α i))) = {⟨i, a i⟩} := by + (({i} : Set ι).sigma fun i ↦ ({a i} : Set (α i))) = {⟨i, a i⟩} := by rw [sigma_singleton, image_singleton] #align set.singleton_sigma_singleton Set.singleton_sigma_singleton @[simp] -theorem union_sigma : (s₁ ∪ s₂).Sigma t = s₁.Sigma t ∪ s₂.Sigma t := - ext fun _ ↦ or_and_right +theorem union_sigma : (s₁ ∪ s₂).sigma t = s₁.sigma t ∪ s₂.sigma t := ext fun _ ↦ or_and_right #align set.union_sigma Set.union_sigma @[simp] -theorem sigma_union : (s.Sigma fun i ↦ t₁ i ∪ t₂ i) = s.Sigma t₁ ∪ s.Sigma t₂ := +theorem sigma_union : s.sigma (fun i ↦ t₁ i ∪ t₂ i) = s.sigma t₁ ∪ s.sigma t₂ := ext fun _ ↦ and_or_left #align set.sigma_union Set.sigma_union -theorem sigma_inter_sigma : s₁.Sigma t₁ ∩ s₂.Sigma t₂ = (s₁ ∩ s₂).Sigma fun i ↦ t₁ i ∩ t₂ i := by +theorem sigma_inter_sigma : s₁.sigma t₁ ∩ s₂.sigma t₂ = (s₁ ∩ s₂).sigma fun i ↦ t₁ i ∩ t₂ i := by ext ⟨x, y⟩ simp [and_assoc, and_left_comm] #align set.sigma_inter_sigma Set.sigma_inter_sigma -theorem insert_sigma : (insert i s).Sigma t = Sigma.mk i '' t i ∪ s.Sigma t := by +theorem insert_sigma : (insert i s).sigma t = Sigma.mk i '' t i ∪ s.sigma t := by rw [insert_eq, union_sigma, singleton_sigma] exact a #align set.insert_sigma Set.insert_sigma theorem sigma_insert {a : ∀ i, α i} : - (s.Sigma fun i ↦ insert (a i) (t i)) = (fun i ↦ ⟨i, a i⟩) '' s ∪ s.Sigma t := by + s.sigma (fun i ↦ insert (a i) (t i)) = (fun i ↦ ⟨i, a i⟩) '' s ∪ s.sigma t := by simp_rw [insert_eq, sigma_union, sigma_singleton] #align set.sigma_insert Set.sigma_insert theorem sigma_preimage_eq {f : ι' → ι} {g : ∀ i, β i → α i} : - ((f ⁻¹' s).Sigma fun i ↦ g (f i) ⁻¹' t (f i)) = - (fun p : Σi, β (f i) ↦ Sigma.mk _ (g _ p.2)) ⁻¹' s.Sigma t := - rfl + (f ⁻¹' s).sigma (fun i ↦ g (f i) ⁻¹' t (f i)) = + (fun p : Σ i, β (f i) ↦ Sigma.mk _ (g _ p.2)) ⁻¹' s.sigma t := rfl #align set.sigma_preimage_eq Set.sigma_preimage_eq theorem sigma_preimage_left {f : ι' → ι} : - ((f ⁻¹' s).Sigma fun i ↦ t (f i)) = (fun p : Σi, α (f i) ↦ Sigma.mk _ p.2) ⁻¹' s.Sigma t := + ((f ⁻¹' s).sigma fun i ↦ t (f i)) = (fun p : Σ i, α (f i) ↦ Sigma.mk _ p.2) ⁻¹' s.sigma t := rfl #align set.sigma_preimage_left Set.sigma_preimage_left theorem sigma_preimage_right {g : ∀ i, β i → α i} : - (s.Sigma fun i ↦ g i ⁻¹' t i) = (fun p : Σi, β i ↦ Sigma.mk p.1 (g _ p.2)) ⁻¹' s.Sigma t := + (s.sigma fun i ↦ g i ⁻¹' t i) = (fun p : Σ i, β i ↦ Sigma.mk p.1 (g _ p.2)) ⁻¹' s.sigma t := rfl #align set.sigma_preimage_right Set.sigma_preimage_right theorem preimage_sigmaMap_sigma {α' : ι' → Type*} (f : ι → ι') (g : ∀ i, α i → α' (f i)) (s : Set ι') (t : ∀ i, Set (α' i)) : - Sigma.map f g ⁻¹' s.Sigma t = (f ⁻¹' s).Sigma fun i ↦ g i ⁻¹' t (f i) := - rfl + Sigma.map f g ⁻¹' s.sigma t = (f ⁻¹' s).sigma fun i ↦ g i ⁻¹' t (f i) := rfl #align set.preimage_sigma_map_sigma Set.preimage_sigmaMap_sigma @[simp] -theorem mk_preimage_sigma (hi : i ∈ s) : Sigma.mk i ⁻¹' s.Sigma t = t i := +theorem mk_preimage_sigma (hi : i ∈ s) : Sigma.mk i ⁻¹' s.sigma t = t i := ext fun _ ↦ and_iff_right hi #align set.mk_preimage_sigma Set.mk_preimage_sigma @[simp] -theorem mk_preimage_sigma_eq_empty (hi : i ∉ s) : Sigma.mk i ⁻¹' s.Sigma t = ∅ := +theorem mk_preimage_sigma_eq_empty (hi : i ∉ s) : Sigma.mk i ⁻¹' s.sigma t = ∅ := ext fun _ ↦ iff_of_false (hi ∘ And.left) id #align set.mk_preimage_sigma_eq_empty Set.mk_preimage_sigma_eq_empty theorem mk_preimage_sigma_eq_if [DecidablePred (· ∈ s)] : - Sigma.mk i ⁻¹' s.Sigma t = if i ∈ s then t i else ∅ := by split_ifs <;> simp [*] + Sigma.mk i ⁻¹' s.sigma t = if i ∈ s then t i else ∅ := by split_ifs <;> simp [*] #align set.mk_preimage_sigma_eq_if Set.mk_preimage_sigma_eq_if theorem mk_preimage_sigma_fn_eq_if {β : Type*} [DecidablePred (· ∈ s)] (g : β → α i) : - (fun b ↦ Sigma.mk i (g b)) ⁻¹' s.Sigma t = if i ∈ s then g ⁻¹' t i else ∅ := + (fun b ↦ Sigma.mk i (g b)) ⁻¹' s.sigma t = if i ∈ s then g ⁻¹' t i else ∅ := ext fun _ ↦ by split_ifs <;> simp [*] #align set.mk_preimage_sigma_fn_eq_if Set.mk_preimage_sigma_fn_eq_if theorem sigma_univ_range_eq {f : ∀ i, α i → β i} : - ((univ : Set ι).Sigma fun i ↦ range (f i)) = range fun x : Σi, α i ↦ ⟨x.1, f _ x.2⟩ := + (univ : Set ι).sigma (fun i ↦ range (f i)) = range fun x : Σ i, α i ↦ ⟨x.1, f _ x.2⟩ := ext <| by simp [range] #align set.sigma_univ_range_eq Set.sigma_univ_range_eq protected theorem Nonempty.sigma : - s.Nonempty → (∀ i, (t i).Nonempty) → (s.Sigma t : Set _).Nonempty := fun ⟨i, hi⟩ h ↦ + s.Nonempty → (∀ i, (t i).Nonempty) → (s.sigma t).Nonempty := fun ⟨i, hi⟩ h ↦ let ⟨a, ha⟩ := h i ⟨⟨i, a⟩, hi, ha⟩ #align set.nonempty.sigma Set.Nonempty.sigma -theorem Nonempty.sigma_fst : (s.Sigma t : Set _).Nonempty → s.Nonempty := fun ⟨x, hx⟩ ↦ ⟨x.1, hx.1⟩ +theorem Nonempty.sigma_fst : (s.sigma t).Nonempty → s.Nonempty := fun ⟨x, hx⟩ ↦ ⟨x.1, hx.1⟩ #align set.nonempty.sigma_fst Set.Nonempty.sigma_fst -theorem Nonempty.sigma_snd : (s.Sigma t : Set _).Nonempty → ∃ i ∈ s, (t i).Nonempty := +theorem Nonempty.sigma_snd : (s.sigma t).Nonempty → ∃ i ∈ s, (t i).Nonempty := fun ⟨x, hx⟩ ↦ ⟨x.1, hx.1, x.2, hx.2⟩ #align set.nonempty.sigma_snd Set.Nonempty.sigma_snd -theorem sigma_nonempty_iff : (s.Sigma t : Set _).Nonempty ↔ ∃ i ∈ s, (t i).Nonempty := +theorem sigma_nonempty_iff : (s.sigma t).Nonempty ↔ ∃ i ∈ s, (t i).Nonempty := ⟨Nonempty.sigma_snd, fun ⟨i, hi, a, ha⟩ ↦ ⟨⟨i, a⟩, hi, ha⟩⟩ #align set.sigma_nonempty_iff Set.sigma_nonempty_iff -theorem sigma_eq_empty_iff : s.Sigma t = ∅ ↔ ∀ i ∈ s, t i = ∅ := +theorem sigma_eq_empty_iff : s.sigma t = ∅ ↔ ∀ i ∈ s, t i = ∅ := not_nonempty_iff_eq_empty.symm.trans <| sigma_nonempty_iff.not.trans <| by simp only [not_nonempty_iff_eq_empty, not_and, not_exists] #align set.sigma_eq_empty_iff Set.sigma_eq_empty_iff theorem image_sigmaMk_subset_sigma_left {a : ∀ i, α i} (ha : ∀ i, a i ∈ t i) : - (fun i ↦ Sigma.mk i (a i)) '' s ⊆ s.Sigma t := + (fun i ↦ Sigma.mk i (a i)) '' s ⊆ s.sigma t := image_subset_iff.2 fun _ hi ↦ ⟨hi, ha _⟩ #align set.image_sigma_mk_subset_sigma_left Set.image_sigmaMk_subset_sigma_left -theorem image_sigmaMk_subset_sigma_right (hi : i ∈ s) : Sigma.mk i '' t i ⊆ s.Sigma t := +theorem image_sigmaMk_subset_sigma_right (hi : i ∈ s) : Sigma.mk i '' t i ⊆ s.sigma t := image_subset_iff.2 fun _ ↦ And.intro hi #align set.image_sigma_mk_subset_sigma_right Set.image_sigmaMk_subset_sigma_right -theorem sigma_subset_preimage_fst (s : Set ι) (t : ∀ i, Set (α i)) : s.Sigma t ⊆ Sigma.fst ⁻¹' s := +theorem sigma_subset_preimage_fst (s : Set ι) (t : ∀ i, Set (α i)) : s.sigma t ⊆ Sigma.fst ⁻¹' s := fun _ ↦ And.left #align set.sigma_subset_preimage_fst Set.sigma_subset_preimage_fst -theorem fst_image_sigma_subset (s : Set ι) (t : ∀ i, Set (α i)) : Sigma.fst '' s.Sigma t ⊆ s := +theorem fst_image_sigma_subset (s : Set ι) (t : ∀ i, Set (α i)) : Sigma.fst '' s.sigma t ⊆ s := image_subset_iff.2 fun _ ↦ And.left #align set.fst_image_sigma_subset Set.fst_image_sigma_subset -theorem fst_image_sigma (s : Set ι) (ht : ∀ i, (t i).Nonempty) : Sigma.fst '' s.Sigma t = s := +theorem fst_image_sigma (s : Set ι) (ht : ∀ i, (t i).Nonempty) : Sigma.fst '' s.sigma t = s := (fst_image_sigma_subset _ _).antisymm fun i hi ↦ let ⟨a, ha⟩ := ht i ⟨⟨i, a⟩, ⟨hi, ha⟩, rfl⟩ #align set.fst_image_sigma Set.fst_image_sigma -theorem sigma_diff_sigma : s₁.Sigma t₁ \ s₂.Sigma t₂ = s₁.Sigma (t₁ \ t₂) ∪ (s₁ \ s₂).Sigma t₁ := +theorem sigma_diff_sigma : s₁.sigma t₁ \ s₂.sigma t₂ = s₁.sigma (t₁ \ t₂) ∪ (s₁ \ s₂).sigma t₁ := ext fun x ↦ by by_cases h₁ : x.1 ∈ s₁ <;> by_cases h₂ : x.2 ∈ t₁ x.1 <;> simp [*, ← imp_iff_or_not] #align set.sigma_diff_sigma Set.sigma_diff_sigma diff --git a/Mathlib/Data/Sym/Basic.lean b/Mathlib/Data/Sym/Basic.lean index 5d71bc1e08dae..97c8e68b0cafa 100644 --- a/Mathlib/Data/Sym/Basic.lean +++ b/Mathlib/Data/Sym/Basic.lean @@ -199,6 +199,7 @@ theorem cons_of_coe_eq (a : α) (v : Vector α n) : a ::ₛ (↑v : Sym α n) = rfl #align sym.cons_of_coe_eq Sym.cons_of_coe_eq +open scoped List in theorem sound {a b : Vector α n} (h : a.val ~ b.val) : (↑a : Sym α n) = ↑b := Subtype.ext <| Quotient.sound h #align sym.sound Sym.sound diff --git a/Mathlib/Data/ZMod/Factorial.lean b/Mathlib/Data/ZMod/Factorial.lean new file mode 100644 index 0000000000000..ddbe5b71ec460 --- /dev/null +++ b/Mathlib/Data/ZMod/Factorial.lean @@ -0,0 +1,42 @@ +/- +Copyright (c) 2023 Moritz Firsching. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Moritz Firsching +-/ +import Mathlib.Data.Nat.Factorial.BigOperators +import Mathlib.Data.ZMod.Basic + +/-! +# Facts about factorials in ZMod + +We collect facts about factorials in context of modular arithmetic. + +## Main statements + +* `ZMod.cast_descFactorial`: For natural numbers `n` and `p`, where `n` is less than or equal to `p` + the descending factorial of `(p - 1)` taken `n` times modulo `p` equals `(-1) ^ n * n!`. + +## See also + +For the prime case and involving `factorial` rather than `descFactorial`, see Wilson's theorem: +* Nat.prime_iff_fac_equiv_neg_one + +-/ + +open Finset Nat + +namespace ZMod + +theorem cast_descFactorial {n p : ℕ} (h : n ≤ p) : + (descFactorial (p - 1) n : ZMod p) = (-1) ^ n * n ! := by + rw [descFactorial_eq_prod_range, ← prod_range_add_one_eq_factorial] + simp only [cast_prod] + nth_rw 2 [← card_range n] + rw [pow_card_mul_prod] + refine prod_congr rfl ?_ + intro x hx + rw [← tsub_add_eq_tsub_tsub_swap, Nat.cast_sub <| Nat.lt_of_lt_of_le (List.mem_range.mp hx) h, + CharP.cast_eq_zero, zero_sub, cast_succ, neg_add_rev, mul_add, neg_mul, one_mul, + mul_one, add_comm] + +end ZMod diff --git a/Mathlib/Data/ZMod/Module.lean b/Mathlib/Data/ZMod/Module.lean new file mode 100644 index 0000000000000..e1aca3dac8582 --- /dev/null +++ b/Mathlib/Data/ZMod/Module.lean @@ -0,0 +1,44 @@ +/- +Copyright (c) 2023 Lawrence Wu. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Lawrence Wu +-/ +import Mathlib.Data.ZMod.Basic +import Mathlib.Algebra.Module.LinearMap + +/-! +# The `ZMod n`-module structure on Abelian groups whose elements have order dividing `n` +-/ + +variable {n : ℕ} {M M₁ : Type*} [AddCommGroup M] [AddCommGroup M₁] + [Module (ZMod n) M] [Module (ZMod n) M₁] + +namespace ZMod + +theorem map_smul (f : M →+ M₁) (c : ZMod n) (x : M) : f (c • x) = c • f x := by + cases n with + | zero => exact map_int_cast_smul f _ _ c x + | succ n => + induction c using Fin.induction with + | zero => simp_rw [zero_smul, map_zero] + | succ c hc => simp_rw [← Fin.coeSucc_eq_succ, add_smul, one_smul, f.map_add, hc] + +end ZMod + +namespace AddMonoidHom + +variable (n) + +/-- Reinterpret an additive homomorphism as a `ℤ/nℤ`-linear map. + +See also: +`AddMonoidHom.toIntLinearMap`, `AddMonoidHom.toNatLinearMap`, `AddMonoidHom.toRatLinearMap` -/ +def toZModLinearMap (f : M →+ M₁) : M →ₗ[ZMod n] M₁ := { f with map_smul' := ZMod.map_smul f } + +theorem toZModLinearMap_injective: Function.Injective <| toZModLinearMap n (M := M) (M₁ := M₁) := + fun _ _ h ↦ ext fun x ↦ congr($h x) + +@[simp] +theorem coe_toZModLinearMap (f : M →+ M₁) : ⇑(f.toZModLinearMap n) = f := rfl + +end AddMonoidHom diff --git a/Mathlib/Dynamics/FixedPoints/Basic.lean b/Mathlib/Dynamics/FixedPoints/Basic.lean index b6005a9005b9c..8c9861ba9836c 100644 --- a/Mathlib/Dynamics/FixedPoints/Basic.lean +++ b/Mathlib/Dynamics/FixedPoints/Basic.lean @@ -100,6 +100,10 @@ theorem preimage_iterate {s : Set α} (h : IsFixedPt (Set.preimage f) s) (n : exact h.iterate n #align function.is_fixed_pt.preimage_iterate Function.IsFixedPt.preimage_iterate +lemma image_iterate {s : Set α} (h : IsFixedPt (Set.image f) s) (n : ℕ) : + IsFixedPt (Set.image f^[n]) s := + Set.image_iterate_eq ▸ h.iterate n + protected theorem equiv_symm (h : IsFixedPt e x) : IsFixedPt e.symm x := h.to_leftInverse e.leftInverse_symm #align function.is_fixed_pt.equiv_symm Function.IsFixedPt.equiv_symm diff --git a/Mathlib/FieldTheory/Adjoin.lean b/Mathlib/FieldTheory/Adjoin.lean index ceb68f0d6d7ed..304f4cbfc7be9 100644 --- a/Mathlib/FieldTheory/Adjoin.lean +++ b/Mathlib/FieldTheory/Adjoin.lean @@ -848,14 +848,20 @@ theorem finrank_eq_one_iff : finrank F K = 1 ↔ K = ⊥ := by bot_toSubalgebra] #align intermediate_field.finrank_eq_one_iff IntermediateField.finrank_eq_one_iff -@[simp] +@[simp] protected theorem rank_bot : Module.rank F (⊥ : IntermediateField F E) = 1 := by rw [rank_eq_one_iff] #align intermediate_field.rank_bot IntermediateField.rank_bot -@[simp] +@[simp] protected theorem finrank_bot : finrank F (⊥ : IntermediateField F E) = 1 := by rw [finrank_eq_one_iff] #align intermediate_field.finrank_bot IntermediateField.finrank_bot +@[simp] protected theorem rank_top : Module.rank (⊤ : IntermediateField F E) E = 1 := + Subalgebra.bot_eq_top_iff_rank_eq_one.mp <| top_le_iff.mp fun x _ ↦ ⟨⟨x, trivial⟩, rfl⟩ + +@[simp] protected theorem finrank_top : finrank (⊤ : IntermediateField F E) E = 1 := + rank_eq_one_iff_finrank_eq_one.mp IntermediateField.rank_top + theorem rank_adjoin_eq_one_iff : Module.rank F (adjoin F S) = 1 ↔ S ⊆ (⊥ : IntermediateField F E) := Iff.trans rank_eq_one_iff adjoin_eq_bot_iff #align intermediate_field.rank_adjoin_eq_one_iff IntermediateField.rank_adjoin_eq_one_iff @@ -1296,6 +1302,25 @@ end AlgHomMkAdjoinSplits end IntermediateField +section Algebra.IsAlgebraic + +/-- Let `K/F` be an algebraic extension of fields and `L` a field in which all the minimal +polynomial over `F` of elements of `K` splits. Then, for `x ∈ K`, the images of `x` by the +`F`-algebra morphisms from `K` to `L` are exactly the roots in `L` of the minimal polynomial +of `x` over `F`. -/ +theorem Algebra.IsAlgebraic.range_eval_eq_rootSet_minpoly_of_splits {F K : Type*} (L : Type*) + [Field F] [Field K] [Field L] [Algebra F L] [Algebra F K] + (hA : ∀ x : K, (minpoly F x).Splits (algebraMap F L)) + (hK : Algebra.IsAlgebraic F K) (x : K) : + (Set.range fun (ψ : K →ₐ[F] L) => ψ x) = (minpoly F x).rootSet L := by + ext a + rw [mem_rootSet_of_ne (minpoly.ne_zero (hK.isIntegral x))] + refine ⟨fun ⟨ψ, hψ⟩ ↦ ?_, fun ha ↦ IntermediateField.exists_algHom_of_splits_of_aeval + (fun x ↦ ⟨hK.isIntegral x, hA x⟩) ha⟩ + rw [← hψ, Polynomial.aeval_algHom_apply ψ x, minpoly.aeval, map_zero] + +end Algebra.IsAlgebraic + section PowerBasis variable {K L : Type*} [Field K] [Field L] [Algebra K L] diff --git a/Mathlib/FieldTheory/IsAlgClosed/Basic.lean b/Mathlib/FieldTheory/IsAlgClosed/Basic.lean index f68d33f25ec35..69dee05f8dff5 100644 --- a/Mathlib/FieldTheory/IsAlgClosed/Basic.lean +++ b/Mathlib/FieldTheory/IsAlgClosed/Basic.lean @@ -396,15 +396,49 @@ end EquivOfEquiv end IsAlgClosure +section Algebra.IsAlgebraic + +variable {F K : Type*} (A : Type*) [Field F] [Field K] [Field A] [Algebra F K] [Algebra F A] + (hK : Algebra.IsAlgebraic F K) + /-- Let `A` be an algebraically closed field and let `x ∈ K`, with `K/F` an algebraic extension of fields. Then the images of `x` by the `F`-algebra morphisms from `K` to `A` are exactly the roots in `A` of the minimal polynomial of `x` over `F`. -/ -theorem Algebra.IsAlgebraic.range_eval_eq_rootSet_minpoly {F K} (A) [Field F] [Field K] [Field A] - [IsAlgClosed A] [Algebra F K] (hK : Algebra.IsAlgebraic F K) [Algebra F A] (x : K) : - (Set.range fun ψ : K →ₐ[F] A ↦ ψ x) = (minpoly F x).rootSet A := by - ext a - rw [mem_rootSet_of_ne (minpoly.ne_zero (hK.isIntegral x))] - refine ⟨fun ⟨ψ, hψ⟩ ↦ ?_, fun ha ↦ IntermediateField.exists_algHom_of_splits_of_aeval - (fun x ↦ ⟨hK.isIntegral x, IsAlgClosed.splits_codomain _⟩) ha⟩ - rw [← hψ, aeval_algHom_apply ψ x, minpoly.aeval, map_zero] +theorem Algebra.IsAlgebraic.range_eval_eq_rootSet_minpoly [IsAlgClosed A] (x : K) : + (Set.range fun ψ : K →ₐ[F] A ↦ ψ x) = (minpoly F x).rootSet A := + range_eval_eq_rootSet_minpoly_of_splits A (fun _ ↦ IsAlgClosed.splits_codomain _) hK x #align algebra.is_algebraic.range_eval_eq_root_set_minpoly Algebra.IsAlgebraic.range_eval_eq_rootSet_minpoly + +/-- All `F`-embeddings of a field `K` into another field `A` factor through any intermediate +field of `A/F` in which the minimal polynomial of elements of `K` splits. -/ +@[simps] +def IntermediateField.algHomEquivAlgHomOfSplits (L : IntermediateField F A) + (hL : ∀ x : K, (minpoly F x).Splits (algebraMap F L)) : + (K →ₐ[F] L) ≃ (K →ₐ[F] A) where + toFun := L.val.comp + invFun f := f.codRestrict _ fun x ↦ + ((hK x).isIntegral.map f).mem_intermediateField_of_minpoly_splits <| by + rw [minpoly.algHom_eq f f.injective]; exact hL x + left_inv _ := rfl + right_inv _ := by rfl + +theorem IntermediateField.algHomEquivAlgHomOfSplits_apply_apply (L : IntermediateField F A) + (hL : ∀ x : K, (minpoly F x).Splits (algebraMap F L)) (f : K →ₐ[F] L) (x : K) : + algHomEquivAlgHomOfSplits A hK L hL f x = algebraMap L A (f x) := rfl + +/-- All `F`-embeddings of a field `K` into another field `A` factor through any subextension +of `A/F` in which the minimal polynomial of elements of `K` splits. -/ +noncomputable def Algebra.IsAlgebraic.algHomEquivAlgHomOfSplits (L : Type*) [Field L] + [Algebra F L] [Algebra L A] [IsScalarTower F L A] + (hL : ∀ x : K, (minpoly F x).Splits (algebraMap F L)) : + (K →ₐ[F] L) ≃ (K →ₐ[F] A) := + (AlgEquiv.refl.arrowCongr (AlgEquiv.ofInjectiveField (IsScalarTower.toAlgHom F L A))).trans <| + IntermediateField.algHomEquivAlgHomOfSplits A hK (IsScalarTower.toAlgHom F L A).fieldRange + fun x ↦ splits_of_algHom (hL x) (AlgHom.rangeRestrict _) + +theorem Algebra.IsAlgebraic.algHomEquivAlgHomOfSplits_apply_apply (L : Type*) [Field L] + [Algebra F L] [Algebra L A] [IsScalarTower F L A] + (hL : ∀ x : K, (minpoly F x).Splits (algebraMap F L)) (f : K →ₐ[F] L) (x : K) : + Algebra.IsAlgebraic.algHomEquivAlgHomOfSplits A hK L hL f x = algebraMap L A (f x) := rfl + +end Algebra.IsAlgebraic diff --git a/Mathlib/FieldTheory/PolynomialGaloisGroup.lean b/Mathlib/FieldTheory/PolynomialGaloisGroup.lean index 4edacc70b512a..f1af3a3f238f2 100644 --- a/Mathlib/FieldTheory/PolynomialGaloisGroup.lean +++ b/Mathlib/FieldTheory/PolynomialGaloisGroup.lean @@ -432,6 +432,7 @@ theorem splits_ℚ_ℂ {p : ℚ[X]} : Fact (p.Splits (algebraMap ℚ ℂ)) := #align polynomial.gal.splits_ℚ_ℂ Polynomial.Gal.splits_ℚ_ℂ attribute [local instance] splits_ℚ_ℂ +attribute [local ext] Complex.ext /-- The number of complex roots equals the number of real roots plus the number of roots not fixed by complex conjugation (i.e. with some imaginary component). -/ diff --git a/Mathlib/FieldTheory/PrimitiveElement.lean b/Mathlib/FieldTheory/PrimitiveElement.lean index 9c8a64e76e75a..c0164c8f3f9f6 100644 --- a/Mathlib/FieldTheory/PrimitiveElement.lean +++ b/Mathlib/FieldTheory/PrimitiveElement.lean @@ -3,9 +3,8 @@ Copyright (c) 2020 Thomas Browning, Patrick Lutz. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Thomas Browning, Patrick Lutz -/ -import Mathlib.FieldTheory.SplittingField.Construction -import Mathlib.FieldTheory.IsAlgClosed.Basic -import Mathlib.FieldTheory.Separable +import Mathlib.FieldTheory.IsAlgClosed.AlgebraicClosure +import Mathlib.FieldTheory.NormalClosure import Mathlib.RingTheory.IntegralDomain #align_import field_theory.primitive_element from "leanprover-community/mathlib"@"df76f43357840485b9d04ed5dee5ab115d420e87" @@ -348,10 +347,65 @@ end FiniteIntermediateField end Field +variable (F E : Type*) [Field F] [Field E] [Algebra F E] [FiniteDimensional F E] [IsSeparable F E] + @[simp] -theorem AlgHom.card (F E K : Type*) [Field F] [Field E] [Field K] [IsAlgClosed K] [Algebra F E] - [FiniteDimensional F E] [IsSeparable F E] [Algebra F K] : +theorem AlgHom.card (K : Type*) [Field K] [IsAlgClosed K] [Algebra F K] : Fintype.card (E →ₐ[F] K) = finrank F E := by convert (AlgHom.card_of_powerBasis (L := K) (Field.powerBasisOfFiniteOfSeparable F E) (IsSeparable.separable _ _) (IsAlgClosed.splits_codomain _)).trans (PowerBasis.finrank _).symm #align alg_hom.card AlgHom.card + +@[simp] +theorem AlgHom.card_of_splits (L : Type*) [Field L] [Algebra F L] + (hL : ∀ x : E, (minpoly F x).Splits (algebraMap F L)) : + Fintype.card (E →ₐ[F] L) = finrank F E := by + rw [← Fintype.ofEquiv_card <| Algebra.IsAlgebraic.algHomEquivAlgHomOfSplits + (AlgebraicClosure L) (Algebra.IsAlgebraic.of_finite F E) _ hL] + convert AlgHom.card F E (AlgebraicClosure L) + +section iff + +namespace Field + +open FiniteDimensional IntermediateField Polynomial Algebra Set + +variable (F : Type*) {E : Type*} [Field F] [Field E] [Algebra F E] [FiniteDimensional F E] + +theorem primitive_element_iff_minpoly_natDegree_eq (α : E) : + F⟮α⟯ = ⊤ ↔ (minpoly F α).natDegree = finrank F E := by + rw [← adjoin.finrank (IsIntegral.of_finite F α), ← finrank_top F E] + refine ⟨fun h => ?_, fun h => eq_of_le_of_finrank_eq le_top h⟩ + exact congr_arg (fun K : IntermediateField F E => finrank F K) h + +theorem primitive_element_iff_minpoly_degree_eq (α : E) : + F⟮α⟯ = ⊤ ↔ (minpoly F α).degree = finrank F E := by + rw [degree_eq_iff_natDegree_eq, primitive_element_iff_minpoly_natDegree_eq] + exact minpoly.ne_zero_of_finite F α + +variable [IsSeparable F E] (A : Type*) [Field A] [Algebra F A] + (hA : ∀ x : E, (minpoly F x).Splits (algebraMap F A)) + +theorem primitive_element_iff_algHom_eq_of_eval' (α : E) : + F⟮α⟯ = ⊤ ↔ Function.Injective fun φ : E →ₐ[F] A ↦ φ α := by + classical + simp_rw [primitive_element_iff_minpoly_natDegree_eq, ← card_rootSet_eq_natDegree (K := A) + (IsSeparable.separable F α) (hA _), ← toFinset_card, + ← (Algebra.IsAlgebraic.of_finite F E).range_eval_eq_rootSet_minpoly_of_splits _ hA α, + ← AlgHom.card_of_splits F E A hA, Fintype.card, toFinset_range, Finset.card_image_iff, + Finset.coe_univ, ← injective_iff_injOn_univ] + +theorem primitive_element_iff_algHom_eq_of_eval (α : E) + (φ : E →ₐ[F] A) : F⟮α⟯ = ⊤ ↔ ∀ ψ : E →ₐ[F] A, φ α = ψ α → φ = ψ := by + refine ⟨fun h ψ hψ ↦ (Field.primitive_element_iff_algHom_eq_of_eval' F A hA α).mp h hψ, + fun h ↦ eq_of_le_of_finrank_eq' le_top ?_⟩ + letI : Algebra F⟮α⟯ A := (φ.comp F⟮α⟯.val).toAlgebra + haveI := isSeparable_tower_top_of_isSeparable F F⟮α⟯ E + rw [IntermediateField.finrank_top, ← AlgHom.card_of_splits _ _ A, Fintype.card_eq_one_iff] + · exact ⟨{ __ := φ, commutes' := fun _ ↦ rfl }, fun ψ ↦ AlgHom.restrictScalars_injective F <| + Eq.symm <| h _ (ψ.commutes <| AdjoinSimple.gen F α).symm⟩ + · exact fun x ↦ (IsIntegral.of_finite F x).minpoly_splits_tower_top (hA x) + +end Field + +end iff diff --git a/Mathlib/FieldTheory/SplittingField/IsSplittingField.lean b/Mathlib/FieldTheory/SplittingField/IsSplittingField.lean index 0b694fbbf230e..2ab079ec52db6 100644 --- a/Mathlib/FieldTheory/SplittingField/IsSplittingField.lean +++ b/Mathlib/FieldTheory/SplittingField/IsSplittingField.lean @@ -151,16 +151,16 @@ end IsSplittingField end Polynomial -namespace IntermediateField - open Polynomial -variable {K L} [Field K] [Field L] [Algebra K L] {p : K[X]} +variable {K L} [Field K] [Field L] [Algebra K L] {p : K[X]} {F : IntermediateField K L} -theorem splits_of_splits {F : IntermediateField K L} (h : p.Splits (algebraMap K L)) +theorem IntermediateField.splits_of_splits (h : p.Splits (algebraMap K L)) (hF : ∀ x ∈ p.rootSet L, x ∈ F) : p.Splits (algebraMap K F) := by simp_rw [← F.fieldRange_val, rootSet_def, Finset.mem_coe, Multiset.mem_toFinset] at hF exact splits_of_comp _ F.val.toRingHom h hF #align intermediate_field.splits_of_splits IntermediateField.splits_of_splits -end IntermediateField +theorem IsIntegral.mem_intermediateField_of_minpoly_splits {x : L} (int : IsIntegral K x) + {F : IntermediateField K L} (h : Splits (algebraMap K F) (minpoly K x)) : x ∈ F := by + rw [← F.fieldRange_val]; exact int.mem_range_algebraMap_of_minpoly_splits h diff --git a/Mathlib/Geometry/Euclidean/Circumcenter.lean b/Mathlib/Geometry/Euclidean/Circumcenter.lean index b4eee81965c78..d9363d59c78b4 100644 --- a/Mathlib/Geometry/Euclidean/Circumcenter.lean +++ b/Mathlib/Geometry/Euclidean/Circumcenter.lean @@ -619,7 +619,7 @@ def centroidWeightsWithCircumcenter {n : ℕ} (fs : Finset (Fin (n + 1))) : theorem sum_centroidWeightsWithCircumcenter {n : ℕ} {fs : Finset (Fin (n + 1))} (h : fs.Nonempty) : ∑ i, centroidWeightsWithCircumcenter fs i = 1 := by simp_rw [sum_pointsWithCircumcenter, centroidWeightsWithCircumcenter, add_zero, ← - fs.sum_centroidWeights_eq_one_of_nonempty ℝ h, Set.sum_indicator_subset _ fs.subset_univ] + fs.sum_centroidWeights_eq_one_of_nonempty ℝ h, ← sum_indicator_subset _ fs.subset_univ] rcongr #align affine.simplex.sum_centroid_weights_with_circumcenter Affine.Simplex.sum_centroidWeightsWithCircumcenter @@ -632,7 +632,7 @@ theorem centroid_eq_affineCombination_of_pointsWithCircumcenter {n : ℕ} (s : S simp_rw [centroid_def, affineCombination_apply, weightedVSubOfPoint_apply, sum_pointsWithCircumcenter, centroidWeightsWithCircumcenter, pointsWithCircumcenter_point, zero_smul, add_zero, centroidWeights, - Set.sum_indicator_subset_of_eq_zero (Function.const (Fin (n + 1)) (card fs : ℝ)⁻¹) + ← sum_indicator_subset_of_eq_zero (Function.const (Fin (n + 1)) (card fs : ℝ)⁻¹) (fun i wi => wi • (s.points i -ᵥ Classical.choice AddTorsor.nonempty)) fs.subset_univ fun _ => zero_smul ℝ _, Set.indicator_apply] diff --git a/Mathlib/Geometry/Manifold/ChartedSpace.lean b/Mathlib/Geometry/Manifold/ChartedSpace.lean index 64f744464d426..1a4ea83cb43ee 100644 --- a/Mathlib/Geometry/Manifold/ChartedSpace.lean +++ b/Mathlib/Geometry/Manifold/ChartedSpace.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ import Mathlib.Init.Align -import Mathlib.Topology.LocalHomeomorph +import Mathlib.Topology.PartialHomeomorph #align_import geometry.manifold.charted_space from "leanprover-community/mathlib"@"431589bce478b2229eba14b14a283250428217db" @@ -122,14 +122,14 @@ universe u variable {H : Type u} {H' : Type*} {M : Type*} {M' : Type*} {M'' : Type*} /- Notational shortcut for the composition of local homeomorphisms and local equivs, i.e., -`LocalHomeomorph.trans` and `LocalEquiv.trans`. +`PartialHomeomorph.trans` and `PartialEquiv.trans`. Note that, as is usual for equivs, the composition is from left to right, hence the direction of the arrow. -/ -scoped[Manifold] infixr:100 " ≫ₕ " => LocalHomeomorph.trans +scoped[Manifold] infixr:100 " ≫ₕ " => PartialHomeomorph.trans -scoped[Manifold] infixr:100 " ≫ " => LocalEquiv.trans +scoped[Manifold] infixr:100 " ≫ " => PartialEquiv.trans -open Set LocalHomeomorph Manifold -- Porting note: Added `Manifold` +open Set PartialHomeomorph Manifold -- Porting note: Added `Manifold` /-! ### Structure groupoids -/ @@ -164,21 +164,21 @@ We use primes in the structure names as we will reformulate them below (without /-- A structure groupoid is a set of local homeomorphisms of a topological space stable under composition and inverse. They appear in the definition of the smoothness class of a manifold. -/ structure StructureGroupoid (H : Type u) [TopologicalSpace H] where - members : Set (LocalHomeomorph H H) - trans' : ∀ e e' : LocalHomeomorph H H, e ∈ members → e' ∈ members → e ≫ₕ e' ∈ members - symm' : ∀ e : LocalHomeomorph H H, e ∈ members → e.symm ∈ members - id_mem' : LocalHomeomorph.refl H ∈ members - locality' : ∀ e : LocalHomeomorph H H, + members : Set (PartialHomeomorph H H) + trans' : ∀ e e' : PartialHomeomorph H H, e ∈ members → e' ∈ members → e ≫ₕ e' ∈ members + symm' : ∀ e : PartialHomeomorph H H, e ∈ members → e.symm ∈ members + id_mem' : PartialHomeomorph.refl H ∈ members + locality' : ∀ e : PartialHomeomorph H H, (∀ x ∈ e.source, ∃ s, IsOpen s ∧ x ∈ s ∧ e.restr s ∈ members) → e ∈ members - eq_on_source' : ∀ e e' : LocalHomeomorph H H, e ∈ members → e' ≈ e → e' ∈ members + eq_on_source' : ∀ e e' : PartialHomeomorph H H, e ∈ members → e' ≈ e → e' ∈ members #align structure_groupoid StructureGroupoid variable [TopologicalSpace H] -instance : Membership (LocalHomeomorph H H) (StructureGroupoid H) := - ⟨fun (e : LocalHomeomorph H H) (G : StructureGroupoid H) ↦ e ∈ G.members⟩ +instance : Membership (PartialHomeomorph H H) (StructureGroupoid H) := + ⟨fun (e : PartialHomeomorph H H) (G : StructureGroupoid H) ↦ e ∈ G.members⟩ -instance (H : Type u) [TopologicalSpace H] : SetLike (StructureGroupoid H) (LocalHomeomorph H H) +instance (H : Type u) [TopologicalSpace H] : SetLike (StructureGroupoid H) (PartialHomeomorph H H) where coe s := s.members coe_injective' N O h := by cases N; cases O; congr @@ -231,26 +231,26 @@ instance : InfSet (StructureGroupoid H) := intro e e' he he'e exact fun i hi => i.eq_on_source' e e' (he i hi) he'e)⟩ -theorem StructureGroupoid.trans (G : StructureGroupoid H) {e e' : LocalHomeomorph H H} (he : e ∈ G) - (he' : e' ∈ G) : e ≫ₕ e' ∈ G := +theorem StructureGroupoid.trans (G : StructureGroupoid H) {e e' : PartialHomeomorph H H} + (he : e ∈ G) (he' : e' ∈ G) : e ≫ₕ e' ∈ G := G.trans' e e' he he' #align structure_groupoid.trans StructureGroupoid.trans -theorem StructureGroupoid.symm (G : StructureGroupoid H) {e : LocalHomeomorph H H} (he : e ∈ G) : +theorem StructureGroupoid.symm (G : StructureGroupoid H) {e : PartialHomeomorph H H} (he : e ∈ G) : e.symm ∈ G := G.symm' e he #align structure_groupoid.symm StructureGroupoid.symm -theorem StructureGroupoid.id_mem (G : StructureGroupoid H) : LocalHomeomorph.refl H ∈ G := +theorem StructureGroupoid.id_mem (G : StructureGroupoid H) : PartialHomeomorph.refl H ∈ G := G.id_mem' #align structure_groupoid.id_mem StructureGroupoid.id_mem -theorem StructureGroupoid.locality (G : StructureGroupoid H) {e : LocalHomeomorph H H} +theorem StructureGroupoid.locality (G : StructureGroupoid H) {e : PartialHomeomorph H H} (h : ∀ x ∈ e.source, ∃ s, IsOpen s ∧ x ∈ s ∧ e.restr s ∈ G) : e ∈ G := G.locality' e h #align structure_groupoid.locality StructureGroupoid.locality -theorem StructureGroupoid.eq_on_source (G : StructureGroupoid H) {e e' : LocalHomeomorph H H} +theorem StructureGroupoid.eq_on_source (G : StructureGroupoid H) {e e' : PartialHomeomorph H H} (he : e ∈ G) (h : e' ≈ e) : e' ∈ G := G.eq_on_source' e e' he h #align structure_groupoid.eq_on_source StructureGroupoid.eq_on_source @@ -272,19 +272,19 @@ theorem StructureGroupoid.le_iff {G₁ G₂ : StructureGroupoid H} : G₁ ≤ G /-- The trivial groupoid, containing only the identity (and maps with empty source, as this is necessary from the definition). -/ def idGroupoid (H : Type u) [TopologicalSpace H] : StructureGroupoid H where - members := {LocalHomeomorph.refl H} ∪ { e : LocalHomeomorph H H | e.source = ∅ } + members := {PartialHomeomorph.refl H} ∪ { e : PartialHomeomorph H H | e.source = ∅ } trans' e e' he he' := by cases' he with he he · simpa only [mem_singleton_iff.1 he, refl_trans] · have : (e ≫ₕ e').source ⊆ e.source := sep_subset _ _ rw [he] at this - have : e ≫ₕ e' ∈ { e : LocalHomeomorph H H | e.source = ∅ } := eq_bot_iff.2 this + have : e ≫ₕ e' ∈ { e : PartialHomeomorph H H | e.source = ∅ } := eq_bot_iff.2 this exact (mem_union _ _ _).2 (Or.inr this) symm' e he := by cases' (mem_union _ _ _).1 he with E E · simp [mem_singleton_iff.mp E] · right - simpa only [e.toLocalEquiv.image_source_eq_target.symm, mfld_simps] using E + simpa only [e.toPartialEquiv.image_source_eq_target.symm, mfld_simps] using E id_mem' := mem_union_left _ rfl locality' e he := by cases' e.source.eq_empty_or_nonempty with h h @@ -297,12 +297,12 @@ def idGroupoid (H : Type u) [TopologicalSpace H] : StructureGroupoid H where rw [restr_source, open_s.interior_eq] exact ⟨hx, xs⟩ cases' hs with hs hs - · replace hs : LocalHomeomorph.restr e s = LocalHomeomorph.refl H + · replace hs : PartialHomeomorph.restr e s = PartialHomeomorph.refl H · simpa only using hs have : (e.restr s).source = univ := by rw [hs] simp - have : e.toLocalEquiv.source ∩ interior s = univ := this + have : e.toPartialEquiv.source ∩ interior s = univ := this have : univ ⊆ interior s := by rw [← this] exact inter_subset_right _ _ @@ -319,7 +319,7 @@ def idGroupoid (H : Type u) [TopologicalSpace H] : StructureGroupoid H where rw [Set.mem_singleton_iff.1 he] <;> rfl rwa [← this] · right - have he : e.toLocalEquiv.source = ∅ := he + have he : e.toPartialEquiv.source = ∅ := he rwa [Set.mem_setOf_eq, EqOnSource.source_eq he'e] #align id_groupoid idGroupoid @@ -328,7 +328,7 @@ instance instStructureGroupoidOrderBot : OrderBot (StructureGroupoid H) where bot := idGroupoid H bot_le := by intro u f hf - have hf : f ∈ {LocalHomeomorph.refl H} ∪ { e : LocalHomeomorph H H | e.source = ∅ } := hf + have hf : f ∈ {PartialHomeomorph.refl H} ∪ { e : PartialHomeomorph H H | e.source = ∅ } := hf simp only [singleton_union, mem_setOf_eq, mem_insert_iff] at hf cases' hf with hf hf · rw [hf] @@ -357,7 +357,7 @@ structure Pregroupoid (H : Type*) [TopologicalSpace H] where /-- Construct a groupoid of local homeos for which the map and its inverse have some property, from a pregroupoid asserting that this property is stable under composition. -/ def Pregroupoid.groupoid (PG : Pregroupoid H) : StructureGroupoid H where - members := { e : LocalHomeomorph H H | PG.property e e.source ∧ PG.property e.symm e.target } + members := { e : PartialHomeomorph H H | PG.property e e.source ∧ PG.property e.symm e.target } trans' e e' he he' := by constructor · apply PG.comp he.1 he'.1 e.open_source e'.open_source @@ -372,7 +372,7 @@ def Pregroupoid.groupoid (PG : Pregroupoid H) : StructureGroupoid H where rcases he x xu with ⟨s, s_open, xs, hs⟩ refine' ⟨s, s_open, xs, _⟩ convert hs.1 using 1 - dsimp [LocalHomeomorph.restr] + dsimp [PartialHomeomorph.restr] rw [s_open.interior_eq] · refine' PG.locality e.open_target fun x xu ↦ _ rcases he (e.symm x) (e.map_target xu) with ⟨s, s_open, xs, hs⟩ @@ -380,7 +380,7 @@ def Pregroupoid.groupoid (PG : Pregroupoid H) : StructureGroupoid H where · exact ContinuousOn.isOpen_inter_preimage e.continuousOn_invFun e.open_target s_open · rw [← inter_assoc, inter_self] convert hs.2 using 1 - dsimp [LocalHomeomorph.restr] + dsimp [PartialHomeomorph.restr] rw [s_open.interior_eq] eq_on_source' e e' he ee' := by constructor @@ -392,11 +392,11 @@ def Pregroupoid.groupoid (PG : Pregroupoid H) : StructureGroupoid H where -- convert he.2 -- rw [A.1] -- rfl - rw [A.1, symm_toLocalEquiv, LocalEquiv.symm_source] + rw [A.1, symm_toPartialEquiv, PartialEquiv.symm_source] exact he.2 #align pregroupoid.groupoid Pregroupoid.groupoid -theorem mem_groupoid_of_pregroupoid {PG : Pregroupoid H} {e : LocalHomeomorph H H} : +theorem mem_groupoid_of_pregroupoid {PG : Pregroupoid H} {e : PartialHomeomorph H H} : e ∈ PG.groupoid ↔ PG.property e e.source ∧ PG.property e.symm e.target := Iff.rfl #align mem_groupoid_of_pregroupoid mem_groupoid_of_pregroupoid @@ -408,7 +408,7 @@ theorem groupoid_of_pregroupoid_le (PG₁ PG₂ : Pregroupoid H) exact ⟨h _ _ he.1, h _ _ he.2⟩ #align groupoid_of_pregroupoid_le groupoid_of_pregroupoid_le -theorem mem_pregroupoid_of_eq_on_source (PG : Pregroupoid H) {e e' : LocalHomeomorph H H} +theorem mem_pregroupoid_of_eq_on_source (PG : Pregroupoid H) {e e' : PartialHomeomorph H H} (he' : e ≈ e') (he : PG.property e e.source) : PG.property e' e'.source := by rw [← he'.1] exact PG.congr e.open_source he'.eqOn.symm he @@ -458,28 +458,28 @@ instance : CompleteLattice (StructureGroupoid H) := homeomorphisms to open subsets of the source. -/ class ClosedUnderRestriction (G : StructureGroupoid H) : Prop where closedUnderRestriction : - ∀ {e : LocalHomeomorph H H}, e ∈ G → ∀ s : Set H, IsOpen s → e.restr s ∈ G + ∀ {e : PartialHomeomorph H H}, e ∈ G → ∀ s : Set H, IsOpen s → e.restr s ∈ G #align closed_under_restriction ClosedUnderRestriction theorem closedUnderRestriction' {G : StructureGroupoid H} [ClosedUnderRestriction G] - {e : LocalHomeomorph H H} (he : e ∈ G) {s : Set H} (hs : IsOpen s) : e.restr s ∈ G := + {e : PartialHomeomorph H H} (he : e ∈ G) {s : Set H} (hs : IsOpen s) : e.restr s ∈ G := ClosedUnderRestriction.closedUnderRestriction he s hs #align closed_under_restriction' closedUnderRestriction' /-- The trivial restriction-closed groupoid, containing only local homeomorphisms equivalent to the restriction of the identity to the various open subsets. -/ def idRestrGroupoid : StructureGroupoid H where - members := { e | ∃ (s : Set H) (h : IsOpen s), e ≈ LocalHomeomorph.ofSet s h } + members := { e | ∃ (s : Set H) (h : IsOpen s), e ≈ PartialHomeomorph.ofSet s h } trans' := by rintro e e' ⟨s, hs, hse⟩ ⟨s', hs', hse'⟩ refine' ⟨s ∩ s', IsOpen.inter hs hs', _⟩ - have := LocalHomeomorph.EqOnSource.trans' hse hse' - rwa [LocalHomeomorph.ofSet_trans_ofSet] at this + have := PartialHomeomorph.EqOnSource.trans' hse hse' + rwa [PartialHomeomorph.ofSet_trans_ofSet] at this symm' := by rintro e ⟨s, hs, hse⟩ refine' ⟨s, hs, _⟩ rw [← ofSet_symm] - exact LocalHomeomorph.EqOnSource.symm' hse + exact PartialHomeomorph.EqOnSource.symm' hse id_mem' := ⟨univ, isOpen_univ, by simp only [mfld_simps, refl]⟩ locality' := by intro e h @@ -491,7 +491,7 @@ def idRestrGroupoid : StructureGroupoid H where refine' ⟨hx, _⟩ rw [hs.interior_eq] exact hxs - simpa only [mfld_simps] using LocalHomeomorph.EqOnSource.eqOn hes' hes + simpa only [mfld_simps] using PartialHomeomorph.EqOnSource.eqOn hes' hes eq_on_source' := by rintro e e' ⟨s, hs, hse⟩ hee' exact ⟨s, hs, Setoid.trans hee' hse⟩ @@ -506,7 +506,7 @@ instance closedUnderRestriction_idRestrGroupoid : ClosedUnderRestriction (@idRes ⟨by rintro e ⟨s', hs', he⟩ s hs use s' ∩ s, IsOpen.inter hs' hs - refine' Setoid.trans (LocalHomeomorph.EqOnSource.restr he s) _ + refine' Setoid.trans (PartialHomeomorph.EqOnSource.restr he s) _ exact ⟨by simp only [hs.interior_eq, mfld_simps], by simp only [mfld_simps, eqOn_refl]⟩⟩ #align closed_under_restriction_id_restr_groupoid closedUnderRestriction_idRestrGroupoid @@ -525,13 +525,13 @@ theorem closedUnderRestriction_iff_id_le (G : StructureGroupoid H) : -- rw [hs.interior_eq] -- simp only [mfld_simps] ext - · rw [LocalHomeomorph.restr_apply, LocalHomeomorph.refl_apply, id, ofSet_apply, id_eq] + · rw [PartialHomeomorph.restr_apply, PartialHomeomorph.refl_apply, id, ofSet_apply, id_eq] · simp [hs] · simp [hs.interior_eq] · intro h constructor intro e he s hs - rw [← ofSet_trans (e : LocalHomeomorph H H) hs] + rw [← ofSet_trans (e : PartialHomeomorph H H) hs] refine' G.trans _ he apply StructureGroupoid.le_iff.mp h exact idRestrGroupoid_mem hs @@ -558,18 +558,18 @@ sometimes as a real manifold over `ℝ^(2n)`. -/ @[ext] class ChartedSpace (H : Type*) [TopologicalSpace H] (M : Type*) [TopologicalSpace M] where - protected atlas : Set (LocalHomeomorph M H) - protected chartAt : M → LocalHomeomorph M H + protected atlas : Set (PartialHomeomorph M H) + protected chartAt : M → PartialHomeomorph M H protected mem_chart_source : ∀ x, x ∈ (chartAt x).source protected chart_mem_atlas : ∀ x, chartAt x ∈ atlas #align charted_space ChartedSpace abbrev atlas (H : Type*) [TopologicalSpace H] (M : Type*) [TopologicalSpace M] - [ChartedSpace H M] : Set (LocalHomeomorph M H) := + [ChartedSpace H M] : Set (PartialHomeomorph M H) := ChartedSpace.atlas abbrev chartAt (H : Type*) [TopologicalSpace H] {M : Type*} [TopologicalSpace M] - [ChartedSpace H M] (x : M) : LocalHomeomorph M H := + [ChartedSpace H M] (x : M) : PartialHomeomorph M H := ChartedSpace.chartAt x @[simp, mfld_simps] @@ -586,8 +586,8 @@ section ChartedSpace /-- Any space is a `ChartedSpace` modelled over itself, by just using the identity chart. -/ instance chartedSpaceSelf (H : Type*) [TopologicalSpace H] : ChartedSpace H H where - atlas := {LocalHomeomorph.refl H} - chartAt _ := LocalHomeomorph.refl H + atlas := {PartialHomeomorph.refl H} + chartAt _ := PartialHomeomorph.refl H mem_chart_source x := mem_univ x chart_mem_atlas _ := mem_singleton _ #align charted_space_self chartedSpaceSelf @@ -595,14 +595,14 @@ instance chartedSpaceSelf (H : Type*) [TopologicalSpace H] : ChartedSpace H H wh /-- In the trivial `ChartedSpace` structure of a space modelled over itself through the identity, the atlas members are just the identity. -/ @[simp, mfld_simps] -theorem chartedSpaceSelf_atlas {H : Type*} [TopologicalSpace H] {e : LocalHomeomorph H H} : - e ∈ atlas H H ↔ e = LocalHomeomorph.refl H := +theorem chartedSpaceSelf_atlas {H : Type*} [TopologicalSpace H] {e : PartialHomeomorph H H} : + e ∈ atlas H H ↔ e = PartialHomeomorph.refl H := Iff.rfl #align charted_space_self_atlas chartedSpaceSelf_atlas /-- In the model space, `chartAt` is always the identity. -/ theorem chartAt_self_eq {H : Type*} [TopologicalSpace H] {x : H} : - chartAt H x = LocalHomeomorph.refl H := rfl + chartAt H x = PartialHomeomorph.refl H := rfl #align chart_at_self_eq chartAt_self_eq section @@ -633,7 +633,7 @@ theorem achart_def (x : M) : achart H x = ⟨chartAt H x, chart_mem_atlas H x⟩ #align achart_def achart_def @[simp, mfld_simps] -theorem coe_achart (x : M) : (achart H x : LocalHomeomorph M H) = chartAt H x := +theorem coe_achart (x : M) : (achart H x : PartialHomeomorph M H) = chartAt H x := rfl #align coe_achart coe_achart @@ -684,11 +684,11 @@ theorem ChartedSpace.locallyCompactSpace [LocallyCompactSpace H] : LocallyCompac /-- If a topological space admits an atlas with locally connected charts, then the space itself is locally connected. -/ theorem ChartedSpace.locallyConnectedSpace [LocallyConnectedSpace H] : LocallyConnectedSpace M := by - let e : M → LocalHomeomorph M H := chartAt H + let e : M → PartialHomeomorph M H := chartAt H refine' locallyConnectedSpace_of_connected_bases (fun x s ↦ (e x).symm '' s) (fun x s ↦ (IsOpen s ∧ e x x ∈ s ∧ IsConnected s) ∧ s ⊆ (e x).target) _ _ · intro x - simpa only [LocalHomeomorph.symm_map_nhds_eq, mem_chart_source] using + simpa only [PartialHomeomorph.symm_map_nhds_eq, mem_chart_source] using ((LocallyConnectedSpace.open_connected_basis (e x x)).restrict_subset ((e x).open_target.mem_nhds (mem_chart_target H x))).map (e x).symm · rintro x s ⟨⟨-, -, hsconn⟩, hssubset⟩ @@ -700,7 +700,7 @@ modelled on `H`. -/ def ChartedSpace.comp (H : Type*) [TopologicalSpace H] (H' : Type*) [TopologicalSpace H'] (M : Type*) [TopologicalSpace M] [ChartedSpace H H'] [ChartedSpace H' M] : ChartedSpace H M where - atlas := image2 LocalHomeomorph.trans (atlas H' M) (atlas H H') + atlas := image2 PartialHomeomorph.trans (atlas H' M) (atlas H H') chartAt p := (chartAt H' p).trans (chartAt H (chartAt H' p p)) mem_chart_source p := by simp only [mfld_simps] chart_mem_atlas p := ⟨chartAt _ p, chartAt _ _, chart_mem_atlas _ p, chart_mem_atlas _ _, rfl⟩ @@ -783,7 +783,7 @@ construction of the atlas of product maps. -/ instance prodChartedSpace (H : Type*) [TopologicalSpace H] (M : Type*) [TopologicalSpace M] [ChartedSpace H M] (H' : Type*) [TopologicalSpace H'] (M' : Type*) [TopologicalSpace M'] [ChartedSpace H' M'] : ChartedSpace (ModelProd H H') (M × M') where - atlas := image2 LocalHomeomorph.prod (atlas H M) (atlas H' M') + atlas := image2 PartialHomeomorph.prod (atlas H M) (atlas H' M') chartAt x := (chartAt H x.1).prod (chartAt H' x.2) mem_chart_source x := ⟨mem_chart_source H x.1, mem_chart_source H' x.2⟩ chart_mem_atlas x := mem_image2_of_mem (chart_mem_atlas H x.1) (chart_mem_atlas H' x.2) @@ -819,8 +819,8 @@ canonical construction of the atlas of finite product maps. -/ instance piChartedSpace {ι : Type*} [Fintype ι] (H : ι → Type*) [∀ i, TopologicalSpace (H i)] (M : ι → Type*) [∀ i, TopologicalSpace (M i)] [∀ i, ChartedSpace (H i) (M i)] : ChartedSpace (ModelPi H) (∀ i, M i) where - atlas := LocalHomeomorph.pi '' Set.pi univ fun _ ↦ atlas (H _) (M _) - chartAt f := LocalHomeomorph.pi fun i ↦ chartAt (H i) (f i) + atlas := PartialHomeomorph.pi '' Set.pi univ fun _ ↦ atlas (H _) (M _) + chartAt f := PartialHomeomorph.pi fun i ↦ chartAt (H i) (f i) mem_chart_source f i _ := mem_chart_source (H i) (f i) chart_mem_atlas f := mem_image_of_mem _ fun i _ ↦ chart_mem_atlas (H i) (f i) #align pi_charted_space piChartedSpace @@ -829,7 +829,7 @@ instance piChartedSpace {ι : Type*} [Fintype ι] (H : ι → Type*) [∀ i, Top theorem piChartedSpace_chartAt {ι : Type*} [Fintype ι] (H : ι → Type*) [∀ i, TopologicalSpace (H i)] (M : ι → Type*) [∀ i, TopologicalSpace (M i)] [∀ i, ChartedSpace (H i) (M i)] (f : ∀ i, M i) : - chartAt (H := ModelPi H) f = LocalHomeomorph.pi fun i ↦ chartAt (H i) (f i) := + chartAt (H := ModelPi H) f = PartialHomeomorph.pi fun i ↦ chartAt (H i) (f i) := rfl #align pi_charted_space_chart_at piChartedSpace_chartAt @@ -844,23 +844,23 @@ charts that are only local equivs, and continuity properties for their compositi This is formalised in `ChartedSpaceCore`. -/ -- @[nolint has_nonempty_instance] -- Porting note: commented out structure ChartedSpaceCore (H : Type*) [TopologicalSpace H] (M : Type*) where - atlas : Set (LocalEquiv M H) - chartAt : M → LocalEquiv M H + atlas : Set (PartialEquiv M H) + chartAt : M → PartialEquiv M H mem_chart_source : ∀ x, x ∈ (chartAt x).source chart_mem_atlas : ∀ x, chartAt x ∈ atlas - open_source : ∀ e e' : LocalEquiv M H, e ∈ atlas → e' ∈ atlas → IsOpen (e.symm.trans e').source - continuousOn_toFun : ∀ e e' : LocalEquiv M H, e ∈ atlas → e' ∈ atlas → + open_source : ∀ e e' : PartialEquiv M H, e ∈ atlas → e' ∈ atlas → IsOpen (e.symm.trans e').source + continuousOn_toFun : ∀ e e' : PartialEquiv M H, e ∈ atlas → e' ∈ atlas → ContinuousOn (e.symm.trans e') (e.symm.trans e').source #align charted_space_core ChartedSpaceCore namespace ChartedSpaceCore -variable [TopologicalSpace H] (c : ChartedSpaceCore H M) {e : LocalEquiv M H} +variable [TopologicalSpace H] (c : ChartedSpaceCore H M) {e : PartialEquiv M H} /-- Topology generated by a set of charts on a Type. -/ protected def toTopologicalSpace : TopologicalSpace M := TopologicalSpace.generateFrom <| - ⋃ (e : LocalEquiv M H) (_ : e ∈ c.atlas) (s : Set H) (_ : IsOpen s), + ⋃ (e : PartialEquiv M H) (_ : e ∈ c.atlas) (s : Set H) (_ : IsOpen s), {e ⁻¹' s ∩ e.source} #align charted_space_core.to_topological_space ChartedSpaceCore.toTopologicalSpace @@ -874,15 +874,15 @@ theorem open_source' (he : e ∈ c.atlas) : IsOpen[c.toTopologicalSpace] e.sourc theorem open_target (he : e ∈ c.atlas) : IsOpen e.target := by have E : e.target ∩ e.symm ⁻¹' e.source = e.target := Subset.antisymm (inter_subset_left _ _) fun x hx ↦ - ⟨hx, LocalEquiv.target_subset_preimage_source _ hx⟩ - simpa [LocalEquiv.trans_source, E] using c.open_source e e he he + ⟨hx, PartialEquiv.target_subset_preimage_source _ hx⟩ + simpa [PartialEquiv.trans_source, E] using c.open_source e e he he #align charted_space_core.open_target ChartedSpaceCore.open_target /-- An element of the atlas in a charted space without topology becomes a local homeomorphism for the topology constructed from this atlas. The `localHomeomorph` version is given in this definition. -/ -protected def localHomeomorph (e : LocalEquiv M H) (he : e ∈ c.atlas) : - @LocalHomeomorph M H c.toTopologicalSpace _ := +protected def localHomeomorph (e : PartialEquiv M H) (he : e ∈ c.atlas) : + @PartialHomeomorph M H c.toTopologicalSpace _ := { c.toTopologicalSpace, e with open_source := by convert c.open_source' he open_target := by convert c.open_target he @@ -910,14 +910,14 @@ protected def localHomeomorph (e : LocalEquiv M H) (he : e ∈ c.atlas) : rw [← inter_assoc, ← inter_assoc] congr 1 exact inter_comm _ _ - simpa [LocalEquiv.trans_source, preimage_inter, preimage_comp.symm, A] using this } + simpa [PartialEquiv.trans_source, preimage_inter, preimage_comp.symm, A] using this } #align charted_space_core.local_homeomorph ChartedSpaceCore.localHomeomorph /-- Given a charted space without topology, endow it with a genuine charted space structure with respect to the topology constructed from the atlas. -/ def toChartedSpace : @ChartedSpace H _ M c.toTopologicalSpace := { c.toTopologicalSpace with - atlas := ⋃ (e : LocalEquiv M H) (he : e ∈ c.atlas), {c.localHomeomorph e he} + atlas := ⋃ (e : PartialEquiv M H) (he : e ∈ c.atlas), {c.localHomeomorph e he} chartAt := fun x ↦ c.localHomeomorph (c.chartAt x) (c.chart_mem_atlas x) mem_chart_source := fun x ↦ c.mem_chart_source x chart_mem_atlas := fun x ↦ by @@ -938,7 +938,7 @@ variable [TopologicalSpace H] [TopologicalSpace M] [ChartedSpace H M] groupoid. -/ class HasGroupoid {H : Type*} [TopologicalSpace H] (M : Type*) [TopologicalSpace M] [ChartedSpace H M] (G : StructureGroupoid H) : Prop where - compatible : ∀ {e e' : LocalHomeomorph M H}, e ∈ atlas H M → e' ∈ atlas H M → e.symm ≫ₕ e' ∈ G + compatible : ∀ {e e' : PartialHomeomorph M H}, e ∈ atlas H M → e' ∈ atlas H M → e.symm ≫ₕ e' ∈ G #align has_groupoid HasGroupoid /-- Reformulate in the `StructureGroupoid` namespace the compatibility condition of charts in a @@ -946,7 +946,7 @@ charted space admitting a structure groupoid, to make it more easily accessible notation. -/ theorem StructureGroupoid.compatible {H : Type*} [TopologicalSpace H] (G : StructureGroupoid H) {M : Type*} [TopologicalSpace M] [ChartedSpace H M] [HasGroupoid M G] - {e e' : LocalHomeomorph M H} (he : e ∈ atlas H M) (he' : e' ∈ atlas H M) : e.symm ≫ₕ e' ∈ G := + {e e' : PartialHomeomorph M H} (he : e ∈ atlas H M) (he' : e' ∈ atlas H M) : e.symm ≫ₕ e' ∈ G := HasGroupoid.compatible he he' #align structure_groupoid.compatible StructureGroupoid.compatible @@ -960,7 +960,7 @@ theorem hasGroupoid_inf_iff {G₁ G₂ : StructureGroupoid H} : HasGroupoid M (G ⟨(fun h ↦ ⟨hasGroupoid_of_le h inf_le_left, hasGroupoid_of_le h inf_le_right⟩), fun ⟨h1, h2⟩ ↦ { compatible := fun he he' ↦ ⟨h1.compatible he he', h2.compatible he he'⟩ }⟩ -theorem hasGroupoid_of_pregroupoid (PG : Pregroupoid H) (h : ∀ {e e' : LocalHomeomorph M H}, +theorem hasGroupoid_of_pregroupoid (PG : Pregroupoid H) (h : ∀ {e e' : PartialHomeomorph M H}, e ∈ atlas H M → e' ∈ atlas H M → PG.property (e.symm ≫ₕ e') (e.symm ≫ₕ e').source) : HasGroupoid M PG.groupoid := ⟨fun he he' ↦ mem_groupoid_of_pregroupoid.mpr ⟨h he he', h he' he⟩⟩ @@ -988,7 +988,7 @@ variable (M) (G : StructureGroupoid H) /-- Given a charted space admitting a structure groupoid, the maximal atlas associated to this structure groupoid is the set of all local charts that are compatible with the atlas, i.e., such that changing coordinates with an atlas member gives an element of the groupoid. -/ -def StructureGroupoid.maximalAtlas : Set (LocalHomeomorph M H) := +def StructureGroupoid.maximalAtlas : Set (PartialHomeomorph M H) := { e | ∀ e' ∈ atlas H M, e.symm ≫ₕ e' ∈ G ∧ e'.symm ≫ₕ e ∈ G } #align structure_groupoid.maximal_atlas StructureGroupoid.maximalAtlas @@ -1006,14 +1006,14 @@ theorem StructureGroupoid.chart_mem_maximalAtlas [HasGroupoid M G] (x : M) : variable {G} -theorem mem_maximalAtlas_iff {e : LocalHomeomorph M H} : +theorem mem_maximalAtlas_iff {e : PartialHomeomorph M H} : e ∈ G.maximalAtlas M ↔ ∀ e' ∈ atlas H M, e.symm ≫ₕ e' ∈ G ∧ e'.symm ≫ₕ e ∈ G := Iff.rfl #align mem_maximal_atlas_iff mem_maximalAtlas_iff /-- Changing coordinates between two elements of the maximal atlas gives rise to an element of the structure groupoid. -/ -theorem StructureGroupoid.compatible_of_mem_maximalAtlas {e e' : LocalHomeomorph M H} +theorem StructureGroupoid.compatible_of_mem_maximalAtlas {e e' : PartialHomeomorph M H} (he : e ∈ G.maximalAtlas M) (he' : e' ∈ G.maximalAtlas M) : e.symm ≫ₕ e' ∈ G := by refine' G.locality fun x hx ↦ _ set f := chartAt (H := H) (e.symm x) @@ -1040,14 +1040,14 @@ theorem StructureGroupoid.compatible_of_mem_maximalAtlas {e e' : LocalHomeomorph variable (G) /-- In the model space, the identity is in any maximal atlas. -/ -theorem StructureGroupoid.id_mem_maximalAtlas : LocalHomeomorph.refl H ∈ G.maximalAtlas H := +theorem StructureGroupoid.id_mem_maximalAtlas : PartialHomeomorph.refl H ∈ G.maximalAtlas H := G.subset_maximalAtlas <| by simp #align structure_groupoid.id_mem_maximal_atlas StructureGroupoid.id_mem_maximalAtlas /-- In the model space, any element of the groupoid is in the maximal atlas. -/ -theorem StructureGroupoid.mem_maximalAtlas_of_mem_groupoid {f : LocalHomeomorph H H} (hf : f ∈ G) : - f ∈ G.maximalAtlas H := by - rintro e (rfl : e = LocalHomeomorph.refl H) +theorem StructureGroupoid.mem_maximalAtlas_of_mem_groupoid {f : PartialHomeomorph H H} + (hf : f ∈ G) : f ∈ G.maximalAtlas H := by + rintro e (rfl : e = PartialHomeomorph.refl H) exact ⟨G.trans (G.symm hf) G.id_mem, G.trans (G.symm G.id_mem) hf⟩ #align structure_groupoid.mem_maximal_atlas_of_mem_groupoid StructureGroupoid.mem_maximalAtlas_of_mem_groupoid @@ -1057,9 +1057,9 @@ section Singleton variable {α : Type*} [TopologicalSpace α] -namespace LocalHomeomorph +namespace PartialHomeomorph -variable (e : LocalHomeomorph α H) +variable (e : PartialHomeomorph α H) /-- If a single local homeomorphism `e` from a space `α` into `H` has source covering the whole space `α`, then that local homeomorphism induces an `H`-charted space structure on `α`. @@ -1070,23 +1070,23 @@ def singletonChartedSpace (h : e.source = Set.univ) : ChartedSpace H α where chartAt _ := e mem_chart_source _ := by rw [h]; apply mem_univ chart_mem_atlas _ := by tauto -#align local_homeomorph.singleton_charted_space LocalHomeomorph.singletonChartedSpace +#align local_homeomorph.singleton_charted_space PartialHomeomorph.singletonChartedSpace @[simp, mfld_simps] theorem singletonChartedSpace_chartAt_eq (h : e.source = Set.univ) {x : α} : @chartAt H _ α _ (e.singletonChartedSpace h) x = e := rfl -#align local_homeomorph.singleton_charted_space_chart_at_eq LocalHomeomorph.singletonChartedSpace_chartAt_eq +#align local_homeomorph.singleton_charted_space_chart_at_eq PartialHomeomorph.singletonChartedSpace_chartAt_eq theorem singletonChartedSpace_chartAt_source (h : e.source = Set.univ) {x : α} : (@chartAt H _ α _ (e.singletonChartedSpace h) x).source = Set.univ := h -#align local_homeomorph.singleton_charted_space_chart_at_source LocalHomeomorph.singletonChartedSpace_chartAt_source +#align local_homeomorph.singleton_charted_space_chart_at_source PartialHomeomorph.singletonChartedSpace_chartAt_source -theorem singletonChartedSpace_mem_atlas_eq (h : e.source = Set.univ) (e' : LocalHomeomorph α H) +theorem singletonChartedSpace_mem_atlas_eq (h : e.source = Set.univ) (e' : PartialHomeomorph α H) (h' : e' ∈ (e.singletonChartedSpace h).atlas) : e' = e := h' -#align local_homeomorph.singleton_charted_space_mem_atlas_eq LocalHomeomorph.singletonChartedSpace_mem_atlas_eq +#align local_homeomorph.singleton_charted_space_mem_atlas_eq PartialHomeomorph.singletonChartedSpace_mem_atlas_eq /-- Given a local homeomorphism `e` from a space `α` into `H`, if its source covers the whole space `α`, then the induced charted space structure on `α` is `HasGroupoid G` for any structure @@ -1101,18 +1101,18 @@ theorem singleton_hasGroupoid (h : e.source = Set.univ) (G : StructureGroupoid H refine' G.eq_on_source _ e.trans_symm_self have hle : idRestrGroupoid ≤ G := (closedUnderRestriction_iff_id_le G).mp (by assumption) exact StructureGroupoid.le_iff.mp hle _ (idRestrGroupoid_mem _) } -#align local_homeomorph.singleton_has_groupoid LocalHomeomorph.singleton_hasGroupoid +#align local_homeomorph.singleton_has_groupoid PartialHomeomorph.singleton_hasGroupoid -end LocalHomeomorph +end PartialHomeomorph namespace OpenEmbedding variable [Nonempty α] /-- An open embedding of `α` into `H` induces an `H`-charted space structure on `α`. -See `LocalHomeomorph.singletonChartedSpace`. -/ +See `PartialHomeomorph.singletonChartedSpace`. -/ def singletonChartedSpace {f : α → H} (h : OpenEmbedding f) : ChartedSpace H α := - (h.toLocalHomeomorph f).singletonChartedSpace (toLocalHomeomorph_source _ _) + (h.toPartialHomeomorph f).singletonChartedSpace (toPartialHomeomorph_source _ _) #align open_embedding.singleton_charted_space OpenEmbedding.singletonChartedSpace theorem singletonChartedSpace_chartAt_eq {f : α → H} (h : OpenEmbedding f) {x : α} : @@ -1122,7 +1122,7 @@ theorem singletonChartedSpace_chartAt_eq {f : α → H} (h : OpenEmbedding f) {x theorem singleton_hasGroupoid {f : α → H} (h : OpenEmbedding f) (G : StructureGroupoid H) [ClosedUnderRestriction G] : @HasGroupoid _ _ _ _ h.singletonChartedSpace G := - (h.toLocalHomeomorph f).singleton_hasGroupoid (toLocalHomeomorph_source _ _) G + (h.toPartialHomeomorph f).singleton_hasGroupoid (toPartialHomeomorph_source _ _) G #align open_embedding.singleton_has_groupoid OpenEmbedding.singleton_hasGroupoid end OpenEmbedding @@ -1139,8 +1139,8 @@ variable (s : Opens M) /-- An open subset of a charted space is naturally a charted space. -/ protected instance instChartedSpace : ChartedSpace H s where - atlas := ⋃ x : s, {@LocalHomeomorph.subtypeRestr _ _ _ _ (chartAt H x.1) s ⟨x⟩} - chartAt x := @LocalHomeomorph.subtypeRestr _ _ _ _ (chartAt H x.1) s ⟨x⟩ + atlas := ⋃ x : s, {@PartialHomeomorph.subtypeRestr _ _ _ _ (chartAt H x.1) s ⟨x⟩} + chartAt x := @PartialHomeomorph.subtypeRestr _ _ _ _ (chartAt H x.1) s ⟨x⟩ mem_chart_source x := ⟨trivial, mem_chart_source H x.1⟩ chart_mem_atlas x := by simp only [mem_iUnion, mem_singleton_iff] @@ -1197,8 +1197,8 @@ and use structomorph instead. -/ -- @[nolint has_nonempty_instance] -- Porting note: commented out structure Structomorph (G : StructureGroupoid H) (M : Type*) (M' : Type*) [TopologicalSpace M] [TopologicalSpace M'] [ChartedSpace H M] [ChartedSpace H M'] extends Homeomorph M M' where - mem_groupoid : ∀ c : LocalHomeomorph M H, ∀ c' : LocalHomeomorph M' H, c ∈ atlas H M → - c' ∈ atlas H M' → c.symm ≫ₕ toHomeomorph.toLocalHomeomorph ≫ₕ c' ∈ G + mem_groupoid : ∀ c : PartialHomeomorph M H, ∀ c' : PartialHomeomorph M' H, c ∈ atlas H M → + c' ∈ atlas H M' → c.symm ≫ₕ toHomeomorph.toPartialHomeomorph ≫ₕ c' ∈ G #align structomorph Structomorph variable [TopologicalSpace M'] [TopologicalSpace M''] {G : StructureGroupoid H} [ChartedSpace H M'] @@ -1209,8 +1209,8 @@ def Structomorph.refl (M : Type*) [TopologicalSpace M] [ChartedSpace H M] [HasGr Structomorph G M M := { Homeomorph.refl M with mem_groupoid := fun c c' hc hc' ↦ by - change LocalHomeomorph.symm c ≫ₕ LocalHomeomorph.refl M ≫ₕ c' ∈ G - rw [LocalHomeomorph.refl_trans] + change PartialHomeomorph.symm c ≫ₕ PartialHomeomorph.refl M ≫ₕ c' ∈ G + rw [PartialHomeomorph.refl_trans] exact G.compatible hc hc' } #align structomorph.refl Structomorph.refl @@ -1219,7 +1219,7 @@ def Structomorph.symm (e : Structomorph G M M') : Structomorph G M' M := { e.toHomeomorph.symm with mem_groupoid := by intro c c' hc hc' - have : (c'.symm ≫ₕ e.toHomeomorph.toLocalHomeomorph ≫ₕ c).symm ∈ G := + have : (c'.symm ≫ₕ e.toHomeomorph.toPartialHomeomorph ≫ₕ c).symm ∈ G := G.symm (e.mem_groupoid c' c hc' hc) rwa [trans_symm_eq_symm_trans_symm, trans_symm_eq_symm_trans_symm, symm_symm, trans_assoc] at this } @@ -1236,10 +1236,10 @@ def Structomorph.trans (e : Structomorph G M M') (e' : Structomorph G M' M'') : their composition is smooth, and it coincides with c' ∘ e' ∘ e ∘ c⁻¹ around x. -/ intro c c' hc hc' refine' G.locality fun x hx ↦ _ - let f₁ := e.toHomeomorph.toLocalHomeomorph - let f₂ := e'.toHomeomorph.toLocalHomeomorph - let f := (e.toHomeomorph.trans e'.toHomeomorph).toLocalHomeomorph - have feq : f = f₁ ≫ₕ f₂ := Homeomorph.trans_toLocalHomeomorph _ _ + let f₁ := e.toHomeomorph.toPartialHomeomorph + let f₂ := e'.toHomeomorph.toPartialHomeomorph + let f := (e.toHomeomorph.trans e'.toHomeomorph).toPartialHomeomorph + have feq : f = f₁ ≫ₕ f₂ := Homeomorph.trans_toPartialHomeomorph _ _ -- define the atlas g around y let y := (c.symm ≫ₕ f₁) x let g := chartAt (H := H) y @@ -1250,7 +1250,7 @@ def Structomorph.trans (e : Structomorph G M M') (e' : Structomorph G M' M'') : apply (c.symm ≫ₕ f₁).continuousOn_toFun.isOpen_inter_preimage <;> apply open_source have : x ∈ s := by constructor - · simp only [trans_source, preimage_univ, inter_univ, Homeomorph.toLocalHomeomorph_source] + · simp only [trans_source, preimage_univ, inter_univ, Homeomorph.toPartialHomeomorph_source] rw [trans_source] at hx exact hx.1 · exact hg₂ diff --git a/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean b/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean index 3bb94c4a4194f..0c8fe428e78af 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean @@ -27,7 +27,7 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {I' : ModelWithCorners 𝕜 E' H'} {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] [SmoothManifoldWithCorners I' M'] -- declare functions, sets, points and smoothness indices - {e : LocalHomeomorph M H} {x : M} {m n : ℕ∞} + {e : PartialHomeomorph M H} {x : M} {m n : ℕ∞} /-! ### Atlas members are smooth -/ @@ -106,7 +106,7 @@ theorem contMDiffOn_extend_symm (he : e ∈ maximalAtlas I M) : ContMDiffOn 𝓘(𝕜, E) I n (e.extend I).symm (I '' e.target) := by refine (contMDiffOn_symm_of_mem_maximalAtlas he).comp (contMDiffOn_model_symm.mono <| image_subset_range _ _) ?_ - simp_rw [image_subset_iff, LocalEquiv.restr_coe_symm, I.toLocalEquiv_coe_symm, + simp_rw [image_subset_iff, PartialEquiv.restr_coe_symm, I.toPartialEquiv_coe_symm, preimage_preimage, I.left_inv, preimage_id']; rfl #align cont_mdiff_on_extend_symm contMDiffOn_extend_symm @@ -117,7 +117,7 @@ theorem contMDiffOn_extChartAt_symm (x : M) : #align cont_mdiff_on_ext_chart_at_symm contMDiffOn_extChartAt_symm /-- An element of `contDiffGroupoid ⊤ I` is `C^n` for any `n`. -/ -theorem contMDiffOn_of_mem_contDiffGroupoid {e' : LocalHomeomorph H H} +theorem contMDiffOn_of_mem_contDiffGroupoid {e' : PartialHomeomorph H H} (h : e' ∈ contDiffGroupoid ⊤ I) : ContMDiffOn I I n e' e'.source := (contDiffWithinAt_localInvariantProp I I n).liftPropOn_of_mem_groupoid (contDiffWithinAtProp_id I) h @@ -131,7 +131,7 @@ section IsLocalStructomorph variable [ChartedSpace H M'] [IsM' : SmoothManifoldWithCorners I M'] -theorem isLocalStructomorphOn_contDiffGroupoid_iff_aux {f : LocalHomeomorph M M'} +theorem isLocalStructomorphOn_contDiffGroupoid_iff_aux {f : PartialHomeomorph M M'} (hf : LiftPropOn (contDiffGroupoid ⊤ I).IsLocalStructomorphWithinAt f f.source) : SmoothOn I I f f.source := by -- It suffices to show smoothness near each `x` @@ -177,7 +177,7 @@ theorem isLocalStructomorphOn_contDiffGroupoid_iff_aux {f : LocalHomeomorph M M' /-- Let `M` and `M'` be smooth manifolds with the same model-with-corners, `I`. Then `f : M → M'` is a local structomorphism for `I`, if and only if it is manifold-smooth on the domain of definition in both directions. -/ -theorem isLocalStructomorphOn_contDiffGroupoid_iff (f : LocalHomeomorph M M') : +theorem isLocalStructomorphOn_contDiffGroupoid_iff (f : PartialHomeomorph M M') : LiftPropOn (contDiffGroupoid ⊤ I).IsLocalStructomorphWithinAt f f.source ↔ SmoothOn I I f f.source ∧ SmoothOn I I f.symm f.target := by constructor @@ -193,7 +193,7 @@ theorem isLocalStructomorphOn_contDiffGroupoid_iff (f : LocalHomeomorph M M') : obtain ⟨-, hxf⟩ := h x hx refine' ⟨(f.symm.continuousAt hX).continuousWithinAt, fun h2x => _⟩ obtain ⟨e, he, h2e, hef, hex⟩ : - ∃ e : LocalHomeomorph H H, + ∃ e : PartialHomeomorph H H, e ∈ contDiffGroupoid ⊤ I ∧ e.source ⊆ (c.symm ≫ₕ f ≫ₕ c').source ∧ EqOn (c' ∘ f ∘ c.symm) e e.source ∧ c x ∈ e.source := by @@ -201,7 +201,7 @@ theorem isLocalStructomorphOn_contDiffGroupoid_iff (f : LocalHomeomorph M M') : have h2 : c' ∘ f ∘ c.symm = ⇑(c.symm ≫ₕ f ≫ₕ c') := rfl have hcx : c x ∈ c.symm ⁻¹' f.source := by simp only [hx, mfld_simps] rw [h2] - rw [← h1, h2, LocalHomeomorph.isLocalStructomorphWithinAt_iff'] at hxf + rw [← h1, h2, PartialHomeomorph.isLocalStructomorphWithinAt_iff'] at hxf · exact hxf hcx · mfld_set_tac · apply Or.inl @@ -219,7 +219,7 @@ theorem isLocalStructomorphOn_contDiffGroupoid_iff (f : LocalHomeomorph M M') : · rw [inter_self]; exact hef.symm have h2 : e.target ⊆ (c.symm ≫ₕ f ≫ₕ c').target := by intro x hx; rw [← e.right_inv hx, ← hef (e.symm.mapsTo hx)] - exact LocalHomeomorph.mapsTo _ (h2e <| e.symm.mapsTo hx) + exact PartialHomeomorph.mapsTo _ (h2e <| e.symm.mapsTo hx) rw [inter_self] at h1 rwa [inter_eq_right.mpr] refine' h2.trans _ diff --git a/Mathlib/Geometry/Manifold/ContMDiff/Basic.lean b/Mathlib/Geometry/Manifold/ContMDiff/Basic.lean index 7abad04c84dd4..8713c9c05f086 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Basic.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Basic.lean @@ -13,6 +13,8 @@ In this file, we show that standard operations on smooth maps between smooth man * `contMDiff_id` gives the smoothness of the identity * `contMDiff_const` gives the smoothness of constant functions * `contMDiff_inclusion` shows that the inclusion between open sets of a topological space is smooth +* `contMDiff_openEmbedding` shows that if `M` has a `ChartedSpace` structure induced by an open +embedding `e : M → H`, then `e` is smooth. ## Tags chain rule, manifolds, higher derivative @@ -53,8 +55,8 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] [NormedSpace 𝕜 F₂] {F₃ : Type*} [NormedAddCommGroup F₃] [NormedSpace 𝕜 F₃] {F₄ : Type*} [NormedAddCommGroup F₄] [NormedSpace 𝕜 F₄] -- declare functions, sets, points and smoothness indices - {e : LocalHomeomorph M H} - {e' : LocalHomeomorph M' H'} {f f₁ : M → M'} {s s₁ t : Set M} {x : M} {m n : ℕ∞} + {e : PartialHomeomorph M H} + {e' : PartialHomeomorph M' H'} {f f₁ : M → M'} {s s₁ t : Set M} {x : M} {m n : ℕ∞} variable {I I'} /-! ### Smoothness of the composition of smooth functions between manifolds -/ @@ -398,3 +400,77 @@ theorem smooth_inclusion {U V : Opens M} (h : U ≤ V) : Smooth I I (Set.inclusi #align smooth_inclusion smooth_inclusion end Inclusion + +/-! ### Open embeddings and their inverses are smooth -/ + +section + +variable (I) + [Nonempty M] {e : M → H} (h : OpenEmbedding e) + [Nonempty M'] {e' : M' → H'} (h' : OpenEmbedding e') + {n : WithTop ℕ} + +/-- If the `ChartedSpace` structure on a manifold `M` is given by an open embedding `e : M → H`, +then `e` is smooth. -/ +lemma contMDiff_openEmbedding : + haveI := h.singletonChartedSpace; ContMDiff I I n e := by + haveI := h.singleton_smoothManifoldWithCorners I + rw [@contMDiff_iff _ _ _ _ _ _ _ _ _ _ h.singletonChartedSpace] + use h.continuous + intros x y + -- show the function is actually the identity on the range of I ∘ e + apply contDiffOn_id.congr + intros z hz + -- factorise into the chart `e` and the model `id` + simp only [mfld_simps] + rw [h.toPartialHomeomorph_right_inv] + · rw [I.right_inv] + apply mem_of_subset_of_mem _ hz.1 + exact haveI := h.singletonChartedSpace; extChartAt_target_subset_range I x + · -- `hz` implies that `z ∈ range (I ∘ e)` + have := hz.1 + rw [@extChartAt_target _ _ _ _ _ _ _ _ _ _ h.singletonChartedSpace] at this + have := this.1 + rw [mem_preimage, PartialHomeomorph.singletonChartedSpace_chartAt_eq, + h.toPartialHomeomorph_target] at this + exact this + +variable {I} +/-- If the `ChartedSpace` structure on a manifold `M` is given by an open embedding `e : M → H`, +then the inverse of `e` is smooth. -/ +lemma contMDiffOn_openEmbedding_symm : + haveI := h.singletonChartedSpace; ContMDiffOn I I + n (OpenEmbedding.toPartialHomeomorph e h).symm (range e) := by + haveI := h.singleton_smoothManifoldWithCorners I + rw [@contMDiffOn_iff _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ h.singletonChartedSpace] + constructor + · rw [← h.toPartialHomeomorph_target] + exact (h.toPartialHomeomorph e).continuousOn_symm + · intros z hz + -- show the function is actually the identity on the range of I ∘ e + apply contDiffOn_id.congr + intros z hz + -- factorise into the chart `e` and the model `id` + simp only [mfld_simps] + have : I.symm z ∈ range e := by + rw [ModelWithCorners.symm, ← mem_preimage] + exact hz.2.1 + rw [h.toPartialHomeomorph_right_inv e this] + apply I.right_inv + exact mem_of_subset_of_mem (extChartAt_target_subset_range _ _) hz.1 + +/-- Let `M'` be a manifold whose chart structure is given by an open embedding `e'` into its model +space `H'`. Then the smoothness of `e' ∘ f : M → H'` implies the smoothness of `f`. + +This is useful, for example, when `e' ∘ f = g ∘ e` for smooth maps `e : M → X` and `g : X → H'`. -/ +lemma ContMDiff.of_comp_openEmbedding {f : M → M'} (hf : ContMDiff I I' n (e' ∘ f)) : + haveI := h'.singletonChartedSpace; ContMDiff I I' n f := by + have : f = (h'.toPartialHomeomorph e').symm ∘ e' ∘ f := by + ext + rw [Function.comp_apply, Function.comp_apply, OpenEmbedding.toPartialHomeomorph_left_inv] + rw [this] + apply @ContMDiffOn.comp_contMDiff _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + h'.singletonChartedSpace _ _ (range e') _ (contMDiffOn_openEmbedding_symm h') hf + simp + +end diff --git a/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean b/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean index cefea4f4b6fd5..392ed7dd07b2a 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean @@ -84,8 +84,8 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] [NormedSpace 𝕜 F₂] {F₃ : Type*} [NormedAddCommGroup F₃] [NormedSpace 𝕜 F₃] {F₄ : Type*} [NormedAddCommGroup F₄] [NormedSpace 𝕜 F₄] -- declare functions, sets, points and smoothness indices - {e : LocalHomeomorph M H} - {e' : LocalHomeomorph M' H'} {f f₁ : M → M'} {s s₁ t : Set M} {x : M} {m n : ℕ∞} + {e : PartialHomeomorph M H} + {e' : PartialHomeomorph M' H'} {f f₁ : M → M'} {s s₁ t : Set M} {x : M} {m n : ℕ∞} /-- Property in the model space of a model with corners of being `C^n` within at set at a point, when read in the model vector space. This property will be lifted to manifolds to define smooth @@ -359,9 +359,9 @@ theorem contMDiffWithinAt_iff_target : ContinuousWithinAt f s x ∧ ContinuousWithinAt (extChartAt I' (f x) ∘ f) s x ↔ ContinuousWithinAt f s x := and_iff_left_of_imp <| (continuousAt_extChartAt _ _).comp_continuousWithinAt - simp_rw [cont, ContDiffWithinAtProp, extChartAt, LocalHomeomorph.extend, LocalEquiv.coe_trans, - ModelWithCorners.toLocalEquiv_coe, LocalHomeomorph.coe_coe, modelWithCornersSelf_coe, - chartAt_self_eq, LocalHomeomorph.refl_apply, comp.left_id] + simp_rw [cont, ContDiffWithinAtProp, extChartAt, PartialHomeomorph.extend, PartialEquiv.coe_trans, + ModelWithCorners.toPartialEquiv_coe, PartialHomeomorph.coe_coe, modelWithCornersSelf_coe, + chartAt_self_eq, PartialHomeomorph.refl_apply, comp.left_id] rfl #align cont_mdiff_within_at_iff_target contMDiffWithinAt_iff_target @@ -582,8 +582,8 @@ theorem contMDiffOn_iff_target : ∀ y : M', ContMDiffOn I 𝓘(𝕜, E') n (extChartAt I' y ∘ f) (s ∩ f ⁻¹' (extChartAt I' y).source) := by simp only [contMDiffOn_iff, ModelWithCorners.source_eq, chartAt_self_eq, - LocalHomeomorph.refl_localEquiv, LocalEquiv.refl_trans, extChartAt, LocalHomeomorph.extend, - Set.preimage_univ, Set.inter_univ, and_congr_right_iff] + PartialHomeomorph.refl_localEquiv, PartialEquiv.refl_trans, extChartAt, + PartialHomeomorph.extend, Set.preimage_univ, Set.inter_univ, and_congr_right_iff] intro h constructor · refine' fun h' y => ⟨_, fun x _ => h' x y⟩ @@ -838,7 +838,7 @@ theorem contMDiffWithinAt_iff_contMDiffOn_nhds {n : ℕ} : have hv₂ : MapsTo f ((extChartAt I x).symm '' v) (extChartAt I' (f x)).source := by rintro _ ⟨y, hy, rfl⟩ exact (hsub hy).2.2 - rwa [contMDiffOn_iff_of_subset_source' hv₁ hv₂, LocalEquiv.image_symm_image_of_subset_target] + rwa [contMDiffOn_iff_of_subset_source' hv₁ hv₂, PartialEquiv.image_symm_image_of_subset_target] exact hsub.trans (inter_subset_left _ _) #align cont_mdiff_within_at_iff_cont_mdiff_on_nhds contMDiffWithinAt_iff_contMDiffOn_nhds diff --git a/Mathlib/Geometry/Manifold/ContMDiff/Product.lean b/Mathlib/Geometry/Manifold/ContMDiff/Product.lean index 74eb5da9a250f..6eb4c75f0c438 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Product.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Product.lean @@ -50,8 +50,8 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] [NormedSpace 𝕜 F₂] {F₃ : Type*} [NormedAddCommGroup F₃] [NormedSpace 𝕜 F₃] {F₄ : Type*} [NormedAddCommGroup F₄] [NormedSpace 𝕜 F₄] -- declare functions, sets, points and smoothness indices - {e : LocalHomeomorph M H} - {e' : LocalHomeomorph M' H'} {f f₁ : M → M'} {s s₁ t : Set M} {x : M} {m n : ℕ∞} + {e : PartialHomeomorph M H} + {e' : PartialHomeomorph M' H'} {f f₁ : M → M'} {s s₁ t : Set M} {x : M} {m n : ℕ∞} variable {I I'} section ProdMk @@ -405,7 +405,7 @@ theorem contMDiffWithinAt_pi_space : -- Porting note: `simp` fails to apply it on the LHS rw [contMDiffWithinAt_iff] simp only [contMDiffWithinAt_iff, continuousWithinAt_pi, contDiffWithinAt_pi, forall_and, - writtenInExtChartAt, extChartAt_model_space_eq_id, (· ∘ ·), LocalEquiv.refl_coe, id] + writtenInExtChartAt, extChartAt_model_space_eq_id, (· ∘ ·), PartialEquiv.refl_coe, id] #align cont_mdiff_within_at_pi_space contMDiffWithinAt_pi_space theorem contMDiffOn_pi_space : diff --git a/Mathlib/Geometry/Manifold/ContMDiffMFDeriv.lean b/Mathlib/Geometry/Manifold/ContMDiffMFDeriv.lean index f12513c1cf22c..29c91bfdbd422 100644 --- a/Mathlib/Geometry/Manifold/ContMDiffMFDeriv.lean +++ b/Mathlib/Geometry/Manifold/ContMDiffMFDeriv.lean @@ -97,7 +97,7 @@ protected theorem ContMDiffAt.mfderiv {x₀ : N} (f : N → M → M') (g : N → (range I) (extChartAt I (g x₀) (g ((extChartAt J x₀).symm x)))) (range J) (extChartAt J x₀ x₀) := by rw [contMDiffAt_iff] at hf hg - simp_rw [Function.comp, uncurry, extChartAt_prod, LocalEquiv.prod_coe_symm, + simp_rw [Function.comp, uncurry, extChartAt_prod, PartialEquiv.prod_coe_symm, ModelWithCorners.range_prod] at hf ⊢ refine' ContDiffWithinAt.fderivWithin _ hg.2 I.unique_diff hmn (mem_range_self _) _ · simp_rw [extChartAt_to_inv]; exact hf.2 @@ -161,11 +161,11 @@ protected theorem ContMDiffAt.mfderiv {x₀ : N} (f : N → M → M') (g : N → symm rw [(h2x₂.mdifferentiableAt le_rfl).mfderiv] have hI := (contDiffWithinAt_ext_coord_change I (g x₂) (g x₀) <| - LocalEquiv.mem_symm_trans_source _ hx₂ <| + PartialEquiv.mem_symm_trans_source _ hx₂ <| mem_extChartAt_source I (g x₂)).differentiableWithinAt le_top have hI' := (contDiffWithinAt_ext_coord_change I' (f x₀ (g x₀)) (f x₂ (g x₂)) <| - LocalEquiv.mem_symm_trans_source _ (mem_extChartAt_source I' (f x₂ (g x₂))) + PartialEquiv.mem_symm_trans_source _ (mem_extChartAt_source I' (f x₂ (g x₂))) h3x₂).differentiableWithinAt le_top have h3f := (h2x₂.mdifferentiableAt le_rfl).2 refine' fderivWithin.comp₃ _ hI' h3f hI _ _ _ _ (I.unique_diff _ <| mem_range_self _) @@ -567,7 +567,7 @@ theorem tangentMap_tangentBundle_pure (p : TangentBundle I M) : rcases p with ⟨x, v⟩ have N : I.symm ⁻¹' (chartAt H x).target ∈ 𝓝 (I ((chartAt H x) x)) := by apply IsOpen.mem_nhds - apply (LocalHomeomorph.open_target _).preimage I.continuous_invFun + apply (PartialHomeomorph.open_target _).preimage I.continuous_invFun simp only [mfld_simps] have A : MDifferentiableAt I I.tangent (fun x => @TotalSpace.mk M E (TangentSpace I) x 0) x := haveI : Smooth I (I.prod 𝓘(𝕜, E)) (zeroSection E (TangentSpace I : M → Type _)) := diff --git a/Mathlib/Geometry/Manifold/Diffeomorph.lean b/Mathlib/Geometry/Manifold/Diffeomorph.lean index 5de132745d0d8..38875a608ffa6 100644 --- a/Mathlib/Geometry/Manifold/Diffeomorph.lean +++ b/Mathlib/Geometry/Manifold/Diffeomorph.lean @@ -374,10 +374,10 @@ theorem contMDiff_diffeomorph_comp_iff {m} (h : M ≃ₘ^n⟮I, J⟯ N) {f : M' forall_congr' fun _ => h.contMDiffWithinAt_diffeomorph_comp_iff hm #align diffeomorph.cont_mdiff_diffeomorph_comp_iff Diffeomorph.contMDiff_diffeomorph_comp_iff -theorem toLocalHomeomorph_mdifferentiable (h : M ≃ₘ^n⟮I, J⟯ N) (hn : 1 ≤ n) : - h.toHomeomorph.toLocalHomeomorph.MDifferentiable I J := +theorem toPartialHomeomorph_mdifferentiable (h : M ≃ₘ^n⟮I, J⟯ N) (hn : 1 ≤ n) : + h.toHomeomorph.toPartialHomeomorph.MDifferentiable I J := ⟨h.mdifferentiableOn _ hn, h.symm.mdifferentiableOn _ hn⟩ -#align diffeomorph.to_local_homeomorph_mdifferentiable Diffeomorph.toLocalHomeomorph_mdifferentiable +#align diffeomorph.to_local_homeomorph_mdifferentiable Diffeomorph.toPartialHomeomorph_mdifferentiable section Constructions @@ -442,7 +442,7 @@ variable [SmoothManifoldWithCorners I M] [SmoothManifoldWithCorners J N] theorem uniqueMDiffOn_image_aux (h : M ≃ₘ^n⟮I, J⟯ N) (hn : 1 ≤ n) {s : Set M} (hs : UniqueMDiffOn I s) : UniqueMDiffOn J (h '' s) := by - convert hs.uniqueMDiffOn_preimage (h.toLocalHomeomorph_mdifferentiable hn) + convert hs.uniqueMDiffOn_preimage (h.toPartialHomeomorph_mdifferentiable hn) simp [h.image_eq_preimage] #align diffeomorph.unique_mdiff_on_image_aux Diffeomorph.uniqueMDiffOn_image_aux @@ -509,7 +509,7 @@ variable (I) (e : E ≃ₘ[𝕜] E') /-- Apply a diffeomorphism (e.g., a continuous linear equivalence) to the model vector space. -/ def transDiffeomorph (I : ModelWithCorners 𝕜 E H) (e : E ≃ₘ[𝕜] E') : ModelWithCorners 𝕜 E' H where - toLocalEquiv := I.toLocalEquiv.trans e.toEquiv.toLocalEquiv + toPartialEquiv := I.toPartialEquiv.trans e.toEquiv.toPartialEquiv source_eq := by simp unique_diff' := by simp [range_comp e, I.unique_diff] continuous_toFun := e.continuous.comp I.continuous diff --git a/Mathlib/Geometry/Manifold/Instances/Real.lean b/Mathlib/Geometry/Manifold/Instances/Real.lean index adfa58088fd11..462fe126222ec 100644 --- a/Mathlib/Geometry/Manifold/Instances/Real.lean +++ b/Mathlib/Geometry/Manifold/Instances/Real.lean @@ -166,7 +166,7 @@ scoped[Manifold] `EuclideanHalfSpace 1`. -/ def IccLeftChart (x y : ℝ) [h : Fact (x < y)] : - LocalHomeomorph (Icc x y) (EuclideanHalfSpace 1) where + PartialHomeomorph (Icc x y) (EuclideanHalfSpace 1) where source := { z : Icc x y | z.val < y } target := { z : EuclideanHalfSpace 1 | z.val 0 < y - x } toFun := fun z : Icc x y => ⟨fun _ => z.val - x, sub_nonneg.mpr z.property.1⟩ @@ -214,7 +214,7 @@ def IccLeftChart (x y : ℝ) [h : Fact (x < y)] : `EuclideanHalfSpace 1`. -/ def IccRightChart (x y : ℝ) [h : Fact (x < y)] : - LocalHomeomorph (Icc x y) (EuclideanHalfSpace 1) where + PartialHomeomorph (Icc x y) (EuclideanHalfSpace 1) where source := { z : Icc x y | x < z.val } target := { z : EuclideanHalfSpace 1 | z.val 0 < y - x } toFun z := ⟨fun _ => y - z.val, sub_nonneg.mpr z.property.2⟩ diff --git a/Mathlib/Geometry/Manifold/Instances/Sphere.lean b/Mathlib/Geometry/Manifold/Instances/Sphere.lean index c39df393555b8..c838ca17e7a53 100644 --- a/Mathlib/Geometry/Manifold/Instances/Sphere.lean +++ b/Mathlib/Geometry/Manifold/Instances/Sphere.lean @@ -281,7 +281,7 @@ theorem stereo_right_inv (hv : ‖v‖ = 1) (w : (ℝ ∙ v)ᗮ) : stereoToFun v /-- Stereographic projection from the unit sphere in `E`, centred at a unit vector `v` in `E`; this is the version as a local homeomorphism. -/ -def stereographic (hv : ‖v‖ = 1) : LocalHomeomorph (sphere (0 : E) 1) (ℝ ∙ v)ᗮ where +def stereographic (hv : ‖v‖ = 1) : PartialHomeomorph (sphere (0 : E) 1) (ℝ ∙ v)ᗮ where toFun := stereoToFun v ∘ (↑) invFun := stereoInvFun hv source := {⟨v, by simp [hv]⟩}ᶜ @@ -364,10 +364,10 @@ space `E`. This version has codomain the Euclidean space of dimension `n`, and composing the original sterographic projection (`stereographic`) with an arbitrary linear isometry from `(ℝ ∙ v)ᗮ` to the Euclidean space. -/ def stereographic' (n : ℕ) [Fact (finrank ℝ E = n + 1)] (v : sphere (0 : E) 1) : - LocalHomeomorph (sphere (0 : E) 1) (EuclideanSpace ℝ (Fin n)) := + PartialHomeomorph (sphere (0 : E) 1) (EuclideanSpace ℝ (Fin n)) := stereographic (norm_eq_of_mem_sphere v) ≫ₕ (OrthonormalBasis.fromOrthogonalSpanSingleton n - (ne_zero_of_mem_unit_sphere v)).repr.toHomeomorph.toLocalHomeomorph + (ne_zero_of_mem_unit_sphere v)).repr.toHomeomorph.toPartialHomeomorph #align stereographic' stereographic' @[simp] @@ -430,12 +430,12 @@ instance smoothMfldWithCorners {n : ℕ} [Fact (finrank ℝ E = n + 1)] : (ℝ ∙ (v : E))ᗮ.subtypeL.contDiff).comp U.symm.contDiff convert H₁.comp' (H₂.contDiffOn : ContDiffOn ℝ ⊤ _ Set.univ) using 1 -- -- squeezed from `ext, simp [sphere_ext_iff, stereographic'_symm_apply, real_inner_comm]` - simp only [LocalHomeomorph.trans_toLocalEquiv, LocalHomeomorph.symm_toLocalEquiv, - LocalEquiv.trans_source, LocalEquiv.symm_source, stereographic'_target, + simp only [PartialHomeomorph.trans_toPartialEquiv, PartialHomeomorph.symm_toPartialEquiv, + PartialEquiv.trans_source, PartialEquiv.symm_source, stereographic'_target, stereographic'_source] simp only [modelWithCornersSelf_coe, modelWithCornersSelf_coe_symm, Set.preimage_id, Set.range_id, Set.inter_univ, Set.univ_inter, Set.compl_singleton_eq, Set.preimage_setOf_eq] - simp only [id.def, comp_apply, Submodule.subtypeL_apply, LocalHomeomorph.coe_coe_symm, + simp only [id.def, comp_apply, Submodule.subtypeL_apply, PartialHomeomorph.coe_coe_symm, innerSL_apply, Ne.def, sphere_ext_iff, real_inner_comm (v' : E)] rfl) diff --git a/Mathlib/Geometry/Manifold/Instances/UnitsOfNormedAlgebra.lean b/Mathlib/Geometry/Manifold/Instances/UnitsOfNormedAlgebra.lean index 6fd20b0d8aeb4..6e2ba2c573fa3 100644 --- a/Mathlib/Geometry/Manifold/Instances/UnitsOfNormedAlgebra.lean +++ b/Mathlib/Geometry/Manifold/Instances/UnitsOfNormedAlgebra.lean @@ -1,48 +1,28 @@ /- Copyright © 2021 Nicolò Cavalleri. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Nicolò Cavalleri, Heather Macbeth +Authors: Nicolò Cavalleri, Heather Macbeth, Winston Yin -/ -import Mathlib.Geometry.Manifold.SmoothManifoldWithCorners -import Mathlib.Analysis.NormedSpace.Units +import Mathlib.Geometry.Manifold.Algebra.LieGroup #align_import geometry.manifold.instances.units_of_normed_algebra from "leanprover-community/mathlib"@"ef901ea68d3bb1dd08f8bc3034ab6b32b2e6ecdf" /-! # Units of a normed algebra -This file is a stub, containing a construction of the charted space structure on the group of units -of a complete normed ring `R`, and of the smooth manifold structure on the group of units of a -complete normed `𝕜`-algebra `R`. - -This manifold is actually a Lie group, which eventually should be the main result of this file. +We construct the Lie group structure on the group of units of a complete normed `𝕜`-algebra `R`. The +group of units `Rˣ` has a natural smooth manifold structure modelled on `R` given by its embedding +into `R`. Together with the smoothness of the multiplication and inverse of its elements, `Rˣ` forms +a Lie group. An important special case of this construction is the general linear group. For a normed space `V` over a field `𝕜`, the `𝕜`-linear endomorphisms of `V` are a normed `𝕜`-algebra (see `ContinuousLinearMap.toNormedAlgebra`), so this construction provides a Lie group structure on -its group of units, the general linear group GL(`𝕜`, `V`). - -## TODO - -The Lie group instance requires the following fields: +its group of units, the general linear group GL(`𝕜`, `V`), as demonstrated by: ``` -instance : LieGroup 𝓘(𝕜, R) Rˣ := - { Units.smoothManifoldWithCorners with - smooth_mul := sorry, - smooth_inv := sorry } +example {V : Type*} [NormedAddCommGroup V] [NormedSpace 𝕜 V] [CompleteSpace V] [Nontrivial V] : + LieGroup 𝓘(𝕜, V →L[𝕜] V) (V →L[𝕜] V)ˣ := by infer_instance ``` - -The ingredients needed for the construction are -* smoothness of multiplication and inversion in the charts, i.e. as functions on the normed - `𝕜`-space `R`: see `contDiffAt_ring_inverse` for the inversion result, and - `contDiff_mul` (needs to be generalized from field to algebra) for the multiplication - result -* for an open embedding `f`, whose domain is equipped with the induced manifold structure - `f.singleton_smoothManifoldWithCorners`, characterization of smoothness of functions to/from - this manifold in terms of smoothness in the target space. See the pair of lemmas - `ContMDiff_coe_sphere` and `ContMDiff.codRestrict_sphere` for a model. -None of this should be particularly difficult. - -/ @@ -70,4 +50,30 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] [NormedAlgebra 𝕜 R] instance : SmoothManifoldWithCorners 𝓘(𝕜, R) Rˣ := openEmbedding_val.singleton_smoothManifoldWithCorners 𝓘(𝕜, R) +/-- For a complete normed ring `R`, the embedding of the units `Rˣ` into `R` is a smooth map between +manifolds. -/ +lemma contMDiff_val {m : ℕ∞} : ContMDiff 𝓘(𝕜, R) 𝓘(𝕜, R) m (val : Rˣ → R) := + contMDiff_openEmbedding 𝓘(𝕜, R) Units.openEmbedding_val + +/-- The units of a complete normed ring form a Lie group. -/ +instance : LieGroup 𝓘(𝕜, R) Rˣ where + smooth_mul := by + apply ContMDiff.of_comp_openEmbedding Units.openEmbedding_val + have : (val : Rˣ → R) ∘ (fun x : Rˣ × Rˣ => x.1 * x.2) = + (fun x : R × R => x.1 * x.2) ∘ (fun x : Rˣ × Rˣ => (x.1, x.2)) := by ext; simp + rw [this] + have : ContMDiff (𝓘(𝕜, R).prod 𝓘(𝕜, R)) 𝓘(𝕜, R × R) ∞ + (fun x : Rˣ × Rˣ => ((x.1 : R), (x.2 : R))) := + (contMDiff_val.comp contMDiff_fst).prod_mk_space (contMDiff_val.comp contMDiff_snd) + refine ContMDiff.comp ?_ this + rw [contMDiff_iff_contDiff] + exact contDiff_mul + smooth_inv := by + apply ContMDiff.of_comp_openEmbedding Units.openEmbedding_val + have : (val : Rˣ → R) ∘ (fun x : Rˣ => x⁻¹) = Ring.inverse ∘ val := by ext; simp + rw [this, ContMDiff] + refine fun x => ContMDiffAt.comp x ?_ (contMDiff_val x) + rw [contMDiffAt_iff_contDiffAt] + exact contDiffAt_ring_inverse _ _ + end Units diff --git a/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean b/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean index 5a71cc39c1d09..49f80e0477536 100644 --- a/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean +++ b/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean @@ -69,10 +69,10 @@ variable (G : StructureGroupoid H) (G' : StructureGroupoid H') to charted spaces admitting these groupoids will inherit the good behavior. -/ structure LocalInvariantProp (P : (H → H') → Set H → H → Prop) : Prop where is_local : ∀ {s x u} {f : H → H'}, IsOpen u → x ∈ u → (P f s x ↔ P f (s ∩ u) x) - right_invariance' : ∀ {s x f} {e : LocalHomeomorph H H}, + right_invariance' : ∀ {s x f} {e : PartialHomeomorph H H}, e ∈ G → x ∈ e.source → P f s x → P (f ∘ e.symm) (e.symm ⁻¹' s) (e x) congr_of_forall : ∀ {s x} {f g : H → H'}, (∀ y ∈ s, f y = g y) → f x = g x → P f s x → P g s x - left_invariance' : ∀ {s x f} {e' : LocalHomeomorph H' H'}, + left_invariance' : ∀ {s x f} {e' : PartialHomeomorph H' H'}, e' ∈ G' → s ⊆ f ⁻¹' e'.source → f x ∈ e'.source → P f s x → P (e' ∘ f) s x #align structure_groupoid.local_invariant_prop StructureGroupoid.LocalInvariantProp @@ -121,7 +121,7 @@ theorem congr' {s : Set H} {x : H} {f g : H → H'} (h : f =ᶠ[𝓝 x] g) (hP : hG.congr h.symm hP #align structure_groupoid.local_invariant_prop.congr' StructureGroupoid.LocalInvariantProp.congr' -theorem left_invariance {s : Set H} {x : H} {f : H → H'} {e' : LocalHomeomorph H' H'} +theorem left_invariance {s : Set H} {x : H} {f : H → H'} {e' : PartialHomeomorph H' H'} (he' : e' ∈ G') (hfs : ContinuousWithinAt f s x) (hxe' : f x ∈ e'.source) : P (e' ∘ f) s x ↔ P f s x := by have h2f := hfs.preimage_mem_nhdsWithin (e'.open_source.mem_nhds hxe') @@ -139,7 +139,7 @@ theorem left_invariance {s : Set H} {x : H} {f : H → H'} {e' : LocalHomeomorph exact hG.left_invariance' he' (inter_subset_right _ _) hxe' #align structure_groupoid.local_invariant_prop.left_invariance StructureGroupoid.LocalInvariantProp.left_invariance -theorem right_invariance {s : Set H} {x : H} {f : H → H'} {e : LocalHomeomorph H H} (he : e ∈ G) +theorem right_invariance {s : Set H} {x : H} {f : H → H'} {e : PartialHomeomorph H H} (he : e ∈ G) (hxe : x ∈ e.source) : P (f ∘ e.symm) (e.symm ⁻¹' s) (e x) ↔ P f s x := by refine' ⟨fun h ↦ _, hG.right_invariance' he hxe⟩ have := hG.right_invariance' (G.symm he) (e.mapsTo hxe) h @@ -208,8 +208,8 @@ open ChartedSpace namespace StructureGroupoid -variable {G : StructureGroupoid H} {G' : StructureGroupoid H'} {e e' : LocalHomeomorph M H} - {f f' : LocalHomeomorph M' H'} {P : (H → H') → Set H → H → Prop} {g g' : M → M'} {s t : Set M} +variable {G : StructureGroupoid H} {G' : StructureGroupoid H'} {e e' : PartialHomeomorph M H} + {f f' : PartialHomeomorph M' H'} {P : (H → H') → Set H → H → Prop} {g g' : M → M'} {s t : Set M} {x : M} {Q : (H → H) → Set H → H → Prop} theorem liftPropWithinAt_univ : LiftPropWithinAt P g univ x ↔ LiftPropAt P g x := Iff.rfl @@ -246,8 +246,8 @@ theorem liftPropWithinAt_iff {f : M → M'} : ((chartAt H x).target ∩ (chartAt H x).symm ⁻¹' (s ∩ f ⁻¹' (chartAt H' (f x)).source)) (chartAt H x x) := by refine' and_congr_right fun hf ↦ hG.congr_set _ - exact LocalHomeomorph.preimage_eventuallyEq_target_inter_preimage_inter hf (mem_chart_source H x) - (chart_source_mem_nhds H' (f x)) + exact PartialHomeomorph.preimage_eventuallyEq_target_inter_preimage_inter hf + (mem_chart_source H x) (chart_source_mem_nhds H' (f x)) #align structure_groupoid.local_invariant_prop.lift_prop_within_at_iff StructureGroupoid.LocalInvariantProp.liftPropWithinAt_iff theorem liftPropWithinAt_indep_chart_source_aux (g : M → H') (he : e ∈ G.maximalAtlas M) @@ -255,13 +255,13 @@ theorem liftPropWithinAt_indep_chart_source_aux (g : M → H') (he : e ∈ G.max P (g ∘ e.symm) (e.symm ⁻¹' s) (e x) ↔ P (g ∘ e'.symm) (e'.symm ⁻¹' s) (e' x) := by rw [← hG.right_invariance (compatible_of_mem_maximalAtlas he he')] swap; · simp only [xe, xe', mfld_simps] - simp_rw [LocalHomeomorph.trans_apply, e.left_inv xe] + simp_rw [PartialHomeomorph.trans_apply, e.left_inv xe] rw [hG.congr_iff] · refine' hG.congr_set _ refine' (eventually_of_mem _ fun y (hy : y ∈ e'.symm ⁻¹' e.source) ↦ _).set_eq · refine' (e'.symm.continuousAt <| e'.mapsTo xe').preimage_mem_nhds (e.open_source.mem_nhds _) simp_rw [e'.left_inv xe', xe] - simp_rw [mem_preimage, LocalHomeomorph.coe_trans_symm, LocalHomeomorph.symm_symm, + simp_rw [mem_preimage, PartialHomeomorph.coe_trans_symm, PartialHomeomorph.symm_symm, Function.comp_apply, e.left_inv hy] · refine' ((e'.eventually_nhds' _ xe').mpr <| e.eventually_left_inverse xe).mono fun y hy ↦ _ simp only [mfld_simps] @@ -278,7 +278,7 @@ theorem liftPropWithinAt_indep_chart_target_aux2 (g : H → M') {x : H} {s : Set exact (hgs.eventually <| f.eventually_left_inverse xf).mono fun y ↦ congr_arg f' #align structure_groupoid.local_invariant_prop.lift_prop_within_at_indep_chart_target_aux2 StructureGroupoid.LocalInvariantProp.liftPropWithinAt_indep_chart_target_aux2 -theorem liftPropWithinAt_indep_chart_target_aux {g : X → M'} {e : LocalHomeomorph X H} {x : X} +theorem liftPropWithinAt_indep_chart_target_aux {g : X → M'} {e : PartialHomeomorph X H} {x : X} {s : Set X} (xe : x ∈ e.source) (hf : f ∈ G'.maximalAtlas M') (xf : g x ∈ f.source) (hf' : f' ∈ G'.maximalAtlas M') (xf' : g x ∈ f'.source) (hgs : ContinuousWithinAt g s x) : P (f ∘ g ∘ e.symm) (e.symm ⁻¹' s) (e x) ↔ P (f' ∘ g ∘ e.symm) (e.symm ⁻¹' s) (e x) := by @@ -527,12 +527,12 @@ theorem liftPropOn_chart_symm [HasGroupoid M G] (hG : G.LocalInvariantProp G Q) #align structure_groupoid.local_invariant_prop.lift_prop_on_chart_symm StructureGroupoid.LocalInvariantProp.liftPropOn_chart_symm theorem liftPropAt_of_mem_groupoid (hG : G.LocalInvariantProp G Q) (hQ : ∀ y, Q id univ y) - {f : LocalHomeomorph H H} (hf : f ∈ G) {x : H} (hx : x ∈ f.source) : LiftPropAt Q f x := + {f : PartialHomeomorph H H} (hf : f ∈ G) {x : H} (hx : x ∈ f.source) : LiftPropAt Q f x := liftPropAt_of_mem_maximalAtlas hG hQ (G.mem_maximalAtlas_of_mem_groupoid hf) hx #align structure_groupoid.local_invariant_prop.lift_prop_at_of_mem_groupoid StructureGroupoid.LocalInvariantProp.liftPropAt_of_mem_groupoid theorem liftPropOn_of_mem_groupoid (hG : G.LocalInvariantProp G Q) (hQ : ∀ y, Q id univ y) - {f : LocalHomeomorph H H} (hf : f ∈ G) : LiftPropOn Q f f.source := + {f : PartialHomeomorph H H} (hf : f ∈ G) : LiftPropOn Q f f.source := liftPropOn_of_mem_maximalAtlas hG hQ (G.mem_maximalAtlas_of_mem_groupoid hf) #align structure_groupoid.local_invariant_prop.lift_prop_on_of_mem_groupoid StructureGroupoid.LocalInvariantProp.liftPropOn_of_mem_groupoid @@ -584,13 +584,13 @@ section LocalStructomorph variable (G) -open LocalHomeomorph +open PartialHomeomorph /-- A function from a model space `H` to itself is a local structomorphism, with respect to a structure groupoid `G` for `H`, relative to a set `s` in `H`, if for all points `x` in the set, the function agrees with a `G`-structomorphism on `s` in a neighbourhood of `x`. -/ def IsLocalStructomorphWithinAt (f : H → H) (s : Set H) (x : H) : Prop := - x ∈ s → ∃ e : LocalHomeomorph H H, e ∈ G ∧ EqOn f e.toFun (s ∩ e.source) ∧ x ∈ e.source + x ∈ s → ∃ e : PartialHomeomorph H H, e ∈ G ∧ EqOn f e.toFun (s ∩ e.source) ∧ x ∈ e.source #align structure_groupoid.is_local_structomorph_within_at StructureGroupoid.IsLocalStructomorphWithinAt /-- For a groupoid `G` which is `ClosedUnderRestriction`, being a local structomorphism is a local @@ -638,17 +638,17 @@ theorem isLocalStructomorphWithinAt_localInvariantProp [ClosedUnderRestriction G /-- A slight reformulation of `IsLocalStructomorphWithinAt` when `f` is a local homeomorph. This gives us an `e` that is defined on a subset of `f.source`. -/ -theorem _root_.LocalHomeomorph.isLocalStructomorphWithinAt_iff {G : StructureGroupoid H} - [ClosedUnderRestriction G] (f : LocalHomeomorph H H) {s : Set H} {x : H} +theorem _root_.PartialHomeomorph.isLocalStructomorphWithinAt_iff {G : StructureGroupoid H} + [ClosedUnderRestriction G] (f : PartialHomeomorph H H) {s : Set H} {x : H} (hx : x ∈ f.source ∪ sᶜ) : G.IsLocalStructomorphWithinAt (⇑f) s x ↔ - x ∈ s → ∃ e : LocalHomeomorph H H, + x ∈ s → ∃ e : PartialHomeomorph H H, e ∈ G ∧ e.source ⊆ f.source ∧ EqOn f (⇑e) (s ∩ e.source) ∧ x ∈ e.source := by constructor · intro hf h2x obtain ⟨e, he, hfe, hxe⟩ := hf h2x refine' ⟨e.restr f.source, closedUnderRestriction' he f.open_source, _, _, hxe, _⟩ - · simp_rw [LocalHomeomorph.restr_source] + · simp_rw [PartialHomeomorph.restr_source] refine' (inter_subset_right _ _).trans interior_subset · intro x' hx' exact hfe ⟨hx'.1, hx'.2.1⟩ @@ -657,32 +657,32 @@ theorem _root_.LocalHomeomorph.isLocalStructomorphWithinAt_iff {G : StructureGro · intro hf hx obtain ⟨e, he, _, hfe, hxe⟩ := hf hx exact ⟨e, he, hfe, hxe⟩ -#align local_homeomorph.is_local_structomorph_within_at_iff LocalHomeomorph.isLocalStructomorphWithinAt_iff +#align local_homeomorph.is_local_structomorph_within_at_iff PartialHomeomorph.isLocalStructomorphWithinAt_iff /-- A slight reformulation of `IsLocalStructomorphWithinAt` when `f` is a local homeomorph and the set we're considering is a superset of `f.source`. -/ -theorem _root_.LocalHomeomorph.isLocalStructomorphWithinAt_iff' {G : StructureGroupoid H} - [ClosedUnderRestriction G] (f : LocalHomeomorph H H) {s : Set H} {x : H} (hs : f.source ⊆ s) +theorem _root_.PartialHomeomorph.isLocalStructomorphWithinAt_iff' {G : StructureGroupoid H} + [ClosedUnderRestriction G] (f : PartialHomeomorph H H) {s : Set H} {x : H} (hs : f.source ⊆ s) (hx : x ∈ f.source ∪ sᶜ) : G.IsLocalStructomorphWithinAt (⇑f) s x ↔ - x ∈ s → ∃ e : LocalHomeomorph H H, + x ∈ s → ∃ e : PartialHomeomorph H H, e ∈ G ∧ e.source ⊆ f.source ∧ EqOn f (⇑e) e.source ∧ x ∈ e.source := by rw [f.isLocalStructomorphWithinAt_iff hx] refine' imp_congr_right fun _ ↦ exists_congr fun e ↦ and_congr_right fun _ ↦ _ refine' and_congr_right fun h2e ↦ _ rw [inter_eq_right.mpr (h2e.trans hs)] -#align local_homeomorph.is_local_structomorph_within_at_iff' LocalHomeomorph.isLocalStructomorphWithinAt_iff' +#align local_homeomorph.is_local_structomorph_within_at_iff' PartialHomeomorph.isLocalStructomorphWithinAt_iff' /-- A slight reformulation of `IsLocalStructomorphWithinAt` when `f` is a local homeomorph and the set we're considering is `f.source`. -/ -theorem _root_.LocalHomeomorph.isLocalStructomorphWithinAt_source_iff {G : StructureGroupoid H} - [ClosedUnderRestriction G] (f : LocalHomeomorph H H) {x : H} : +theorem _root_.PartialHomeomorph.isLocalStructomorphWithinAt_source_iff {G : StructureGroupoid H} + [ClosedUnderRestriction G] (f : PartialHomeomorph H H) {x : H} : G.IsLocalStructomorphWithinAt (⇑f) f.source x ↔ - x ∈ f.source → ∃ e : LocalHomeomorph H H, + x ∈ f.source → ∃ e : PartialHomeomorph H H, e ∈ G ∧ e.source ⊆ f.source ∧ EqOn f (⇑e) e.source ∧ x ∈ e.source := haveI : x ∈ f.source ∪ f.sourceᶜ := by simp_rw [union_compl_self, mem_univ] f.isLocalStructomorphWithinAt_iff' Subset.rfl this -#align local_homeomorph.is_local_structomorph_within_at_source_iff LocalHomeomorph.isLocalStructomorphWithinAt_source_iff +#align local_homeomorph.is_local_structomorph_within_at_source_iff PartialHomeomorph.isLocalStructomorphWithinAt_source_iff variable {H₁ : Type*} [TopologicalSpace H₁] {H₂ : Type*} [TopologicalSpace H₂] {H₃ : Type*} [TopologicalSpace H₃] [ChartedSpace H₁ H₂] [ChartedSpace H₂ H₃] {G₁ : StructureGroupoid H₁} @@ -703,15 +703,15 @@ theorem HasGroupoid.comp obtain ⟨φ, hφG₁, hφ, hφ_dom⟩ := LocalInvariantProp.liftPropOn_indep_chart (isLocalStructomorphWithinAt_localInvariantProp G₁) (G₁.subset_maximalAtlas hf) (G₁.subset_maximalAtlas hf') (H _ (G₂.compatible he he')) hxs' hxs - simp_rw [← LocalHomeomorph.coe_trans, LocalHomeomorph.trans_assoc] at hφ - simp_rw [LocalHomeomorph.trans_symm_eq_symm_trans_symm, LocalHomeomorph.trans_assoc] + simp_rw [← PartialHomeomorph.coe_trans, PartialHomeomorph.trans_assoc] at hφ + simp_rw [PartialHomeomorph.trans_symm_eq_symm_trans_symm, PartialHomeomorph.trans_assoc] have hs : IsOpen (f.symm ≫ₕ e.symm ≫ₕ e' ≫ₕ f').source := (f.symm ≫ₕ e.symm ≫ₕ e' ≫ₕ f').open_source refine' ⟨_, hs.inter φ.open_source, _, _⟩ · simp only [hx, hφ_dom, mfld_simps] · refine' G₁.eq_on_source (closedUnderRestriction' hφG₁ hs) _ - rw [LocalHomeomorph.restr_source_inter] - refine' LocalHomeomorph.Set.EqOn.restr_eqOn_source (hφ.mono _) + rw [PartialHomeomorph.restr_source_inter] + refine' PartialHomeomorph.Set.EqOn.restr_eqOn_source (hφ.mono _) mfld_set_tac } #align structure_groupoid.has_groupoid.comp StructureGroupoid.HasGroupoid.comp diff --git a/Mathlib/Geometry/Manifold/MFDeriv.lean b/Mathlib/Geometry/Manifold/MFDeriv.lean index 8ea9f73b508e3..9b5ba6a0fb688 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv.lean @@ -243,9 +243,9 @@ def MDifferentiable (f : M → M') := #align mdifferentiable MDifferentiable /-- Prop registering if a local homeomorphism is a local diffeomorphism on its source -/ -def LocalHomeomorph.MDifferentiable (f : LocalHomeomorph M M') := +def PartialHomeomorph.MDifferentiable (f : PartialHomeomorph M M') := MDifferentiableOn I I' f f.source ∧ MDifferentiableOn I' I f.symm f.target -#align local_homeomorph.mdifferentiable LocalHomeomorph.MDifferentiable +#align local_homeomorph.mdifferentiable PartialHomeomorph.MDifferentiable variable [SmoothManifoldWithCorners I M] [SmoothManifoldWithCorners I' M'] @@ -1804,7 +1804,7 @@ end ModelWithCorners section Charts -variable {e : LocalHomeomorph M H} +variable {e : PartialHomeomorph M H} theorem mdifferentiableAt_atlas (h : e ∈ atlas H M) {x : M} (hx : x ∈ e.source) : MDifferentiableAt I I e x := by @@ -1822,7 +1822,7 @@ theorem mdifferentiableAt_atlas (h : e ∈ atlas H M) {x : M} (hx : x ∈ e.sour simp only [mfld_simps] at B rw [inter_comm, differentiableWithinAt_inter] at B · simpa only [mfld_simps] - · apply IsOpen.mem_nhds ((LocalHomeomorph.open_source _).preimage I.continuous_symm) mem.1 + · apply IsOpen.mem_nhds ((PartialHomeomorph.open_source _).preimage I.continuous_symm) mem.1 #align mdifferentiable_at_atlas mdifferentiableAt_atlas theorem mdifferentiableOn_atlas (h : e ∈ atlas H M) : MDifferentiableOn I I e e.source := @@ -1844,7 +1844,7 @@ theorem mdifferentiableAt_atlas_symm (h : e ∈ atlas H M) {x : H} (hx : x ∈ e simp only [mfld_simps] at B rw [inter_comm, differentiableWithinAt_inter] at B · simpa only [mfld_simps] - · apply IsOpen.mem_nhds ((LocalHomeomorph.open_source _).preimage I.continuous_symm) mem.1 + · apply IsOpen.mem_nhds ((PartialHomeomorph.open_source _).preimage I.continuous_symm) mem.1 #align mdifferentiable_at_atlas_symm mdifferentiableAt_atlas_symm theorem mdifferentiableOn_atlas_symm (h : e ∈ atlas H M) : MDifferentiableOn I I e.symm e.target := @@ -1882,7 +1882,7 @@ theorem tangentMap_chart_symm {p : TangentBundle I M} {q : TangentBundle I H} rw [MDifferentiableAt.mfderiv (mdifferentiableAt_atlas_symm _ (chart_mem_atlas _ _) h)] simp only [ContinuousLinearMap.coe_coe, TangentBundle.chartAt, h, tangentBundleCore, mfld_simps, (· ∘ ·)] - -- `simp` fails to apply `LocalEquiv.prod_symm` with `ModelProd` + -- `simp` fails to apply `PartialEquiv.prod_symm` with `ModelProd` congr exact ((chartAt H (TotalSpace.proj p)).right_inv h).symm #align tangent_map_chart_symm tangentMap_chart_symm @@ -1893,7 +1893,7 @@ end SpecificFunctions /-! ### Differentiable local homeomorphisms -/ -namespace LocalHomeomorph.MDifferentiable +namespace PartialHomeomorph.MDifferentiable variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] {I : ModelWithCorners 𝕜 E H} {M : Type*} @@ -1901,19 +1901,19 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCom {H' : Type*} [TopologicalSpace H'] {I' : ModelWithCorners 𝕜 E' H'} {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] {E'' : Type*} [NormedAddCommGroup E''] [NormedSpace 𝕜 E''] {H'' : Type*} [TopologicalSpace H''] {I'' : ModelWithCorners 𝕜 E'' H''} - {M'' : Type*} [TopologicalSpace M''] [ChartedSpace H'' M''] {e : LocalHomeomorph M M'} - (he : e.MDifferentiable I I') {e' : LocalHomeomorph M' M''} + {M'' : Type*} [TopologicalSpace M''] [ChartedSpace H'' M''] {e : PartialHomeomorph M M'} + (he : e.MDifferentiable I I') {e' : PartialHomeomorph M' M''} nonrec theorem symm : e.symm.MDifferentiable I' I := he.symm -#align local_homeomorph.mdifferentiable.symm LocalHomeomorph.MDifferentiable.symm +#align local_homeomorph.mdifferentiable.symm PartialHomeomorph.MDifferentiable.symm protected theorem mdifferentiableAt {x : M} (hx : x ∈ e.source) : MDifferentiableAt I I' e x := (he.1 x hx).mdifferentiableAt (IsOpen.mem_nhds e.open_source hx) -#align local_homeomorph.mdifferentiable.mdifferentiable_at LocalHomeomorph.MDifferentiable.mdifferentiableAt +#align local_homeomorph.mdifferentiable.mdifferentiable_at PartialHomeomorph.MDifferentiable.mdifferentiableAt theorem mdifferentiableAt_symm {x : M'} (hx : x ∈ e.target) : MDifferentiableAt I' I e.symm x := (he.2 x hx).mdifferentiableAt (IsOpen.mem_nhds e.open_target hx) -#align local_homeomorph.mdifferentiable.mdifferentiable_at_symm LocalHomeomorph.MDifferentiable.mdifferentiableAt_symm +#align local_homeomorph.mdifferentiable.mdifferentiable_at_symm PartialHomeomorph.MDifferentiable.mdifferentiableAt_symm variable [SmoothManifoldWithCorners I M] [SmoothManifoldWithCorners I' M'] [SmoothManifoldWithCorners I'' M''] @@ -1929,13 +1929,13 @@ theorem symm_comp_deriv {x : M} (hx : x ∈ e.source) : apply Filter.EventuallyEq.mfderiv_eq have : e.source ∈ 𝓝 x := IsOpen.mem_nhds e.open_source hx exact Filter.mem_of_superset this (by mfld_set_tac) -#align local_homeomorph.mdifferentiable.symm_comp_deriv LocalHomeomorph.MDifferentiable.symm_comp_deriv +#align local_homeomorph.mdifferentiable.symm_comp_deriv PartialHomeomorph.MDifferentiable.symm_comp_deriv theorem comp_symm_deriv {x : M'} (hx : x ∈ e.target) : (mfderiv I I' e (e.symm x)).comp (mfderiv I' I e.symm x) = ContinuousLinearMap.id 𝕜 (TangentSpace I' x) := he.symm.symm_comp_deriv hx -#align local_homeomorph.mdifferentiable.comp_symm_deriv LocalHomeomorph.MDifferentiable.comp_symm_deriv +#align local_homeomorph.mdifferentiable.comp_symm_deriv PartialHomeomorph.MDifferentiable.comp_symm_deriv /-- The derivative of a differentiable local homeomorphism, as a continuous linear equivalence between the tangent spaces at `x` and `e x`. -/ @@ -1954,31 +1954,31 @@ protected def mfderiv {x : M} (hx : x ∈ e.source) : TangentSpace I x ≃L[𝕜 conv_rhs => rw [← this, ← he.comp_symm_deriv (e.map_source hx)] rw [e.left_inv hx] rfl } -#align local_homeomorph.mdifferentiable.mfderiv LocalHomeomorph.MDifferentiable.mfderiv +#align local_homeomorph.mdifferentiable.mfderiv PartialHomeomorph.MDifferentiable.mfderiv theorem mfderiv_bijective {x : M} (hx : x ∈ e.source) : Function.Bijective (mfderiv I I' e x) := (he.mfderiv hx).bijective -#align local_homeomorph.mdifferentiable.mfderiv_bijective LocalHomeomorph.MDifferentiable.mfderiv_bijective +#align local_homeomorph.mdifferentiable.mfderiv_bijective PartialHomeomorph.MDifferentiable.mfderiv_bijective theorem mfderiv_injective {x : M} (hx : x ∈ e.source) : Function.Injective (mfderiv I I' e x) := (he.mfderiv hx).injective -#align local_homeomorph.mdifferentiable.mfderiv_injective LocalHomeomorph.MDifferentiable.mfderiv_injective +#align local_homeomorph.mdifferentiable.mfderiv_injective PartialHomeomorph.MDifferentiable.mfderiv_injective theorem mfderiv_surjective {x : M} (hx : x ∈ e.source) : Function.Surjective (mfderiv I I' e x) := (he.mfderiv hx).surjective -#align local_homeomorph.mdifferentiable.mfderiv_surjective LocalHomeomorph.MDifferentiable.mfderiv_surjective +#align local_homeomorph.mdifferentiable.mfderiv_surjective PartialHomeomorph.MDifferentiable.mfderiv_surjective theorem ker_mfderiv_eq_bot {x : M} (hx : x ∈ e.source) : LinearMap.ker (mfderiv I I' e x) = ⊥ := (he.mfderiv hx).toLinearEquiv.ker -#align local_homeomorph.mdifferentiable.ker_mfderiv_eq_bot LocalHomeomorph.MDifferentiable.ker_mfderiv_eq_bot +#align local_homeomorph.mdifferentiable.ker_mfderiv_eq_bot PartialHomeomorph.MDifferentiable.ker_mfderiv_eq_bot theorem range_mfderiv_eq_top {x : M} (hx : x ∈ e.source) : LinearMap.range (mfderiv I I' e x) = ⊤ := (he.mfderiv hx).toLinearEquiv.range -#align local_homeomorph.mdifferentiable.range_mfderiv_eq_top LocalHomeomorph.MDifferentiable.range_mfderiv_eq_top +#align local_homeomorph.mdifferentiable.range_mfderiv_eq_top PartialHomeomorph.MDifferentiable.range_mfderiv_eq_top theorem range_mfderiv_eq_univ {x : M} (hx : x ∈ e.source) : range (mfderiv I I' e x) = univ := (he.mfderiv_surjective hx).range_eq -#align local_homeomorph.mdifferentiable.range_mfderiv_eq_univ LocalHomeomorph.MDifferentiable.range_mfderiv_eq_univ +#align local_homeomorph.mdifferentiable.range_mfderiv_eq_univ PartialHomeomorph.MDifferentiable.range_mfderiv_eq_univ theorem trans (he' : e'.MDifferentiable I' I'') : (e.trans e').MDifferentiable I I'' := by constructor @@ -1991,9 +1991,9 @@ theorem trans (he' : e'.MDifferentiable I' I'') : (e.trans e').MDifferentiable I exact ((he.symm.mdifferentiableAt hx.2).comp _ (he'.symm.mdifferentiableAt hx.1)).mdifferentiableWithinAt -#align local_homeomorph.mdifferentiable.trans LocalHomeomorph.MDifferentiable.trans +#align local_homeomorph.mdifferentiable.trans PartialHomeomorph.MDifferentiable.trans -end LocalHomeomorph.MDifferentiable +end PartialHomeomorph.MDifferentiable /-! ### Differentiability of `extChartAt` -/ @@ -2067,7 +2067,7 @@ theorem UniqueMDiffOn.image_denseRange (hs : UniqueMDiffOn I s) {f : M → M'} hs.image_denseRange' (fun x hx ↦ (hf x hx).hasMFDerivWithinAt) hd protected theorem UniqueMDiffWithinAt.preimage_localHomeomorph (hs : UniqueMDiffWithinAt I s x) - {e : LocalHomeomorph M M'} (he : e.MDifferentiable I I') (hx : x ∈ e.source) : + {e : PartialHomeomorph M M'} (he : e.MDifferentiable I I') (hx : x ∈ e.source) : UniqueMDiffWithinAt I' (e.target ∩ e.symm ⁻¹' s) (e x) := by rw [← e.image_source_inter_eq', inter_comm] exact (hs.inter (e.open_source.mem_nhds hx)).image_denseRange @@ -2076,7 +2076,7 @@ protected theorem UniqueMDiffWithinAt.preimage_localHomeomorph (hs : UniqueMDiff /-- If a set has the unique differential property, then its image under a local diffeomorphism also has the unique differential property. -/ -theorem UniqueMDiffOn.uniqueMDiffOn_preimage (hs : UniqueMDiffOn I s) {e : LocalHomeomorph M M'} +theorem UniqueMDiffOn.uniqueMDiffOn_preimage (hs : UniqueMDiffOn I s) {e : PartialHomeomorph M M'} (he : e.MDifferentiable I I') : UniqueMDiffOn I' (e.target ∩ e.symm ⁻¹' s) := fun _x hx ↦ e.right_inv hx.1 ▸ (hs _ hx.2).preimage_localHomeomorph he (e.map_target hx.1) #align unique_mdiff_on.unique_mdiff_on_preimage UniqueMDiffOn.uniqueMDiffOn_preimage @@ -2088,7 +2088,7 @@ theorem UniqueMDiffOn.uniqueDiffOn_target_inter (hs : UniqueMDiffOn I s) (x : M) -- this is just a reformulation of `UniqueMDiffOn.uniqueMDiffOn_preimage`, using as `e` -- the local chart at `x`. apply UniqueMDiffOn.uniqueDiffOn - rw [← LocalEquiv.image_source_inter_eq', inter_comm, extChartAt_source] + rw [← PartialEquiv.image_source_inter_eq', inter_comm, extChartAt_source] exact (hs.inter (chartAt H x).open_source).image_denseRange' (fun y hy ↦ hasMFDerivWithinAt_extChartAt I hy.2) fun y hy ↦ ((mdifferentiable_chart _ _).mfderiv_surjective hy.2).denseRange @@ -2116,7 +2116,7 @@ variable {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] {Z : M → Type [∀ b, Module 𝕜 (Z b)] [FiberBundle F Z] [VectorBundle 𝕜 F Z] [SmoothVectorBundle F Z I] theorem Trivialization.mdifferentiable (e : Trivialization F (π F Z)) [MemTrivializationAtlas e] : - e.toLocalHomeomorph.MDifferentiable (I.prod 𝓘(𝕜, F)) (I.prod 𝓘(𝕜, F)) := + e.toPartialHomeomorph.MDifferentiable (I.prod 𝓘(𝕜, F)) (I.prod 𝓘(𝕜, F)) := ⟨(e.smoothOn I).mdifferentiableOn, (e.smoothOn_symm I).mdifferentiableOn⟩ theorem UniqueMDiffWithinAt.smooth_bundle_preimage {p : TotalSpace F Z} @@ -2130,7 +2130,7 @@ theorem UniqueMDiffWithinAt.smooth_bundle_preimage {p : TotalSpace F Z} rw [← e.left_inv hp] refine (this.preimage_localHomeomorph e.mdifferentiable.symm (e.map_source hp)).mono ?_ rintro y ⟨hy, hys, -⟩ - rwa [LocalHomeomorph.symm_symm, e.coe_coe, e.coe_fst hy] at hys + rwa [PartialHomeomorph.symm_symm, e.coe_coe, e.coe_fst hy] at hys variable (Z) diff --git a/Mathlib/Geometry/Manifold/PartitionOfUnity.lean b/Mathlib/Geometry/Manifold/PartitionOfUnity.lean index 059b502b06fe5..de3cdb468ed3b 100644 --- a/Mathlib/Geometry/Manifold/PartitionOfUnity.lean +++ b/Mathlib/Geometry/Manifold/PartitionOfUnity.lean @@ -642,7 +642,7 @@ theorem IsOpen.exists_msmooth_support_eq (hs : IsOpen s) : Smooth I 𝓘(ℝ) g ∧ Set.range g ⊆ Set.Icc 0 1 := by intro i apply IsOpen.exists_msmooth_support_eq_aux - exact LocalHomeomorph.isOpen_inter_preimage_symm _ hs + exact PartialHomeomorph.isOpen_inter_preimage_symm _ hs choose g g_supp g_diff hg using A have h'g : ∀ c x, 0 ≤ g c x := fun c x ↦ (hg c (mem_range_self (f := g c) x)).1 have h''g : ∀ c x, 0 ≤ f c x * g c (chartAt H c x) := diff --git a/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean b/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean index 40c7bb08fe3ac..000615ba8de8d 100644 --- a/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean +++ b/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean @@ -141,9 +141,9 @@ define a smooth manifold with model space `H`, and model vector space `E`. @[ext] -- porting note: was nolint has_nonempty_instance structure ModelWithCorners (𝕜 : Type*) [NontriviallyNormedField 𝕜] (E : Type*) [NormedAddCommGroup E] [NormedSpace 𝕜 E] (H : Type*) [TopologicalSpace H] extends - LocalEquiv H E where + PartialEquiv H E where source_eq : source = univ - unique_diff' : UniqueDiffOn 𝕜 toLocalEquiv.target + unique_diff' : UniqueDiffOn 𝕜 toPartialEquiv.target continuous_toFun : Continuous toFun := by continuity continuous_invFun : Continuous invFun := by continuity #align model_with_corners ModelWithCorners @@ -153,7 +153,7 @@ attribute [simp, mfld_simps] ModelWithCorners.source_eq /-- A vector space is a model with corners. -/ def modelWithCornersSelf (𝕜 : Type*) [NontriviallyNormedField 𝕜] (E : Type*) [NormedAddCommGroup E] [NormedSpace 𝕜 E] : ModelWithCorners 𝕜 E E where - toLocalEquiv := LocalEquiv.refl E + toPartialEquiv := PartialEquiv.refl E source_eq := rfl unique_diff' := uniqueDiffOn_univ continuous_toFun := continuous_id @@ -171,15 +171,15 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCom namespace ModelWithCorners /-- Coercion of a model with corners to a function. We don't use `e.toFun` because it is actually -`e.toLocalEquiv.toFun`, so `simp` will apply lemmas about `toLocalEquiv`. While we may want to +`e.toPartialEquiv.toFun`, so `simp` will apply lemmas about `toPartialEquiv`. While we may want to switch to this behavior later, doing it mid-port will break a lot of proofs. -/ @[coe] def toFun' (e : ModelWithCorners 𝕜 E H) : H → E := e.toFun instance : CoeFun (ModelWithCorners 𝕜 E H) fun _ => H → E := ⟨toFun'⟩ /-- The inverse to a model with corners, only registered as a local equiv. -/ -protected def symm : LocalEquiv E H := - I.toLocalEquiv.symm +protected def symm : PartialEquiv E H := + I.toPartialEquiv.symm #align model_with_corners.symm ModelWithCorners.symm /-- See Note [custom simps projection]. We need to specify this projection explicitly in this case, @@ -199,23 +199,23 @@ initialize_simps_projections ModelWithCorners (toFun → apply, invFun → symm_ -- Register a few lemmas to make sure that `simp` puts expressions in normal form @[simp, mfld_simps] -theorem toLocalEquiv_coe : (I.toLocalEquiv : H → E) = I := +theorem toPartialEquiv_coe : (I.toPartialEquiv : H → E) = I := rfl -#align model_with_corners.to_local_equiv_coe ModelWithCorners.toLocalEquiv_coe +#align model_with_corners.to_local_equiv_coe ModelWithCorners.toPartialEquiv_coe @[simp, mfld_simps] -theorem mk_coe (e : LocalEquiv H E) (a b c d) : +theorem mk_coe (e : PartialEquiv H E) (a b c d) : ((ModelWithCorners.mk e a b c d : ModelWithCorners 𝕜 E H) : H → E) = (e : H → E) := rfl #align model_with_corners.mk_coe ModelWithCorners.mk_coe @[simp, mfld_simps] -theorem toLocalEquiv_coe_symm : (I.toLocalEquiv.symm : E → H) = I.symm := +theorem toPartialEquiv_coe_symm : (I.toPartialEquiv.symm : E → H) = I.symm := rfl -#align model_with_corners.to_local_equiv_coe_symm ModelWithCorners.toLocalEquiv_coe_symm +#align model_with_corners.to_local_equiv_coe_symm ModelWithCorners.toPartialEquiv_coe_symm @[simp, mfld_simps] -theorem mk_symm (e : LocalEquiv H E) (a b c d) : +theorem mk_symm (e : PartialEquiv H E) (a b c d) : (ModelWithCorners.mk e a b c d : ModelWithCorners 𝕜 E H).symm = e.symm := rfl #align model_with_corners.mk_symm ModelWithCorners.mk_symm @@ -291,9 +291,9 @@ theorem preimage_image (s : Set H) : I ⁻¹' (I '' s) = s := #align model_with_corners.preimage_image ModelWithCorners.preimage_image protected theorem image_eq (s : Set H) : I '' s = I.symm ⁻¹' s ∩ range I := by - refine' (I.toLocalEquiv.image_eq_target_inter_inv_preimage _).trans _ + refine' (I.toPartialEquiv.image_eq_target_inter_inv_preimage _).trans _ · rw [I.source_eq]; exact subset_univ _ - · rw [inter_comm, I.target_eq, I.toLocalEquiv_coe_symm] + · rw [inter_comm, I.target_eq, I.toPartialEquiv_coe_symm] #align model_with_corners.image_eq ModelWithCorners.image_eq protected theorem closedEmbedding : ClosedEmbedding I := @@ -330,7 +330,7 @@ theorem unique_diff_preimage {s : Set H} (hs : IsOpen s) : exact I.unique_diff.inter (hs.preimage I.continuous_invFun) #align model_with_corners.unique_diff_preimage ModelWithCorners.unique_diff_preimage -theorem unique_diff_preimage_source {β : Type*} [TopologicalSpace β] {e : LocalHomeomorph H β} : +theorem unique_diff_preimage_source {β : Type*} [TopologicalSpace β] {e : PartialHomeomorph H β} : UniqueDiffOn 𝕜 (I.symm ⁻¹' e.source ∩ range I) := I.unique_diff_preimage e.open_source #align model_with_corners.unique_diff_preimage_source ModelWithCorners.unique_diff_preimage_source @@ -376,7 +376,7 @@ variable (𝕜 E) /-- In the trivial model with corners, the associated local equiv is the identity. -/ @[simp, mfld_simps] -theorem modelWithCornersSelf_localEquiv : 𝓘(𝕜, E).toLocalEquiv = LocalEquiv.refl E := +theorem modelWithCornersSelf_localEquiv : 𝓘(𝕜, E).toPartialEquiv = PartialEquiv.refl E := rfl #align model_with_corners_self_local_equiv modelWithCornersSelf_localEquiv @@ -407,7 +407,7 @@ def ModelWithCorners.prod {𝕜 : Type u} [NontriviallyNormedField 𝕜] {E : Ty (I : ModelWithCorners 𝕜 E H) {E' : Type v'} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {H' : Type w'} [TopologicalSpace H'] (I' : ModelWithCorners 𝕜 E' H') : ModelWithCorners 𝕜 (E × E') (ModelProd H H') := - { I.toLocalEquiv.prod I'.toLocalEquiv with + { I.toPartialEquiv.prod I'.toPartialEquiv with toFun := fun x => (I x.1, I' x.2) invFun := fun x => (I.symm x.1, I'.symm x.2) source := { x | x.1 ∈ I.source ∧ x.2 ∈ I'.source } @@ -424,7 +424,7 @@ def ModelWithCorners.pi {𝕜 : Type u} [NontriviallyNormedField 𝕜] {ι : Typ {E : ι → Type w} [∀ i, NormedAddCommGroup (E i)] [∀ i, NormedSpace 𝕜 (E i)] {H : ι → Type u'} [∀ i, TopologicalSpace (H i)] (I : ∀ i, ModelWithCorners 𝕜 (E i) (H i)) : ModelWithCorners 𝕜 (∀ i, E i) (ModelPi H) where - toLocalEquiv := LocalEquiv.pi fun i => (I i).toLocalEquiv + toPartialEquiv := PartialEquiv.pi fun i => (I i).toPartialEquiv source_eq := by simp only [pi_univ, mfld_simps] unique_diff' := UniqueDiffOn.pi ι E _ _ fun i _ => (I i).unique_diff' continuous_toFun := continuous_pi fun i => (I i).continuous.comp (continuous_apply i) @@ -448,10 +448,10 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCom {J : ModelWithCorners 𝕜 F G} @[simp, mfld_simps] -theorem modelWithCorners_prod_toLocalEquiv : - (I.prod J).toLocalEquiv = I.toLocalEquiv.prod J.toLocalEquiv := +theorem modelWithCorners_prod_toPartialEquiv : + (I.prod J).toPartialEquiv = I.toPartialEquiv.prod J.toPartialEquiv := rfl -#align model_with_corners_prod_to_local_equiv modelWithCorners_prod_toLocalEquiv +#align model_with_corners_prod_to_local_equiv modelWithCorners_prod_toPartialEquiv @[simp, mfld_simps] theorem modelWithCorners_prod_coe (I : ModelWithCorners 𝕜 E H) (I' : ModelWithCorners 𝕜 E' H') : @@ -603,7 +603,7 @@ variable (n) /-- An identity local homeomorphism belongs to the `C^n` groupoid. -/ theorem ofSet_mem_contDiffGroupoid {s : Set H} (hs : IsOpen s) : - LocalHomeomorph.ofSet s hs ∈ contDiffGroupoid n I := by + PartialHomeomorph.ofSet s hs ∈ contDiffGroupoid n I := by rw [contDiffGroupoid, mem_groupoid_of_pregroupoid] suffices h : ContDiffOn 𝕜 n (I ∘ I.symm) (I.symm ⁻¹' s ∩ range I) · simp [h] @@ -613,10 +613,10 @@ theorem ofSet_mem_contDiffGroupoid {s : Set H} (hs : IsOpen s) : /-- The composition of a local homeomorphism from `H` to `M` and its inverse belongs to the `C^n` groupoid. -/ -theorem symm_trans_mem_contDiffGroupoid (e : LocalHomeomorph M H) : +theorem symm_trans_mem_contDiffGroupoid (e : PartialHomeomorph M H) : e.symm.trans e ∈ contDiffGroupoid n I := - haveI : e.symm.trans e ≈ LocalHomeomorph.ofSet e.target e.open_target := - LocalHomeomorph.trans_symm_self _ + haveI : e.symm.trans e ≈ PartialHomeomorph.ofSet e.target e.open_target := + PartialHomeomorph.trans_symm_self _ StructureGroupoid.eq_on_source _ (ofSet_mem_contDiffGroupoid n I e.open_target) this #align symm_trans_mem_cont_diff_groupoid symm_trans_mem_contDiffGroupoid @@ -624,12 +624,12 @@ variable {E' H' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] [Topologi /-- The product of two smooth local homeomorphisms is smooth. -/ theorem contDiffGroupoid_prod {I : ModelWithCorners 𝕜 E H} {I' : ModelWithCorners 𝕜 E' H'} - {e : LocalHomeomorph H H} {e' : LocalHomeomorph H' H'} (he : e ∈ contDiffGroupoid ⊤ I) + {e : PartialHomeomorph H H} {e' : PartialHomeomorph H' H'} (he : e ∈ contDiffGroupoid ⊤ I) (he' : e' ∈ contDiffGroupoid ⊤ I') : e.prod e' ∈ contDiffGroupoid ⊤ (I.prod I') := by cases' he with he he_symm cases' he' with he' he'_symm simp only at he he_symm he' he'_symm - constructor <;> simp only [LocalEquiv.prod_source, LocalHomeomorph.prod_toLocalEquiv] + constructor <;> simp only [PartialEquiv.prod_source, PartialHomeomorph.prod_toPartialEquiv] · have h3 := ContDiffOn.prod_map he he' rw [← I.image_eq, ← I'.image_eq, prod_image_image_eq] at h3 rw [← (I.prod I').image_eq] @@ -746,15 +746,15 @@ def analyticGroupoid : StructureGroupoid H := /-- An identity local homeomorphism belongs to the analytic groupoid. -/ theorem ofSet_mem_analyticGroupoid {s : Set H} (hs : IsOpen s) : - LocalHomeomorph.ofSet s hs ∈ analyticGroupoid I := by + PartialHomeomorph.ofSet s hs ∈ analyticGroupoid I := by rw [analyticGroupoid] refine And.intro (ofSet_mem_contDiffGroupoid ∞ I hs) ?_ apply mem_groupoid_of_pregroupoid.mpr suffices h : AnalyticOn 𝕜 (I ∘ I.symm) (I.symm ⁻¹' s ∩ interior (range I)) ∧ (I.symm ⁻¹' s ∩ interior (range I)).image (I ∘ I.symm) ⊆ interior (range I) - · simp only [LocalHomeomorph.ofSet_apply, left_id, LocalHomeomorph.ofSet_toLocalEquiv, - LocalEquiv.ofSet_source, h, comp_apply, mem_range, image_subset_iff, true_and, - LocalHomeomorph.ofSet_symm, LocalEquiv.ofSet_target, and_self] + · simp only [PartialHomeomorph.ofSet_apply, left_id, PartialHomeomorph.ofSet_toPartialEquiv, + PartialEquiv.ofSet_source, h, comp_apply, mem_range, image_subset_iff, true_and, + PartialHomeomorph.ofSet_symm, PartialEquiv.ofSet_target, and_self] intro x hx refine mem_preimage.mpr ?_ rw [← I.right_inv (interior_subset hx.right)] at hx @@ -772,10 +772,10 @@ theorem ofSet_mem_analyticGroupoid {s : Set H} (hs : IsOpen s) : /-- The composition of a local homeomorphism from `H` to `M` and its inverse belongs to the analytic groupoid. -/ -theorem symm_trans_mem_analyticGroupoid (e : LocalHomeomorph M H) : +theorem symm_trans_mem_analyticGroupoid (e : PartialHomeomorph M H) : e.symm.trans e ∈ analyticGroupoid I := - haveI : e.symm.trans e ≈ LocalHomeomorph.ofSet e.target e.open_target := - LocalHomeomorph.trans_symm_self _ + haveI : e.symm.trans e ≈ PartialHomeomorph.ofSet e.target e.open_target := + PartialHomeomorph.trans_symm_self _ StructureGroupoid.eq_on_source _ (ofSet_mem_analyticGroupoid I e.open_target) this /-- The analytic groupoid is closed under restriction. -/ @@ -790,7 +790,7 @@ instance : ClosedUnderRestriction (analyticGroupoid I) := /-- The analytic groupoid on a boundaryless charted space modeled on a complete vector space consists of the local homeomorphisms which are analytic and have analytic inverse. -/ theorem mem_analyticGroupoid_of_boundaryless [CompleteSpace E] [I.Boundaryless] - (e : LocalHomeomorph H H) : + (e : PartialHomeomorph H H) : e ∈ analyticGroupoid I ↔ AnalyticOn 𝕜 (I ∘ e ∘ I.symm) (I '' e.source) ∧ AnalyticOn 𝕜 (I ∘ e.symm ∘ I.symm) (I '' e.target) := by apply Iff.intro @@ -830,7 +830,7 @@ theorem SmoothManifoldWithCorners.mk' {𝕜 : Type*} [NontriviallyNormedField theorem smoothManifoldWithCorners_of_contDiffOn {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) (M : Type*) [TopologicalSpace M] [ChartedSpace H M] - (h : ∀ e e' : LocalHomeomorph M H, e ∈ atlas H M → e' ∈ atlas H M → + (h : ∀ e e' : PartialHomeomorph M H, e ∈ atlas H M → e' ∈ atlas H M → ContDiffOn 𝕜 ⊤ (I ∘ e.symm ≫ₕ e' ∘ I.symm) (I.symm ⁻¹' (e.symm ≫ₕ e').source ∩ range I)) : SmoothManifoldWithCorners I M where compatible := by @@ -875,7 +875,7 @@ theorem chart_mem_maximalAtlas [SmoothManifoldWithCorners I M] (x : M) : variable {I} -theorem compatible_of_mem_maximalAtlas {e e' : LocalHomeomorph M H} (he : e ∈ maximalAtlas I M) +theorem compatible_of_mem_maximalAtlas {e e' : PartialHomeomorph M H} (he : e ∈ maximalAtlas I M) (he' : e' ∈ maximalAtlas I M) : e.symm.trans e' ∈ contDiffGroupoid ∞ I := StructureGroupoid.compatible_of_mem_maximalAtlas he he' #align smooth_manifold_with_corners.compatible_of_mem_maximal_atlas SmoothManifoldWithCorners.compatible_of_mem_maximalAtlas @@ -889,7 +889,7 @@ instance prod {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedA [SmoothManifoldWithCorners I' M'] : SmoothManifoldWithCorners (I.prod I') (M × M') where compatible := by rintro f g ⟨f1, f2, hf1, hf2, rfl⟩ ⟨g1, g2, hg1, hg2, rfl⟩ - rw [LocalHomeomorph.prod_symm, LocalHomeomorph.prod_trans] + rw [PartialHomeomorph.prod_symm, PartialHomeomorph.prod_trans] have h1 := (contDiffGroupoid ⊤ I).compatible hf1 hg1 have h2 := (contDiffGroupoid ⊤ I').compatible hf2 hg2 exact contDiffGroupoid_prod h1 h2 @@ -897,21 +897,21 @@ instance prod {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedA end SmoothManifoldWithCorners -theorem LocalHomeomorph.singleton_smoothManifoldWithCorners {𝕜 : Type*} [NontriviallyNormedField 𝕜] - {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] - (I : ModelWithCorners 𝕜 E H) {M : Type*} [TopologicalSpace M] (e : LocalHomeomorph M H) - (h : e.source = Set.univ) : +theorem PartialHomeomorph.singleton_smoothManifoldWithCorners + {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] + {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) + {M : Type*} [TopologicalSpace M] (e : PartialHomeomorph M H) (h : e.source = Set.univ) : @SmoothManifoldWithCorners 𝕜 _ E _ _ H _ I M _ (e.singletonChartedSpace h) := @SmoothManifoldWithCorners.mk' _ _ _ _ _ _ _ _ _ _ (id _) <| e.singleton_hasGroupoid h (contDiffGroupoid ∞ I) -#align local_homeomorph.singleton_smooth_manifold_with_corners LocalHomeomorph.singleton_smoothManifoldWithCorners +#align local_homeomorph.singleton_smooth_manifold_with_corners PartialHomeomorph.singleton_smoothManifoldWithCorners theorem OpenEmbedding.singleton_smoothManifoldWithCorners {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) {M : Type*} [TopologicalSpace M] [Nonempty M] {f : M → H} (h : OpenEmbedding f) : @SmoothManifoldWithCorners 𝕜 _ E _ _ H _ I M _ h.singletonChartedSpace := - (h.toLocalHomeomorph f).singleton_smoothManifoldWithCorners I (by simp) + (h.toPartialHomeomorph f).singleton_smoothManifoldWithCorners I (by simp) #align open_embedding.singleton_smooth_manifold_with_corners OpenEmbedding.singleton_smoothManifoldWithCorners namespace TopologicalSpace.Opens @@ -932,7 +932,7 @@ section ExtendedCharts open scoped Topology variable {𝕜 E M H E' M' H' : Type*} [NontriviallyNormedField 𝕜] [NormedAddCommGroup E] - [NormedSpace 𝕜 E] [TopologicalSpace H] [TopologicalSpace M] (f f' : LocalHomeomorph M H) + [NormedSpace 𝕜 E] [TopologicalSpace H] [TopologicalSpace M] (f f' : PartialHomeomorph M H) (I : ModelWithCorners 𝕜 E H) [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] [TopologicalSpace H'] [TopologicalSpace M'] (I' : ModelWithCorners 𝕜 E' H') (x : M) {s t : Set M} @@ -941,51 +941,51 @@ variable {𝕜 E M H E' M' H' : Type*} [NontriviallyNormedField 𝕜] [NormedAdd In a smooth manifold with corners, the model space is the space `H`. However, we will also need to use extended charts taking values in the model vector space `E`. These extended charts are -not `LocalHomeomorph` as the target is not open in `E` in general, but we can still register them -as `LocalEquiv`. +not `PartialHomeomorph` as the target is not open in `E` in general, but we can still register them +as `PartialEquiv`. -/ -namespace LocalHomeomorph +namespace PartialHomeomorph /-- Given a chart `f` on a manifold with corners, `f.extend I` is the extended chart to the model vector space. -/ @[simp, mfld_simps] -def extend : LocalEquiv M E := - f.toLocalEquiv ≫ I.toLocalEquiv -#align local_homeomorph.extend LocalHomeomorph.extend +def extend : PartialEquiv M E := + f.toPartialEquiv ≫ I.toPartialEquiv +#align local_homeomorph.extend PartialHomeomorph.extend theorem extend_coe : ⇑(f.extend I) = I ∘ f := rfl -#align local_homeomorph.extend_coe LocalHomeomorph.extend_coe +#align local_homeomorph.extend_coe PartialHomeomorph.extend_coe theorem extend_coe_symm : ⇑(f.extend I).symm = f.symm ∘ I.symm := rfl -#align local_homeomorph.extend_coe_symm LocalHomeomorph.extend_coe_symm +#align local_homeomorph.extend_coe_symm PartialHomeomorph.extend_coe_symm theorem extend_source : (f.extend I).source = f.source := by - rw [extend, LocalEquiv.trans_source, I.source_eq, preimage_univ, inter_univ] -#align local_homeomorph.extend_source LocalHomeomorph.extend_source + rw [extend, PartialEquiv.trans_source, I.source_eq, preimage_univ, inter_univ] +#align local_homeomorph.extend_source PartialHomeomorph.extend_source theorem isOpen_extend_source : IsOpen (f.extend I).source := by rw [extend_source] exact f.open_source -#align local_homeomorph.is_open_extend_source LocalHomeomorph.isOpen_extend_source +#align local_homeomorph.is_open_extend_source PartialHomeomorph.isOpen_extend_source theorem extend_target : (f.extend I).target = I.symm ⁻¹' f.target ∩ range I := by - simp_rw [extend, LocalEquiv.trans_target, I.target_eq, I.toLocalEquiv_coe_symm, inter_comm] -#align local_homeomorph.extend_target LocalHomeomorph.extend_target + simp_rw [extend, PartialEquiv.trans_target, I.target_eq, I.toPartialEquiv_coe_symm, inter_comm] +#align local_homeomorph.extend_target PartialHomeomorph.extend_target theorem mapsTo_extend (hs : s ⊆ f.source) : MapsTo (f.extend I) s ((f.extend I).symm ⁻¹' s ∩ range I) := by rw [mapsTo', extend_coe, extend_coe_symm, preimage_comp, ← I.image_eq, image_comp, f.image_eq_target_inter_inv_preimage hs] exact image_subset _ (inter_subset_right _ _) -#align local_homeomorph.maps_to_extend LocalHomeomorph.mapsTo_extend +#align local_homeomorph.maps_to_extend PartialHomeomorph.mapsTo_extend theorem extend_left_inv {x : M} (hxf : x ∈ f.source) : (f.extend I).symm (f.extend I x) = x := (f.extend I).left_inv <| by rwa [f.extend_source] -#align local_homeomorph.extend_left_inv LocalHomeomorph.extend_left_inv +#align local_homeomorph.extend_left_inv PartialHomeomorph.extend_left_inv /-- Variant of `f.extend_left_inv I`, stated in terms of images. -/ lemma extend_left_inv' (ht: t ⊆ f.source) : ((f.extend I).symm ∘ (f.extend I)) '' t = t := @@ -993,71 +993,71 @@ lemma extend_left_inv' (ht: t ⊆ f.source) : ((f.extend I).symm ∘ (f.extend I theorem extend_source_mem_nhds {x : M} (h : x ∈ f.source) : (f.extend I).source ∈ 𝓝 x := (isOpen_extend_source f I).mem_nhds <| by rwa [f.extend_source I] -#align local_homeomorph.extend_source_mem_nhds LocalHomeomorph.extend_source_mem_nhds +#align local_homeomorph.extend_source_mem_nhds PartialHomeomorph.extend_source_mem_nhds theorem extend_source_mem_nhdsWithin {x : M} (h : x ∈ f.source) : (f.extend I).source ∈ 𝓝[s] x := mem_nhdsWithin_of_mem_nhds <| extend_source_mem_nhds f I h -#align local_homeomorph.extend_source_mem_nhds_within LocalHomeomorph.extend_source_mem_nhdsWithin +#align local_homeomorph.extend_source_mem_nhds_within PartialHomeomorph.extend_source_mem_nhdsWithin theorem continuousOn_extend : ContinuousOn (f.extend I) (f.extend I).source := by refine' I.continuous.comp_continuousOn _ rw [extend_source] exact f.continuousOn -#align local_homeomorph.continuous_on_extend LocalHomeomorph.continuousOn_extend +#align local_homeomorph.continuous_on_extend PartialHomeomorph.continuousOn_extend theorem continuousAt_extend {x : M} (h : x ∈ f.source) : ContinuousAt (f.extend I) x := (continuousOn_extend f I).continuousAt <| extend_source_mem_nhds f I h -#align local_homeomorph.continuous_at_extend LocalHomeomorph.continuousAt_extend +#align local_homeomorph.continuous_at_extend PartialHomeomorph.continuousAt_extend theorem map_extend_nhds {x : M} (hy : x ∈ f.source) : map (f.extend I) (𝓝 x) = 𝓝[range I] f.extend I x := by rwa [extend_coe, comp_apply, ← I.map_nhds_eq, ← f.map_nhds_eq, map_map] -#align local_homeomorph.map_extend_nhds LocalHomeomorph.map_extend_nhds +#align local_homeomorph.map_extend_nhds PartialHomeomorph.map_extend_nhds theorem extend_target_mem_nhdsWithin {y : M} (hy : y ∈ f.source) : (f.extend I).target ∈ 𝓝[range I] f.extend I y := by - rw [← LocalEquiv.image_source_eq_target, ← map_extend_nhds f I hy] + rw [← PartialEquiv.image_source_eq_target, ← map_extend_nhds f I hy] exact image_mem_map (extend_source_mem_nhds _ _ hy) -#align local_homeomorph.extend_target_mem_nhds_within LocalHomeomorph.extend_target_mem_nhdsWithin +#align local_homeomorph.extend_target_mem_nhds_within PartialHomeomorph.extend_target_mem_nhdsWithin theorem extend_target_subset_range : (f.extend I).target ⊆ range I := by simp only [mfld_simps] -#align local_homeomorph.extend_target_subset_range LocalHomeomorph.extend_target_subset_range +#align local_homeomorph.extend_target_subset_range PartialHomeomorph.extend_target_subset_range theorem nhdsWithin_extend_target_eq {y : M} (hy : y ∈ f.source) : 𝓝[(f.extend I).target] f.extend I y = 𝓝[range I] f.extend I y := (nhdsWithin_mono _ (extend_target_subset_range _ _)).antisymm <| nhdsWithin_le_of_mem (extend_target_mem_nhdsWithin _ _ hy) -#align local_homeomorph.nhds_within_extend_target_eq LocalHomeomorph.nhdsWithin_extend_target_eq +#align local_homeomorph.nhds_within_extend_target_eq PartialHomeomorph.nhdsWithin_extend_target_eq theorem continuousAt_extend_symm' {x : E} (h : x ∈ (f.extend I).target) : ContinuousAt (f.extend I).symm x := (f.continuousAt_symm h.2).comp I.continuous_symm.continuousAt -#align local_homeomorph.continuous_at_extend_symm' LocalHomeomorph.continuousAt_extend_symm' +#align local_homeomorph.continuous_at_extend_symm' PartialHomeomorph.continuousAt_extend_symm' theorem continuousAt_extend_symm {x : M} (h : x ∈ f.source) : ContinuousAt (f.extend I).symm (f.extend I x) := continuousAt_extend_symm' f I <| (f.extend I).map_source <| by rwa [f.extend_source] -#align local_homeomorph.continuous_at_extend_symm LocalHomeomorph.continuousAt_extend_symm +#align local_homeomorph.continuous_at_extend_symm PartialHomeomorph.continuousAt_extend_symm theorem continuousOn_extend_symm : ContinuousOn (f.extend I).symm (f.extend I).target := fun _ h => (continuousAt_extend_symm' _ _ h).continuousWithinAt -#align local_homeomorph.continuous_on_extend_symm LocalHomeomorph.continuousOn_extend_symm +#align local_homeomorph.continuous_on_extend_symm PartialHomeomorph.continuousOn_extend_symm theorem extend_symm_continuousWithinAt_comp_right_iff {X} [TopologicalSpace X] {g : M → X} {s : Set M} {x : M} : ContinuousWithinAt (g ∘ (f.extend I).symm) ((f.extend I).symm ⁻¹' s ∩ range I) (f.extend I x) ↔ ContinuousWithinAt (g ∘ f.symm) (f.symm ⁻¹' s) (f x) := by rw [← I.symm_continuousWithinAt_comp_right_iff]; rfl -#align local_homeomorph.extend_symm_continuous_within_at_comp_right_iff LocalHomeomorph.extend_symm_continuousWithinAt_comp_right_iff +#align local_homeomorph.extend_symm_continuous_within_at_comp_right_iff PartialHomeomorph.extend_symm_continuousWithinAt_comp_right_iff theorem isOpen_extend_preimage' {s : Set E} (hs : IsOpen s) : IsOpen ((f.extend I).source ∩ f.extend I ⁻¹' s) := (continuousOn_extend f I).isOpen_inter_preimage (isOpen_extend_source _ _) hs -#align local_homeomorph.is_open_extend_preimage' LocalHomeomorph.isOpen_extend_preimage' +#align local_homeomorph.is_open_extend_preimage' PartialHomeomorph.isOpen_extend_preimage' theorem isOpen_extend_preimage {s : Set E} (hs : IsOpen s) : IsOpen (f.source ∩ f.extend I ⁻¹' s) := by rw [← extend_source f I]; exact isOpen_extend_preimage' f I hs -#align local_homeomorph.is_open_extend_preimage LocalHomeomorph.isOpen_extend_preimage +#align local_homeomorph.is_open_extend_preimage PartialHomeomorph.isOpen_extend_preimage theorem map_extend_nhdsWithin_eq_image {y : M} (hy : y ∈ f.source) : map (f.extend I) (𝓝[s] y) = 𝓝[f.extend I '' ((f.extend I).source ∩ s)] f.extend I y := by @@ -1070,7 +1070,7 @@ theorem map_extend_nhdsWithin_eq_image {y : M} (hy : y ∈ f.source) : ((f.extend I).left_inv <| by rwa [f.extend_source]) (continuousAt_extend_symm f I hy).continuousWithinAt (continuousAt_extend f I hy).continuousWithinAt -#align local_homeomorph.map_extend_nhds_within_eq_image LocalHomeomorph.map_extend_nhdsWithin_eq_image +#align local_homeomorph.map_extend_nhds_within_eq_image PartialHomeomorph.map_extend_nhdsWithin_eq_image theorem map_extend_nhdsWithin_eq_image_of_subset {y : M} (hy : y ∈ f.source) (hs : s ⊆ f.source) : map (f.extend I) (𝓝[s] y) = 𝓝[f.extend I '' s] f.extend I y := by @@ -1082,18 +1082,18 @@ theorem map_extend_nhdsWithin {y : M} (hy : y ∈ f.source) : rw [map_extend_nhdsWithin_eq_image f I hy, nhdsWithin_inter, ← nhdsWithin_extend_target_eq _ _ hy, ← nhdsWithin_inter, (f.extend I).image_source_inter_eq', inter_comm] -#align local_homeomorph.map_extend_nhds_within LocalHomeomorph.map_extend_nhdsWithin +#align local_homeomorph.map_extend_nhds_within PartialHomeomorph.map_extend_nhdsWithin theorem map_extend_symm_nhdsWithin {y : M} (hy : y ∈ f.source) : map (f.extend I).symm (𝓝[(f.extend I).symm ⁻¹' s ∩ range I] f.extend I y) = 𝓝[s] y := by rw [← map_extend_nhdsWithin f I hy, map_map, Filter.map_congr, map_id] exact (f.extend I).leftInvOn.eqOn.eventuallyEq_of_mem (extend_source_mem_nhdsWithin _ _ hy) -#align local_homeomorph.map_extend_symm_nhds_within LocalHomeomorph.map_extend_symm_nhdsWithin +#align local_homeomorph.map_extend_symm_nhds_within PartialHomeomorph.map_extend_symm_nhdsWithin theorem map_extend_symm_nhdsWithin_range {y : M} (hy : y ∈ f.source) : map (f.extend I).symm (𝓝[range I] f.extend I y) = 𝓝 y := by rw [← nhdsWithin_univ, ← map_extend_symm_nhdsWithin f I hy, preimage_univ, univ_inter] -#align local_homeomorph.map_extend_symm_nhds_within_range LocalHomeomorph.map_extend_symm_nhdsWithin_range +#align local_homeomorph.map_extend_symm_nhds_within_range PartialHomeomorph.map_extend_symm_nhdsWithin_range theorem tendsto_extend_comp_iff {l : Filter α} {g : α → M} (hg : ∀ᶠ z in l, g z ∈ f.source) (hy : y ∈ f.source) : @@ -1105,7 +1105,7 @@ theorem tendsto_extend_comp_iff {l : Filter α} {g : α → M} (hg : ∀ᶠ z in simpa only [(· ∘ ·), extend_left_inv _ _ hz, mem_preimage] using hzu -- there is no definition `writtenInExtend` but we already use some made-up names in this file -theorem continuousWithinAt_writtenInExtend_iff {f' : LocalHomeomorph M' H'} {g : M → M'} +theorem continuousWithinAt_writtenInExtend_iff {f' : PartialHomeomorph M' H'} {g : M → M'} (hy : y ∈ f.source) (hgy : g y ∈ f'.source) (hmaps : MapsTo g s f'.source) : ContinuousWithinAt (f'.extend I' ∘ g ∘ (f.extend I).symm) ((f.extend I).symm ⁻¹' s ∩ range I) (f.extend I y) ↔ ContinuousWithinAt g s y := by @@ -1122,7 +1122,7 @@ theorem continuousWithinAt_writtenInExtend_iff {f' : LocalHomeomorph M' H'} {g : /-- If `s ⊆ f.source` and `g x ∈ f'.source` whenever `x ∈ s`, then `g` is continuous on `s` if and only if `g` written in charts `f.extend I` and `f'.extend I'` is continuous on `f.extend I '' s`. -/ -theorem continuousOn_writtenInExtend_iff {f' : LocalHomeomorph M' H'} {g : M → M'} +theorem continuousOn_writtenInExtend_iff {f' : PartialHomeomorph M' H'} {g : M → M'} (hs : s ⊆ f.source) (hmaps : MapsTo g s f'.source) : ContinuousOn (f'.extend I' ∘ g ∘ (f.extend I).symm) (f.extend I '' s) ↔ ContinuousOn g s := by refine ball_image_iff.trans <| forall₂_congr fun x hx ↦ ?_ @@ -1136,14 +1136,14 @@ in the source is a neighborhood of the preimage, within a set. -/ theorem extend_preimage_mem_nhdsWithin {x : M} (h : x ∈ f.source) (ht : t ∈ 𝓝[s] x) : (f.extend I).symm ⁻¹' t ∈ 𝓝[(f.extend I).symm ⁻¹' s ∩ range I] f.extend I x := by rwa [← map_extend_symm_nhdsWithin f I h, mem_map] at ht -#align local_homeomorph.extend_preimage_mem_nhds_within LocalHomeomorph.extend_preimage_mem_nhdsWithin +#align local_homeomorph.extend_preimage_mem_nhds_within PartialHomeomorph.extend_preimage_mem_nhdsWithin theorem extend_preimage_mem_nhds {x : M} (h : x ∈ f.source) (ht : t ∈ 𝓝 x) : (f.extend I).symm ⁻¹' t ∈ 𝓝 (f.extend I x) := by apply (continuousAt_extend_symm f I h).preimage_mem_nhds rwa [(f.extend I).left_inv] rwa [f.extend_source] -#align local_homeomorph.extend_preimage_mem_nhds LocalHomeomorph.extend_preimage_mem_nhds +#align local_homeomorph.extend_preimage_mem_nhds PartialHomeomorph.extend_preimage_mem_nhds /-- Technical lemma to rewrite suitably the preimage of an intersection under an extended chart, to bring it into a convenient form to apply derivative lemmas. -/ @@ -1151,7 +1151,7 @@ theorem extend_preimage_inter_eq : (f.extend I).symm ⁻¹' (s ∩ t) ∩ range I = (f.extend I).symm ⁻¹' s ∩ range I ∩ (f.extend I).symm ⁻¹' t := by mfld_set_tac -#align local_homeomorph.extend_preimage_inter_eq LocalHomeomorph.extend_preimage_inter_eq +#align local_homeomorph.extend_preimage_inter_eq PartialHomeomorph.extend_preimage_inter_eq -- porting note: an `aux` lemma that is no longer needed. Delete? theorem extend_symm_preimage_inter_range_eventuallyEq_aux {s : Set M} {x : M} (hx : x ∈ f.source) : @@ -1165,29 +1165,29 @@ theorem extend_symm_preimage_inter_range_eventuallyEq_aux {s : Set M} {x : M} (h refine' (eventuallyEq_univ.mpr _).symm.inter EventuallyEq.rfl refine' I.continuousAt_symm.preimage_mem_nhds (f.open_target.mem_nhds _) simp_rw [f.extend_coe, Function.comp_apply, I.left_inv, f.mapsTo hx] -#align local_homeomorph.extend_symm_preimage_inter_range_eventually_eq_aux LocalHomeomorph.extend_symm_preimage_inter_range_eventuallyEq_aux +#align local_homeomorph.extend_symm_preimage_inter_range_eventually_eq_aux PartialHomeomorph.extend_symm_preimage_inter_range_eventuallyEq_aux theorem extend_symm_preimage_inter_range_eventuallyEq {s : Set M} {x : M} (hs : s ⊆ f.source) (hx : x ∈ f.source) : ((f.extend I).symm ⁻¹' s ∩ range I : Set _) =ᶠ[𝓝 (f.extend I x)] f.extend I '' s := by rw [← nhdsWithin_eq_iff_eventuallyEq, ← map_extend_nhdsWithin _ _ hx, map_extend_nhdsWithin_eq_image_of_subset _ _ hx hs] -#align local_homeomorph.extend_symm_preimage_inter_range_eventually_eq LocalHomeomorph.extend_symm_preimage_inter_range_eventuallyEq +#align local_homeomorph.extend_symm_preimage_inter_range_eventually_eq PartialHomeomorph.extend_symm_preimage_inter_range_eventuallyEq /-! We use the name `extend_coord_change` for `(f'.extend I).symm ≫ f.extend I`. -/ theorem extend_coord_change_source : ((f.extend I).symm ≫ f'.extend I).source = I '' (f.symm ≫ₕ f').source := by - simp_rw [LocalEquiv.trans_source, I.image_eq, extend_source, LocalEquiv.symm_source, + simp_rw [PartialEquiv.trans_source, I.image_eq, extend_source, PartialEquiv.symm_source, extend_target, inter_right_comm _ (range I)] rfl -#align local_homeomorph.extend_coord_change_source LocalHomeomorph.extend_coord_change_source +#align local_homeomorph.extend_coord_change_source PartialHomeomorph.extend_coord_change_source theorem extend_image_source_inter : f.extend I '' (f.source ∩ f'.source) = ((f.extend I).symm ≫ f'.extend I).source := by simp_rw [f.extend_coord_change_source, f.extend_coe, image_comp I f, trans_source'', symm_symm, symm_target] -#align local_homeomorph.extend_image_source_inter LocalHomeomorph.extend_image_source_inter +#align local_homeomorph.extend_image_source_inter PartialHomeomorph.extend_image_source_inter theorem extend_coord_change_source_mem_nhdsWithin {x : E} (hx : x ∈ ((f.extend I).symm ≫ f'.extend I).source) : @@ -1195,8 +1195,8 @@ theorem extend_coord_change_source_mem_nhdsWithin {x : E} rw [f.extend_coord_change_source] at hx ⊢ obtain ⟨x, hx, rfl⟩ := hx refine' I.image_mem_nhdsWithin _ - refine' (LocalHomeomorph.open_source _).mem_nhds hx -#align local_homeomorph.extend_coord_change_source_mem_nhds_within LocalHomeomorph.extend_coord_change_source_mem_nhdsWithin + refine' (PartialHomeomorph.open_source _).mem_nhds hx +#align local_homeomorph.extend_coord_change_source_mem_nhds_within PartialHomeomorph.extend_coord_change_source_mem_nhdsWithin theorem extend_coord_change_source_mem_nhdsWithin' {x : M} (hxf : x ∈ f.source) (hxf' : x ∈ f'.source) : @@ -1204,7 +1204,7 @@ theorem extend_coord_change_source_mem_nhdsWithin' {x : M} (hxf : x ∈ f.source apply extend_coord_change_source_mem_nhdsWithin rw [← extend_image_source_inter] exact mem_image_of_mem _ ⟨hxf, hxf'⟩ -#align local_homeomorph.extend_coord_change_source_mem_nhds_within' LocalHomeomorph.extend_coord_change_source_mem_nhdsWithin' +#align local_homeomorph.extend_coord_change_source_mem_nhds_within' PartialHomeomorph.extend_coord_change_source_mem_nhdsWithin' variable {f f'} @@ -1215,7 +1215,7 @@ theorem contDiffOn_extend_coord_change [ChartedSpace H M] (hf : f ∈ maximalAtl ContDiffOn 𝕜 ⊤ (f.extend I ∘ (f'.extend I).symm) ((f'.extend I).symm ≫ f.extend I).source := by rw [extend_coord_change_source, I.image_eq] exact (StructureGroupoid.compatible_of_mem_maximalAtlas hf' hf).1 -#align local_homeomorph.cont_diff_on_extend_coord_change LocalHomeomorph.contDiffOn_extend_coord_change +#align local_homeomorph.cont_diff_on_extend_coord_change PartialHomeomorph.contDiffOn_extend_coord_change theorem contDiffWithinAt_extend_coord_change [ChartedSpace H M] (hf : f ∈ maximalAtlas I M) (hf' : f' ∈ maximalAtlas I M) {x : E} (hx : x ∈ ((f'.extend I).symm ≫ f.extend I).source) : @@ -1223,8 +1223,8 @@ theorem contDiffWithinAt_extend_coord_change [ChartedSpace H M] (hf : f ∈ maxi apply (contDiffOn_extend_coord_change I hf hf' x hx).mono_of_mem rw [extend_coord_change_source] at hx ⊢ obtain ⟨z, hz, rfl⟩ := hx - exact I.image_mem_nhdsWithin ((LocalHomeomorph.open_source _).mem_nhds hz) -#align local_homeomorph.cont_diff_within_at_extend_coord_change LocalHomeomorph.contDiffWithinAt_extend_coord_change + exact I.image_mem_nhdsWithin ((PartialHomeomorph.open_source _).mem_nhds hz) +#align local_homeomorph.cont_diff_within_at_extend_coord_change PartialHomeomorph.contDiffWithinAt_extend_coord_change theorem contDiffWithinAt_extend_coord_change' [ChartedSpace H M] (hf : f ∈ maximalAtlas I M) (hf' : f' ∈ maximalAtlas I M) {x : M} (hxf : x ∈ f.source) (hxf' : x ∈ f'.source) : @@ -1232,18 +1232,18 @@ theorem contDiffWithinAt_extend_coord_change' [ChartedSpace H M] (hf : f ∈ max refine' contDiffWithinAt_extend_coord_change I hf hf' _ rw [← extend_image_source_inter] exact mem_image_of_mem _ ⟨hxf', hxf⟩ -#align local_homeomorph.cont_diff_within_at_extend_coord_change' LocalHomeomorph.contDiffWithinAt_extend_coord_change' +#align local_homeomorph.cont_diff_within_at_extend_coord_change' PartialHomeomorph.contDiffWithinAt_extend_coord_change' -end LocalHomeomorph +end PartialHomeomorph -open LocalHomeomorph +open PartialHomeomorph variable [ChartedSpace H M] [ChartedSpace H' M'] /-- The preferred extended chart on a manifold with corners around a point `x`, from a neighborhood of `x` to the model vector space. -/ @[simp, mfld_simps] -def extChartAt (x : M) : LocalEquiv M E := +def extChartAt (x : M) : PartialEquiv M E := (chartAt H x).extend I #align ext_chart_at extChartAt @@ -1530,7 +1530,7 @@ theorem extChartAt_self_apply {x y : H} : extChartAt I x y = I y := /-- In the case of the manifold structure on a vector space, the extended charts are just the identity.-/ -theorem extChartAt_model_space_eq_id (x : E) : extChartAt 𝓘(𝕜, E) x = LocalEquiv.refl E := by +theorem extChartAt_model_space_eq_id (x : E) : extChartAt 𝓘(𝕜, E) x = PartialEquiv.refl E := by simp only [mfld_simps] #align ext_chart_at_model_space_eq_id extChartAt_model_space_eq_id @@ -1543,15 +1543,15 @@ variable {𝕜} theorem extChartAt_prod (x : M × M') : extChartAt (I.prod I') x = (extChartAt I x.1).prod (extChartAt I' x.2) := by simp only [mfld_simps] - -- Porting note: `simp` can't use `LocalEquiv.prod_trans` here because of a type + -- Porting note: `simp` can't use `PartialEquiv.prod_trans` here because of a type -- synonym - rw [LocalEquiv.prod_trans] + rw [PartialEquiv.prod_trans] #align ext_chart_at_prod extChartAt_prod theorem extChartAt_comp [ChartedSpace H H'] (x : M') : (letI := ChartedSpace.comp H H' M'; extChartAt I x) = - (chartAt H' x).toLocalEquiv ≫ extChartAt I (chartAt H' x x) := - LocalEquiv.trans_assoc .. + (chartAt H' x).toPartialEquiv ≫ extChartAt I (chartAt H' x x) := + PartialEquiv.trans_assoc .. theorem writtenInExtChartAt_chartAt_comp [ChartedSpace H H'] (x : M') {y} (hy : y ∈ letI := ChartedSpace.comp H H' M'; (extChartAt I x).target) : diff --git a/Mathlib/Geometry/Manifold/VectorBundle/Basic.lean b/Mathlib/Geometry/Manifold/VectorBundle/Basic.lean index 2a00233017f6b..71a68fc1d2de3 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/Basic.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/Basic.lean @@ -64,7 +64,7 @@ set_option autoImplicit true assert_not_exists mfderiv -open Bundle Set LocalHomeomorph +open Bundle Set PartialHomeomorph open Function (id_def) @@ -85,15 +85,15 @@ variable [TopologicalSpace F] [TopologicalSpace (TotalSpace F E)] [∀ x, Topolo /-- A fiber bundle `E` over a base `B` with model fiber `F` is naturally a charted space modelled on `B × F`. -/ instance FiberBundle.chartedSpace' : ChartedSpace (B × F) (TotalSpace F E) where - atlas := (fun e : Trivialization F (π F E) => e.toLocalHomeomorph) '' trivializationAtlas F E - chartAt x := (trivializationAt F E x.proj).toLocalHomeomorph + atlas := (fun e : Trivialization F (π F E) => e.toPartialHomeomorph) '' trivializationAtlas F E + chartAt x := (trivializationAt F E x.proj).toPartialHomeomorph mem_chart_source x := (trivializationAt F E x.proj).mem_source.mpr (mem_baseSet_trivializationAt F E x.proj) chart_mem_atlas _ := mem_image_of_mem _ (trivialization_mem_atlas F E _) #align fiber_bundle.charted_space FiberBundle.chartedSpace' theorem FiberBundle.chartedSpace'_chartAt (x : TotalSpace F E) : - chartAt (B × F) x = (trivializationAt F E x.proj).toLocalHomeomorph := + chartAt (B × F) x = (trivializationAt F E x.proj).toPartialHomeomorph := rfl /- Porting note: In Lean 3, the next instance was inside a section with locally reducible @@ -110,8 +110,8 @@ instance FiberBundle.chartedSpace : ChartedSpace (ModelProd HB F) (TotalSpace F theorem FiberBundle.chartedSpace_chartAt (x : TotalSpace F E) : chartAt (ModelProd HB F) x = - (trivializationAt F E x.proj).toLocalHomeomorph ≫ₕ - (chartAt HB x.proj).prod (LocalHomeomorph.refl F) := by + (trivializationAt F E x.proj).toPartialHomeomorph ≫ₕ + (chartAt HB x.proj).prod (PartialHomeomorph.refl F) := by dsimp only [chartAt_comp, prodChartedSpace_chartAt, FiberBundle.chartedSpace'_chartAt, chartAt_self_eq] rw [Trivialization.coe_coe, Trivialization.coe_fst' _ (mem_baseSet_trivializationAt F E x.proj)] @@ -140,19 +140,19 @@ variable [TopologicalSpace B] [ChartedSpace HB B] [FiberBundle F E] protected theorem FiberBundle.extChartAt (x : TotalSpace F E) : extChartAt (IB.prod 𝓘(𝕜, F)) x = - (trivializationAt F E x.proj).toLocalEquiv ≫ - (extChartAt IB x.proj).prod (LocalEquiv.refl F) := by + (trivializationAt F E x.proj).toPartialEquiv ≫ + (extChartAt IB x.proj).prod (PartialEquiv.refl F) := by simp_rw [extChartAt, FiberBundle.chartedSpace_chartAt, extend] - simp only [LocalEquiv.trans_assoc, mfld_simps] + simp only [PartialEquiv.trans_assoc, mfld_simps] -- porting note: should not be needed - rw [LocalEquiv.prod_trans, LocalEquiv.refl_trans] + rw [PartialEquiv.prod_trans, PartialEquiv.refl_trans] #align fiber_bundle.ext_chart_at FiberBundle.extChartAt protected theorem FiberBundle.extChartAt_target (x : TotalSpace F E) : (extChartAt (IB.prod 𝓘(𝕜, F)) x).target = ((extChartAt IB x.proj).target ∩ (extChartAt IB x.proj).symm ⁻¹' (trivializationAt F E x.proj).baseSet) ×ˢ univ := by - rw [FiberBundle.extChartAt, LocalEquiv.trans_target, Trivialization.target_eq, inter_prod] + rw [FiberBundle.extChartAt, PartialEquiv.trans_target, Trivialization.target_eq, inter_prod] rfl theorem FiberBundle.writtenInExtChartAt_trivializationAt {x : TotalSpace F E} {y} @@ -164,7 +164,7 @@ theorem FiberBundle.writtenInExtChartAt_trivializationAt {x : TotalSpace F E} {y theorem FiberBundle.writtenInExtChartAt_trivializationAt_symm {x : TotalSpace F E} {y} (hy : y ∈ (extChartAt (IB.prod 𝓘(𝕜, F)) x).target) : writtenInExtChartAt (IB.prod 𝓘(𝕜, F)) (IB.prod 𝓘(𝕜, F)) (trivializationAt F E x.proj x) - (trivializationAt F E x.proj).toLocalHomeomorph.symm y = y := + (trivializationAt F E x.proj).toPartialHomeomorph.symm y = y := writtenInExtChartAt_chartAt_symm_comp _ _ hy /-! ### Smoothness of maps in/out fiber bundles @@ -185,15 +185,15 @@ theorem contMDiffWithinAt_totalSpace (f : M → TotalSpace F E) {s : Set M} {x simp (config := { singlePass := true }) only [contMDiffWithinAt_iff_target] rw [and_and_and_comm, ← FiberBundle.continuousWithinAt_totalSpace, and_congr_right_iff] intro hf - simp_rw [modelWithCornersSelf_prod, FiberBundle.extChartAt, Function.comp, LocalEquiv.trans_apply, - LocalEquiv.prod_coe, LocalEquiv.refl_coe, extChartAt_self_apply, modelWithCornersSelf_coe, - id_def] + simp_rw [modelWithCornersSelf_prod, FiberBundle.extChartAt, Function.comp, + PartialEquiv.trans_apply, PartialEquiv.prod_coe, PartialEquiv.refl_coe, extChartAt_self_apply, + modelWithCornersSelf_coe, id_def] refine (contMDiffWithinAt_prod_iff _).trans (and_congr ?_ Iff.rfl) have h1 : (fun x => (f x).proj) ⁻¹' (trivializationAt F E (f x₀).proj).baseSet ∈ 𝓝[s] x₀ := ((FiberBundle.continuous_proj F E).continuousWithinAt.comp hf (mapsTo_image f s)) ((Trivialization.open_baseSet _).mem_nhds (mem_baseSet_trivializationAt F E _)) refine EventuallyEq.contMDiffWithinAt_iff (eventually_of_mem h1 fun x hx => ?_) ?_ - · simp_rw [Function.comp, LocalHomeomorph.coe_coe, Trivialization.coe_coe] + · simp_rw [Function.comp, PartialHomeomorph.coe_coe, Trivialization.coe_coe] rw [Trivialization.coe_fst'] exact hx · simp only [mfld_simps] @@ -431,7 +431,7 @@ variable (IB e e') theorem Trivialization.contMDiffOn_symm_trans : ContMDiffOn (IB.prod 𝓘(𝕜, F)) (IB.prod 𝓘(𝕜, F)) n - (e.toLocalHomeomorph.symm ≫ₕ e'.toLocalHomeomorph) (e.target ∩ e'.target) := by + (e.toPartialHomeomorph.symm ≫ₕ e'.toPartialHomeomorph) (e.target ∩ e'.target) := by have Hmaps : MapsTo Prod.fst (e.target ∩ e'.target) (e.baseSet ∩ e'.baseSet) := fun x hx ↦ ⟨e.mem_target.1 hx.1, e'.mem_target.1 hx.2⟩ rw [mapsTo_inter] at Hmaps @@ -440,7 +440,7 @@ theorem Trivialization.contMDiffOn_symm_trans : (contMDiffOn_fst.coordChange contMDiffOn_snd Hmaps.1 Hmaps.2)).congr ?_ rintro ⟨b, x⟩ hb refine Prod.ext ?_ rfl - · have : (e.toLocalHomeomorph.symm (b, x)).1 ∈ e'.baseSet + · have : (e.toPartialHomeomorph.symm (b, x)).1 ∈ e'.baseSet · simp_all only [Trivialization.mem_target, mfld_simps] exact (e'.coe_fst' this).trans (e.proj_symm_apply hb.1) @@ -478,9 +478,9 @@ instance SmoothFiberwiseLinear.hasGroupoid : rw [mem_smoothFiberwiseLinear_iff] refine' ⟨_, _, e.open_baseSet.inter e'.open_baseSet, smoothOn_coordChangeL IB e e', smoothOn_symm_coordChangeL IB e e', _⟩ - refine LocalHomeomorph.eqOnSourceSetoid.symm ⟨?_, ?_⟩ - · simp only [e.symm_trans_source_eq e', FiberwiseLinear.localHomeomorph, trans_toLocalEquiv, - symm_toLocalEquiv] + refine PartialHomeomorph.eqOnSourceSetoid.symm ⟨?_, ?_⟩ + · simp only [e.symm_trans_source_eq e', FiberwiseLinear.localHomeomorph, trans_toPartialEquiv, + symm_toPartialEquiv] · rintro ⟨b, v⟩ hb exact (e.apply_symm_apply_eq_coordChangeL e' hb.1 v).symm #align smooth_fiberwise_linear.has_groupoid SmoothFiberwiseLinear.hasGroupoid @@ -566,8 +566,8 @@ theorem Trivialization.smoothOn (e : Trivialization F (π F E)) [MemTrivializati exact (this.1.prod_mk this.2).congr fun x hx ↦ (e.mk_proj_snd hx).symm theorem Trivialization.smoothOn_symm (e : Trivialization F (π F E)) [MemTrivializationAtlas e] : - SmoothOn (IB.prod 𝓘(𝕜, F)) (IB.prod 𝓘(𝕜, F)) e.toLocalHomeomorph.symm e.target := by - rw [e.smoothOn_iff IB e.toLocalHomeomorph.symm_mapsTo] + SmoothOn (IB.prod 𝓘(𝕜, F)) (IB.prod 𝓘(𝕜, F)) e.toPartialHomeomorph.symm e.target := by + rw [e.smoothOn_iff IB e.toPartialHomeomorph.symm_mapsTo] refine ⟨smoothOn_fst.congr fun x hx ↦ e.proj_symm_apply hx, smoothOn_snd.congr fun x hx ↦ ?_⟩ rw [e.apply_symm_apply hx] diff --git a/Mathlib/Geometry/Manifold/VectorBundle/FiberwiseLinear.lean b/Mathlib/Geometry/Manifold/VectorBundle/FiberwiseLinear.lean index fb1125210b8b3..affd63ea672c9 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/FiberwiseLinear.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/FiberwiseLinear.lean @@ -35,7 +35,7 @@ determines a local homeomorphism from `B × F` to itself by its action fiberwise def localHomeomorph (φ : B → F ≃L[𝕜] F) (hU : IsOpen U) (hφ : ContinuousOn (fun x => φ x : B → F →L[𝕜] F) U) (h2φ : ContinuousOn (fun x => (φ x).symm : B → F →L[𝕜] F) U) : - LocalHomeomorph (B × F) (B × F) where + PartialHomeomorph (B × F) (B × F) where toFun x := (x.1, φ x.1 x.2) invFun x := (x.1, (φ x.1).symm x.2) source := U ×ˢ univ @@ -106,7 +106,7 @@ local homeomorphism. Then the source of `e` is of the form `U ×ˢ univ`, for some set `U` in `B`, and, at any point `x` in `U`, admits a neighbourhood `u` of `x` such that `e` is equal on `u ×ˢ univ` to some bi-smooth fiberwise linear local homeomorphism. -/ -theorem SmoothFiberwiseLinear.locality_aux₁ (e : LocalHomeomorph (B × F) (B × F)) +theorem SmoothFiberwiseLinear.locality_aux₁ (e : PartialHomeomorph (B × F) (B × F)) (h : ∀ p ∈ e.source, ∃ s : Set (B × F), IsOpen s ∧ p ∈ s ∧ ∃ (φ : B → F ≃L[𝕜] F) (u : Set B) (hu : IsOpen u) (hφ : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => (φ x : F →L[𝕜] F)) u) @@ -158,7 +158,7 @@ together the various bi-smooth fiberwise linear local homeomorphism which exist The `U` in the conclusion is the same `U` as in the hypothesis. We state it like this, because this is exactly what we need for `smoothFiberwiseLinear`. -/ -theorem SmoothFiberwiseLinear.locality_aux₂ (e : LocalHomeomorph (B × F) (B × F)) (U : Set B) +theorem SmoothFiberwiseLinear.locality_aux₂ (e : PartialHomeomorph (B × F) (B × F)) (U : Set B) (hU : e.source = U ×ˢ univ) (h : ∀ x ∈ U, ∃ (φ : B → F ≃L[𝕜] F) (u : Set B) (hu : IsOpen u) (_hUu : u ⊆ U) (_hux : x ∈ u) @@ -223,7 +223,7 @@ theorem SmoothFiberwiseLinear.locality_aux₂ (e : LocalHomeomorph (B × F) (B /- Porting note: `simp only [mem_iUnion]` fails in the next definition. This aux lemma is a workaround. -/ -private theorem mem_aux {e : LocalHomeomorph (B × F) (B × F)} : +private theorem mem_aux {e : PartialHomeomorph (B × F) (B × F)} : (e ∈ ⋃ (φ : B → F ≃L[𝕜] F) (U : Set B) (hU : IsOpen U) (hφ : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => φ x : B → F →L[𝕜] F) U) (h2φ : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => (φ x).symm : B → F →L[𝕜] F) U), @@ -251,7 +251,7 @@ def smoothFiberwiseLinear : StructureGroupoid (B × F) where simp only [mem_aux] rintro e e' ⟨φ, U, hU, hφ, h2φ, heφ⟩ ⟨φ', U', hU', hφ', h2φ', heφ'⟩ refine' ⟨fun b => (φ b).trans (φ' b), _, hU.inter hU', _, _, - Setoid.trans (LocalHomeomorph.EqOnSource.trans' heφ heφ') ⟨_, _⟩⟩ + Setoid.trans (PartialHomeomorph.EqOnSource.trans' heφ heφ') ⟨_, _⟩⟩ · show SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x : B => (φ' x).toContinuousLinearMap ∘L (φ x).toContinuousLinearMap) (U ∩ U') @@ -267,7 +267,7 @@ def smoothFiberwiseLinear : StructureGroupoid (B × F) where symm' := fun e ↦ by simp only [mem_iUnion] rintro ⟨φ, U, hU, hφ, h2φ, heφ⟩ - refine' ⟨fun b => (φ b).symm, U, hU, h2φ, _, LocalHomeomorph.EqOnSource.symm' heφ⟩ + refine' ⟨fun b => (φ b).symm, U, hU, h2φ, _, PartialHomeomorph.EqOnSource.symm' heφ⟩ simp_rw [ContinuousLinearEquiv.symm_symm] exact hφ id_mem' := by @@ -277,8 +277,8 @@ def smoothFiberwiseLinear : StructureGroupoid (B × F) where -/ refine mem_iUnion.2 ⟨fun _ ↦ .refl 𝕜 F, mem_iUnion.2 ⟨univ, mem_iUnion.2 ⟨isOpen_univ, ?_⟩⟩⟩ refine mem_iUnion.2 ⟨contMDiffOn_const, mem_iUnion.2 ⟨contMDiffOn_const, ?_, ?_⟩⟩ - · simp only [FiberwiseLinear.localHomeomorph, LocalHomeomorph.refl_localEquiv, - LocalEquiv.refl_source, univ_prod_univ] + · simp only [FiberwiseLinear.localHomeomorph, PartialHomeomorph.refl_localEquiv, + PartialEquiv.refl_source, univ_prod_univ] · exact eqOn_refl id _ locality' := by -- the hard work has been extracted to `locality_aux₁` and `locality_aux₂` @@ -293,7 +293,7 @@ def smoothFiberwiseLinear : StructureGroupoid (B × F) where #align smooth_fiberwise_linear smoothFiberwiseLinear @[simp] -theorem mem_smoothFiberwiseLinear_iff (e : LocalHomeomorph (B × F) (B × F)) : +theorem mem_smoothFiberwiseLinear_iff (e : PartialHomeomorph (B × F) (B × F)) : e ∈ smoothFiberwiseLinear B F IB ↔ ∃ (φ : B → F ≃L[𝕜] F) (U : Set B) (hU : IsOpen U) (hφ : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => φ x : B → F →L[𝕜] F) U) (h2φ : diff --git a/Mathlib/Geometry/Manifold/VectorBundle/Hom.lean b/Mathlib/Geometry/Manifold/VectorBundle/Hom.lean index bdd48637bd1d1..2e07c956dd408 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/Hom.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/Hom.lean @@ -20,7 +20,7 @@ To do it for semilinear maps, we would need to generalize `ContinuousLinearMap.c noncomputable section -open Bundle Set LocalHomeomorph ContinuousLinearMap Pretrivialization +open Bundle Set PartialHomeomorph ContinuousLinearMap Pretrivialization open scoped Manifold Bundle @@ -55,8 +55,9 @@ theorem smoothOn_continuousLinearMapCoordChange theorem hom_chart (y₀ y : LE₁E₂) : chartAt (ModelProd HB (F₁ →L[𝕜] F₂)) y₀ y = (chartAt HB y₀.1 y.1, inCoordinates F₁ E₁ F₂ E₂ y₀.1 y.1 y₀.1 y.1 y.2) := by - rw [FiberBundle.chartedSpace_chartAt, trans_apply, LocalHomeomorph.prod_apply, - Trivialization.coe_coe, LocalHomeomorph.refl_apply, Function.id_def, hom_trivializationAt_apply] + rw [FiberBundle.chartedSpace_chartAt, trans_apply, PartialHomeomorph.prod_apply, + Trivialization.coe_coe, PartialHomeomorph.refl_apply, Function.id_def, + hom_trivializationAt_apply] #align hom_chart hom_chart variable {IB} diff --git a/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean b/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean index aeb31731a39da..bce81054d2c41 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean @@ -14,8 +14,8 @@ This file defines the tangent bundle as a smooth vector bundle. Let `M` be a smooth manifold with corners with model `I` on `(E, H)`. We define the tangent bundle of `M` using the `VectorBundleCore` construction indexed by the charts of `M` with fibers `E`. -Given two charts `i, j : LocalHomeomorph M H`, the coordinate change between `i` and `j` at a point -`x : M` is the derivative of the composite +Given two charts `i, j : PartialHomeomorph M H`, the coordinate change between `i` and `j` +at a point `x : M` is the derivative of the composite ``` I.symm i.symm j I E -----> H -----> M --> H --> E @@ -32,7 +32,7 @@ This defines a smooth vector bundle `TangentBundle` with fibers `TangentSpace`. -/ -open Bundle Set SmoothManifoldWithCorners LocalHomeomorph ContinuousLinearMap +open Bundle Set SmoothManifoldWithCorners PartialHomeomorph ContinuousLinearMap open scoped Manifold Topology Bundle @@ -58,7 +58,7 @@ theorem contDiffOn_fderiv_coord_change (i j : atlas H M) : rw [i.1.extend_coord_change_source]; apply image_subset_range intro x hx refine' (ContDiffWithinAt.fderivWithin_right _ I.unique_diff le_top <| h hx).mono h - refine' (LocalHomeomorph.contDiffOn_extend_coord_change I (subset_maximalAtlas I j.2) + refine' (PartialHomeomorph.contDiffOn_extend_coord_change I (subset_maximalAtlas I j.2) (subset_maximalAtlas I i.2) x hx).mono_of_mem _ exact i.1.extend_coord_change_source_mem_nhdsWithin j.1 I hx #align cont_diff_on_fderiv_coord_change contDiffOn_fderiv_coord_change @@ -181,17 +181,17 @@ namespace TangentBundle protected theorem chartAt (p : TM) : chartAt (ModelProd H E) p = - ((tangentBundleCore I M).toFiberBundleCore.localTriv (achart H p.1)).toLocalHomeomorph ≫ₕ - (chartAt H p.1).prod (LocalHomeomorph.refl E) := + ((tangentBundleCore I M).toFiberBundleCore.localTriv (achart H p.1)).toPartialHomeomorph ≫ₕ + (chartAt H p.1).prod (PartialHomeomorph.refl E) := rfl #align tangent_bundle.chart_at TangentBundle.chartAt -theorem chartAt_toLocalEquiv (p : TM) : - (chartAt (ModelProd H E) p).toLocalEquiv = - (tangentBundleCore I M).toFiberBundleCore.localTrivAsLocalEquiv (achart H p.1) ≫ - (chartAt H p.1).toLocalEquiv.prod (LocalEquiv.refl E) := +theorem chartAt_toPartialEquiv (p : TM) : + (chartAt (ModelProd H E) p).toPartialEquiv = + (tangentBundleCore I M).toFiberBundleCore.localTrivAsPartialEquiv (achart H p.1) ≫ + (chartAt H p.1).toPartialEquiv.prod (PartialEquiv.refl E) := rfl -#align tangent_bundle.chart_at_to_local_equiv TangentBundle.chartAt_toLocalEquiv +#align tangent_bundle.chart_at_to_local_equiv TangentBundle.chartAt_toPartialEquiv theorem trivializationAt_eq_localTriv (x : M) : trivializationAt E (TangentSpace I) x = @@ -244,7 +244,7 @@ theorem mem_chart_target_iff (p : H × E) (q : TM) : and_iff_left_iff_imp, mfld_simps] -/ simp only [FiberBundle.chartedSpace_chartAt, mfld_simps] - rw [LocalEquiv.prod_symm] + rw [PartialEquiv.prod_symm] simp (config := { contextual := true }) only [and_iff_left_iff_imp, mfld_simps] #align tangent_bundle.mem_chart_target_iff TangentBundle.mem_chart_target_iff @@ -308,7 +308,7 @@ instance tangentBundleCore.isSmooth : (tangentBundleCore I M).IsSmooth I := by rw [SmoothOn, contMDiffOn_iff_source_of_mem_maximalAtlas (subset_maximalAtlas I i.2), contMDiffOn_iff_contDiffOn] refine' ((contDiffOn_fderiv_coord_change I i j).congr fun x hx => _).mono _ - · rw [LocalEquiv.trans_source'] at hx + · rw [PartialEquiv.trans_source'] at hx simp_rw [Function.comp_apply, tangentBundleCore_coordChange, (i.1.extend I).right_inv hx.1] · exact (i.1.extend_image_source_inter j.1 I).subset · apply inter_subset_left @@ -327,29 +327,30 @@ end TangentBundleInstances between a product type and a sigma type, a.k.a. `TotalSpace.toProd`. -/ @[simp, mfld_simps] theorem tangentBundle_model_space_chartAt (p : TangentBundle I H) : - (chartAt (ModelProd H E) p).toLocalEquiv = (TotalSpace.toProd H E).toLocalEquiv := by + (chartAt (ModelProd H E) p).toPartialEquiv = (TotalSpace.toProd H E).toPartialEquiv := by ext x : 1 · ext; · rfl exact (tangentBundleCore I H).coordChange_self (achart _ x.1) x.1 (mem_achart_source H x.1) x.2 · -- porting note: was ext; · rfl; apply hEq_of_eq refine congr_arg (TotalSpace.mk _) ?_ exact (tangentBundleCore I H).coordChange_self (achart _ x.1) x.1 (mem_achart_source H x.1) x.2 - simp_rw [TangentBundle.chartAt, FiberBundleCore.localTriv, FiberBundleCore.localTrivAsLocalEquiv, - VectorBundleCore.toFiberBundleCore_baseSet, tangentBundleCore_baseSet] + simp_rw [TangentBundle.chartAt, FiberBundleCore.localTriv, + FiberBundleCore.localTrivAsPartialEquiv, VectorBundleCore.toFiberBundleCore_baseSet, + tangentBundleCore_baseSet] simp only [mfld_simps] #align tangent_bundle_model_space_chart_at tangentBundle_model_space_chartAt @[simp, mfld_simps] theorem tangentBundle_model_space_coe_chartAt (p : TangentBundle I H) : ⇑(chartAt (ModelProd H E) p) = TotalSpace.toProd H E := by - rw [← LocalHomeomorph.coe_coe, tangentBundle_model_space_chartAt]; rfl + rw [← PartialHomeomorph.coe_coe, tangentBundle_model_space_chartAt]; rfl #align tangent_bundle_model_space_coe_chart_at tangentBundle_model_space_coe_chartAt @[simp, mfld_simps] theorem tangentBundle_model_space_coe_chartAt_symm (p : TangentBundle I H) : ((chartAt (ModelProd H E) p).symm : ModelProd H E → TangentBundle I H) = (TotalSpace.toProd H E).symm := by - rw [← LocalHomeomorph.coe_coe, LocalHomeomorph.symm_toLocalEquiv, + rw [← PartialHomeomorph.coe_coe, PartialHomeomorph.symm_toPartialEquiv, tangentBundle_model_space_chartAt]; rfl #align tangent_bundle_model_space_coe_chart_at_symm tangentBundle_model_space_coe_chartAt_symm diff --git a/Mathlib/GroupTheory/Complement.lean b/Mathlib/GroupTheory/Complement.lean index 8e446606e9fd3..43b19480a6298 100644 --- a/Mathlib/GroupTheory/Complement.lean +++ b/Mathlib/GroupTheory/Complement.lean @@ -28,8 +28,8 @@ In this file we define the complement of a subgroup. - `isComplement'_of_coprime` : Subgroups of coprime order are complements. -/ - -open BigOperators Pointwise +open Set +open scoped BigOperators Pointwise namespace Subgroup @@ -107,32 +107,32 @@ theorem isComplement'_comm : IsComplement' H K ↔ IsComplement' K H := #align add_subgroup.is_complement'_comm AddSubgroup.isComplement'_comm @[to_additive] -theorem isComplement_top_singleton {g : G} : IsComplement (⊤ : Set G) {g} := +theorem isComplement_univ_singleton {g : G} : IsComplement (univ : Set G) {g} := ⟨fun ⟨_, _, rfl⟩ ⟨_, _, rfl⟩ h => Prod.ext (Subtype.ext (mul_right_cancel h)) rfl, fun x => ⟨⟨⟨x * g⁻¹, ⟨⟩⟩, g, rfl⟩, inv_mul_cancel_right x g⟩⟩ -#align subgroup.is_complement_top_singleton Subgroup.isComplement_top_singleton -#align add_subgroup.is_complement_top_singleton AddSubgroup.isComplement_top_singleton +#align subgroup.is_complement_top_singleton Subgroup.isComplement_univ_singleton +#align add_subgroup.is_complement_top_singleton AddSubgroup.isComplement_univ_singleton @[to_additive] -theorem isComplement_singleton_top {g : G} : IsComplement ({g} : Set G) ⊤ := +theorem isComplement_singleton_univ {g : G} : IsComplement ({g} : Set G) univ := ⟨fun ⟨⟨_, rfl⟩, _⟩ ⟨⟨_, rfl⟩, _⟩ h => Prod.ext rfl (Subtype.ext (mul_left_cancel h)), fun x => ⟨⟨⟨g, rfl⟩, g⁻¹ * x, ⟨⟩⟩, mul_inv_cancel_left g x⟩⟩ -#align subgroup.is_complement_singleton_top Subgroup.isComplement_singleton_top -#align add_subgroup.is_complement_singleton_top AddSubgroup.isComplement_singleton_top +#align subgroup.is_complement_singleton_top Subgroup.isComplement_singleton_univ +#align add_subgroup.is_complement_singleton_top AddSubgroup.isComplement_singleton_univ @[to_additive] -theorem isComplement_singleton_left {g : G} : IsComplement {g} S ↔ S = ⊤ := by +theorem isComplement_singleton_left {g : G} : IsComplement {g} S ↔ S = univ := by refine' - ⟨fun h => top_le_iff.mp fun x _ => _, fun h => (congr_arg _ h).mpr isComplement_singleton_top⟩ + ⟨fun h => top_le_iff.mp fun x _ => _, fun h => (congr_arg _ h).mpr isComplement_singleton_univ⟩ obtain ⟨⟨⟨z, rfl : z = g⟩, y, _⟩, hy⟩ := h.2 (g * x) rwa [← mul_left_cancel hy] #align subgroup.is_complement_singleton_left Subgroup.isComplement_singleton_left #align add_subgroup.is_complement_singleton_left AddSubgroup.isComplement_singleton_left @[to_additive] -theorem isComplement_singleton_right {g : G} : IsComplement S {g} ↔ S = ⊤ := by +theorem isComplement_singleton_right {g : G} : IsComplement S {g} ↔ S = univ := by refine' - ⟨fun h => top_le_iff.mp fun x _ => _, fun h => h ▸ isComplement_top_singleton⟩ + ⟨fun h => top_le_iff.mp fun x _ => _, fun h => h ▸ isComplement_univ_singleton⟩ obtain ⟨y, hy⟩ := h.2 (x * g) conv_rhs at hy => rw [← show y.2.1 = g from y.2.2] rw [← mul_right_cancel hy] @@ -141,7 +141,7 @@ theorem isComplement_singleton_right {g : G} : IsComplement S {g} ↔ S = ⊤ := #align add_subgroup.is_complement_singleton_right AddSubgroup.isComplement_singleton_right @[to_additive] -theorem isComplement_top_left : IsComplement ⊤ S ↔ ∃ g : G, S = {g} := by +theorem isComplement_univ_left : IsComplement univ S ↔ ∃ g : G, S = {g} := by refine' ⟨fun h => Set.exists_eq_singleton_iff_nonempty_subsingleton.mpr ⟨_, fun a ha b hb => _⟩, _⟩ · obtain ⟨a, _⟩ := h.2 1 @@ -150,12 +150,12 @@ theorem isComplement_top_left : IsComplement ⊤ S ↔ ∃ g : G, S = {g} := by h.1 ((inv_mul_self a).trans (inv_mul_self b).symm) exact Subtype.ext_iff.mp (Prod.ext_iff.mp this).2 · rintro ⟨g, rfl⟩ - exact isComplement_top_singleton -#align subgroup.is_complement_top_left Subgroup.isComplement_top_left -#align add_subgroup.is_complement_top_left AddSubgroup.isComplement_top_left + exact isComplement_univ_singleton +#align subgroup.is_complement_top_left Subgroup.isComplement_univ_left +#align add_subgroup.is_complement_top_left AddSubgroup.isComplement_univ_left @[to_additive] -theorem isComplement_top_right : IsComplement S ⊤ ↔ ∃ g : G, S = {g} := by +theorem isComplement_univ_right : IsComplement S univ ↔ ∃ g : G, S = {g} := by refine' ⟨fun h => Set.exists_eq_singleton_iff_nonempty_subsingleton.mpr ⟨_, fun a ha b hb => _⟩, _⟩ · obtain ⟨a, _⟩ := h.2 1 @@ -164,19 +164,27 @@ theorem isComplement_top_right : IsComplement S ⊤ ↔ ∃ g : G, S = {g} := by h.1 ((mul_inv_self a).trans (mul_inv_self b).symm) exact Subtype.ext_iff.mp (Prod.ext_iff.mp this).1 · rintro ⟨g, rfl⟩ - exact isComplement_singleton_top -#align subgroup.is_complement_top_right Subgroup.isComplement_top_right -#align add_subgroup.is_complement_top_right AddSubgroup.isComplement_top_right + exact isComplement_singleton_univ +#align subgroup.is_complement_top_right Subgroup.isComplement_univ_right +#align add_subgroup.is_complement_top_right AddSubgroup.isComplement_univ_right + +@[to_additive] +lemma IsComplement.mul_eq (h : IsComplement S T) : S * T = univ := + eq_univ_of_forall fun x ↦ by simpa [mem_mul] using (h.existsUnique x).exists + +@[to_additive AddSubgroup.IsComplement.card_mul_card] +lemma IsComplement.card_mul_card (h : IsComplement S T) : Nat.card S * Nat.card T = Nat.card G := + (Nat.card_prod _ _).symm.trans $ Nat.card_congr $ Equiv.ofBijective _ h @[to_additive] theorem isComplement'_top_bot : IsComplement' (⊤ : Subgroup G) ⊥ := - isComplement_top_singleton + isComplement_univ_singleton #align subgroup.is_complement'_top_bot Subgroup.isComplement'_top_bot #align add_subgroup.is_complement'_top_bot AddSubgroup.isComplement'_top_bot @[to_additive] theorem isComplement'_bot_top : IsComplement' (⊥ : Subgroup G) ⊤ := - isComplement_singleton_top + isComplement_singleton_univ #align subgroup.is_complement'_bot_top Subgroup.isComplement'_bot_top #align add_subgroup.is_complement'_bot_top AddSubgroup.isComplement'_bot_top @@ -194,13 +202,13 @@ theorem isComplement'_bot_right : IsComplement' H ⊥ ↔ H = ⊤ := @[to_additive (attr := simp)] theorem isComplement'_top_left : IsComplement' ⊤ H ↔ H = ⊥ := - isComplement_top_left.trans coe_eq_singleton + isComplement_univ_left.trans coe_eq_singleton #align subgroup.is_complement'_top_left Subgroup.isComplement'_top_left #align add_subgroup.is_complement'_top_left AddSubgroup.isComplement'_top_left @[to_additive (attr := simp)] theorem isComplement'_top_right : IsComplement' H ⊤ ↔ H = ⊥ := - isComplement_top_right.trans coe_eq_singleton + isComplement_univ_right.trans coe_eq_singleton #align subgroup.is_complement'_top_right Subgroup.isComplement'_top_right #align add_subgroup.is_complement'_top_right AddSubgroup.isComplement'_top_right @@ -309,7 +317,8 @@ theorem range_mem_rightTransversals {f : Quotient (QuotientGroup.rightRel H) → #align add_subgroup.range_mem_right_transversals AddSubgroup.range_mem_rightTransversals @[to_additive] -theorem exists_left_transversal (g : G) : ∃ S ∈ leftTransversals (H : Set G), g ∈ S := by +lemma exists_left_transversal (H : Subgroup G) (g : G) : + ∃ S ∈ leftTransversals (H : Set G), g ∈ S := by classical refine' ⟨Set.range (Function.update Quotient.out' _ g), range_mem_leftTransversals fun q => _, @@ -322,7 +331,8 @@ theorem exists_left_transversal (g : G) : ∃ S ∈ leftTransversals (H : Set G) #align add_subgroup.exists_left_transversal AddSubgroup.exists_left_transversal @[to_additive] -theorem exists_right_transversal (g : G) : ∃ S ∈ rightTransversals (H : Set G), g ∈ S := by +lemma exists_right_transversal (H : Subgroup G) (g : G) : + ∃ S ∈ rightTransversals (H : Set G), g ∈ S := by classical refine' ⟨Set.range (Function.update Quotient.out' _ g), range_mem_rightTransversals fun q => _, @@ -333,6 +343,39 @@ theorem exists_right_transversal (g : G) : ∃ S ∈ rightTransversals (H : Set #align subgroup.exists_right_transversal Subgroup.exists_right_transversal #align add_subgroup.exists_right_transversal AddSubgroup.exists_right_transversal +/-- Given two subgroups `H' ⊆ H`, there exists a left transversal to `H'` inside `H`. -/ +@[to_additive "Given two subgroups `H' ⊆ H`, there exists a transversal to `H'` inside `H`"] +lemma exists_left_transversal_of_le {H' H : Subgroup G} (h : H' ≤ H) : + ∃ S : Set G, S * H' = H ∧ Nat.card S * Nat.card H' = Nat.card H := by + let H'' : Subgroup H := H'.comap H.subtype + have : H' = H''.map H.subtype := by simp [h] + rw [this] + obtain ⟨S, cmem, -⟩ := H''.exists_left_transversal 1 + refine ⟨H.subtype '' S, ?_, ?_⟩ + · have : H.subtype '' (S * H'') = H.subtype '' S * H''.map H.subtype := image_mul H.subtype + rw [← this, cmem.mul_eq] + simp [Set.ext_iff] + · rw [← cmem.card_mul_card] + refine congr_arg₂ (· * ·) ?_ ?_ <;> + exact Nat.card_congr (Equiv.Set.image _ _ $ subtype_injective H).symm + +/-- Given two subgroups `H' ⊆ H`, there exists a right transversal to `H'` inside `H`. -/ +@[to_additive "Given two subgroups `H' ⊆ H`, there exists a transversal to `H'` inside `H`"] +lemma exists_right_transversal_of_le {H' H : Subgroup G} (h : H' ≤ H) : + ∃ S : Set G, H' * S = H ∧ Nat.card H' * Nat.card S = Nat.card H := by + let H'' : Subgroup H := H'.comap H.subtype + have : H' = H''.map H.subtype := by simp [h] + rw [this] + obtain ⟨S, cmem, -⟩ := H''.exists_right_transversal 1 + refine ⟨H.subtype '' S, ?_, ?_⟩ + · have : H.subtype '' (H'' * S) = H''.map H.subtype * H.subtype '' S := image_mul H.subtype + rw [← this, cmem.mul_eq] + simp [Set.ext_iff] + · have : Nat.card H'' * Nat.card S = Nat.card H := cmem.card_mul_card + rw [← this] + refine congr_arg₂ (· * ·) ?_ ?_ <;> + exact Nat.card_congr (Equiv.Set.image _ _ $ subtype_injective H).symm + namespace IsComplement /-- The equivalence `G ≃ S × T`, such that the inverse is `(*) : S × T → G` -/ diff --git a/Mathlib/GroupTheory/Exponent.lean b/Mathlib/GroupTheory/Exponent.lean index 1479a4106e6b8..f532888920a15 100644 --- a/Mathlib/GroupTheory/Exponent.lean +++ b/Mathlib/GroupTheory/Exponent.lean @@ -236,6 +236,21 @@ theorem _root_.Nat.Prime.exists_orderOf_eq_pow_factorization_exponent {p : ℕ} #align nat.prime.exists_order_of_eq_pow_factorization_exponent Nat.Prime.exists_orderOf_eq_pow_factorization_exponent #align nat.prime.exists_order_of_eq_pow_padic_val_nat_add_exponent Nat.Prime.exists_addOrderOf_eq_pow_padic_val_nat_add_exponent +/-- A nontrivial monoid has prime exponent `p` if and only if every non-identity element has +order `p`. -/ +@[to_additive] +lemma exponent_eq_prime_iff {G : Type*} [Monoid G] [Nontrivial G] {p : ℕ} (hp : p.Prime) : + Monoid.exponent G = p ↔ ∀ g : G, g ≠ 1 → orderOf g = p := by + refine ⟨fun hG g hg ↦ ?_, fun h ↦ dvd_antisymm ?_ ?_⟩ + · rw [Ne.def, ← orderOf_eq_one_iff] at hg + exact Eq.symm <| (hp.dvd_iff_eq hg).mp <| hG ▸ Monoid.order_dvd_exponent g + · apply Monoid.exponent_dvd_of_forall_pow_eq_one G p fun g ↦ ?_ + by_cases hg : g = 1 + · simp [hg] + · simpa [h g hg] using pow_orderOf_eq_one g + · obtain ⟨g, hg⟩ := exists_ne (1 : G) + simpa [h g hg] using Monoid.order_dvd_exponent g + variable {G} @[to_additive] @@ -374,6 +389,23 @@ end CancelCommMonoid end Monoid +section Group + +@[to_additive AddGroup.one_lt_exponent] +lemma Group.one_lt_exponent [Group G] [Finite G] [Nontrivial G] : + 1 < Monoid.exponent G := by + let _inst := Fintype.ofFinite G + obtain ⟨g, hg⟩ := exists_ne (1 : G) + rw [← Monoid.lcm_order_eq_exponent] + have hg' : 2 ≤ orderOf g := Nat.lt_of_le_of_ne (orderOf_pos g) <| by + simpa [eq_comm, orderOf_eq_one_iff] using hg + refine hg'.trans <| Nat.le_of_dvd ?_ <| Finset.dvd_lcm (by simp) + rw [Nat.pos_iff_ne_zero, Ne.def, Finset.lcm_eq_zero_iff] + rintro ⟨x, -, hx⟩ + exact (orderOf_pos x).ne' hx + +end Group + section CommGroup open Subgroup diff --git a/Mathlib/GroupTheory/HNNExtension.lean b/Mathlib/GroupTheory/HNNExtension.lean index 0350fceacee4d..aee574848c695 100644 --- a/Mathlib/GroupTheory/HNNExtension.lean +++ b/Mathlib/GroupTheory/HNNExtension.lean @@ -181,13 +181,8 @@ structure TransversalPair : Type _ := compl : ∀ u, IsComplement (toSubgroup A B u : Subgroup G) (set u) instance TransversalPair.nonempty : Nonempty (TransversalPair G A B) := by - have := fun u => exists_right_transversal (H := toSubgroup A B u) (1 : G) - simp only [Classical.skolem] at this - rcases this with ⟨t, ht⟩ - apply Nonempty.intro - exact - { set := t - compl := fun i => (ht i).1 } + choose t ht using fun u ↦ (toSubgroup A B u).exists_right_transversal 1 + exact ⟨⟨t, fun i ↦ (ht i).1⟩⟩ /-- A reduced word is a `head`, which is an element of `G`, followed by the product list of pairs. There should also be no sequences of the form `t^u * g * t^-u`, where `g` is in diff --git a/Mathlib/GroupTheory/OrderOfElement.lean b/Mathlib/GroupTheory/OrderOfElement.lean index 86394cbe12d6b..ac769989cd29a 100644 --- a/Mathlib/GroupTheory/OrderOfElement.lean +++ b/Mathlib/GroupTheory/OrderOfElement.lean @@ -351,6 +351,11 @@ theorem orderOf_injective {H : Type*} [Monoid H] (f : G →* H) (hf : Function.I #align order_of_injective orderOf_injective #align add_order_of_injective addOrderOf_injective +@[to_additive] +theorem Function.Injective.isOfFinOrder_iff [Monoid H] {f : G →* H} (hf : Injective f) : + IsOfFinOrder (f x) ↔ IsOfFinOrder x := by + rw [← orderOf_pos_iff, orderOf_injective f hf x, ← orderOf_pos_iff] + @[to_additive (attr := norm_cast, simp)] theorem orderOf_submonoid {H : Submonoid G} (y : H) : orderOf (y : G) = orderOf y := orderOf_injective H.subtype Subtype.coe_injective y diff --git a/Mathlib/GroupTheory/Perm/Cycle/Basic.lean b/Mathlib/GroupTheory/Perm/Cycle/Basic.lean index 15c0d11bea434..b0b0f7b1fc3a0 100644 --- a/Mathlib/GroupTheory/Perm/Cycle/Basic.lean +++ b/Mathlib/GroupTheory/Perm/Cycle/Basic.lean @@ -1220,9 +1220,9 @@ end CycleOf ### `cycleFactors` -/ - variable [DecidableEq α] +open scoped List in /-- Given a list `l : List α` and a permutation `f : perm α` whose nonfixed points are all in `l`, recursively factors `f` into cycles. -/ def cycleFactorsAux [Fintype α] : @@ -1263,7 +1263,7 @@ def cycleFactorsAux [Fintype α] : List.cons_perm_iff_perm_erase.2 ⟨hg, List.Perm.refl _⟩ have : ∀ h ∈ m.erase g, Disjoint g h := (List.pairwise_cons.1 - ((hgm.pairwise_iff fun a b (h : Disjoint a b) => h.symm).2 hm₃)).1 + ((hgm.pairwise_iff @fun a b (h : Disjoint a b) => h.symm).2 hm₃)).1 by_cases id fun hgy : g y ≠ y => (disjoint_prod_right _ this y).resolve_right <| by have hsc : SameCycle f⁻¹ x (f y) := by @@ -1303,13 +1303,14 @@ theorem mem_list_cycles_iff {α : Type*} [Finite α] {l : List (Perm α)} exact key a (mem_inter_of_mem ha hτa) #align equiv.perm.mem_list_cycles_iff Equiv.Perm.mem_list_cycles_iff +open scoped List in theorem list_cycles_perm_list_cycles {α : Type*} [Finite α] {l₁ l₂ : List (Perm α)} (h₀ : l₁.prod = l₂.prod) (h₁l₁ : ∀ σ : Perm α, σ ∈ l₁ → σ.IsCycle) (h₁l₂ : ∀ σ : Perm α, σ ∈ l₂ → σ.IsCycle) (h₂l₁ : l₁.Pairwise Disjoint) (h₂l₂ : l₂.Pairwise Disjoint) : l₁ ~ l₂ := by classical refine' - (List.perm_ext (nodup_of_pairwise_disjoint_cycles h₁l₁ h₂l₁) + (List.perm_ext_iff_of_nodup (nodup_of_pairwise_disjoint_cycles h₁l₁ h₂l₁) (nodup_of_pairwise_disjoint_cycles h₁l₂ h₂l₂)).mpr fun σ => _ by_cases hσ : σ.IsCycle @@ -1348,6 +1349,7 @@ def cycleFactorsFinset : Finset (Perm α) := hl.right.right hl'.right.right) #align equiv.perm.cycle_factors_finset Equiv.Perm.cycleFactorsFinset +open scoped List in theorem cycleFactorsFinset_eq_list_toFinset {σ : Perm α} {l : List (Perm α)} (hn : l.Nodup) : σ.cycleFactorsFinset = l.toFinset ↔ (∀ f : Perm α, f ∈ l → f.IsCycle) ∧ l.Pairwise Disjoint ∧ l.prod = σ := by @@ -1361,7 +1363,8 @@ theorem cycleFactorsFinset_eq_list_toFinset {σ : Perm α} {l : List (Perm α)} have hperm : l ~ l' := List.perm_of_nodup_nodup_toFinset_eq hn hn' h.symm refine' ⟨_, _, _⟩ · exact fun _ h => hc' _ (hperm.subset h) - · rwa [List.Perm.pairwise_iff Disjoint.symmetric hperm] + · have := List.Perm.pairwise_iff (@Disjoint.symmetric _) hperm + rwa [this] · rw [← hp', hperm.symm.prod_eq'] refine' hd'.imp _ exact Disjoint.commute diff --git a/Mathlib/GroupTheory/Perm/Cycle/Type.lean b/Mathlib/GroupTheory/Perm/Cycle/Type.lean index 990e070f8df2e..86064bffa2f56 100644 --- a/Mathlib/GroupTheory/Perm/Cycle/Type.lean +++ b/Mathlib/GroupTheory/Perm/Cycle/Type.lean @@ -293,7 +293,7 @@ theorem mem_cycleType_iff {n : ℕ} {σ : Perm α} : obtain ⟨l, rfl, hlc, hld⟩ := truncCycleFactors σ rw [cycleType_eq _ rfl hlc hld, Multiset.mem_coe, List.mem_map] at h obtain ⟨c, cl, rfl⟩ := h - rw [(List.perm_cons_erase cl).pairwise_iff Disjoint.symmetric] at hld + rw [(List.perm_cons_erase cl).pairwise_iff @(Disjoint.symmetric)] at hld refine' ⟨c, (l.erase c).prod, _, _, hlc _ cl, rfl⟩ · rw [← List.prod_cons, (List.perm_cons_erase cl).symm.prod_eq' (hld.imp Disjoint.commute)] · exact disjoint_prod_right _ fun g => List.rel_of_pairwise_cons hld diff --git a/Mathlib/GroupTheory/Perm/Support.lean b/Mathlib/GroupTheory/Perm/Support.lean index d3e7fa25ec23c..fc8bdcee2d395 100644 --- a/Mathlib/GroupTheory/Perm/Support.lean +++ b/Mathlib/GroupTheory/Perm/Support.lean @@ -129,6 +129,7 @@ theorem disjoint_prod_right (l : List (Perm α)) (h : ∀ g ∈ l, Disjoint f g) exact (h _ (List.mem_cons_self _ _)).mul_right (ih fun g hg => h g (List.mem_cons_of_mem _ hg)) #align equiv.perm.disjoint_prod_right Equiv.Perm.disjoint_prod_right +open scoped List in theorem disjoint_prod_perm {l₁ l₂ : List (Perm α)} (hl : l₁.Pairwise Disjoint) (hp : l₁ ~ l₂) : l₁.prod = l₂.prod := hp.prod_eq' <| hl.imp Disjoint.commute diff --git a/Mathlib/GroupTheory/PushoutI.lean b/Mathlib/GroupTheory/PushoutI.lean index 31a6d39b6746f..9d4feaead5dcf 100644 --- a/Mathlib/GroupTheory/PushoutI.lean +++ b/Mathlib/GroupTheory/PushoutI.lean @@ -229,9 +229,7 @@ structure Transversal : Type _ where compl : ∀ i, IsComplement (φ i).range (set i) theorem transversal_nonempty (hφ : ∀ i, Injective (φ i)) : Nonempty (Transversal φ) := by - have := fun i => exists_right_transversal (H := (φ i).range) 1 - simp only [Classical.skolem] at this - rcases this with ⟨t, ht⟩ + choose t ht using fun i => (φ i).range.exists_right_transversal 1 apply Nonempty.intro exact { injective := hφ diff --git a/Mathlib/GroupTheory/Schreier.lean b/Mathlib/GroupTheory/Schreier.lean index 0951415f54021..e066b6ab84ca0 100644 --- a/Mathlib/GroupTheory/Schreier.lean +++ b/Mathlib/GroupTheory/Schreier.lean @@ -106,7 +106,7 @@ theorem exists_finset_card_le_mul [FiniteIndex H] {S : Finset G} (hS : closure ( ∃ T : Finset H, T.card ≤ H.index * S.card ∧ closure (T : Set H) = ⊤ := by letI := H.fintypeQuotientOfFiniteIndex haveI : DecidableEq G := Classical.decEq G - obtain ⟨R₀, hR : R₀ ∈ rightTransversals (H : Set G), hR1⟩ := exists_right_transversal (1 : G) + obtain ⟨R₀, hR, hR1⟩ := H.exists_right_transversal 1 haveI : Fintype R₀ := Fintype.ofEquiv _ (toEquiv hR) let R : Finset G := Set.toFinset R₀ replace hR : (R : Set G) ∈ rightTransversals (H : Set G) := by rwa [Set.coe_toFinset] diff --git a/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean b/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean index eaa1466940348..996979b0824de 100644 --- a/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean +++ b/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean @@ -651,4 +651,32 @@ protected theorem ZMod.exponent (n : ℕ) : AddMonoid.exponent (ZMod n) = n := b · rw [IsAddCyclic.exponent_eq_zero_of_infinite] · rw [IsAddCyclic.exponent_eq_card, card] +/-- A group of order `p ^ 2` is not cyclic if and only if its exponent is `p`. -/ +@[to_additive] +lemma not_isCyclic_iff_exponent_eq_prime [Group α] {p : ℕ} (hp : p.Prime) + (hα : Nat.card α = p ^ 2) : ¬ IsCyclic α ↔ Monoid.exponent α = p := by + -- G is a nontrivial fintype of cardinality `p ^ 2` + let _inst : Fintype α := @Fintype.ofFinite α <| Nat.finite_of_card_ne_zero <| by aesop + have hα' : Fintype.card α = p ^ 2 := by simpa using hα + have := (Fintype.one_lt_card_iff_nontrivial (α := α)).mp <| + hα' ▸ one_lt_pow hp.one_lt two_ne_zero + /- in the forward direction, we apply `exponent_eq_prime_iff`, and the reverse direction follows + immediately because if `α` has exponent `p`, it has no element of order `p ^ 2`. -/ + refine ⟨fun h_cyc ↦ (Monoid.exponent_eq_prime_iff hp).mpr fun g hg ↦ ?_, fun h_exp h_cyc ↦ by + obtain (rfl|rfl) := eq_zero_or_one_of_sq_eq_self <| hα' ▸ h_exp ▸ (h_cyc.exponent_eq_card).symm + · exact Nat.not_prime_zero hp + · exact Nat.not_prime_one hp⟩ + /- we must show every non-identity element has order `p`. By Lagrange's theorem, the only possible + orders of `g` are `1`, `p`, or `p ^ 2`. It can't be the former because `g ≠ 1`, and it can't + the latter because the group isn't cyclic. -/ + have := (Nat.mem_divisors (m := p ^ 2)).mpr ⟨hα' ▸ orderOf_dvd_card (x := g), by aesop⟩ + simp? [Nat.divisors_prime_pow hp 2] at this says + simp only [Nat.divisors_prime_pow hp 2, Finset.mem_map, Finset.mem_range, + Function.Embedding.coeFn_mk] at this + obtain ⟨a, ha, ha'⟩ := this + interval_cases a + · exact False.elim <| hg <| orderOf_eq_one_iff.mp <| by aesop + · aesop + · exact False.elim <| h_cyc <| isCyclic_of_orderOf_eq_card g <| by aesop + end Exponent diff --git a/Mathlib/GroupTheory/Subgroup/ZPowers.lean b/Mathlib/GroupTheory/Subgroup/ZPowers.lean index 4136676683f8d..4a2cfc434fad9 100644 --- a/Mathlib/GroupTheory/Subgroup/ZPowers.lean +++ b/Mathlib/GroupTheory/Subgroup/ZPowers.lean @@ -171,6 +171,11 @@ theorem Int.mem_zmultiples_iff {a b : ℤ} : b ∈ AddSubgroup.zmultiples a ↔ exists_congr fun k => by rw [mul_comm, eq_comm, ← smul_eq_mul] #align int.mem_zmultiples_iff Int.mem_zmultiples_iff +@[simp] +lemma Int.zmultiples_one : AddSubgroup.zmultiples (1 : ℤ) = ⊤ := by + ext z + simpa only [AddSubgroup.mem_top, iff_true] using ⟨z, zsmul_int_one z⟩ + theorem ofMul_image_zpowers_eq_zmultiples_ofMul {x : G} : Additive.ofMul '' (Subgroup.zpowers x : Set G) = AddSubgroup.zmultiples (Additive.ofMul x) := by ext y diff --git a/Mathlib/LinearAlgebra/AffineSpace/Combination.lean b/Mathlib/LinearAlgebra/AffineSpace/Combination.lean index b8cab2b2369ce..fe55de73cdca5 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Combination.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Combination.lean @@ -3,7 +3,6 @@ Copyright (c) 2020 Joseph Myers. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Joseph Myers -/ -import Mathlib.Algebra.IndicatorFunction import Mathlib.Algebra.Module.BigOperators import Mathlib.Data.Fintype.BigOperators import Mathlib.LinearAlgebra.AffineSpace.AffineMap @@ -165,8 +164,8 @@ theorem weightedVSubOfPoint_indicator_subset (w : ι → k) (p : ι → P) (b : (h : s₁ ⊆ s₂) : s₁.weightedVSubOfPoint p b w = s₂.weightedVSubOfPoint p b (Set.indicator (↑s₁) w) := by rw [weightedVSubOfPoint_apply, weightedVSubOfPoint_apply] - exact - Set.sum_indicator_subset_of_eq_zero w (fun i wi => wi • (p i -ᵥ b : V)) h fun i => zero_smul k _ + exact Eq.symm $ + sum_indicator_subset_of_eq_zero w (fun i wi => wi • (p i -ᵥ b : V)) h fun i => zero_smul k _ #align finset.weighted_vsub_of_point_indicator_subset Finset.weightedVSubOfPoint_indicator_subset /-- A weighted sum, over the image of an embedding, equals a weighted @@ -903,7 +902,7 @@ theorem centroidWeightsIndicator_def : /-- The sum of the weights for the centroid indexed by a `Fintype`. -/ theorem sum_centroidWeightsIndicator [Fintype ι] : ∑ i, s.centroidWeightsIndicator k i = ∑ i in s, s.centroidWeights k i := - (Set.sum_indicator_subset _ (subset_univ _)).symm + sum_indicator_subset _ (subset_univ _) #align finset.sum_centroid_weights_indicator Finset.sum_centroidWeightsIndicator /-- In the characteristic zero case, the weights in the centroid @@ -1100,7 +1099,7 @@ theorem eq_affineCombination_of_mem_affineSpan {p1 : P} {p : ι → P} let s' := insert i0 s let w' := Set.indicator (↑s) w have h' : ∑ i in s', w' i = 0 := by - rw [← h, Set.sum_indicator_subset _ (Finset.subset_insert i0 s)] + rw [← h, Finset.sum_indicator_subset _ (Finset.subset_insert i0 s)] have hs' : s'.weightedVSub p w' = p1 -ᵥ p i0 := by rw [hs] exact (Finset.weightedVSub_indicator_subset _ _ (Finset.subset_insert i0 s)).symm diff --git a/Mathlib/LinearAlgebra/AffineSpace/Independent.lean b/Mathlib/LinearAlgebra/AffineSpace/Independent.lean index 71d355e43e595..ae9605f394ce5 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Independent.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Independent.lean @@ -78,7 +78,7 @@ theorem affineIndependent_iff_of_fintype [Fintype ι] (p : ι → P) : · exact fun h w hw hs i => h Finset.univ w hw hs i (Finset.mem_univ _) · intro h s w hw hs i hi rw [Finset.weightedVSub_indicator_subset _ _ (Finset.subset_univ s)] at hs - rw [Set.sum_indicator_subset _ (Finset.subset_univ s)] at hw + rw [← Finset.sum_indicator_subset _ (Finset.subset_univ s)] at hw replace h := h ((↑s : Set ι).indicator w) hw hs i simpa [hi] using h #align affine_independent_iff_of_fintype affineIndependent_iff_of_fintype @@ -191,8 +191,8 @@ theorem affineIndependent_iff_indicator_eq_of_affineCombination_eq (p : ι → P ext i by_cases hi : i ∈ s1 ∪ s2 · rw [← sub_eq_zero] - rw [Set.sum_indicator_subset _ (Finset.subset_union_left s1 s2)] at hw1 - rw [Set.sum_indicator_subset _ (Finset.subset_union_right s1 s2)] at hw2 + rw [← Finset.sum_indicator_subset _ (Finset.subset_union_left s1 s2)] at hw1 + rw [← Finset.sum_indicator_subset _ (Finset.subset_union_right s1 s2)] at hw2 have hws : (∑ i in s1 ∪ s2, (Set.indicator (↑s1) w1 - Set.indicator (↑s2) w2) i) = 0 := by simp [hw1, hw2] rw [Finset.affineCombination_indicator_subset _ _ (Finset.subset_union_left s1 s2), @@ -242,9 +242,9 @@ theorem affineIndependent_iff_eq_of_fintype_affineCombination_eq [Fintype ι] (p simpa only [Set.indicator_univ, Finset.coe_univ] using h _ _ w1 w2 hw1 hw2 hweq · intro h s1 s2 w1 w2 hw1 hw2 hweq have hw1' : (∑ i, (s1 : Set ι).indicator w1 i) = 1 := by - rwa [Set.sum_indicator_subset _ (Finset.subset_univ s1)] at hw1 + rwa [Finset.sum_indicator_subset _ (Finset.subset_univ s1)] have hw2' : (∑ i, (s2 : Set ι).indicator w2 i) = 1 := by - rwa [Set.sum_indicator_subset _ (Finset.subset_univ s2)] at hw2 + rwa [Finset.sum_indicator_subset _ (Finset.subset_univ s2)] rw [Finset.affineCombination_indicator_subset w1 p (Finset.subset_univ s1), Finset.affineCombination_indicator_subset w2 p (Finset.subset_univ s2)] at hweq exact h _ _ hw1' hw2' hweq diff --git a/Mathlib/LinearAlgebra/BilinearForm/Basic.lean b/Mathlib/LinearAlgebra/BilinearForm/Basic.lean index c377b5e193f46..e5452c4decaa7 100644 --- a/Mathlib/LinearAlgebra/BilinearForm/Basic.lean +++ b/Mathlib/LinearAlgebra/BilinearForm/Basic.lean @@ -61,6 +61,8 @@ structure BilinForm (R : Type*) (M : Type*) [Semiring R] [AddCommMonoid M] [Modu variable {R : Type*} {M : Type*} [Semiring R] [AddCommMonoid M] [Module R M] +variable {S : Type*} [CommSemiring S] [Algebra S R] [Module S M] [IsScalarTower S R M] + variable {R₁ : Type*} {M₁ : Type*} [Ring R₁] [AddCommGroup M₁] [Module R₁ M₁] variable {R₂ : Type*} {M₂ : Type*} [CommSemiring R₂] [AddCommMonoid M₂] [Module R₂ M₂] @@ -137,6 +139,14 @@ theorem sub_right (x y z : M₁) : B₁ x (y - z) = B₁ x y - B₁ x z := by rw [sub_eq_add_neg, sub_eq_add_neg, add_right, neg_right] #align bilin_form.sub_right BilinForm.sub_right +@[simp] +lemma smul_left_of_tower (r : S) (x y : M) : B (r • x) y = r • B x y := by + rw [← IsScalarTower.algebraMap_smul R r, smul_left, Algebra.smul_def] + +@[simp] +lemma smul_right_of_tower (r : S) (x y : M) : B x (r • y) = r • B x y := by + rw [← IsScalarTower.algebraMap_smul R r, smul_right, Algebra.smul_def] + variable {D : BilinForm R M} {D₁ : BilinForm R₁ M₁} -- TODO: instantiate `FunLike` diff --git a/Mathlib/LinearAlgebra/BilinearForm/DualLattice.lean b/Mathlib/LinearAlgebra/BilinearForm/DualLattice.lean new file mode 100644 index 0000000000000..9c21359640e88 --- /dev/null +++ b/Mathlib/LinearAlgebra/BilinearForm/DualLattice.lean @@ -0,0 +1,130 @@ +/- +Copyright (c) 2018 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.LinearAlgebra.BilinearForm.Properties + +/-! + +# Dual submodule with respect to a bilinear form. + +## Main definitions and results +- `BilinForm.dualSubmodule`: The dual submodule with respect to a bilinear form. +- `BilinForm.dualSubmodule_span_of_basis`: The dual of a lattice is spanned by the dual basis. + +## TODO +Properly develop the material in the context of lattices. +-/ + +variable {R S M} [CommRing R] [Field S] [AddCommGroup M] +variable [Algebra R S] [Module R M] [Module S M] [IsScalarTower R S M] + +namespace BilinForm + +variable (B : BilinForm S M) + +/-- The dual submodule of a submodule with respect to a bilinear form. -/ +def dualSubmodule (N : Submodule R M) : Submodule R M where + carrier := { x | ∀ y ∈ N, B x y ∈ (1 : Submodule R S) } + add_mem' {a b} ha hb y hy := by simpa using add_mem (ha y hy) (hb y hy) + zero_mem' y _ := by rw [B.zero_left]; exact zero_mem _ + smul_mem' r a ha y hy := by + convert (1 : Submodule R S).smul_mem r (ha y hy) + rw [← IsScalarTower.algebraMap_smul S r a, bilin_smul_left, Algebra.smul_def] + +lemma mem_dualSubmodule {N : Submodule R M} {x} : + x ∈ B.dualSubmodule N ↔ ∀ y ∈ N, B x y ∈ (1 : Submodule R S) := Iff.rfl + +lemma le_flip_dualSubmodule {N₁ N₂ : Submodule R M} : + N₁ ≤ B.flip.dualSubmodule N₂ ↔ N₂ ≤ B.dualSubmodule N₁ := by + show (∀ (x : M), x ∈ N₁ → _) ↔ ∀ (x : M), x ∈ N₂ → _ + simp only [mem_dualSubmodule, Submodule.mem_one, flip_apply] + exact forall₂_swap + +/-- The natural paring of `B.dualSubmodule N` and `N`. +This is bundled as a bilinear map in `BilinForm.dualSubmoduleToDual`. -/ +noncomputable +def dualSubmoduleParing {N : Submodule R M} (x : B.dualSubmodule N) (y : N) : R := + (x.prop y y.prop).choose + +@[simp] +lemma dualSubmoduleParing_spec {N : Submodule R M} (x : B.dualSubmodule N) (y : N) : + algebraMap R S (B.dualSubmoduleParing x y) = B x y := + (x.prop y y.prop).choose_spec + +/-- The natural paring of `B.dualSubmodule N` and `N`. -/ +-- TODO: Show that this is perfect when `N` is a lattice and `B` is nondegenerate. +@[simps] +noncomputable +def dualSubmoduleToDual [NoZeroSMulDivisors R S] (N : Submodule R M) : + B.dualSubmodule N →ₗ[R] Module.Dual R N := + { toFun := fun x ↦ + { toFun := B.dualSubmoduleParing x + map_add' := fun x y ↦ NoZeroSMulDivisors.algebraMap_injective R S (by simp) + map_smul' := fun r m ↦ NoZeroSMulDivisors.algebraMap_injective R S + (by simp [← Algebra.smul_def]) } + map_add' := fun x y ↦ LinearMap.ext fun z ↦ NoZeroSMulDivisors.algebraMap_injective R S + (by simp) + map_smul' := fun r x ↦ LinearMap.ext fun y ↦ NoZeroSMulDivisors.algebraMap_injective R S + (by simp [← Algebra.smul_def]) } + +lemma dualSubmoduleToDual_injective (hB : B.Nondegenerate) [NoZeroSMulDivisors R S] + (N : Submodule R M) (hN : Submodule.span S (N : Set M) = ⊤) : + Function.Injective (B.dualSubmoduleToDual N) := by + intro x y e + ext + apply LinearMap.ker_eq_bot.mp hB.ker_eq_bot + apply LinearMap.ext_on hN + intro z hz + simpa using congr_arg (algebraMap R S) (LinearMap.congr_fun e ⟨z, hz⟩) + +lemma dualSubmodule_span_of_basis {ι} [Fintype ι] [DecidableEq ι] + (hB : B.Nondegenerate) (b : Basis ι S M) : + B.dualSubmodule (Submodule.span R (Set.range b)) = + Submodule.span R (Set.range <| B.dualBasis hB b) := by + apply le_antisymm + · intro x hx + rw [← (B.dualBasis hB b).sum_repr x] + apply sum_mem + rintro i - + obtain ⟨r, hr⟩ := hx (b i) (Submodule.subset_span ⟨_, rfl⟩) + simp only [dualBasis_repr_apply, ← hr, Algebra.linearMap_apply, algebraMap_smul] + apply Submodule.smul_mem + exact Submodule.subset_span ⟨_, rfl⟩ + · rw [Submodule.span_le] + rintro _ ⟨i, rfl⟩ y hy + obtain ⟨f, rfl⟩ := (mem_span_range_iff_exists_fun _).mp hy + simp only [sum_right, bilin_smul_right] + apply sum_mem + rintro j - + rw [← IsScalarTower.algebraMap_smul S (f j), B.bilin_smul_right, apply_dualBasis_left, + mul_ite, mul_one, mul_zero, ← (algebraMap R S).map_zero, ← apply_ite] + exact ⟨_, rfl⟩ + +lemma dualSubmodule_dualSubmodule_flip_of_basis {ι} [Fintype ι] + (hB : B.Nondegenerate) (b : Basis ι S M) : + B.dualSubmodule (B.flip.dualSubmodule (Submodule.span R (Set.range b))) = + Submodule.span R (Set.range b) := by + classical + letI := FiniteDimensional.of_fintype_basis b + rw [dualSubmodule_span_of_basis _ hB.flip, dualSubmodule_span_of_basis B hB, + dualBasis_dualBasis_flip B hB] + +lemma dualSubmodule_flip_dualSubmodule_of_basis {ι} [Fintype ι] + (hB : B.Nondegenerate) (b : Basis ι S M) : + B.flip.dualSubmodule (B.dualSubmodule (Submodule.span R (Set.range b))) = + Submodule.span R (Set.range b) := by + classical + letI := FiniteDimensional.of_fintype_basis b + rw [dualSubmodule_span_of_basis B hB, dualSubmodule_span_of_basis _ hB.flip, + dualBasis_flip_dualBasis B hB] + +lemma dualSubmodule_dualSubmodule_of_basis + {ι} [Fintype ι] (hB : B.Nondegenerate) (hB' : B.IsSymm) (b : Basis ι S M) : + B.dualSubmodule (B.dualSubmodule (Submodule.span R (Set.range b))) = + Submodule.span R (Set.range b) := by + classical + letI := FiniteDimensional.of_fintype_basis b + rw [dualSubmodule_span_of_basis B hB, dualSubmodule_span_of_basis B hB, + dualBasis_dualBasis B hB hB'] diff --git a/Mathlib/LinearAlgebra/BilinearForm/Properties.lean b/Mathlib/LinearAlgebra/BilinearForm/Properties.lean index 10f09d415a2d3..8cb79c1718ba2 100644 --- a/Mathlib/LinearAlgebra/BilinearForm/Properties.lean +++ b/Mathlib/LinearAlgebra/BilinearForm/Properties.lean @@ -461,6 +461,17 @@ theorem toDual_def {B : BilinForm K V} (b : B.Nondegenerate) {m n : V} : B.toDua rfl #align bilin_form.to_dual_def BilinForm.toDual_def +lemma Nondegenerate.flip {B : BilinForm K V} (hB : B.Nondegenerate) : + B.flip.Nondegenerate := by + intro x hx + apply (Module.evalEquiv K V).injective + ext f + obtain ⟨y, rfl⟩ := (B.toDual hB).surjective f + simpa using hx y + +lemma nonDegenerateFlip_iff {B : BilinForm K V} : + B.flip.Nondegenerate ↔ B.Nondegenerate := ⟨Nondegenerate.flip, Nondegenerate.flip⟩ + section DualBasis variable {ι : Type*} [DecidableEq ι] [Fintype ι] @@ -470,6 +481,7 @@ variable {ι : Type*} [DecidableEq ι] [Fintype ι] where `B` is a nondegenerate (symmetric) bilinear form and `b` is a finite basis. -/ noncomputable def dualBasis (B : BilinForm K V) (hB : B.Nondegenerate) (b : Basis ι K V) : Basis ι K V := + haveI := FiniteDimensional.of_fintype_basis b b.dualBasis.map (B.toDual hB).symm #align bilin_form.dual_basis BilinForm.dualBasis @@ -482,6 +494,7 @@ theorem dualBasis_repr_apply (B : BilinForm K V) (hB : B.Nondegenerate) (b : Bas theorem apply_dualBasis_left (B : BilinForm K V) (hB : B.Nondegenerate) (b : Basis ι K V) (i j) : B (B.dualBasis hB b i) (b j) = if j = i then 1 else 0 := by + have := FiniteDimensional.of_fintype_basis b rw [dualBasis, Basis.map_apply, Basis.coe_dualBasis, ← toDual_def hB, LinearEquiv.apply_symm_apply, Basis.coord_apply, Basis.repr_self, Finsupp.single_apply] #align bilin_form.apply_dual_basis_left BilinForm.apply_dualBasis_left @@ -491,6 +504,29 @@ theorem apply_dualBasis_right (B : BilinForm K V) (hB : B.Nondegenerate) (sym : rw [sym, apply_dualBasis_left] #align bilin_form.apply_dual_basis_right BilinForm.apply_dualBasis_right +@[simp] +lemma dualBasis_dualBasis_flip (B : BilinForm K V) (hB : B.Nondegenerate) {ι} + [Fintype ι] [DecidableEq ι] (b : Basis ι K V) : + B.dualBasis hB (B.flip.dualBasis hB.flip b) = b := by + ext i + refine LinearMap.ker_eq_bot.mp hB.ker_eq_bot ((B.flip.dualBasis hB.flip b).ext (fun j ↦ ?_)) + rw [toLin_apply, apply_dualBasis_left, toLin_apply, ← B.flip_apply (R₂ := K), + apply_dualBasis_left] + simp_rw [@eq_comm _ i j] + +@[simp] +lemma dualBasis_flip_dualBasis (B : BilinForm K V) (hB : B.Nondegenerate) {ι} + [Fintype ι] [DecidableEq ι] [FiniteDimensional K V] (b : Basis ι K V) : + B.flip.dualBasis hB.flip (B.dualBasis hB b) = b := + dualBasis_dualBasis_flip _ hB.flip b + +@[simp] +lemma dualBasis_dualBasis (B : BilinForm K V) (hB : B.Nondegenerate) (hB' : B.IsSymm) {ι} + [Fintype ι] [DecidableEq ι] [FiniteDimensional K V] (b : Basis ι K V) : + B.dualBasis hB (B.dualBasis hB b) = b := by + convert dualBasis_dualBasis_flip _ hB.flip b + rwa [eq_comm, ← isSymm_iff_flip] + end DualBasis section LinearAdjoints diff --git a/Mathlib/LinearAlgebra/FiniteSpan.lean b/Mathlib/LinearAlgebra/FiniteSpan.lean new file mode 100644 index 0000000000000..cf9d642fab923 --- /dev/null +++ b/Mathlib/LinearAlgebra/FiniteSpan.lean @@ -0,0 +1,36 @@ +/- +Copyright (c) 2023 Oliver Nash. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Oliver Nash, Deepro Choudhury +-/ +import Mathlib.GroupTheory.OrderOfElement +import Mathlib.LinearAlgebra.Span + +/-! + +# Additional results about finite spanning sets in linear algebra + +-/ + +open Set Function +open Submodule (span) + +/-- A linear equivalence which preserves a finite spanning set must have finite order. -/ +lemma LinearEquiv.isOfFinOrder_of_finite_of_span_eq_top_of_mapsTo + {R M : Type*} [CommSemiring R] [AddCommMonoid M] [Module R M] + {Φ : Set M} (hΦ₁ : Φ.Finite) (hΦ₂ : span R Φ = ⊤) {e : M ≃ₗ[R] M} (he : MapsTo e Φ Φ) : + IsOfFinOrder e := by + replace he : BijOn e Φ Φ := (hΦ₁.injOn_iff_bijOn_of_mapsTo he).mp (e.injective.injOn Φ) + let e' := he.equiv + have : Finite Φ := finite_coe_iff.mpr hΦ₁ + obtain ⟨k, hk₀, hk⟩ := isOfFinOrder_of_finite e' + refine ⟨k, hk₀, ?_⟩ + ext m + have hm : m ∈ span R Φ := hΦ₂ ▸ Submodule.mem_top + simp only [mul_left_iterate, mul_one, LinearEquiv.coe_one, id_eq] + refine Submodule.span_induction hm (fun x hx ↦ ?_) (by simp) + (fun x y hx hy ↦ by simp [map_add, hx, hy]) (fun t x hx ↦ by simp [map_smul, hx]) + rw [LinearEquiv.pow_apply, ← he.1.coe_iterate_restrict ⟨x, hx⟩ k] + replace hk : (e') ^ k = 1 := by simpa [IsPeriodicPt, IsFixedPt] using hk + replace hk := Equiv.congr_fun hk ⟨x, hx⟩ + rwa [Equiv.Perm.coe_one, id_eq, Subtype.ext_iff, Equiv.Perm.coe_pow] at hk diff --git a/Mathlib/LinearAlgebra/Finsupp.lean b/Mathlib/LinearAlgebra/Finsupp.lean index 2bbafda85532f..d744c6c65652d 100644 --- a/Mathlib/LinearAlgebra/Finsupp.lean +++ b/Mathlib/LinearAlgebra/Finsupp.lean @@ -213,6 +213,13 @@ theorem lapply_apply (a : α) (f : α →₀ M) : (lapply a : (α →₀ M) → rfl #align finsupp.lapply_apply Finsupp.lapply_apply +@[simp] +theorem lapply_comp_lsingle_same (a : α) : lapply a ∘ₗ lsingle a = (.id : M →ₗ[R] M) := by ext; simp + +@[simp] +theorem lapply_comp_lsingle_of_ne (a a' : α) (h : a ≠ a') : + lapply a ∘ₗ lsingle a' = (0 : M →ₗ[R] M) := by ext; simp [h.symm] + @[simp] theorem ker_lsingle (a : α) : ker (lsingle a : M →ₗ[R] α →₀ M) = ⊥ := ker_eq_bot_of_injective (single_injective a) @@ -467,6 +474,9 @@ theorem lsum_single (f : α → M →ₗ[R] N) (i : α) (m : M) : Finsupp.sum_single_index (f i).map_zero #align finsupp.lsum_single Finsupp.lsum_single +@[simp] theorem lsum_comp_lsingle (f : α → M →ₗ[R] N) (i : α) : + Finsupp.lsum S f ∘ₗ lsingle i = f i := by ext; simp + theorem lsum_symm_apply (f : (α →₀ M) →ₗ[R] N) (x : α) : (lsum S).symm f x = f.comp (lsingle x) := rfl #align finsupp.lsum_symm_apply Finsupp.lsum_symm_apply diff --git a/Mathlib/LinearAlgebra/Reflection.lean b/Mathlib/LinearAlgebra/Reflection.lean new file mode 100644 index 0000000000000..237044b5c06c8 --- /dev/null +++ b/Mathlib/LinearAlgebra/Reflection.lean @@ -0,0 +1,161 @@ +/- +Copyright (c) 2023 Oliver Nash. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Oliver Nash, Deepro Choudhury +-/ +import Mathlib.GroupTheory.OrderOfElement +import Mathlib.LinearAlgebra.Dual +import Mathlib.LinearAlgebra.FiniteSpan + +/-! +# Reflections in linear algebra + +Given an element `x` in a module `M` together with a linear form `f` on `M` such that `f x = 2`, the +map `y ↦ y - (f y) • x` is an involutive endomorphism of `M`, such that: + 1. the kernel of `f` is fixed, + 2. the point `x ↦ -x`. + +Such endomorphisms are often called reflections of the module `M`. When `M` carries an inner product +for which `x` is perpendicular to the kernel of `f`, then (with mild assumptions) the endomorphism +is characterised by properties 1 and 2 above, and is a linear isometry. + +## Main definitions / results: + + * `Module.preReflection`: the definition of the map `y ↦ y - (f y) • x`. Its main utility lies in + the fact that it does not require the assumption `f x = 2`, giving the user freedom to defer + discharging this proof obligation. + * `Module.reflection`: the definition of the map `y ↦ y - (f y) • x`. This requires the assumption + that `f x = 2` but by way of compensation it produces a linear equivalence rather than a mere + linear map. + * `Module.Dual.eq_of_preReflection_mapsTo`: a uniqueness result about reflections preserving + finite spanning sets that is useful in the theory of root data / systems. + +## TODO + +Related definitions of reflection exists elsewhere in the library. These more specialised +definitions, which require an ambient `InnerProductSpace` structure, are `reflection` (of type +`LinearIsometryEquiv`) and `EuclideanGeometry.reflection` (of type `AffineIsometryEquiv`). We +should connect (or unify) these definitions with `Module.reflecton` defined here. + +-/ + +open Set Function Pointwise +open Module hiding Finite +open Submodule (span) + +noncomputable section + +variable {R M : Type*} [CommRing R] [AddCommGroup M] [Module R M] (x : M) (f : Dual R M) (y : M) + +namespace Module + +/-- Given an element `x` in a module `M` and a linear form `f` on `M`, we define the endomorphism +of `M` for which `y ↦ y - (f y) • x`. + +One is typically interested in this endomorphism when `f x = 2`; this definition exists to allow the +user defer discharging this proof obligation. See also `Module.reflection`. -/ +def preReflection : End R M := + LinearMap.id - f.smulRight x + +lemma preReflection_apply : + preReflection x f y = y - (f y) • x := by + simp [preReflection] + +variable {x f} + +lemma preReflection_apply_self (h : f x = 2) : + preReflection x f x = - x := by + rw [preReflection_apply, h, two_smul]; abel + +lemma involutive_preReflection (h : f x = 2) : + Involutive (preReflection x f) := + fun y ↦ by simp [h, smul_sub, two_smul, preReflection_apply] + +lemma preReflection_preReflection (g : Dual R M) (h : f x = 2) : + preReflection (preReflection x f y) (preReflection f (Dual.eval R M x) g) = + (preReflection x f) ∘ₗ (preReflection y g) ∘ₗ (preReflection x f) := by + ext m + simp only [h, preReflection_apply, mul_comm (g x) (f m), mul_two, mul_assoc, Dual.eval_apply, + LinearMap.sub_apply, LinearMap.coe_comp, LinearMap.smul_apply, smul_eq_mul, smul_sub, sub_smul, + smul_smul, sub_mul, comp_apply, map_sub, map_smul, add_smul] + abel + +/-- Given an element `x` in a module `M` and a linear form `f` on `M` for which `f x = 2`, we define +the endomorphism of `M` for which `y ↦ y - (f y) • x`. + +It is an involutive endomorphism of `M` fixing the kernel of `f` for which `x ↦ -x`. -/ +def reflection (h : f x = 2) : M ≃ₗ[R] M := + { preReflection x f, (involutive_preReflection h).toPerm with } + +lemma reflection_apply (h : f x = 2) : + reflection h y = y - (f y) • x := + preReflection_apply x f y + +@[simp] +lemma reflection_apply_self (h : f x = 2) : + reflection h x = - x := + preReflection_apply_self h + +lemma involutive_reflection (h : f x = 2) : + Involutive (reflection h) := + involutive_preReflection h + +@[simp] +lemma reflection_symm (h : f x = 2) : + (reflection h).symm = reflection h := + rfl + +/-- See also `Module.Dual.eq_of_preReflection_mapsTo'` for a variant of this lemma which +applies when `Φ` does not span. + +This rather technical-looking lemma exists because it is exactly what is needed to establish various +uniqueness results for root data / systems. One might regard this lemma as lying at the boundary of +linear algebra and combinatorics since the finiteness assumption is the key. -/ +lemma Dual.eq_of_preReflection_mapsTo [CharZero R] [NoZeroSMulDivisors R M] + {x : M} (hx : x ≠ 0) {Φ : Set M} (hΦ₁ : Φ.Finite) (hΦ₂ : span R Φ = ⊤) {f g : Dual R M} + (hf₁ : f x = 2) (hf₂ : MapsTo (preReflection x f) Φ Φ) + (hg₁ : g x = 2) (hg₂ : MapsTo (preReflection x g) Φ Φ) : + f = g := by + let u := reflection hg₁ * reflection hf₁ + have hu : u = LinearMap.id (R := R) (M := M) + (f - g).smulRight x := by + ext y + simp only [reflection_apply, hg₁, two_smul, LinearEquiv.coe_toLinearMap_mul, LinearMap.id_coe, + LinearEquiv.coe_coe, LinearMap.mul_apply, LinearMap.add_apply, id_eq, LinearMap.coe_smulRight, + LinearMap.sub_apply, map_sub, map_smul, sub_add_cancel', smul_neg, sub_neg_eq_add, sub_smul] + abel + replace hu : ∀ (n : ℕ), + ↑(u ^ n) = LinearMap.id (R := R) (M := M) + (n : R) • (f - g).smulRight x := by + intros n + induction' n with n ih; simp + have : ((f - g).smulRight x).comp ((n : R) • (f - g).smulRight x) = 0 := by ext; simp [hf₁, hg₁] + rw [pow_succ, LinearEquiv.coe_toLinearMap_mul, ih, hu, add_mul, mul_add, mul_add] + simp_rw [LinearMap.mul_eq_comp, LinearMap.comp_id, LinearMap.id_comp, this, add_zero, add_assoc, + Nat.cast_succ, add_smul, one_smul] + suffices IsOfFinOrder u by + obtain ⟨n, hn₀, hn₁⟩ := isOfFinOrder_iff_pow_eq_one.mp this + replace hn₁ : (↑(u ^ n) : M →ₗ[R] M) = LinearMap.id := LinearEquiv.toLinearMap_inj.mpr hn₁ + simpa [hn₁, hn₀.ne', hx, sub_eq_zero] using hu n + exact u.isOfFinOrder_of_finite_of_span_eq_top_of_mapsTo hΦ₁ hΦ₂ (hg₂.comp hf₂) + +/-- This rather technical-looking lemma exists because it is exactly what is needed to establish a +uniqueness result for root data. See the doc string of `Module.Dual.eq_of_preReflection_mapsTo` for +further remarks. -/ +lemma Dual.eq_of_preReflection_mapsTo' [CharZero R] [NoZeroSMulDivisors R M] + {x : M} (hx : x ≠ 0) {Φ : Set M} (hΦ₁ : Φ.Finite) (hx' : x ∈ span R Φ) {f g : Dual R M} + (hf₁ : f x = 2) (hf₂ : MapsTo (preReflection x f) Φ Φ) + (hg₁ : g x = 2) (hg₂ : MapsTo (preReflection x g) Φ Φ) : + (span R Φ).subtype.dualMap f = (span R Φ).subtype.dualMap g := by + set Φ' : Set (span R Φ) := range (inclusion <| Submodule.subset_span (R := R) (s := Φ)) + rw [← finite_coe_iff] at hΦ₁ + have hΦ'₁ : Φ'.Finite := finite_range (inclusion Submodule.subset_span) + have hΦ'₂ : span R Φ' = ⊤ := by simp + let x' : span R Φ := ⟨x, hx'⟩ + have hx' : x' ≠ 0 := Subtype.ne_of_val_ne hx + have this : ∀ {F : Dual R M}, MapsTo (preReflection x F) Φ Φ → + MapsTo (preReflection x' ((span R Φ).subtype.dualMap F)) Φ' Φ' := by + intro F hF ⟨y, hy⟩ hy' + simp only [range_inclusion, SetLike.coe_sort_coe, mem_setOf_eq] at hy' ⊢ + exact hF hy' + exact eq_of_preReflection_mapsTo hx' hΦ'₁ hΦ'₂ hf₁ (this hf₂) hg₁ (this hg₂) + +end Module diff --git a/Mathlib/LinearAlgebra/Span.lean b/Mathlib/LinearAlgebra/Span.lean index 709f084eb84de..9da5117bab683 100644 --- a/Mathlib/LinearAlgebra/Span.lean +++ b/Mathlib/LinearAlgebra/Span.lean @@ -190,6 +190,11 @@ theorem span_span_coe_preimage : span R (((↑) : span R s → M) ⁻¹' s) = · exact smul_mem _ _ #align submodule.span_span_coe_preimage Submodule.span_span_coe_preimage +@[simp] +lemma span_setOf_mem_eq_top : + span R {x : span R s | (x : M) ∈ s} = ⊤ := + span_span_coe_preimage + theorem span_nat_eq_addSubmonoid_closure (s : Set M) : (span ℕ s).toAddSubmonoid = AddSubmonoid.closure s := by refine' Eq.symm (AddSubmonoid.closure_eq_of_le subset_span _) diff --git a/Mathlib/LinearAlgebra/Trace.lean b/Mathlib/LinearAlgebra/Trace.lean index 9a3d8b6b8a8f4..2c292d45e5369 100644 --- a/Mathlib/LinearAlgebra/Trace.lean +++ b/Mathlib/LinearAlgebra/Trace.lean @@ -299,8 +299,19 @@ lemma trace_comp_cycle' (f : M →ₗ[R] N) (g : N →ₗ[R] P) (h : P →ₗ[R] @[simp] theorem trace_conj' (f : M →ₗ[R] M) (e : M ≃ₗ[R] N) : trace R N (e.conj f) = trace R M f := by - rw [e.conj_apply, trace_comp_comm', ← comp_assoc, LinearEquiv.comp_coe, - LinearEquiv.self_trans_symm, LinearEquiv.refl_toLinearMap, id_comp] + classical + by_cases hM : ∃ s : Finset M, Nonempty (Basis s R M) + · obtain ⟨s, ⟨b⟩⟩ := hM + haveI := Module.Finite.of_basis b + haveI := (Module.free_def R M).mpr ⟨_, ⟨b⟩⟩ + haveI := Module.Finite.of_basis (b.map e) + haveI := (Module.free_def R N).mpr ⟨_, ⟨(b.map e).reindex (e.toEquiv.image _)⟩⟩ + rw [e.conj_apply, trace_comp_comm', ← comp_assoc, LinearEquiv.comp_coe, + LinearEquiv.self_trans_symm, LinearEquiv.refl_toLinearMap, id_comp] + · rw [trace, trace, dif_neg hM, dif_neg]; rfl + rintro ⟨s, ⟨b⟩⟩ + exact hM ⟨s.image e.symm, ⟨(b.map e.symm).reindex + ((e.symm.toEquiv.image s).trans (Equiv.Set.ofEq Finset.coe_image.symm))⟩⟩ #align linear_map.trace_conj' LinearMap.trace_conj' theorem IsProj.trace {p : Submodule R M} {f : M →ₗ[R] M} (h : IsProj p f) [Module.Free R p] diff --git a/Mathlib/Logic/Equiv/LocalEquiv.lean b/Mathlib/Logic/Equiv/PartialEquiv.lean similarity index 50% rename from Mathlib/Logic/Equiv/LocalEquiv.lean rename to Mathlib/Logic/Equiv/PartialEquiv.lean index 814b8d495151e..39ed99c0b3f3a 100644 --- a/Mathlib/Logic/Equiv/LocalEquiv.lean +++ b/Mathlib/Logic/Equiv/PartialEquiv.lean @@ -11,16 +11,16 @@ import Mathlib.Tactic.Attr.Core #align_import logic.equiv.local_equiv from "leanprover-community/mathlib"@"48fb5b5280e7c81672afc9524185ae994553ebf4" /-! -# Local equivalences +# Partial equivalences This files defines equivalences between subsets of given types. -An element `e` of `LocalEquiv α β` is made of two maps `e.toFun` and `e.invFun` respectively +An element `e` of `PartialEquiv α β` is made of two maps `e.toFun` and `e.invFun` respectively from α to β and from β to α (just like equivs), which are inverse to each other on the subsets `e.source` and `e.target` of respectively α and β. They are designed in particular to define charts on manifolds. -The main functionality is `e.trans f`, which composes the two local equivalences by restricting +The main functionality is `e.trans f`, which composes the two partial equivalences by restricting the source and target to the maximal set where the composition makes sense. As for equivs, we register a coercion to functions and use it in our simp normal form: we write @@ -28,19 +28,19 @@ As for equivs, we register a coercion to functions and use it in our simp normal ## Main definitions -* `Equiv.toLocalEquiv`: associating a local equiv to an equiv, with source = target = univ -* `LocalEquiv.symm`: the inverse of a local equiv -* `LocalEquiv.trans`: the composition of two local equivs -* `LocalEquiv.refl`: the identity local equiv -* `LocalEquiv.ofSet`: the identity on a set `s` -* `EqOnSource`: equivalence relation describing the "right" notion of equality for local - equivs (see below in implementation notes) +* `Equiv.toPartialEquiv`: associating a partial equiv to an equiv, with source = target = univ +* `PartialEquiv.symm`: the inverse of a partial equivalence +* `PartialEquiv.trans`: the composition of two partial equivalences +* `PartialEquiv.refl`: the identity partial equivalence +* `PartialEquiv.ofSet`: the identity on a set `s` +* `EqOnSource`: equivalence relation describing the "right" notion of equality for partial + equivalences (see below in implementation notes) ## Implementation notes -There are at least three possible implementations of local equivalences: +There are at least three possible implementations of partial equivalences: * equivs on subtypes -* pairs of functions taking values in `Option α` and `Option β`, equal to none where the local +* pairs of functions taking values in `Option α` and `Option β`, equal to none where the partial equivalence is not defined * pairs of functions defined everywhere, keeping the source and target as additional data @@ -53,25 +53,25 @@ instance). the domain is restricted automatically). These are implemented in `PEquiv.lean`. For manifolds, where one wants to discuss thoroughly the smoothness of the maps, this creates however a lot of overhead as one would need to extend all classes of smoothness to option-valued maps. -* The `LocalEquiv` version as explained above is easier to use for manifolds. The drawback is that +* The `PartialEquiv` version as explained above is easier to use for manifolds. The drawback is that there is extra useless data (the values of `toFun` and `invFun` outside of `source` and `target`). -In particular, the equality notion between local equivs is not "the right one", i.e., coinciding -source and target and equality there. Moreover, there are no local equivs in this sense between +In particular, the equality notion between partial equivs is not "the right one", i.e., coinciding +source and target and equality there. Moreover, there are no partial equivs in this sense between an empty type and a nonempty type. Since empty types are not that useful, and since one almost never -needs to talk about equal local equivs, this is not an issue in practice. +needs to talk about equal partial equivs, this is not an issue in practice. Still, we introduce an equivalence relation `EqOnSource` that captures this right notion of equality, and show that many properties are invariant under this equivalence relation. ### Local coding conventions -If a lemma deals with the intersection of a set with either source or target of a `LocalEquiv`, +If a lemma deals with the intersection of a set with either source or target of a `PartialEquiv`, then it should use `e.source ∩ s` or `e.target ∩ t`, not `s ∩ e.source` or `t ∩ e.target`. -/ open Lean Meta Elab Tactic /-! Implementation of the `mfld_set_tac` tactic for working with the domains of partially-defined -functions (`LocalEquiv`, `LocalHomeomorph`, etc). +functions (`PartialEquiv`, `PartialHomeomorph`, etc). This is in a separate file from `Mathlib.Logic.Equiv.MfldSimpsAttr` because attributes need a new file to become functional. @@ -117,38 +117,38 @@ variable {α : Type*} {β : Type*} {γ : Type*} {δ : Type*} (global) maps `toFun : α → β` and `invFun : β → α` map `source` to `target` and conversely, and are inverse to each other there. The values of `toFun` outside of `source` and of `invFun` outside of `target` are irrelevant. -/ -structure LocalEquiv (α : Type*) (β : Type*) where - /-- The global function which has a local inverse. Its value outside of the `source` subset is +structure PartialEquiv (α : Type*) (β : Type*) where + /-- The global function which has a partial inverse. Its value outside of the `source` subset is irrelevant. -/ toFun : α → β - /-- The local inverse to `toFun`. Its value outside of the `target` subset is irrelevant. -/ + /-- The partial inverse to `toFun`. Its value outside of the `target` subset is irrelevant. -/ invFun : β → α - /-- The domain of the local equivalence. -/ + /-- The domain of the partial equivalence. -/ source : Set α - /-- The codomain of the local equivalence. -/ + /-- The codomain of the partial equivalence. -/ target : Set β /-- The proposition that elements of `source` are mapped to elements of `target`. -/ map_source' : ∀ ⦃x⦄, x ∈ source → toFun x ∈ target /-- The proposition that elements of `target` are mapped to elements of `source`. -/ map_target' : ∀ ⦃x⦄, x ∈ target → invFun x ∈ source - /-- The proposition that `invFun` is a local left-inverse of `toFun` on `source`. -/ + /-- The proposition that `invFun` is a left-inverse of `toFun` on `source`. -/ left_inv' : ∀ ⦃x⦄, x ∈ source → invFun (toFun x) = x - /-- The proposition that `invFun` is a local right-inverse of `toFun` on `target`. -/ + /-- The proposition that `invFun` is a right-inverse of `toFun` on `target`. -/ right_inv' : ∀ ⦃x⦄, x ∈ target → toFun (invFun x) = x -#align local_equiv LocalEquiv +#align local_equiv PartialEquiv -attribute [coe] LocalEquiv.toFun +attribute [coe] PartialEquiv.toFun -namespace LocalEquiv +namespace PartialEquiv -variable (e : LocalEquiv α β) (e' : LocalEquiv β γ) +variable (e : PartialEquiv α β) (e' : PartialEquiv β γ) -instance [Inhabited α] [Inhabited β] : Inhabited (LocalEquiv α β) := +instance [Inhabited α] [Inhabited β] : Inhabited (PartialEquiv α β) := ⟨⟨const α default, const β default, ∅, ∅, mapsTo_empty _ _, mapsTo_empty _ _, eqOn_empty _ _, eqOn_empty _ _⟩⟩ -/-- The inverse of a local equiv -/ -protected def symm : LocalEquiv β α where +/-- The inverse of a partial equivalence -/ +protected def symm : PartialEquiv β α where toFun := e.invFun invFun := e.toFun source := e.target @@ -157,46 +157,46 @@ protected def symm : LocalEquiv β α where map_target' := e.map_source' left_inv' := e.right_inv' right_inv' := e.left_inv' -#align local_equiv.symm LocalEquiv.symm +#align local_equiv.symm PartialEquiv.symm -instance : CoeFun (LocalEquiv α β) fun _ => α → β := - ⟨LocalEquiv.toFun⟩ +instance : CoeFun (PartialEquiv α β) fun _ => α → β := + ⟨PartialEquiv.toFun⟩ /-- See Note [custom simps projection] -/ -def Simps.symm_apply (e : LocalEquiv α β) : β → α := +def Simps.symm_apply (e : PartialEquiv α β) : β → α := e.symm -#align local_equiv.simps.symm_apply LocalEquiv.Simps.symm_apply +#align local_equiv.simps.symm_apply PartialEquiv.Simps.symm_apply -initialize_simps_projections LocalEquiv (toFun → apply, invFun → symm_apply) +initialize_simps_projections PartialEquiv (toFun → apply, invFun → symm_apply) -- Porting note: this can be proven with `dsimp only` -- @[simp, mfld_simps] --- theorem coe_mk (f : α → β) (g s t ml mr il ir) : (LocalEquiv.mk f g s t ml mr il ir : α → β) = f --- := by dsimp only --- #align local_equiv.coe_mk LocalEquiv.coe_mk +-- theorem coe_mk (f : α → β) (g s t ml mr il ir) : +-- (PartialEquiv.mk f g s t ml mr il ir : α → β) = f := by dsimp only +-- #align local_equiv.coe_mk PartialEquiv.coe_mk #noalign local_equiv.coe_mk @[simp, mfld_simps] theorem coe_symm_mk (f : α → β) (g s t ml mr il ir) : - ((LocalEquiv.mk f g s t ml mr il ir).symm : β → α) = g := + ((PartialEquiv.mk f g s t ml mr il ir).symm : β → α) = g := rfl -#align local_equiv.coe_symm_mk LocalEquiv.coe_symm_mk +#align local_equiv.coe_symm_mk PartialEquiv.coe_symm_mk -- Porting note: this is now a syntactic tautology -- @[simp, mfld_simps] -- theorem toFun_as_coe : e.toFun = e := rfl --- #align local_equiv.to_fun_as_coe LocalEquiv.toFun_as_coe +-- #align local_equiv.to_fun_as_coe PartialEquiv.toFun_as_coe #noalign local_equiv.to_fun_as_coe @[simp, mfld_simps] theorem invFun_as_coe : e.invFun = e.symm := rfl -#align local_equiv.inv_fun_as_coe LocalEquiv.invFun_as_coe +#align local_equiv.inv_fun_as_coe PartialEquiv.invFun_as_coe @[simp, mfld_simps] theorem map_source {x : α} (h : x ∈ e.source) : e x ∈ e.target := e.map_source' h -#align local_equiv.map_source LocalEquiv.map_source +#align local_equiv.map_source PartialEquiv.map_source /-- Variant of `e.map_source` and `map_source'`, stated for images of subsets of `source`. -/ lemma map_source'' : e '' e.source ⊆ e.target := @@ -205,57 +205,57 @@ lemma map_source'' : e '' e.source ⊆ e.target := @[simp, mfld_simps] theorem map_target {x : β} (h : x ∈ e.target) : e.symm x ∈ e.source := e.map_target' h -#align local_equiv.map_target LocalEquiv.map_target +#align local_equiv.map_target PartialEquiv.map_target @[simp, mfld_simps] theorem left_inv {x : α} (h : x ∈ e.source) : e.symm (e x) = x := e.left_inv' h -#align local_equiv.left_inv LocalEquiv.left_inv +#align local_equiv.left_inv PartialEquiv.left_inv @[simp, mfld_simps] theorem right_inv {x : β} (h : x ∈ e.target) : e (e.symm x) = x := e.right_inv' h -#align local_equiv.right_inv LocalEquiv.right_inv +#align local_equiv.right_inv PartialEquiv.right_inv theorem eq_symm_apply {x : α} {y : β} (hx : x ∈ e.source) (hy : y ∈ e.target) : x = e.symm y ↔ e x = y := ⟨fun h => by rw [← e.right_inv hy, h], fun h => by rw [← e.left_inv hx, h]⟩ -#align local_equiv.eq_symm_apply LocalEquiv.eq_symm_apply +#align local_equiv.eq_symm_apply PartialEquiv.eq_symm_apply protected theorem mapsTo : MapsTo e e.source e.target := fun _ => e.map_source -#align local_equiv.maps_to LocalEquiv.mapsTo +#align local_equiv.maps_to PartialEquiv.mapsTo theorem symm_mapsTo : MapsTo e.symm e.target e.source := e.symm.mapsTo -#align local_equiv.symm_maps_to LocalEquiv.symm_mapsTo +#align local_equiv.symm_maps_to PartialEquiv.symm_mapsTo protected theorem leftInvOn : LeftInvOn e.symm e e.source := fun _ => e.left_inv -#align local_equiv.left_inv_on LocalEquiv.leftInvOn +#align local_equiv.left_inv_on PartialEquiv.leftInvOn protected theorem rightInvOn : RightInvOn e.symm e e.target := fun _ => e.right_inv -#align local_equiv.right_inv_on LocalEquiv.rightInvOn +#align local_equiv.right_inv_on PartialEquiv.rightInvOn protected theorem invOn : InvOn e.symm e e.source e.target := ⟨e.leftInvOn, e.rightInvOn⟩ -#align local_equiv.inv_on LocalEquiv.invOn +#align local_equiv.inv_on PartialEquiv.invOn protected theorem injOn : InjOn e e.source := e.leftInvOn.injOn -#align local_equiv.inj_on LocalEquiv.injOn +#align local_equiv.inj_on PartialEquiv.injOn protected theorem bijOn : BijOn e e.source e.target := e.invOn.bijOn e.mapsTo e.symm_mapsTo -#align local_equiv.bij_on LocalEquiv.bijOn +#align local_equiv.bij_on PartialEquiv.bijOn protected theorem surjOn : SurjOn e e.source e.target := e.bijOn.surjOn -#align local_equiv.surj_on LocalEquiv.surjOn +#align local_equiv.surj_on PartialEquiv.surjOn -/-- Interpret an `Equiv` as a `LocalEquiv` by restricting it to `s` in the domain +/-- Interpret an `Equiv` as a `PartialEquiv` by restricting it to `s` in the domain and to `t` in the codomain. -/ @[simps (config := .asFn)] -def _root_.Equiv.toLocalEquivOfImageEq (e : α ≃ β) (s : Set α) (t : Set β) (h : e '' s = t) : - LocalEquiv α β where +def _root_.Equiv.toPartialEquivOfImageEq (e : α ≃ β) (s : Set α) (t : Set β) (h : e '' s = t) : + PartialEquiv α β where toFun := e invFun := e.symm source := s @@ -268,25 +268,25 @@ def _root_.Equiv.toLocalEquivOfImageEq (e : α ≃ β) (s : Set α) (t : Set β) left_inv' x _ := e.symm_apply_apply x right_inv' x _ := e.apply_symm_apply x -/-- Associate a `LocalEquiv` to an `Equiv`. -/ +/-- Associate a `PartialEquiv` to an `Equiv`. -/ @[simps! (config := mfld_cfg)] -def _root_.Equiv.toLocalEquiv (e : α ≃ β) : LocalEquiv α β := - e.toLocalEquivOfImageEq univ univ <| by rw [image_univ, e.surjective.range_eq] -#align equiv.to_local_equiv Equiv.toLocalEquiv -#align equiv.to_local_equiv_symm_apply Equiv.toLocalEquiv_symm_apply -#align equiv.to_local_equiv_target Equiv.toLocalEquiv_target -#align equiv.to_local_equiv_apply Equiv.toLocalEquiv_apply -#align equiv.to_local_equiv_source Equiv.toLocalEquiv_source - -instance inhabitedOfEmpty [IsEmpty α] [IsEmpty β] : Inhabited (LocalEquiv α β) := - ⟨((Equiv.equivEmpty α).trans (Equiv.equivEmpty β).symm).toLocalEquiv⟩ -#align local_equiv.inhabited_of_empty LocalEquiv.inhabitedOfEmpty - -/-- Create a copy of a `LocalEquiv` providing better definitional equalities. -/ +def _root_.Equiv.toPartialEquiv (e : α ≃ β) : PartialEquiv α β := + e.toPartialEquivOfImageEq univ univ <| by rw [image_univ, e.surjective.range_eq] +#align equiv.to_local_equiv Equiv.toPartialEquiv +#align equiv.to_local_equiv_symm_apply Equiv.toPartialEquiv_symm_apply +#align equiv.to_local_equiv_target Equiv.toPartialEquiv_target +#align equiv.to_local_equiv_apply Equiv.toPartialEquiv_apply +#align equiv.to_local_equiv_source Equiv.toPartialEquiv_source + +instance inhabitedOfEmpty [IsEmpty α] [IsEmpty β] : Inhabited (PartialEquiv α β) := + ⟨((Equiv.equivEmpty α).trans (Equiv.equivEmpty β).symm).toPartialEquiv⟩ +#align local_equiv.inhabited_of_empty PartialEquiv.inhabitedOfEmpty + +/-- Create a copy of a `PartialEquiv` providing better definitional equalities. -/ @[simps (config := .asFn)] -def copy (e : LocalEquiv α β) (f : α → β) (hf : ⇑e = f) (g : β → α) (hg : ⇑e.symm = g) (s : Set α) +def copy (e : PartialEquiv α β) (f : α → β) (hf : ⇑e = f) (g : β → α) (hg : ⇑e.symm = g) (s : Set α) (hs : e.source = s) (t : Set β) (ht : e.target = t) : - LocalEquiv α β where + PartialEquiv α β where toFun := f invFun := g source := s @@ -295,60 +295,61 @@ def copy (e : LocalEquiv α β) (f : α → β) (hf : ⇑e = f) (g : β → α) map_target' _ := hs ▸ ht ▸ hg ▸ e.map_target left_inv' _ := hs ▸ hf ▸ hg ▸ e.left_inv right_inv' _ := ht ▸ hf ▸ hg ▸ e.right_inv -#align local_equiv.copy LocalEquiv.copy -#align local_equiv.copy_source LocalEquiv.copy_source -#align local_equiv.copy_apply LocalEquiv.copy_apply -#align local_equiv.copy_symm_apply LocalEquiv.copy_symm_apply -#align local_equiv.copy_target LocalEquiv.copy_target +#align local_equiv.copy PartialEquiv.copy +#align local_equiv.copy_source PartialEquiv.copy_source +#align local_equiv.copy_apply PartialEquiv.copy_apply +#align local_equiv.copy_symm_apply PartialEquiv.copy_symm_apply +#align local_equiv.copy_target PartialEquiv.copy_target -theorem copy_eq (e : LocalEquiv α β) (f : α → β) (hf : ⇑e = f) (g : β → α) (hg : ⇑e.symm = g) +theorem copy_eq (e : PartialEquiv α β) (f : α → β) (hf : ⇑e = f) (g : β → α) (hg : ⇑e.symm = g) (s : Set α) (hs : e.source = s) (t : Set β) (ht : e.target = t) : e.copy f hf g hg s hs t ht = e := by substs f g s t cases e rfl -#align local_equiv.copy_eq LocalEquiv.copy_eq +#align local_equiv.copy_eq PartialEquiv.copy_eq -/-- Associate to a `LocalEquiv` an `Equiv` between the source and the target. -/ +/-- Associate to a `PartialEquiv` an `Equiv` between the source and the target. -/ protected def toEquiv : e.source ≃ e.target where toFun x := ⟨e x, e.map_source x.mem⟩ invFun y := ⟨e.symm y, e.map_target y.mem⟩ left_inv := fun ⟨_, hx⟩ => Subtype.eq <| e.left_inv hx right_inv := fun ⟨_, hy⟩ => Subtype.eq <| e.right_inv hy -#align local_equiv.to_equiv LocalEquiv.toEquiv +#align local_equiv.to_equiv PartialEquiv.toEquiv @[simp, mfld_simps] theorem symm_source : e.symm.source = e.target := rfl -#align local_equiv.symm_source LocalEquiv.symm_source +#align local_equiv.symm_source PartialEquiv.symm_source @[simp, mfld_simps] theorem symm_target : e.symm.target = e.source := rfl -#align local_equiv.symm_target LocalEquiv.symm_target +#align local_equiv.symm_target PartialEquiv.symm_target @[simp, mfld_simps] theorem symm_symm : e.symm.symm = e := by cases e rfl -#align local_equiv.symm_symm LocalEquiv.symm_symm +#align local_equiv.symm_symm PartialEquiv.symm_symm -theorem symm_bijective : Function.Bijective (LocalEquiv.symm : LocalEquiv α β → LocalEquiv β α) := +theorem symm_bijective : + Function.Bijective (PartialEquiv.symm : PartialEquiv α β → PartialEquiv β α) := Function.bijective_iff_has_inverse.mpr ⟨_, symm_symm, symm_symm⟩ theorem image_source_eq_target : e '' e.source = e.target := e.bijOn.image_eq -#align local_equiv.image_source_eq_target LocalEquiv.image_source_eq_target +#align local_equiv.image_source_eq_target PartialEquiv.image_source_eq_target theorem forall_mem_target {p : β → Prop} : (∀ y ∈ e.target, p y) ↔ ∀ x ∈ e.source, p (e x) := by rw [← image_source_eq_target, ball_image_iff] -#align local_equiv.forall_mem_target LocalEquiv.forall_mem_target +#align local_equiv.forall_mem_target PartialEquiv.forall_mem_target theorem exists_mem_target {p : β → Prop} : (∃ y ∈ e.target, p y) ↔ ∃ x ∈ e.source, p (e x) := by rw [← image_source_eq_target, bex_image_iff] -#align local_equiv.exists_mem_target LocalEquiv.exists_mem_target +#align local_equiv.exists_mem_target PartialEquiv.exists_mem_target -/-- We say that `t : Set β` is an image of `s : Set α` under a local equivalence if +/-- We say that `t : Set β` is an image of `s : Set α` under a partial equivalence if any of the following equivalent conditions hold: * `e '' (e.source ∩ s) = e.target ∩ t`; @@ -357,7 +358,7 @@ any of the following equivalent conditions hold: -/ def IsImage (s : Set α) (t : Set β) : Prop := ∀ ⦃x⦄, x ∈ e.source → (e x ∈ t ↔ x ∈ s) -#align local_equiv.is_image LocalEquiv.IsImage +#align local_equiv.is_image PartialEquiv.IsImage namespace IsImage @@ -365,32 +366,32 @@ variable {e} {s : Set α} {t : Set β} {x : α} {y : β} theorem apply_mem_iff (h : e.IsImage s t) (hx : x ∈ e.source) : e x ∈ t ↔ x ∈ s := h hx -#align local_equiv.is_image.apply_mem_iff LocalEquiv.IsImage.apply_mem_iff +#align local_equiv.is_image.apply_mem_iff PartialEquiv.IsImage.apply_mem_iff theorem symm_apply_mem_iff (h : e.IsImage s t) : ∀ ⦃y⦄, y ∈ e.target → (e.symm y ∈ s ↔ y ∈ t) := e.forall_mem_target.mpr fun x hx => by rw [e.left_inv hx, h hx] -#align local_equiv.is_image.symm_apply_mem_iff LocalEquiv.IsImage.symm_apply_mem_iff +#align local_equiv.is_image.symm_apply_mem_iff PartialEquiv.IsImage.symm_apply_mem_iff protected theorem symm (h : e.IsImage s t) : e.symm.IsImage t s := h.symm_apply_mem_iff -#align local_equiv.is_image.symm LocalEquiv.IsImage.symm +#align local_equiv.is_image.symm PartialEquiv.IsImage.symm @[simp] theorem symm_iff : e.symm.IsImage t s ↔ e.IsImage s t := ⟨fun h => h.symm, fun h => h.symm⟩ -#align local_equiv.is_image.symm_iff LocalEquiv.IsImage.symm_iff +#align local_equiv.is_image.symm_iff PartialEquiv.IsImage.symm_iff protected theorem mapsTo (h : e.IsImage s t) : MapsTo e (e.source ∩ s) (e.target ∩ t) := fun _ hx => ⟨e.mapsTo hx.1, (h hx.1).2 hx.2⟩ -#align local_equiv.is_image.maps_to LocalEquiv.IsImage.mapsTo +#align local_equiv.is_image.maps_to PartialEquiv.IsImage.mapsTo theorem symm_mapsTo (h : e.IsImage s t) : MapsTo e.symm (e.target ∩ t) (e.source ∩ s) := h.symm.mapsTo -#align local_equiv.is_image.symm_maps_to LocalEquiv.IsImage.symm_mapsTo +#align local_equiv.is_image.symm_maps_to PartialEquiv.IsImage.symm_mapsTo -/-- Restrict a `LocalEquiv` to a pair of corresponding sets. -/ +/-- Restrict a `PartialEquiv` to a pair of corresponding sets. -/ @[simps (config := .asFn)] -def restr (h : e.IsImage s t) : LocalEquiv α β where +def restr (h : e.IsImage s t) : PartialEquiv α β where toFun := e invFun := e.symm source := e.source ∩ s @@ -399,160 +400,160 @@ def restr (h : e.IsImage s t) : LocalEquiv α β where map_target' := h.symm_mapsTo left_inv' := e.leftInvOn.mono (inter_subset_left _ _) right_inv' := e.rightInvOn.mono (inter_subset_left _ _) -#align local_equiv.is_image.restr LocalEquiv.IsImage.restr -#align local_equiv.is_image.restr_apply LocalEquiv.IsImage.restr_apply -#align local_equiv.is_image.restr_source LocalEquiv.IsImage.restr_source -#align local_equiv.is_image.restr_target LocalEquiv.IsImage.restr_target -#align local_equiv.is_image.restr_symm_apply LocalEquiv.IsImage.restr_symm_apply +#align local_equiv.is_image.restr PartialEquiv.IsImage.restr +#align local_equiv.is_image.restr_apply PartialEquiv.IsImage.restr_apply +#align local_equiv.is_image.restr_source PartialEquiv.IsImage.restr_source +#align local_equiv.is_image.restr_target PartialEquiv.IsImage.restr_target +#align local_equiv.is_image.restr_symm_apply PartialEquiv.IsImage.restr_symm_apply theorem image_eq (h : e.IsImage s t) : e '' (e.source ∩ s) = e.target ∩ t := h.restr.image_source_eq_target -#align local_equiv.is_image.image_eq LocalEquiv.IsImage.image_eq +#align local_equiv.is_image.image_eq PartialEquiv.IsImage.image_eq theorem symm_image_eq (h : e.IsImage s t) : e.symm '' (e.target ∩ t) = e.source ∩ s := h.symm.image_eq -#align local_equiv.is_image.symm_image_eq LocalEquiv.IsImage.symm_image_eq +#align local_equiv.is_image.symm_image_eq PartialEquiv.IsImage.symm_image_eq theorem iff_preimage_eq : e.IsImage s t ↔ e.source ∩ e ⁻¹' t = e.source ∩ s := by simp only [IsImage, ext_iff, mem_inter_iff, mem_preimage, and_congr_right_iff] -#align local_equiv.is_image.iff_preimage_eq LocalEquiv.IsImage.iff_preimage_eq +#align local_equiv.is_image.iff_preimage_eq PartialEquiv.IsImage.iff_preimage_eq alias ⟨preimage_eq, of_preimage_eq⟩ := iff_preimage_eq -#align local_equiv.is_image.of_preimage_eq LocalEquiv.IsImage.of_preimage_eq -#align local_equiv.is_image.preimage_eq LocalEquiv.IsImage.preimage_eq +#align local_equiv.is_image.of_preimage_eq PartialEquiv.IsImage.of_preimage_eq +#align local_equiv.is_image.preimage_eq PartialEquiv.IsImage.preimage_eq theorem iff_symm_preimage_eq : e.IsImage s t ↔ e.target ∩ e.symm ⁻¹' s = e.target ∩ t := symm_iff.symm.trans iff_preimage_eq -#align local_equiv.is_image.iff_symm_preimage_eq LocalEquiv.IsImage.iff_symm_preimage_eq +#align local_equiv.is_image.iff_symm_preimage_eq PartialEquiv.IsImage.iff_symm_preimage_eq alias ⟨symm_preimage_eq, of_symm_preimage_eq⟩ := iff_symm_preimage_eq -#align local_equiv.is_image.of_symm_preimage_eq LocalEquiv.IsImage.of_symm_preimage_eq -#align local_equiv.is_image.symm_preimage_eq LocalEquiv.IsImage.symm_preimage_eq +#align local_equiv.is_image.of_symm_preimage_eq PartialEquiv.IsImage.of_symm_preimage_eq +#align local_equiv.is_image.symm_preimage_eq PartialEquiv.IsImage.symm_preimage_eq theorem of_image_eq (h : e '' (e.source ∩ s) = e.target ∩ t) : e.IsImage s t := of_symm_preimage_eq <| Eq.trans (of_symm_preimage_eq rfl).image_eq.symm h -#align local_equiv.is_image.of_image_eq LocalEquiv.IsImage.of_image_eq +#align local_equiv.is_image.of_image_eq PartialEquiv.IsImage.of_image_eq theorem of_symm_image_eq (h : e.symm '' (e.target ∩ t) = e.source ∩ s) : e.IsImage s t := of_preimage_eq <| Eq.trans (iff_preimage_eq.2 rfl).symm_image_eq.symm h -#align local_equiv.is_image.of_symm_image_eq LocalEquiv.IsImage.of_symm_image_eq +#align local_equiv.is_image.of_symm_image_eq PartialEquiv.IsImage.of_symm_image_eq protected theorem compl (h : e.IsImage s t) : e.IsImage sᶜ tᶜ := fun _ hx => not_congr (h hx) -#align local_equiv.is_image.compl LocalEquiv.IsImage.compl +#align local_equiv.is_image.compl PartialEquiv.IsImage.compl protected theorem inter {s' t'} (h : e.IsImage s t) (h' : e.IsImage s' t') : e.IsImage (s ∩ s') (t ∩ t') := fun _ hx => and_congr (h hx) (h' hx) -#align local_equiv.is_image.inter LocalEquiv.IsImage.inter +#align local_equiv.is_image.inter PartialEquiv.IsImage.inter protected theorem union {s' t'} (h : e.IsImage s t) (h' : e.IsImage s' t') : e.IsImage (s ∪ s') (t ∪ t') := fun _ hx => or_congr (h hx) (h' hx) -#align local_equiv.is_image.union LocalEquiv.IsImage.union +#align local_equiv.is_image.union PartialEquiv.IsImage.union protected theorem diff {s' t'} (h : e.IsImage s t) (h' : e.IsImage s' t') : e.IsImage (s \ s') (t \ t') := h.inter h'.compl -#align local_equiv.is_image.diff LocalEquiv.IsImage.diff +#align local_equiv.is_image.diff PartialEquiv.IsImage.diff -theorem leftInvOn_piecewise {e' : LocalEquiv α β} [∀ i, Decidable (i ∈ s)] +theorem leftInvOn_piecewise {e' : PartialEquiv α β} [∀ i, Decidable (i ∈ s)] [∀ i, Decidable (i ∈ t)] (h : e.IsImage s t) (h' : e'.IsImage s t) : LeftInvOn (t.piecewise e.symm e'.symm) (s.piecewise e e') (s.ite e.source e'.source) := by rintro x (⟨he, hs⟩ | ⟨he, hs : x ∉ s⟩) · rw [piecewise_eq_of_mem _ _ _ hs, piecewise_eq_of_mem _ _ _ ((h he).2 hs), e.left_inv he] · rw [piecewise_eq_of_not_mem _ _ _ hs, piecewise_eq_of_not_mem _ _ _ ((h'.compl he).2 hs), e'.left_inv he] -#align local_equiv.is_image.left_inv_on_piecewise LocalEquiv.IsImage.leftInvOn_piecewise +#align local_equiv.is_image.left_inv_on_piecewise PartialEquiv.IsImage.leftInvOn_piecewise -theorem inter_eq_of_inter_eq_of_eqOn {e' : LocalEquiv α β} (h : e.IsImage s t) +theorem inter_eq_of_inter_eq_of_eqOn {e' : PartialEquiv α β} (h : e.IsImage s t) (h' : e'.IsImage s t) (hs : e.source ∩ s = e'.source ∩ s) (heq : EqOn e e' (e.source ∩ s)) : e.target ∩ t = e'.target ∩ t := by rw [← h.image_eq, ← h'.image_eq, ← hs, heq.image_eq] -#align local_equiv.is_image.inter_eq_of_inter_eq_of_eq_on LocalEquiv.IsImage.inter_eq_of_inter_eq_of_eqOn +#align local_equiv.is_image.inter_eq_of_inter_eq_of_eq_on PartialEquiv.IsImage.inter_eq_of_inter_eq_of_eqOn -theorem symm_eq_on_of_inter_eq_of_eqOn {e' : LocalEquiv α β} (h : e.IsImage s t) +theorem symm_eq_on_of_inter_eq_of_eqOn {e' : PartialEquiv α β} (h : e.IsImage s t) (hs : e.source ∩ s = e'.source ∩ s) (heq : EqOn e e' (e.source ∩ s)) : EqOn e.symm e'.symm (e.target ∩ t) := by rw [← h.image_eq] rintro y ⟨x, hx, rfl⟩ have hx' := hx; rw [hs] at hx' rw [e.left_inv hx.1, heq hx, e'.left_inv hx'.1] -#align local_equiv.is_image.symm_eq_on_of_inter_eq_of_eq_on LocalEquiv.IsImage.symm_eq_on_of_inter_eq_of_eqOn +#align local_equiv.is_image.symm_eq_on_of_inter_eq_of_eq_on PartialEquiv.IsImage.symm_eq_on_of_inter_eq_of_eqOn end IsImage theorem isImage_source_target : e.IsImage e.source e.target := fun x hx => by simp [hx] -#align local_equiv.is_image_source_target LocalEquiv.isImage_source_target +#align local_equiv.is_image_source_target PartialEquiv.isImage_source_target -theorem isImage_source_target_of_disjoint (e' : LocalEquiv α β) (hs : Disjoint e.source e'.source) +theorem isImage_source_target_of_disjoint (e' : PartialEquiv α β) (hs : Disjoint e.source e'.source) (ht : Disjoint e.target e'.target) : e.IsImage e'.source e'.target := IsImage.of_image_eq <| by rw [hs.inter_eq, ht.inter_eq, image_empty] -#align local_equiv.is_image_source_target_of_disjoint LocalEquiv.isImage_source_target_of_disjoint +#align local_equiv.is_image_source_target_of_disjoint PartialEquiv.isImage_source_target_of_disjoint theorem image_source_inter_eq' (s : Set α) : e '' (e.source ∩ s) = e.target ∩ e.symm ⁻¹' s := by rw [inter_comm, e.leftInvOn.image_inter', image_source_eq_target, inter_comm] -#align local_equiv.image_source_inter_eq' LocalEquiv.image_source_inter_eq' +#align local_equiv.image_source_inter_eq' PartialEquiv.image_source_inter_eq' theorem image_source_inter_eq (s : Set α) : e '' (e.source ∩ s) = e.target ∩ e.symm ⁻¹' (e.source ∩ s) := by rw [inter_comm, e.leftInvOn.image_inter, image_source_eq_target, inter_comm] -#align local_equiv.image_source_inter_eq LocalEquiv.image_source_inter_eq +#align local_equiv.image_source_inter_eq PartialEquiv.image_source_inter_eq theorem image_eq_target_inter_inv_preimage {s : Set α} (h : s ⊆ e.source) : e '' s = e.target ∩ e.symm ⁻¹' s := by rw [← e.image_source_inter_eq', inter_eq_self_of_subset_right h] -#align local_equiv.image_eq_target_inter_inv_preimage LocalEquiv.image_eq_target_inter_inv_preimage +#align local_equiv.image_eq_target_inter_inv_preimage PartialEquiv.image_eq_target_inter_inv_preimage theorem symm_image_eq_source_inter_preimage {s : Set β} (h : s ⊆ e.target) : e.symm '' s = e.source ∩ e ⁻¹' s := e.symm.image_eq_target_inter_inv_preimage h -#align local_equiv.symm_image_eq_source_inter_preimage LocalEquiv.symm_image_eq_source_inter_preimage +#align local_equiv.symm_image_eq_source_inter_preimage PartialEquiv.symm_image_eq_source_inter_preimage theorem symm_image_target_inter_eq (s : Set β) : e.symm '' (e.target ∩ s) = e.source ∩ e ⁻¹' (e.target ∩ s) := e.symm.image_source_inter_eq _ -#align local_equiv.symm_image_target_inter_eq LocalEquiv.symm_image_target_inter_eq +#align local_equiv.symm_image_target_inter_eq PartialEquiv.symm_image_target_inter_eq theorem symm_image_target_inter_eq' (s : Set β) : e.symm '' (e.target ∩ s) = e.source ∩ e ⁻¹' s := e.symm.image_source_inter_eq' _ -#align local_equiv.symm_image_target_inter_eq' LocalEquiv.symm_image_target_inter_eq' +#align local_equiv.symm_image_target_inter_eq' PartialEquiv.symm_image_target_inter_eq' theorem source_inter_preimage_inv_preimage (s : Set α) : e.source ∩ e ⁻¹' (e.symm ⁻¹' s) = e.source ∩ s := Set.ext fun x => and_congr_right_iff.2 fun hx => by simp only [mem_preimage, e.left_inv hx] -#align local_equiv.source_inter_preimage_inv_preimage LocalEquiv.source_inter_preimage_inv_preimage +#align local_equiv.source_inter_preimage_inv_preimage PartialEquiv.source_inter_preimage_inv_preimage theorem source_inter_preimage_target_inter (s : Set β) : e.source ∩ e ⁻¹' (e.target ∩ s) = e.source ∩ e ⁻¹' s := ext fun _ => ⟨fun hx => ⟨hx.1, hx.2.2⟩, fun hx => ⟨hx.1, e.map_source hx.1, hx.2⟩⟩ -#align local_equiv.source_inter_preimage_target_inter LocalEquiv.source_inter_preimage_target_inter +#align local_equiv.source_inter_preimage_target_inter PartialEquiv.source_inter_preimage_target_inter theorem target_inter_inv_preimage_preimage (s : Set β) : e.target ∩ e.symm ⁻¹' (e ⁻¹' s) = e.target ∩ s := e.symm.source_inter_preimage_inv_preimage _ -#align local_equiv.target_inter_inv_preimage_preimage LocalEquiv.target_inter_inv_preimage_preimage +#align local_equiv.target_inter_inv_preimage_preimage PartialEquiv.target_inter_inv_preimage_preimage theorem symm_image_image_of_subset_source {s : Set α} (h : s ⊆ e.source) : e.symm '' (e '' s) = s := (e.leftInvOn.mono h).image_image -#align local_equiv.symm_image_image_of_subset_source LocalEquiv.symm_image_image_of_subset_source +#align local_equiv.symm_image_image_of_subset_source PartialEquiv.symm_image_image_of_subset_source theorem image_symm_image_of_subset_target {s : Set β} (h : s ⊆ e.target) : e '' (e.symm '' s) = s := e.symm.symm_image_image_of_subset_source h -#align local_equiv.image_symm_image_of_subset_target LocalEquiv.image_symm_image_of_subset_target +#align local_equiv.image_symm_image_of_subset_target PartialEquiv.image_symm_image_of_subset_target theorem source_subset_preimage_target : e.source ⊆ e ⁻¹' e.target := e.mapsTo -#align local_equiv.source_subset_preimage_target LocalEquiv.source_subset_preimage_target +#align local_equiv.source_subset_preimage_target PartialEquiv.source_subset_preimage_target theorem symm_image_target_eq_source : e.symm '' e.target = e.source := e.symm.image_source_eq_target -#align local_equiv.symm_image_target_eq_source LocalEquiv.symm_image_target_eq_source +#align local_equiv.symm_image_target_eq_source PartialEquiv.symm_image_target_eq_source theorem target_subset_preimage_source : e.target ⊆ e.symm ⁻¹' e.source := e.symm_mapsTo -#align local_equiv.target_subset_preimage_source LocalEquiv.target_subset_preimage_source +#align local_equiv.target_subset_preimage_source PartialEquiv.target_subset_preimage_source -/-- Two local equivs that have the same `source`, same `toFun` and same `invFun`, coincide. -/ +/-- Two partial equivs that have the same `source`, same `toFun` and same `invFun`, coincide. -/ @[ext] -protected theorem ext {e e' : LocalEquiv α β} (h : ∀ x, e x = e' x) +protected theorem ext {e e' : PartialEquiv α β} (h : ∀ x, e x = e' x) (hsymm : ∀ x, e.symm x = e'.symm x) (hs : e.source = e'.source) : e = e' := by have A : (e : α → β) = e' := by ext x @@ -566,82 +567,82 @@ protected theorem ext {e e' : LocalEquiv α β} (h : ∀ x, e x = e' x) cases e; cases e' simp [*] at * simp [*] -#align local_equiv.ext LocalEquiv.ext +#align local_equiv.ext PartialEquiv.ext -/-- Restricting a local equivalence to e.source ∩ s -/ -protected def restr (s : Set α) : LocalEquiv α β := +/-- Restricting a partial equivalence to `e.source ∩ s` -/ +protected def restr (s : Set α) : PartialEquiv α β := (@IsImage.of_symm_preimage_eq α β e s (e.symm ⁻¹' s) rfl).restr -#align local_equiv.restr LocalEquiv.restr +#align local_equiv.restr PartialEquiv.restr @[simp, mfld_simps] theorem restr_coe (s : Set α) : (e.restr s : α → β) = e := rfl -#align local_equiv.restr_coe LocalEquiv.restr_coe +#align local_equiv.restr_coe PartialEquiv.restr_coe @[simp, mfld_simps] theorem restr_coe_symm (s : Set α) : ((e.restr s).symm : β → α) = e.symm := rfl -#align local_equiv.restr_coe_symm LocalEquiv.restr_coe_symm +#align local_equiv.restr_coe_symm PartialEquiv.restr_coe_symm @[simp, mfld_simps] theorem restr_source (s : Set α) : (e.restr s).source = e.source ∩ s := rfl -#align local_equiv.restr_source LocalEquiv.restr_source +#align local_equiv.restr_source PartialEquiv.restr_source @[simp, mfld_simps] theorem restr_target (s : Set α) : (e.restr s).target = e.target ∩ e.symm ⁻¹' s := rfl -#align local_equiv.restr_target LocalEquiv.restr_target +#align local_equiv.restr_target PartialEquiv.restr_target -theorem restr_eq_of_source_subset {e : LocalEquiv α β} {s : Set α} (h : e.source ⊆ s) : +theorem restr_eq_of_source_subset {e : PartialEquiv α β} {s : Set α} (h : e.source ⊆ s) : e.restr s = e := - LocalEquiv.ext (fun _ => rfl) (fun _ => rfl) (by simp [inter_eq_self_of_subset_left h]) -#align local_equiv.restr_eq_of_source_subset LocalEquiv.restr_eq_of_source_subset + PartialEquiv.ext (fun _ => rfl) (fun _ => rfl) (by simp [inter_eq_self_of_subset_left h]) +#align local_equiv.restr_eq_of_source_subset PartialEquiv.restr_eq_of_source_subset @[simp, mfld_simps] -theorem restr_univ {e : LocalEquiv α β} : e.restr univ = e := +theorem restr_univ {e : PartialEquiv α β} : e.restr univ = e := restr_eq_of_source_subset (subset_univ _) -#align local_equiv.restr_univ LocalEquiv.restr_univ +#align local_equiv.restr_univ PartialEquiv.restr_univ -/-- The identity local equiv -/ -protected def refl (α : Type*) : LocalEquiv α α := - (Equiv.refl α).toLocalEquiv -#align local_equiv.refl LocalEquiv.refl +/-- The identity partial equiv -/ +protected def refl (α : Type*) : PartialEquiv α α := + (Equiv.refl α).toPartialEquiv +#align local_equiv.refl PartialEquiv.refl @[simp, mfld_simps] -theorem refl_source : (LocalEquiv.refl α).source = univ := +theorem refl_source : (PartialEquiv.refl α).source = univ := rfl -#align local_equiv.refl_source LocalEquiv.refl_source +#align local_equiv.refl_source PartialEquiv.refl_source @[simp, mfld_simps] -theorem refl_target : (LocalEquiv.refl α).target = univ := +theorem refl_target : (PartialEquiv.refl α).target = univ := rfl -#align local_equiv.refl_target LocalEquiv.refl_target +#align local_equiv.refl_target PartialEquiv.refl_target @[simp, mfld_simps] -theorem refl_coe : (LocalEquiv.refl α : α → α) = id := +theorem refl_coe : (PartialEquiv.refl α : α → α) = id := rfl -#align local_equiv.refl_coe LocalEquiv.refl_coe +#align local_equiv.refl_coe PartialEquiv.refl_coe @[simp, mfld_simps] -theorem refl_symm : (LocalEquiv.refl α).symm = LocalEquiv.refl α := +theorem refl_symm : (PartialEquiv.refl α).symm = PartialEquiv.refl α := rfl -#align local_equiv.refl_symm LocalEquiv.refl_symm +#align local_equiv.refl_symm PartialEquiv.refl_symm -- Porting note: removed `simp` because `simp` can prove this @[mfld_simps] -theorem refl_restr_source (s : Set α) : ((LocalEquiv.refl α).restr s).source = s := by simp -#align local_equiv.refl_restr_source LocalEquiv.refl_restr_source +theorem refl_restr_source (s : Set α) : ((PartialEquiv.refl α).restr s).source = s := by simp +#align local_equiv.refl_restr_source PartialEquiv.refl_restr_source -- Porting note: removed `simp` because `simp` can prove this @[mfld_simps] -theorem refl_restr_target (s : Set α) : ((LocalEquiv.refl α).restr s).target = s := by +theorem refl_restr_target (s : Set α) : ((PartialEquiv.refl α).restr s).target = s := by change univ ∩ id ⁻¹' s = s simp -#align local_equiv.refl_restr_target LocalEquiv.refl_restr_target +#align local_equiv.refl_restr_target PartialEquiv.refl_restr_target -/-- The identity local equiv on a set `s` -/ -def ofSet (s : Set α) : LocalEquiv α α where +/-- The identity partial equivalence on a set `s` -/ +def ofSet (s : Set α) : PartialEquiv α α where toFun := id invFun := id source := s @@ -650,32 +651,32 @@ def ofSet (s : Set α) : LocalEquiv α α where map_target' _ hx := hx left_inv' _ _ := rfl right_inv' _ _ := rfl -#align local_equiv.of_set LocalEquiv.ofSet +#align local_equiv.of_set PartialEquiv.ofSet @[simp, mfld_simps] -theorem ofSet_source (s : Set α) : (LocalEquiv.ofSet s).source = s := +theorem ofSet_source (s : Set α) : (PartialEquiv.ofSet s).source = s := rfl -#align local_equiv.of_set_source LocalEquiv.ofSet_source +#align local_equiv.of_set_source PartialEquiv.ofSet_source @[simp, mfld_simps] -theorem ofSet_target (s : Set α) : (LocalEquiv.ofSet s).target = s := +theorem ofSet_target (s : Set α) : (PartialEquiv.ofSet s).target = s := rfl -#align local_equiv.of_set_target LocalEquiv.ofSet_target +#align local_equiv.of_set_target PartialEquiv.ofSet_target @[simp, mfld_simps] -theorem ofSet_coe (s : Set α) : (LocalEquiv.ofSet s : α → α) = id := +theorem ofSet_coe (s : Set α) : (PartialEquiv.ofSet s : α → α) = id := rfl -#align local_equiv.of_set_coe LocalEquiv.ofSet_coe +#align local_equiv.of_set_coe PartialEquiv.ofSet_coe @[simp, mfld_simps] -theorem ofSet_symm (s : Set α) : (LocalEquiv.ofSet s).symm = LocalEquiv.ofSet s := +theorem ofSet_symm (s : Set α) : (PartialEquiv.ofSet s).symm = PartialEquiv.ofSet s := rfl -#align local_equiv.of_set_symm LocalEquiv.ofSet_symm +#align local_equiv.of_set_symm PartialEquiv.ofSet_symm -/-- Composing two local equivs if the target of the first coincides with the source of the +/-- Composing two partial equivs if the target of the first coincides with the source of the second. -/ @[simps] -protected def trans' (e' : LocalEquiv β γ) (h : e.target = e'.source) : LocalEquiv α γ where +protected def trans' (e' : PartialEquiv β γ) (h : e.target = e'.source) : PartialEquiv α γ where toFun := e' ∘ e invFun := e.symm ∘ e'.symm source := e.source @@ -684,244 +685,246 @@ protected def trans' (e' : LocalEquiv β γ) (h : e.target = e'.source) : LocalE map_target' y hy := by simp [h, hy] left_inv' x hx := by simp [hx, ← h] right_inv' y hy := by simp [hy, h] -#align local_equiv.trans' LocalEquiv.trans' +#align local_equiv.trans' PartialEquiv.trans' -/-- Composing two local equivs, by restricting to the maximal domain where their composition +/-- Composing two partial equivs, by restricting to the maximal domain where their composition is well defined. -/ -protected def trans : LocalEquiv α γ := - LocalEquiv.trans' (e.symm.restr e'.source).symm (e'.restr e.target) (inter_comm _ _) -#align local_equiv.trans LocalEquiv.trans +protected def trans : PartialEquiv α γ := + PartialEquiv.trans' (e.symm.restr e'.source).symm (e'.restr e.target) (inter_comm _ _) +#align local_equiv.trans PartialEquiv.trans @[simp, mfld_simps] theorem coe_trans : (e.trans e' : α → γ) = e' ∘ e := rfl -#align local_equiv.coe_trans LocalEquiv.coe_trans +#align local_equiv.coe_trans PartialEquiv.coe_trans @[simp, mfld_simps] theorem coe_trans_symm : ((e.trans e').symm : γ → α) = e.symm ∘ e'.symm := rfl -#align local_equiv.coe_trans_symm LocalEquiv.coe_trans_symm +#align local_equiv.coe_trans_symm PartialEquiv.coe_trans_symm theorem trans_apply {x : α} : (e.trans e') x = e' (e x) := rfl -#align local_equiv.trans_apply LocalEquiv.trans_apply +#align local_equiv.trans_apply PartialEquiv.trans_apply theorem trans_symm_eq_symm_trans_symm : (e.trans e').symm = e'.symm.trans e.symm := by cases e; cases e'; rfl -#align local_equiv.trans_symm_eq_symm_trans_symm LocalEquiv.trans_symm_eq_symm_trans_symm +#align local_equiv.trans_symm_eq_symm_trans_symm PartialEquiv.trans_symm_eq_symm_trans_symm @[simp, mfld_simps] theorem trans_source : (e.trans e').source = e.source ∩ e ⁻¹' e'.source := rfl -#align local_equiv.trans_source LocalEquiv.trans_source +#align local_equiv.trans_source PartialEquiv.trans_source theorem trans_source' : (e.trans e').source = e.source ∩ e ⁻¹' (e.target ∩ e'.source) := by mfld_set_tac -#align local_equiv.trans_source' LocalEquiv.trans_source' +#align local_equiv.trans_source' PartialEquiv.trans_source' theorem trans_source'' : (e.trans e').source = e.symm '' (e.target ∩ e'.source) := by rw [e.trans_source', e.symm_image_target_inter_eq] -#align local_equiv.trans_source'' LocalEquiv.trans_source'' +#align local_equiv.trans_source'' PartialEquiv.trans_source'' theorem image_trans_source : e '' (e.trans e').source = e.target ∩ e'.source := (e.symm.restr e'.source).symm.image_source_eq_target -#align local_equiv.image_trans_source LocalEquiv.image_trans_source +#align local_equiv.image_trans_source PartialEquiv.image_trans_source @[simp, mfld_simps] theorem trans_target : (e.trans e').target = e'.target ∩ e'.symm ⁻¹' e.target := rfl -#align local_equiv.trans_target LocalEquiv.trans_target +#align local_equiv.trans_target PartialEquiv.trans_target theorem trans_target' : (e.trans e').target = e'.target ∩ e'.symm ⁻¹' (e'.source ∩ e.target) := trans_source' e'.symm e.symm -#align local_equiv.trans_target' LocalEquiv.trans_target' +#align local_equiv.trans_target' PartialEquiv.trans_target' theorem trans_target'' : (e.trans e').target = e' '' (e'.source ∩ e.target) := trans_source'' e'.symm e.symm -#align local_equiv.trans_target'' LocalEquiv.trans_target'' +#align local_equiv.trans_target'' PartialEquiv.trans_target'' theorem inv_image_trans_target : e'.symm '' (e.trans e').target = e'.source ∩ e.target := image_trans_source e'.symm e.symm -#align local_equiv.inv_image_trans_target LocalEquiv.inv_image_trans_target +#align local_equiv.inv_image_trans_target PartialEquiv.inv_image_trans_target -theorem trans_assoc (e'' : LocalEquiv γ δ) : (e.trans e').trans e'' = e.trans (e'.trans e'') := - LocalEquiv.ext (fun x => rfl) (fun x => rfl) +theorem trans_assoc (e'' : PartialEquiv γ δ) : (e.trans e').trans e'' = e.trans (e'.trans e'') := + PartialEquiv.ext (fun x => rfl) (fun x => rfl) (by simp [trans_source, @preimage_comp α β γ, inter_assoc]) -#align local_equiv.trans_assoc LocalEquiv.trans_assoc +#align local_equiv.trans_assoc PartialEquiv.trans_assoc @[simp, mfld_simps] -theorem trans_refl : e.trans (LocalEquiv.refl β) = e := - LocalEquiv.ext (fun x => rfl) (fun x => rfl) (by simp [trans_source]) -#align local_equiv.trans_refl LocalEquiv.trans_refl +theorem trans_refl : e.trans (PartialEquiv.refl β) = e := + PartialEquiv.ext (fun x => rfl) (fun x => rfl) (by simp [trans_source]) +#align local_equiv.trans_refl PartialEquiv.trans_refl @[simp, mfld_simps] -theorem refl_trans : (LocalEquiv.refl α).trans e = e := - LocalEquiv.ext (fun x => rfl) (fun x => rfl) (by simp [trans_source, preimage_id]) -#align local_equiv.refl_trans LocalEquiv.refl_trans +theorem refl_trans : (PartialEquiv.refl α).trans e = e := + PartialEquiv.ext (fun x => rfl) (fun x => rfl) (by simp [trans_source, preimage_id]) +#align local_equiv.refl_trans PartialEquiv.refl_trans theorem trans_ofSet (s : Set β) : e.trans (ofSet s) = e.restr (e ⁻¹' s) := - LocalEquiv.ext (fun _ => rfl) (fun _ => rfl) rfl + PartialEquiv.ext (fun _ => rfl) (fun _ => rfl) rfl -theorem trans_refl_restr (s : Set β) : e.trans ((LocalEquiv.refl β).restr s) = e.restr (e ⁻¹' s) := - LocalEquiv.ext (fun x => rfl) (fun x => rfl) (by simp [trans_source]) -#align local_equiv.trans_refl_restr LocalEquiv.trans_refl_restr +theorem trans_refl_restr (s : Set β) : + e.trans ((PartialEquiv.refl β).restr s) = e.restr (e ⁻¹' s) := + PartialEquiv.ext (fun x => rfl) (fun x => rfl) (by simp [trans_source]) +#align local_equiv.trans_refl_restr PartialEquiv.trans_refl_restr theorem trans_refl_restr' (s : Set β) : - e.trans ((LocalEquiv.refl β).restr s) = e.restr (e.source ∩ e ⁻¹' s) := - LocalEquiv.ext (fun x => rfl) (fun x => rfl) <| by + e.trans ((PartialEquiv.refl β).restr s) = e.restr (e.source ∩ e ⁻¹' s) := + PartialEquiv.ext (fun x => rfl) (fun x => rfl) <| by simp only [trans_source, restr_source, refl_source, univ_inter] rw [← inter_assoc, inter_self] -#align local_equiv.trans_refl_restr' LocalEquiv.trans_refl_restr' +#align local_equiv.trans_refl_restr' PartialEquiv.trans_refl_restr' theorem restr_trans (s : Set α) : (e.restr s).trans e' = (e.trans e').restr s := - LocalEquiv.ext (fun x => rfl) (fun x => rfl) <| by + PartialEquiv.ext (fun x => rfl) (fun x => rfl) <| by simp [trans_source, inter_comm, inter_assoc] -#align local_equiv.restr_trans LocalEquiv.restr_trans +#align local_equiv.restr_trans PartialEquiv.restr_trans /-- A lemma commonly useful when `e` and `e'` are charts of a manifold. -/ -theorem mem_symm_trans_source {e' : LocalEquiv α γ} {x : α} (he : x ∈ e.source) +theorem mem_symm_trans_source {e' : PartialEquiv α γ} {x : α} (he : x ∈ e.source) (he' : x ∈ e'.source) : e x ∈ (e.symm.trans e').source := - ⟨e.mapsTo he, by rwa [mem_preimage, LocalEquiv.symm_symm, e.left_inv he]⟩ -#align local_equiv.mem_symm_trans_source LocalEquiv.mem_symm_trans_source + ⟨e.mapsTo he, by rwa [mem_preimage, PartialEquiv.symm_symm, e.left_inv he]⟩ +#align local_equiv.mem_symm_trans_source PartialEquiv.mem_symm_trans_source -/-- Postcompose a local equivalence with an equivalence. +/-- Postcompose a partial equivalence with an equivalence. We modify the source and target to have better definitional behavior. -/ @[simps!] -def transEquiv (e' : β ≃ γ) : LocalEquiv α γ := - (e.trans e'.toLocalEquiv).copy _ rfl _ rfl e.source (inter_univ _) (e'.symm ⁻¹' e.target) +def transEquiv (e' : β ≃ γ) : PartialEquiv α γ := + (e.trans e'.toPartialEquiv).copy _ rfl _ rfl e.source (inter_univ _) (e'.symm ⁻¹' e.target) (univ_inter _) -#align local_equiv.trans_equiv LocalEquiv.transEquiv -#align local_equiv.trans_equiv_source LocalEquiv.transEquiv_source -#align local_equiv.trans_equiv_apply LocalEquiv.transEquiv_apply -#align local_equiv.trans_equiv_target LocalEquiv.transEquiv_target -#align local_equiv.trans_equiv_symm_apply LocalEquiv.transEquiv_symm_apply +#align local_equiv.trans_equiv PartialEquiv.transEquiv +#align local_equiv.trans_equiv_source PartialEquiv.transEquiv_source +#align local_equiv.trans_equiv_apply PartialEquiv.transEquiv_apply +#align local_equiv.trans_equiv_target PartialEquiv.transEquiv_target +#align local_equiv.trans_equiv_symm_apply PartialEquiv.transEquiv_symm_apply -theorem transEquiv_eq_trans (e' : β ≃ γ) : e.transEquiv e' = e.trans e'.toLocalEquiv := +theorem transEquiv_eq_trans (e' : β ≃ γ) : e.transEquiv e' = e.trans e'.toPartialEquiv := copy_eq .. -#align local_equiv.trans_equiv_eq_trans LocalEquiv.transEquiv_eq_trans +#align local_equiv.trans_equiv_eq_trans PartialEquiv.transEquiv_eq_trans -/-- Precompose a local equivalence with an equivalence. +/-- Precompose a partial equivalence with an equivalence. We modify the source and target to have better definitional behavior. -/ @[simps!] -def _root_.Equiv.transLocalEquiv (e : α ≃ β) : LocalEquiv α γ := - (e.toLocalEquiv.trans e').copy _ rfl _ rfl (e ⁻¹' e'.source) (univ_inter _) e'.target +def _root_.Equiv.transPartialEquiv (e : α ≃ β) : PartialEquiv α γ := + (e.toPartialEquiv.trans e').copy _ rfl _ rfl (e ⁻¹' e'.source) (univ_inter _) e'.target (inter_univ _) -#align equiv.trans_local_equiv Equiv.transLocalEquiv -#align equiv.trans_local_equiv_target Equiv.transLocalEquiv_target -#align equiv.trans_local_equiv_apply Equiv.transLocalEquiv_apply -#align equiv.trans_local_equiv_source Equiv.transLocalEquiv_source -#align equiv.trans_local_equiv_symm_apply Equiv.transLocalEquiv_symm_apply - -theorem _root_.Equiv.transLocalEquiv_eq_trans (e : α ≃ β) : - e.transLocalEquiv e' = e.toLocalEquiv.trans e' := +#align equiv.trans_local_equiv Equiv.transPartialEquiv +#align equiv.trans_local_equiv_target Equiv.transPartialEquiv_target +#align equiv.trans_local_equiv_apply Equiv.transPartialEquiv_apply +#align equiv.trans_local_equiv_source Equiv.transPartialEquiv_source +#align equiv.trans_local_equiv_symm_apply Equiv.transPartialEquiv_symm_apply + +theorem _root_.Equiv.transPartialEquiv_eq_trans (e : α ≃ β) : + e.transPartialEquiv e' = e.toPartialEquiv.trans e' := copy_eq .. -#align equiv.trans_local_equiv_eq_trans Equiv.transLocalEquiv_eq_trans +#align equiv.trans_local_equiv_eq_trans Equiv.transPartialEquiv_eq_trans /-- `EqOnSource e e'` means that `e` and `e'` have the same source, and coincide there. Then `e` -and `e'` should really be considered the same local equiv. -/ -def EqOnSource (e e' : LocalEquiv α β) : Prop := +and `e'` should really be considered the same partial equiv. -/ +def EqOnSource (e e' : PartialEquiv α β) : Prop := e.source = e'.source ∧ e.source.EqOn e e' -#align local_equiv.eq_on_source LocalEquiv.EqOnSource +#align local_equiv.eq_on_source PartialEquiv.EqOnSource /-- `EqOnSource` is an equivalence relation. This instance provides the `≈` notation between two -`LocalEquiv`s. -/ -instance eqOnSourceSetoid : Setoid (LocalEquiv α β) where +`PartialEquiv`s. -/ +instance eqOnSourceSetoid : Setoid (PartialEquiv α β) where r := EqOnSource iseqv := by constructor <;> simp only [Equivalence, EqOnSource, EqOn] <;> aesop -#align local_equiv.eq_on_source_setoid LocalEquiv.eqOnSourceSetoid +#align local_equiv.eq_on_source_setoid PartialEquiv.eqOnSourceSetoid theorem eqOnSource_refl : e ≈ e := Setoid.refl _ -#align local_equiv.eq_on_source_refl LocalEquiv.eqOnSource_refl +#align local_equiv.eq_on_source_refl PartialEquiv.eqOnSource_refl -/-- Two equivalent local equivs have the same source. -/ -theorem EqOnSource.source_eq {e e' : LocalEquiv α β} (h : e ≈ e') : e.source = e'.source := +/-- Two equivalent partial equivs have the same source. -/ +theorem EqOnSource.source_eq {e e' : PartialEquiv α β} (h : e ≈ e') : e.source = e'.source := h.1 -#align local_equiv.eq_on_source.source_eq LocalEquiv.EqOnSource.source_eq +#align local_equiv.eq_on_source.source_eq PartialEquiv.EqOnSource.source_eq -/-- Two equivalent local equivs coincide on the source. -/ -theorem EqOnSource.eqOn {e e' : LocalEquiv α β} (h : e ≈ e') : e.source.EqOn e e' := +/-- Two equivalent partial equivs coincide on the source. -/ +theorem EqOnSource.eqOn {e e' : PartialEquiv α β} (h : e ≈ e') : e.source.EqOn e e' := h.2 -#align local_equiv.eq_on_source.eq_on LocalEquiv.EqOnSource.eqOn +#align local_equiv.eq_on_source.eq_on PartialEquiv.EqOnSource.eqOn --Porting note: A lot of dot notation failures here. Maybe we should not use `≈` -/-- Two equivalent local equivs have the same target. -/ -theorem EqOnSource.target_eq {e e' : LocalEquiv α β} (h : e ≈ e') : e.target = e'.target := by +/-- Two equivalent partial equivs have the same target. -/ +theorem EqOnSource.target_eq {e e' : PartialEquiv α β} (h : e ≈ e') : e.target = e'.target := by simp only [← image_source_eq_target, ← source_eq h, h.2.image_eq] -#align local_equiv.eq_on_source.target_eq LocalEquiv.EqOnSource.target_eq +#align local_equiv.eq_on_source.target_eq PartialEquiv.EqOnSource.target_eq -/-- If two local equivs are equivalent, so are their inverses. -/ -theorem EqOnSource.symm' {e e' : LocalEquiv α β} (h : e ≈ e') : e.symm ≈ e'.symm := by +/-- If two partial equivs are equivalent, so are their inverses. -/ +theorem EqOnSource.symm' {e e' : PartialEquiv α β} (h : e ≈ e') : e.symm ≈ e'.symm := by refine' ⟨target_eq h, eqOn_of_leftInvOn_of_rightInvOn e.leftInvOn _ _⟩ <;> simp only [symm_source, target_eq h, source_eq h, e'.symm_mapsTo] exact e'.rightInvOn.congr_right e'.symm_mapsTo (source_eq h ▸ h.eqOn.symm) -#align local_equiv.eq_on_source.symm' LocalEquiv.EqOnSource.symm' +#align local_equiv.eq_on_source.symm' PartialEquiv.EqOnSource.symm' -/-- Two equivalent local equivs have coinciding inverses on the target. -/ -theorem EqOnSource.symm_eqOn {e e' : LocalEquiv α β} (h : e ≈ e') : EqOn e.symm e'.symm e.target := +/-- Two equivalent partial equivs have coinciding inverses on the target. -/ +theorem EqOnSource.symm_eqOn {e e' : PartialEquiv α β} (h : e ≈ e') : + EqOn e.symm e'.symm e.target := -- Porting note: `h.symm'` dot notation doesn't work anymore because `h` is not recognised as - -- `LocalEquiv.EqOnSource` for some reason. + -- `PartialEquiv.EqOnSource` for some reason. eqOn (symm' h) -#align local_equiv.eq_on_source.symm_eq_on LocalEquiv.EqOnSource.symm_eqOn +#align local_equiv.eq_on_source.symm_eq_on PartialEquiv.EqOnSource.symm_eqOn -/-- Composition of local equivs respects equivalence. -/ -theorem EqOnSource.trans' {e e' : LocalEquiv α β} {f f' : LocalEquiv β γ} (he : e ≈ e') +/-- Composition of partial equivs respects equivalence. -/ +theorem EqOnSource.trans' {e e' : PartialEquiv α β} {f f' : PartialEquiv β γ} (he : e ≈ e') (hf : f ≈ f') : e.trans f ≈ e'.trans f' := by constructor · rw [trans_source'', trans_source'', ← target_eq he, ← hf.1] exact (he.symm'.eqOn.mono <| inter_subset_left _ _).image_eq · intro x hx rw [trans_source] at hx - simp [Function.comp_apply, LocalEquiv.coe_trans, (he.2 hx.1).symm, hf.2 hx.2] -#align local_equiv.eq_on_source.trans' LocalEquiv.EqOnSource.trans' + simp [Function.comp_apply, PartialEquiv.coe_trans, (he.2 hx.1).symm, hf.2 hx.2] +#align local_equiv.eq_on_source.trans' PartialEquiv.EqOnSource.trans' -/-- Restriction of local equivs respects equivalence. -/ -theorem EqOnSource.restr {e e' : LocalEquiv α β} (he : e ≈ e') (s : Set α) : +/-- Restriction of partial equivs respects equivalence. -/ +theorem EqOnSource.restr {e e' : PartialEquiv α β} (he : e ≈ e') (s : Set α) : e.restr s ≈ e'.restr s := by constructor · simp [he.1] · intro x hx simp only [mem_inter_iff, restr_source] at hx exact he.2 hx.1 -#align local_equiv.eq_on_source.restr LocalEquiv.EqOnSource.restr +#align local_equiv.eq_on_source.restr PartialEquiv.EqOnSource.restr /-- Preimages are respected by equivalence. -/ -theorem EqOnSource.source_inter_preimage_eq {e e' : LocalEquiv α β} (he : e ≈ e') (s : Set β) : +theorem EqOnSource.source_inter_preimage_eq {e e' : PartialEquiv α β} (he : e ≈ e') (s : Set β) : e.source ∩ e ⁻¹' s = e'.source ∩ e' ⁻¹' s := by rw [he.eqOn.inter_preimage_eq, source_eq he] -#align local_equiv.eq_on_source.source_inter_preimage_eq LocalEquiv.EqOnSource.source_inter_preimage_eq +#align local_equiv.eq_on_source.source_inter_preimage_eq PartialEquiv.EqOnSource.source_inter_preimage_eq -/-- Composition of a local equiv and its inverse is equivalent to the restriction of the identity -to the source. -/ +/-- Composition of a partial equivlance and its inverse is equivalent to +the restriction of the identity to the source. -/ theorem trans_self_symm : e.trans e.symm ≈ ofSet e.source := by have A : (e.trans e.symm).source = e.source := by mfld_set_tac refine' ⟨by rw [A, ofSet_source], fun x hx => _⟩ rw [A] at hx simp only [hx, mfld_simps] -#align local_equiv.trans_self_symm LocalEquiv.trans_self_symm +#align local_equiv.trans_self_symm PartialEquiv.trans_self_symm -/-- Composition of the inverse of a local equiv and this local equiv is equivalent to the -restriction of the identity to the target. -/ -theorem trans_symm_self : e.symm.trans e ≈ LocalEquiv.ofSet e.target := +/-- Composition of the inverse of a partial equivalence and this partial equivalence is equivalent +to the restriction of the identity to the target. -/ +theorem trans_symm_self : e.symm.trans e ≈ PartialEquiv.ofSet e.target := trans_self_symm e.symm -#align local_equiv.trans_symm_self LocalEquiv.trans_symm_self +#align local_equiv.trans_symm_self PartialEquiv.trans_symm_self -/-- Two equivalent local equivs are equal when the source and target are `univ`. -/ -theorem eq_of_eqOnSource_univ (e e' : LocalEquiv α β) (h : e ≈ e') (s : e.source = univ) +/-- Two equivalent partial equivs are equal when the source and target are `univ`. -/ +theorem eq_of_eqOnSource_univ (e e' : PartialEquiv α β) (h : e ≈ e') (s : e.source = univ) (t : e.target = univ) : e = e' := by - refine LocalEquiv.ext (fun x => ?_) (fun x => ?_) h.1 + refine PartialEquiv.ext (fun x => ?_) (fun x => ?_) h.1 · apply h.2 rw [s] exact mem_univ _ · apply h.symm'.2 rw [symm_source, t] exact mem_univ _ -#align local_equiv.eq_of_eq_on_source_univ LocalEquiv.eq_of_eqOnSource_univ +#align local_equiv.eq_of_eq_on_source_univ PartialEquiv.eq_of_eqOnSource_univ section Prod -/-- The product of two local equivs, as a local equiv on the product. -/ -def prod (e : LocalEquiv α β) (e' : LocalEquiv γ δ) : LocalEquiv (α × γ) (β × δ) where +/-- The product of two partial equivalences, as a partial equivalence on the product. -/ +def prod (e : PartialEquiv α β) (e' : PartialEquiv γ δ) : PartialEquiv (α × γ) (β × δ) where source := e.source ×ˢ e'.source target := e.target ×ˢ e'.target toFun p := (e p.1, e' p.2) @@ -938,62 +941,62 @@ def prod (e : LocalEquiv α β) (e' : LocalEquiv γ δ) : LocalEquiv (α × γ) right_inv' p hp := by simp at hp simp [hp] -#align local_equiv.prod LocalEquiv.prod +#align local_equiv.prod PartialEquiv.prod @[simp, mfld_simps] -theorem prod_source (e : LocalEquiv α β) (e' : LocalEquiv γ δ) : +theorem prod_source (e : PartialEquiv α β) (e' : PartialEquiv γ δ) : (e.prod e').source = e.source ×ˢ e'.source := rfl -#align local_equiv.prod_source LocalEquiv.prod_source +#align local_equiv.prod_source PartialEquiv.prod_source @[simp, mfld_simps] -theorem prod_target (e : LocalEquiv α β) (e' : LocalEquiv γ δ) : +theorem prod_target (e : PartialEquiv α β) (e' : PartialEquiv γ δ) : (e.prod e').target = e.target ×ˢ e'.target := rfl -#align local_equiv.prod_target LocalEquiv.prod_target +#align local_equiv.prod_target PartialEquiv.prod_target @[simp, mfld_simps] -theorem prod_coe (e : LocalEquiv α β) (e' : LocalEquiv γ δ) : +theorem prod_coe (e : PartialEquiv α β) (e' : PartialEquiv γ δ) : (e.prod e' : α × γ → β × δ) = fun p => (e p.1, e' p.2) := rfl -#align local_equiv.prod_coe LocalEquiv.prod_coe +#align local_equiv.prod_coe PartialEquiv.prod_coe -theorem prod_coe_symm (e : LocalEquiv α β) (e' : LocalEquiv γ δ) : +theorem prod_coe_symm (e : PartialEquiv α β) (e' : PartialEquiv γ δ) : ((e.prod e').symm : β × δ → α × γ) = fun p => (e.symm p.1, e'.symm p.2) := rfl -#align local_equiv.prod_coe_symm LocalEquiv.prod_coe_symm +#align local_equiv.prod_coe_symm PartialEquiv.prod_coe_symm @[simp, mfld_simps] -theorem prod_symm (e : LocalEquiv α β) (e' : LocalEquiv γ δ) : +theorem prod_symm (e : PartialEquiv α β) (e' : PartialEquiv γ δ) : (e.prod e').symm = e.symm.prod e'.symm := by ext x <;> simp [prod_coe_symm] -#align local_equiv.prod_symm LocalEquiv.prod_symm +#align local_equiv.prod_symm PartialEquiv.prod_symm @[simp, mfld_simps] theorem refl_prod_refl : - (LocalEquiv.refl α).prod (LocalEquiv.refl β) = LocalEquiv.refl (α × β) := by + (PartialEquiv.refl α).prod (PartialEquiv.refl β) = PartialEquiv.refl (α × β) := by -- Porting note: `ext1 ⟨x, y⟩` insufficient number of binders ext ⟨x, y⟩ <;> simp -#align local_equiv.refl_prod_refl LocalEquiv.refl_prod_refl +#align local_equiv.refl_prod_refl PartialEquiv.refl_prod_refl @[simp, mfld_simps] -theorem prod_trans {η : Type*} {ε : Type*} (e : LocalEquiv α β) (f : LocalEquiv β γ) - (e' : LocalEquiv δ η) (f' : LocalEquiv η ε) : +theorem prod_trans {η : Type*} {ε : Type*} (e : PartialEquiv α β) (f : PartialEquiv β γ) + (e' : PartialEquiv δ η) (f' : PartialEquiv η ε) : (e.prod e').trans (f.prod f') = (e.trans f).prod (e'.trans f') := by ext ⟨x, y⟩ <;> simp [ext_iff]; tauto -#align local_equiv.prod_trans LocalEquiv.prod_trans +#align local_equiv.prod_trans PartialEquiv.prod_trans end Prod -/-- Combine two `LocalEquiv`s using `Set.piecewise`. The source of the new `LocalEquiv` is +/-- Combine two `PartialEquiv`s using `Set.piecewise`. The source of the new `PartialEquiv` is `s.ite e.source e'.source = e.source ∩ s ∪ e'.source \ s`, and similarly for target. The function sends `e.source ∩ s` to `e.target ∩ t` using `e` and `e'.source \ s` to `e'.target \ t` using `e'`, and similarly for the inverse function. The definition assumes `e.isImage s t` and `e'.isImage s t`. -/ @[simps (config := .asFn)] -def piecewise (e e' : LocalEquiv α β) (s : Set α) (t : Set β) [∀ x, Decidable (x ∈ s)] +def piecewise (e e' : PartialEquiv α β) (s : Set α) (t : Set β) [∀ x, Decidable (x ∈ s)] [∀ y, Decidable (y ∈ t)] (H : e.IsImage s t) (H' : e'.IsImage s t) : - LocalEquiv α β where + PartialEquiv α β where toFun := s.piecewise e e' invFun := t.piecewise e.symm e'.symm source := s.ite e.source e'.source @@ -1002,50 +1005,50 @@ def piecewise (e e' : LocalEquiv α β) (s : Set α) (t : Set β) [∀ x, Decida map_target' := H.symm.mapsTo.piecewise_ite H'.symm.compl.mapsTo left_inv' := H.leftInvOn_piecewise H' right_inv' := H.symm.leftInvOn_piecewise H'.symm -#align local_equiv.piecewise LocalEquiv.piecewise -#align local_equiv.piecewise_source LocalEquiv.piecewise_source -#align local_equiv.piecewise_target LocalEquiv.piecewise_target -#align local_equiv.piecewise_symm_apply LocalEquiv.piecewise_symm_apply -#align local_equiv.piecewise_apply LocalEquiv.piecewise_apply +#align local_equiv.piecewise PartialEquiv.piecewise +#align local_equiv.piecewise_source PartialEquiv.piecewise_source +#align local_equiv.piecewise_target PartialEquiv.piecewise_target +#align local_equiv.piecewise_symm_apply PartialEquiv.piecewise_symm_apply +#align local_equiv.piecewise_apply PartialEquiv.piecewise_apply -theorem symm_piecewise (e e' : LocalEquiv α β) {s : Set α} {t : Set β} [∀ x, Decidable (x ∈ s)] +theorem symm_piecewise (e e' : PartialEquiv α β) {s : Set α} {t : Set β} [∀ x, Decidable (x ∈ s)] [∀ y, Decidable (y ∈ t)] (H : e.IsImage s t) (H' : e'.IsImage s t) : (e.piecewise e' s t H H').symm = e.symm.piecewise e'.symm t s H.symm H'.symm := rfl -#align local_equiv.symm_piecewise LocalEquiv.symm_piecewise +#align local_equiv.symm_piecewise PartialEquiv.symm_piecewise -/-- Combine two `LocalEquiv`s with disjoint sources and disjoint targets. We reuse -`LocalEquiv.piecewise`, then override `source` and `target` to ensure better definitional +/-- Combine two `PartialEquiv`s with disjoint sources and disjoint targets. We reuse +`PartialEquiv.piecewise`, then override `source` and `target` to ensure better definitional equalities. -/ @[simps! (config := .asFn)] -def disjointUnion (e e' : LocalEquiv α β) (hs : Disjoint e.source e'.source) +def disjointUnion (e e' : PartialEquiv α β) (hs : Disjoint e.source e'.source) (ht : Disjoint e.target e'.target) [∀ x, Decidable (x ∈ e.source)] - [∀ y, Decidable (y ∈ e.target)] : LocalEquiv α β := + [∀ y, Decidable (y ∈ e.target)] : PartialEquiv α β := (e.piecewise e' e.source e.target e.isImage_source_target <| e'.isImage_source_target_of_disjoint _ hs.symm ht.symm).copy _ rfl _ rfl (e.source ∪ e'.source) (ite_left _ _) (e.target ∪ e'.target) (ite_left _ _) -#align local_equiv.disjoint_union LocalEquiv.disjointUnion -#align local_equiv.disjoint_union_source LocalEquiv.disjointUnion_source -#align local_equiv.disjoint_union_target LocalEquiv.disjointUnion_target -#align local_equiv.disjoint_union_symm_apply LocalEquiv.disjointUnion_symm_apply -#align local_equiv.disjoint_union_apply LocalEquiv.disjointUnion_apply +#align local_equiv.disjoint_union PartialEquiv.disjointUnion +#align local_equiv.disjoint_union_source PartialEquiv.disjointUnion_source +#align local_equiv.disjoint_union_target PartialEquiv.disjointUnion_target +#align local_equiv.disjoint_union_symm_apply PartialEquiv.disjointUnion_symm_apply +#align local_equiv.disjoint_union_apply PartialEquiv.disjointUnion_apply -theorem disjointUnion_eq_piecewise (e e' : LocalEquiv α β) (hs : Disjoint e.source e'.source) +theorem disjointUnion_eq_piecewise (e e' : PartialEquiv α β) (hs : Disjoint e.source e'.source) (ht : Disjoint e.target e'.target) [∀ x, Decidable (x ∈ e.source)] [∀ y, Decidable (y ∈ e.target)] : e.disjointUnion e' hs ht = e.piecewise e' e.source e.target e.isImage_source_target (e'.isImage_source_target_of_disjoint _ hs.symm ht.symm) := copy_eq .. -#align local_equiv.disjoint_union_eq_piecewise LocalEquiv.disjointUnion_eq_piecewise +#align local_equiv.disjoint_union_eq_piecewise PartialEquiv.disjointUnion_eq_piecewise section Pi variable {ι : Type*} {αi βi γi : ι → Type*} -/-- The product of a family of local equivs, as a local equiv on the pi type. -/ +/-- The product of a family of partial equivalences, as a partial equivalence on the pi type. -/ @[simps (config := mfld_cfg) apply source target] -protected def pi (ei : ∀ i, LocalEquiv (αi i) (βi i)) : LocalEquiv (∀ i, αi i) (∀ i, βi i) where +protected def pi (ei : ∀ i, PartialEquiv (αi i) (βi i)) : PartialEquiv (∀ i, αi i) (∀ i, βi i) where toFun f i := ei i (f i) invFun f i := (ei i).symm (f i) source := pi univ fun i => (ei i).source @@ -1054,42 +1057,42 @@ protected def pi (ei : ∀ i, LocalEquiv (αi i) (βi i)) : LocalEquiv (∀ i, map_target' _ hf i hi := (ei i).map_target (hf i hi) left_inv' _ hf := funext fun i => (ei i).left_inv (hf i trivial) right_inv' _ hf := funext fun i => (ei i).right_inv (hf i trivial) -#align local_equiv.pi LocalEquiv.pi -#align local_equiv.pi_source LocalEquiv.pi_source -#align local_equiv.pi_apply LocalEquiv.pi_apply -#align local_equiv.pi_target LocalEquiv.pi_target +#align local_equiv.pi PartialEquiv.pi +#align local_equiv.pi_source PartialEquiv.pi_source +#align local_equiv.pi_apply PartialEquiv.pi_apply +#align local_equiv.pi_target PartialEquiv.pi_target @[simp, mfld_simps] -theorem pi_symm (ei : ∀ i, LocalEquiv (αi i) (βi i)) : - (LocalEquiv.pi ei).symm = .pi fun i ↦ (ei i).symm := +theorem pi_symm (ei : ∀ i, PartialEquiv (αi i) (βi i)) : + (PartialEquiv.pi ei).symm = .pi fun i ↦ (ei i).symm := rfl -theorem pi_symm_apply (ei : ∀ i, LocalEquiv (αi i) (βi i)) : - ⇑(LocalEquiv.pi ei).symm = fun f i ↦ (ei i).symm (f i) := +theorem pi_symm_apply (ei : ∀ i, PartialEquiv (αi i) (βi i)) : + ⇑(PartialEquiv.pi ei).symm = fun f i ↦ (ei i).symm (f i) := rfl -#align local_equiv.pi_symm_apply LocalEquiv.pi_symm_apply +#align local_equiv.pi_symm_apply PartialEquiv.pi_symm_apply @[simp, mfld_simps] -theorem pi_refl : (LocalEquiv.pi fun i ↦ LocalEquiv.refl (αi i)) = .refl (∀ i, αi i) := by +theorem pi_refl : (PartialEquiv.pi fun i ↦ PartialEquiv.refl (αi i)) = .refl (∀ i, αi i) := by ext <;> simp @[simp, mfld_simps] -theorem pi_trans (ei : ∀ i, LocalEquiv (αi i) (βi i)) (ei' : ∀ i, LocalEquiv (βi i) (γi i)) : - (LocalEquiv.pi ei).trans (LocalEquiv.pi ei') = .pi fun i ↦ (ei i).trans (ei' i) := by +theorem pi_trans (ei : ∀ i, PartialEquiv (αi i) (βi i)) (ei' : ∀ i, PartialEquiv (βi i) (γi i)) : + (PartialEquiv.pi ei).trans (PartialEquiv.pi ei') = .pi fun i ↦ (ei i).trans (ei' i) := by ext <;> simp [forall_and] end Pi -end LocalEquiv +end PartialEquiv namespace Set -- All arguments are explicit to avoid missing information in the pretty printer output -/-- A bijection between two sets `s : Set α` and `t : Set β` provides a local equivalence +/-- A bijection between two sets `s : Set α` and `t : Set β` provides a partial equivalence between `α` and `β`. -/ @[simps (config := .asFn)] -noncomputable def BijOn.toLocalEquiv [Nonempty α] (f : α → β) (s : Set α) (t : Set β) - (hf : BijOn f s t) : LocalEquiv α β where +noncomputable def BijOn.toPartialEquiv [Nonempty α] (f : α → β) (s : Set α) (t : Set β) + (hf : BijOn f s t) : PartialEquiv α β where toFun := f invFun := invFunOn f s source := s @@ -1098,41 +1101,42 @@ noncomputable def BijOn.toLocalEquiv [Nonempty α] (f : α → β) (s : Set α) map_target' := hf.surjOn.mapsTo_invFunOn left_inv' := hf.invOn_invFunOn.1 right_inv' := hf.invOn_invFunOn.2 -#align set.bij_on.to_local_equiv Set.BijOn.toLocalEquiv -#align set.bij_on.to_local_equiv_target Set.BijOn.toLocalEquiv_target -#align set.bij_on.to_local_equiv_symm_apply Set.BijOn.toLocalEquiv_symm_apply -#align set.bij_on.to_local_equiv_apply Set.BijOn.toLocalEquiv_apply -#align set.bij_on.to_local_equiv_source Set.BijOn.toLocalEquiv_source +#align set.bij_on.to_local_equiv Set.BijOn.toPartialEquiv +#align set.bij_on.to_local_equiv_target Set.BijOn.toPartialEquiv_target +#align set.bij_on.to_local_equiv_symm_apply Set.BijOn.toPartialEquiv_symm_apply +#align set.bij_on.to_local_equiv_apply Set.BijOn.toPartialEquiv_apply +#align set.bij_on.to_local_equiv_source Set.BijOn.toPartialEquiv_source -/-- A map injective on a subset of its domain provides a local equivalence. -/ +/-- A map injective on a subset of its domain provides a partial equivalence. -/ @[simp, mfld_simps] -noncomputable def InjOn.toLocalEquiv [Nonempty α] (f : α → β) (s : Set α) (hf : InjOn f s) : - LocalEquiv α β := - hf.bijOn_image.toLocalEquiv f s (f '' s) -#align set.inj_on.to_local_equiv Set.InjOn.toLocalEquiv +noncomputable def InjOn.toPartialEquiv [Nonempty α] (f : α → β) (s : Set α) (hf : InjOn f s) : + PartialEquiv α β := + hf.bijOn_image.toPartialEquiv f s (f '' s) +#align set.inj_on.to_local_equiv Set.InjOn.toPartialEquiv end Set namespace Equiv -/- `Equiv`s give rise to `LocalEquiv`s. We set up simp lemmas to reduce most properties of the -`LocalEquiv` to that of the `Equiv`. -/ +/- `Equiv`s give rise to `PartialEquiv`s. We set up simp lemmas to reduce most properties of the +`PartialEquiv` to that of the `Equiv`. -/ variable (e : α ≃ β) (e' : β ≃ γ) @[simp, mfld_simps] -theorem refl_toLocalEquiv : (Equiv.refl α).toLocalEquiv = LocalEquiv.refl α := +theorem refl_toPartialEquiv : (Equiv.refl α).toPartialEquiv = PartialEquiv.refl α := rfl -#align equiv.refl_to_local_equiv Equiv.refl_toLocalEquiv +#align equiv.refl_to_local_equiv Equiv.refl_toPartialEquiv @[simp, mfld_simps] -theorem symm_toLocalEquiv : e.symm.toLocalEquiv = e.toLocalEquiv.symm := +theorem symm_toPartialEquiv : e.symm.toPartialEquiv = e.toPartialEquiv.symm := rfl -#align equiv.symm_to_local_equiv Equiv.symm_toLocalEquiv +#align equiv.symm_to_local_equiv Equiv.symm_toPartialEquiv @[simp, mfld_simps] -theorem trans_toLocalEquiv : (e.trans e').toLocalEquiv = e.toLocalEquiv.trans e'.toLocalEquiv := - LocalEquiv.ext (fun x => rfl) (fun x => rfl) - (by simp [LocalEquiv.trans_source, Equiv.toLocalEquiv]) -#align equiv.trans_to_local_equiv Equiv.trans_toLocalEquiv +theorem trans_toPartialEquiv : + (e.trans e').toPartialEquiv = e.toPartialEquiv.trans e'.toPartialEquiv := + PartialEquiv.ext (fun x => rfl) (fun x => rfl) + (by simp [PartialEquiv.trans_source, Equiv.toPartialEquiv]) +#align equiv.trans_to_local_equiv Equiv.trans_toPartialEquiv end Equiv diff --git a/Mathlib/Logic/Equiv/Set.lean b/Mathlib/Logic/Equiv/Set.lean index ad4d0840336b3..2b6b7cff2e998 100644 --- a/Mathlib/Logic/Equiv/Set.lean +++ b/Mathlib/Logic/Equiv/Set.lean @@ -486,18 +486,16 @@ protected noncomputable def image {α β} (f : α → β) (s : Set α) (H : Inje #align equiv.set.image Equiv.Set.image #align equiv.set.image_apply Equiv.Set.image_apply -@[simp, nolint simpNF] -- see std4#365 for the simpNF issue +@[simp] protected theorem image_symm_apply {α β} (f : α → β) (s : Set α) (H : Injective f) (x : α) - (h : x ∈ s) : (Set.image f s H).symm ⟨f x, ⟨x, ⟨h, rfl⟩⟩⟩ = ⟨x, h⟩ := by - apply (Set.image f s H).injective - simp [(Set.image f s H).apply_symm_apply] + (h : f x ∈ f '' s) : (Set.image f s H).symm ⟨f x, h⟩ = ⟨x, H.mem_set_image.1 h⟩ := + (Equiv.symm_apply_eq _).2 rfl #align equiv.set.image_symm_apply Equiv.Set.image_symm_apply theorem image_symm_preimage {α β} {f : α → β} (hf : Injective f) (u s : Set α) : (fun x => (Set.image f s hf).symm x : f '' s → α) ⁻¹' u = Subtype.val ⁻¹' (f '' u) := by ext ⟨b, a, has, rfl⟩ - have : ∀ h : ∃ a', a' ∈ s ∧ a' = a, Classical.choose h = a := fun h => (Classical.choose_spec h).2 - simp [Equiv.Set.image, Equiv.Set.imageOfInjOn, hf.eq_iff, this] + simp [hf.eq_iff] #align equiv.set.image_symm_preimage Equiv.Set.image_symm_preimage /-- If `α` is equivalent to `β`, then `Set α` is equivalent to `Set β`. -/ diff --git a/Mathlib/Mathport/Syntax.lean b/Mathlib/Mathport/Syntax.lean index 69cd1979c88fc..afc5049d8f5ac 100644 --- a/Mathlib/Mathport/Syntax.lean +++ b/Mathlib/Mathport/Syntax.lean @@ -9,7 +9,7 @@ import Std.Tactic.Ext import Std.Tactic.RCases import Std.Tactic.Where import Mathlib.Data.Matrix.Notation -import Mathlib.Logic.Equiv.LocalEquiv +import Mathlib.Logic.Equiv.PartialEquiv import Mathlib.MeasureTheory.Constructions.BorelSpace.Basic import Mathlib.Order.Filter.Basic import Mathlib.RingTheory.WittVector.Basic diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean index 7f3e324a8a0c1..1a11f186b838a 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean @@ -1105,6 +1105,10 @@ instance Prod.borelSpace [SecondCountableTopologyEither α β] : ⟨le_antisymm prod_le_borel_prod OpensMeasurableSpace.borel_le⟩ #align prod.borel_space Prod.borelSpace +instance DiscreteMeasurableSpace.toBorelSpace {α : Type*} [TopologicalSpace α] [DiscreteTopology α] + [MeasurableSpace α] [DiscreteMeasurableSpace α] : BorelSpace α := by + constructor; ext; simp [MeasurableSpace.measurableSet_generateFrom, measurableSet_discrete] + protected theorem Embedding.measurableEmbedding {f : α → β} (h₁ : Embedding f) (h₂ : MeasurableSet (range f)) : MeasurableEmbedding f := show MeasurableEmbedding diff --git a/Mathlib/MeasureTheory/Decomposition/SignedLebesgue.lean b/Mathlib/MeasureTheory/Decomposition/SignedLebesgue.lean index 461d1672745c4..2d7ffe0b4235d 100644 --- a/Mathlib/MeasureTheory/Decomposition/SignedLebesgue.lean +++ b/Mathlib/MeasureTheory/Decomposition/SignedLebesgue.lean @@ -508,7 +508,7 @@ theorem singularPart_add_withDensity_rnDeriv_eq [c.HaveLebesgueDecomposition μ] conv_rhs => rw [← c.toComplexMeasure_to_signedMeasure] ext i hi : 1 rw [VectorMeasure.add_apply, SignedMeasure.toComplexMeasure_apply] - ext + apply Complex.ext · rw [Complex.add_re, withDensityᵥ_apply (c.integrable_rnDeriv μ) hi, ← IsROrC.re_eq_complex_re, ← integral_re (c.integrable_rnDeriv μ).integrableOn, IsROrC.re_eq_complex_re, ← withDensityᵥ_apply _ hi] diff --git a/Mathlib/MeasureTheory/Function/Jacobian.lean b/Mathlib/MeasureTheory/Function/Jacobian.lean index 995cdca6dea03..0afc446ce88dc 100644 --- a/Mathlib/MeasureTheory/Function/Jacobian.lean +++ b/Mathlib/MeasureTheory/Function/Jacobian.lean @@ -445,7 +445,7 @@ theorem mul_le_addHaar_image_of_lt_det (A : E →L[ℝ] E) {m : ℝ≥0} filter_upwards [L1, L2] intro δ h1δ h2δ s f hf have hf' : ApproximatesLinearOn f (B : E →L[ℝ] E) s δ := by convert hf - let F := hf'.toLocalEquiv h1δ + let F := hf'.toPartialEquiv h1δ -- the condition to be checked can be reformulated in terms of the inverse maps suffices H : μ (F.symm '' F.target) ≤ (m⁻¹ : ℝ≥0) * μ F.target · change (m : ℝ≥0∞) * μ F.source ≤ μ F.target @@ -1252,10 +1252,10 @@ theorem integral_image_eq_integral_abs_deriv_smul {s : Set ℝ} {f : ℝ → ℝ (fun x hx => (hf' x hx).hasFDerivWithinAt) hf g #align measure_theory.integral_image_eq_integral_abs_deriv_smul MeasureTheory.integral_image_eq_integral_abs_deriv_smul -theorem integral_target_eq_integral_abs_det_fderiv_smul {f : LocalHomeomorph E E} +theorem integral_target_eq_integral_abs_det_fderiv_smul {f : PartialHomeomorph E E} (hf' : ∀ x ∈ f.source, HasFDerivAt f (f' x) x) (g : E → F) : ∫ x in f.target, g x ∂μ = ∫ x in f.source, |(f' x).det| • g (f x) ∂μ := by - have : f '' f.source = f.target := LocalEquiv.image_source_eq_target f.toLocalEquiv + have : f '' f.source = f.target := PartialEquiv.image_source_eq_target f.toPartialEquiv rw [← this] apply integral_image_eq_integral_abs_det_fderiv_smul μ f.open_source.measurableSet _ f.injOn intro x hx diff --git a/Mathlib/MeasureTheory/Function/L2Space.lean b/Mathlib/MeasureTheory/Function/L2Space.lean index b880a7b3dba5c..438e79a41953e 100644 --- a/Mathlib/MeasureTheory/Function/L2Space.lean +++ b/Mathlib/MeasureTheory/Function/L2Space.lean @@ -280,7 +280,7 @@ end L2 section InnerContinuous -variable {α : Type*} [TopologicalSpace α] [MeasureSpace α] [BorelSpace α] {𝕜 : Type*} [IsROrC 𝕜] +variable {α : Type*} [TopologicalSpace α] [MeasurableSpace α] [BorelSpace α] {𝕜 : Type*} [IsROrC 𝕜] variable (μ : Measure α) [IsFiniteMeasure μ] diff --git a/Mathlib/MeasureTheory/Function/SimpleFunc.lean b/Mathlib/MeasureTheory/Function/SimpleFunc.lean index d23675b8bdeb5..b0bb65acb19e3 100644 --- a/Mathlib/MeasureTheory/Function/SimpleFunc.lean +++ b/Mathlib/MeasureTheory/Function/SimpleFunc.lean @@ -4,8 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Johannes Hölzl -/ import Mathlib.MeasureTheory.Constructions.BorelSpace.Basic -import Mathlib.Algebra.IndicatorFunction -import Mathlib.Algebra.Support #align_import measure_theory.function.simple_func from "leanprover-community/mathlib"@"bf6a01357ff5684b1ebcd0f1a13be314fc82c0bf" diff --git a/Mathlib/MeasureTheory/Function/UniformIntegrable.lean b/Mathlib/MeasureTheory/Function/UniformIntegrable.lean index e7146ef9d7b02..59a49dfd3cc87 100644 --- a/Mathlib/MeasureTheory/Function/UniformIntegrable.lean +++ b/Mathlib/MeasureTheory/Function/UniformIntegrable.lean @@ -926,7 +926,7 @@ theorem uniformIntegrable_average · exact (Finset.aestronglyMeasurable_sum' _ fun i _ => hf₁ i).const_smul _ · obtain ⟨δ, hδ₁, hδ₂⟩ := hf₂ hε refine' ⟨δ, hδ₁, fun n s hs hle => _⟩ - simp_rw [Finset.smul_sum, Set.indicator_finset_sum] + simp_rw [Finset.smul_sum, Finset.indicator_sum] refine' le_trans (snorm_sum_le (fun i _ => ((hf₁ i).const_smul _).indicator hs) hp) _ have : ∀ i, s.indicator ((n : ℝ) ⁻¹ • f i) = (↑n : ℝ)⁻¹ • s.indicator (f i) := fun i ↦ indicator_const_smul _ _ _ diff --git a/Mathlib/MeasureTheory/Integral/Marginal.lean b/Mathlib/MeasureTheory/Integral/Marginal.lean index 8ed430fb7a7f8..6568cf9f2ea25 100644 --- a/Mathlib/MeasureTheory/Integral/Marginal.lean +++ b/Mathlib/MeasureTheory/Integral/Marginal.lean @@ -103,9 +103,7 @@ theorem _root_.Measurable.lmarginal (hf : Measurable f) : Measurable (∫⋯∫ /-- The marginal distribution is independent of the variables in `s`. -/ theorem lmarginal_congr {x y : ∀ i, π i} (f : (∀ i, π i) → ℝ≥0∞) - -- TODO: change back from `∀ i, i ∉ s →` to `∀ i ∉ s,` after bumping past - -- https://github.com/leanprover/std4/pull/427 - (h : ∀ i, i ∉ s → x i = y i) : + (h : ∀ i ∉ s, x i = y i) : (∫⋯∫⁻_s, f ∂μ) x = (∫⋯∫⁻_s, f ∂μ) y := by dsimp [lmarginal, updateFinset_def]; rcongr; exact h _ ‹_› diff --git a/Mathlib/MeasureTheory/Integral/Pi.lean b/Mathlib/MeasureTheory/Integral/Pi.lean index c55904596ab46..4640804bcc361 100644 --- a/Mathlib/MeasureTheory/Integral/Pi.lean +++ b/Mathlib/MeasureTheory/Integral/Pi.lean @@ -12,38 +12,40 @@ import Mathlib.MeasureTheory.Constructions.Prod.Integral open BigOperators Fintype MeasureTheory MeasureTheory.Measure -theorem MeasureTheory.integral_finset_prod_eq_prod' {E : Type*} {n : ℕ} (f : (Fin n) → E → ℝ) - [MeasureSpace E] [SigmaFinite (volume : Measure E)] : - ∫ x : (Fin n) → E, ∏ i, f i (x i) = ∏ i, ∫ x, f i x := by +variable {𝕜 : Type*} [IsROrC 𝕜] + +/-- A version of **Fubini's theorem** in `n` variables, for a natural number `n`. -/ +theorem MeasureTheory.integral_fin_nat_prod_eq_prod {n : ℕ} {E : Fin n → Type*} + [∀ i, MeasureSpace (E i)] [∀ i, SigmaFinite (volume : Measure (E i))] + (f : (i : Fin n) → E i → 𝕜) : + ∫ x : (i : Fin n) → E i, ∏ i, f i (x i) = ∏ i, ∫ x, f i x := by induction n with | zero => simp only [Nat.zero_eq, volume_pi, Finset.univ_eq_empty, Finset.prod_empty, integral_const, - pi_empty_univ, ENNReal.one_toReal, smul_eq_mul, mul_one, pow_zero] + pi_empty_univ, ENNReal.one_toReal, smul_eq_mul, mul_one, pow_zero, one_smul] | succ n n_ih => calc - _ = ∫ x : E × (Fin n → E), f 0 x.1 * ∏ i : Fin n, f (Fin.succ i) (x.2 i) := by + _ = ∫ x : E 0 × ((i : Fin n) → E (Fin.succ i)), + f 0 x.1 * ∏ i : Fin n, f (Fin.succ i) (x.2 i) := by rw [volume_pi, ← ((measurePreserving_piFinSuccAboveEquiv - (fun _ => (volume : Measure E)) 0).symm).integral_comp'] - simp_rw [MeasurableEquiv.piFinSuccAboveEquiv_symm_apply, Fin.insertNth_zero', - Fin.prod_univ_succ, Fin.cons_zero, Fin.cons_succ] + (fun i => (volume : Measure (E i))) 0).symm).integral_comp'] + simp_rw [MeasurableEquiv.piFinSuccAboveEquiv_symm_apply, + Fin.prod_univ_succ, Fin.insertNth_zero, Fin.cons_succ] rfl - _ = (∫ x, f 0 x) * ∏ i : Fin n, ∫ (x : E), f (Fin.succ i) x := by + _ = (∫ x, f 0 x) * ∏ i : Fin n, ∫ (x : E (Fin.succ i)), f (Fin.succ i) x := by rw [← n_ih, ← integral_prod_mul, volume_eq_prod] _ = ∏ i, ∫ x, f i x := by rw [Fin.prod_univ_succ] -theorem MeasureTheory.integral_finset_prod_eq_prod {E : Type*} (ι : Type*) [Fintype ι] - (f : ι → E → ℝ) [MeasureSpace E] [SigmaFinite (volume : Measure E)] : - ∫ x : ι → E, ∏ i, f i (x i) = ∏ i, ∫ x, f i x := by - let e := (equivFin ι) - let p := measurePreserving_piCongrLeft (fun _ => (volume : Measure E)) e - rw [volume_pi, ← (p.symm).integral_comp', Fintype.prod_equiv e _ (fun j => ∫ x, f (e.symm j) x) - (fun _ => by simp_rw [e.symm_apply_apply]), ← integral_finset_prod_eq_prod' - (fun j => f (e.symm j))] - congr! - rw [Fintype.prod_equiv e] - exact fun _ => by simp [Equiv.symm_apply_apply]; rfl +/-- A version of **Fubini's theorem** with the variables indexed by a general finite type. -/ +theorem MeasureTheory.integral_fintype_prod_eq_prod (ι : Type*) [Fintype ι] {E : ι → Type*} + (f : (i : ι) → E i → 𝕜) [∀ i, MeasureSpace (E i)] [∀ i, SigmaFinite (volume : Measure (E i))] : + ∫ x : (i : ι) → E i, ∏ i, f i (x i) = ∏ i, ∫ x, f i x := by + let e := (equivFin ι).symm + rw [← (volume_measurePreserving_piCongrLeft _ e).integral_comp'] + simp_rw [← e.prod_comp, MeasurableEquiv.coe_piCongrLeft, Equiv.piCongrLeft_apply_apply, + MeasureTheory.integral_fin_nat_prod_eq_prod] -theorem MeasureTheory.integral_finset_prod_eq_pow {E : Type*} (ι : Type*) [Fintype ι] (f : E → ℝ) +theorem MeasureTheory.integral_fintype_prod_eq_pow {E : Type*} (ι : Type*) [Fintype ι] (f : E → 𝕜) [MeasureSpace E] [SigmaFinite (volume : Measure E)] : ∫ x : ι → E, ∏ i, f (x i) = (∫ x, f x) ^ (card ι) := by - rw [integral_finset_prod_eq_prod, Finset.prod_const, Fintype.card] + rw [integral_fintype_prod_eq_prod, Finset.prod_const, card] diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean b/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean index 2b29d7e2d7887..d90b5ac09382e 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean @@ -3,7 +3,6 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro -/ -import Mathlib.Algebra.IndicatorFunction import Mathlib.Data.Finset.Update import Mathlib.Data.Prod.TProd import Mathlib.GroupTheory.Coset @@ -1142,7 +1141,7 @@ instance Sigma.instMeasurableSpace {α} {β : α → Type*} [m : ∀ a, Measurab #align sigma.measurable_space Sigma.instMeasurableSpace section prop -variable [MeasurableSpace α] {p : α → Prop} +variable [MeasurableSpace α] {p q : α → Prop} @[simp] theorem measurableSet_setOf : MeasurableSet {a | p a} ↔ Measurable p := ⟨fun h ↦ measurable_to_prop <| by simpa only [preimage_singleton_true], fun h => by @@ -1158,7 +1157,62 @@ alias ⟨_, Measurable.setOf⟩ := measurableSet_setOf alias ⟨_, MeasurableSet.mem⟩ := measurable_mem #align measurable_set.mem MeasurableSet.mem +lemma Measurable.not (hp : Measurable p) : Measurable (¬ p ·) := + measurableSet_setOf.1 hp.setOf.compl + +lemma Measurable.and (hp : Measurable p) (hq : Measurable q) : Measurable fun a ↦ p a ∧ q a := + measurableSet_setOf.1 <| hp.setOf.inter hq.setOf + +lemma Measurable.or (hp : Measurable p) (hq : Measurable q) : Measurable fun a ↦ p a ∨ q a := + measurableSet_setOf.1 <| hp.setOf.union hq.setOf + +lemma Measurable.imp (hp : Measurable p) (hq : Measurable q) : Measurable fun a ↦ p a → q a := + measurableSet_setOf.1 <| hp.setOf.himp hq.setOf + +lemma Measurable.iff (hp : Measurable p) (hq : Measurable q) : Measurable fun a ↦ p a ↔ q a := + measurableSet_setOf.1 <| by simp_rw [iff_iff_implies_and_implies]; exact hq.setOf.bihimp hp.setOf + +lemma Measurable.forall [Countable ι] {p : ι → α → Prop} (hp : ∀ i, Measurable (p i)) : + Measurable fun a ↦ ∀ i, p i a := + measurableSet_setOf.1 <| by rw [setOf_forall]; exact MeasurableSet.iInter fun i ↦ (hp i).setOf + +lemma Measurable.exists [Countable ι] {p : ι → α → Prop} (hp : ∀ i, Measurable (p i)) : + Measurable fun a ↦ ∃ i, p i a := + measurableSet_setOf.1 <| by rw [setOf_exists]; exact MeasurableSet.iUnion fun i ↦ (hp i).setOf + end prop + +section Set +variable [MeasurableSpace β] {g : β → Set α} + +/-- This instance is useful when talking about Bernoulli sequences of random variables or binomial +random graphs. -/ +instance Set.instMeasurableSpace : MeasurableSpace (Set α) := by unfold Set; infer_instance + +instance Set.instMeasurableSingletonClass [Countable α] : MeasurableSingletonClass (Set α) := by + unfold Set; infer_instance + +lemma measurable_set_iff : Measurable g ↔ ∀ a, Measurable fun x ↦ a ∈ g x := measurable_pi_iff + +@[aesop safe 100 apply (rule_sets [Measurable])] +lemma measurable_set_mem (a : α) : Measurable fun s : Set α ↦ a ∈ s := measurable_pi_apply _ + +@[aesop safe 100 apply (rule_sets [Measurable])] +lemma measurable_set_not_mem (a : α) : Measurable fun s : Set α ↦ a ∉ s := + (measurable_discrete Not).comp $ measurable_set_mem a + +@[aesop safe 100 apply (rule_sets [Measurable])] +lemma measurableSet_mem (a : α) : MeasurableSet {s : Set α | a ∈ s} := + measurableSet_setOf.2 $ measurable_set_mem _ + +@[aesop safe 100 apply (rule_sets [Measurable])] +lemma measurableSet_not_mem (a : α) : MeasurableSet {s : Set α | a ∉ s} := + measurableSet_setOf.2 $ measurable_set_not_mem _ + +lemma measurable_compl : Measurable ((·ᶜ) : Set α → Set α) := + measurable_set_iff.2 fun _ ↦ measurable_set_not_mem _ + +end Set end Constructions namespace MeasurableSpace diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Defs.lean b/Mathlib/MeasureTheory/MeasurableSpace/Defs.lean index 4f4a719eabb26..d44779419111a 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/Defs.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/Defs.lean @@ -207,12 +207,20 @@ protected theorem MeasurableSet.diff {s₁ s₂ : Set α} (h₁ : MeasurableSet h₁.inter h₂.compl #align measurable_set.diff MeasurableSet.diff +@[simp, measurability] +protected lemma MeasurableSet.himp {s₁ s₂ : Set α} (h₁ : MeasurableSet s₁) (h₂ : MeasurableSet s₂) : + MeasurableSet (s₁ ⇨ s₂) := by rw [himp_eq]; exact h₂.union h₁.compl + @[simp, measurability] protected theorem MeasurableSet.symmDiff {s₁ s₂ : Set α} (h₁ : MeasurableSet s₁) (h₂ : MeasurableSet s₂) : MeasurableSet (s₁ ∆ s₂) := (h₁.diff h₂).union (h₂.diff h₁) #align measurable_set.symm_diff MeasurableSet.symmDiff +@[simp, measurability] +protected lemma MeasurableSet.bihimp {s₁ s₂ : Set α} (h₁ : MeasurableSet s₁) + (h₂ : MeasurableSet s₂) : MeasurableSet (s₁ ⇔ s₂) := (h₂.himp h₁).inter (h₁.himp h₂) + @[simp, measurability] protected theorem MeasurableSet.ite {t s₁ s₂ : Set α} (ht : MeasurableSet t) (h₁ : MeasurableSet s₁) (h₂ : MeasurableSet s₂) : MeasurableSet (t.ite s₁ s₂) := diff --git a/Mathlib/MeasureTheory/Measure/Lebesgue/VolumeOfBalls.lean b/Mathlib/MeasureTheory/Measure/Lebesgue/VolumeOfBalls.lean index b54551595ef01..722ea369f324d 100644 --- a/Mathlib/MeasureTheory/Measure/Lebesgue/VolumeOfBalls.lean +++ b/Mathlib/MeasureTheory/Measure/Lebesgue/VolumeOfBalls.lean @@ -190,7 +190,7 @@ theorem MeasureTheory.volume_sum_rpow_lt_one : exact Finset.sum_nonneg' (fun _ => rpow_nonneg_of_nonneg (abs_nonneg _) _) · simp_rw [← rpow_mul (h₂ _), div_mul_cancel _ (ne_of_gt h₁), Real.rpow_one, ← Finset.sum_neg_distrib, exp_sum] - rw [integral_finset_prod_eq_pow ι fun x : ℝ => exp (- |x| ^ p), integral_comp_abs + rw [integral_fintype_prod_eq_pow ι fun x : ℝ => exp (- |x| ^ p), integral_comp_abs (f := fun x => exp (- x ^ p)), integral_exp_neg_rpow h₁] · rw [finrank_fintype_fun_eq_card] @@ -264,7 +264,7 @@ theorem Complex.volume_sum_rpow_lt_one {p : ℝ} (hp : 1 ≤ p) : exact Finset.sum_nonneg' (fun _ => rpow_nonneg_of_nonneg (norm_nonneg _) _) · simp_rw [← rpow_mul (h₂ _), div_mul_cancel _ (ne_of_gt h₁), Real.rpow_one, ← Finset.sum_neg_distrib, Real.exp_sum] - rw [integral_finset_prod_eq_pow ι fun x : ℂ => Real.exp (- ‖x‖ ^ p), + rw [integral_fintype_prod_eq_pow ι fun x : ℂ => Real.exp (- ‖x‖ ^ p), Complex.integral_exp_neg_rpow hp] · rw [finrank_pi_fintype, Complex.finrank_real_complex, Finset.sum_const, smul_eq_mul, Nat.cast_mul, Nat.cast_ofNat, Fintype.card, mul_comm] diff --git a/Mathlib/NumberTheory/Divisors.lean b/Mathlib/NumberTheory/Divisors.lean index 55c241255ab9b..9f85d351a8bdd 100644 --- a/Mathlib/NumberTheory/Divisors.lean +++ b/Mathlib/NumberTheory/Divisors.lean @@ -445,9 +445,8 @@ theorem mem_properDivisors_prime_pow {p : ℕ} (pp : p.Prime) (k : ℕ) {x : ℕ simp [h_left, le_of_lt] #align nat.mem_proper_divisors_prime_pow Nat.mem_properDivisors_prime_pow --- Porting note: Specified pow to Nat.pow theorem properDivisors_prime_pow {p : ℕ} (pp : p.Prime) (k : ℕ) : - properDivisors (p ^ k) = (Finset.range k).map ⟨Nat.pow p, pow_right_injective pp.two_le⟩ := by + properDivisors (p ^ k) = (Finset.range k).map ⟨HPow.hPow p, pow_right_injective pp.two_le⟩ := by ext a simp only [mem_properDivisors, Nat.isUnit_iff, mem_map, mem_range, Function.Embedding.coeFn_mk, pow_eq] diff --git a/Mathlib/NumberTheory/NumberField/CanonicalEmbedding.lean b/Mathlib/NumberTheory/NumberField/CanonicalEmbedding.lean index efa124321229e..62d0862730210 100644 --- a/Mathlib/NumberTheory/NumberField/CanonicalEmbedding.lean +++ b/Mathlib/NumberTheory/NumberField/CanonicalEmbedding.lean @@ -3,11 +3,11 @@ Copyright (c) 2022 Xavier Roblot. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Xavier Roblot -/ -import Mathlib.RingTheory.Discriminant import Mathlib.Algebra.Module.Zlattice import Mathlib.MeasureTheory.Group.GeometryOfNumbers import Mathlib.MeasureTheory.Measure.Lebesgue.VolumeOfBalls import Mathlib.NumberTheory.NumberField.Embeddings +import Mathlib.RingTheory.Discriminant #align_import number_theory.number_field.canonical_embedding from "leanprover-community/mathlib"@"60da01b41bbe4206f05d34fd70c8dd7498717a30" @@ -464,6 +464,13 @@ variable [NumberField K] instance : IsAddHaarMeasure (volume : Measure (E K)) := prod.instIsAddHaarMeasure volume volume +instance : NoAtoms (volume : Measure (E K)) := by + obtain ⟨w⟩ := (inferInstance : Nonempty (InfinitePlace K)) + by_cases hw : IsReal w + exact @prod.instNoAtoms_fst _ _ _ _ volume volume _ (pi_noAtoms ⟨w, hw⟩) + · exact @prod.instNoAtoms_snd _ _ _ _ volume volume _ + (pi_noAtoms ⟨w, not_isReal_iff_isComplex.mp hw⟩) + /-- The fudge factor that appears in the formula for the volume of `convexBodyLT`. -/ noncomputable abbrev convexBodyLTFactor : ℝ≥0∞ := (2 : ℝ≥0∞) ^ NrRealPlaces K * (NNReal.pi : ℝ≥0∞) ^ NrComplexPlaces K @@ -524,50 +531,199 @@ section convexBodySum open ENNReal BigOperators Classical MeasureTheory Fintype +open scoped Real + variable [NumberField K] (B : ℝ) +variable {K} + +/-- The function that sends `x : ({w // IsReal w} → ℝ) × ({w // IsComplex w} → ℂ)` to + `∑ w, ‖x.1 w‖ + 2 * ∑ w, ‖x.2 w‖`. It defines a norm and it used to define `convexBodySum`. -/ +noncomputable abbrev convexBodySumFun (x : E K) : ℝ := ∑ w, ‖x.1 w‖ + 2 * ∑ w, ‖x.2 w‖ + +theorem convexBodySumFun_nonneg (x : E K) : + 0 ≤ convexBodySumFun x := by + refine add_nonneg ?_ ?_ + · exact Finset.sum_nonneg (fun _ _ => norm_nonneg _) + · exact mul_nonneg zero_le_two (Finset.sum_nonneg (fun _ _ => norm_nonneg _)) + +theorem convexBodySumFun_neg (x : E K) : + convexBodySumFun (- x) = convexBodySumFun x := by + simp_rw [convexBodySumFun, Prod.fst_neg, Prod.snd_neg, Pi.neg_apply, norm_neg] + +theorem convexBodySumFun_add_le (x y : E K) : + convexBodySumFun (x + y) ≤ convexBodySumFun x + convexBodySumFun y := by + simp_rw [convexBodySumFun, Prod.fst_add, Pi.add_apply, Prod.snd_add] + refine le_trans (add_le_add + (Finset.sum_le_sum (fun w _ => norm_add_le (x.1 w) (y.1 w))) + (mul_le_mul_of_nonneg_left + (Finset.sum_le_sum (fun w _ => norm_add_le (x.2 w) (y.2 w))) (by norm_num))) ?_ + simp_rw [Finset.sum_add_distrib, mul_add] + exact le_of_eq (by ring) + +theorem convexBodySumFun_smul (c : ℝ) (x : E K) : + convexBodySumFun (c • x) = |c| * convexBodySumFun x := by + simp_rw [convexBodySumFun, Prod.smul_fst, Prod.smul_snd, Pi.smul_apply, smul_eq_mul, + Complex.real_smul, norm_mul, Complex.norm_real, ← Finset.mul_sum, Real.norm_eq_abs] + ring + +theorem convexBodySumFun_eq_zero_iff (x : E K) : + convexBodySumFun x = 0 ↔ x = 0 := by + refine ⟨fun h => ?_, fun h => ?_⟩ + · rw [add_eq_zero_iff' (Finset.sum_nonneg fun _ _ => norm_nonneg _) (mul_nonneg zero_le_two + (Finset.sum_nonneg fun _ _ => norm_nonneg _)), Finset.mul_sum, + Finset.sum_eq_zero_iff_of_nonneg (fun _ _ => mul_nonneg zero_le_two (norm_nonneg _)), + Finset.sum_eq_zero_iff_of_nonneg (fun _ _ => norm_nonneg _)] at h + ext : 2 + · exact norm_eq_zero.mp (h.1 _ (Finset.mem_univ _)) + · exact norm_eq_zero.mp ((smul_eq_zero_iff_eq' two_ne_zero (α := ℝ)).mp + (h.2 _ (Finset.mem_univ _))) + · simp only [convexBodySumFun, h, Prod.fst_zero, Pi.zero_apply, norm_zero, Finset.sum_const_zero, + Prod.snd_zero, mul_zero, add_zero] + +theorem norm_le_convexBodySumFun (x : E K) : ‖x‖ ≤ convexBodySumFun x := by + refine max_le ?_ ?_ + · refine (pi_norm_le_iff_of_nonneg (convexBodySumFun_nonneg x)).mpr (fun w => ?_) + refine le_add_of_le_of_nonneg ?_ ?_ + · exact Finset.single_le_sum (fun z _ => norm_nonneg (x.1 z)) (Finset.mem_univ w) + · exact mul_nonneg zero_le_two <| Finset.sum_nonneg (fun w _ => norm_nonneg (x.2 w)) + · refine (pi_norm_le_iff_of_nonneg (convexBodySumFun_nonneg x)).mpr (fun w => ?_) + refine le_add_of_nonneg_of_le ?_ ?_ + · exact Finset.sum_nonneg (fun w _ => norm_nonneg (x.1 w)) + · rw [Finset.mul_sum] + refine le_trans (by linarith [norm_nonneg (x.2 w)] : ‖x.2 w‖ ≤ 2 * ‖x.2 w‖) ?_ + exact Finset.single_le_sum (fun z _ => mul_nonneg zero_le_two (norm_nonneg (x.2 z))) + (Finset.mem_univ w) + +variable (K) + +theorem convexBodySumFun_continuous : + Continuous (convexBodySumFun : (E K) → ℝ) := by + refine Continuous.add ?_ ?_ + · exact continuous_finset_sum Finset.univ + (fun i _ => continuous_norm.comp' (continuous_apply i).fst') + · refine Continuous.const_smul ?_ (2:ℝ) + exact continuous_finset_sum Finset.univ + (fun i _ => continuous_norm.comp' (continuous_apply i).snd') + /-- The convex body equal to the set of points `x : E` such that `∑ w real, ‖x w‖ + 2 * ∑ w complex, ‖x w‖ ≤ B`. -/ -abbrev convexBodySum : Set (E K) := { x | ∑ w, ‖x.1 w‖ + 2 * ∑ w, ‖x.2 w‖ ≤ B } - -theorem convexBodySum_empty {B} (h : B < 0) : convexBodySum K B = ∅ := by - ext x - refine ⟨fun hx => ?_, fun h => h.elim⟩ - · rw [Set.mem_setOf] at hx - have : 0 ≤ ∑ w, ‖x.1 w‖ + 2 * ∑ w, ‖x.2 w‖ := by - refine add_nonneg ?_ ?_ - · exact Finset.sum_nonneg (fun _ _ => norm_nonneg _) - · exact mul_nonneg zero_le_two (Finset.sum_nonneg (fun _ _ => norm_nonneg _)) - linarith +abbrev convexBodySum : Set (E K) := { x | convexBodySumFun x ≤ B } + +theorem convexBodySum_volume_eq_zero_of_le_zero {B} (hB : B ≤ 0) : + volume (convexBodySum K B) = 0 := by + obtain hB | hB := lt_or_eq_of_le hB + · suffices convexBodySum K B = ∅ by rw [this, measure_empty] + ext x + refine ⟨fun hx => ?_, fun h => h.elim⟩ + rw [Set.mem_setOf] at hx + linarith [convexBodySumFun_nonneg x] + · suffices convexBodySum K B = { 0 } by rw [this, measure_singleton] + ext + rw [convexBodySum, Set.mem_setOf_eq, Set.mem_singleton_iff, hB, ← convexBodySumFun_eq_zero_iff] + exact (convexBodySumFun_nonneg _).le_iff_eq theorem convexBodySum_mem {x : K} : mixedEmbedding K x ∈ (convexBodySum K B) ↔ ∑ w : InfinitePlace K, (mult w) * w.val x ≤ B := by - simp_rw [Set.mem_setOf_eq, mixedEmbedding, RingHom.prod_apply, Pi.ringHom_apply, + simp_rw [Set.mem_setOf_eq, mixedEmbedding, RingHom.prod_apply, convexBodySumFun, Pi.ringHom_apply, ← Complex.norm_real, embedding_of_isReal_apply, norm_embedding_eq, mult, Nat.cast_ite, ite_mul, Finset.sum_ite, Finset.filter_congr (fun _ _ => not_isReal_iff_isComplex), Finset.mul_sum, ← Finset.sum_subtype_eq_sum_filter, Finset.subtype_univ, Nat.cast_one, one_mul, Nat.cast_ofNat] rfl -theorem convexBodySum_symmetric (x : E K) (hx : x ∈ (convexBodySum K B)) : +theorem convexBodySum_symmetric {x : E K} (hx : x ∈ (convexBodySum K B)) : -x ∈ (convexBodySum K B) := by - simp_rw [Set.mem_setOf_eq, Prod.fst_neg, Prod.snd_neg, Pi.neg_apply, norm_neg] + rw [Set.mem_setOf, convexBodySumFun_neg] exact hx theorem convexBodySum_convex : Convex ℝ (convexBodySum K B) := by - refine Convex_subadditive_le ?_ ?_ B - · intro x y - simp_rw [Prod.fst_add, Pi.add_apply, Prod.snd_add] - refine le_trans (add_le_add - (Finset.sum_le_sum (fun w _ => norm_add_le (x.1 w) (y.1 w))) - (mul_le_mul_of_nonneg_left - (Finset.sum_le_sum (fun w _ => norm_add_le (x.2 w) (y.2 w))) (by norm_num))) ?_ - simp_rw [Finset.sum_add_distrib, mul_add] - exact le_of_eq (by ring) - · intro _ _ h - simp_rw [Prod.smul_fst, Prod.smul_snd, Pi.smul_apply, smul_eq_mul, Complex.real_smul, norm_mul, - Complex.norm_real, Real.norm_of_nonneg h, ← Finset.mul_sum] - exact le_of_eq (by ring) + refine Convex_subadditive_le (fun _ _ => convexBodySumFun_add_le _ _) (fun c x h => ?_) B + convert le_of_eq (convexBodySumFun_smul c x) + exact (abs_eq_self.mpr h).symm + +theorem convexBodySum_isBounded : Bornology.IsBounded (convexBodySum K B) := by + refine Metric.isBounded_iff.mpr ⟨B + B, fun x hx y hy => ?_⟩ + refine le_trans (norm_sub_le x y) (add_le_add ?_ ?_) + exact le_trans (norm_le_convexBodySumFun x) hx + exact le_trans (norm_le_convexBodySumFun y) hy + +theorem convexBodySum_compact : IsCompact (convexBodySum K B) := by + rw [Metric.isCompact_iff_isClosed_bounded] + refine ⟨?_, convexBodySum_isBounded K B⟩ + convert IsClosed.preimage (convexBodySumFun_continuous K) (isClosed_Icc : IsClosed (Set.Icc 0 B)) + ext + simp [convexBodySumFun_nonneg] + +/-- The fudge factor that appears in the formula for the volume of `convexBodyLt`. -/ +noncomputable abbrev convexBodySumFactor : ℝ≥0∞ := + (2:ℝ≥0∞) ^ NrRealPlaces K * (NNReal.pi / 2) ^ NrComplexPlaces K / (finrank ℚ K).factorial + +theorem convexBodySumFactor_ne_zero : convexBodySumFactor K ≠ 0 := by + dsimp [convexBodySumFactor] + refine mul_ne_zero (mul_ne_zero (pow_ne_zero _ two_ne_zero) ?_) ?_ + · refine ENNReal.pow_ne_zero ?_ _ + exact ne_of_gt <| div_pos_iff.mpr ⟨coe_ne_zero.mpr NNReal.pi_ne_zero, two_ne_top⟩ + · exact ENNReal.inv_ne_zero.mpr (nat_ne_top _) + +theorem convexBodySumFactor_ne_top : convexBodySumFactor K ≠ ⊤ := by + refine mul_ne_top (mul_ne_top (pow_ne_top two_ne_top) ?_) ?_ + · rw [show (2:ℝ≥0∞) = (2:NNReal) by rfl, ← ENNReal.coe_div two_ne_zero] + exact pow_ne_top coe_ne_top + · exact inv_ne_top.mpr <| Nat.cast_ne_zero.mpr (Nat.factorial_ne_zero _) + +open MeasureTheory MeasureTheory.Measure Real in +theorem convexBodySum_volume : + volume (convexBodySum K B) = (convexBodySumFactor K) * (.ofReal B) ^ (finrank ℚ K) := by + obtain hB | hB := le_or_lt B 0 + · rw [convexBodySum_volume_eq_zero_of_le_zero K hB, ofReal_eq_zero.mpr hB, zero_pow, mul_zero] + exact finrank_pos + · suffices volume (convexBodySum K 1) = (convexBodySumFactor K) by + rw [mul_comm] + convert addHaar_smul volume B (convexBodySum K 1) + · simp_rw [← Set.preimage_smul_inv₀ (ne_of_gt hB), Set.preimage_setOf_eq, convexBodySumFun, + Prod.smul_fst, Prod.smul_snd, Pi.smul_apply, Complex.real_smul, smul_eq_mul, norm_mul, + Complex.ofReal_inv, norm_inv, norm_eq_abs B, Complex.norm_eq_abs B, Complex.abs_ofReal, + abs_eq_self.mpr (le_of_lt hB), ← Finset.mul_sum, ← mul_assoc, mul_comm (2:ℝ), mul_assoc, + ← mul_add, inv_mul_le_iff hB, mul_one] + · rw [abs_pow, ofReal_pow (abs_nonneg _), abs_eq_self.mpr (le_of_lt hB), + mixedEmbedding.finrank] + · exact this.symm + rw [MeasureTheory.measure_le_eq_lt _ ((convexBodySumFun_eq_zero_iff 0).mpr rfl) + convexBodySumFun_neg convexBodySumFun_add_le + (fun hx => (convexBodySumFun_eq_zero_iff _).mp hx) + (fun r x => le_of_eq (convexBodySumFun_smul r x))] + rw [measure_lt_one_eq_integral_div_gamma (g := fun x : (E K) => convexBodySumFun x) + volume ((convexBodySumFun_eq_zero_iff 0).mpr rfl) convexBodySumFun_neg convexBodySumFun_add_le + (fun hx => (convexBodySumFun_eq_zero_iff _).mp hx) + (fun r x => le_of_eq (convexBodySumFun_smul r x)) zero_lt_one] + simp_rw [mixedEmbedding.finrank, div_one, Gamma_nat_eq_factorial, ofReal_div_of_pos + (Nat.cast_pos.mpr (Nat.factorial_pos _)), Real.rpow_one, ofReal_coe_nat] + suffices ∫ x : E K, exp (-convexBodySumFun x) = + (2:ℝ) ^ NrRealPlaces K * (π / 2) ^ NrComplexPlaces K by + rw [this, convexBodySumFactor, ofReal_mul (by positivity), ofReal_pow zero_le_two, + ofReal_pow (by positivity), ofReal_div_of_pos zero_lt_two, ofReal_ofNat, + ← NNReal.coe_real_pi, ofReal_coe_nnreal] + calc + _ = (∫ x : {w : InfinitePlace K // IsReal w} → ℝ, ∏ w, exp (- ‖x w‖)) * + (∫ x : {w : InfinitePlace K // IsComplex w} → ℂ, ∏ w, exp (- 2 * ‖x w‖)) := by + simp_rw [convexBodySumFun, neg_add, ← neg_mul, Finset.mul_sum, ← Finset.sum_neg_distrib, + exp_add, exp_sum, ← integral_prod_mul, volume_eq_prod] + _ = (∫ x : ℝ, exp (-|x|)) ^ NrRealPlaces K * + (∫ x : ℂ, Real.exp (-2 * ‖x‖)) ^ NrComplexPlaces K := by + rw [integral_fintype_prod_eq_pow _ (fun x => exp (- ‖x‖)), integral_fintype_prod_eq_pow _ + (fun x => exp (- 2 * ‖x‖))] + simp_rw [norm_eq_abs] + _ = (2 * Gamma (1 / 1 + 1)) ^ NrRealPlaces K * + (π * (2:ℝ) ^ (-(2:ℝ) / 1) * Gamma (2 / 1 + 1)) ^ NrComplexPlaces K := by + rw [integral_comp_abs (f := fun x => exp (- x)), ← integral_exp_neg_rpow zero_lt_one, + ← Complex.integral_exp_neg_mul_rpow le_rfl zero_lt_two] + simp_rw [Real.rpow_one] + _ = (2:ℝ) ^ NrRealPlaces K * (π / 2) ^ NrComplexPlaces K := by + simp_rw [div_one, one_add_one_eq_two, Gamma_add_one two_ne_zero, Gamma_two, mul_one, + mul_assoc, ← Real.rpow_add_one two_ne_zero, show (-2:ℝ) + 1 = -1 by norm_num, + Real.rpow_neg_one] + rfl end convexBodySum @@ -591,9 +747,12 @@ theorem minkowskiBound_lt_top : minkowskiBound K < ⊤ := by · exact ne_of_lt (fundamentalDomain_isBounded (latticeBasis K)).measure_lt_top · exact ne_of_lt (ENNReal.pow_lt_top (lt_top_iff_ne_top.mpr ENNReal.two_ne_top) _) -variable {f : InfinitePlace K → ℝ≥0} +theorem minkowskiBound_pos : 0 < minkowskiBound K := by + refine zero_lt_iff.mpr (mul_ne_zero ?_ ?_) + · exact Zspan.measure_fundamentalDomain_ne_zero (latticeBasis K) + · exact ENNReal.pow_ne_zero two_ne_zero _ -instance : IsAddHaarMeasure (volume : Measure (E K)) := prod.instIsAddHaarMeasure volume volume +variable {f : InfinitePlace K → ℝ≥0} /-- Assume that `f : InfinitePlace K → ℝ≥0` is such that `minkowskiBound K < volume (convexBodyLT K f)` where `convexBodyLT K f` is the set of @@ -615,12 +774,12 @@ theorem exists_ne_zero_mem_ringOfIntegers_lt (h : minkowskiBound K < volume (con exact Subtype.ne_of_val_ne h_nzr theorem exists_ne_zero_mem_ringOfIntegers_of_norm_le {B : ℝ} - (h : (minkowskiBound K) < volume (convexBodySum K B)) : + (h : (minkowskiBound K) ≤ volume (convexBodySum K B)) : ∃ (a : 𝓞 K), a ≠ 0 ∧ |Algebra.norm ℚ (a:K)| ≤ (B / (finrank ℚ K)) ^ (finrank ℚ K) := by have hB : 0 ≤ B := by contrapose! h - rw [convexBodySum_empty K h, measure_empty] - exact zero_le (minkowskiBound K) + rw [convexBodySum_volume_eq_zero_of_le_zero K (le_of_lt h)] + exact minkowskiBound_pos K -- Some inequalities that will be useful later on have h1 : 0 < (finrank ℚ K : ℝ)⁻¹ := inv_pos.mpr (Nat.cast_pos.mpr finrank_pos) have h2 : 0 ≤ B / (finrank ℚ K) := div_nonneg hB (Nat.cast_nonneg _) @@ -628,8 +787,12 @@ theorem exists_ne_zero_mem_ringOfIntegers_of_norm_le {B : ℝ} have : Countable (Submodule.span ℤ (Set.range (latticeBasis K))).toAddSubgroup := by change Countable (Submodule.span ℤ (Set.range (latticeBasis K)): Set (E K)) infer_instance - obtain ⟨⟨x, hx⟩, h_nzr, h_mem⟩ := exists_ne_zero_mem_lattice_of_measure_mul_two_pow_lt_measure - h_fund (convexBodySum_symmetric K B) (convexBodySum_convex K B) h + have : DiscreteTopology (Submodule.span ℤ (Set.range (latticeBasis K))).toAddSubgroup := by + change DiscreteTopology (Submodule.span ℤ (Set.range (latticeBasis K)): Set (E K)) + infer_instance + obtain ⟨⟨x, hx⟩, h_nzr, h_mem⟩ := exists_ne_zero_mem_lattice_of_measure_mul_two_pow_le_measure + h_fund (fun _ ↦ convexBodySum_symmetric K B) (convexBodySum_convex K B) + (convexBodySum_compact K B) h rw [Submodule.mem_toAddSubgroup, mem_span_latticeBasis] at hx obtain ⟨a, ha, rfl⟩ := hx refine ⟨⟨a, ha⟩, ?_, ?_⟩ diff --git a/Mathlib/NumberTheory/NumberField/Discriminant.lean b/Mathlib/NumberTheory/NumberField/Discriminant.lean index 70cdaf6747c82..8a5cec7b1b634 100644 --- a/Mathlib/NumberTheory/NumberField/Discriminant.lean +++ b/Mathlib/NumberTheory/NumberField/Discriminant.lean @@ -3,15 +3,22 @@ Copyright (c) 2023 Xavier Roblot. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Xavier Roblot -/ +import Mathlib.Data.Real.Pi.Bounds import Mathlib.NumberTheory.NumberField.CanonicalEmbedding -import Mathlib.RingTheory.Localization.NormTrace +import Mathlib.NumberTheory.NumberField.Norm /-! # Number field discriminant This file defines the discriminant of a number field. ## Main definitions - - `discr` the absolute discriminant of a number field. + +* `NumberField.discr`: the absolute discriminant of a number field. + +## Main result + +* `NumberField.discr_gt_one`: **Hermite-Minkowski Theorem**. A nontrivial number field has +nontrivial discriminant. ## Tags number field, discriminant @@ -22,7 +29,9 @@ number field, discriminant namespace NumberField -open Classical NumberField Matrix NumberField.InfinitePlace +open Classical NumberField Matrix NumberField.InfinitePlace FiniteDimensional + +open scoped Real variable (K : Type*) [Field K] [NumberField K] @@ -43,7 +52,7 @@ theorem discr_eq_discr {ι : Type*} [Fintype ι] [DecidableEq ι] (b : Basis ι theorem discr_eq_discr_of_algEquiv {L : Type*} [Field L] [NumberField L] (f : K ≃ₐ[ℚ] L) : discr K = discr L := by - let f₀ : 𝓞 K ≃ₗ[ℤ] 𝓞 L := (integralClosure_algEquiv_restrict (f.restrictScalars ℤ)).toLinearEquiv + let f₀ : 𝓞 K ≃ₗ[ℤ] 𝓞 L := (f.restrictScalars ℤ).mapIntegralClosure.toLinearEquiv let e : Module.Free.ChooseBasisIndex ℤ (𝓞 K) ≃ (K →ₐ[ℚ] ℂ) := by refine Fintype.equivOfCardEq ?_ rw [← FiniteDimensional.finrank_eq_card_chooseBasisIndex, RingOfIntegers.rank, AlgHom.card] @@ -62,7 +71,7 @@ open MeasureTheory MeasureTheory.Measure Zspan NumberField.mixedEmbedding theorem _root_.NumberField.mixedEmbedding.volume_fundamentalDomain_latticeBasis : volume (fundamentalDomain (latticeBasis K)) = - (2 : ℝ≥0∞)⁻¹ ^ (NrComplexPlaces K) * sqrt ‖discr K‖₊ := by + (2 : ℝ≥0∞)⁻¹ ^ NrComplexPlaces K * sqrt ‖discr K‖₊ := by let f : Module.Free.ChooseBasisIndex ℤ (𝓞 K) ≃ (K →+* ℂ) := (canonicalEmbedding.latticeBasis K).indexEquiv (Pi.basisFun ℂ _) let e : (index K) ≃ Module.Free.ChooseBasisIndex ℤ (𝓞 K) := (indexEquiv K).trans f.symm @@ -94,6 +103,109 @@ theorem _root_.NumberField.mixedEmbedding.volume_fundamentalDomain_latticeBasis stdBasis_repr_eq_matrixToStdBasis_mul K _ (fun _ => rfl)] rfl +theorem exists_ne_zero_mem_ringOfIntegers_of_norm_le_mul_sqrt_discr : + ∃ (a : 𝓞 K), a ≠ 0 ∧ + |Algebra.norm ℚ (a:K)| ≤ (4 / π) ^ NrComplexPlaces K * + (finrank ℚ K).factorial / (finrank ℚ K) ^ (finrank ℚ K) * Real.sqrt |discr K| := by + -- The smallest possible value for `exists_ne_zero_mem_ringOfIntegers_of_norm_le` + let B := (minkowskiBound K * (convexBodySumFactor K)⁻¹).toReal ^ (1 / (finrank ℚ K : ℝ)) + have hB : 0 ≤ B := Real.rpow_nonneg_of_nonneg toReal_nonneg _ + have h_le : (minkowskiBound K) ≤ volume (convexBodySum K B) := by + refine le_of_eq ?_ + rw [convexBodySum_volume, ← ENNReal.ofReal_pow hB, ← Real.rpow_nat_cast, ← Real.rpow_mul + toReal_nonneg, div_mul_cancel _ (Nat.cast_ne_zero.mpr (ne_of_gt finrank_pos)), Real.rpow_one, + ofReal_toReal, mul_comm, mul_assoc, ENNReal.inv_mul_cancel (convexBodySumFactor_ne_zero K) + (convexBodySumFactor_ne_top K), mul_one] + exact mul_ne_top (ne_of_lt (minkowskiBound_lt_top K)) + (ENNReal.inv_ne_top.mpr (convexBodySumFactor_ne_zero K)) + obtain ⟨x, h_nz, h_bd⟩ := exists_ne_zero_mem_ringOfIntegers_of_norm_le K h_le + refine ⟨x, h_nz, ?_⟩ + convert h_bd + rw [div_pow B, ← Real.rpow_nat_cast B, ← Real.rpow_mul (by positivity), div_mul_cancel _ + (Nat.cast_ne_zero.mpr <| ne_of_gt finrank_pos), Real.rpow_one, mul_comm_div, mul_div_assoc'] + congr 1 + rw [eq_comm] + calc + _ = (2:ℝ)⁻¹ ^ NrComplexPlaces K * sqrt ‖discr K‖₊ * (2:ℝ) ^ finrank ℚ K * + ((2:ℝ) ^ NrRealPlaces K * (π / 2) ^ NrComplexPlaces K / + (Nat.factorial (finrank ℚ K)))⁻¹ := by + simp_rw [minkowskiBound, convexBodySumFactor, volume_fundamentalDomain_latticeBasis, + toReal_mul, toReal_inv, toReal_div, toReal_mul, coe_toReal, toReal_pow, toReal_inv, + toReal_ofNat, mixedEmbedding.finrank, toReal_div, toReal_ofNat, coe_toReal, coe_real_pi, + toReal_nat] + _ = (2:ℝ) ^ (finrank ℚ K - NrComplexPlaces K - NrRealPlaces K + NrComplexPlaces K : ℤ) * + Real.sqrt ‖discr K‖ * Nat.factorial (finrank ℚ K) * π⁻¹ ^ (NrComplexPlaces K) := by + simp_rw [inv_div, div_eq_mul_inv, mul_inv, ← zpow_neg_one, ← zpow_coe_nat, mul_zpow, + ← zpow_mul, neg_one_mul, mul_neg_one, neg_neg, Real.coe_sqrt, coe_nnnorm, sub_eq_add_neg, + zpow_add₀ (two_ne_zero : (2:ℝ) ≠ 0)] + ring + _ = (2:ℝ) ^ (2 * NrComplexPlaces K : ℤ) * Real.sqrt ‖discr K‖ * Nat.factorial (finrank ℚ K) * + π⁻¹ ^ (NrComplexPlaces K) := by + congr + rw [← card_add_two_mul_card_eq_rank, Nat.cast_add, Nat.cast_mul, Nat.cast_ofNat] + ring + _ = (4 / π) ^ NrComplexPlaces K * (finrank ℚ K).factorial * Real.sqrt |discr K| := by + rw [show ‖discr K‖ = |(discr K : ℝ)| by rfl, zpow_mul, show (2:ℝ) ^ (2:ℤ) = 4 by norm_cast, + div_pow, inv_eq_one_div, div_pow, one_pow, zpow_coe_nat] + ring + +variable {K} + +theorem abs_discr_ge (h : 1 < finrank ℚ K) : + (4 / 9 : ℝ) * (3 * π / 4) ^ finrank ℚ K ≤ |discr K| := by + -- We use `exists_ne_zero_mem_ringOfIntegers_of_norm_le_mul_sqrt_discr` to get a nonzero + -- algebraic integer `x` of small norm and the fact that `1 ≤ |Norm x|` to get a lower bound + -- on `sqrt |discr K|`. + obtain ⟨x, h_nz, h_bd⟩ := exists_ne_zero_mem_ringOfIntegers_of_norm_le_mul_sqrt_discr K + have h_nm : (1:ℝ) ≤ |(Algebra.norm ℚ) (x:K)| := by + rw [← Algebra.coe_norm_int, ← Int.cast_one, ← Int.cast_abs, Rat.cast_coe_int, Int.cast_le] + exact Int.one_le_abs (Algebra.norm_ne_zero_iff.mpr h_nz) + replace h_bd := le_trans h_nm h_bd + rw [← inv_mul_le_iff (by positivity), inv_div, mul_one, Real.le_sqrt (by positivity) + (by positivity), ← Int.cast_abs, div_pow, mul_pow, ← pow_mul, ← pow_mul] at h_bd + refine le_trans ?_ h_bd + -- The sequence `a n` is a lower bound for `|discr K|`. We prove below by induction an uniform + -- lower bound for this sequence from which we deduce the result. + let a : ℕ → ℝ := fun n => (n:ℝ) ^ (n * 2) / ((4 / π) ^ n * (n.factorial:ℝ) ^ 2) + suffices ∀ n, 2 ≤ n → (4 / 9 : ℝ) * (3 * π / 4) ^ n ≤ a n by + refine le_trans (this (finrank ℚ K) h) ?_ + refine div_le_div_of_le_left (by positivity) (by positivity) ?_ + refine mul_le_mul_of_nonneg_right (pow_le_pow ?_ ?_) (by positivity) + · rw [_root_.le_div_iff Real.pi_pos, one_mul] + exact Real.pi_le_four + · rw [← card_add_two_mul_card_eq_rank, mul_comm] + exact Nat.le_add_left _ _ + intro n hn + induction n, hn using Nat.le_induction with + | base => exact le_of_eq <| by norm_num [Nat.factorial_two]; field_simp; ring + | succ m _ h_m => + suffices (3:ℝ) ≤ (1 + 1 / m : ℝ) ^ (2 * m) by + convert_to _ ≤ (a m) * (1 + 1 / m : ℝ) ^ (2 * m) / (4 / π) + · simp_rw [add_mul, one_mul, pow_succ, Nat.factorial_succ] + field_simp; ring + · rw [_root_.le_div_iff (by positivity), pow_succ] + convert (mul_le_mul h_m this (by positivity) (by positivity)) using 1 + field_simp; ring + refine le_trans (le_of_eq (by field_simp; norm_num)) (one_add_mul_le_pow ?_ (2 * m)) + exact le_trans (by norm_num : (-2:ℝ) ≤ 0) (by positivity) + +/-- **Hermite-Minkowski Theorem**. A nontrivial number field has nontrivial discriminant. -/ +theorem discr_gt_one (h : 1 < finrank ℚ K) : 2 < |discr K| := by + have h₁ : 1 ≤ 3 * π / 4 := by + rw [_root_.le_div_iff (by positivity), ← _root_.div_le_iff' (by positivity), one_mul] + linarith [Real.pi_gt_three] + have h₂ : (9:ℝ) < π ^ 2 := by + rw [ ← Real.sqrt_lt (by positivity) (by positivity), show Real.sqrt (9:ℝ) = 3 from + (Real.sqrt_eq_iff_sq_eq (by positivity) (by positivity)).mpr (by norm_num)] + exact Real.pi_gt_three + refine Int.cast_lt.mp <| lt_of_lt_of_le ?_ (abs_discr_ge h) + rw [← _root_.div_lt_iff' (by positivity), Int.int_cast_ofNat] + refine lt_of_lt_of_le ?_ (pow_le_pow (n := 2) h₁ h) + rw [div_pow, _root_.lt_div_iff (by norm_num), mul_pow] + norm_num + rw [ ← _root_.div_lt_iff' (by positivity), show (72:ℝ) / 9 = 8 by norm_num] + linarith [h₂] + end NumberField namespace Rat diff --git a/Mathlib/NumberTheory/NumberField/Embeddings.lean b/Mathlib/NumberTheory/NumberField/Embeddings.lean index f8415a6958393..77a7f8adfa8d8 100644 --- a/Mathlib/NumberTheory/NumberField/Embeddings.lean +++ b/Mathlib/NumberTheory/NumberField/Embeddings.lean @@ -197,7 +197,7 @@ def IsReal.embedding {φ : K →+* ℂ} (hφ : IsReal φ) : K →+* ℝ where @[simp] theorem IsReal.coe_embedding_apply {φ : K →+* ℂ} (hφ : IsReal φ) (x : K) : (hφ.embedding x : ℂ) = φ x := by - ext + apply Complex.ext · rfl · rw [ofReal_im, eq_comm, ← Complex.conj_eq_iff_im] exact RingHom.congr_fun hφ x diff --git a/Mathlib/NumberTheory/Pell.lean b/Mathlib/NumberTheory/Pell.lean index 381623c485e23..8cd4d4e8bbc30 100644 --- a/Mathlib/NumberTheory/Pell.lean +++ b/Mathlib/NumberTheory/Pell.lean @@ -211,8 +211,6 @@ theorem eq_zero_of_d_neg (h₀ : d < 0) (a : Solution₁ d) : a.x = 0 ∨ a.y = contrapose! h have h1 := sq_pos_of_ne_zero a.x h.1 have h2 := sq_pos_of_ne_zero a.y h.2 - -- Porting note: added this to help `nlinarith` - obtain ⟨d', rfl⟩ : ∃ d', d = -d' := ⟨-d, by exact Iff.mp neg_eq_iff_eq_neg rfl⟩ nlinarith #align pell.solution₁.eq_zero_of_d_neg Pell.Solution₁.eq_zero_of_d_neg diff --git a/Mathlib/NumberTheory/SmoothNumbers.lean b/Mathlib/NumberTheory/SmoothNumbers.lean index d9575c0730bcf..1d1c73e257f44 100644 --- a/Mathlib/NumberTheory/SmoothNumbers.lean +++ b/Mathlib/NumberTheory/SmoothNumbers.lean @@ -155,7 +155,8 @@ def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) : simp only [not_lt, le_iff_eq_or_lt, H, or_false, eq_comm, Bool.true_eq_decide_iff] refine prod_eq <| (filter_eq' m.factors p).symm ▸ this ▸ perm_append_comm.trans ?_ convert filter_append_perm .. - simp only [decide_eq_true_eq] + simp only [not_lt] + simp only [decide_not, Bool.not_not, lt_iff_not_ge] @[simp] lemma equivProdNatSmoothNumbers_apply {p e m : ℕ} (hp: p.Prime) (hm : m ∈ p.smoothNumbers) : diff --git a/Mathlib/Order/Cover.lean b/Mathlib/Order/Cover.lean index 2a89ad9138e3e..a08c80dc06f25 100644 --- a/Mathlib/Order/Cover.lean +++ b/Mathlib/Order/Cover.lean @@ -501,7 +501,7 @@ variable {s t : Set α} {a : α} @[simp] lemma sdiff_singleton_covby (ha : a ∈ s) : s \ {a} ⋖ s := ⟨sdiff_lt (singleton_subset_iff.2 ha) $ singleton_ne_empty _, (sdiff_singleton_wcovby _ _).2⟩ -lemma _root_.Covby.exists_set_insert (h : s ⋖ t) : ∃ a, a ∉ s ∧ insert a s = t := +lemma _root_.Covby.exists_set_insert (h : s ⋖ t) : ∃ a ∉ s, insert a s = t := let ⟨a, ha, hst⟩ := ssubset_iff_insert.1 h.lt ⟨a, ha, (hst.eq_of_not_ssuperset $ h.2 $ ssubset_insert ha).symm⟩ @@ -510,7 +510,7 @@ lemma _root_.Covby.exists_set_sdiff_singleton (h : s ⋖ t) : ∃ a ∈ t, t \ { ⟨a, ha, (hst.eq_of_not_ssubset fun h' ↦ h.2 h' $ sdiff_lt (singleton_subset_iff.2 ha) $ singleton_ne_empty _).symm⟩ -lemma covby_iff_exists_insert : s ⋖ t ↔ ∃ a, a ∉ s ∧ insert a s = t := +lemma covby_iff_exists_insert : s ⋖ t ↔ ∃ a ∉ s, insert a s = t := ⟨Covby.exists_set_insert, by rintro ⟨a, ha, rfl⟩; exact covby_insert ha⟩ lemma covby_iff_exists_sdiff_singleton : s ⋖ t ↔ ∃ a ∈ t, t \ {a} = s := diff --git a/Mathlib/Order/Filter/AtTopBot.lean b/Mathlib/Order/Filter/AtTopBot.lean index ecb105a1add78..85cad5e9e9889 100644 --- a/Mathlib/Order/Filter/AtTopBot.lean +++ b/Mathlib/Order/Filter/AtTopBot.lean @@ -1861,10 +1861,8 @@ antitone basis with basis sets decreasing "sufficiently fast". -/ theorem HasAntitoneBasis.subbasis_with_rel {f : Filter α} {s : ℕ → Set α} (hs : f.HasAntitoneBasis s) {r : ℕ → ℕ → Prop} (hr : ∀ m, ∀ᶠ n in atTop, r m n) : ∃ φ : ℕ → ℕ, StrictMono φ ∧ (∀ ⦃m n⦄, m < n → r (φ m) (φ n)) ∧ f.HasAntitoneBasis (s ∘ φ) := by - -- porting note: use `rsuffices` - suffices : ∃ φ : ℕ → ℕ, StrictMono φ ∧ ∀ m n, m < n → r (φ m) (φ n) - · rcases this with ⟨φ, hφ, hrφ⟩ - exact ⟨φ, hφ, hrφ, hs.comp_strictMono hφ⟩ + rsuffices ⟨φ, hφ, hrφ⟩ : ∃ φ : ℕ → ℕ, StrictMono φ ∧ ∀ m n, m < n → r (φ m) (φ n) + · exact ⟨φ, hφ, hrφ, hs.comp_strictMono hφ⟩ have : ∀ t : Set ℕ, t.Finite → ∀ᶠ n in atTop, ∀ m ∈ t, m < n ∧ r m n := fun t ht => (eventually_all_finite ht).2 fun m _ => (eventually_gt_atTop m).and (hr _) rcases seq_of_forall_finite_exists fun t ht => (this t ht).exists with ⟨φ, hφ⟩ diff --git a/Mathlib/Order/Filter/EventuallyConst.lean b/Mathlib/Order/Filter/EventuallyConst.lean index e5b7f7576a0f3..09c4284d8bed2 100644 --- a/Mathlib/Order/Filter/EventuallyConst.lean +++ b/Mathlib/Order/Filter/EventuallyConst.lean @@ -5,7 +5,7 @@ Authors: Yury Kudryashov, Floris van Doorn -/ import Mathlib.Order.Filter.AtTopBot import Mathlib.Order.Filter.Subsingleton -import Mathlib.Algebra.IndicatorFunction +import Mathlib.Algebra.Function.Indicator /-! # Functions that are eventually constant along a filter diff --git a/Mathlib/Order/Filter/IndicatorFunction.lean b/Mathlib/Order/Filter/IndicatorFunction.lean index e3b129df67696..8242f91ef60fe 100644 --- a/Mathlib/Order/Filter/IndicatorFunction.lean +++ b/Mathlib/Order/Filter/IndicatorFunction.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Zhouhang Zhou. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Zhouhang Zhou, Yury Kudryashov -/ -import Mathlib.Algebra.IndicatorFunction +import Mathlib.Algebra.Function.Indicator import Mathlib.Order.Filter.AtTopBot #align_import order.filter.indicator_function from "leanprover-community/mathlib"@"8631e2d5ea77f6c13054d9151d82b83069680cb1" diff --git a/Mathlib/Probability/Martingale/Upcrossing.lean b/Mathlib/Probability/Martingale/Upcrossing.lean index 1adef8da72489..727525fecc760 100644 --- a/Mathlib/Probability/Martingale/Upcrossing.lean +++ b/Mathlib/Probability/Martingale/Upcrossing.lean @@ -375,24 +375,24 @@ theorem upcrossingStrat_nonneg : 0 ≤ upcrossingStrat a b f N n ω := #align measure_theory.upcrossing_strat_nonneg MeasureTheory.upcrossingStrat_nonneg theorem upcrossingStrat_le_one : upcrossingStrat a b f N n ω ≤ 1 := by - rw [upcrossingStrat, ← Set.indicator_finset_biUnion_apply] + rw [upcrossingStrat, ← Finset.indicator_biUnion_apply] · exact Set.indicator_le_self' (fun _ _ => zero_le_one) _ - · intro i _ j _ hij - rw [Set.Ico_disjoint_Ico] - obtain hij' | hij' := lt_or_gt_of_ne hij - · rw [min_eq_left (upperCrossingTime_mono (Nat.succ_le_succ hij'.le) : - upperCrossingTime a b f N _ ω ≤ upperCrossingTime a b f N _ ω), - max_eq_right (lowerCrossingTime_mono hij'.le : - lowerCrossingTime a b f N _ _ ≤ lowerCrossingTime _ _ _ _ _ _)] - refine' le_trans upperCrossingTime_le_lowerCrossingTime - (lowerCrossingTime_mono (Nat.succ_le_of_lt hij')) - · rw [gt_iff_lt] at hij' - rw [min_eq_right (upperCrossingTime_mono (Nat.succ_le_succ hij'.le) : - upperCrossingTime a b f N _ ω ≤ upperCrossingTime a b f N _ ω), - max_eq_left (lowerCrossingTime_mono hij'.le : - lowerCrossingTime a b f N _ _ ≤ lowerCrossingTime _ _ _ _ _ _)] - refine' le_trans upperCrossingTime_le_lowerCrossingTime - (lowerCrossingTime_mono (Nat.succ_le_of_lt hij')) + intro i _ j _ hij + simp only [Set.Ico_disjoint_Ico] + obtain hij' | hij' := lt_or_gt_of_ne hij + · rw [min_eq_left (upperCrossingTime_mono (Nat.succ_le_succ hij'.le) : + upperCrossingTime a b f N _ ω ≤ upperCrossingTime a b f N _ ω), + max_eq_right (lowerCrossingTime_mono hij'.le : + lowerCrossingTime a b f N _ _ ≤ lowerCrossingTime _ _ _ _ _ _)] + refine' le_trans upperCrossingTime_le_lowerCrossingTime + (lowerCrossingTime_mono (Nat.succ_le_of_lt hij')) + · rw [gt_iff_lt] at hij' + rw [min_eq_right (upperCrossingTime_mono (Nat.succ_le_succ hij'.le) : + upperCrossingTime a b f N _ ω ≤ upperCrossingTime a b f N _ ω), + max_eq_left (lowerCrossingTime_mono hij'.le : + lowerCrossingTime a b f N _ _ ≤ lowerCrossingTime _ _ _ _ _ _)] + refine' le_trans upperCrossingTime_le_lowerCrossingTime + (lowerCrossingTime_mono (Nat.succ_le_of_lt hij')) #align measure_theory.upcrossing_strat_le_one MeasureTheory.upcrossingStrat_le_one theorem Adapted.upcrossingStrat_adapted (hf : Adapted ℱ f) : diff --git a/Mathlib/RingTheory/Adjoin/Field.lean b/Mathlib/RingTheory/Adjoin/Field.lean index dbfd1b1aadf24..71d1adc086ce5 100644 --- a/Mathlib/RingTheory/Adjoin/Field.lean +++ b/Mathlib/RingTheory/Adjoin/Field.lean @@ -82,3 +82,23 @@ theorem Polynomial.lift_of_splits {F K L : Type*} [Field F] [Field K] [Field L] #align lift_of_splits Polynomial.lift_of_splits end Embeddings + +variable {R K L M : Type*} [CommRing R] [Field K] [Field L] [CommRing M] [Algebra R K] [Algebra R L] + [Algebra R M] {x : L} (int : IsIntegral R x) (h : Splits (algebraMap R K) (minpoly R x)) + +theorem IsIntegral.mem_range_algHom_of_minpoly_splits (f : K →ₐ[R] L) : x ∈ f.range := + show x ∈ Set.range f from Set.image_subset_range _ _ <| by + rw [image_rootSet h f, mem_rootSet'] + exact ⟨((minpoly.monic int).map _).ne_zero, minpoly.aeval R x⟩ + +theorem IsIntegral.mem_range_algebraMap_of_minpoly_splits [Algebra K L] [IsScalarTower R K L] : + x ∈ (algebraMap K L).range := + int.mem_range_algHom_of_minpoly_splits h (IsScalarTower.toAlgHom R K L) + +theorem IsIntegral.minpoly_splits_tower_top + [Algebra K L] [IsScalarTower R K L] [Algebra K M] [IsScalarTower R K M] + {x : M} (int : IsIntegral R x) (h : Splits (algebraMap R L) (minpoly R x)) : + Splits (algebraMap K L) (minpoly K x) := by + rw [IsScalarTower.algebraMap_eq R K L] at h + exact splits_of_splits_of_dvd _ ((minpoly.monic int).map _).ne_zero + ((splits_map_iff _ _).mpr h) (minpoly.dvd_map_of_isScalarTower R _ x) diff --git a/Mathlib/RingTheory/Coalgebra.lean b/Mathlib/RingTheory/Coalgebra.lean index f98cfbea5accc..155c0d5edad7b 100644 --- a/Mathlib/RingTheory/Coalgebra.lean +++ b/Mathlib/RingTheory/Coalgebra.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2023 Ali Ramsey. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Ali Ramsey +Authors: Ali Ramsey, Eric Wieser -/ import Mathlib.LinearAlgebra.Finsupp import Mathlib.LinearAlgebra.Prod @@ -82,11 +82,11 @@ theorem lTensor_counit_comul (a : A) : counit.lTensor A (comul a) = a ⊗ₜ[R] end Coalgebra section CommSemiring -variable (R : Type u) [CommSemiring R] open Coalgebra namespace CommSemiring +variable (R : Type u) [CommSemiring R] /-- Every commutative (semi)ring is a coalgebra over itself, with `Δ r = 1 ⊗ₜ r`. -/ instance toCoalgebra : Coalgebra R R where @@ -182,29 +182,61 @@ instance instCoalgebra : Coalgebra R (A × B) where end Prod namespace Finsupp -variable (ι : Type v) - -/-- The `R`-module whose elements are functions `ι → R` which are zero on all but finitely many -elements of `ι` has a coalgebra structure. The coproduct `Δ` is given by `Δ(fᵢ) = fᵢ ⊗ fᵢ` and the -counit `ε` by `ε(fᵢ) = 1`, where `fᵢ` is the function sending `i` to `1` and all other elements of -`ι` to zero. -/ -noncomputable -instance instCoalgebra : Coalgebra R (ι →₀ R) where - comul := Finsupp.total ι ((ι →₀ R) ⊗[R] (ι →₀ R)) R (fun i ↦ .single i 1 ⊗ₜ .single i 1) - counit := Finsupp.total ι R R (fun _ ↦ 1) - coassoc := by ext; simp - rTensor_counit_comp_comul := by ext; simp - lTensor_counit_comp_comul := by ext; simp +variable (R : Type u) (ι : Type v) (A : Type w) +variable [CommSemiring R] [AddCommMonoid A] [Module R A] [Coalgebra R A] + +open LinearMap + +instance instCoalgebraStruct : CoalgebraStruct R (ι →₀ A) where + comul := Finsupp.lsum R fun i => + TensorProduct.map (Finsupp.lsingle i) (Finsupp.lsingle i) ∘ₗ comul + counit := Finsupp.lsum R fun _ => counit @[simp] -theorem comul_single (i : ι) (r : R) : - comul (Finsupp.single i r) = (Finsupp.single i r) ⊗ₜ[R] (Finsupp.single i 1) := by - unfold comul instCoalgebra toCoalgebraStruct - rw [total_single, TensorProduct.smul_tmul', smul_single_one i r] +theorem comul_single (i : ι) (a : A) : + comul (R := R) (Finsupp.single i a) = + (TensorProduct.map (Finsupp.lsingle i) (Finsupp.lsingle i) : _ →ₗ[R] _) (comul a) := + lsum_single _ _ _ _ @[simp] -theorem counit_single (i : ι) (r : R) : counit (Finsupp.single i r) = r := by - unfold counit instCoalgebra; simp +theorem counit_single (i : ι) (a : A) : counit (Finsupp.single i a) = counit (R := R) a := + lsum_single _ _ _ _ + +theorem comul_comp_lsingle (i : ι) : + comul ∘ₗ (lsingle i : A →ₗ[R] _) = TensorProduct.map (lsingle i) (lsingle i) ∘ₗ comul := by + ext; simp + +theorem comul_comp_lapply (i : ι) : + comul ∘ₗ (lapply i : _ →ₗ[R] A) = TensorProduct.map (lapply i) (lapply i) ∘ₗ comul := by + ext j : 1 + conv_rhs => rw [comp_assoc, comul_comp_lsingle, ← comp_assoc, ← TensorProduct.map_comp] + obtain rfl | hij := eq_or_ne i j + · rw [comp_assoc, lapply_comp_lsingle_same, comp_id, TensorProduct.map_id, id_comp] + · rw [comp_assoc, lapply_comp_lsingle_of_ne _ _ hij, comp_zero, TensorProduct.map_zero_left, + zero_comp] + +@[simp] theorem counit_comp_lsingle (i : ι) : counit ∘ₗ (lsingle i : A →ₗ[R] _) = counit := by + ext; simp + +/-- The `R`-module whose elements are functions `ι → A` which are zero on all but finitely many +elements of `ι` has a coalgebra structure. The coproduct `Δ` is given by `Δ(fᵢ a) = fᵢ a₁ ⊗ fᵢ a₂` +where `Δ(a) = a₁ ⊗ a₂` and the counit `ε` by `ε(fᵢ a) = ε(a)`, where `fᵢ a` is the function sending +`i` to `a` and all other elements of `ι` to zero. -/ +instance instCoalgebra : Coalgebra R (ι →₀ A) where + rTensor_counit_comp_comul := by + ext : 1 + rw [comp_assoc, comul_comp_lsingle, ← comp_assoc, rTensor_comp_map, counit_comp_lsingle, + ← lTensor_comp_rTensor, comp_assoc, rTensor_counit_comp_comul, lTensor_comp_mk] + lTensor_counit_comp_comul := by + ext : 1 + rw [comp_assoc, comul_comp_lsingle, ← comp_assoc, lTensor_comp_map, counit_comp_lsingle, + ← rTensor_comp_lTensor, comp_assoc, lTensor_counit_comp_comul, rTensor_comp_flip_mk] + coassoc := by + ext i : 1 + simp_rw [comp_assoc, comul_comp_lsingle, ← comp_assoc, lTensor_comp_map, comul_comp_lsingle, + comp_assoc, ← comp_assoc comul, rTensor_comp_map, comul_comp_lsingle, ← map_comp_rTensor, + ← map_comp_lTensor, comp_assoc, ← coassoc, ← comp_assoc comul, ← comp_assoc, + TensorProduct.map_map_comp_assoc_eq] end Finsupp diff --git a/Mathlib/RingTheory/HahnSeries.lean b/Mathlib/RingTheory/HahnSeries.lean index e61875f401cdd..4b7f1888ec2d3 100644 --- a/Mathlib/RingTheory/HahnSeries.lean +++ b/Mathlib/RingTheory/HahnSeries.lean @@ -1117,12 +1117,13 @@ def toPowerSeries : HahnSeries ℕ R ≃+* PowerSeries R where ext n simp only [PowerSeries.coeff_mul, PowerSeries.coeff_mk, mul_coeff, isPwo_support] classical - refine' sum_filter_ne_zero.symm.trans ((sum_congr _ fun _ _ => rfl).trans sum_filter_ne_zero) - ext m - simp only [mem_antidiagonal, mem_addAntidiagonal, and_congr_left_iff, mem_filter, - mem_support] - rintro h - rw [and_iff_right (left_ne_zero_of_mul h), and_iff_right (right_ne_zero_of_mul h)] + refine (sum_filter_ne_zero _).symm.trans $ (sum_congr ?_ fun _ _ ↦ rfl).trans $ + sum_filter_ne_zero _ + ext m + simp only [mem_antidiagonal, mem_addAntidiagonal, and_congr_left_iff, mem_filter, + mem_support] + rintro h + rw [and_iff_right (left_ne_zero_of_mul h), and_iff_right (right_ne_zero_of_mul h)] #align hahn_series.to_power_series HahnSeries.toPowerSeries theorem coeff_toPowerSeries {f : HahnSeries ℕ R} {n : ℕ} : @@ -1231,7 +1232,8 @@ def toMvPowerSeries {σ : Type*} [Fintype σ] : HahnSeries (σ →₀ ℕ) R ≃ classical change (f * g).coeff n = _ simp_rw [mul_coeff] - refine' sum_filter_ne_zero.symm.trans ((sum_congr _ fun _ _ => rfl).trans sum_filter_ne_zero) + refine' (sum_filter_ne_zero _).symm.trans $ (sum_congr _ fun _ _ ↦ rfl).trans $ + sum_filter_ne_zero _ ext m simp only [and_congr_left_iff, mem_addAntidiagonal, mem_filter, mem_support, Finset.mem_antidiagonal] diff --git a/Mathlib/RingTheory/IntegralClosure.lean b/Mathlib/RingTheory/IntegralClosure.lean index 2cc38fdf8f000..86743a62a9475 100644 --- a/Mathlib/RingTheory/IntegralClosure.lean +++ b/Mathlib/RingTheory/IntegralClosure.lean @@ -469,27 +469,25 @@ theorem integralClosure_map_algEquiv [Algebra R S] (f : A ≃ₐ[R] S) : /-- An `AlgHom` between two rings restrict to an `AlgHom` between the integral closures inside them. -/ -def integralClosure_algHom_restrict [Algebra R S] (f : A →ₐ[R] S) : +def AlgHom.mapIntegralClosure [Algebra R S] (f : A →ₐ[R] S) : integralClosure R A →ₐ[R] integralClosure R S := (f.restrictDomain (integralClosure R A)).codRestrict (integralClosure R S) (fun ⟨_, h⟩ => h.map f) @[simp] -theorem integralClosure_coe_algHom_restrict [Algebra R S] (f : A →ₐ[R] S) - (x : integralClosure R A) : (integralClosure_algHom_restrict f x : S) = f (x : A) := rfl +theorem AlgHom.coe_mapIntegralClosure [Algebra R S] (f : A →ₐ[R] S) + (x : integralClosure R A) : (f.mapIntegralClosure x : S) = f (x : A) := rfl /-- An `AlgEquiv` between two rings restrict to an `AlgEquiv` between the integral closures inside them. -/ -noncomputable def integralClosure_algEquiv_restrict [Algebra R S] (f : A ≃ₐ[R] S) : - integralClosure R A ≃ₐ[R] integralClosure R S := by - refine AlgEquiv.ofBijective (integralClosure_algHom_restrict f) ⟨?_, ?_⟩ - · erw [AlgHom.injective_codRestrict] - exact (EquivLike.injective f).comp Subtype.val_injective - · rintro ⟨y, hy⟩ - exact ⟨⟨f.symm y, hy.map f.symm⟩, by rw [Subtype.mk_eq_mk]; simp⟩ +def AlgEquiv.mapIntegralClosure [Algebra R S] (f : A ≃ₐ[R] S) : + integralClosure R A ≃ₐ[R] integralClosure R S := + AlgEquiv.ofAlgHom (f : A →ₐ[R] S).mapIntegralClosure (f.symm : S →ₐ[R] A).mapIntegralClosure + (AlgHom.ext fun _ ↦ Subtype.ext (f.right_inv _)) + (AlgHom.ext fun _ ↦ Subtype.ext (f.left_inv _)) @[simp] -theorem integralClosure_coe_algEquiv_restrict [Algebra R S] (f : A ≃ₐ[R] S) - (x : integralClosure R A) : (integralClosure_algEquiv_restrict f x : S) = f (x : A) := rfl +theorem AlgEquiv.coe_mapIntegralClosure [Algebra R S] (f : A ≃ₐ[R] S) + (x : integralClosure R A) : (f.mapIntegralClosure x : S) = f (x : A) := rfl theorem integralClosure.isIntegral (x : integralClosure R A) : IsIntegral R x := let ⟨p, hpm, hpx⟩ := x.2 diff --git a/Mathlib/RingTheory/Norm.lean b/Mathlib/RingTheory/Norm.lean index 93ea9dd61fcc2..61bae51d574f1 100644 --- a/Mathlib/RingTheory/Norm.lean +++ b/Mathlib/RingTheory/Norm.lean @@ -331,6 +331,43 @@ theorem isIntegral_norm [Algebra R L] [Algebra R K] [IsScalarTower R K L] [IsSep · apply IsAlgClosed.splits_codomain #align algebra.is_integral_norm Algebra.isIntegral_norm +lemma norm_eq_of_algEquiv [Ring T] [Algebra R T] (e : S ≃ₐ[R] T) (x) : + Algebra.norm R (e x) = Algebra.norm R x := by + simp_rw [Algebra.norm_apply, ← LinearMap.det_conj _ e.toLinearEquiv]; congr; ext; simp + +lemma norm_eq_of_ringEquiv {A B C : Type*} [CommRing A] [CommRing B] [Ring C] + [Algebra A C] [Algebra B C] (e : A ≃+* B) (he : (algebraMap B C).comp e = algebraMap A C) + (x : C) : + e (Algebra.norm A x) = Algebra.norm B x := by + classical + by_cases h : ∃ s : Finset C, Nonempty (Basis s B C) + · obtain ⟨s, ⟨b⟩⟩ := h + letI : Algebra A B := RingHom.toAlgebra e + letI : IsScalarTower A B C := IsScalarTower.of_algebraMap_eq' he.symm + rw [Algebra.norm_eq_matrix_det b, + Algebra.norm_eq_matrix_det (b.mapCoeffs e.symm (by simp [Algebra.smul_def, ← he])), + e.map_det] + congr + ext i j + simp [leftMulMatrix_apply, LinearMap.toMatrix_apply] + rw [norm_eq_one_of_not_exists_basis _ h, norm_eq_one_of_not_exists_basis, _root_.map_one] + intro ⟨s, ⟨b⟩⟩ + exact h ⟨s, ⟨b.mapCoeffs e (by simp [Algebra.smul_def, ← he])⟩⟩ + +lemma norm_eq_of_equiv_equiv {A₁ B₁ A₂ B₂ : Type*} [CommRing A₁] [Ring B₁] + [CommRing A₂] [Ring B₂] [Algebra A₁ B₁] [Algebra A₂ B₂] (e₁ : A₁ ≃+* A₂) (e₂ : B₁ ≃+* B₂) + (he : RingHom.comp (algebraMap A₂ B₂) ↑e₁ = RingHom.comp ↑e₂ (algebraMap A₁ B₁)) (x) : + Algebra.norm A₁ x = e₁.symm (Algebra.norm A₂ (e₂ x)) := by + letI := (RingHom.comp (e₂ : B₁ →+* B₂) (algebraMap A₁ B₁)).toAlgebra' ?_ + let e' : B₁ ≃ₐ[A₁] B₂ := { e₂ with commutes' := fun _ ↦ rfl } + rw [← Algebra.norm_eq_of_ringEquiv e₁ he, ← Algebra.norm_eq_of_algEquiv e', + RingEquiv.symm_apply_apply] + rfl + intros c x + apply e₂.symm.injective + simp only [RingHom.coe_comp, RingHom.coe_coe, Function.comp_apply, _root_.map_mul, + RingEquiv.symm_apply_apply, commutes] + variable {F} (L) -- TODO. Generalize this proof to rings diff --git a/Mathlib/RingTheory/Polynomial/Cyclotomic/Eval.lean b/Mathlib/RingTheory/Polynomial/Cyclotomic/Eval.lean index eeb0c4cc212ab..6a188a7455410 100644 --- a/Mathlib/RingTheory/Polynomial/Cyclotomic/Eval.lean +++ b/Mathlib/RingTheory/Polynomial/Cyclotomic/Eval.lean @@ -264,7 +264,7 @@ theorem cyclotomic_eval_lt_add_one_pow_totient {n : ℕ} {q : ℝ} (hn' : 3 ≤ rw [this] at hζ linarith [hζ.unique <| IsPrimitiveRoot.neg_one 0 two_ne_zero.symm] · contrapose! hζ₀ - ext <;> simp [hζ₀, h.2] + apply Complex.ext <;> simp [hζ₀, h.2] have : ¬eval (↑q) (cyclotomic n ℂ) = 0 := by erw [cyclotomic.eval_apply q n (algebraMap ℝ ℂ)] simp only [Complex.coe_algebraMap, Complex.ofReal_eq_zero] diff --git a/Mathlib/RingTheory/Subring/Basic.lean b/Mathlib/RingTheory/Subring/Basic.lean index 96b8a6018a3ad..7b6687d429053 100644 --- a/Mathlib/RingTheory/Subring/Basic.lean +++ b/Mathlib/RingTheory/Subring/Basic.lean @@ -1383,10 +1383,8 @@ protected theorem InClosure.recOn {C : R → Prop} {x : R} (hx : x ∈ closure s exact ha this (ih HL.2) replace HL := HL.1 clear ih tl - -- Porting note: was `rsuffices` instead of `obtain` + `rotate_left` - obtain ⟨L, HL', HP | HP⟩ : + rsuffices ⟨L, HL', HP | HP⟩ : ∃ L : List R, (∀ x ∈ L, x ∈ s) ∧ (List.prod hd = List.prod L ∨ List.prod hd = -List.prod L) - rotate_left · rw [HP] clear HP HL hd induction' L with hd tl ih diff --git a/Mathlib/RingTheory/Trace.lean b/Mathlib/RingTheory/Trace.lean index b602bbe48df34..a5f45443e639b 100644 --- a/Mathlib/RingTheory/Trace.lean +++ b/Mathlib/RingTheory/Trace.lean @@ -328,6 +328,42 @@ theorem Algebra.isIntegral_trace [FiniteDimensional L F] {x : F} (hx : IsIntegra · apply IsAlgClosed.splits_codomain #align algebra.is_integral_trace Algebra.isIntegral_trace +lemma Algebra.trace_eq_of_algEquiv {A B C : Type*} [CommRing A] [CommRing B] [CommRing C] + [Algebra A B] [Algebra A C] (e : B ≃ₐ[A] C) (x) : + Algebra.trace A C (e x) = Algebra.trace A B x := by + simp_rw [Algebra.trace_apply, ← LinearMap.trace_conj' _ e.toLinearEquiv] + congr; ext; simp [LinearEquiv.conj_apply] + +lemma Algebra.trace_eq_of_ringEquiv {A B C : Type*} [CommRing A] [CommRing B] [CommRing C] + [Algebra A C] [Algebra B C] (e : A ≃+* B) (he : (algebraMap B C).comp e = algebraMap A C) (x) : + e (Algebra.trace A C x) = Algebra.trace B C x := by + classical + by_cases h : ∃ s : Finset C, Nonempty (Basis s B C) + · obtain ⟨s, ⟨b⟩⟩ := h + letI : Algebra A B := RingHom.toAlgebra e + letI : IsScalarTower A B C := IsScalarTower.of_algebraMap_eq' he.symm + rw [Algebra.trace_eq_matrix_trace b, + Algebra.trace_eq_matrix_trace (b.mapCoeffs e.symm (by simp [Algebra.smul_def, ← he]))] + show e.toAddMonoidHom _ = _ + rw [AddMonoidHom.map_trace] + congr + ext i j + simp [leftMulMatrix_apply, LinearMap.toMatrix_apply] + rw [trace_eq_zero_of_not_exists_basis _ h, trace_eq_zero_of_not_exists_basis, + LinearMap.zero_apply, LinearMap.zero_apply, map_zero] + intro ⟨s, ⟨b⟩⟩ + exact h ⟨s, ⟨b.mapCoeffs e (by simp [Algebra.smul_def, ← he])⟩⟩ + +lemma Algebra.trace_eq_of_equiv_equiv {A₁ B₁ A₂ B₂ : Type*} [CommRing A₁] [CommRing B₁] + [CommRing A₂] [CommRing B₂] [Algebra A₁ B₁] [Algebra A₂ B₂] (e₁ : A₁ ≃+* A₂) (e₂ : B₁ ≃+* B₂) + (he : RingHom.comp (algebraMap A₂ B₂) ↑e₁ = RingHom.comp ↑e₂ (algebraMap A₁ B₁)) (x) : + Algebra.trace A₁ B₁ x = e₁.symm (Algebra.trace A₂ B₂ (e₂ x)) := by + letI := (RingHom.comp (e₂ : B₁ →+* B₂) (algebraMap A₁ B₁)).toAlgebra + let e' : B₁ ≃ₐ[A₁] B₂ := { e₂ with commutes' := fun _ ↦ rfl } + rw [← Algebra.trace_eq_of_ringEquiv e₁ he, ← Algebra.trace_eq_of_algEquiv e', + RingEquiv.symm_apply_apply] + rfl + section EqSumEmbeddings variable [Algebra K F] [IsScalarTower K L F] diff --git a/Mathlib/SetTheory/Cardinal/Basic.lean b/Mathlib/SetTheory/Cardinal/Basic.lean index 8145fddfb5a20..946dc432dad93 100644 --- a/Mathlib/SetTheory/Cardinal/Basic.lean +++ b/Mathlib/SetTheory/Cardinal/Basic.lean @@ -3,6 +3,7 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro, Floris van Doorn -/ +import Mathlib.Algebra.Module.Basic import Mathlib.Data.Fintype.BigOperators import Mathlib.Data.Finsupp.Defs import Mathlib.Data.Nat.PartENat diff --git a/Mathlib/Tactic/MoveAdd.lean b/Mathlib/Tactic/MoveAdd.lean index 9ec4a85bf3df5..1dc9815dc4756 100644 --- a/Mathlib/Tactic/MoveAdd.lean +++ b/Mathlib/Tactic/MoveAdd.lean @@ -215,18 +215,25 @@ def prepareOp (sum : Expr) : Expr := let opargs := sum.getAppArgs (opargs.toList.take (opargs.size - 2)).foldl (fun x y => Expr.app x y) sum.getAppFn -/-- `sumList prepOp exs` assumes that `prepOp` is an `Expr`ession representing a binary operation -already fully applied up until its last two arguments and assumes that the last two arguments -are the operands of the operation. +/-- `sumList prepOp left_assoc? exs` assumes that `prepOp` is an `Expr`ession representing a +binary operation already fully applied up until its last two arguments and assumes that the +last two arguments are the operands of the operation. Such an expression is the result of `prepareOp`. -If `exs` is the list `[e₁, e₂, ..., eₙ]` of `Expr`essions, then `sumList prepOp exs` returns -`prepOp (prepOp( ... prepOp (prepOp e₁ e₂) e₃) ... eₙ)`. + +If `exs` is the list `[e₁, e₂, ..., eₙ]` of `Expr`essions, then `sumList prepOp left_assoc? exs` +returns +* `prepOp (prepOp( ... prepOp (prepOp e₁ e₂) e₃) ... eₙ)`, if `left_assoc?` is `false`, and +* `prepOp e₁ (prepOp e₂ (... prepOp (prepOp eₙ₋₁ eₙ))`, if `left_assoc?` is `true`. -/ partial -def sumList (prepOp : Expr) : List Expr → Expr +def sumList (prepOp : Expr) (left_assoc? : Bool) : List Expr → Expr | [] => default - | [a] => a - | a::as => as.foldl (fun x y => Expr.app (prepOp.app x) y) a + | [a] => a + | a::as => + if left_assoc? then + Expr.app (prepOp.app a) (sumList prepOp true as) + else + as.foldl (fun x y => Expr.app (prepOp.app x) y) a end ExprProcessing @@ -273,7 +280,8 @@ def rankSums (tgt : Expr) (instructions : List (Expr × Bool)) : MetaM (List (Ex let sums ← getOps op (← instantiateMVars tgt) let candidates := sums.map fun (addends, sum) => do let reord := reorderUsing addends.toList instructions - let resummed := sumList (prepareOp sum) reord + let left_assoc? := sum.getAppFn.isConstOf `And || sum.getAppFn.isConstOf `Or + let resummed := sumList (prepareOp sum) left_assoc? reord if (resummed != sum) then some (sum, resummed) else none return (candidates.toList.reduceOption.toArray.qsort (fun x y : Expr × Expr ↦ (y.1.size ≤ x.1.size))).toList diff --git a/Mathlib/Tactic/NormNum/Result.lean b/Mathlib/Tactic/NormNum/Result.lean index 03036c0c5f485..1ae40eff0db16 100644 --- a/Mathlib/Tactic/NormNum/Result.lean +++ b/Mathlib/Tactic/NormNum/Result.lean @@ -194,7 +194,11 @@ A "raw rat cast" is an expression of the form: * `(Nat.rawCast lit : α)` where `lit` is a raw natural number literal * `(Int.rawCast (Int.negOfNat lit) : α)` where `lit` is a nonzero raw natural number literal -* `(Rat.rawCast n d : α)` where `n` is a raw int cast, `d` is a raw nat cast, and `d` is not 1 or 0. +* `(Rat.rawCast n d : α)` where `n` is a raw int literal, `d` is a raw nat literal, and `d` is not + `1` or `0`. + +(where a raw int literal is of the form `Int.ofNat lit` or `Int.negOfNat nzlit` where `lit` is a raw +nat literal) This representation is used by tactics like `ring` to decrease the number of typeclass arguments required in each use of a number literal at type `α`. diff --git a/Mathlib/Tactic/Ring/RingNF.lean b/Mathlib/Tactic/Ring/RingNF.lean index 4e6c06f7f3d1f..fab03e31671c0 100644 --- a/Mathlib/Tactic/Ring/RingNF.lean +++ b/Mathlib/Tactic/Ring/RingNF.lean @@ -119,12 +119,11 @@ theorem add_neg {R} [Ring R] (a b : R) : a + -b = a - b := (sub_eq_add_neg ..).s theorem nat_rawCast_0 : (Nat.rawCast 0 : R) = 0 := by simp theorem nat_rawCast_1 : (Nat.rawCast 1 : R) = 1 := by simp theorem nat_rawCast_2 [Nat.AtLeastTwo n] : (Nat.rawCast n : R) = OfNat.ofNat n := rfl -theorem int_rawCast_1 {R} [Ring R] : (Int.rawCast (.negOfNat 1) : R) = -1 := by - simp [Int.negOfNat_eq] -theorem int_rawCast_2 {R} [Ring R] [Nat.AtLeastTwo n] : - (Int.rawCast (.negOfNat n) : R) = -OfNat.ofNat n := by - simp [Int.negOfNat_eq, OfNat.ofNat] -theorem rat_rawCast_2 {R} [DivisionRing R] : (Rat.rawCast n d : R) = n / d := by simp +theorem int_rawCast_neg {R} [Ring R] : (Int.rawCast (.negOfNat n) : R) = -Nat.rawCast n := by simp +theorem rat_rawCast_pos {R} [DivisionRing R] : + (Rat.rawCast (.ofNat n) d : R) = Nat.rawCast n / Nat.rawCast d := by simp +theorem rat_rawCast_neg {R} [DivisionRing R] : + (Rat.rawCast (.negOfNat n) d : R) = Int.rawCast (.negOfNat n) / Nat.rawCast d := by simp /-- Runs a tactic in the `RingNF.M` monad, given initial data: @@ -138,15 +137,16 @@ partial def M.run (s : IO.Ref AtomM.State) (cfg : RingNF.Config) (x : M α) : MetaM α := do let ctx := { simpTheorems := #[← Elab.Tactic.simpOnlyBuiltins.foldlM (·.addConst ·) {}] - congrTheorems := ← getSimpCongrTheorems } + congrTheorems := ← getSimpCongrTheorems + config.singlePass := cfg.mode matches .raw } let simp ← match cfg.mode with | .raw => pure pure | .SOP => let thms : SimpTheorems := {} let thms ← [``add_zero, ``add_assoc_rev, ``_root_.mul_one, ``mul_assoc_rev, ``_root_.pow_one, ``mul_neg, ``add_neg].foldlM (·.addConst ·) thms - let thms ← [``nat_rawCast_0, ``nat_rawCast_1, ``nat_rawCast_2, ``int_rawCast_1, ``int_rawCast_2, - ``rat_rawCast_2].foldlM (·.addConst · (post := false)) thms + let thms ← [``nat_rawCast_0, ``nat_rawCast_1, ``nat_rawCast_2, ``int_rawCast_neg, + ``rat_rawCast_neg, ``rat_rawCast_pos].foldlM (·.addConst · (post := false)) thms let ctx' := { ctx with simpTheorems := #[thms] } pure fun r' : Simp.Result ↦ do Simp.mkEqTrans r' (← Simp.main r'.expr ctx' (methods := Simp.DefaultMethods.methods)).1 diff --git a/Mathlib/Testing/SlimCheck/Functions.lean b/Mathlib/Testing/SlimCheck/Functions.lean index 16c9564f7353e..9e042dd0ef2f6 100644 --- a/Mathlib/Testing/SlimCheck/Functions.lean +++ b/Mathlib/Testing/SlimCheck/Functions.lean @@ -10,6 +10,7 @@ import Mathlib.Data.Finsupp.ToDFinsupp import Mathlib.Data.LazyList import Mathlib.Testing.SlimCheck.Sampleable import Mathlib.Testing.SlimCheck.Testable +import Std.Data.List.Perm #align_import testing.slim_check.functions from "leanprover-community/mathlib"@"f9c300047a57aeda7c2fe15a3ac2455eb05ec225" @@ -146,8 +147,7 @@ instance Pi.sampleableExt : SampleableExt (α → β) where interp f := SampleableExt.interp ∘ f.apply sample := do let xs : List (_ × _) ← (SampleableExt.sample (α := List (α × β))) - let ⟨x⟩ ← (ULiftable.up <| - SampleableExt.sample : Gen (ULift.{max u ub} (SampleableExt.proxy β))) + let ⟨x⟩ ← ULiftable.up.{max u ub} <| (SampleableExt.sample : Gen (SampleableExt.proxy β)) pure <| TotalFunction.withDefault (List.toFinmap' <| xs.map <| Prod.map SampleableExt.interp id) x -- note: no way of shrinking the domain without an inverse to `interp` @@ -246,6 +246,15 @@ end SampleableExt end TotalFunction +end SlimCheck + +-- We need List perm notation from `List` namespace but can't open `_root_.List` directly, +-- so have to close the `SlimCheck` namespace first. +-- Lean issue: https://github.com/leanprover/lean4/issues/3045 +open List + +namespace SlimCheck + /-- Data structure specifying a total function using a list of pairs and a default value returned when the input is not in the domain of the partial function. diff --git a/Mathlib/Testing/SlimCheck/Gen.lean b/Mathlib/Testing/SlimCheck/Gen.lean index 501fa156ee0fe..1992a955a8455 100644 --- a/Mathlib/Testing/SlimCheck/Gen.lean +++ b/Mathlib/Testing/SlimCheck/Gen.lean @@ -45,11 +45,11 @@ abbrev Gen (α : Type u) := ReaderT (ULift Nat) Rand α namespace Gen /-- Lift `Random.random` to the `Gen` monad. -/ -def chooseAny (α : Type u) [Random α] : Gen α := +def chooseAny (α : Type u) [Random Id α] : Gen α := λ _ => rand α /-- Lift `BoundedRandom.randomR` to the `Gen` monad. -/ -def choose (α : Type u) [Preorder α] [BoundedRandom α] (lo hi : α) (h : lo ≤ hi) : +def choose (α : Type u) [Preorder α] [BoundedRandom Id α] (lo hi : α) (h : lo ≤ hi) : Gen {a // lo ≤ a ∧ a ≤ hi} := λ _ => randBound α lo hi h @@ -78,7 +78,7 @@ variable {α : Type u} /-- Create an `Array` of examples using `x`. The size is controlled by the size parameter of `Gen`. -/ def arrayOf (x : Gen α) : Gen (Array α) := do - let ⟨sz⟩ ← (ULiftable.up <| do choose Nat 0 (← getSize) (Nat.zero_le _) : Gen (ULift ℕ)) + let (⟨sz⟩ : ULift ℕ) ← ULiftable.up do choose Nat 0 (← getSize) (Nat.zero_le _) let mut res := #[] for _ in [0:sz] do res := res.push (← x) @@ -110,15 +110,15 @@ def permutationOf : (xs : List α) → Gen { ys // xs ~ ys } /-- Given two generators produces a tuple consisting out of the result of both -/ def prodOf {α : Type u} {β : Type v} (x : Gen α) (y : Gen β) : Gen (α × β) := do - let ⟨a⟩ ← (ULiftable.up x : Gen (ULift.{max u v} α)) - let ⟨b⟩ ← (ULiftable.up y : Gen (ULift.{max u v} β)) + let ⟨a⟩ ← ULiftable.up.{max u v} x + let ⟨b⟩ ← ULiftable.up.{max u v} y pure (a, b) end Gen /-- Execute a `Gen` inside the `IO` monad using `size` as the example size-/ def Gen.run (x : Gen α) (size : Nat) : BaseIO α := - IO.runRand $ ReaderT.run x ⟨size⟩ - + letI : MonadLift Id BaseIO := ⟨fun f => pure <| Id.run f⟩ + IO.runRand (ReaderT.run x ⟨size⟩:) end SlimCheck diff --git a/Mathlib/Testing/SlimCheck/Testable.lean b/Mathlib/Testing/SlimCheck/Testable.lean index 311e1e5492b08..2309c579d39f2 100644 --- a/Mathlib/Testing/SlimCheck/Testable.lean +++ b/Mathlib/Testing/SlimCheck/Testable.lean @@ -480,6 +480,7 @@ def Testable.runSuite (p : Prop) [Testable p] (cfg : Configuration := {}) : Rand /-- Run a test suite for `p` in `BaseIO` using the global RNG in `stdGenRef`. -/ def Testable.checkIO (p : Prop) [Testable p] (cfg : Configuration := {}) : BaseIO (TestResult p) := + letI : MonadLift Id BaseIO := ⟨fun f => pure <| Id.run f⟩ match cfg.randomSeed with | none => IO.runRand (Testable.runSuite p cfg) | some seed => IO.runRandWith seed (Testable.runSuite p cfg) diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean b/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean index 95ebda29f1eea..b2bf9a0577126 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean @@ -361,7 +361,7 @@ theorem hasSum_sum_disjoint {ι} (s : Finset ι) {t : ι → Set β} {a : ι → (hs : (s : Set ι).Pairwise (Disjoint on t)) (hf : ∀ i ∈ s, HasSum (f ∘ (↑) : t i → α) (a i)) : HasSum (f ∘ (↑) : (⋃ i ∈ s, t i) → α) (∑ i in s, a i) := by simp_rw [hasSum_subtype_iff_indicator] at * - rw [Set.indicator_finset_biUnion _ _ hs] + rw [Finset.indicator_biUnion _ _ hs] exact hasSum_sum hf #align has_sum_sum_disjoint hasSum_sum_disjoint diff --git a/Mathlib/Topology/Algebra/Order/LiminfLimsup.lean b/Mathlib/Topology/Algebra/Order/LiminfLimsup.lean index 79654909e4d9a..6fc5d651befad 100644 --- a/Mathlib/Topology/Algebra/Order/LiminfLimsup.lean +++ b/Mathlib/Topology/Algebra/Order/LiminfLimsup.lean @@ -5,11 +5,11 @@ Authors: Johannes Hölzl, Mario Carneiro, Yury Kudryashov, Yaël Dillies -/ import Mathlib.Algebra.BigOperators.Intervals import Mathlib.Algebra.BigOperators.Order -import Mathlib.Algebra.IndicatorFunction -import Mathlib.Topology.Algebra.Group.Basic +import Mathlib.Algebra.Order.Support import Mathlib.Order.LiminfLimsup import Mathlib.Order.Filter.Archimedean import Mathlib.Order.Filter.CountableInter +import Mathlib.Topology.Algebra.Group.Basic import Mathlib.Topology.Order.Basic #align_import topology.algebra.order.liminf_limsup from "leanprover-community/mathlib"@"ce64cd319bb6b3e82f31c2d38e79080d377be451" diff --git a/Mathlib/Topology/Algebra/Semigroup.lean b/Mathlib/Topology/Algebra/Semigroup.lean index 3edff530b6e16..0d1f978cd890a 100644 --- a/Mathlib/Topology/Algebra/Semigroup.lean +++ b/Mathlib/Topology/Algebra/Semigroup.lean @@ -32,8 +32,7 @@ theorem exists_idempotent_of_compact_t2_of_continuous_mul_left {M} [Nonempty M] It will turn out that any minimal element is `{m}` for an idempotent `m : M`. -/ let S : Set (Set M) := { N | IsClosed N ∧ N.Nonempty ∧ ∀ (m) (_ : m ∈ N) (m') (_ : m' ∈ N), m * m' ∈ N } - obtain ⟨N, ⟨N_closed, ⟨m, hm⟩, N_mul⟩, N_minimal⟩ : ∃ N ∈ S, ∀ N' ∈ S, N' ⊆ N → N' = N - rotate_left -- Porting note: restore to `rsuffices` + rsuffices ⟨N, ⟨N_closed, ⟨m, hm⟩, N_mul⟩, N_minimal⟩ : ∃ N ∈ S, ∀ N' ∈ S, N' ⊆ N → N' = N · use m /- We now have an element `m : M` of a minimal subsemigroup `N`, and want to show `m + m = m`. We first show that every element of `N` is of the form `m' + m`.-/ diff --git a/Mathlib/Topology/Basic.lean b/Mathlib/Topology/Basic.lean index cc50d82071bce..b81a2a4d7c5bb 100644 --- a/Mathlib/Topology/Basic.lean +++ b/Mathlib/Topology/Basic.lean @@ -3,9 +3,9 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro, Jeremy Avigad -/ -import Mathlib.Order.Filter.Ultrafilter -import Mathlib.Algebra.Support +import Mathlib.Algebra.Function.Support import Mathlib.Order.Filter.Lift +import Mathlib.Order.Filter.Ultrafilter import Mathlib.Tactic.Continuity #align_import topology.basic from "leanprover-community/mathlib"@"e354e865255654389cc46e6032160238df2e0f40" diff --git a/Mathlib/Topology/ContinuousOn.lean b/Mathlib/Topology/ContinuousOn.lean index 16845e5ea41af..72946fc5e3eba 100644 --- a/Mathlib/Topology/ContinuousOn.lean +++ b/Mathlib/Topology/ContinuousOn.lean @@ -3,7 +3,7 @@ Copyright (c) 2019 Reid Barton. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ -import Mathlib.Algebra.IndicatorFunction +import Mathlib.Algebra.Function.Indicator import Mathlib.Topology.Constructions #align_import topology.continuous_on from "leanprover-community/mathlib"@"d4f691b9e5f94cfc64639973f3544c95f8d5d494" diff --git a/Mathlib/Topology/Covering.lean b/Mathlib/Topology/Covering.lean index 032667d3d27f9..f27bfd29adedc 100644 --- a/Mathlib/Topology/Covering.lean +++ b/Mathlib/Topology/Covering.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Thomas Browning. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Thomas Browning -/ -import Mathlib.Topology.IsLocallyHomeomorph +import Mathlib.Topology.IsLocalHomeomorph import Mathlib.Topology.FiberBundle.Basic #align_import topology.covering from "leanprover-community/mathlib"@"e473c3198bb41f68560cab68a0529c854b618833" @@ -55,7 +55,7 @@ theorem toTrivialization_apply {x : E} {I : Type*} [TopologicalSpace I] let h := Classical.choose_spec h.2 let he := e.mk_proj_snd' h Subtype.ext - ((e.toLocalEquiv.eq_symm_apply (e.mem_source.mpr h) + ((e.toPartialEquiv.eq_symm_apply (e.mem_source.mpr h) (by rwa [he, e.mem_target, e.coe_fst (e.mem_source.mpr h)])).mpr he.symm).symm #align is_evenly_covered.to_trivialization_apply IsEvenlyCovered.toTrivialization_apply @@ -101,14 +101,14 @@ protected theorem continuousOn (hf : IsCoveringMapOn f s) : ContinuousOn f (f ContinuousAt.continuousOn fun _ => hf.continuousAt #align is_covering_map_on.continuous_on IsCoveringMapOn.continuousOn -protected theorem isLocallyHomeomorphOn (hf : IsCoveringMapOn f s) : - IsLocallyHomeomorphOn f (f ⁻¹' s) := by - refine' IsLocallyHomeomorphOn.mk f (f ⁻¹' s) fun x hx => _ +protected theorem isLocalHomeomorphOn (hf : IsCoveringMapOn f s) : + IsLocalHomeomorphOn f (f ⁻¹' s) := by + refine' IsLocalHomeomorphOn.mk f (f ⁻¹' s) fun x hx => _ let e := (hf (f x) hx).toTrivialization have h := (hf (f x) hx).mem_toTrivialization_baseSet let he := e.mem_source.2 h refine' - ⟨e.toLocalHomeomorph.trans + ⟨e.toPartialHomeomorph.trans { toFun := fun p => p.1 invFun := fun p => ⟨p, x, rfl⟩ source := e.baseSet ×ˢ ({⟨x, rfl⟩} : Set (f ⁻¹' {f x})) @@ -122,10 +122,10 @@ protected theorem isLocallyHomeomorphOn (hf : IsCoveringMapOn f s) : right_inv' := fun p _ => rfl continuousOn_toFun := continuous_fst.continuousOn continuousOn_invFun := (continuous_id'.prod_mk continuous_const).continuousOn }, - ⟨he, by rwa [e.toLocalHomeomorph.symm_symm, e.proj_toFun x he], + ⟨he, by rwa [e.toPartialHomeomorph.symm_symm, e.proj_toFun x he], (hf (f x) hx).toTrivialization_apply⟩, fun p h => (e.proj_toFun p h.1).symm⟩ -#align is_covering_map_on.is_locally_homeomorph_on IsCoveringMapOn.isLocallyHomeomorphOn +#align is_covering_map_on.is_locally_homeomorph_on IsCoveringMapOn.isLocalHomeomorphOn end IsCoveringMapOn @@ -162,12 +162,12 @@ protected theorem continuous : Continuous f := continuous_iff_continuousOn_univ.mpr hf.isCoveringMapOn.continuousOn #align is_covering_map.continuous IsCoveringMap.continuous -protected theorem isLocallyHomeomorph : IsLocallyHomeomorph f := - isLocallyHomeomorph_iff_isLocallyHomeomorphOn_univ.mpr hf.isCoveringMapOn.isLocallyHomeomorphOn -#align is_covering_map.is_locally_homeomorph IsCoveringMap.isLocallyHomeomorph +protected theorem isLocalHomeomorph : IsLocalHomeomorph f := + isLocalHomeomorph_iff_isLocalHomeomorphOn_univ.mpr hf.isCoveringMapOn.isLocalHomeomorphOn +#align is_covering_map.is_locally_homeomorph IsCoveringMap.isLocalHomeomorph protected theorem isOpenMap : IsOpenMap f := - hf.isLocallyHomeomorph.isOpenMap + hf.isLocalHomeomorph.isOpenMap #align is_covering_map.is_open_map IsCoveringMap.isOpenMap protected theorem quotientMap (hf' : Function.Surjective f) : QuotientMap f := @@ -190,20 +190,20 @@ variable {A} [TopologicalSpace A] {s : Set A} (hs : IsPreconnected s) {g g₁ g theorem eq_of_comp_eq [PreconnectedSpace A] (h₁ : Continuous g₁) (h₂ : Continuous g₂) (he : f ∘ g₁ = f ∘ g₂) (a : A) (ha : g₁ a = g₂ a) : g₁ = g₂ := - hf.isSeparatedMap.eq_of_comp_eq hf.isLocallyHomeomorph.isLocallyInjective h₁ h₂ he a ha + hf.isSeparatedMap.eq_of_comp_eq hf.isLocalHomeomorph.isLocallyInjective h₁ h₂ he a ha theorem eqOn_of_comp_eqOn (h₁ : ContinuousOn g₁ s) (h₂ : ContinuousOn g₂ s) (he : s.EqOn (f ∘ g₁) (f ∘ g₂)) {a : A} (has : a ∈ s) (ha : g₁ a = g₂ a) : s.EqOn g₁ g₂ := - hf.isSeparatedMap.eqOn_of_comp_eqOn hf.isLocallyHomeomorph.isLocallyInjective hs h₁ h₂ he has ha + hf.isSeparatedMap.eqOn_of_comp_eqOn hf.isLocalHomeomorph.isLocallyInjective hs h₁ h₂ he has ha theorem const_of_comp [PreconnectedSpace A] (cont : Continuous g) (he : ∀ a a', f (g a) = f (g a')) (a a') : g a = g a' := - hf.isSeparatedMap.const_of_comp hf.isLocallyHomeomorph.isLocallyInjective cont he a a' + hf.isSeparatedMap.const_of_comp hf.isLocalHomeomorph.isLocallyInjective cont he a a' theorem constOn_of_comp (cont : ContinuousOn g s) (he : ∀ a ∈ s, ∀ a' ∈ s, f (g a) = f (g a')) {a a'} (ha : a ∈ s) (ha' : a' ∈ s) : g a = g a' := - hf.isSeparatedMap.constOn_of_comp hf.isLocallyHomeomorph.isLocallyInjective hs cont he ha ha' + hf.isSeparatedMap.constOn_of_comp hf.isLocalHomeomorph.isLocallyInjective hs cont he ha ha' end IsCoveringMap diff --git a/Mathlib/Topology/FiberBundle/Basic.lean b/Mathlib/Topology/FiberBundle/Basic.lean index 64394bf49d6ee..d95f99bad8467 100644 --- a/Mathlib/Topology/FiberBundle/Basic.lean +++ b/Mathlib/Topology/FiberBundle/Basic.lean @@ -353,9 +353,8 @@ theorem FiberBundle.exists_trivialization_Icc_subset [ConditionallyCompleteLinea `d ∈ (c, b]`, hence `c` is not an upper bound of `s`. -/ cases' hc.2.eq_or_lt with heq hlt · exact ⟨ec, heq ▸ hec⟩ - suffices : ∃ d ∈ Ioc c b, ∃ e : Trivialization F (π F E), Icc a d ⊆ e.baseSet - · rcases this with ⟨d, hdcb, hd⟩ -- porting note: todo: use `rsuffices` - exact ((hsc.1 ⟨⟨hc.1.trans hdcb.1.le, hdcb.2⟩, hd⟩).not_lt hdcb.1).elim + rsuffices ⟨d, hdcb, hd⟩ : ∃ d ∈ Ioc c b, ∃ e : Trivialization F (π F E), Icc a d ⊆ e.baseSet + · exact ((hsc.1 ⟨⟨hc.1.trans hdcb.1.le, hdcb.2⟩, hd⟩).not_lt hdcb.1).elim /- Since the base set of `ec` is open, it includes `[c, d)` (hence, `[a, d)`) for some `d ∈ (c, b]`. -/ obtain ⟨d, hdcb, hd⟩ : ∃ d ∈ Ioc c b, Ico c d ⊆ ec.baseSet := @@ -444,7 +443,7 @@ def proj : Z.TotalSpace → B := #align fiber_bundle_core.proj FiberBundleCore.proj /-- Local homeomorphism version of the trivialization change. -/ -def trivChange (i j : ι) : LocalHomeomorph (B × F) (B × F) where +def trivChange (i j : ι) : PartialHomeomorph (B × F) (B × F) where source := (Z.baseSet i ∩ Z.baseSet j) ×ˢ univ target := (Z.baseSet i ∩ Z.baseSet j) ×ˢ univ toFun p := ⟨p.1, Z.coordChange i j p.1 p.2⟩ @@ -483,10 +482,9 @@ between `proj ⁻¹ (baseSet i)` and `baseSet i × F`. As the fiber above `x` is chart with index `index_at x`, the trivialization in the fiber above x is by definition the coordinate change from i to `index_at x`, so it depends on `x`. The local trivialization will ultimately be a local homeomorphism. For now, we only introduce the -local equiv version, denoted with a prime. In further developments, avoid this auxiliary version, -and use `Z.local_triv` instead. --/ -def localTrivAsLocalEquiv (i : ι) : LocalEquiv Z.TotalSpace (B × F) where +partial equivalence version, denoted with a prime. +In further developments, avoid this auxiliary version, and use `Z.local_triv` instead. -/ +def localTrivAsPartialEquiv (i : ι) : PartialEquiv Z.TotalSpace (B × F) where source := Z.proj ⁻¹' Z.baseSet i target := Z.baseSet i ×ˢ univ invFun p := ⟨p.1, Z.coordChange i (Z.indexAt p.1) p.1 p.2⟩ @@ -506,58 +504,58 @@ def localTrivAsLocalEquiv (i : ι) : LocalEquiv Z.TotalSpace (B × F) where dsimp only rw [Z.coordChange_comp, Z.coordChange_self] exacts [hx, ⟨⟨hx, Z.mem_baseSet_at _⟩, hx⟩] -#align fiber_bundle_core.local_triv_as_local_equiv FiberBundleCore.localTrivAsLocalEquiv +#align fiber_bundle_core.local_triv_as_local_equiv FiberBundleCore.localTrivAsPartialEquiv variable (i : ι) -theorem mem_localTrivAsLocalEquiv_source (p : Z.TotalSpace) : - p ∈ (Z.localTrivAsLocalEquiv i).source ↔ p.1 ∈ Z.baseSet i := +theorem mem_localTrivAsPartialEquiv_source (p : Z.TotalSpace) : + p ∈ (Z.localTrivAsPartialEquiv i).source ↔ p.1 ∈ Z.baseSet i := Iff.rfl -#align fiber_bundle_core.mem_local_triv_as_local_equiv_source FiberBundleCore.mem_localTrivAsLocalEquiv_source +#align fiber_bundle_core.mem_local_triv_as_local_equiv_source FiberBundleCore.mem_localTrivAsPartialEquiv_source -theorem mem_localTrivAsLocalEquiv_target (p : B × F) : - p ∈ (Z.localTrivAsLocalEquiv i).target ↔ p.1 ∈ Z.baseSet i := by +theorem mem_localTrivAsPartialEquiv_target (p : B × F) : + p ∈ (Z.localTrivAsPartialEquiv i).target ↔ p.1 ∈ Z.baseSet i := by erw [mem_prod] simp only [and_true_iff, mem_univ] -#align fiber_bundle_core.mem_local_triv_as_local_equiv_target FiberBundleCore.mem_localTrivAsLocalEquiv_target +#align fiber_bundle_core.mem_local_triv_as_local_equiv_target FiberBundleCore.mem_localTrivAsPartialEquiv_target -theorem localTrivAsLocalEquiv_apply (p : Z.TotalSpace) : - (Z.localTrivAsLocalEquiv i) p = ⟨p.1, Z.coordChange (Z.indexAt p.1) i p.1 p.2⟩ := +theorem localTrivAsPartialEquiv_apply (p : Z.TotalSpace) : + (Z.localTrivAsPartialEquiv i) p = ⟨p.1, Z.coordChange (Z.indexAt p.1) i p.1 p.2⟩ := rfl -#align fiber_bundle_core.local_triv_as_local_equiv_apply FiberBundleCore.localTrivAsLocalEquiv_apply +#align fiber_bundle_core.local_triv_as_local_equiv_apply FiberBundleCore.localTrivAsPartialEquiv_apply /-- The composition of two local trivializations is the trivialization change Z.triv_change i j. -/ -theorem localTrivAsLocalEquiv_trans (i j : ι) : - (Z.localTrivAsLocalEquiv i).symm.trans (Z.localTrivAsLocalEquiv j) ≈ - (Z.trivChange i j).toLocalEquiv := by +theorem localTrivAsPartialEquiv_trans (i j : ι) : + (Z.localTrivAsPartialEquiv i).symm.trans (Z.localTrivAsPartialEquiv j) ≈ + (Z.trivChange i j).toPartialEquiv := by constructor · ext x - simp only [mem_localTrivAsLocalEquiv_target, mfld_simps] + simp only [mem_localTrivAsPartialEquiv_target, mfld_simps] rfl · rintro ⟨x, v⟩ hx - simp only [trivChange, localTrivAsLocalEquiv, LocalEquiv.symm, true_and_iff, - Prod.mk.inj_iff, prod_mk_mem_set_prod_eq, LocalEquiv.trans_source, mem_inter_iff, + simp only [trivChange, localTrivAsPartialEquiv, PartialEquiv.symm, true_and_iff, + Prod.mk.inj_iff, prod_mk_mem_set_prod_eq, PartialEquiv.trans_source, mem_inter_iff, and_true_iff, mem_preimage, proj, mem_univ, eq_self_iff_true, (· ∘ ·), - LocalEquiv.coe_trans, TotalSpace.proj] at hx ⊢ + PartialEquiv.coe_trans, TotalSpace.proj] at hx ⊢ simp only [Z.coordChange_comp, hx, mem_inter_iff, and_self_iff, mem_baseSet_at] -#align fiber_bundle_core.local_triv_as_local_equiv_trans FiberBundleCore.localTrivAsLocalEquiv_trans +#align fiber_bundle_core.local_triv_as_local_equiv_trans FiberBundleCore.localTrivAsPartialEquiv_trans /-- Topological structure on the total space of a fiber bundle created from core, designed so that all the local trivialization are continuous. -/ instance toTopologicalSpace : TopologicalSpace (Bundle.TotalSpace F Z.Fiber) := TopologicalSpace.generateFrom <| ⋃ (i : ι) (s : Set (B × F)) (_ : IsOpen s), - {(Z.localTrivAsLocalEquiv i).source ∩ Z.localTrivAsLocalEquiv i ⁻¹' s} + {(Z.localTrivAsPartialEquiv i).source ∩ Z.localTrivAsPartialEquiv i ⁻¹' s} #align fiber_bundle_core.to_topological_space FiberBundleCore.toTopologicalSpace variable (b : B) (a : F) -theorem open_source' (i : ι) : IsOpen (Z.localTrivAsLocalEquiv i).source := by +theorem open_source' (i : ι) : IsOpen (Z.localTrivAsPartialEquiv i).source := by apply TopologicalSpace.GenerateOpen.basic simp only [exists_prop, mem_iUnion, mem_singleton_iff] refine ⟨i, Z.baseSet i ×ˢ univ, (Z.isOpen_baseSet i).prod isOpen_univ, ?_⟩ ext p - simp only [localTrivAsLocalEquiv_apply, prod_mk_mem_set_prod_eq, mem_inter_iff, and_self_iff, - mem_localTrivAsLocalEquiv_source, and_true, mem_univ, mem_preimage] + simp only [localTrivAsPartialEquiv_apply, prod_mk_mem_set_prod_eq, mem_inter_iff, and_self_iff, + mem_localTrivAsPartialEquiv_source, and_true, mem_univ, mem_preimage] #align fiber_bundle_core.open_source' FiberBundleCore.open_source' /-- Extended version of the local trivialization of a fiber bundle constructed from core, @@ -582,20 +580,20 @@ def localTriv (i : ι) : Trivialization F Z.proj where refine continuousOn_isOpen_of_generateFrom fun t ht ↦ ?_ simp only [exists_prop, mem_iUnion, mem_singleton_iff] at ht obtain ⟨j, s, s_open, ts⟩ : ∃ j s, IsOpen s ∧ - t = (localTrivAsLocalEquiv Z j).source ∩ localTrivAsLocalEquiv Z j ⁻¹' s := ht + t = (localTrivAsPartialEquiv Z j).source ∩ localTrivAsPartialEquiv Z j ⁻¹' s := ht rw [ts] - simp only [LocalEquiv.right_inv, preimage_inter, LocalEquiv.left_inv] - let e := Z.localTrivAsLocalEquiv i - let e' := Z.localTrivAsLocalEquiv j + simp only [PartialEquiv.right_inv, preimage_inter, PartialEquiv.left_inv] + let e := Z.localTrivAsPartialEquiv i + let e' := Z.localTrivAsPartialEquiv j let f := e.symm.trans e' have : IsOpen (f.source ∩ f ⁻¹' s) := by - rw [LocalEquiv.EqOnSource.source_inter_preimage_eq (Z.localTrivAsLocalEquiv_trans i j)] + rw [PartialEquiv.EqOnSource.source_inter_preimage_eq (Z.localTrivAsPartialEquiv_trans i j)] exact (continuousOn_open_iff (Z.trivChange i j).open_source).1 (Z.trivChange i j).continuousOn _ s_open convert this using 1 - dsimp [LocalEquiv.trans_source] + dsimp [PartialEquiv.trans_source] rw [← preimage_comp, inter_assoc] - toLocalEquiv := Z.localTrivAsLocalEquiv i + toPartialEquiv := Z.localTrivAsPartialEquiv i #align fiber_bundle_core.local_triv FiberBundleCore.localTriv /-- Preferred local trivialization of a fiber bundle constructed from core, at a given point, as @@ -623,7 +621,7 @@ theorem continuous_const_section (v : F) refine continuous_iff_continuousAt.2 fun x => ?_ have A : Z.baseSet (Z.indexAt x) ∈ 𝓝 x := IsOpen.mem_nhds (Z.isOpen_baseSet (Z.indexAt x)) (Z.mem_baseSet_at x) - refine ((Z.localTrivAt x).toLocalHomeomorph.continuousAt_iff_continuousAt_comp_left ?_).2 ?_ + refine ((Z.localTrivAt x).toPartialHomeomorph.continuousAt_iff_continuousAt_comp_left ?_).2 ?_ · exact A · apply continuousAt_id.prod simp only [(· ∘ ·), mfld_simps, localTrivAt_snd] @@ -633,27 +631,27 @@ theorem continuous_const_section (v : F) #align fiber_bundle_core.continuous_const_section FiberBundleCore.continuous_const_section @[simp, mfld_simps] -theorem localTrivAsLocalEquiv_coe : ⇑(Z.localTrivAsLocalEquiv i) = Z.localTriv i := +theorem localTrivAsPartialEquiv_coe : ⇑(Z.localTrivAsPartialEquiv i) = Z.localTriv i := rfl -#align fiber_bundle_core.local_triv_as_local_equiv_coe FiberBundleCore.localTrivAsLocalEquiv_coe +#align fiber_bundle_core.local_triv_as_local_equiv_coe FiberBundleCore.localTrivAsPartialEquiv_coe @[simp, mfld_simps] -theorem localTrivAsLocalEquiv_source : - (Z.localTrivAsLocalEquiv i).source = (Z.localTriv i).source := +theorem localTrivAsPartialEquiv_source : + (Z.localTrivAsPartialEquiv i).source = (Z.localTriv i).source := rfl -#align fiber_bundle_core.local_triv_as_local_equiv_source FiberBundleCore.localTrivAsLocalEquiv_source +#align fiber_bundle_core.local_triv_as_local_equiv_source FiberBundleCore.localTrivAsPartialEquiv_source @[simp, mfld_simps] -theorem localTrivAsLocalEquiv_target : - (Z.localTrivAsLocalEquiv i).target = (Z.localTriv i).target := +theorem localTrivAsPartialEquiv_target : + (Z.localTrivAsPartialEquiv i).target = (Z.localTriv i).target := rfl -#align fiber_bundle_core.local_triv_as_local_equiv_target FiberBundleCore.localTrivAsLocalEquiv_target +#align fiber_bundle_core.local_triv_as_local_equiv_target FiberBundleCore.localTrivAsPartialEquiv_target @[simp, mfld_simps] -theorem localTrivAsLocalEquiv_symm : - (Z.localTrivAsLocalEquiv i).symm = (Z.localTriv i).toLocalEquiv.symm := +theorem localTrivAsPartialEquiv_symm : + (Z.localTrivAsPartialEquiv i).symm = (Z.localTriv i).toPartialEquiv.symm := rfl -#align fiber_bundle_core.local_triv_as_local_equiv_symm FiberBundleCore.localTrivAsLocalEquiv_symm +#align fiber_bundle_core.local_triv_as_local_equiv_symm FiberBundleCore.localTrivAsPartialEquiv_symm @[simp, mfld_simps] theorem baseSet_at : Z.baseSet i = (Z.localTriv i).baseSet := @@ -703,7 +701,7 @@ theorem mem_localTrivAt_target (p : B × F) (b : B) : @[simp, mfld_simps] theorem localTriv_symm_apply (p : B × F) : - (Z.localTriv i).toLocalHomeomorph.symm p = ⟨p.1, Z.coordChange i (Z.indexAt p.1) p.1 p.2⟩ := + (Z.localTriv i).toPartialHomeomorph.symm p = ⟨p.1, Z.coordChange i (Z.indexAt p.1) p.1 p.2⟩ := rfl #align fiber_bundle_core.local_triv_symm_apply FiberBundleCore.localTriv_symm_apply @@ -770,7 +768,7 @@ structure FiberPrebundle where mem_base_pretrivializationAt : ∀ x : B, x ∈ (pretrivializationAt x).baseSet pretrivialization_mem_atlas : ∀ x : B, pretrivializationAt x ∈ pretrivializationAtlas continuous_trivChange : ∀ e, e ∈ pretrivializationAtlas → ∀ e', e' ∈ pretrivializationAtlas → - ContinuousOn (e ∘ e'.toLocalEquiv.symm) (e'.target ∩ e'.toLocalEquiv.symm ⁻¹' e.source) + ContinuousOn (e ∘ e'.toPartialEquiv.symm) (e'.target ∩ e'.toPartialEquiv.symm ⁻¹' e.source) totalSpaceMk_inducing : ∀ b : B, Inducing (pretrivializationAt b ∘ TotalSpace.mk b) #align fiber_prebundle FiberPrebundle @@ -786,7 +784,7 @@ def totalSpaceTopology (a : FiberPrebundle F E) : TopologicalSpace (TotalSpace F #align fiber_prebundle.total_space_topology FiberPrebundle.totalSpaceTopology theorem continuous_symm_of_mem_pretrivializationAtlas (he : e ∈ a.pretrivializationAtlas) : - @ContinuousOn _ _ _ a.totalSpaceTopology e.toLocalEquiv.symm e.target := by + @ContinuousOn _ _ _ a.totalSpaceTopology e.toPartialEquiv.symm e.target := by refine' fun z H U h => preimage_nhdsWithin_coinduced' H (le_def.1 (nhds_mono _) U h) exact le_iSup₂ (α := TopologicalSpace (TotalSpace F E)) e he #align fiber_prebundle.continuous_symm_of_mem_pretrivialization_atlas FiberPrebundle.continuous_symm_of_mem_pretrivializationAtlas @@ -802,7 +800,7 @@ theorem isOpen_source (e : Pretrivialization F (π F E)) : theorem isOpen_target_of_mem_pretrivializationAtlas_inter (e e' : Pretrivialization F (π F E)) (he' : e' ∈ a.pretrivializationAtlas) : - IsOpen (e'.toLocalEquiv.target ∩ e'.toLocalEquiv.symm ⁻¹' e.source) := by + IsOpen (e'.toPartialEquiv.target ∩ e'.toPartialEquiv.symm ⁻¹' e.source) := by letI := a.totalSpaceTopology obtain ⟨u, hu1, hu2⟩ := continuousOn_iff'.mp (a.continuous_symm_of_mem_pretrivializationAtlas he') e.source (a.isOpen_source e) @@ -824,7 +822,7 @@ def trivializationOfMemPretrivializationAtlas (he : e ∈ a.pretrivializationAtl obtain ⟨u, hu1, hu2⟩ := continuousOn_iff'.mp (a.continuous_trivChange _ he _ he') s hs have hu3 := congr_arg (fun s => (fun x : e'.target => (x : B × F)) ⁻¹' s) hu2 simp only [Subtype.coe_preimage_self, preimage_inter, univ_inter] at hu3 - refine ⟨u ∩ e'.toLocalEquiv.target ∩ e'.toLocalEquiv.symm ⁻¹' e.source, ?_, by + refine ⟨u ∩ e'.toPartialEquiv.target ∩ e'.toPartialEquiv.symm ⁻¹' e.source, ?_, by simp only [preimage_inter, inter_univ, Subtype.coe_preimage_self, hu3.symm]; rfl⟩ rw [inter_assoc] exact hu1.inter (a.isOpen_target_of_mem_pretrivializationAtlas_inter e e' he') @@ -848,7 +846,7 @@ theorem continuous_totalSpaceMk (b : B) : Continuous[_, a.totalSpaceTopology] (TotalSpace.mk b) := by letI := a.totalSpaceTopology let e := a.trivializationOfMemPretrivializationAtlas (a.pretrivialization_mem_atlas b) - rw [e.toLocalHomeomorph.continuous_iff_continuous_comp_left + rw [e.toPartialHomeomorph.continuous_iff_continuous_comp_left (a.totalSpaceMk_preimage_source b)] exact continuous_iff_le_induced.mpr (le_antisymm_iff.mp (a.totalSpaceMk_inducing b).induced).1 #align fiber_prebundle.continuous_total_space_mk FiberPrebundle.continuous_totalSpaceMk @@ -900,7 +898,7 @@ continuity of a function `TotalSpace F E → X` on an open set `s` can be checke each point with the pretrivialization used for the construction at that point. -/ theorem continuousOn_of_comp_right {X : Type*} [TopologicalSpace X] {f : TotalSpace F E → X} {s : Set B} (hs : IsOpen s) (hf : ∀ b ∈ s, - ContinuousOn (f ∘ (a.pretrivializationAt b).toLocalEquiv.symm) + ContinuousOn (f ∘ (a.pretrivializationAt b).toPartialEquiv.symm) ((s ∩ (a.pretrivializationAt b).baseSet) ×ˢ (Set.univ : Set F))) : @ContinuousOn _ _ a.totalSpaceTopology _ f (π F E ⁻¹' s) := by letI := a.totalSpaceTopology diff --git a/Mathlib/Topology/FiberBundle/Constructions.lean b/Mathlib/Topology/FiberBundle/Constructions.lean index b279d4cde31c6..d2401793d34bb 100644 --- a/Mathlib/Topology/FiberBundle/Constructions.lean +++ b/Mathlib/Topology/FiberBundle/Constructions.lean @@ -60,7 +60,7 @@ def homeomorphProd : TotalSpace F (Trivial B F) ≃ₜ B × F := /-- Local trivialization for trivial bundle. -/ def trivialization : Trivialization F (π F (Bundle.Trivial B F)) where -- porting note: golfed - toLocalHomeomorph := (homeomorphProd B F).toLocalHomeomorph + toPartialHomeomorph := (homeomorphProd B F).toPartialHomeomorph baseSet := univ open_baseSet := isOpen_univ source_eq := rfl @@ -153,7 +153,7 @@ theorem Prod.continuous_to_fun : ContinuousOn (Prod.toFun' e₁ e₂) let f₃ : (B × F₁) × B × F₂ → B × F₁ × F₂ := fun p ↦ ⟨p.1.1, p.1.2, p.2.2⟩ have hf₁ : Continuous f₁ := (Prod.inducing_diag F₁ E₁ F₂ E₂).continuous have hf₂ : ContinuousOn f₂ (e₁.source ×ˢ e₂.source) := - e₁.toLocalHomeomorph.continuousOn.prod_map e₂.toLocalHomeomorph.continuousOn + e₁.toPartialHomeomorph.continuousOn.prod_map e₂.toPartialHomeomorph.continuousOn have hf₃ : Continuous f₃ := (continuous_fst.comp continuous_fst).prod_mk (continuous_snd.prod_map continuous_snd) refine' ((hf₃.comp_continuousOn hf₂).comp hf₁.continuousOn _).congr _ @@ -236,7 +236,7 @@ theorem baseSet_prod : (prod e₁ e₂).baseSet = e₁.baseSet ∩ e₂.baseSet #align trivialization.base_set_prod Trivialization.baseSet_prod theorem prod_symm_apply (x : B) (w₁ : F₁) (w₂ : F₂) : - (prod e₁ e₂).toLocalEquiv.symm (x, w₁, w₂) = ⟨x, e₁.symm x w₁, e₂.symm x w₂⟩ := rfl + (prod e₁ e₂).toPartialEquiv.symm (x, w₁, w₂) = ⟨x, e₁.symm x w₁, e₂.symm x w₂⟩ := rfl #align trivialization.prod_symm_apply Trivialization.prod_symm_apply end Trivialization diff --git a/Mathlib/Topology/FiberBundle/Trivialization.lean b/Mathlib/Topology/FiberBundle/Trivialization.lean index ae8f2f643d730..e5ec9d3cf64f8 100644 --- a/Mathlib/Topology/FiberBundle/Trivialization.lean +++ b/Mathlib/Topology/FiberBundle/Trivialization.lean @@ -5,7 +5,7 @@ Authors: Sébastien Gouëzel -/ import Mathlib.Data.Bundle import Mathlib.Topology.Algebra.Order.Field -import Mathlib.Topology.LocalHomeomorph +import Mathlib.Topology.PartialHomeomorph #align_import topology.fiber_bundle.trivialization from "leanprover-community/mathlib"@"e473c3198bb41f68560cab68a0529c854b618833" @@ -64,7 +64,7 @@ below as `Trivialization F proj`) if the total space has not been given a topolo have a topology on both the fiber and the base space. Through the construction `topological_fiber_prebundle F proj` it will be possible to promote a `Pretrivialization F proj` to a `Trivialization F proj`. -/ -structure Pretrivialization (proj : Z → B) extends LocalEquiv Z (B × F) where +structure Pretrivialization (proj : Z → B) extends PartialEquiv Z (B × F) where open_target : IsOpen target baseSet : Set B open_baseSet : IsOpen baseSet @@ -79,37 +79,37 @@ variable {F} variable (e : Pretrivialization F proj) {x : Z} /-- Coercion of a pretrivialization to a function. We don't use `e.toFun` in the `CoeFun` instance -because it is actually `e.toLocalEquiv.toFun`, so `simp` will apply lemmas about -`toLocalEquiv`. While we may want to switch to this behavior later, doing it mid-port will break a +because it is actually `e.toPartialEquiv.toFun`, so `simp` will apply lemmas about +`toPartialEquiv`. While we may want to switch to this behavior later, doing it mid-port will break a lot of proofs. -/ @[coe] def toFun' : Z → (B × F) := e.toFun instance : CoeFun (Pretrivialization F proj) fun _ => Z → B × F := ⟨toFun'⟩ @[ext] -lemma ext' (e e' : Pretrivialization F proj) (h₁ : e.toLocalEquiv = e'.toLocalEquiv) +lemma ext' (e e' : Pretrivialization F proj) (h₁ : e.toPartialEquiv = e'.toPartialEquiv) (h₂ : e.baseSet = e'.baseSet) : e = e' := by cases e; cases e'; congr #align pretrivialization.ext Pretrivialization.ext' -- porting note: todo: move `ext` here? lemma ext {e e' : Pretrivialization F proj} (h₁ : ∀ x, e x = e' x) - (h₂ : ∀ x, e.toLocalEquiv.symm x = e'.toLocalEquiv.symm x) (h₃ : e.baseSet = e'.baseSet) : + (h₂ : ∀ x, e.toPartialEquiv.symm x = e'.toPartialEquiv.symm x) (h₃ : e.baseSet = e'.baseSet) : e = e' := by ext1 <;> [ext1; exact h₃] · apply h₁ · apply h₂ · rw [e.source_eq, e'.source_eq, h₃] -/-- If the fiber is nonempty, then the projection to -/ -lemma toLocalEquiv_injective [Nonempty F] : - Injective (toLocalEquiv : Pretrivialization F proj → LocalEquiv Z (B × F)) := fun e e' h => by - refine ext' _ _ h ?_ +/-- If the fiber is nonempty, then the projection also is. -/ +lemma toPartialEquiv_injective [Nonempty F] : + Injective (toPartialEquiv : Pretrivialization F proj → PartialEquiv Z (B × F)) := by + refine fun e e' h ↦ ext' _ _ h ?_ simpa only [fst_image_prod, univ_nonempty, target_eq] - using congr_arg (Prod.fst '' LocalEquiv.target ·) h + using congr_arg (Prod.fst '' PartialEquiv.target ·) h @[simp, mfld_simps] -theorem coe_coe : ⇑e.toLocalEquiv = e := +theorem coe_coe : ⇑e.toPartialEquiv = e := rfl #align pretrivialization.coe_coe Pretrivialization.coe_coe @@ -138,91 +138,91 @@ theorem mk_proj_snd' (ex : proj x ∈ e.baseSet) : (proj x, (e x).2) = e x := /-- Composition of inverse and coercion from the subtype of the target. -/ def setSymm : e.target → Z := - e.target.restrict e.toLocalEquiv.symm + e.target.restrict e.toPartialEquiv.symm #align pretrivialization.set_symm Pretrivialization.setSymm theorem mem_target {x : B × F} : x ∈ e.target ↔ x.1 ∈ e.baseSet := by rw [e.target_eq, prod_univ, mem_preimage] #align pretrivialization.mem_target Pretrivialization.mem_target -theorem proj_symm_apply {x : B × F} (hx : x ∈ e.target) : proj (e.toLocalEquiv.symm x) = x.1 := by +theorem proj_symm_apply {x : B × F} (hx : x ∈ e.target) : proj (e.toPartialEquiv.symm x) = x.1 := by have := (e.coe_fst (e.map_target hx)).symm rwa [← e.coe_coe, e.right_inv hx] at this #align pretrivialization.proj_symm_apply Pretrivialization.proj_symm_apply theorem proj_symm_apply' {b : B} {x : F} (hx : b ∈ e.baseSet) : - proj (e.toLocalEquiv.symm (b, x)) = b := + proj (e.toPartialEquiv.symm (b, x)) = b := e.proj_symm_apply (e.mem_target.2 hx) #align pretrivialization.proj_symm_apply' Pretrivialization.proj_symm_apply' theorem proj_surjOn_baseSet [Nonempty F] : Set.SurjOn proj e.source e.baseSet := fun b hb => let ⟨y⟩ := ‹Nonempty F› - ⟨e.toLocalEquiv.symm (b, y), e.toLocalEquiv.map_target <| e.mem_target.2 hb, + ⟨e.toPartialEquiv.symm (b, y), e.toPartialEquiv.map_target <| e.mem_target.2 hb, e.proj_symm_apply' hb⟩ #align pretrivialization.proj_surj_on_base_set Pretrivialization.proj_surjOn_baseSet -theorem apply_symm_apply {x : B × F} (hx : x ∈ e.target) : e (e.toLocalEquiv.symm x) = x := - e.toLocalEquiv.right_inv hx +theorem apply_symm_apply {x : B × F} (hx : x ∈ e.target) : e (e.toPartialEquiv.symm x) = x := + e.toPartialEquiv.right_inv hx #align pretrivialization.apply_symm_apply Pretrivialization.apply_symm_apply theorem apply_symm_apply' {b : B} {x : F} (hx : b ∈ e.baseSet) : - e (e.toLocalEquiv.symm (b, x)) = (b, x) := + e (e.toPartialEquiv.symm (b, x)) = (b, x) := e.apply_symm_apply (e.mem_target.2 hx) #align pretrivialization.apply_symm_apply' Pretrivialization.apply_symm_apply' -theorem symm_apply_apply {x : Z} (hx : x ∈ e.source) : e.toLocalEquiv.symm (e x) = x := - e.toLocalEquiv.left_inv hx +theorem symm_apply_apply {x : Z} (hx : x ∈ e.source) : e.toPartialEquiv.symm (e x) = x := + e.toPartialEquiv.left_inv hx #align pretrivialization.symm_apply_apply Pretrivialization.symm_apply_apply @[simp, mfld_simps] theorem symm_apply_mk_proj {x : Z} (ex : x ∈ e.source) : - e.toLocalEquiv.symm (proj x, (e x).2) = x := by + e.toPartialEquiv.symm (proj x, (e x).2) = x := by rw [← e.coe_fst ex, ← e.coe_coe, e.left_inv ex] #align pretrivialization.symm_apply_mk_proj Pretrivialization.symm_apply_mk_proj @[simp, mfld_simps] theorem preimage_symm_proj_baseSet : - e.toLocalEquiv.symm ⁻¹' (proj ⁻¹' e.baseSet) ∩ e.target = e.target := by + e.toPartialEquiv.symm ⁻¹' (proj ⁻¹' e.baseSet) ∩ e.target = e.target := by refine' inter_eq_right.mpr fun x hx => _ - simp only [mem_preimage, LocalEquiv.invFun_as_coe, e.proj_symm_apply hx] + simp only [mem_preimage, PartialEquiv.invFun_as_coe, e.proj_symm_apply hx] exact e.mem_target.mp hx #align pretrivialization.preimage_symm_proj_base_set Pretrivialization.preimage_symm_proj_baseSet @[simp, mfld_simps] theorem preimage_symm_proj_inter (s : Set B) : - e.toLocalEquiv.symm ⁻¹' (proj ⁻¹' s) ∩ e.baseSet ×ˢ univ = (s ∩ e.baseSet) ×ˢ univ := by + e.toPartialEquiv.symm ⁻¹' (proj ⁻¹' s) ∩ e.baseSet ×ˢ univ = (s ∩ e.baseSet) ×ˢ univ := by ext ⟨x, y⟩ - suffices x ∈ e.baseSet → (proj (e.toLocalEquiv.symm (x, y)) ∈ s ↔ x ∈ s) by + suffices x ∈ e.baseSet → (proj (e.toPartialEquiv.symm (x, y)) ∈ s ↔ x ∈ s) by simpa only [prod_mk_mem_set_prod_eq, mem_inter_iff, and_true_iff, mem_univ, and_congr_left_iff] intro h rw [e.proj_symm_apply' h] #align pretrivialization.preimage_symm_proj_inter Pretrivialization.preimage_symm_proj_inter theorem target_inter_preimage_symm_source_eq (e f : Pretrivialization F proj) : - f.target ∩ f.toLocalEquiv.symm ⁻¹' e.source = (e.baseSet ∩ f.baseSet) ×ˢ univ := by + f.target ∩ f.toPartialEquiv.symm ⁻¹' e.source = (e.baseSet ∩ f.baseSet) ×ˢ univ := by rw [inter_comm, f.target_eq, e.source_eq, f.preimage_symm_proj_inter] #align pretrivialization.target_inter_preimage_symm_source_eq Pretrivialization.target_inter_preimage_symm_source_eq theorem trans_source (e f : Pretrivialization F proj) : - (f.toLocalEquiv.symm.trans e.toLocalEquiv).source = (e.baseSet ∩ f.baseSet) ×ˢ univ := by - rw [LocalEquiv.trans_source, LocalEquiv.symm_source, e.target_inter_preimage_symm_source_eq] + (f.toPartialEquiv.symm.trans e.toPartialEquiv).source = (e.baseSet ∩ f.baseSet) ×ˢ univ := by + rw [PartialEquiv.trans_source, PartialEquiv.symm_source, e.target_inter_preimage_symm_source_eq] #align pretrivialization.trans_source Pretrivialization.trans_source theorem symm_trans_symm (e e' : Pretrivialization F proj) : - (e.toLocalEquiv.symm.trans e'.toLocalEquiv).symm - = e'.toLocalEquiv.symm.trans e.toLocalEquiv := by - rw [LocalEquiv.trans_symm_eq_symm_trans_symm, LocalEquiv.symm_symm] + (e.toPartialEquiv.symm.trans e'.toPartialEquiv).symm + = e'.toPartialEquiv.symm.trans e.toPartialEquiv := by + rw [PartialEquiv.trans_symm_eq_symm_trans_symm, PartialEquiv.symm_symm] #align pretrivialization.symm_trans_symm Pretrivialization.symm_trans_symm theorem symm_trans_source_eq (e e' : Pretrivialization F proj) : - (e.toLocalEquiv.symm.trans e'.toLocalEquiv).source = (e.baseSet ∩ e'.baseSet) ×ˢ univ := by - rw [LocalEquiv.trans_source, e'.source_eq, LocalEquiv.symm_source, e.target_eq, inter_comm, + (e.toPartialEquiv.symm.trans e'.toPartialEquiv).source = (e.baseSet ∩ e'.baseSet) ×ˢ univ := by + rw [PartialEquiv.trans_source, e'.source_eq, PartialEquiv.symm_source, e.target_eq, inter_comm, e.preimage_symm_proj_inter, inter_comm] #align pretrivialization.symm_trans_source_eq Pretrivialization.symm_trans_source_eq theorem symm_trans_target_eq (e e' : Pretrivialization F proj) : - (e.toLocalEquiv.symm.trans e'.toLocalEquiv).target = (e.baseSet ∩ e'.baseSet) ×ˢ univ := by - rw [← LocalEquiv.symm_source, symm_trans_symm, symm_trans_source_eq, inter_comm] + (e.toPartialEquiv.symm.trans e'.toPartialEquiv).target = (e.baseSet ∩ e'.baseSet) ×ˢ univ := by + rw [← PartialEquiv.symm_source, symm_trans_symm, symm_trans_source_eq, inter_comm] #align pretrivialization.symm_trans_target_eq Pretrivialization.symm_trans_target_eq variable (e' : Pretrivialization F (π F E)) {x' : TotalSpace F E} {b : B} {y : E b} @@ -242,7 +242,7 @@ theorem mk_mem_target {x : B} {y : F} : (x, y) ∈ e'.target ↔ x ∈ e'.baseSe #align pretrivialization.mk_mem_target Pretrivialization.mk_mem_target theorem symm_coe_proj {x : B} {y : F} (e' : Pretrivialization F (π F E)) (h : x ∈ e'.baseSet) : - (e'.toLocalEquiv.symm (x, y)).1 = x := + (e'.toPartialEquiv.symm (x, y)).1 = x := e'.proj_symm_apply' h #align pretrivialization.symm_coe_proj Pretrivialization.symm_coe_proj @@ -254,12 +254,12 @@ variable [∀ x, Zero (E x)] `B × F → TotalSpace F E` of `e` on `e.baseSet`. It is defined to be `0` outside `e.baseSet`. -/ protected noncomputable def symm (e : Pretrivialization F (π F E)) (b : B) (y : F) : E b := if hb : b ∈ e.baseSet then - cast (congr_arg E (e.proj_symm_apply' hb)) (e.toLocalEquiv.symm (b, y)).2 + cast (congr_arg E (e.proj_symm_apply' hb)) (e.toPartialEquiv.symm (b, y)).2 else 0 #align pretrivialization.symm Pretrivialization.symm theorem symm_apply (e : Pretrivialization F (π F E)) {b : B} (hb : b ∈ e.baseSet) (y : F) : - e.symm b y = cast (congr_arg E (e.symm_coe_proj hb)) (e.toLocalEquiv.symm (b, y)).2 := + e.symm b y = cast (congr_arg E (e.symm_coe_proj hb)) (e.toPartialEquiv.symm (b, y)).2 := dif_pos hb #align pretrivialization.symm_apply Pretrivialization.symm_apply @@ -274,7 +274,7 @@ theorem coe_symm_of_not_mem (e : Pretrivialization F (π F E)) {b : B} (hb : b #align pretrivialization.coe_symm_of_not_mem Pretrivialization.coe_symm_of_not_mem theorem mk_symm (e : Pretrivialization F (π F E)) {b : B} (hb : b ∈ e.baseSet) (y : F) : - TotalSpace.mk b (e.symm b y) = e.toLocalEquiv.symm (b, y) := by + TotalSpace.mk b (e.symm b y) = e.toPartialEquiv.symm (b, y) := by simp only [e.symm_apply hb, TotalSpace.mk_cast (e.proj_symm_apply' hb), TotalSpace.eta] #align pretrivialization.mk_symm Pretrivialization.mk_symm @@ -304,12 +304,12 @@ variable [TopologicalSpace Z] [TopologicalSpace (TotalSpace F E)] sets of the form `proj ⁻¹' baseSet` and `baseSet × F`, acting trivially on the first coordinate. -/ -- porting note: todo: was @[nolint has_nonempty_instance] -structure Trivialization (proj : Z → B) extends LocalHomeomorph Z (B × F) where +structure Trivialization (proj : Z → B) extends PartialHomeomorph Z (B × F) where baseSet : Set B open_baseSet : IsOpen baseSet source_eq : source = proj ⁻¹' baseSet target_eq : target = baseSet ×ˢ univ - proj_toFun : ∀ p ∈ source, (toLocalHomeomorph p).1 = proj p + proj_toFun : ∀ p ∈ source, (toPartialHomeomorph p).1 = proj p #align trivialization Trivialization namespace Trivialization @@ -318,14 +318,14 @@ variable {F} variable (e : Trivialization F proj) {x : Z} @[ext] -lemma ext' (e e' : Trivialization F proj) (h₁ : e.toLocalHomeomorph = e'.toLocalHomeomorph) +lemma ext' (e e' : Trivialization F proj) (h₁ : e.toPartialHomeomorph = e'.toPartialHomeomorph) (h₂ : e.baseSet = e'.baseSet) : e = e' := by cases e; cases e'; congr #align trivialization.ext Trivialization.ext' /-- Coercion of a trivialization to a function. We don't use `e.toFun` in the `CoeFun` instance -because it is actually `e.toLocalEquiv.toFun`, so `simp` will apply lemmas about -`toLocalEquiv`. While we may want to switch to this behavior later, doing it mid-port will break a +because it is actually `e.toPartialEquiv.toFun`, so `simp` will apply lemmas about +`toPartialEquiv`. While we may want to switch to this behavior later, doing it mid-port will break a lot of proofs. -/ @[coe] def toFun' : Z → (B × F) := e.toFun @@ -342,12 +342,12 @@ instance : Coe (Trivialization F proj) (Pretrivialization F proj) := theorem toPretrivialization_injective : Function.Injective fun e : Trivialization F proj => e.toPretrivialization := fun e e' h => by ext1 - exacts [LocalHomeomorph.toLocalEquiv_injective (congr_arg Pretrivialization.toLocalEquiv h), + exacts [PartialHomeomorph.toPartialEquiv_injective (congr_arg Pretrivialization.toPartialEquiv h), congr_arg Pretrivialization.baseSet h] #align trivialization.to_pretrivialization_injective Trivialization.toPretrivialization_injective @[simp, mfld_simps] -theorem coe_coe : ⇑e.toLocalHomeomorph = e := +theorem coe_coe : ⇑e.toPartialHomeomorph = e := rfl #align trivialization.coe_coe Trivialization.coe_coe @@ -376,11 +376,11 @@ theorem mk_proj_snd' (ex : proj x ∈ e.baseSet) : (proj x, (e x).2) = e x := theorem source_inter_preimage_target_inter (s : Set (B × F)) : e.source ∩ e ⁻¹' (e.target ∩ s) = e.source ∩ e ⁻¹' s := - e.toLocalHomeomorph.source_inter_preimage_target_inter s + e.toPartialHomeomorph.source_inter_preimage_target_inter s #align trivialization.source_inter_preimage_target_inter Trivialization.source_inter_preimage_target_inter @[simp, mfld_simps] -theorem coe_mk (e : LocalHomeomorph Z (B × F)) (i j k l m) (x : Z) : +theorem coe_mk (e : PartialHomeomorph Z (B × F)) (i j k l m) (x : Z) : (Trivialization.mk e i j k l m : Trivialization F proj) x = e x := rfl #align trivialization.coe_mk Trivialization.coe_mk @@ -389,16 +389,17 @@ theorem mem_target {x : B × F} : x ∈ e.target ↔ x.1 ∈ e.baseSet := e.toPretrivialization.mem_target #align trivialization.mem_target Trivialization.mem_target -theorem map_target {x : B × F} (hx : x ∈ e.target) : e.toLocalHomeomorph.symm x ∈ e.source := - e.toLocalHomeomorph.map_target hx +theorem map_target {x : B × F} (hx : x ∈ e.target) : e.toPartialHomeomorph.symm x ∈ e.source := + e.toPartialHomeomorph.map_target hx #align trivialization.map_target Trivialization.map_target -theorem proj_symm_apply {x : B × F} (hx : x ∈ e.target) : proj (e.toLocalHomeomorph.symm x) = x.1 := +theorem proj_symm_apply {x : B × F} (hx : x ∈ e.target) : + proj (e.toPartialHomeomorph.symm x) = x.1 := e.toPretrivialization.proj_symm_apply hx #align trivialization.proj_symm_apply Trivialization.proj_symm_apply theorem proj_symm_apply' {b : B} {x : F} (hx : b ∈ e.baseSet) : - proj (e.toLocalHomeomorph.symm (b, x)) = b := + proj (e.toPartialHomeomorph.symm (b, x)) = b := e.toPretrivialization.proj_symm_apply' hx #align trivialization.proj_symm_apply' Trivialization.proj_symm_apply' @@ -406,27 +407,27 @@ theorem proj_surjOn_baseSet [Nonempty F] : Set.SurjOn proj e.source e.baseSet := e.toPretrivialization.proj_surjOn_baseSet #align trivialization.proj_surj_on_base_set Trivialization.proj_surjOn_baseSet -theorem apply_symm_apply {x : B × F} (hx : x ∈ e.target) : e (e.toLocalHomeomorph.symm x) = x := - e.toLocalHomeomorph.right_inv hx +theorem apply_symm_apply {x : B × F} (hx : x ∈ e.target) : e (e.toPartialHomeomorph.symm x) = x := + e.toPartialHomeomorph.right_inv hx #align trivialization.apply_symm_apply Trivialization.apply_symm_apply theorem apply_symm_apply' {b : B} {x : F} (hx : b ∈ e.baseSet) : - e (e.toLocalHomeomorph.symm (b, x)) = (b, x) := + e (e.toPartialHomeomorph.symm (b, x)) = (b, x) := e.toPretrivialization.apply_symm_apply' hx #align trivialization.apply_symm_apply' Trivialization.apply_symm_apply' @[simp, mfld_simps] -theorem symm_apply_mk_proj (ex : x ∈ e.source) : e.toLocalHomeomorph.symm (proj x, (e x).2) = x := +theorem symm_apply_mk_proj (ex : x ∈ e.source) : e.toPartialHomeomorph.symm (proj x, (e x).2) = x := e.toPretrivialization.symm_apply_mk_proj ex #align trivialization.symm_apply_mk_proj Trivialization.symm_apply_mk_proj theorem symm_trans_source_eq (e e' : Trivialization F proj) : - (e.toLocalEquiv.symm.trans e'.toLocalEquiv).source = (e.baseSet ∩ e'.baseSet) ×ˢ univ := + (e.toPartialEquiv.symm.trans e'.toPartialEquiv).source = (e.baseSet ∩ e'.baseSet) ×ˢ univ := Pretrivialization.symm_trans_source_eq e.toPretrivialization e' #align trivialization.symm_trans_source_eq Trivialization.symm_trans_source_eq theorem symm_trans_target_eq (e e' : Trivialization F proj) : - (e.toLocalEquiv.symm.trans e'.toLocalEquiv).target = (e.baseSet ∩ e'.baseSet) ×ˢ univ := + (e.toPartialEquiv.symm.trans e'.toPartialEquiv).target = (e.baseSet ∩ e'.baseSet) ×ˢ univ := Pretrivialization.symm_trans_target_eq e.toPretrivialization e' #align trivialization.symm_trans_target_eq Trivialization.symm_trans_target_eq @@ -478,7 +479,7 @@ theorem nhds_eq_inf_comap {z : Z} (hz : z ∈ e.source) : /-- The preimage of a subset of the base set is homeomorphic to the product with the fiber. -/ def preimageHomeomorph {s : Set B} (hb : s ⊆ e.baseSet) : proj ⁻¹' s ≃ₜ s × F := - (e.toLocalHomeomorph.homeomorphOfImageSubsetSource (e.preimage_subset_source hb) + (e.toPartialHomeomorph.homeomorphOfImageSubsetSource (e.preimage_subset_source hb) (e.image_preimage_eq_prod_univ hb)).trans ((Homeomorph.Set.prod s univ).trans ((Homeomorph.refl s).prodCongr (Homeomorph.Set.univ F))) #align trivialization.preimage_homeomorph Trivialization.preimageHomeomorph @@ -541,7 +542,7 @@ theorem continuousAt_proj (ex : x ∈ e.source) : ContinuousAt proj x := /-- Composition of a `Trivialization` and a `Homeomorph`. -/ protected def compHomeomorph {Z' : Type*} [TopologicalSpace Z'] (h : Z' ≃ₜ Z) : Trivialization F (proj ∘ h) where - toLocalHomeomorph := h.toLocalHomeomorph.trans e.toLocalHomeomorph + toPartialHomeomorph := h.toPartialHomeomorph.trans e.toPartialHomeomorph baseSet := e.baseSet open_baseSet := e.open_baseSet source_eq := by simp [source_eq, preimage_preimage, (· ∘ ·)] @@ -555,12 +556,12 @@ protected def compHomeomorph {Z' : Type*} [TopologicalSpace Z'] (h : Z' ≃ₜ Z trivialization of `Z` containing `z`. -/ theorem continuousAt_of_comp_right {X : Type*} [TopologicalSpace X] {f : Z → X} {z : Z} (e : Trivialization F proj) (he : proj z ∈ e.baseSet) - (hf : ContinuousAt (f ∘ e.toLocalEquiv.symm) (e z)) : ContinuousAt f z := by - have hez : z ∈ e.toLocalEquiv.symm.target := by - rw [LocalEquiv.symm_target, e.mem_source] + (hf : ContinuousAt (f ∘ e.toPartialEquiv.symm) (e z)) : ContinuousAt f z := by + have hez : z ∈ e.toPartialEquiv.symm.target := by + rw [PartialEquiv.symm_target, e.mem_source] exact he - rwa [e.toLocalHomeomorph.symm.continuousAt_iff_continuousAt_comp_right hez, - LocalHomeomorph.symm_symm] + rwa [e.toPartialHomeomorph.symm.continuousAt_iff_continuousAt_comp_right hez, + PartialHomeomorph.symm_symm] #align trivialization.continuous_at_of_comp_right Trivialization.continuousAt_of_comp_right /-- Read off the continuity of a function `f : X → Z` at `x : X` by transferring via a @@ -584,7 +585,7 @@ theorem coe_mem_source : ↑y ∈ e'.source ↔ b ∈ e'.baseSet := e'.mem_source #align trivialization.coe_mem_source Trivialization.coe_mem_source -@[deprecated LocalHomeomorph.open_target] +@[deprecated PartialHomeomorph.open_target] theorem open_target' : IsOpen e'.target := e'.open_target #align trivialization.open_target Trivialization.open_target' @@ -598,13 +599,13 @@ theorem mk_mem_target {y : F} : (b, y) ∈ e'.target ↔ b ∈ e'.baseSet := #align trivialization.mk_mem_target Trivialization.mk_mem_target theorem symm_apply_apply {x : TotalSpace F E} (hx : x ∈ e'.source) : - e'.toLocalHomeomorph.symm (e' x) = x := - e'.toLocalEquiv.left_inv hx + e'.toPartialHomeomorph.symm (e' x) = x := + e'.toPartialEquiv.left_inv hx #align trivialization.symm_apply_apply Trivialization.symm_apply_apply @[simp, mfld_simps] theorem symm_coe_proj {x : B} {y : F} (e : Trivialization F (π F E)) (h : x ∈ e.baseSet) : - (e.toLocalHomeomorph.symm (x, y)).1 = x := + (e.toPartialHomeomorph.symm (x, y)).1 = x := e.proj_symm_apply' h #align trivialization.symm_coe_proj Trivialization.symm_coe_proj @@ -619,7 +620,7 @@ protected noncomputable def symm (e : Trivialization F (π F E)) (b : B) (y : F) #align trivialization.symm Trivialization.symm theorem symm_apply (e : Trivialization F (π F E)) {b : B} (hb : b ∈ e.baseSet) (y : F) : - e.symm b y = cast (congr_arg E (e.symm_coe_proj hb)) (e.toLocalHomeomorph.symm (b, y)).2 := + e.symm b y = cast (congr_arg E (e.symm_coe_proj hb)) (e.toPartialHomeomorph.symm (b, y)).2 := dif_pos hb #align trivialization.symm_apply Trivialization.symm_apply @@ -629,7 +630,7 @@ theorem symm_apply_of_not_mem (e : Trivialization F (π F E)) {b : B} (hb : b #align trivialization.symm_apply_of_not_mem Trivialization.symm_apply_of_not_mem theorem mk_symm (e : Trivialization F (π F E)) {b : B} (hb : b ∈ e.baseSet) (y : F) : - TotalSpace.mk b (e.symm b y) = e.toLocalHomeomorph.symm (b, y) := + TotalSpace.mk b (e.symm b y) = e.toPartialHomeomorph.symm (b, y) := e.toPretrivialization.mk_symm hb y #align trivialization.mk_symm Trivialization.mk_symm @@ -651,12 +652,12 @@ theorem apply_mk_symm (e : Trivialization F (π F E)) {b : B} (hb : b ∈ e.base theorem continuousOn_symm (e : Trivialization F (π F E)) : ContinuousOn (fun z : B × F => TotalSpace.mk' F z.1 (e.symm z.1 z.2)) (e.baseSet ×ˢ univ) := by have : ∀ z ∈ e.baseSet ×ˢ (univ : Set F), - TotalSpace.mk z.1 (e.symm z.1 z.2) = e.toLocalHomeomorph.symm z := by + TotalSpace.mk z.1 (e.symm z.1 z.2) = e.toPartialHomeomorph.symm z := by rintro x ⟨hx : x.1 ∈ e.baseSet, _⟩ rw [e.mk_symm hx] refine' ContinuousOn.congr _ this rw [← e.target_eq] - exact e.toLocalHomeomorph.continuousOn_symm + exact e.toPartialHomeomorph.continuousOn_symm #align trivialization.continuous_on_symm Trivialization.continuousOn_symm end Zero @@ -666,7 +667,7 @@ end Zero that sends `p : Z` to `((e p).1, h (e p).2)`. -/ def transFiberHomeomorph {F' : Type*} [TopologicalSpace F'] (e : Trivialization F proj) (h : F ≃ₜ F') : Trivialization F' proj where - toLocalHomeomorph := e.toLocalHomeomorph.transHomeomorph <| (Homeomorph.refl _).prodCongr h + toPartialHomeomorph := e.toPartialHomeomorph.transHomeomorph <| (Homeomorph.refl _).prodCongr h baseSet := e.baseSet open_baseSet := e.open_baseSet source_eq := e.source_eq @@ -683,12 +684,12 @@ theorem transFiberHomeomorph_apply {F' : Type*} [TopologicalSpace F'] (e : Trivi /-- Coordinate transformation in the fiber induced by a pair of bundle trivializations. See also `Trivialization.coordChangeHomeomorph` for a version bundled as `F ≃ₜ F`. -/ def coordChange (e₁ e₂ : Trivialization F proj) (b : B) (x : F) : F := - (e₂ <| e₁.toLocalHomeomorph.symm (b, x)).2 + (e₂ <| e₁.toPartialHomeomorph.symm (b, x)).2 #align trivialization.coord_change Trivialization.coordChange theorem mk_coordChange (e₁ e₂ : Trivialization F proj) {b : B} (h₁ : b ∈ e₁.baseSet) (h₂ : b ∈ e₂.baseSet) (x : F) : - (b, e₁.coordChange e₂ b x) = e₂ (e₁.toLocalHomeomorph.symm (b, x)) := by + (b, e₁.coordChange e₂ b x) = e₂ (e₁.toPartialHomeomorph.symm (b, x)) := by refine' Prod.ext _ rfl rw [e₂.coe_fst', ← e₁.coe_fst', e₁.apply_symm_apply' h₁] · rwa [e₁.proj_symm_apply' h₁] @@ -718,8 +719,8 @@ theorem coordChange_coordChange (e₁ e₂ e₃ : Trivialization F proj) {b : B} theorem continuous_coordChange (e₁ e₂ : Trivialization F proj) {b : B} (h₁ : b ∈ e₁.baseSet) (h₂ : b ∈ e₂.baseSet) : Continuous (e₁.coordChange e₂ b) := by - refine' continuous_snd.comp (e₂.toLocalHomeomorph.continuousOn.comp_continuous - (e₁.toLocalHomeomorph.continuousOn_symm.comp_continuous _ _) _) + refine' continuous_snd.comp (e₂.toPartialHomeomorph.continuousOn.comp_continuous + (e₁.toPartialHomeomorph.continuousOn_symm.comp_continuous _ _) _) · exact continuous_const.prod_mk continuous_id · exact fun x => e₁.mem_target.2 h₁ · intro x @@ -747,13 +748,13 @@ theorem coordChangeHomeomorph_coe (e₁ e₂ : Trivialization F proj) {b : B} (h variable {B' : Type*} [TopologicalSpace B'] theorem isImage_preimage_prod (e : Trivialization F proj) (s : Set B) : - e.toLocalHomeomorph.IsImage (proj ⁻¹' s) (s ×ˢ univ) := fun x hx => by simp [e.coe_fst', hx] + e.toPartialHomeomorph.IsImage (proj ⁻¹' s) (s ×ˢ univ) := fun x hx => by simp [e.coe_fst', hx] #align trivialization.is_image_preimage_prod Trivialization.isImage_preimage_prod /-- Restrict a `Trivialization` to an open set in the base. -/ protected def restrOpen (e : Trivialization F proj) (s : Set B) (hs : IsOpen s) : Trivialization F proj where - toLocalHomeomorph := + toPartialHomeomorph := ((e.isImage_preimage_prod s).symm.restr (IsOpen.inter e.open_target (hs.prod isOpen_univ))).symm baseSet := e.baseSet ∩ s open_baseSet := IsOpen.inter e.open_baseSet hs @@ -778,8 +779,8 @@ otherwise. -/ noncomputable def piecewise (e e' : Trivialization F proj) (s : Set B) (Hs : e.baseSet ∩ frontier s = e'.baseSet ∩ frontier s) (Heq : EqOn e e' <| proj ⁻¹' (e.baseSet ∩ frontier s)) : Trivialization F proj where - toLocalHomeomorph := - e.toLocalHomeomorph.piecewise e'.toLocalHomeomorph (proj ⁻¹' s) (s ×ˢ univ) + toPartialHomeomorph := + e.toPartialHomeomorph.piecewise e'.toPartialHomeomorph (proj ⁻¹' s) (s ×ˢ univ) (e.isImage_preimage_prod s) (e'.isImage_preimage_prod s) (by rw [e.frontier_preimage, e'.frontier_preimage, Hs]) (by rwa [e.frontier_preimage]) baseSet := s.ite e.baseSet e'.baseSet @@ -828,8 +829,8 @@ bundle trivialization over the union of the base sets that agrees with `e` and ` base sets. -/ noncomputable def disjointUnion (e e' : Trivialization F proj) (H : Disjoint e.baseSet e'.baseSet) : Trivialization F proj where - toLocalHomeomorph := - e.toLocalHomeomorph.disjointUnion e'.toLocalHomeomorph + toPartialHomeomorph := + e.toPartialHomeomorph.disjointUnion e'.toPartialHomeomorph (by rw [e.source_eq, e'.source_eq] exact H.preimage _) diff --git a/Mathlib/Topology/IndicatorConstPointwise.lean b/Mathlib/Topology/IndicatorConstPointwise.lean index 8f395f8a4aebd..18df1ff3674da 100644 --- a/Mathlib/Topology/IndicatorConstPointwise.lean +++ b/Mathlib/Topology/IndicatorConstPointwise.lean @@ -3,7 +3,7 @@ Copyright (c) 2023 Kalle Kytölä. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kalle Kytölä -/ -import Mathlib.Algebra.IndicatorFunction +import Mathlib.Algebra.Function.Indicator import Mathlib.Topology.Separation /-! diff --git a/Mathlib/Topology/Instances/NNReal.lean b/Mathlib/Topology/Instances/NNReal.lean index a7b2c8694b8ac..b8cbdac0d0802 100644 --- a/Mathlib/Topology/Instances/NNReal.lean +++ b/Mathlib/Topology/Instances/NNReal.lean @@ -74,6 +74,8 @@ instance : OrderTopology ℝ≥0 := instance : CompleteSpace ℝ≥0 := isClosed_Ici.completeSpace_coe +instance : ContinuousStar ℝ≥0 where + continuous_star := continuous_id section coe variable {α : Type*} diff --git a/Mathlib/Topology/IsLocalHomeomorph.lean b/Mathlib/Topology/IsLocalHomeomorph.lean new file mode 100644 index 0000000000000..4348b9b62e049 --- /dev/null +++ b/Mathlib/Topology/IsLocalHomeomorph.lean @@ -0,0 +1,220 @@ +/- +Copyright (c) 2021 Thomas Browning. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Thomas Browning +-/ +import Mathlib.Topology.PartialHomeomorph +import Mathlib.Topology.SeparatedMap + +#align_import topology.is_locally_homeomorph from "leanprover-community/mathlib"@"e97cf15cd1aec9bd5c193b2ffac5a6dc9118912b" + +/-! +# Local homeomorphisms + +This file defines local homeomorphisms. + +## Main definitions + +* `IsLocalHomeomorph`: A function `f : X → Y` satisfies `IsLocalHomeomorph` if for each + point `x : X`, the restriction of `f` to some open neighborhood `U` of `x` gives a homeomorphism + between `U` and an open subset of `Y`. + + Note that `IsLocalHomeomorph` is a global condition. This is in contrast to + `PartialHomeomorph`, which is a homeomorphism between specific open subsets. +-/ + + +open Topology + +variable {X Y Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] (g : Y → Z) + (f : X → Y) (s : Set X) (t : Set Y) + +/-- A function `f : X → Y` satisfies `IsLocalHomeomorphOn f s` if each `x ∈ s` is contained in +the source of some `e : PartialHomeomorph X Y` with `f = e`. -/ +def IsLocalHomeomorphOn := + ∀ x ∈ s, ∃ e : PartialHomeomorph X Y, x ∈ e.source ∧ f = e +#align is_locally_homeomorph_on IsLocalHomeomorphOn + +theorem isLocalHomeomorphOn_iff_openEmbedding_restrict {f : X → Y} : + IsLocalHomeomorphOn f s ↔ ∀ x ∈ s, ∃ U ∈ 𝓝 x, OpenEmbedding (U.restrict f) := by + refine ⟨fun h x hx ↦ ?_, fun h x hx ↦ ?_⟩ + · obtain ⟨e, hxe, rfl⟩ := h x hx + exact ⟨e.source, e.open_source.mem_nhds hxe, e.openEmbedding_restrict⟩ + · obtain ⟨U, hU, emb⟩ := h x hx + have : OpenEmbedding ((interior U).restrict f) + · refine emb.comp ⟨embedding_inclusion interior_subset, ?_⟩ + rw [Set.range_inclusion]; exact isOpen_induced isOpen_interior + obtain ⟨cont, inj, openMap⟩ := openEmbedding_iff_continuous_injective_open.mp this + haveI : Nonempty X := ⟨x⟩ + exact ⟨PartialHomeomorph.ofContinuousOpenRestrict + (Set.injOn_iff_injective.mpr inj).toPartialEquiv + (continuousOn_iff_continuous_restrict.mpr cont) openMap isOpen_interior, + mem_interior_iff_mem_nhds.mpr hU, rfl⟩ + +namespace IsLocalHomeomorphOn + +/-- Proves that `f` satisfies `IsLocalHomeomorphOn f s`. The condition `h` is weaker than the +definition of `IsLocalHomeomorphOn f s`, since it only requires `e : PartialHomeomorph X Y` to +agree with `f` on its source `e.source`, as opposed to on the whole space `X`. -/ +theorem mk (h : ∀ x ∈ s, ∃ e : PartialHomeomorph X Y, x ∈ e.source ∧ ∀ y ∈ e.source, f y = e y) : + IsLocalHomeomorphOn f s := by + intro x hx + obtain ⟨e, hx, he⟩ := h x hx + exact + ⟨{ e with + toFun := f + map_source' := fun x hx => by rw [he x hx]; exact e.map_source' hx + left_inv' := fun x hx => by rw [he x hx]; exact e.left_inv' hx + right_inv' := fun y hy => by rw [he _ (e.map_target' hy)]; exact e.right_inv' hy + continuousOn_toFun := (continuousOn_congr he).mpr e.continuousOn_toFun }, + hx, rfl⟩ +#align is_locally_homeomorph_on.mk IsLocalHomeomorphOn.mk + +variable {g f s t} + +theorem mono {t : Set X} (hf : IsLocalHomeomorphOn f t) (hst : s ⊆ t) : + IsLocalHomeomorphOn f s := fun x hx ↦ hf x (hst hx) + +theorem of_comp_left (hgf : IsLocalHomeomorphOn (g ∘ f) s) (hg : IsLocalHomeomorphOn g (f '' s)) + (cont : ∀ x ∈ s, ContinuousAt f x) : IsLocalHomeomorphOn f s := mk f s fun x hx ↦ by + obtain ⟨g, hxg, rfl⟩ := hg (f x) ⟨x, hx, rfl⟩ + obtain ⟨gf, hgf, he⟩ := hgf x hx + refine ⟨(gf.restr <| f ⁻¹' g.source).trans g.symm, ⟨⟨hgf, mem_interior_iff_mem_nhds.mpr + ((cont x hx).preimage_mem_nhds <| g.open_source.mem_nhds hxg)⟩, he ▸ g.map_source hxg⟩, + fun y hy ↦ ?_⟩ + change f y = g.symm (gf y) + have : f y ∈ g.source := by apply interior_subset hy.1.2 + rw [← he, g.eq_symm_apply this (by apply g.map_source this)] + rfl + +theorem of_comp_right (hgf : IsLocalHomeomorphOn (g ∘ f) s) (hf : IsLocalHomeomorphOn f s) : + IsLocalHomeomorphOn g (f '' s) := mk g _ <| by + rintro _ ⟨x, hx, rfl⟩ + obtain ⟨f, hxf, rfl⟩ := hf x hx + obtain ⟨gf, hgf, he⟩ := hgf x hx + refine ⟨f.symm.trans gf, ⟨f.map_source hxf, ?_⟩, fun y hy ↦ ?_⟩ + · apply (f.left_inv hxf).symm ▸ hgf + · change g y = gf (f.symm y) + rw [← he, Function.comp_apply, f.right_inv hy.1] + +theorem map_nhds_eq (hf : IsLocalHomeomorphOn f s) {x : X} (hx : x ∈ s) : (𝓝 x).map f = 𝓝 (f x) := + let ⟨e, hx, he⟩ := hf x hx + he.symm ▸ e.map_nhds_eq hx +#align is_locally_homeomorph_on.map_nhds_eq IsLocalHomeomorphOn.map_nhds_eq + +protected theorem continuousAt (hf : IsLocalHomeomorphOn f s) {x : X} (hx : x ∈ s) : + ContinuousAt f x := + (hf.map_nhds_eq hx).le +#align is_locally_homeomorph_on.continuous_at IsLocalHomeomorphOn.continuousAt + +protected theorem continuousOn (hf : IsLocalHomeomorphOn f s) : ContinuousOn f s := + ContinuousAt.continuousOn fun _x => hf.continuousAt +#align is_locally_homeomorph_on.continuous_on IsLocalHomeomorphOn.continuousOn + +protected theorem comp (hg : IsLocalHomeomorphOn g t) (hf : IsLocalHomeomorphOn f s) + (h : Set.MapsTo f s t) : IsLocalHomeomorphOn (g ∘ f) s := by + intro x hx + obtain ⟨eg, hxg, rfl⟩ := hg (f x) (h hx) + obtain ⟨ef, hxf, rfl⟩ := hf x hx + exact ⟨ef.trans eg, ⟨hxf, hxg⟩, rfl⟩ +#align is_locally_homeomorph_on.comp IsLocalHomeomorphOn.comp + +end IsLocalHomeomorphOn + +/-- A function `f : X → Y` satisfies `IsLocalHomeomorph f` if each `x : x` is contained in + the source of some `e : PartialHomeomorph X Y` with `f = e`. -/ +def IsLocalHomeomorph := + ∀ x : X, ∃ e : PartialHomeomorph X Y, x ∈ e.source ∧ f = e +#align is_locally_homeomorph IsLocalHomeomorph + +theorem Homeomorph.isLocalHomeomorph (f : X ≃ₜ Y) : IsLocalHomeomorph f := + fun _ ↦ ⟨f.toPartialHomeomorph, trivial, rfl⟩ + +variable {f s} + +theorem isLocalHomeomorph_iff_isLocalHomeomorphOn_univ : + IsLocalHomeomorph f ↔ IsLocalHomeomorphOn f Set.univ := + ⟨fun h x _ ↦ h x, fun h x ↦ h x trivial⟩ +#align is_locally_homeomorph_iff_is_locally_homeomorph_on_univ isLocalHomeomorph_iff_isLocalHomeomorphOn_univ + +protected theorem IsLocalHomeomorph.isLocalHomeomorphOn (hf : IsLocalHomeomorph f) : + IsLocalHomeomorphOn f s := fun x _ ↦ hf x +#align is_locally_homeomorph.is_locally_homeomorph_on IsLocalHomeomorph.isLocalHomeomorphOn + +theorem isLocalHomeomorph_iff_openEmbedding_restrict {f : X → Y} : + IsLocalHomeomorph f ↔ ∀ x : X, ∃ U ∈ 𝓝 x, OpenEmbedding (U.restrict f) := by + simp_rw [isLocalHomeomorph_iff_isLocalHomeomorphOn_univ, + isLocalHomeomorphOn_iff_openEmbedding_restrict, imp_iff_right (Set.mem_univ _)] + +theorem OpenEmbedding.isLocalHomeomorph (hf : OpenEmbedding f) : IsLocalHomeomorph f := + isLocalHomeomorph_iff_openEmbedding_restrict.mpr fun _ ↦ + ⟨_, Filter.univ_mem, hf.comp (Homeomorph.Set.univ X).openEmbedding⟩ + +variable (f) + +namespace IsLocalHomeomorph + +/-- Proves that `f` satisfies `IsLocalHomeomorph f`. The condition `h` is weaker than the +definition of `IsLocalHomeomorph f`, since it only requires `e : PartialHomeomorph X Y` to +agree with `f` on its source `e.source`, as opposed to on the whole space `X`. -/ +theorem mk (h : ∀ x : X, ∃ e : PartialHomeomorph X Y, x ∈ e.source ∧ ∀ y ∈ e.source, f y = e y) : + IsLocalHomeomorph f := + isLocalHomeomorph_iff_isLocalHomeomorphOn_univ.mpr + (IsLocalHomeomorphOn.mk f Set.univ fun x _hx => h x) +#align is_locally_homeomorph.mk IsLocalHomeomorph.mk + +variable {g f} + +lemma isLocallyInjective (hf : IsLocalHomeomorph f) : IsLocallyInjective f := + fun x ↦ by obtain ⟨f, hx, rfl⟩ := hf x; exact ⟨f.source, f.open_source, hx, f.injOn⟩ + +theorem of_comp (hgf : IsLocalHomeomorph (g ∘ f)) (hg : IsLocalHomeomorph g) + (cont : Continuous f) : IsLocalHomeomorph f := + isLocalHomeomorph_iff_isLocalHomeomorphOn_univ.mpr <| + hgf.isLocalHomeomorphOn.of_comp_left hg.isLocalHomeomorphOn fun _ _ ↦ cont.continuousAt + +theorem map_nhds_eq (hf : IsLocalHomeomorph f) (x : X) : (𝓝 x).map f = 𝓝 (f x) := + hf.isLocalHomeomorphOn.map_nhds_eq (Set.mem_univ x) +#align is_locally_homeomorph.map_nhds_eq IsLocalHomeomorph.map_nhds_eq + +protected theorem continuous (hf : IsLocalHomeomorph f) : Continuous f := + continuous_iff_continuousOn_univ.mpr hf.isLocalHomeomorphOn.continuousOn +#align is_locally_homeomorph.continuous IsLocalHomeomorph.continuous + +protected theorem isOpenMap (hf : IsLocalHomeomorph f) : IsOpenMap f := + IsOpenMap.of_nhds_le fun x => ge_of_eq (hf.map_nhds_eq x) +#align is_locally_homeomorph.is_open_map IsLocalHomeomorph.isOpenMap + +protected theorem comp (hg : IsLocalHomeomorph g) (hf : IsLocalHomeomorph f) : + IsLocalHomeomorph (g ∘ f) := + isLocalHomeomorph_iff_isLocalHomeomorphOn_univ.mpr + (hg.isLocalHomeomorphOn.comp hf.isLocalHomeomorphOn (Set.univ.mapsTo_univ f)) +#align is_locally_homeomorph.comp IsLocalHomeomorph.comp + +theorem openEmbedding_of_injective (hf : IsLocalHomeomorph f) (hi : f.Injective) : + OpenEmbedding f := + openEmbedding_of_continuous_injective_open hf.continuous hi hf.isOpenMap + +/-- Continuous local sections of a local homeomorphism are open embeddings. -/ +theorem openEmbedding_of_comp (hf : IsLocalHomeomorph g) (hgf : OpenEmbedding (g ∘ f)) + (cont : Continuous f) : OpenEmbedding f := + (hgf.isLocalHomeomorph.of_comp hf cont).openEmbedding_of_injective hgf.inj.of_comp + +open TopologicalSpace in +/-- Ranges of continuous local sections of a local homeomorphism form a basis of the source space.-/ +theorem isTopologicalBasis (hf : IsLocalHomeomorph f) : IsTopologicalBasis + {U : Set X | ∃ V : Set Y, IsOpen V ∧ ∃ s : C(V,X), f ∘ s = (↑) ∧ Set.range s = U} := by + refine isTopologicalBasis_of_isOpen_of_nhds ?_ fun x U hx hU ↦ ?_ + · rintro _ ⟨U, hU, s, hs, rfl⟩ + refine (openEmbedding_of_comp hf (hs ▸ ⟨embedding_subtype_val, ?_⟩) s.continuous).open_range + rwa [Subtype.range_val] + · obtain ⟨f, hxf, rfl⟩ := hf x + refine ⟨f.source ∩ U, ⟨f.target ∩ f.symm ⁻¹' U, f.symm.isOpen_inter_preimage hU, + ⟨_, continuousOn_iff_continuous_restrict.mp (f.continuousOn_invFun.mono fun _ h ↦ h.1)⟩, + ?_, (Set.range_restrict _ _).trans ?_⟩, ⟨hxf, hx⟩, fun _ h ↦ h.2⟩ + · ext y; exact f.right_inv y.2.1 + · apply (f.symm_image_target_inter_eq _).trans + rw [Set.preimage_inter, ← Set.inter_assoc, Set.inter_eq_self_of_subset_left + f.source_preimage_target, f.source_inter_preimage_inv_preimage] + +end IsLocalHomeomorph diff --git a/Mathlib/Topology/IsLocallyHomeomorph.lean b/Mathlib/Topology/IsLocallyHomeomorph.lean deleted file mode 100644 index db0137f3ac0ae..0000000000000 --- a/Mathlib/Topology/IsLocallyHomeomorph.lean +++ /dev/null @@ -1,219 +0,0 @@ -/- -Copyright (c) 2021 Thomas Browning. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Thomas Browning --/ -import Mathlib.Topology.LocalHomeomorph -import Mathlib.Topology.SeparatedMap - -#align_import topology.is_locally_homeomorph from "leanprover-community/mathlib"@"e97cf15cd1aec9bd5c193b2ffac5a6dc9118912b" - -/-! -# Local homeomorphisms - -This file defines local homeomorphisms. - -## Main definitions - -* `IsLocallyHomeomorph`: A function `f : X → Y` satisfies `IsLocallyHomeomorph` if for each - point `x : X`, the restriction of `f` to some open neighborhood `U` of `x` gives a homeomorphism - between `U` and an open subset of `Y`. - - Note that `IsLocallyHomeomorph` is a global condition. This is in contrast to - `LocalHomeomorph`, which is a homeomorphism between specific open subsets. --/ - - -open Topology - -variable {X Y Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] (g : Y → Z) - (f : X → Y) (s : Set X) (t : Set Y) - -/-- A function `f : X → Y` satisfies `IsLocallyHomeomorphOn f s` if each `x ∈ s` is contained in -the source of some `e : LocalHomeomorph X Y` with `f = e`. -/ -def IsLocallyHomeomorphOn := - ∀ x ∈ s, ∃ e : LocalHomeomorph X Y, x ∈ e.source ∧ f = e -#align is_locally_homeomorph_on IsLocallyHomeomorphOn - -theorem isLocallyHomeomorphOn_iff_openEmbedding_restrict {f : X → Y} : - IsLocallyHomeomorphOn f s ↔ ∀ x ∈ s, ∃ U ∈ 𝓝 x, OpenEmbedding (U.restrict f) := by - refine ⟨fun h x hx ↦ ?_, fun h x hx ↦ ?_⟩ - · obtain ⟨e, hxe, rfl⟩ := h x hx - exact ⟨e.source, e.open_source.mem_nhds hxe, e.openEmbedding_restrict⟩ - · obtain ⟨U, hU, emb⟩ := h x hx - have : OpenEmbedding ((interior U).restrict f) - · refine emb.comp ⟨embedding_inclusion interior_subset, ?_⟩ - rw [Set.range_inclusion]; exact isOpen_induced isOpen_interior - obtain ⟨cont, inj, openMap⟩ := openEmbedding_iff_continuous_injective_open.mp this - haveI : Nonempty X := ⟨x⟩ - exact ⟨LocalHomeomorph.ofContinuousOpenRestrict (Set.injOn_iff_injective.mpr inj).toLocalEquiv - (continuousOn_iff_continuous_restrict.mpr cont) openMap isOpen_interior, - mem_interior_iff_mem_nhds.mpr hU, rfl⟩ - -namespace IsLocallyHomeomorphOn - -/-- Proves that `f` satisfies `IsLocallyHomeomorphOn f s`. The condition `h` is weaker than the -definition of `IsLocallyHomeomorphOn f s`, since it only requires `e : LocalHomeomorph X Y` to -agree with `f` on its source `e.source`, as opposed to on the whole space `X`. -/ -theorem mk (h : ∀ x ∈ s, ∃ e : LocalHomeomorph X Y, x ∈ e.source ∧ ∀ y ∈ e.source, f y = e y) : - IsLocallyHomeomorphOn f s := by - intro x hx - obtain ⟨e, hx, he⟩ := h x hx - exact - ⟨{ e with - toFun := f - map_source' := fun x hx => by rw [he x hx]; exact e.map_source' hx - left_inv' := fun x hx => by rw [he x hx]; exact e.left_inv' hx - right_inv' := fun y hy => by rw [he _ (e.map_target' hy)]; exact e.right_inv' hy - continuousOn_toFun := (continuousOn_congr he).mpr e.continuousOn_toFun }, - hx, rfl⟩ -#align is_locally_homeomorph_on.mk IsLocallyHomeomorphOn.mk - -variable {g f s t} - -theorem mono {t : Set X} (hf : IsLocallyHomeomorphOn f t) (hst : s ⊆ t) : - IsLocallyHomeomorphOn f s := fun x hx ↦ hf x (hst hx) - -theorem of_comp_left (hgf : IsLocallyHomeomorphOn (g ∘ f) s) (hg : IsLocallyHomeomorphOn g (f '' s)) - (cont : ∀ x ∈ s, ContinuousAt f x) : IsLocallyHomeomorphOn f s := mk f s fun x hx ↦ by - obtain ⟨g, hxg, rfl⟩ := hg (f x) ⟨x, hx, rfl⟩ - obtain ⟨gf, hgf, he⟩ := hgf x hx - refine ⟨(gf.restr <| f ⁻¹' g.source).trans g.symm, ⟨⟨hgf, mem_interior_iff_mem_nhds.mpr - ((cont x hx).preimage_mem_nhds <| g.open_source.mem_nhds hxg)⟩, he ▸ g.map_source hxg⟩, - fun y hy ↦ ?_⟩ - change f y = g.symm (gf y) - have : f y ∈ g.source := by apply interior_subset hy.1.2 - rw [← he, g.eq_symm_apply this (by apply g.map_source this)] - rfl - -theorem of_comp_right (hgf : IsLocallyHomeomorphOn (g ∘ f) s) (hf : IsLocallyHomeomorphOn f s) : - IsLocallyHomeomorphOn g (f '' s) := mk g _ <| by - rintro _ ⟨x, hx, rfl⟩ - obtain ⟨f, hxf, rfl⟩ := hf x hx - obtain ⟨gf, hgf, he⟩ := hgf x hx - refine ⟨f.symm.trans gf, ⟨f.map_source hxf, ?_⟩, fun y hy ↦ ?_⟩ - · apply (f.left_inv hxf).symm ▸ hgf - · change g y = gf (f.symm y) - rw [← he, Function.comp_apply, f.right_inv hy.1] - -theorem map_nhds_eq (hf : IsLocallyHomeomorphOn f s) {x : X} (hx : x ∈ s) : (𝓝 x).map f = 𝓝 (f x) := - let ⟨e, hx, he⟩ := hf x hx - he.symm ▸ e.map_nhds_eq hx -#align is_locally_homeomorph_on.map_nhds_eq IsLocallyHomeomorphOn.map_nhds_eq - -protected theorem continuousAt (hf : IsLocallyHomeomorphOn f s) {x : X} (hx : x ∈ s) : - ContinuousAt f x := - (hf.map_nhds_eq hx).le -#align is_locally_homeomorph_on.continuous_at IsLocallyHomeomorphOn.continuousAt - -protected theorem continuousOn (hf : IsLocallyHomeomorphOn f s) : ContinuousOn f s := - ContinuousAt.continuousOn fun _x => hf.continuousAt -#align is_locally_homeomorph_on.continuous_on IsLocallyHomeomorphOn.continuousOn - -protected theorem comp (hg : IsLocallyHomeomorphOn g t) (hf : IsLocallyHomeomorphOn f s) - (h : Set.MapsTo f s t) : IsLocallyHomeomorphOn (g ∘ f) s := by - intro x hx - obtain ⟨eg, hxg, rfl⟩ := hg (f x) (h hx) - obtain ⟨ef, hxf, rfl⟩ := hf x hx - exact ⟨ef.trans eg, ⟨hxf, hxg⟩, rfl⟩ -#align is_locally_homeomorph_on.comp IsLocallyHomeomorphOn.comp - -end IsLocallyHomeomorphOn - -/-- A function `f : X → Y` satisfies `IsLocallyHomeomorph f` if each `x : x` is contained in - the source of some `e : LocalHomeomorph X Y` with `f = e`. -/ -def IsLocallyHomeomorph := - ∀ x : X, ∃ e : LocalHomeomorph X Y, x ∈ e.source ∧ f = e -#align is_locally_homeomorph IsLocallyHomeomorph - -theorem Homeomorph.isLocallyHomeomorph (f : X ≃ₜ Y) : IsLocallyHomeomorph f := - fun _ ↦ ⟨f.toLocalHomeomorph, trivial, rfl⟩ - -variable {f s} - -theorem isLocallyHomeomorph_iff_isLocallyHomeomorphOn_univ : - IsLocallyHomeomorph f ↔ IsLocallyHomeomorphOn f Set.univ := - ⟨fun h x _ ↦ h x, fun h x ↦ h x trivial⟩ -#align is_locally_homeomorph_iff_is_locally_homeomorph_on_univ isLocallyHomeomorph_iff_isLocallyHomeomorphOn_univ - -protected theorem IsLocallyHomeomorph.isLocallyHomeomorphOn (hf : IsLocallyHomeomorph f) : - IsLocallyHomeomorphOn f s := fun x _ ↦ hf x -#align is_locally_homeomorph.is_locally_homeomorph_on IsLocallyHomeomorph.isLocallyHomeomorphOn - -theorem isLocallyHomeomorph_iff_openEmbedding_restrict {f : X → Y} : - IsLocallyHomeomorph f ↔ ∀ x : X, ∃ U ∈ 𝓝 x, OpenEmbedding (U.restrict f) := by - simp_rw [isLocallyHomeomorph_iff_isLocallyHomeomorphOn_univ, - isLocallyHomeomorphOn_iff_openEmbedding_restrict, imp_iff_right (Set.mem_univ _)] - -theorem OpenEmbedding.isLocallyHomeomorph (hf : OpenEmbedding f) : IsLocallyHomeomorph f := - isLocallyHomeomorph_iff_openEmbedding_restrict.mpr fun _ ↦ - ⟨_, Filter.univ_mem, hf.comp (Homeomorph.Set.univ X).openEmbedding⟩ - -variable (f) - -namespace IsLocallyHomeomorph - -/-- Proves that `f` satisfies `IsLocallyHomeomorph f`. The condition `h` is weaker than the -definition of `IsLocallyHomeomorph f`, since it only requires `e : LocalHomeomorph X Y` to -agree with `f` on its source `e.source`, as opposed to on the whole space `X`. -/ -theorem mk (h : ∀ x : X, ∃ e : LocalHomeomorph X Y, x ∈ e.source ∧ ∀ y ∈ e.source, f y = e y) : - IsLocallyHomeomorph f := - isLocallyHomeomorph_iff_isLocallyHomeomorphOn_univ.mpr - (IsLocallyHomeomorphOn.mk f Set.univ fun x _hx => h x) -#align is_locally_homeomorph.mk IsLocallyHomeomorph.mk - -variable {g f} - -lemma isLocallyInjective (hf : IsLocallyHomeomorph f) : IsLocallyInjective f := - fun x ↦ by obtain ⟨f, hx, rfl⟩ := hf x; exact ⟨f.source, f.open_source, hx, f.injOn⟩ - -theorem of_comp (hgf : IsLocallyHomeomorph (g ∘ f)) (hg : IsLocallyHomeomorph g) - (cont : Continuous f) : IsLocallyHomeomorph f := - isLocallyHomeomorph_iff_isLocallyHomeomorphOn_univ.mpr <| - hgf.isLocallyHomeomorphOn.of_comp_left hg.isLocallyHomeomorphOn fun _ _ ↦ cont.continuousAt - -theorem map_nhds_eq (hf : IsLocallyHomeomorph f) (x : X) : (𝓝 x).map f = 𝓝 (f x) := - hf.isLocallyHomeomorphOn.map_nhds_eq (Set.mem_univ x) -#align is_locally_homeomorph.map_nhds_eq IsLocallyHomeomorph.map_nhds_eq - -protected theorem continuous (hf : IsLocallyHomeomorph f) : Continuous f := - continuous_iff_continuousOn_univ.mpr hf.isLocallyHomeomorphOn.continuousOn -#align is_locally_homeomorph.continuous IsLocallyHomeomorph.continuous - -protected theorem isOpenMap (hf : IsLocallyHomeomorph f) : IsOpenMap f := - IsOpenMap.of_nhds_le fun x => ge_of_eq (hf.map_nhds_eq x) -#align is_locally_homeomorph.is_open_map IsLocallyHomeomorph.isOpenMap - -protected theorem comp (hg : IsLocallyHomeomorph g) (hf : IsLocallyHomeomorph f) : - IsLocallyHomeomorph (g ∘ f) := - isLocallyHomeomorph_iff_isLocallyHomeomorphOn_univ.mpr - (hg.isLocallyHomeomorphOn.comp hf.isLocallyHomeomorphOn (Set.univ.mapsTo_univ f)) -#align is_locally_homeomorph.comp IsLocallyHomeomorph.comp - -theorem openEmbedding_of_injective (hf : IsLocallyHomeomorph f) (hi : f.Injective) : - OpenEmbedding f := - openEmbedding_of_continuous_injective_open hf.continuous hi hf.isOpenMap - -/-- Continuous local sections of a local homeomorphism are open embeddings. -/ -theorem openEmbedding_of_comp (hf : IsLocallyHomeomorph g) (hgf : OpenEmbedding (g ∘ f)) - (cont : Continuous f) : OpenEmbedding f := - (hgf.isLocallyHomeomorph.of_comp hf cont).openEmbedding_of_injective hgf.inj.of_comp - -open TopologicalSpace in -/-- Ranges of continuous local sections of a local homeomorphism form a basis of the source space.-/ -theorem isTopologicalBasis (hf : IsLocallyHomeomorph f) : IsTopologicalBasis - {U : Set X | ∃ V : Set Y, IsOpen V ∧ ∃ s : C(V,X), f ∘ s = (↑) ∧ Set.range s = U} := by - refine isTopologicalBasis_of_isOpen_of_nhds ?_ fun x U hx hU ↦ ?_ - · rintro _ ⟨U, hU, s, hs, rfl⟩ - refine (openEmbedding_of_comp hf (hs ▸ ⟨embedding_subtype_val, ?_⟩) s.continuous).open_range - rwa [Subtype.range_val] - · obtain ⟨f, hxf, rfl⟩ := hf x - refine ⟨f.source ∩ U, ⟨f.target ∩ f.symm ⁻¹' U, f.symm.isOpen_inter_preimage hU, - ⟨_, continuousOn_iff_continuous_restrict.mp (f.continuousOn_invFun.mono fun _ h ↦ h.1)⟩, - ?_, (Set.range_restrict _ _).trans ?_⟩, ⟨hxf, hx⟩, fun _ h ↦ h.2⟩ - · ext y; exact f.right_inv y.2.1 - · apply (f.symm_image_target_inter_eq _).trans - rw [Set.preimage_inter, ← Set.inter_assoc, Set.inter_eq_self_of_subset_left - f.source_preimage_target, f.source_inter_preimage_inv_preimage] - -end IsLocallyHomeomorph diff --git a/Mathlib/Topology/LocallyConstant/Basic.lean b/Mathlib/Topology/LocallyConstant/Basic.lean index bac88a372cc4c..830a05bb51e67 100644 --- a/Mathlib/Topology/LocallyConstant/Basic.lean +++ b/Mathlib/Topology/LocallyConstant/Basic.lean @@ -3,9 +3,9 @@ Copyright (c) 2021 Johan Commelin. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin -/ -import Mathlib.Topology.ContinuousFunction.Basic -import Mathlib.Algebra.IndicatorFunction +import Mathlib.Algebra.Function.Indicator import Mathlib.Tactic.FinCases +import Mathlib.Topology.ContinuousFunction.Basic #align_import topology.locally_constant.basic from "leanprover-community/mathlib"@"0a0ec35061ed9960bf0e7ffb0335f44447b58977" diff --git a/Mathlib/Topology/LocalHomeomorph.lean b/Mathlib/Topology/PartialHomeomorph.lean similarity index 50% rename from Mathlib/Topology/LocalHomeomorph.lean rename to Mathlib/Topology/PartialHomeomorph.lean index a39c69ce16469..8e77cd79d5d68 100644 --- a/Mathlib/Topology/LocalHomeomorph.lean +++ b/Mathlib/Topology/PartialHomeomorph.lean @@ -3,16 +3,17 @@ Copyright (c) 2019 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ -import Mathlib.Logic.Equiv.LocalEquiv +import Mathlib.Logic.Equiv.PartialEquiv import Mathlib.Topology.Sets.Opens #align_import topology.local_homeomorph from "leanprover-community/mathlib"@"431589bce478b2229eba14b14a283250428217db" /-! -# Local homeomorphisms +# Partial homeomorphisms +# Partial homeomorphisms This file defines homeomorphisms between open subsets of topological spaces. An element `e` of -`LocalHomeomorph α β` is an extension of `LocalEquiv α β`, i.e., it is a pair of functions +`PartialHomeomorph α β` is an extension of `PartialEquiv α β`, i.e., it is a pair of functions `e.toFun` and `e.invFun`, inverse of each other on the sets `e.source` and `e.target`. Additionally, we require that these sets are open, and that the functions are continuous on them. Equivalently, they are homeomorphisms there. @@ -22,25 +23,25 @@ instead of `e.toFun x` and `e.invFun x`. ## Main definitions -* `Homeomorph.toLocalHomeomorph`: associating a local homeomorphism to a homeomorphism, with +* `Homeomorph.toPartialHomeomorph`: associating a partial homeomorphism to a homeomorphism, with `source = target = Set.univ`; -* `LocalHomeomorph.symm`: the inverse of a local homeomorphism -* `LocalHomeomorph.trans`: the composition of two local homeomorphisms -* `LocalHomeomorph.refl`: the identity local homeomorphism -* `LocalHomeomorph.ofSet`: the identity on a set `s` -* `LocalHomeomorph.EqOnSource`: equivalence relation describing the "right" notion of equality - for local homeomorphisms +* `PartialHomeomorph.symm`: the inverse of a partial homeomorphism +* `PartialHomeomorph.trans`: the composition of two partial homeomorphisms +* `PartialHomeomorph.refl`: the identity partial homeomorphism +* `PartialHomeomorph.ofSet`: the identity on a set `s` +* `PartialHomeomorph.EqOnSource`: equivalence relation describing the "right" notion of equality + for partial homeomorphisms ## Implementation notes -Most statements are copied from their `LocalEquiv` versions, although some care is required +Most statements are copied from their `PartialEquiv` versions, although some care is required especially when restricting to subsets, as these should be open subsets. -For design notes, see `LocalEquiv.lean`. +For design notes, see `PartialEquiv.lean`. ### Local coding conventions -If a lemma deals with the intersection of a set with either source or target of a `LocalEquiv`, +If a lemma deals with the intersection of a set with either source or target of a `PartialEquiv`, then it should use `e.source ∩ s` or `e.target ∩ t`, not `s ∩ e.source` or `t ∩ e.target`. -/ @@ -50,98 +51,100 @@ open Function Set Filter Topology variable {α : Type*} {β : Type*} {γ : Type*} {δ : Type*} [TopologicalSpace α] [TopologicalSpace β] [TopologicalSpace γ] [TopologicalSpace δ] -/-- local homeomorphisms, defined on open subsets of the space -/ +/-- Partial homeomorphisms, defined on open subsets of the space -/ -- porting note: commented @[nolint has_nonempty_instance] -structure LocalHomeomorph (α : Type*) (β : Type*) [TopologicalSpace α] - [TopologicalSpace β] extends LocalEquiv α β where +structure PartialHomeomorph (α : Type*) (β : Type*) [TopologicalSpace α] + [TopologicalSpace β] extends PartialEquiv α β where open_source : IsOpen source open_target : IsOpen target continuousOn_toFun : ContinuousOn toFun source continuousOn_invFun : ContinuousOn invFun target -#align local_homeomorph LocalHomeomorph +#align local_homeomorph PartialHomeomorph -namespace LocalHomeomorph +namespace PartialHomeomorph -variable (e : LocalHomeomorph α β) (e' : LocalHomeomorph β γ) +variable (e : PartialHomeomorph α β) (e' : PartialHomeomorph β γ) -/-- Coercion of a local homeomorphisms to a function. We don't use `e.toFun` because it is actually -`e.toLocalEquiv.toFun`, so `simp` will apply lemmas about `toLocalEquiv`. While we may want to -switch to this behavior later, doing it mid-port will break a lot of proofs. -/ +/-- Coercion of a partial homeomorphisms to a function. We don't use `e.toFun` because it is +actually `e.toPartialEquiv.toFun`, so `simp` will apply lemmas about `toPartialEquiv`. +While we may want to switch to this behavior later, doing it mid-port will break a lot of proofs. -/ @[coe] def toFun' : α → β := e.toFun -/-- Coercion of a `LocalHomeomorph` to function. Note that a `LocalHomeomorph` is not `FunLike`. -/ -instance : CoeFun (LocalHomeomorph α β) fun _ => α → β := +/-- Coercion of a `PartialHomeomorph` to function. +Note that a `PartialHomeomorph` is not `FunLike`. -/ +instance : CoeFun (PartialHomeomorph α β) fun _ => α → β := ⟨fun e => e.toFun'⟩ -/-- The inverse of a local homeomorphism -/ -protected def symm : LocalHomeomorph β α where - toLocalEquiv := e.toLocalEquiv.symm +/-- The inverse of a partial homeomorphism -/ +protected def symm : PartialHomeomorph β α where + toPartialEquiv := e.toPartialEquiv.symm open_source := e.open_target open_target := e.open_source continuousOn_toFun := e.continuousOn_invFun continuousOn_invFun := e.continuousOn_toFun -#align local_homeomorph.symm LocalHomeomorph.symm +#align local_homeomorph.symm PartialHomeomorph.symm /-- See Note [custom simps projection]. We need to specify this projection explicitly in this case, because it is a composition of multiple projections. -/ -def Simps.apply (e : LocalHomeomorph α β) : α → β := e -#align local_homeomorph.simps.apply LocalHomeomorph.Simps.apply +def Simps.apply (e : PartialHomeomorph α β) : α → β := e +#align local_homeomorph.simps.apply PartialHomeomorph.Simps.apply /-- See Note [custom simps projection] -/ -def Simps.symm_apply (e : LocalHomeomorph α β) : β → α := e.symm -#align local_homeomorph.simps.symm_apply LocalHomeomorph.Simps.symm_apply +def Simps.symm_apply (e : PartialHomeomorph α β) : β → α := e.symm +#align local_homeomorph.simps.symm_apply PartialHomeomorph.Simps.symm_apply -initialize_simps_projections LocalHomeomorph (toFun → apply, invFun → symm_apply) +initialize_simps_projections PartialHomeomorph (toFun → apply, invFun → symm_apply) protected theorem continuousOn : ContinuousOn e e.source := e.continuousOn_toFun -#align local_homeomorph.continuous_on LocalHomeomorph.continuousOn +#align local_homeomorph.continuous_on PartialHomeomorph.continuousOn theorem continuousOn_symm : ContinuousOn e.symm e.target := e.continuousOn_invFun -#align local_homeomorph.continuous_on_symm LocalHomeomorph.continuousOn_symm +#align local_homeomorph.continuous_on_symm PartialHomeomorph.continuousOn_symm @[simp, mfld_simps] -theorem mk_coe (e : LocalEquiv α β) (a b c d) : (LocalHomeomorph.mk e a b c d : α → β) = e := +theorem mk_coe (e : PartialEquiv α β) (a b c d) : (PartialHomeomorph.mk e a b c d : α → β) = e := rfl -#align local_homeomorph.mk_coe LocalHomeomorph.mk_coe +#align local_homeomorph.mk_coe PartialHomeomorph.mk_coe @[simp, mfld_simps] -theorem mk_coe_symm (e : LocalEquiv α β) (a b c d) : - ((LocalHomeomorph.mk e a b c d).symm : β → α) = e.symm := +theorem mk_coe_symm (e : PartialEquiv α β) (a b c d) : + ((PartialHomeomorph.mk e a b c d).symm : β → α) = e.symm := rfl -#align local_homeomorph.mk_coe_symm LocalHomeomorph.mk_coe_symm +#align local_homeomorph.mk_coe_symm PartialHomeomorph.mk_coe_symm -theorem toLocalEquiv_injective : Injective (toLocalEquiv : LocalHomeomorph α β → LocalEquiv α β) +theorem toPartialEquiv_injective : + Injective (toPartialEquiv : PartialHomeomorph α β → PartialEquiv α β) | ⟨_, _, _, _, _⟩, ⟨_, _, _, _, _⟩, rfl => rfl -#align local_homeomorph.to_local_equiv_injective LocalHomeomorph.toLocalEquiv_injective +#align local_homeomorph.to_local_equiv_injective PartialHomeomorph.toPartialEquiv_injective /- Register a few simp lemmas to make sure that `simp` puts the application of a local homeomorphism in its normal form, i.e., in terms of its coercion to a function. -/ @[simp, mfld_simps] -theorem toFun_eq_coe (e : LocalHomeomorph α β) : e.toFun = e := +theorem toFun_eq_coe (e : PartialHomeomorph α β) : e.toFun = e := rfl -#align local_homeomorph.to_fun_eq_coe LocalHomeomorph.toFun_eq_coe +#align local_homeomorph.to_fun_eq_coe PartialHomeomorph.toFun_eq_coe @[simp, mfld_simps] -theorem invFun_eq_coe (e : LocalHomeomorph α β) : e.invFun = e.symm := +theorem invFun_eq_coe (e : PartialHomeomorph α β) : e.invFun = e.symm := rfl -#align local_homeomorph.inv_fun_eq_coe LocalHomeomorph.invFun_eq_coe +#align local_homeomorph.inv_fun_eq_coe PartialHomeomorph.invFun_eq_coe @[simp, mfld_simps] -theorem coe_coe : (e.toLocalEquiv : α → β) = e := +theorem coe_coe : (e.toPartialEquiv : α → β) = e := rfl -#align local_homeomorph.coe_coe LocalHomeomorph.coe_coe +#align local_homeomorph.coe_coe PartialHomeomorph.coe_coe @[simp, mfld_simps] -theorem coe_coe_symm : (e.toLocalEquiv.symm : β → α) = e.symm := +theorem coe_coe_symm : (e.toPartialEquiv.symm : β → α) = e.symm := rfl -#align local_homeomorph.coe_coe_symm LocalHomeomorph.coe_coe_symm +#align local_homeomorph.coe_coe_symm PartialHomeomorph.coe_coe_symm @[simp, mfld_simps] theorem map_source {x : α} (h : x ∈ e.source) : e x ∈ e.target := e.map_source' h -#align local_homeomorph.map_source LocalHomeomorph.map_source +#align local_homeomorph.map_source PartialHomeomorph.map_source /-- Variant of `map_source`, stated for images of subsets of `source`. -/ lemma map_source'' : e '' e.source ⊆ e.target := @@ -150,244 +153,245 @@ lemma map_source'' : e '' e.source ⊆ e.target := @[simp, mfld_simps] theorem map_target {x : β} (h : x ∈ e.target) : e.symm x ∈ e.source := e.map_target' h -#align local_homeomorph.map_target LocalHomeomorph.map_target +#align local_homeomorph.map_target PartialHomeomorph.map_target @[simp, mfld_simps] theorem left_inv {x : α} (h : x ∈ e.source) : e.symm (e x) = x := e.left_inv' h -#align local_homeomorph.left_inv LocalHomeomorph.left_inv +#align local_homeomorph.left_inv PartialHomeomorph.left_inv @[simp, mfld_simps] theorem right_inv {x : β} (h : x ∈ e.target) : e (e.symm x) = x := e.right_inv' h -#align local_homeomorph.right_inv LocalHomeomorph.right_inv +#align local_homeomorph.right_inv PartialHomeomorph.right_inv theorem eq_symm_apply {x : α} {y : β} (hx : x ∈ e.source) (hy : y ∈ e.target) : x = e.symm y ↔ e x = y := - e.toLocalEquiv.eq_symm_apply hx hy -#align local_homeomorph.eq_symm_apply LocalHomeomorph.eq_symm_apply + e.toPartialEquiv.eq_symm_apply hx hy +#align local_homeomorph.eq_symm_apply PartialHomeomorph.eq_symm_apply protected theorem mapsTo : MapsTo e e.source e.target := fun _ => e.map_source -#align local_homeomorph.maps_to LocalHomeomorph.mapsTo +#align local_homeomorph.maps_to PartialHomeomorph.mapsTo protected theorem symm_mapsTo : MapsTo e.symm e.target e.source := e.symm.mapsTo -#align local_homeomorph.symm_maps_to LocalHomeomorph.symm_mapsTo +#align local_homeomorph.symm_maps_to PartialHomeomorph.symm_mapsTo protected theorem leftInvOn : LeftInvOn e.symm e e.source := fun _ => e.left_inv -#align local_homeomorph.left_inv_on LocalHomeomorph.leftInvOn +#align local_homeomorph.left_inv_on PartialHomeomorph.leftInvOn protected theorem rightInvOn : RightInvOn e.symm e e.target := fun _ => e.right_inv -#align local_homeomorph.right_inv_on LocalHomeomorph.rightInvOn +#align local_homeomorph.right_inv_on PartialHomeomorph.rightInvOn protected theorem invOn : InvOn e.symm e e.source e.target := ⟨e.leftInvOn, e.rightInvOn⟩ -#align local_homeomorph.inv_on LocalHomeomorph.invOn +#align local_homeomorph.inv_on PartialHomeomorph.invOn protected theorem injOn : InjOn e e.source := e.leftInvOn.injOn -#align local_homeomorph.inj_on LocalHomeomorph.injOn +#align local_homeomorph.inj_on PartialHomeomorph.injOn protected theorem bijOn : BijOn e e.source e.target := e.invOn.bijOn e.mapsTo e.symm_mapsTo -#align local_homeomorph.bij_on LocalHomeomorph.bijOn +#align local_homeomorph.bij_on PartialHomeomorph.bijOn protected theorem surjOn : SurjOn e e.source e.target := e.bijOn.surjOn -#align local_homeomorph.surj_on LocalHomeomorph.surjOn +#align local_homeomorph.surj_on PartialHomeomorph.surjOn -/-- Interpret a `Homeomorph` as a `LocalHomeomorph` by restricting it +/-- Interpret a `Homeomorph` as a `PartialHomeomorph` by restricting it to an open set `s` in the domain and to `t` in the codomain. -/ -@[simps! (config := .asFn) apply symm_apply toLocalEquiv, +@[simps! (config := .asFn) apply symm_apply toPartialEquiv, simps! (config := .lemmasOnly) source target] -def _root_.Homeomorph.toLocalHomeomorphOfImageEq (e : α ≃ₜ β) (s : Set α) (hs : IsOpen s) - (t : Set β) (h : e '' s = t) : LocalHomeomorph α β where - toLocalEquiv := e.toLocalEquivOfImageEq s t h +def _root_.Homeomorph.toPartialHomeomorphOfImageEq (e : α ≃ₜ β) (s : Set α) (hs : IsOpen s) + (t : Set β) (h : e '' s = t) : PartialHomeomorph α β where + toPartialEquiv := e.toPartialEquivOfImageEq s t h open_source := hs open_target := by simpa [← h] continuousOn_toFun := e.continuous.continuousOn continuousOn_invFun := e.symm.continuous.continuousOn -/-- A homeomorphism induces a local homeomorphism on the whole space -/ +/-- A homeomorphism induces a partial homeomorphism on the whole space -/ @[simps! (config := mfld_cfg)] -def _root_.Homeomorph.toLocalHomeomorph (e : α ≃ₜ β) : LocalHomeomorph α β := - e.toLocalHomeomorphOfImageEq univ isOpen_univ univ <| by rw [image_univ, e.surjective.range_eq] -#align homeomorph.to_local_homeomorph Homeomorph.toLocalHomeomorph - -/-- Replace `toLocalEquiv` field to provide better definitional equalities. -/ -def replaceEquiv (e : LocalHomeomorph α β) (e' : LocalEquiv α β) (h : e.toLocalEquiv = e') : - LocalHomeomorph α β where - toLocalEquiv := e' +def _root_.Homeomorph.toPartialHomeomorph (e : α ≃ₜ β) : PartialHomeomorph α β := + e.toPartialHomeomorphOfImageEq univ isOpen_univ univ <| by rw [image_univ, e.surjective.range_eq] +#align homeomorph.to_local_homeomorph Homeomorph.toPartialHomeomorph + +/-- Replace `toPartialEquiv` field to provide better definitional equalities. -/ +def replaceEquiv (e : PartialHomeomorph α β) (e' : PartialEquiv α β) (h : e.toPartialEquiv = e') : + PartialHomeomorph α β where + toPartialEquiv := e' open_source := h ▸ e.open_source open_target := h ▸ e.open_target continuousOn_toFun := h ▸ e.continuousOn_toFun continuousOn_invFun := h ▸ e.continuousOn_invFun -#align local_homeomorph.replace_equiv LocalHomeomorph.replaceEquiv +#align local_homeomorph.replace_equiv PartialHomeomorph.replaceEquiv -theorem replaceEquiv_eq_self (e : LocalHomeomorph α β) (e' : LocalEquiv α β) - (h : e.toLocalEquiv = e') : e.replaceEquiv e' h = e := by +theorem replaceEquiv_eq_self (e : PartialHomeomorph α β) (e' : PartialEquiv α β) + (h : e.toPartialEquiv = e') : e.replaceEquiv e' h = e := by cases e subst e' rfl -#align local_homeomorph.replace_equiv_eq_self LocalHomeomorph.replaceEquiv_eq_self +#align local_homeomorph.replace_equiv_eq_self PartialHomeomorph.replaceEquiv_eq_self theorem source_preimage_target : e.source ⊆ e ⁻¹' e.target := e.mapsTo -#align local_homeomorph.source_preimage_target LocalHomeomorph.source_preimage_target +#align local_homeomorph.source_preimage_target PartialHomeomorph.source_preimage_target -@[deprecated toLocalEquiv_injective] -theorem eq_of_localEquiv_eq {e e' : LocalHomeomorph α β} (h : e.toLocalEquiv = e'.toLocalEquiv) : - e = e' := toLocalEquiv_injective h -#align local_homeomorph.eq_of_local_equiv_eq LocalHomeomorph.eq_of_localEquiv_eq +@[deprecated toPartialEquiv_injective] +theorem eq_of_localEquiv_eq {e e' : PartialHomeomorph α β} + (h : e.toPartialEquiv = e'.toPartialEquiv) : e = e' := + toPartialEquiv_injective h +#align local_homeomorph.eq_of_local_equiv_eq PartialHomeomorph.eq_of_localEquiv_eq -theorem eventually_left_inverse (e : LocalHomeomorph α β) {x} (hx : x ∈ e.source) : +theorem eventually_left_inverse (e : PartialHomeomorph α β) {x} (hx : x ∈ e.source) : ∀ᶠ y in 𝓝 x, e.symm (e y) = y := (e.open_source.eventually_mem hx).mono e.left_inv' -#align local_homeomorph.eventually_left_inverse LocalHomeomorph.eventually_left_inverse +#align local_homeomorph.eventually_left_inverse PartialHomeomorph.eventually_left_inverse -theorem eventually_left_inverse' (e : LocalHomeomorph α β) {x} (hx : x ∈ e.target) : +theorem eventually_left_inverse' (e : PartialHomeomorph α β) {x} (hx : x ∈ e.target) : ∀ᶠ y in 𝓝 (e.symm x), e.symm (e y) = y := e.eventually_left_inverse (e.map_target hx) -#align local_homeomorph.eventually_left_inverse' LocalHomeomorph.eventually_left_inverse' +#align local_homeomorph.eventually_left_inverse' PartialHomeomorph.eventually_left_inverse' -theorem eventually_right_inverse (e : LocalHomeomorph α β) {x} (hx : x ∈ e.target) : +theorem eventually_right_inverse (e : PartialHomeomorph α β) {x} (hx : x ∈ e.target) : ∀ᶠ y in 𝓝 x, e (e.symm y) = y := (e.open_target.eventually_mem hx).mono e.right_inv' -#align local_homeomorph.eventually_right_inverse LocalHomeomorph.eventually_right_inverse +#align local_homeomorph.eventually_right_inverse PartialHomeomorph.eventually_right_inverse -theorem eventually_right_inverse' (e : LocalHomeomorph α β) {x} (hx : x ∈ e.source) : +theorem eventually_right_inverse' (e : PartialHomeomorph α β) {x} (hx : x ∈ e.source) : ∀ᶠ y in 𝓝 (e x), e (e.symm y) = y := e.eventually_right_inverse (e.map_source hx) -#align local_homeomorph.eventually_right_inverse' LocalHomeomorph.eventually_right_inverse' +#align local_homeomorph.eventually_right_inverse' PartialHomeomorph.eventually_right_inverse' -theorem eventually_ne_nhdsWithin (e : LocalHomeomorph α β) {x} (hx : x ∈ e.source) : +theorem eventually_ne_nhdsWithin (e : PartialHomeomorph α β) {x} (hx : x ∈ e.source) : ∀ᶠ x' in 𝓝[≠] x, e x' ≠ e x := eventually_nhdsWithin_iff.2 <| (e.eventually_left_inverse hx).mono fun x' hx' => mt fun h => by rw [mem_singleton_iff, ← e.left_inv hx, ← h, hx'] -#align local_homeomorph.eventually_ne_nhds_within LocalHomeomorph.eventually_ne_nhdsWithin +#align local_homeomorph.eventually_ne_nhds_within PartialHomeomorph.eventually_ne_nhdsWithin theorem nhdsWithin_source_inter {x} (hx : x ∈ e.source) (s : Set α) : 𝓝[e.source ∩ s] x = 𝓝[s] x := nhdsWithin_inter_of_mem (mem_nhdsWithin_of_mem_nhds <| IsOpen.mem_nhds e.open_source hx) -#align local_homeomorph.nhds_within_source_inter LocalHomeomorph.nhdsWithin_source_inter +#align local_homeomorph.nhds_within_source_inter PartialHomeomorph.nhdsWithin_source_inter theorem nhdsWithin_target_inter {x} (hx : x ∈ e.target) (s : Set β) : 𝓝[e.target ∩ s] x = 𝓝[s] x := e.symm.nhdsWithin_source_inter hx s -#align local_homeomorph.nhds_within_target_inter LocalHomeomorph.nhdsWithin_target_inter +#align local_homeomorph.nhds_within_target_inter PartialHomeomorph.nhdsWithin_target_inter theorem image_eq_target_inter_inv_preimage {s : Set α} (h : s ⊆ e.source) : e '' s = e.target ∩ e.symm ⁻¹' s := - e.toLocalEquiv.image_eq_target_inter_inv_preimage h -#align local_homeomorph.image_eq_target_inter_inv_preimage LocalHomeomorph.image_eq_target_inter_inv_preimage + e.toPartialEquiv.image_eq_target_inter_inv_preimage h +#align local_homeomorph.image_eq_target_inter_inv_preimage PartialHomeomorph.image_eq_target_inter_inv_preimage theorem image_source_inter_eq' (s : Set α) : e '' (e.source ∩ s) = e.target ∩ e.symm ⁻¹' s := - e.toLocalEquiv.image_source_inter_eq' s -#align local_homeomorph.image_source_inter_eq' LocalHomeomorph.image_source_inter_eq' + e.toPartialEquiv.image_source_inter_eq' s +#align local_homeomorph.image_source_inter_eq' PartialHomeomorph.image_source_inter_eq' theorem image_source_inter_eq (s : Set α) : e '' (e.source ∩ s) = e.target ∩ e.symm ⁻¹' (e.source ∩ s) := - e.toLocalEquiv.image_source_inter_eq s -#align local_homeomorph.image_source_inter_eq LocalHomeomorph.image_source_inter_eq + e.toPartialEquiv.image_source_inter_eq s +#align local_homeomorph.image_source_inter_eq PartialHomeomorph.image_source_inter_eq theorem symm_image_eq_source_inter_preimage {s : Set β} (h : s ⊆ e.target) : e.symm '' s = e.source ∩ e ⁻¹' s := e.symm.image_eq_target_inter_inv_preimage h -#align local_homeomorph.symm_image_eq_source_inter_preimage LocalHomeomorph.symm_image_eq_source_inter_preimage +#align local_homeomorph.symm_image_eq_source_inter_preimage PartialHomeomorph.symm_image_eq_source_inter_preimage theorem symm_image_target_inter_eq (s : Set β) : e.symm '' (e.target ∩ s) = e.source ∩ e ⁻¹' (e.target ∩ s) := e.symm.image_source_inter_eq _ -#align local_homeomorph.symm_image_target_inter_eq LocalHomeomorph.symm_image_target_inter_eq +#align local_homeomorph.symm_image_target_inter_eq PartialHomeomorph.symm_image_target_inter_eq theorem source_inter_preimage_inv_preimage (s : Set α) : e.source ∩ e ⁻¹' (e.symm ⁻¹' s) = e.source ∩ s := - e.toLocalEquiv.source_inter_preimage_inv_preimage s -#align local_homeomorph.source_inter_preimage_inv_preimage LocalHomeomorph.source_inter_preimage_inv_preimage + e.toPartialEquiv.source_inter_preimage_inv_preimage s +#align local_homeomorph.source_inter_preimage_inv_preimage PartialHomeomorph.source_inter_preimage_inv_preimage theorem target_inter_inv_preimage_preimage (s : Set β) : e.target ∩ e.symm ⁻¹' (e ⁻¹' s) = e.target ∩ s := e.symm.source_inter_preimage_inv_preimage _ -#align local_homeomorph.target_inter_inv_preimage_preimage LocalHomeomorph.target_inter_inv_preimage_preimage +#align local_homeomorph.target_inter_inv_preimage_preimage PartialHomeomorph.target_inter_inv_preimage_preimage theorem source_inter_preimage_target_inter (s : Set β) : e.source ∩ e ⁻¹' (e.target ∩ s) = e.source ∩ e ⁻¹' s := - e.toLocalEquiv.source_inter_preimage_target_inter s -#align local_homeomorph.source_inter_preimage_target_inter LocalHomeomorph.source_inter_preimage_target_inter + e.toPartialEquiv.source_inter_preimage_target_inter s +#align local_homeomorph.source_inter_preimage_target_inter PartialHomeomorph.source_inter_preimage_target_inter -theorem image_source_eq_target (e : LocalHomeomorph α β) : e '' e.source = e.target := - e.toLocalEquiv.image_source_eq_target -#align local_homeomorph.image_source_eq_target LocalHomeomorph.image_source_eq_target +theorem image_source_eq_target (e : PartialHomeomorph α β) : e '' e.source = e.target := + e.toPartialEquiv.image_source_eq_target +#align local_homeomorph.image_source_eq_target PartialHomeomorph.image_source_eq_target -theorem symm_image_target_eq_source (e : LocalHomeomorph α β) : e.symm '' e.target = e.source := +theorem symm_image_target_eq_source (e : PartialHomeomorph α β) : e.symm '' e.target = e.source := e.symm.image_source_eq_target -#align local_homeomorph.symm_image_target_eq_source LocalHomeomorph.symm_image_target_eq_source +#align local_homeomorph.symm_image_target_eq_source PartialHomeomorph.symm_image_target_eq_source -/-- Two local homeomorphisms are equal when they have equal `toFun`, `invFun` and `source`. +/-- Two partial homeomorphisms are equal when they have equal `toFun`, `invFun` and `source`. It is not sufficient to have equal `toFun` and `source`, as this only determines `invFun` on the target. This would only be true for a weaker notion of equality, arguably the right one, called `EqOnSource`. -/ @[ext] -protected theorem ext (e' : LocalHomeomorph α β) (h : ∀ x, e x = e' x) +protected theorem ext (e' : PartialHomeomorph α β) (h : ∀ x, e x = e' x) (hinv : ∀ x, e.symm x = e'.symm x) (hs : e.source = e'.source) : e = e' := - toLocalEquiv_injective (LocalEquiv.ext h hinv hs) -#align local_homeomorph.ext LocalHomeomorph.ext + toPartialEquiv_injective (PartialEquiv.ext h hinv hs) +#align local_homeomorph.ext PartialHomeomorph.ext -protected theorem ext_iff {e e' : LocalHomeomorph α β} : +protected theorem ext_iff {e e' : PartialHomeomorph α β} : e = e' ↔ (∀ x, e x = e' x) ∧ (∀ x, e.symm x = e'.symm x) ∧ e.source = e'.source := ⟨by rintro rfl exact ⟨fun x => rfl, fun x => rfl, rfl⟩, fun h => e.ext e' h.1 h.2.1 h.2.2⟩ -#align local_homeomorph.ext_iff LocalHomeomorph.ext_iff +#align local_homeomorph.ext_iff PartialHomeomorph.ext_iff @[simp, mfld_simps] -theorem symm_toLocalEquiv : e.symm.toLocalEquiv = e.toLocalEquiv.symm := +theorem symm_toPartialEquiv : e.symm.toPartialEquiv = e.toPartialEquiv.symm := rfl -#align local_homeomorph.symm_to_local_equiv LocalHomeomorph.symm_toLocalEquiv +#align local_homeomorph.symm_to_local_equiv PartialHomeomorph.symm_toPartialEquiv --- The following lemmas are already simp via `LocalEquiv` +-- The following lemmas are already simp via `PartialEquiv` theorem symm_source : e.symm.source = e.target := rfl -#align local_homeomorph.symm_source LocalHomeomorph.symm_source +#align local_homeomorph.symm_source PartialHomeomorph.symm_source theorem symm_target : e.symm.target = e.source := rfl -#align local_homeomorph.symm_target LocalHomeomorph.symm_target +#align local_homeomorph.symm_target PartialHomeomorph.symm_target @[simp, mfld_simps] theorem symm_symm : e.symm.symm = e := rfl -#align local_homeomorph.symm_symm LocalHomeomorph.symm_symm +#align local_homeomorph.symm_symm PartialHomeomorph.symm_symm theorem symm_bijective : Function.Bijective - (LocalHomeomorph.symm : LocalHomeomorph α β → LocalHomeomorph β α) := + (PartialHomeomorph.symm : PartialHomeomorph α β → PartialHomeomorph β α) := Function.bijective_iff_has_inverse.mpr ⟨_, symm_symm, symm_symm⟩ -/-- A local homeomorphism is continuous at any point of its source -/ +/-- A partial homeomorphism is continuous at any point of its source -/ protected theorem continuousAt {x : α} (h : x ∈ e.source) : ContinuousAt e x := (e.continuousOn x h).continuousAt (e.open_source.mem_nhds h) -#align local_homeomorph.continuous_at LocalHomeomorph.continuousAt +#align local_homeomorph.continuous_at PartialHomeomorph.continuousAt -/-- A local homeomorphism inverse is continuous at any point of its target -/ +/-- A partial homeomorphism inverse is continuous at any point of its target -/ theorem continuousAt_symm {x : β} (h : x ∈ e.target) : ContinuousAt e.symm x := e.symm.continuousAt h -#align local_homeomorph.continuous_at_symm LocalHomeomorph.continuousAt_symm +#align local_homeomorph.continuous_at_symm PartialHomeomorph.continuousAt_symm theorem tendsto_symm {x} (hx : x ∈ e.source) : Tendsto e.symm (𝓝 (e x)) (𝓝 x) := by simpa only [ContinuousAt, e.left_inv hx] using e.continuousAt_symm (e.map_source hx) -#align local_homeomorph.tendsto_symm LocalHomeomorph.tendsto_symm +#align local_homeomorph.tendsto_symm PartialHomeomorph.tendsto_symm theorem map_nhds_eq {x} (hx : x ∈ e.source) : map e (𝓝 x) = 𝓝 (e x) := le_antisymm (e.continuousAt hx) <| le_map_of_right_inverse (e.eventually_right_inverse' hx) (e.tendsto_symm hx) -#align local_homeomorph.map_nhds_eq LocalHomeomorph.map_nhds_eq +#align local_homeomorph.map_nhds_eq PartialHomeomorph.map_nhds_eq theorem symm_map_nhds_eq {x} (hx : x ∈ e.source) : map e.symm (𝓝 (e x)) = 𝓝 x := (e.symm.map_nhds_eq <| e.map_source hx).trans <| by rw [e.left_inv hx] -#align local_homeomorph.symm_map_nhds_eq LocalHomeomorph.symm_map_nhds_eq +#align local_homeomorph.symm_map_nhds_eq PartialHomeomorph.symm_map_nhds_eq theorem image_mem_nhds {x} (hx : x ∈ e.source) {s : Set α} (hs : s ∈ 𝓝 x) : e '' s ∈ 𝓝 (e x) := e.map_nhds_eq hx ▸ Filter.image_mem_map hs -#align local_homeomorph.image_mem_nhds LocalHomeomorph.image_mem_nhds +#align local_homeomorph.image_mem_nhds PartialHomeomorph.image_mem_nhds -theorem map_nhdsWithin_eq (e : LocalHomeomorph α β) {x} (hx : x ∈ e.source) (s : Set α) : +theorem map_nhdsWithin_eq (e : PartialHomeomorph α β) {x} (hx : x ∈ e.source) (s : Set α) : map e (𝓝[s] x) = 𝓝[e '' (e.source ∩ s)] e x := calc map e (𝓝[s] x) = map e (𝓝[e.source ∩ s] x) := @@ -396,44 +400,44 @@ theorem map_nhdsWithin_eq (e : LocalHomeomorph α β) {x} (hx : x ∈ e.source) (e.leftInvOn.mono <| inter_subset_left _ _).map_nhdsWithin_eq (e.left_inv hx) (e.continuousAt_symm (e.map_source hx)).continuousWithinAt (e.continuousAt hx).continuousWithinAt -#align local_homeomorph.map_nhds_within_eq LocalHomeomorph.map_nhdsWithin_eq +#align local_homeomorph.map_nhds_within_eq PartialHomeomorph.map_nhdsWithin_eq -theorem map_nhdsWithin_preimage_eq (e : LocalHomeomorph α β) {x} (hx : x ∈ e.source) (s : Set β) : +theorem map_nhdsWithin_preimage_eq (e : PartialHomeomorph α β) {x} (hx : x ∈ e.source) (s : Set β) : map e (𝓝[e ⁻¹' s] x) = 𝓝[s] e x := by rw [e.map_nhdsWithin_eq hx, e.image_source_inter_eq', e.target_inter_inv_preimage_preimage, e.nhdsWithin_target_inter (e.map_source hx)] -#align local_homeomorph.map_nhds_within_preimage_eq LocalHomeomorph.map_nhdsWithin_preimage_eq +#align local_homeomorph.map_nhds_within_preimage_eq PartialHomeomorph.map_nhdsWithin_preimage_eq -theorem eventually_nhds (e : LocalHomeomorph α β) {x : α} (p : β → Prop) (hx : x ∈ e.source) : +theorem eventually_nhds (e : PartialHomeomorph α β) {x : α} (p : β → Prop) (hx : x ∈ e.source) : (∀ᶠ y in 𝓝 (e x), p y) ↔ ∀ᶠ x in 𝓝 x, p (e x) := Iff.trans (by rw [e.map_nhds_eq hx]) eventually_map -#align local_homeomorph.eventually_nhds LocalHomeomorph.eventually_nhds +#align local_homeomorph.eventually_nhds PartialHomeomorph.eventually_nhds -theorem eventually_nhds' (e : LocalHomeomorph α β) {x : α} (p : α → Prop) (hx : x ∈ e.source) : +theorem eventually_nhds' (e : PartialHomeomorph α β) {x : α} (p : α → Prop) (hx : x ∈ e.source) : (∀ᶠ y in 𝓝 (e x), p (e.symm y)) ↔ ∀ᶠ x in 𝓝 x, p x := by rw [e.eventually_nhds _ hx] refine' eventually_congr ((e.eventually_left_inverse hx).mono fun y hy => _) rw [hy] -#align local_homeomorph.eventually_nhds' LocalHomeomorph.eventually_nhds' +#align local_homeomorph.eventually_nhds' PartialHomeomorph.eventually_nhds' -theorem eventually_nhdsWithin (e : LocalHomeomorph α β) {x : α} (p : β → Prop) {s : Set α} +theorem eventually_nhdsWithin (e : PartialHomeomorph α β) {x : α} (p : β → Prop) {s : Set α} (hx : x ∈ e.source) : (∀ᶠ y in 𝓝[e.symm ⁻¹' s] e x, p y) ↔ ∀ᶠ x in 𝓝[s] x, p (e x) := by refine' Iff.trans _ eventually_map rw [e.map_nhdsWithin_eq hx, e.image_source_inter_eq', e.nhdsWithin_target_inter (e.mapsTo hx)] -#align local_homeomorph.eventually_nhds_within LocalHomeomorph.eventually_nhdsWithin +#align local_homeomorph.eventually_nhds_within PartialHomeomorph.eventually_nhdsWithin -theorem eventually_nhdsWithin' (e : LocalHomeomorph α β) {x : α} (p : α → Prop) {s : Set α} +theorem eventually_nhdsWithin' (e : PartialHomeomorph α β) {x : α} (p : α → Prop) {s : Set α} (hx : x ∈ e.source) : (∀ᶠ y in 𝓝[e.symm ⁻¹' s] e x, p (e.symm y)) ↔ ∀ᶠ x in 𝓝[s] x, p x := by rw [e.eventually_nhdsWithin _ hx] refine eventually_congr <| (eventually_nhdsWithin_of_eventually_nhds <| e.eventually_left_inverse hx).mono fun y hy => ?_ rw [hy] -#align local_homeomorph.eventually_nhds_within' LocalHomeomorph.eventually_nhdsWithin' +#align local_homeomorph.eventually_nhds_within' PartialHomeomorph.eventually_nhdsWithin' /-- This lemma is useful in the manifold library in the case that `e` is a chart. It states that locally around `e x` the set `e.symm ⁻¹' s` is the same as the set intersected with the target of `e` and some other neighborhood of `f x` (which will be the source of a chart on `γ`). -/ -theorem preimage_eventuallyEq_target_inter_preimage_inter {e : LocalHomeomorph α β} {s : Set α} +theorem preimage_eventuallyEq_target_inter_preimage_inter {e : PartialHomeomorph α β} {s : Set α} {t : Set γ} {x : α} {f : α → γ} (hf : ContinuousWithinAt f s x) (hxe : x ∈ e.source) (ht : t ∈ 𝓝 (f x)) : e.symm ⁻¹' s =ᶠ[𝓝 (e x)] (e.target ∩ e.symm ⁻¹' (s ∩ f ⁻¹' t) : Set β) := by @@ -443,40 +447,40 @@ theorem preimage_eventuallyEq_target_inter_preimage_inter {e : LocalHomeomorph intro y hy hyu simp_rw [mem_inter_iff, mem_preimage, mem_inter_iff, e.mapsTo hy, true_and_iff, iff_self_and, e.left_inv hy, iff_true_intro hyu] -#align local_homeomorph.preimage_eventually_eq_target_inter_preimage_inter LocalHomeomorph.preimage_eventuallyEq_target_inter_preimage_inter +#align local_homeomorph.preimage_eventually_eq_target_inter_preimage_inter PartialHomeomorph.preimage_eventuallyEq_target_inter_preimage_inter theorem isOpen_inter_preimage {s : Set β} (hs : IsOpen s) : IsOpen (e.source ∩ e ⁻¹' s) := e.continuousOn.isOpen_inter_preimage e.open_source hs -#align local_homeomorph.preimage_open_of_open LocalHomeomorph.isOpen_inter_preimage +#align local_homeomorph.preimage_open_of_open PartialHomeomorph.isOpen_inter_preimage -/-- A local homeomorphism is an open map on its source. -/ +/-- A partial homeomorphism is an open map on its source. -/ lemma isOpen_image_of_subset_source {s : Set α} (hs : IsOpen s) (hse : s ⊆ e.source) : IsOpen (e '' s) := by rw [(image_eq_target_inter_inv_preimage (e := e) hse)] exact e.continuousOn_invFun.isOpen_inter_preimage e.open_target hs -/-- The inverse of a local homeomorphism `e` is an open map on `e.target`. -/ +/-- The inverse of a partial homeomorphism `e` is an open map on `e.target`. -/ lemma isOpen_image_symm_of_subset_target {t : Set β} (ht : IsOpen t) (hte : t ⊆ e.target) : IsOpen (e.symm '' t) := isOpen_image_of_subset_source e.symm ht (e.symm_source ▸ hte) /-! -### `LocalHomeomorph.IsImage` relation +### `PartialHomeomorph.IsImage` relation -We say that `t : Set β` is an image of `s : Set α` under a local homeomorphism `e` if any of the +We say that `t : Set β` is an image of `s : Set α` under a partial homeomorphism `e` if any of the following equivalent conditions hold: * `e '' (e.source ∩ s) = e.target ∩ t`; * `e.source ∩ e ⁻¹ t = e.source ∩ s`; * `∀ x ∈ e.source, e x ∈ t ↔ x ∈ s` (this one is used in the definition). -This definition is a restatement of `LocalEquiv.IsImage` for local homeomorphisms. In this section -we transfer API about `LocalEquiv.IsImage` to local homeomorphisms and add a few -`LocalHomeomorph`-specific lemmas like `LocalHomeomorph.IsImage.closure`. +This definition is a restatement of `PartialEquiv.IsImage` for partial homeomorphisms. +In this section we transfer API about `PartialEquiv.IsImage` to partial homeomorphisms and +add a few `PartialHomeomorph`-specific lemmas like `PartialHomeomorph.IsImage.closure`. -/ -/-- We say that `t : Set β` is an image of `s : Set α` under a local homeomorphism `e` if any of the -following equivalent conditions hold: +/-- We say that `t : Set β` is an image of `s : Set α` under a partial homeomorphism `e` +if any of the following equivalent conditions hold: * `e '' (e.source ∩ s) = e.target ∩ t`; * `e.source ∩ e ⁻¹ t = e.source ∩ s`; @@ -484,528 +488,531 @@ following equivalent conditions hold: -/ def IsImage (s : Set α) (t : Set β) : Prop := ∀ ⦃x⦄, x ∈ e.source → (e x ∈ t ↔ x ∈ s) -#align local_homeomorph.is_image LocalHomeomorph.IsImage +#align local_homeomorph.is_image PartialHomeomorph.IsImage namespace IsImage variable {e} {s : Set α} {t : Set β} {x : α} {y : β} -theorem toLocalEquiv (h : e.IsImage s t) : e.toLocalEquiv.IsImage s t := +theorem toPartialEquiv (h : e.IsImage s t) : e.toPartialEquiv.IsImage s t := h -#align local_homeomorph.is_image.to_local_equiv LocalHomeomorph.IsImage.toLocalEquiv +#align local_homeomorph.is_image.to_local_equiv PartialHomeomorph.IsImage.toPartialEquiv theorem apply_mem_iff (h : e.IsImage s t) (hx : x ∈ e.source) : e x ∈ t ↔ x ∈ s := h hx -#align local_homeomorph.is_image.apply_mem_iff LocalHomeomorph.IsImage.apply_mem_iff +#align local_homeomorph.is_image.apply_mem_iff PartialHomeomorph.IsImage.apply_mem_iff protected theorem symm (h : e.IsImage s t) : e.symm.IsImage t s := - h.toLocalEquiv.symm -#align local_homeomorph.is_image.symm LocalHomeomorph.IsImage.symm + h.toPartialEquiv.symm +#align local_homeomorph.is_image.symm PartialHomeomorph.IsImage.symm theorem symm_apply_mem_iff (h : e.IsImage s t) (hy : y ∈ e.target) : e.symm y ∈ s ↔ y ∈ t := h.symm hy -#align local_homeomorph.is_image.symm_apply_mem_iff LocalHomeomorph.IsImage.symm_apply_mem_iff +#align local_homeomorph.is_image.symm_apply_mem_iff PartialHomeomorph.IsImage.symm_apply_mem_iff @[simp] theorem symm_iff : e.symm.IsImage t s ↔ e.IsImage s t := ⟨fun h => h.symm, fun h => h.symm⟩ -#align local_homeomorph.is_image.symm_iff LocalHomeomorph.IsImage.symm_iff +#align local_homeomorph.is_image.symm_iff PartialHomeomorph.IsImage.symm_iff protected theorem mapsTo (h : e.IsImage s t) : MapsTo e (e.source ∩ s) (e.target ∩ t) := - h.toLocalEquiv.mapsTo -#align local_homeomorph.is_image.maps_to LocalHomeomorph.IsImage.mapsTo + h.toPartialEquiv.mapsTo +#align local_homeomorph.is_image.maps_to PartialHomeomorph.IsImage.mapsTo theorem symm_mapsTo (h : e.IsImage s t) : MapsTo e.symm (e.target ∩ t) (e.source ∩ s) := h.symm.mapsTo -#align local_homeomorph.is_image.symm_maps_to LocalHomeomorph.IsImage.symm_mapsTo +#align local_homeomorph.is_image.symm_maps_to PartialHomeomorph.IsImage.symm_mapsTo theorem image_eq (h : e.IsImage s t) : e '' (e.source ∩ s) = e.target ∩ t := - h.toLocalEquiv.image_eq -#align local_homeomorph.is_image.image_eq LocalHomeomorph.IsImage.image_eq + h.toPartialEquiv.image_eq +#align local_homeomorph.is_image.image_eq PartialHomeomorph.IsImage.image_eq theorem symm_image_eq (h : e.IsImage s t) : e.symm '' (e.target ∩ t) = e.source ∩ s := h.symm.image_eq -#align local_homeomorph.is_image.symm_image_eq LocalHomeomorph.IsImage.symm_image_eq +#align local_homeomorph.is_image.symm_image_eq PartialHomeomorph.IsImage.symm_image_eq theorem iff_preimage_eq : e.IsImage s t ↔ e.source ∩ e ⁻¹' t = e.source ∩ s := - LocalEquiv.IsImage.iff_preimage_eq -#align local_homeomorph.is_image.iff_preimage_eq LocalHomeomorph.IsImage.iff_preimage_eq + PartialEquiv.IsImage.iff_preimage_eq +#align local_homeomorph.is_image.iff_preimage_eq PartialHomeomorph.IsImage.iff_preimage_eq alias ⟨preimage_eq, of_preimage_eq⟩ := iff_preimage_eq -#align local_homeomorph.is_image.preimage_eq LocalHomeomorph.IsImage.preimage_eq -#align local_homeomorph.is_image.of_preimage_eq LocalHomeomorph.IsImage.of_preimage_eq +#align local_homeomorph.is_image.preimage_eq PartialHomeomorph.IsImage.preimage_eq +#align local_homeomorph.is_image.of_preimage_eq PartialHomeomorph.IsImage.of_preimage_eq theorem iff_symm_preimage_eq : e.IsImage s t ↔ e.target ∩ e.symm ⁻¹' s = e.target ∩ t := symm_iff.symm.trans iff_preimage_eq -#align local_homeomorph.is_image.iff_symm_preimage_eq LocalHomeomorph.IsImage.iff_symm_preimage_eq +#align local_homeomorph.is_image.iff_symm_preimage_eq PartialHomeomorph.IsImage.iff_symm_preimage_eq alias ⟨symm_preimage_eq, of_symm_preimage_eq⟩ := iff_symm_preimage_eq -#align local_homeomorph.is_image.symm_preimage_eq LocalHomeomorph.IsImage.symm_preimage_eq -#align local_homeomorph.is_image.of_symm_preimage_eq LocalHomeomorph.IsImage.of_symm_preimage_eq +#align local_homeomorph.is_image.symm_preimage_eq PartialHomeomorph.IsImage.symm_preimage_eq +#align local_homeomorph.is_image.of_symm_preimage_eq PartialHomeomorph.IsImage.of_symm_preimage_eq theorem iff_symm_preimage_eq' : e.IsImage s t ↔ e.target ∩ e.symm ⁻¹' (e.source ∩ s) = e.target ∩ t := by rw [iff_symm_preimage_eq, ← image_source_inter_eq, ← image_source_inter_eq'] -#align local_homeomorph.is_image.iff_symm_preimage_eq' LocalHomeomorph.IsImage.iff_symm_preimage_eq' +#align local_homeomorph.is_image.iff_symm_preimage_eq' PartialHomeomorph.IsImage.iff_symm_preimage_eq' alias ⟨symm_preimage_eq', of_symm_preimage_eq'⟩ := iff_symm_preimage_eq' -#align local_homeomorph.is_image.symm_preimage_eq' LocalHomeomorph.IsImage.symm_preimage_eq' -#align local_homeomorph.is_image.of_symm_preimage_eq' LocalHomeomorph.IsImage.of_symm_preimage_eq' +#align local_homeomorph.is_image.symm_preimage_eq' PartialHomeomorph.IsImage.symm_preimage_eq' +#align local_homeomorph.is_image.of_symm_preimage_eq' PartialHomeomorph.IsImage.of_symm_preimage_eq' theorem iff_preimage_eq' : e.IsImage s t ↔ e.source ∩ e ⁻¹' (e.target ∩ t) = e.source ∩ s := symm_iff.symm.trans iff_symm_preimage_eq' -#align local_homeomorph.is_image.iff_preimage_eq' LocalHomeomorph.IsImage.iff_preimage_eq' +#align local_homeomorph.is_image.iff_preimage_eq' PartialHomeomorph.IsImage.iff_preimage_eq' alias ⟨preimage_eq', of_preimage_eq'⟩ := iff_preimage_eq' -#align local_homeomorph.is_image.preimage_eq' LocalHomeomorph.IsImage.preimage_eq' -#align local_homeomorph.is_image.of_preimage_eq' LocalHomeomorph.IsImage.of_preimage_eq' +#align local_homeomorph.is_image.preimage_eq' PartialHomeomorph.IsImage.preimage_eq' +#align local_homeomorph.is_image.of_preimage_eq' PartialHomeomorph.IsImage.of_preimage_eq' theorem of_image_eq (h : e '' (e.source ∩ s) = e.target ∩ t) : e.IsImage s t := - LocalEquiv.IsImage.of_image_eq h -#align local_homeomorph.is_image.of_image_eq LocalHomeomorph.IsImage.of_image_eq + PartialEquiv.IsImage.of_image_eq h +#align local_homeomorph.is_image.of_image_eq PartialHomeomorph.IsImage.of_image_eq theorem of_symm_image_eq (h : e.symm '' (e.target ∩ t) = e.source ∩ s) : e.IsImage s t := - LocalEquiv.IsImage.of_symm_image_eq h -#align local_homeomorph.is_image.of_symm_image_eq LocalHomeomorph.IsImage.of_symm_image_eq + PartialEquiv.IsImage.of_symm_image_eq h +#align local_homeomorph.is_image.of_symm_image_eq PartialHomeomorph.IsImage.of_symm_image_eq protected theorem compl (h : e.IsImage s t) : e.IsImage sᶜ tᶜ := fun _ hx => (h hx).not -#align local_homeomorph.is_image.compl LocalHomeomorph.IsImage.compl +#align local_homeomorph.is_image.compl PartialHomeomorph.IsImage.compl protected theorem inter {s' t'} (h : e.IsImage s t) (h' : e.IsImage s' t') : e.IsImage (s ∩ s') (t ∩ t') := fun _ hx => (h hx).and (h' hx) -#align local_homeomorph.is_image.inter LocalHomeomorph.IsImage.inter +#align local_homeomorph.is_image.inter PartialHomeomorph.IsImage.inter protected theorem union {s' t'} (h : e.IsImage s t) (h' : e.IsImage s' t') : e.IsImage (s ∪ s') (t ∪ t') := fun _ hx => (h hx).or (h' hx) -#align local_homeomorph.is_image.union LocalHomeomorph.IsImage.union +#align local_homeomorph.is_image.union PartialHomeomorph.IsImage.union protected theorem diff {s' t'} (h : e.IsImage s t) (h' : e.IsImage s' t') : e.IsImage (s \ s') (t \ t') := h.inter h'.compl -#align local_homeomorph.is_image.diff LocalHomeomorph.IsImage.diff +#align local_homeomorph.is_image.diff PartialHomeomorph.IsImage.diff -theorem leftInvOn_piecewise {e' : LocalHomeomorph α β} [∀ i, Decidable (i ∈ s)] +theorem leftInvOn_piecewise {e' : PartialHomeomorph α β} [∀ i, Decidable (i ∈ s)] [∀ i, Decidable (i ∈ t)] (h : e.IsImage s t) (h' : e'.IsImage s t) : LeftInvOn (t.piecewise e.symm e'.symm) (s.piecewise e e') (s.ite e.source e'.source) := - h.toLocalEquiv.leftInvOn_piecewise h' -#align local_homeomorph.is_image.left_inv_on_piecewise LocalHomeomorph.IsImage.leftInvOn_piecewise + h.toPartialEquiv.leftInvOn_piecewise h' +#align local_homeomorph.is_image.left_inv_on_piecewise PartialHomeomorph.IsImage.leftInvOn_piecewise -theorem inter_eq_of_inter_eq_of_eqOn {e' : LocalHomeomorph α β} (h : e.IsImage s t) +theorem inter_eq_of_inter_eq_of_eqOn {e' : PartialHomeomorph α β} (h : e.IsImage s t) (h' : e'.IsImage s t) (hs : e.source ∩ s = e'.source ∩ s) (Heq : EqOn e e' (e.source ∩ s)) : e.target ∩ t = e'.target ∩ t := - h.toLocalEquiv.inter_eq_of_inter_eq_of_eqOn h' hs Heq -#align local_homeomorph.is_image.inter_eq_of_inter_eq_of_eq_on LocalHomeomorph.IsImage.inter_eq_of_inter_eq_of_eqOn + h.toPartialEquiv.inter_eq_of_inter_eq_of_eqOn h' hs Heq +#align local_homeomorph.is_image.inter_eq_of_inter_eq_of_eq_on PartialHomeomorph.IsImage.inter_eq_of_inter_eq_of_eqOn -theorem symm_eqOn_of_inter_eq_of_eqOn {e' : LocalHomeomorph α β} (h : e.IsImage s t) +theorem symm_eqOn_of_inter_eq_of_eqOn {e' : PartialHomeomorph α β} (h : e.IsImage s t) (hs : e.source ∩ s = e'.source ∩ s) (Heq : EqOn e e' (e.source ∩ s)) : EqOn e.symm e'.symm (e.target ∩ t) := - h.toLocalEquiv.symm_eq_on_of_inter_eq_of_eqOn hs Heq -#align local_homeomorph.is_image.symm_eq_on_of_inter_eq_of_eq_on LocalHomeomorph.IsImage.symm_eqOn_of_inter_eq_of_eqOn + h.toPartialEquiv.symm_eq_on_of_inter_eq_of_eqOn hs Heq +#align local_homeomorph.is_image.symm_eq_on_of_inter_eq_of_eq_on PartialHomeomorph.IsImage.symm_eqOn_of_inter_eq_of_eqOn theorem map_nhdsWithin_eq (h : e.IsImage s t) (hx : x ∈ e.source) : map e (𝓝[s] x) = 𝓝[t] e x := by rw [e.map_nhdsWithin_eq hx, h.image_eq, e.nhdsWithin_target_inter (e.map_source hx)] -#align local_homeomorph.is_image.map_nhds_within_eq LocalHomeomorph.IsImage.map_nhdsWithin_eq +#align local_homeomorph.is_image.map_nhds_within_eq PartialHomeomorph.IsImage.map_nhdsWithin_eq protected theorem closure (h : e.IsImage s t) : e.IsImage (closure s) (closure t) := fun x hx => by simp only [mem_closure_iff_nhdsWithin_neBot, ← h.map_nhdsWithin_eq hx, map_neBot_iff] -#align local_homeomorph.is_image.closure LocalHomeomorph.IsImage.closure +#align local_homeomorph.is_image.closure PartialHomeomorph.IsImage.closure protected theorem interior (h : e.IsImage s t) : e.IsImage (interior s) (interior t) := by simpa only [closure_compl, compl_compl] using h.compl.closure.compl -#align local_homeomorph.is_image.interior LocalHomeomorph.IsImage.interior +#align local_homeomorph.is_image.interior PartialHomeomorph.IsImage.interior protected theorem frontier (h : e.IsImage s t) : e.IsImage (frontier s) (frontier t) := h.closure.diff h.interior -#align local_homeomorph.is_image.frontier LocalHomeomorph.IsImage.frontier +#align local_homeomorph.is_image.frontier PartialHomeomorph.IsImage.frontier theorem isOpen_iff (h : e.IsImage s t) : IsOpen (e.source ∩ s) ↔ IsOpen (e.target ∩ t) := ⟨fun hs => h.symm_preimage_eq' ▸ e.symm.isOpen_inter_preimage hs, fun hs => h.preimage_eq' ▸ e.isOpen_inter_preimage hs⟩ -#align local_homeomorph.is_image.is_open_iff LocalHomeomorph.IsImage.isOpen_iff +#align local_homeomorph.is_image.is_open_iff PartialHomeomorph.IsImage.isOpen_iff -/-- Restrict a `LocalHomeomorph` to a pair of corresponding open sets. -/ -@[simps toLocalEquiv] -def restr (h : e.IsImage s t) (hs : IsOpen (e.source ∩ s)) : LocalHomeomorph α β where - toLocalEquiv := h.toLocalEquiv.restr +/-- Restrict a `PartialHomeomorph` to a pair of corresponding open sets. -/ +@[simps toPartialEquiv] +def restr (h : e.IsImage s t) (hs : IsOpen (e.source ∩ s)) : PartialHomeomorph α β where + toPartialEquiv := h.toPartialEquiv.restr open_source := hs open_target := h.isOpen_iff.1 hs continuousOn_toFun := e.continuousOn.mono (inter_subset_left _ _) continuousOn_invFun := e.symm.continuousOn.mono (inter_subset_left _ _) -#align local_homeomorph.is_image.restr LocalHomeomorph.IsImage.restr +#align local_homeomorph.is_image.restr PartialHomeomorph.IsImage.restr end IsImage theorem isImage_source_target : e.IsImage e.source e.target := - e.toLocalEquiv.isImage_source_target -#align local_homeomorph.is_image_source_target LocalHomeomorph.isImage_source_target + e.toPartialEquiv.isImage_source_target +#align local_homeomorph.is_image_source_target PartialHomeomorph.isImage_source_target -theorem isImage_source_target_of_disjoint (e' : LocalHomeomorph α β) +theorem isImage_source_target_of_disjoint (e' : PartialHomeomorph α β) (hs : Disjoint e.source e'.source) (ht : Disjoint e.target e'.target) : e.IsImage e'.source e'.target := - e.toLocalEquiv.isImage_source_target_of_disjoint e'.toLocalEquiv hs ht -#align local_homeomorph.is_image_source_target_of_disjoint LocalHomeomorph.isImage_source_target_of_disjoint + e.toPartialEquiv.isImage_source_target_of_disjoint e'.toPartialEquiv hs ht +#align local_homeomorph.is_image_source_target_of_disjoint PartialHomeomorph.isImage_source_target_of_disjoint -/-- Preimage of interior or interior of preimage coincide for local homeomorphisms, when restricted -to the source. -/ +/-- Preimage of interior or interior of preimage coincide for partial homeomorphisms, +when restricted to the source. -/ theorem preimage_interior (s : Set β) : e.source ∩ e ⁻¹' interior s = e.source ∩ interior (e ⁻¹' s) := (IsImage.of_preimage_eq rfl).interior.preimage_eq -#align local_homeomorph.preimage_interior LocalHomeomorph.preimage_interior +#align local_homeomorph.preimage_interior PartialHomeomorph.preimage_interior theorem preimage_closure (s : Set β) : e.source ∩ e ⁻¹' closure s = e.source ∩ closure (e ⁻¹' s) := (IsImage.of_preimage_eq rfl).closure.preimage_eq -#align local_homeomorph.preimage_closure LocalHomeomorph.preimage_closure +#align local_homeomorph.preimage_closure PartialHomeomorph.preimage_closure theorem preimage_frontier (s : Set β) : e.source ∩ e ⁻¹' frontier s = e.source ∩ frontier (e ⁻¹' s) := (IsImage.of_preimage_eq rfl).frontier.preimage_eq -#align local_homeomorph.preimage_frontier LocalHomeomorph.preimage_frontier +#align local_homeomorph.preimage_frontier PartialHomeomorph.preimage_frontier theorem isOpen_inter_preimage_symm {s : Set α} (hs : IsOpen s) : IsOpen (e.target ∩ e.symm ⁻¹' s) := e.symm.continuousOn.isOpen_inter_preimage e.open_target hs -#align local_homeomorph.preimage_open_of_open_symm LocalHomeomorph.isOpen_inter_preimage_symm +#align local_homeomorph.preimage_open_of_open_symm PartialHomeomorph.isOpen_inter_preimage_symm /-- The image of an open set in the source is open. -/ theorem image_isOpen_of_isOpen {s : Set α} (hs : IsOpen s) (h : s ⊆ e.source) : IsOpen (e '' s) := by - have : e '' s = e.target ∩ e.symm ⁻¹' s := e.toLocalEquiv.image_eq_target_inter_inv_preimage h + have : e '' s = e.target ∩ e.symm ⁻¹' s := e.toPartialEquiv.image_eq_target_inter_inv_preimage h rw [this] exact e.continuousOn_symm.isOpen_inter_preimage e.open_target hs -#align local_homeomorph.image_open_of_open LocalHomeomorph.image_isOpen_of_isOpen +#align local_homeomorph.image_open_of_open PartialHomeomorph.image_isOpen_of_isOpen /-- The image of the restriction of an open set to the source is open. -/ theorem image_isOpen_of_isOpen' {s : Set α} (hs : IsOpen s) : IsOpen (e '' (e.source ∩ s)) := image_isOpen_of_isOpen _ (IsOpen.inter e.open_source hs) (inter_subset_left _ _) -#align local_homeomorph.image_open_of_open' LocalHomeomorph.image_isOpen_of_isOpen' +#align local_homeomorph.image_open_of_open' PartialHomeomorph.image_isOpen_of_isOpen' -/-- A `LocalEquiv` with continuous open forward map and an open source is a `LocalHomeomorph`. -/ -def ofContinuousOpenRestrict (e : LocalEquiv α β) (hc : ContinuousOn e e.source) - (ho : IsOpenMap (e.source.restrict e)) (hs : IsOpen e.source) : LocalHomeomorph α β where - toLocalEquiv := e +/-- A `PartialEquiv` with continuous open forward map and open source is a `PartialHomeomorph`. -/ +def ofContinuousOpenRestrict (e : PartialEquiv α β) (hc : ContinuousOn e e.source) + (ho : IsOpenMap (e.source.restrict e)) (hs : IsOpen e.source) : PartialHomeomorph α β where + toPartialEquiv := e open_source := hs open_target := by simpa only [range_restrict, e.image_source_eq_target] using ho.isOpen_range continuousOn_toFun := hc continuousOn_invFun := e.image_source_eq_target ▸ ho.continuousOn_image_of_leftInvOn e.leftInvOn -#align local_homeomorph.of_continuous_open_restrict LocalHomeomorph.ofContinuousOpenRestrict +#align local_homeomorph.of_continuous_open_restrict PartialHomeomorph.ofContinuousOpenRestrict -/-- A `LocalEquiv` with continuous open forward map and an open source is a `LocalHomeomorph`. -/ -def ofContinuousOpen (e : LocalEquiv α β) (hc : ContinuousOn e e.source) (ho : IsOpenMap e) - (hs : IsOpen e.source) : LocalHomeomorph α β := +/-- A `PartialEquiv` with continuous open forward map and open source is a `PartialHomeomorph`. -/ +def ofContinuousOpen (e : PartialEquiv α β) (hc : ContinuousOn e e.source) (ho : IsOpenMap e) + (hs : IsOpen e.source) : PartialHomeomorph α β := ofContinuousOpenRestrict e hc (ho.restrict hs) hs -#align local_homeomorph.of_continuous_open LocalHomeomorph.ofContinuousOpen +#align local_homeomorph.of_continuous_open PartialHomeomorph.ofContinuousOpen -/-- Restricting a local homeomorphism `e` to `e.source ∩ s` when `s` is open. This is sometimes hard -to use because of the openness assumption, but it has the advantage that when it can -be used then its local_equiv is defeq to local_equiv.restr -/ -protected def restrOpen (s : Set α) (hs : IsOpen s) : LocalHomeomorph α β := +/-- Restricting a partial homeomorphism `e` to `e.source ∩ s` when `s` is open. +This is sometimes hard to use because of the openness assumption, but it has the advantage that +when it can be used then its `PartialEquiv` is defeq to `PartialEquiv.restr`. -/ +protected def restrOpen (s : Set α) (hs : IsOpen s) : PartialHomeomorph α β := (@IsImage.of_symm_preimage_eq α β _ _ e s (e.symm ⁻¹' s) rfl).restr (IsOpen.inter e.open_source hs) -#align local_homeomorph.restr_open LocalHomeomorph.restrOpen +#align local_homeomorph.restr_open PartialHomeomorph.restrOpen @[simp, mfld_simps] -theorem restrOpen_toLocalEquiv (s : Set α) (hs : IsOpen s) : - (e.restrOpen s hs).toLocalEquiv = e.toLocalEquiv.restr s := +theorem restrOpen_toPartialEquiv (s : Set α) (hs : IsOpen s) : + (e.restrOpen s hs).toPartialEquiv = e.toPartialEquiv.restr s := rfl -#align local_homeomorph.restr_open_to_local_equiv LocalHomeomorph.restrOpen_toLocalEquiv +#align local_homeomorph.restr_open_to_local_equiv PartialHomeomorph.restrOpen_toPartialEquiv --- Already simp via `LocalEquiv` +-- Already simp via `PartialEquiv` theorem restrOpen_source (s : Set α) (hs : IsOpen s) : (e.restrOpen s hs).source = e.source ∩ s := rfl -#align local_homeomorph.restr_open_source LocalHomeomorph.restrOpen_source +#align local_homeomorph.restr_open_source PartialHomeomorph.restrOpen_source -/-- Restricting a local homeomorphism `e` to `e.source ∩ interior s`. We use the interior to make -sure that the restriction is well defined whatever the set s, since local homeomorphisms are by +/-- Restricting a partial homeomorphism `e` to `e.source ∩ interior s`. We use the interior to make +sure that the restriction is well defined whatever the set s, since partial homeomorphisms are by definition defined on open sets. In applications where `s` is open, this coincides with the -restriction of local equivalences -/ +restriction of partial equivalences -/ @[simps! (config := mfld_cfg) apply symm_apply, simps! (config := .lemmasOnly) source target] -protected def restr (s : Set α) : LocalHomeomorph α β := +protected def restr (s : Set α) : PartialHomeomorph α β := e.restrOpen (interior s) isOpen_interior -#align local_homeomorph.restr LocalHomeomorph.restr +#align local_homeomorph.restr PartialHomeomorph.restr @[simp, mfld_simps] -theorem restr_toLocalEquiv (s : Set α) : - (e.restr s).toLocalEquiv = e.toLocalEquiv.restr (interior s) := +theorem restr_toPartialEquiv (s : Set α) : + (e.restr s).toPartialEquiv = e.toPartialEquiv.restr (interior s) := rfl -#align local_homeomorph.restr_to_local_equiv LocalHomeomorph.restr_toLocalEquiv +#align local_homeomorph.restr_to_local_equiv PartialHomeomorph.restr_toPartialEquiv theorem restr_source' (s : Set α) (hs : IsOpen s) : (e.restr s).source = e.source ∩ s := by rw [e.restr_source, hs.interior_eq] -#align local_homeomorph.restr_source' LocalHomeomorph.restr_source' +#align local_homeomorph.restr_source' PartialHomeomorph.restr_source' -theorem restr_toLocalEquiv' (s : Set α) (hs : IsOpen s) : - (e.restr s).toLocalEquiv = e.toLocalEquiv.restr s := by - rw [e.restr_toLocalEquiv, hs.interior_eq] -#align local_homeomorph.restr_to_local_equiv' LocalHomeomorph.restr_toLocalEquiv' +theorem restr_toPartialEquiv' (s : Set α) (hs : IsOpen s) : + (e.restr s).toPartialEquiv = e.toPartialEquiv.restr s := by + rw [e.restr_toPartialEquiv, hs.interior_eq] +#align local_homeomorph.restr_to_local_equiv' PartialHomeomorph.restr_toPartialEquiv' -theorem restr_eq_of_source_subset {e : LocalHomeomorph α β} {s : Set α} (h : e.source ⊆ s) : +theorem restr_eq_of_source_subset {e : PartialHomeomorph α β} {s : Set α} (h : e.source ⊆ s) : e.restr s = e := - toLocalEquiv_injective <| LocalEquiv.restr_eq_of_source_subset <| interior_maximal h e.open_source -#align local_homeomorph.restr_eq_of_source_subset LocalHomeomorph.restr_eq_of_source_subset + toPartialEquiv_injective <| PartialEquiv.restr_eq_of_source_subset <| + interior_maximal h e.open_source +#align local_homeomorph.restr_eq_of_source_subset PartialHomeomorph.restr_eq_of_source_subset @[simp, mfld_simps] -theorem restr_univ {e : LocalHomeomorph α β} : e.restr univ = e := +theorem restr_univ {e : PartialHomeomorph α β} : e.restr univ = e := restr_eq_of_source_subset (subset_univ _) -#align local_homeomorph.restr_univ LocalHomeomorph.restr_univ +#align local_homeomorph.restr_univ PartialHomeomorph.restr_univ theorem restr_source_inter (s : Set α) : e.restr (e.source ∩ s) = e.restr s := by - refine' LocalHomeomorph.ext _ _ (fun x => rfl) (fun x => rfl) _ + refine' PartialHomeomorph.ext _ _ (fun x => rfl) (fun x => rfl) _ simp [e.open_source.interior_eq, ← inter_assoc] -#align local_homeomorph.restr_source_inter LocalHomeomorph.restr_source_inter +#align local_homeomorph.restr_source_inter PartialHomeomorph.restr_source_inter -/-- The identity on the whole space as a local homeomorphism. -/ +/-- The identity on the whole space as a partial homeomorphism. -/ @[simps! (config := mfld_cfg) apply, simps! (config := .lemmasOnly) source target] -protected def refl (α : Type*) [TopologicalSpace α] : LocalHomeomorph α α := - (Homeomorph.refl α).toLocalHomeomorph -#align local_homeomorph.refl LocalHomeomorph.refl +protected def refl (α : Type*) [TopologicalSpace α] : PartialHomeomorph α α := + (Homeomorph.refl α).toPartialHomeomorph +#align local_homeomorph.refl PartialHomeomorph.refl @[simp, mfld_simps] -theorem refl_localEquiv : (LocalHomeomorph.refl α).toLocalEquiv = LocalEquiv.refl α := +theorem refl_localEquiv : (PartialHomeomorph.refl α).toPartialEquiv = PartialEquiv.refl α := rfl -#align local_homeomorph.refl_local_equiv LocalHomeomorph.refl_localEquiv +#align local_homeomorph.refl_local_equiv PartialHomeomorph.refl_localEquiv @[simp, mfld_simps] -theorem refl_symm : (LocalHomeomorph.refl α).symm = LocalHomeomorph.refl α := +theorem refl_symm : (PartialHomeomorph.refl α).symm = PartialHomeomorph.refl α := rfl -#align local_homeomorph.refl_symm LocalHomeomorph.refl_symm +#align local_homeomorph.refl_symm PartialHomeomorph.refl_symm section variable {s : Set α} (hs : IsOpen s) -/-- The identity local equiv on a set `s` -/ +/-- The identity partial equivalence on a set `s` -/ @[simps! (config := mfld_cfg) apply, simps! (config := .lemmasOnly) source target] -def ofSet (s : Set α) (hs : IsOpen s) : LocalHomeomorph α α where - toLocalEquiv := LocalEquiv.ofSet s +def ofSet (s : Set α) (hs : IsOpen s) : PartialHomeomorph α α where + toPartialEquiv := PartialEquiv.ofSet s open_source := hs open_target := hs continuousOn_toFun := continuous_id.continuousOn continuousOn_invFun := continuous_id.continuousOn -#align local_homeomorph.of_set LocalHomeomorph.ofSet +#align local_homeomorph.of_set PartialHomeomorph.ofSet @[simp, mfld_simps] -theorem ofSet_toLocalEquiv : (ofSet s hs).toLocalEquiv = LocalEquiv.ofSet s := +theorem ofSet_toPartialEquiv : (ofSet s hs).toPartialEquiv = PartialEquiv.ofSet s := rfl -#align local_homeomorph.of_set_to_local_equiv LocalHomeomorph.ofSet_toLocalEquiv +#align local_homeomorph.of_set_to_local_equiv PartialHomeomorph.ofSet_toPartialEquiv @[simp, mfld_simps] theorem ofSet_symm : (ofSet s hs).symm = ofSet s hs := rfl -#align local_homeomorph.of_set_symm LocalHomeomorph.ofSet_symm +#align local_homeomorph.of_set_symm PartialHomeomorph.ofSet_symm @[simp, mfld_simps] -theorem ofSet_univ_eq_refl : ofSet univ isOpen_univ = LocalHomeomorph.refl α := by ext <;> simp -#align local_homeomorph.of_set_univ_eq_refl LocalHomeomorph.ofSet_univ_eq_refl +theorem ofSet_univ_eq_refl : ofSet univ isOpen_univ = PartialHomeomorph.refl α := by ext <;> simp +#align local_homeomorph.of_set_univ_eq_refl PartialHomeomorph.ofSet_univ_eq_refl end -/-- Composition of two local homeomorphisms when the target of the first and the source of +/-- Composition of two partial homeomorphisms when the target of the first and the source of the second coincide. -/ -@[simps! apply symm_apply toLocalEquiv, simps! (config := .lemmasOnly) source target] -protected def trans' (h : e.target = e'.source) : LocalHomeomorph α γ where - toLocalEquiv := LocalEquiv.trans' e.toLocalEquiv e'.toLocalEquiv h +@[simps! apply symm_apply toPartialEquiv, simps! (config := .lemmasOnly) source target] +protected def trans' (h : e.target = e'.source) : PartialHomeomorph α γ where + toPartialEquiv := PartialEquiv.trans' e.toPartialEquiv e'.toPartialEquiv h open_source := e.open_source open_target := e'.open_target continuousOn_toFun := e'.continuousOn.comp e.continuousOn <| h ▸ e.mapsTo continuousOn_invFun := e.continuousOn_symm.comp e'.continuousOn_symm <| h.symm ▸ e'.symm_mapsTo -#align local_homeomorph.trans' LocalHomeomorph.trans' +#align local_homeomorph.trans' PartialHomeomorph.trans' -/-- Composing two local homeomorphisms, by restricting to the maximal domain where their +/-- Composing two partial homeomorphisms, by restricting to the maximal domain where their composition is well defined. -/ -protected def trans : LocalHomeomorph α γ := - LocalHomeomorph.trans' (e.symm.restrOpen e'.source e'.open_source).symm +protected def trans : PartialHomeomorph α γ := + PartialHomeomorph.trans' (e.symm.restrOpen e'.source e'.open_source).symm (e'.restrOpen e.target e.open_target) (by simp [inter_comm]) -#align local_homeomorph.trans LocalHomeomorph.trans +#align local_homeomorph.trans PartialHomeomorph.trans @[simp, mfld_simps] -theorem trans_toLocalEquiv : (e.trans e').toLocalEquiv = e.toLocalEquiv.trans e'.toLocalEquiv := +theorem trans_toPartialEquiv : + (e.trans e').toPartialEquiv = e.toPartialEquiv.trans e'.toPartialEquiv := rfl -#align local_homeomorph.trans_to_local_equiv LocalHomeomorph.trans_toLocalEquiv +#align local_homeomorph.trans_to_local_equiv PartialHomeomorph.trans_toPartialEquiv @[simp, mfld_simps] theorem coe_trans : (e.trans e' : α → γ) = e' ∘ e := rfl -#align local_homeomorph.coe_trans LocalHomeomorph.coe_trans +#align local_homeomorph.coe_trans PartialHomeomorph.coe_trans @[simp, mfld_simps] theorem coe_trans_symm : ((e.trans e').symm : γ → α) = e.symm ∘ e'.symm := rfl -#align local_homeomorph.coe_trans_symm LocalHomeomorph.coe_trans_symm +#align local_homeomorph.coe_trans_symm PartialHomeomorph.coe_trans_symm theorem trans_apply {x : α} : (e.trans e') x = e' (e x) := rfl -#align local_homeomorph.trans_apply LocalHomeomorph.trans_apply +#align local_homeomorph.trans_apply PartialHomeomorph.trans_apply theorem trans_symm_eq_symm_trans_symm : (e.trans e').symm = e'.symm.trans e.symm := rfl -#align local_homeomorph.trans_symm_eq_symm_trans_symm LocalHomeomorph.trans_symm_eq_symm_trans_symm +#align local_homeomorph.trans_symm_eq_symm_trans_symm PartialHomeomorph.trans_symm_eq_symm_trans_symm /- This could be considered as a simp lemma, but there are many situations where it makes something simple into something more complicated. -/ theorem trans_source : (e.trans e').source = e.source ∩ e ⁻¹' e'.source := - LocalEquiv.trans_source e.toLocalEquiv e'.toLocalEquiv -#align local_homeomorph.trans_source LocalHomeomorph.trans_source + PartialEquiv.trans_source e.toPartialEquiv e'.toPartialEquiv +#align local_homeomorph.trans_source PartialHomeomorph.trans_source theorem trans_source' : (e.trans e').source = e.source ∩ e ⁻¹' (e.target ∩ e'.source) := - LocalEquiv.trans_source' e.toLocalEquiv e'.toLocalEquiv -#align local_homeomorph.trans_source' LocalHomeomorph.trans_source' + PartialEquiv.trans_source' e.toPartialEquiv e'.toPartialEquiv +#align local_homeomorph.trans_source' PartialHomeomorph.trans_source' theorem trans_source'' : (e.trans e').source = e.symm '' (e.target ∩ e'.source) := - LocalEquiv.trans_source'' e.toLocalEquiv e'.toLocalEquiv -#align local_homeomorph.trans_source'' LocalHomeomorph.trans_source'' + PartialEquiv.trans_source'' e.toPartialEquiv e'.toPartialEquiv +#align local_homeomorph.trans_source'' PartialHomeomorph.trans_source'' theorem image_trans_source : e '' (e.trans e').source = e.target ∩ e'.source := - LocalEquiv.image_trans_source e.toLocalEquiv e'.toLocalEquiv -#align local_homeomorph.image_trans_source LocalHomeomorph.image_trans_source + PartialEquiv.image_trans_source e.toPartialEquiv e'.toPartialEquiv +#align local_homeomorph.image_trans_source PartialHomeomorph.image_trans_source theorem trans_target : (e.trans e').target = e'.target ∩ e'.symm ⁻¹' e.target := rfl -#align local_homeomorph.trans_target LocalHomeomorph.trans_target +#align local_homeomorph.trans_target PartialHomeomorph.trans_target theorem trans_target' : (e.trans e').target = e'.target ∩ e'.symm ⁻¹' (e'.source ∩ e.target) := trans_source' e'.symm e.symm -#align local_homeomorph.trans_target' LocalHomeomorph.trans_target' +#align local_homeomorph.trans_target' PartialHomeomorph.trans_target' theorem trans_target'' : (e.trans e').target = e' '' (e'.source ∩ e.target) := trans_source'' e'.symm e.symm -#align local_homeomorph.trans_target'' LocalHomeomorph.trans_target'' +#align local_homeomorph.trans_target'' PartialHomeomorph.trans_target'' theorem inv_image_trans_target : e'.symm '' (e.trans e').target = e'.source ∩ e.target := image_trans_source e'.symm e.symm -#align local_homeomorph.inv_image_trans_target LocalHomeomorph.inv_image_trans_target +#align local_homeomorph.inv_image_trans_target PartialHomeomorph.inv_image_trans_target -theorem trans_assoc (e'' : LocalHomeomorph γ δ) : +theorem trans_assoc (e'' : PartialHomeomorph γ δ) : (e.trans e').trans e'' = e.trans (e'.trans e'') := - toLocalEquiv_injective <| e.1.trans_assoc _ _ -#align local_homeomorph.trans_assoc LocalHomeomorph.trans_assoc + toPartialEquiv_injective <| e.1.trans_assoc _ _ +#align local_homeomorph.trans_assoc PartialHomeomorph.trans_assoc @[simp, mfld_simps] -theorem trans_refl : e.trans (LocalHomeomorph.refl β) = e := - toLocalEquiv_injective e.1.trans_refl -#align local_homeomorph.trans_refl LocalHomeomorph.trans_refl +theorem trans_refl : e.trans (PartialHomeomorph.refl β) = e := + toPartialEquiv_injective e.1.trans_refl +#align local_homeomorph.trans_refl PartialHomeomorph.trans_refl @[simp, mfld_simps] -theorem refl_trans : (LocalHomeomorph.refl α).trans e = e := - toLocalEquiv_injective e.1.refl_trans -#align local_homeomorph.refl_trans LocalHomeomorph.refl_trans +theorem refl_trans : (PartialHomeomorph.refl α).trans e = e := + toPartialEquiv_injective e.1.refl_trans +#align local_homeomorph.refl_trans PartialHomeomorph.refl_trans theorem trans_ofSet {s : Set β} (hs : IsOpen s) : e.trans (ofSet s hs) = e.restr (e ⁻¹' s) := - LocalHomeomorph.ext _ _ (fun _ => rfl) (fun _ => rfl) <| by + PartialHomeomorph.ext _ _ (fun _ => rfl) (fun _ => rfl) <| by rw [trans_source, restr_source, ofSet_source, ← preimage_interior, hs.interior_eq] -#align local_homeomorph.trans_of_set LocalHomeomorph.trans_ofSet +#align local_homeomorph.trans_of_set PartialHomeomorph.trans_ofSet theorem trans_of_set' {s : Set β} (hs : IsOpen s) : e.trans (ofSet s hs) = e.restr (e.source ∩ e ⁻¹' s) := by rw [trans_ofSet, restr_source_inter] -#align local_homeomorph.trans_of_set' LocalHomeomorph.trans_of_set' +#align local_homeomorph.trans_of_set' PartialHomeomorph.trans_of_set' theorem ofSet_trans {s : Set α} (hs : IsOpen s) : (ofSet s hs).trans e = e.restr s := - LocalHomeomorph.ext _ _ (fun x => rfl) (fun x => rfl) <| by simp [hs.interior_eq, inter_comm] -#align local_homeomorph.of_set_trans LocalHomeomorph.ofSet_trans + PartialHomeomorph.ext _ _ (fun x => rfl) (fun x => rfl) <| by simp [hs.interior_eq, inter_comm] +#align local_homeomorph.of_set_trans PartialHomeomorph.ofSet_trans theorem ofSet_trans' {s : Set α} (hs : IsOpen s) : (ofSet s hs).trans e = e.restr (e.source ∩ s) := by rw [ofSet_trans, restr_source_inter] -#align local_homeomorph.of_set_trans' LocalHomeomorph.ofSet_trans' +#align local_homeomorph.of_set_trans' PartialHomeomorph.ofSet_trans' @[simp, mfld_simps] theorem ofSet_trans_ofSet {s : Set α} (hs : IsOpen s) {s' : Set α} (hs' : IsOpen s') : (ofSet s hs).trans (ofSet s' hs') = ofSet (s ∩ s') (IsOpen.inter hs hs') := by rw [(ofSet s hs).trans_ofSet hs'] ext <;> simp [hs'.interior_eq] -#align local_homeomorph.of_set_trans_of_set LocalHomeomorph.ofSet_trans_ofSet +#align local_homeomorph.of_set_trans_of_set PartialHomeomorph.ofSet_trans_ofSet theorem restr_trans (s : Set α) : (e.restr s).trans e' = (e.trans e').restr s := - toLocalEquiv_injective <| LocalEquiv.restr_trans e.toLocalEquiv e'.toLocalEquiv (interior s) -#align local_homeomorph.restr_trans LocalHomeomorph.restr_trans + toPartialEquiv_injective <| + PartialEquiv.restr_trans e.toPartialEquiv e'.toPartialEquiv (interior s) +#align local_homeomorph.restr_trans PartialHomeomorph.restr_trans -/-- Postcompose a local homeomorphism with a homeomorphism. +/-- Postcompose a partial homeomorphism with a homeomorphism. We modify the source and target to have better definitional behavior. -/ @[simps! (config := .asFn)] -def transHomeomorph (e' : β ≃ₜ γ) : LocalHomeomorph α γ where - toLocalEquiv := e.toLocalEquiv.transEquiv e'.toEquiv +def transHomeomorph (e' : β ≃ₜ γ) : PartialHomeomorph α γ where + toPartialEquiv := e.toPartialEquiv.transEquiv e'.toEquiv open_source := e.open_source open_target := e.open_target.preimage e'.symm.continuous continuousOn_toFun := e'.continuous.comp_continuousOn e.continuousOn continuousOn_invFun := e.symm.continuousOn.comp e'.symm.continuous.continuousOn fun _ => id -#align local_homeomorph.trans_homeomorph LocalHomeomorph.transHomeomorph +#align local_homeomorph.trans_homeomorph PartialHomeomorph.transHomeomorph theorem transHomeomorph_eq_trans (e' : β ≃ₜ γ) : - e.transHomeomorph e' = e.trans e'.toLocalHomeomorph := - toLocalEquiv_injective <| LocalEquiv.transEquiv_eq_trans _ _ -#align local_homeomorph.trans_equiv_eq_trans LocalHomeomorph.transHomeomorph_eq_trans + e.transHomeomorph e' = e.trans e'.toPartialHomeomorph := + toPartialEquiv_injective <| PartialEquiv.transEquiv_eq_trans _ _ +#align local_homeomorph.trans_equiv_eq_trans PartialHomeomorph.transHomeomorph_eq_trans -/-- Precompose a local homeomorphism with a homeomorphism. +/-- Precompose a partial homeomorphism with a homeomorphism. We modify the source and target to have better definitional behavior. -/ @[simps! (config := .asFn)] -def _root_.Homeomorph.transLocalHomeomorph (e : α ≃ₜ β) : LocalHomeomorph α γ where - toLocalEquiv := e.toEquiv.transLocalEquiv e'.toLocalEquiv +def _root_.Homeomorph.transPartialHomeomorph (e : α ≃ₜ β) : PartialHomeomorph α γ where + toPartialEquiv := e.toEquiv.transPartialEquiv e'.toPartialEquiv open_source := e'.open_source.preimage e.continuous open_target := e'.open_target continuousOn_toFun := e'.continuousOn.comp e.continuous.continuousOn fun _ => id continuousOn_invFun := e.symm.continuous.comp_continuousOn e'.symm.continuousOn -#align homeomorph.trans_local_homeomorph Homeomorph.transLocalHomeomorph +#align homeomorph.trans_local_homeomorph Homeomorph.transPartialHomeomorph -theorem _root_.Homeomorph.transLocalHomeomorph_eq_trans (e : α ≃ₜ β) : - e.transLocalHomeomorph e' = e.toLocalHomeomorph.trans e' := - toLocalEquiv_injective <| Equiv.transLocalEquiv_eq_trans _ _ -#align homeomorph.trans_local_homeomorph_eq_trans Homeomorph.transLocalHomeomorph_eq_trans +theorem _root_.Homeomorph.transPartialHomeomorph_eq_trans (e : α ≃ₜ β) : + e.transPartialHomeomorph e' = e.toPartialHomeomorph.trans e' := + toPartialEquiv_injective <| Equiv.transPartialEquiv_eq_trans _ _ +#align homeomorph.trans_local_homeomorph_eq_trans Homeomorph.transPartialHomeomorph_eq_trans /-- `EqOnSource e e'` means that `e` and `e'` have the same source, and coincide there. They -should really be considered the same local equiv. -/ -def EqOnSource (e e' : LocalHomeomorph α β) : Prop := +should really be considered the same partial equivalence. -/ +def EqOnSource (e e' : PartialHomeomorph α β) : Prop := e.source = e'.source ∧ EqOn e e' e.source -#align local_homeomorph.eq_on_source LocalHomeomorph.EqOnSource +#align local_homeomorph.eq_on_source PartialHomeomorph.EqOnSource -theorem eqOnSource_iff (e e' : LocalHomeomorph α β) : - EqOnSource e e' ↔ LocalEquiv.EqOnSource e.toLocalEquiv e'.toLocalEquiv := +theorem eqOnSource_iff (e e' : PartialHomeomorph α β) : + EqOnSource e e' ↔ PartialEquiv.EqOnSource e.toPartialEquiv e'.toPartialEquiv := Iff.rfl -#align local_homeomorph.eq_on_source_iff LocalHomeomorph.eqOnSource_iff +#align local_homeomorph.eq_on_source_iff PartialHomeomorph.eqOnSource_iff /-- `EqOnSource` is an equivalence relation. -/ -instance eqOnSourceSetoid : Setoid (LocalHomeomorph α β) := - { LocalEquiv.eqOnSourceSetoid.comap toLocalEquiv with r := EqOnSource } +instance eqOnSourceSetoid : Setoid (PartialHomeomorph α β) := + { PartialEquiv.eqOnSourceSetoid.comap toPartialEquiv with r := EqOnSource } theorem eqOnSource_refl : e ≈ e := Setoid.refl _ -#align local_homeomorph.eq_on_source_refl LocalHomeomorph.eqOnSource_refl +#align local_homeomorph.eq_on_source_refl PartialHomeomorph.eqOnSource_refl -/-- If two local homeomorphisms are equivalent, so are their inverses. -/ -theorem EqOnSource.symm' {e e' : LocalHomeomorph α β} (h : e ≈ e') : e.symm ≈ e'.symm := - LocalEquiv.EqOnSource.symm' h -#align local_homeomorph.eq_on_source.symm' LocalHomeomorph.EqOnSource.symm' +/-- If two partial homeomorphisms are equivalent, so are their inverses. -/ +theorem EqOnSource.symm' {e e' : PartialHomeomorph α β} (h : e ≈ e') : e.symm ≈ e'.symm := + PartialEquiv.EqOnSource.symm' h +#align local_homeomorph.eq_on_source.symm' PartialHomeomorph.EqOnSource.symm' -/-- Two equivalent local homeomorphisms have the same source. -/ -theorem EqOnSource.source_eq {e e' : LocalHomeomorph α β} (h : e ≈ e') : e.source = e'.source := +/-- Two equivalent partial homeomorphisms have the same source. -/ +theorem EqOnSource.source_eq {e e' : PartialHomeomorph α β} (h : e ≈ e') : e.source = e'.source := h.1 -#align local_homeomorph.eq_on_source.source_eq LocalHomeomorph.EqOnSource.source_eq +#align local_homeomorph.eq_on_source.source_eq PartialHomeomorph.EqOnSource.source_eq -/-- Two equivalent local homeomorphisms have the same target. -/ -theorem EqOnSource.target_eq {e e' : LocalHomeomorph α β} (h : e ≈ e') : e.target = e'.target := +/-- Two equivalent partial homeomorphisms have the same target. -/ +theorem EqOnSource.target_eq {e e' : PartialHomeomorph α β} (h : e ≈ e') : e.target = e'.target := h.symm'.1 -#align local_homeomorph.eq_on_source.target_eq LocalHomeomorph.EqOnSource.target_eq +#align local_homeomorph.eq_on_source.target_eq PartialHomeomorph.EqOnSource.target_eq -/-- Two equivalent local homeomorphisms have coinciding `toFun` on the source -/ -theorem EqOnSource.eqOn {e e' : LocalHomeomorph α β} (h : e ≈ e') : EqOn e e' e.source := +/-- Two equivalent partial homeomorphisms have coinciding `toFun` on the source -/ +theorem EqOnSource.eqOn {e e' : PartialHomeomorph α β} (h : e ≈ e') : EqOn e e' e.source := h.2 -#align local_homeomorph.eq_on_source.eq_on LocalHomeomorph.EqOnSource.eqOn +#align local_homeomorph.eq_on_source.eq_on PartialHomeomorph.EqOnSource.eqOn -/-- Two equivalent local homeomorphisms have coinciding `invFun` on the target -/ -theorem EqOnSource.symm_eqOn_target {e e' : LocalHomeomorph α β} (h : e ≈ e') : +/-- Two equivalent partial homeomorphisms have coinciding `invFun` on the target -/ +theorem EqOnSource.symm_eqOn_target {e e' : PartialHomeomorph α β} (h : e ≈ e') : EqOn e.symm e'.symm e.target := h.symm'.2 -#align local_homeomorph.eq_on_source.symm_eq_on_target LocalHomeomorph.EqOnSource.symm_eqOn_target +#align local_homeomorph.eq_on_source.symm_eq_on_target PartialHomeomorph.EqOnSource.symm_eqOn_target -/-- Composition of local homeomorphisms respects equivalence -/ -theorem EqOnSource.trans' {e e' : LocalHomeomorph α β} {f f' : LocalHomeomorph β γ} (he : e ≈ e') - (hf : f ≈ f') : e.trans f ≈ e'.trans f' := - LocalEquiv.EqOnSource.trans' he hf -#align local_homeomorph.eq_on_source.trans' LocalHomeomorph.EqOnSource.trans' +/-- Composition of partial homeomorphisms respects equivalence. -/ +theorem EqOnSource.trans' {e e' : PartialHomeomorph α β} {f f' : PartialHomeomorph β γ} + (he : e ≈ e') (hf : f ≈ f') : e.trans f ≈ e'.trans f' := + PartialEquiv.EqOnSource.trans' he hf +#align local_homeomorph.eq_on_source.trans' PartialHomeomorph.EqOnSource.trans' -/-- Restriction of local homeomorphisms respects equivalence -/ -theorem EqOnSource.restr {e e' : LocalHomeomorph α β} (he : e ≈ e') (s : Set α) : +/-- Restriction of partial homeomorphisms respects equivalence -/ +theorem EqOnSource.restr {e e' : PartialHomeomorph α β} (he : e ≈ e') (s : Set α) : e.restr s ≈ e'.restr s := - LocalEquiv.EqOnSource.restr he _ -#align local_homeomorph.eq_on_source.restr LocalHomeomorph.EqOnSource.restr + PartialEquiv.EqOnSource.restr he _ +#align local_homeomorph.eq_on_source.restr PartialHomeomorph.EqOnSource.restr -/- Two equivalent local homeomorphisms are equal when the source and target are `univ`. -/ -theorem Set.EqOn.restr_eqOn_source {e e' : LocalHomeomorph α β} +/- Two equivalent partial homeomorphisms are equal when the source and target are `univ`. -/ +theorem Set.EqOn.restr_eqOn_source {e e' : PartialHomeomorph α β} (h : EqOn e e' (e.source ∩ e'.source)) : e.restr e'.source ≈ e'.restr e.source := by constructor · rw [e'.restr_source' _ e.open_source] @@ -1013,91 +1020,91 @@ theorem Set.EqOn.restr_eqOn_source {e e' : LocalHomeomorph α β} exact Set.inter_comm _ _ · rw [e.restr_source' _ e'.open_source] refine' (EqOn.trans _ h).trans _ <;> simp only [mfld_simps, eqOn_refl] -#align local_homeomorph.set.eq_on.restr_eq_on_source LocalHomeomorph.Set.EqOn.restr_eqOn_source +#align local_homeomorph.set.eq_on.restr_eq_on_source PartialHomeomorph.Set.EqOn.restr_eqOn_source -/-- Composition of a local homeomorphism and its inverse is equivalent to the restriction of the +/-- Composition of a partial homeomorphism and its inverse is equivalent to the restriction of the identity to the source -/ -theorem trans_self_symm : e.trans e.symm ≈ LocalHomeomorph.ofSet e.source e.open_source := - LocalEquiv.trans_self_symm _ -#align local_homeomorph.trans_self_symm LocalHomeomorph.trans_self_symm +theorem trans_self_symm : e.trans e.symm ≈ PartialHomeomorph.ofSet e.source e.open_source := + PartialEquiv.trans_self_symm _ +#align local_homeomorph.trans_self_symm PartialHomeomorph.trans_self_symm -theorem trans_symm_self : e.symm.trans e ≈ LocalHomeomorph.ofSet e.target e.open_target := +theorem trans_symm_self : e.symm.trans e ≈ PartialHomeomorph.ofSet e.target e.open_target := e.symm.trans_self_symm -#align local_homeomorph.trans_symm_self LocalHomeomorph.trans_symm_self +#align local_homeomorph.trans_symm_self PartialHomeomorph.trans_symm_self -theorem eq_of_eqOnSource_univ {e e' : LocalHomeomorph α β} (h : e ≈ e') (s : e.source = univ) +theorem eq_of_eqOnSource_univ {e e' : PartialHomeomorph α β} (h : e ≈ e') (s : e.source = univ) (t : e.target = univ) : e = e' := - toLocalEquiv_injective <| LocalEquiv.eq_of_eqOnSource_univ _ _ h s t -#align local_homeomorph.eq_of_eq_on_source_univ LocalHomeomorph.eq_of_eqOnSource_univ + toPartialEquiv_injective <| PartialEquiv.eq_of_eqOnSource_univ _ _ h s t +#align local_homeomorph.eq_of_eq_on_source_univ PartialHomeomorph.eq_of_eqOnSource_univ section Prod -/-- The product of two local homeomorphisms, as a local homeomorphism on the product space. -/ -@[simps! (config := mfld_cfg) toLocalEquiv apply, +/-- The product of two partial homeomorphisms, as a partial homeomorphism on the product space. -/ +@[simps! (config := mfld_cfg) toPartialEquiv apply, simps! (config := .lemmasOnly) source target symm_apply] -def prod (e : LocalHomeomorph α β) (e' : LocalHomeomorph γ δ) : - LocalHomeomorph (α × γ) (β × δ) where +def prod (e : PartialHomeomorph α β) (e' : PartialHomeomorph γ δ) : + PartialHomeomorph (α × γ) (β × δ) where open_source := e.open_source.prod e'.open_source open_target := e.open_target.prod e'.open_target continuousOn_toFun := e.continuousOn.prod_map e'.continuousOn continuousOn_invFun := e.continuousOn_symm.prod_map e'.continuousOn_symm - toLocalEquiv := e.toLocalEquiv.prod e'.toLocalEquiv -#align local_homeomorph.prod LocalHomeomorph.prod + toPartialEquiv := e.toPartialEquiv.prod e'.toPartialEquiv +#align local_homeomorph.prod PartialHomeomorph.prod @[simp, mfld_simps] -theorem prod_symm (e : LocalHomeomorph α β) (e' : LocalHomeomorph γ δ) : +theorem prod_symm (e : PartialHomeomorph α β) (e' : PartialHomeomorph γ δ) : (e.prod e').symm = e.symm.prod e'.symm := rfl -#align local_homeomorph.prod_symm LocalHomeomorph.prod_symm +#align local_homeomorph.prod_symm PartialHomeomorph.prod_symm @[simp] theorem refl_prod_refl {α β : Type*} [TopologicalSpace α] [TopologicalSpace β] : - (LocalHomeomorph.refl α).prod (LocalHomeomorph.refl β) = LocalHomeomorph.refl (α × β) := - LocalHomeomorph.ext _ _ (fun _ => rfl) (fun _ => rfl) univ_prod_univ -#align local_homeomorph.refl_prod_refl LocalHomeomorph.refl_prod_refl + (PartialHomeomorph.refl α).prod (PartialHomeomorph.refl β) = PartialHomeomorph.refl (α × β) := + PartialHomeomorph.ext _ _ (fun _ => rfl) (fun _ => rfl) univ_prod_univ +#align local_homeomorph.refl_prod_refl PartialHomeomorph.refl_prod_refl @[simp, mfld_simps] theorem prod_trans {η : Type*} {ε : Type*} [TopologicalSpace η] [TopologicalSpace ε] - (e : LocalHomeomorph α β) (f : LocalHomeomorph β γ) (e' : LocalHomeomorph δ η) - (f' : LocalHomeomorph η ε) : (e.prod e').trans (f.prod f') = (e.trans f).prod (e'.trans f') := - toLocalEquiv_injective <| e.1.prod_trans .. -#align local_homeomorph.prod_trans LocalHomeomorph.prod_trans + (e : PartialHomeomorph α β) (f : PartialHomeomorph β γ) (e' : PartialHomeomorph δ η) + (f' : PartialHomeomorph η ε) : (e.prod e').trans (f.prod f') = (e.trans f).prod (e'.trans f') := + toPartialEquiv_injective <| e.1.prod_trans .. +#align local_homeomorph.prod_trans PartialHomeomorph.prod_trans -theorem prod_eq_prod_of_nonempty {e₁ e₁' : LocalHomeomorph α β} {e₂ e₂' : LocalHomeomorph γ δ} +theorem prod_eq_prod_of_nonempty {e₁ e₁' : PartialHomeomorph α β} {e₂ e₂' : PartialHomeomorph γ δ} (h : (e₁.prod e₂).source.Nonempty) : e₁.prod e₂ = e₁'.prod e₂' ↔ e₁ = e₁' ∧ e₂ = e₂' := by obtain ⟨⟨x, y⟩, -⟩ := id h haveI : Nonempty α := ⟨x⟩ haveI : Nonempty β := ⟨e₁ x⟩ haveI : Nonempty γ := ⟨y⟩ haveI : Nonempty δ := ⟨e₂ y⟩ - simp_rw [LocalHomeomorph.ext_iff, prod_apply, prod_symm_apply, prod_source, Prod.ext_iff, + simp_rw [PartialHomeomorph.ext_iff, prod_apply, prod_symm_apply, prod_source, Prod.ext_iff, Set.prod_eq_prod_iff_of_nonempty h, forall_and, Prod.forall, forall_const, and_assoc, and_left_comm] -#align local_homeomorph.prod_eq_prod_of_nonempty LocalHomeomorph.prod_eq_prod_of_nonempty +#align local_homeomorph.prod_eq_prod_of_nonempty PartialHomeomorph.prod_eq_prod_of_nonempty -theorem prod_eq_prod_of_nonempty' {e₁ e₁' : LocalHomeomorph α β} {e₂ e₂' : LocalHomeomorph γ δ} +theorem prod_eq_prod_of_nonempty' {e₁ e₁' : PartialHomeomorph α β} {e₂ e₂' : PartialHomeomorph γ δ} (h : (e₁'.prod e₂').source.Nonempty) : e₁.prod e₂ = e₁'.prod e₂' ↔ e₁ = e₁' ∧ e₂ = e₂' := by rw [eq_comm, prod_eq_prod_of_nonempty h, eq_comm, @eq_comm _ e₂'] -#align local_homeomorph.prod_eq_prod_of_nonempty' LocalHomeomorph.prod_eq_prod_of_nonempty' +#align local_homeomorph.prod_eq_prod_of_nonempty' PartialHomeomorph.prod_eq_prod_of_nonempty' end Prod section Piecewise -/-- Combine two `LocalHomeomorph`s using `Set.piecewise`. The source of the new `LocalHomeomorph` -is `s.ite e.source e'.source = e.source ∩ s ∪ e'.source \ s`, and similarly for target. The -function sends `e.source ∩ s` to `e.target ∩ t` using `e` and `e'.source \ s` to `e'.target \ t` -using `e'`, and similarly for the inverse function. To ensure that the maps `toFun` and `invFun` -are inverse of each other on the new `source` and `target`, the definition assumes that the sets `s` -and `t` are related both by `e.is_image` and `e'.is_image`. To ensure that the new maps are -continuous on `source`/`target`, it also assumes that `e.source` and `e'.source` meet `frontier s` -on the same set and `e x = e' x` on this intersection. -/ -@[simps! (config := .asFn) toLocalEquiv apply] -def piecewise (e e' : LocalHomeomorph α β) (s : Set α) (t : Set β) [∀ x, Decidable (x ∈ s)] +/-- Combine two `PartialHomeomorph`s using `Set.piecewise`. The source of the new +`PartialHomeomorph` is `s.ite e.source e'.source = e.source ∩ s ∪ e'.source \ s`, and similarly for +target. The function sends `e.source ∩ s` to `e.target ∩ t` using `e` and +`e'.source \ s` to `e'.target \ t` using `e'`, and similarly for the inverse function. +To ensure the maps `toFun` and `invFun` are inverse of each other on the new `source` and `target`, +the definition assumes that the sets `s` and `t` are related both by `e.is_image` and `e'.is_image`. +To ensure that the new maps are continuous on `source`/`target`, it also assumes that `e.source` and +`e'.source` meet `frontier s` on the same set and `e x = e' x` on this intersection. -/ +@[simps! (config := .asFn) toPartialEquiv apply] +def piecewise (e e' : PartialHomeomorph α β) (s : Set α) (t : Set β) [∀ x, Decidable (x ∈ s)] [∀ y, Decidable (y ∈ t)] (H : e.IsImage s t) (H' : e'.IsImage s t) (Hs : e.source ∩ frontier s = e'.source ∩ frontier s) - (Heq : EqOn e e' (e.source ∩ frontier s)) : LocalHomeomorph α β where - toLocalEquiv := e.toLocalEquiv.piecewise e'.toLocalEquiv s t H H' + (Heq : EqOn e e' (e.source ∩ frontier s)) : PartialHomeomorph α β where + toPartialEquiv := e.toPartialEquiv.piecewise e'.toPartialEquiv s t H H' open_source := e.open_source.ite e'.open_source Hs open_target := e.open_target.ite e'.open_target <| H.frontier.inter_eq_of_inter_eq_of_eqOn H'.frontier Hs Heq @@ -1106,11 +1113,11 @@ def piecewise (e e' : LocalHomeomorph α β) (s : Set α) (t : Set β) [∀ x, D continuousOn_piecewise_ite e.continuousOn_symm e'.continuousOn_symm (H.frontier.inter_eq_of_inter_eq_of_eqOn H'.frontier Hs Heq) (H.frontier.symm_eqOn_of_inter_eq_of_eqOn Hs Heq) -#align local_homeomorph.piecewise LocalHomeomorph.piecewise +#align local_homeomorph.piecewise PartialHomeomorph.piecewise @[simp] -theorem symm_piecewise (e e' : LocalHomeomorph α β) {s : Set α} {t : Set β} [∀ x, Decidable (x ∈ s)] - [∀ y, Decidable (y ∈ t)] (H : e.IsImage s t) (H' : e'.IsImage s t) +theorem symm_piecewise (e e' : PartialHomeomorph α β) {s : Set α} {t : Set β} + [∀ x, Decidable (x ∈ s)] [∀ y, Decidable (y ∈ t)] (H : e.IsImage s t) (H' : e'.IsImage s t) (Hs : e.source ∩ frontier s = e'.source ∩ frontier s) (Heq : EqOn e e' (e.source ∩ frontier s)) : (e.piecewise e' s t H H' Hs Heq).symm = @@ -1118,42 +1125,42 @@ theorem symm_piecewise (e e' : LocalHomeomorph α β) {s : Set α} {t : Set β} (H.frontier.inter_eq_of_inter_eq_of_eqOn H'.frontier Hs Heq) (H.frontier.symm_eqOn_of_inter_eq_of_eqOn Hs Heq) := rfl -#align local_homeomorph.symm_piecewise LocalHomeomorph.symm_piecewise +#align local_homeomorph.symm_piecewise PartialHomeomorph.symm_piecewise -/-- Combine two `LocalHomeomorph`s with disjoint sources and disjoint targets. We reuse -`LocalHomeomorph.piecewise` then override `toLocalEquiv` to `LocalEquiv.disjointUnion`. +/-- Combine two `PartialHomeomorph`s with disjoint sources and disjoint targets. We reuse +`PartialHomeomorph.piecewise` then override `toPartialEquiv` to `PartialEquiv.disjointUnion`. This way we have better definitional equalities for `source` and `target`. -/ -def disjointUnion (e e' : LocalHomeomorph α β) [∀ x, Decidable (x ∈ e.source)] +def disjointUnion (e e' : PartialHomeomorph α β) [∀ x, Decidable (x ∈ e.source)] [∀ y, Decidable (y ∈ e.target)] (Hs : Disjoint e.source e'.source) - (Ht : Disjoint e.target e'.target) : LocalHomeomorph α β := + (Ht : Disjoint e.target e'.target) : PartialHomeomorph α β := (e.piecewise e' e.source e.target e.isImage_source_target (e'.isImage_source_target_of_disjoint e Hs.symm Ht.symm) (by rw [e.open_source.inter_frontier_eq, (Hs.symm.frontier_right e'.open_source).inter_eq]) (by rw [e.open_source.inter_frontier_eq] exact eqOn_empty _ _)).replaceEquiv - (e.toLocalEquiv.disjointUnion e'.toLocalEquiv Hs Ht) - (LocalEquiv.disjointUnion_eq_piecewise _ _ _ _).symm -#align local_homeomorph.disjoint_union LocalHomeomorph.disjointUnion + (e.toPartialEquiv.disjointUnion e'.toPartialEquiv Hs Ht) + (PartialEquiv.disjointUnion_eq_piecewise _ _ _ _).symm +#align local_homeomorph.disjoint_union PartialHomeomorph.disjointUnion end Piecewise section Pi variable {ι : Type*} [Fintype ι] {Xi Yi : ι → Type*} [∀ i, TopologicalSpace (Xi i)] - [∀ i, TopologicalSpace (Yi i)] (ei : ∀ i, LocalHomeomorph (Xi i) (Yi i)) + [∀ i, TopologicalSpace (Yi i)] (ei : ∀ i, PartialHomeomorph (Xi i) (Yi i)) -/-- The product of a finite family of `LocalHomeomorph`s. -/ -@[simps toLocalEquiv] -def pi : LocalHomeomorph (∀ i, Xi i) (∀ i, Yi i) where - toLocalEquiv := LocalEquiv.pi fun i => (ei i).toLocalEquiv +/-- The product of a finite family of `PartialHomeomorph`s. -/ +@[simps toPartialEquiv] +def pi : PartialHomeomorph (∀ i, Xi i) (∀ i, Yi i) where + toPartialEquiv := PartialEquiv.pi fun i => (ei i).toPartialEquiv open_source := isOpen_set_pi finite_univ fun i _ => (ei i).open_source open_target := isOpen_set_pi finite_univ fun i _ => (ei i).open_target continuousOn_toFun := continuousOn_pi.2 fun i => (ei i).continuousOn.comp (continuous_apply _).continuousOn fun _f hf => hf i trivial continuousOn_invFun := continuousOn_pi.2 fun i => (ei i).continuousOn_symm.comp (continuous_apply _).continuousOn fun _f hf => hf i trivial -#align local_homeomorph.pi LocalHomeomorph.pi +#align local_homeomorph.pi PartialHomeomorph.pi end Pi @@ -1166,17 +1173,17 @@ theorem continuousWithinAt_iff_continuousWithinAt_comp_right {f : β → γ} {s ContinuousWithinAt f s x ↔ ContinuousWithinAt (f ∘ e) (e ⁻¹' s) (e.symm x) := by simp_rw [ContinuousWithinAt, ← @tendsto_map'_iff _ _ _ _ e, e.map_nhdsWithin_preimage_eq (e.map_target h), (· ∘ ·), e.right_inv h] -#align local_homeomorph.continuous_within_at_iff_continuous_within_at_comp_right LocalHomeomorph.continuousWithinAt_iff_continuousWithinAt_comp_right +#align local_homeomorph.continuous_within_at_iff_continuous_within_at_comp_right PartialHomeomorph.continuousWithinAt_iff_continuousWithinAt_comp_right -/-- Continuity at a point can be read under right composition with a local homeomorphism, if the +/-- Continuity at a point can be read under right composition with a partial homeomorphism, if the point is in its target -/ theorem continuousAt_iff_continuousAt_comp_right {f : β → γ} {x : β} (h : x ∈ e.target) : ContinuousAt f x ↔ ContinuousAt (f ∘ e) (e.symm x) := by rw [← continuousWithinAt_univ, e.continuousWithinAt_iff_continuousWithinAt_comp_right h, preimage_univ, continuousWithinAt_univ] -#align local_homeomorph.continuous_at_iff_continuous_at_comp_right LocalHomeomorph.continuousAt_iff_continuousAt_comp_right +#align local_homeomorph.continuous_at_iff_continuous_at_comp_right PartialHomeomorph.continuousAt_iff_continuousAt_comp_right -/-- A function is continuous on a set if and only if its composition with a local homeomorphism +/-- A function is continuous on a set if and only if its composition with a partial homeomorphism on the right is continuous on the corresponding set. -/ theorem continuousOn_iff_continuousOn_comp_right {f : β → γ} {s : Set β} (h : s ⊆ e.target) : ContinuousOn f s ↔ ContinuousOn (f ∘ e) (e.source ∩ e ⁻¹' s) := by @@ -1185,7 +1192,7 @@ theorem continuousOn_iff_continuousOn_comp_right {f : β → γ} {s : Set β} (h rw [e.continuousWithinAt_iff_continuousWithinAt_comp_right (h hx), e.symm_image_eq_source_inter_preimage h, inter_comm, continuousWithinAt_inter] exact IsOpen.mem_nhds e.open_source (e.map_target (h hx)) -#align local_homeomorph.continuous_on_iff_continuous_on_comp_right LocalHomeomorph.continuousOn_iff_continuousOn_comp_right +#align local_homeomorph.continuous_on_iff_continuous_on_comp_right PartialHomeomorph.continuousOn_iff_continuousOn_comp_right /-- Continuity within a set at a point can be read under left composition with a local homeomorphism if a neighborhood of the initial point is sent to the source of the local @@ -1200,38 +1207,38 @@ theorem continuousWithinAt_iff_continuousWithinAt_comp_left {f : γ → α} {s : (e.continuousAt_symm (e.map_source hx)).continuousWithinAt ContinuousWithinAt.comp this fe_cont (subset_univ _) exact this.congr (fun y hy => by simp [e.left_inv hy.2]) (by simp [e.left_inv hx]) -#align local_homeomorph.continuous_within_at_iff_continuous_within_at_comp_left LocalHomeomorph.continuousWithinAt_iff_continuousWithinAt_comp_left +#align local_homeomorph.continuous_within_at_iff_continuous_within_at_comp_left PartialHomeomorph.continuousWithinAt_iff_continuousWithinAt_comp_left -/-- Continuity at a point can be read under left composition with a local homeomorphism if a -neighborhood of the initial point is sent to the source of the local homeomorphism-/ +/-- Continuity at a point can be read under left composition with a partial homeomorphism if a +neighborhood of the initial point is sent to the source of the partial homeomorphism-/ theorem continuousAt_iff_continuousAt_comp_left {f : γ → α} {x : γ} (h : f ⁻¹' e.source ∈ 𝓝 x) : ContinuousAt f x ↔ ContinuousAt (e ∘ f) x := by have hx : f x ∈ e.source := (mem_of_mem_nhds h : _) have h' : f ⁻¹' e.source ∈ 𝓝[univ] x := by rwa [nhdsWithin_univ] rw [← continuousWithinAt_univ, ← continuousWithinAt_univ, e.continuousWithinAt_iff_continuousWithinAt_comp_left hx h'] -#align local_homeomorph.continuous_at_iff_continuous_at_comp_left LocalHomeomorph.continuousAt_iff_continuousAt_comp_left +#align local_homeomorph.continuous_at_iff_continuous_at_comp_left PartialHomeomorph.continuousAt_iff_continuousAt_comp_left -/-- A function is continuous on a set if and only if its composition with a local homeomorphism +/-- A function is continuous on a set if and only if its composition with a partial homeomorphism on the left is continuous on the corresponding set. -/ theorem continuousOn_iff_continuousOn_comp_left {f : γ → α} {s : Set γ} (h : s ⊆ f ⁻¹' e.source) : ContinuousOn f s ↔ ContinuousOn (e ∘ f) s := forall₂_congr fun _x hx => e.continuousWithinAt_iff_continuousWithinAt_comp_left (h hx) (mem_of_superset self_mem_nhdsWithin h) -#align local_homeomorph.continuous_on_iff_continuous_on_comp_left LocalHomeomorph.continuousOn_iff_continuousOn_comp_left +#align local_homeomorph.continuous_on_iff_continuous_on_comp_left PartialHomeomorph.continuousOn_iff_continuousOn_comp_left -/-- A function is continuous if and only if its composition with a local homeomorphism +/-- A function is continuous if and only if its composition with a partial homeomorphism on the left is continuous and its image is contained in the source. -/ theorem continuous_iff_continuous_comp_left {f : γ → α} (h : f ⁻¹' e.source = univ) : Continuous f ↔ Continuous (e ∘ f) := by simp only [continuous_iff_continuousOn_univ] exact e.continuousOn_iff_continuousOn_comp_left (Eq.symm h).subset -#align local_homeomorph.continuous_iff_continuous_comp_left LocalHomeomorph.continuous_iff_continuous_comp_left +#align local_homeomorph.continuous_iff_continuous_comp_left PartialHomeomorph.continuous_iff_continuous_comp_left end Continuity -/-- The homeomorphism obtained by restricting a `LocalHomeomorph` to a subset of the source. -/ +/-- The homeomorphism obtained by restricting a `PartialHomeomorph` to a subset of the source. -/ @[simps] def homeomorphOfImageSubsetSource {s : Set α} {t : Set β} (hs : s ⊆ e.source) (ht : e '' s = t) : s ≃ₜ t := @@ -1245,18 +1252,18 @@ def homeomorphOfImageSubsetSource {s : Set α} {t : Set β} (hs : s ⊆ e.source right_inv := fun b => Subtype.eq <| e.right_inv (h₂ b.2) continuous_toFun := (e.continuousOn.mono hs).restrict_mapsTo h₁ continuous_invFun := (e.continuousOn_symm.mono h₂).restrict_mapsTo h₃ } -#align local_homeomorph.homeomorph_of_image_subset_source LocalHomeomorph.homeomorphOfImageSubsetSource +#align local_homeomorph.homeomorph_of_image_subset_source PartialHomeomorph.homeomorphOfImageSubsetSource -/-- A local homeomorphism defines a homeomorphism between its source and target. -/ +/-- A partial homeomorphism defines a homeomorphism between its source and target. -/ @[simps!] -- porting note: new `simps` def toHomeomorphSourceTarget : e.source ≃ₜ e.target := e.homeomorphOfImageSubsetSource subset_rfl e.image_source_eq_target -#align local_homeomorph.to_homeomorph_source_target LocalHomeomorph.toHomeomorphSourceTarget +#align local_homeomorph.to_homeomorph_source_target PartialHomeomorph.toHomeomorphSourceTarget -theorem secondCountableTopology_source [SecondCountableTopology β] (e : LocalHomeomorph α β) : +theorem secondCountableTopology_source [SecondCountableTopology β] (e : PartialHomeomorph α β) : SecondCountableTopology e.source := e.toHomeomorphSourceTarget.secondCountableTopology -#align local_homeomorph.second_countable_topology_source LocalHomeomorph.secondCountableTopology_source +#align local_homeomorph.second_countable_topology_source PartialHomeomorph.secondCountableTopology_source theorem nhds_eq_comap_inf_principal {x} (hx : x ∈ e.source) : 𝓝 x = comap e (𝓝 (e x)) ⊓ 𝓟 e.source := by @@ -1265,9 +1272,9 @@ theorem nhds_eq_comap_inf_principal {x} (hx : x ∈ e.source) : e.toHomeomorphSourceTarget.nhds_eq_comap, nhds_subtype_eq_comap] simp only [(· ∘ ·), toHomeomorphSourceTarget_apply_coe, comap_comap] -/-- If a local homeomorphism has source and target equal to univ, then it induces a homeomorphism +/-- If a partial homeomorphism has source and target equal to univ, then it induces a homeomorphism between the whole spaces, expressed in this definition. -/ -@[simps (config := mfld_cfg) apply symm_apply] -- porting note: todo: add a `LocalEquiv` version +@[simps (config := mfld_cfg) apply symm_apply] -- porting note: todo: add a `PartialEquiv` version def toHomeomorphOfSourceEqUnivTargetEqUniv (h : e.source = (univ : Set α)) (h' : e.target = univ) : α ≃ₜ β where toFun := e @@ -1284,7 +1291,7 @@ def toHomeomorphOfSourceEqUnivTargetEqUniv (h : e.source = (univ : Set α)) (h' simpa only [continuous_iff_continuousOn_univ, h] using e.continuousOn continuous_invFun := by simpa only [continuous_iff_continuousOn_univ, h'] using e.continuousOn_symm -#align local_homeomorph.to_homeomorph_of_source_eq_univ_target_eq_univ LocalHomeomorph.toHomeomorphOfSourceEqUnivTargetEqUniv +#align local_homeomorph.to_homeomorph_of_source_eq_univ_target_eq_univ PartialHomeomorph.toHomeomorphOfSourceEqUnivTargetEqUniv theorem openEmbedding_restrict : OpenEmbedding (e.source.restrict e) := by refine openEmbedding_of_continuous_injective_open (e.continuousOn.comp_continuous @@ -1293,37 +1300,38 @@ theorem openEmbedding_restrict : OpenEmbedding (e.source.restrict e) := by exact e.image_isOpen_of_isOpen (e.open_source.isOpenMap_subtype_val V hV) fun _ ⟨x, _, h⟩ ↦ h ▸ x.2 -/-- A local homeomorphism whose source is all of `α` defines an open embedding of `α` into `β`. The -converse is also true; see `OpenEmbedding.toLocalHomeomorph`. -/ +/-- A partial homeomorphism whose source is all of `α` defines an open embedding of `α` into `β`. +The converse is also true; see `OpenEmbedding.toPartialHomeomorph`. -/ theorem to_openEmbedding (h : e.source = Set.univ) : OpenEmbedding e := e.openEmbedding_restrict.comp ((Homeomorph.setCongr h).trans <| Homeomorph.Set.univ α).symm.openEmbedding -#align local_homeomorph.to_open_embedding LocalHomeomorph.to_openEmbedding +#align local_homeomorph.to_open_embedding PartialHomeomorph.to_openEmbedding -end LocalHomeomorph +end PartialHomeomorph namespace Homeomorph variable (e : α ≃ₜ β) (e' : β ≃ₜ γ) -/- Register as simp lemmas that the fields of a local homeomorphism built from a homeomorphism +/- Register as simp lemmas that the fields of a partial homeomorphism built from a homeomorphism correspond to the fields of the original homeomorphism. -/ @[simp, mfld_simps] -theorem refl_toLocalHomeomorph : (Homeomorph.refl α).toLocalHomeomorph = LocalHomeomorph.refl α := +theorem refl_toPartialHomeomorph : + (Homeomorph.refl α).toPartialHomeomorph = PartialHomeomorph.refl α := rfl -#align homeomorph.refl_to_local_homeomorph Homeomorph.refl_toLocalHomeomorph +#align homeomorph.refl_to_local_homeomorph Homeomorph.refl_toPartialHomeomorph @[simp, mfld_simps] -theorem symm_toLocalHomeomorph : e.symm.toLocalHomeomorph = e.toLocalHomeomorph.symm := +theorem symm_toPartialHomeomorph : e.symm.toPartialHomeomorph = e.toPartialHomeomorph.symm := rfl -#align homeomorph.symm_to_local_homeomorph Homeomorph.symm_toLocalHomeomorph +#align homeomorph.symm_to_local_homeomorph Homeomorph.symm_toPartialHomeomorph @[simp, mfld_simps] -theorem trans_toLocalHomeomorph : - (e.trans e').toLocalHomeomorph = e.toLocalHomeomorph.trans e'.toLocalHomeomorph := - LocalHomeomorph.toLocalEquiv_injective <| Equiv.trans_toLocalEquiv _ _ -#align homeomorph.trans_to_local_homeomorph Homeomorph.trans_toLocalHomeomorph +theorem trans_toPartialHomeomorph : + (e.trans e').toPartialHomeomorph = e.toPartialHomeomorph.trans e'.toPartialHomeomorph := + PartialHomeomorph.toPartialEquiv_injective <| Equiv.trans_toPartialEquiv _ _ +#align homeomorph.trans_to_local_homeomorph Homeomorph.trans_toPartialHomeomorph end Homeomorph @@ -1331,13 +1339,24 @@ namespace OpenEmbedding variable (f : α → β) (h : OpenEmbedding f) -/-- An open embedding of `α` into `β`, with `α` nonempty, defines a local homeomorphism whose source -is all of `α`. The converse is also true; see `LocalHomeomorph.to_openEmbedding`. -/ +/-- An open embedding of `α` into `β`, with `α` nonempty, defines a partial homeomorphism +whose source is all of `α`. The converse is also true; see `PartialHomeomorph.to_openEmbedding`. -/ @[simps! (config := mfld_cfg) apply source target] -noncomputable def toLocalHomeomorph [Nonempty α] : LocalHomeomorph α β := - LocalHomeomorph.ofContinuousOpen ((h.toEmbedding.inj.injOn univ).toLocalEquiv _ _) +noncomputable def toPartialHomeomorph [Nonempty α] : PartialHomeomorph α β := + PartialHomeomorph.ofContinuousOpen ((h.toEmbedding.inj.injOn univ).toPartialEquiv _ _) h.continuous.continuousOn h.isOpenMap isOpen_univ -#align open_embedding.to_local_homeomorph OpenEmbedding.toLocalHomeomorph +#align open_embedding.to_local_homeomorph OpenEmbedding.toPartialHomeomorph + +variable [Nonempty α] + +lemma toPartialHomeomorph_left_inv {x : α} : (h.toPartialHomeomorph f).symm (f x) = x := by + rw [← congr_fun (h.toPartialHomeomorph_apply f), PartialHomeomorph.left_inv] + exact Set.mem_univ _ + +lemma toPartialHomeomorph_right_inv {x : β} (hx : x ∈ Set.range f) : + f ((h.toPartialHomeomorph f).symm x) = x := by + rw [← congr_fun (h.toPartialHomeomorph_apply f), PartialHomeomorph.right_inv] + rwa [toPartialHomeomorph_target] end OpenEmbedding @@ -1347,10 +1366,10 @@ open TopologicalSpace variable (s : Opens α) [Nonempty s] -/-- The inclusion of an open subset `s` of a space `α` into `α` is a local homeomorphism from the +/-- The inclusion of an open subset `s` of a space `α` into `α` is a partial homeomorphism from the subtype `s` to `α`. -/ -noncomputable def localHomeomorphSubtypeCoe : LocalHomeomorph s α := - OpenEmbedding.toLocalHomeomorph _ s.2.openEmbedding_subtype_val +noncomputable def localHomeomorphSubtypeCoe : PartialHomeomorph s α := + OpenEmbedding.toPartialHomeomorph _ s.2.openEmbedding_subtype_val #align topological_space.opens.local_homeomorph_subtype_coe TopologicalSpace.Opens.localHomeomorphSubtypeCoe @[simp, mfld_simps] @@ -1371,34 +1390,34 @@ theorem localHomeomorphSubtypeCoe_target : s.localHomeomorphSubtypeCoe.target = end TopologicalSpace.Opens -namespace LocalHomeomorph +namespace PartialHomeomorph open TopologicalSpace -variable (e : LocalHomeomorph α β) +variable (e : PartialHomeomorph α β) variable (s : Opens α) [Nonempty s] -/-- The restriction of a local homeomorphism `e` to an open subset `s` of the domain type produces a -local homeomorphism whose domain is the subtype `s`.-/ -noncomputable def subtypeRestr : LocalHomeomorph s β := +/-- The restriction of a partial homeomorphism `e` to an open subset `s` of the domain type +produces a partial homeomorphism whose domain is the subtype `s`. -/ +noncomputable def subtypeRestr : PartialHomeomorph s β := s.localHomeomorphSubtypeCoe.trans e -#align local_homeomorph.subtype_restr LocalHomeomorph.subtypeRestr +#align local_homeomorph.subtype_restr PartialHomeomorph.subtypeRestr theorem subtypeRestr_def : e.subtypeRestr s = s.localHomeomorphSubtypeCoe.trans e := rfl -#align local_homeomorph.subtype_restr_def LocalHomeomorph.subtypeRestr_def +#align local_homeomorph.subtype_restr_def PartialHomeomorph.subtypeRestr_def @[simp, mfld_simps] theorem subtypeRestr_coe : - ((e.subtypeRestr s : LocalHomeomorph s β) : s → β) = Set.restrict ↑s (e : α → β) := + ((e.subtypeRestr s : PartialHomeomorph s β) : s → β) = Set.restrict ↑s (e : α → β) := rfl -#align local_homeomorph.subtype_restr_coe LocalHomeomorph.subtypeRestr_coe +#align local_homeomorph.subtype_restr_coe PartialHomeomorph.subtypeRestr_coe @[simp, mfld_simps] theorem subtypeRestr_source : (e.subtypeRestr s).source = (↑) ⁻¹' e.source := by simp only [subtypeRestr_def, mfld_simps] -#align local_homeomorph.subtype_restr_source LocalHomeomorph.subtypeRestr_source +#align local_homeomorph.subtype_restr_source PartialHomeomorph.subtypeRestr_source variable {s} @@ -1406,13 +1425,13 @@ theorem map_subtype_source {x : s} (hxe : (x : α) ∈ e.source): e x ∈ (e.sub refine' ⟨e.map_source hxe, _⟩ rw [s.localHomeomorphSubtypeCoe_target, mem_preimage, e.leftInvOn hxe] exact x.prop -#align local_homeomorph.map_subtype_source LocalHomeomorph.map_subtype_source +#align local_homeomorph.map_subtype_source PartialHomeomorph.map_subtype_source variable (s) /- This lemma characterizes the transition functions of an open subset in terms of the transition functions of the original space. -/ -theorem subtypeRestr_symm_trans_subtypeRestr (f f' : LocalHomeomorph α β) : +theorem subtypeRestr_symm_trans_subtypeRestr (f f' : PartialHomeomorph α β) : (f.subtypeRestr s).symm.trans (f'.subtypeRestr s) ≈ (f.symm.trans f').restr (f.target ∩ f.symm ⁻¹' s) := by simp only [subtypeRestr_def, trans_symm_eq_symm_trans_symm] @@ -1428,7 +1447,7 @@ theorem subtypeRestr_symm_trans_subtypeRestr (f f' : LocalHomeomorph α β) : -- f has been eliminated !!! refine' Setoid.trans (trans_symm_self s.localHomeomorphSubtypeCoe) _ simp only [mfld_simps, Setoid.refl] -#align local_homeomorph.subtype_restr_symm_trans_subtype_restr LocalHomeomorph.subtypeRestr_symm_trans_subtypeRestr +#align local_homeomorph.subtype_restr_symm_trans_subtype_restr PartialHomeomorph.subtypeRestr_symm_trans_subtypeRestr theorem subtypeRestr_symm_eqOn (U : Opens α) [Nonempty U] : EqOn e.symm (Subtype.val ∘ (e.subtypeRestr U).symm) (e.subtypeRestr U).target := by @@ -1443,18 +1462,18 @@ theorem subtypeRestr_symm_eqOn_of_le {U V : Opens α} [Nonempty U] [Nonempty V] (e.subtypeRestr U).target := by set i := Set.inclusion hUV intro y hy - dsimp [LocalHomeomorph.subtypeRestr_def] at hy ⊢ + dsimp [PartialHomeomorph.subtypeRestr_def] at hy ⊢ have hyV : e.symm y ∈ V.localHomeomorphSubtypeCoe.target := by rw [Opens.localHomeomorphSubtypeCoe_target] at hy ⊢ exact hUV hy.2 refine' V.localHomeomorphSubtypeCoe.injOn _ trivial _ - · rw [← LocalHomeomorph.symm_target] - apply LocalHomeomorph.map_source - rw [LocalHomeomorph.symm_source] + · rw [← PartialHomeomorph.symm_target] + apply PartialHomeomorph.map_source + rw [PartialHomeomorph.symm_source] exact hyV · rw [V.localHomeomorphSubtypeCoe.right_inv hyV] show _ = U.localHomeomorphSubtypeCoe _ rw [U.localHomeomorphSubtypeCoe.right_inv hy.2] -#align local_homeomorph.subtype_restr_symm_eq_on_of_le LocalHomeomorph.subtypeRestr_symm_eqOn_of_le +#align local_homeomorph.subtype_restr_symm_eq_on_of_le PartialHomeomorph.subtypeRestr_symm_eqOn_of_le -end LocalHomeomorph +end PartialHomeomorph diff --git a/Mathlib/Topology/Semicontinuous.lean b/Mathlib/Topology/Semicontinuous.lean index 3204a1d0f1ffa..4ca4fa36d269f 100644 --- a/Mathlib/Topology/Semicontinuous.lean +++ b/Mathlib/Topology/Semicontinuous.lean @@ -3,7 +3,7 @@ Copyright (c) 2021 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ -import Mathlib.Algebra.IndicatorFunction +import Mathlib.Algebra.Function.Indicator import Mathlib.Topology.ContinuousOn import Mathlib.Topology.Instances.ENNReal diff --git a/Mathlib/Topology/Sheaves/LocalPredicate.lean b/Mathlib/Topology/Sheaves/LocalPredicate.lean index 8b1e61d4bdf67..9cbd1e3f6b1a6 100644 --- a/Mathlib/Topology/Sheaves/LocalPredicate.lean +++ b/Mathlib/Topology/Sheaves/LocalPredicate.lean @@ -5,7 +5,7 @@ Authors: Johan Commelin, Scott Morrison, Adam Topaz -/ import Mathlib.Topology.Sheaves.SheafOfFunctions import Mathlib.Topology.Sheaves.Stalks -import Mathlib.Topology.LocalHomeomorph +import Mathlib.Topology.PartialHomeomorph import Mathlib.Topology.Sheaves.SheafCondition.UniqueGluing #align_import topology.sheaves.local_predicate from "leanprover-community/mathlib"@"5dc6092d09e5e489106865241986f7f2ad28d4c8" diff --git a/Mathlib/Topology/Support.lean b/Mathlib/Topology/Support.lean index 8e651d564976a..81b3234fa8e6a 100644 --- a/Mathlib/Topology/Support.lean +++ b/Mathlib/Topology/Support.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Floris van Doorn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn, Patrick Massot -/ +import Mathlib.Algebra.Module.Basic import Mathlib.Topology.Separation #align_import topology.support from "leanprover-community/mathlib"@"d90e4e186f1d18e375dcd4e5b5f6364b01cb3e46" diff --git a/Mathlib/Topology/VectorBundle/Basic.lean b/Mathlib/Topology/VectorBundle/Basic.lean index de9ecf145514d..625d8332aaf98 100644 --- a/Mathlib/Topology/VectorBundle/Basic.lean +++ b/Mathlib/Topology/VectorBundle/Basic.lean @@ -344,7 +344,7 @@ set_option linter.uppercaseLean3 false in theorem apply_symm_apply_eq_coordChangeL (e e' : Trivialization F (π F E)) [e.IsLinear R] [e'.IsLinear R] {b : B} (hb : b ∈ e.baseSet ∩ e'.baseSet) (v : F) : - e' (e.toLocalHomeomorph.symm (b, v)) = (b, e.coordChangeL R e' b v) := by + e' (e.toPartialHomeomorph.symm (b, v)) = (b, e.coordChangeL R e' b v) := by rw [e.mk_coordChangeL e' hb, e.mk_symm hb.1] set_option linter.uppercaseLean3 false in #align trivialization.apply_symm_apply_eq_coord_changeL Trivialization.apply_symm_apply_eq_coordChangeL @@ -354,7 +354,7 @@ right-hand side is ugly, but has good definitional properties for specifically d trivializations. -/ theorem coordChangeL_apply' (e e' : Trivialization F (π F E)) [e.IsLinear R] [e'.IsLinear R] {b : B} (hb : b ∈ e.baseSet ∩ e'.baseSet) (y : F) : - coordChangeL R e e' b y = (e' (e.toLocalHomeomorph.symm (b, y))).2 := by + coordChangeL R e e' b y = (e' (e.toPartialHomeomorph.symm (b, y))).2 := by rw [e.coordChangeL_apply e' hb, e.mk_symm hb.1] set_option linter.uppercaseLean3 false in #align trivialization.coord_changeL_apply' Trivialization.coordChangeL_apply' @@ -521,7 +521,7 @@ variable {R} theorem symm_apply_eq_mk_continuousLinearEquivAt_symm (e : Trivialization F (π F E)) [e.IsLinear R] (b : B) (hb : b ∈ e.baseSet) (z : F) : - e.toLocalHomeomorph.symm ⟨b, z⟩ = ⟨b, (e.continuousLinearEquivAt R b hb).symm z⟩ := by + e.toPartialHomeomorph.symm ⟨b, z⟩ = ⟨b, (e.continuousLinearEquivAt R b hb).symm z⟩ := by have h : (b, z) ∈ e.target · rw [e.target_eq] exact ⟨hb, mem_univ _⟩ @@ -649,7 +649,7 @@ protected def TotalSpace := #align vector_bundle_core.total_space VectorBundleCore.TotalSpace /-- Local homeomorphism version of the trivialization change. -/ -def trivChange (i j : ι) : LocalHomeomorph (B × F) (B × F) := +def trivChange (i j : ι) : PartialHomeomorph (B × F) (B × F) := Z.toFiberBundleCore.trivChange i j #align vector_bundle_core.triv_change VectorBundleCore.trivChange @@ -712,7 +712,7 @@ theorem mem_localTriv_target (p : B × F) : @[simp, mfld_simps] theorem localTriv_symm_fst (p : B × F) : - (Z.localTriv i).toLocalHomeomorph.symm p = ⟨p.1, Z.coordChange i (Z.indexAt p.1) p.1 p.2⟩ := + (Z.localTriv i).toPartialHomeomorph.symm p = ⟨p.1, Z.coordChange i (Z.indexAt p.1) p.1 p.2⟩ := rfl #align vector_bundle_core.local_triv_symm_fst VectorBundleCore.localTriv_symm_fst diff --git a/Mathlib/Topology/VectorBundle/Hom.lean b/Mathlib/Topology/VectorBundle/Hom.lean index 88a8cc9dab708..1a6b649526806 100644 --- a/Mathlib/Topology/VectorBundle/Hom.lean +++ b/Mathlib/Topology/VectorBundle/Hom.lean @@ -175,7 +175,7 @@ theorem continuousLinearMap_apply (p : TotalSpace (F₁ →SL[σ] F₂) fun x => #align pretrivialization.continuous_linear_map_apply Pretrivialization.continuousLinearMap_apply theorem continuousLinearMap_symm_apply (p : B × (F₁ →SL[σ] F₂)) : - (continuousLinearMap σ e₁ e₂).toLocalEquiv.symm p = + (continuousLinearMap σ e₁ e₂).toPartialEquiv.symm p = ⟨p.1, .comp (e₂.symmL 𝕜₂ p.1) (p.2.comp (e₁.continuousLinearMapAt 𝕜₁ p.1))⟩ := rfl #align pretrivialization.continuous_linear_map_symm_apply Pretrivialization.continuousLinearMap_symm_apply diff --git a/docs/references.bib b/docs/references.bib index 490980d11cd07..ace2c2904f440 100644 --- a/docs/references.bib +++ b/docs/references.bib @@ -2324,6 +2324,14 @@ @Book{ rudin2006real isbn = {0-07-100276-6} } +@Article{ ruzsa2009, + author = {Ruzsa, Imre}, + title = {Sumsets and structure}, + journal = {Combinatorial Number Theory and Additive Group Theory}, + year = {2009}, + month = {01} +} + @Article{ salwinski2018, author = {Salwinski, David}, title = {Euler's sine product formula: an elementary proof}, diff --git a/lake-manifest.json b/lake-manifest.json index cc9da57b5fd74..397f4d21cb731 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -4,7 +4,7 @@ [{"url": "https://github.com/leanprover/std4", "type": "git", "subDir": null, - "rev": "dbb4045860667f0d09669dbfb524b6e7b0ca3aca", + "rev": "483fd2846f9fe5107011ece0cc3d8d88af1a8603", "name": "std", "manifestFile": "lake-manifest.json", "inputRev": "main", diff --git a/scripts/bench/temci-config.run.yml b/scripts/bench/temci-config.run.yml index b737b9776c1c4..e0872f2798a78 100644 --- a/scripts/bench/temci-config.run.yml +++ b/scripts/bench/temci-config.run.yml @@ -1,15 +1,14 @@ - attributes: description: build - time: &time - runner: perf_stat - perf_stat: - properties: ['wall-clock', 'task-clock', 'instructions', 'branches', 'branch-misses'] - rusage_properties: ['maxrss'] run_config: - <<: *time + runner: perf_stat + perf_stat: + properties: ['wall-clock', 'task-clock', 'instructions', 'branches', 'branch-misses'] + rusage_properties: ['maxrss'] cmd: | bash -c 'set -eo pipefail; lake clean && LEAN_PATH=$(lean --print-libdir) lake build -v --lean ./scripts/bench/fake-root/bin/lean | ./scripts/bench/accumulate_profile.py | grep -v took' parse_output: true + runs: 1 - attributes: description: lint run_config: @@ -18,6 +17,7 @@ properties: ['wall-clock', 'instructions'] cmd: | make lint + runs: 1 - attributes: description: open Mathlib run_config: @@ -28,8 +28,7 @@ cmd: | # run lake+lean like the file worker would LEAN_PATH=$(lake setup-file --no-build Mathlib Mathlib | jq -r '.paths.oleanPath | join(":")') lean Mathlib.lean - discarded_runs: 1 - min_runs: 5 + runs: 5 - attributes: description: size run_config: @@ -41,5 +40,5 @@ echo -n '.olean|bytes: ' && find .lake/build -name '*.olean' -print0 | wc -c --files0-from=- | tail -1 | cut -d' ' -f 1 " - max_runs: 1 + runs: 1 runner: output diff --git a/scripts/bench/temci-config.yml b/scripts/bench/temci-config.yml index c91784ab28b8e..5eea7b5c2faa9 100644 --- a/scripts/bench/temci-config.yml +++ b/scripts/bench/temci-config.yml @@ -1,5 +1,4 @@ run: discarded_runs: 0 - runs: 1 shuffle: false in: ./scripts/bench/temci-config.run.yml diff --git a/scripts/nolints.json b/scripts/nolints.json index 112195fadba12..21ee2657fed9f 100644 --- a/scripts/nolints.json +++ b/scripts/nolints.json @@ -661,10 +661,10 @@ ["docBlame", "List.equiv"], ["docBlame", "List.inj_on"], ["docBlame", "List.remove"], - ["docBlame", "LocalHomeomorph.continuousOn_invFun"], - ["docBlame", "LocalHomeomorph.continuousOn_toFun"], - ["docBlame", "LocalHomeomorph.open_source"], - ["docBlame", "LocalHomeomorph.open_target"], + ["docBlame", "PartialHomeomorph.continuousOn_invFun"], + ["docBlame", "PartialHomeomorph.continuousOn_toFun"], + ["docBlame", "PartialHomeomorph.open_source"], + ["docBlame", "PartialHomeomorph.open_target"], ["docBlame", "LocallyConvexSpace.convex_basis"], ["docBlame", "LowerSetTopology.topology_eq_lowerSetTopology"], ["docBlame", "LowerTopology.topology_eq_lowerTopology"], diff --git a/scripts/style-exceptions.txt b/scripts/style-exceptions.txt index a0dba87cb5b61..9334e4a13a11d 100644 --- a/scripts/style-exceptions.txt +++ b/scripts/style-exceptions.txt @@ -84,9 +84,9 @@ Mathlib/Lean/Exception.lean : line 4 : ERR_AUT : Authors line should look like: Mathlib/Lean/Exception.lean : line 7 : ERR_MOD : Module docstring missing, or too late Mathlib/Lean/Expr/ReplaceRec.lean : line 12 : ERR_MOD : Module docstring missing, or too late Mathlib/Lean/LocalContext.lean : line 8 : ERR_MOD : Module docstring missing, or too late -Mathlib/Logic/Equiv/LocalEquiv.lean : line 1 : ERR_COP : Malformed or missing copyright header -Mathlib/Logic/Equiv/LocalEquiv.lean : line 12 : ERR_MOD : Module docstring missing, or too late -Mathlib/Logic/Equiv/LocalEquiv.lean : line 4 : ERR_AUT : Authors line should look like: 'Authors: Jean Dupont, Иван Иванович Иванов' +Mathlib/Logic/Equiv/PartialEquiv.lean : line 1 : ERR_COP : Malformed or missing copyright header +Mathlib/Logic/Equiv/PartialEquiv.lean : line 12 : ERR_MOD : Module docstring missing, or too late +Mathlib/Logic/Equiv/PartialEquiv.lean : line 4 : ERR_AUT : Authors line should look like: 'Authors: Jean Dupont, Иван Иванович Иванов' Mathlib/Logic/Equiv/MfldSimpsAttr.lean : line 1 : ERR_COP : Malformed or missing copyright header Mathlib/Logic/Equiv/MfldSimpsAttr.lean : line 4 : ERR_AUT : Authors line should look like: 'Authors: Jean Dupont, Иван Иванович Иванов' Mathlib/Logic/Equiv/MfldSimpsAttr.lean : line 9 : ERR_MOD : Module docstring missing, or too late diff --git a/test/Continuity.lean b/test/Continuity.lean index 1ec9168868da1..ced88c7cef85e 100644 --- a/test/Continuity.lean +++ b/test/Continuity.lean @@ -1,3 +1,4 @@ +import Mathlib.Analysis.SpecialFunctions.Trigonometric.Basic import Mathlib.Topology.Basic import Mathlib.Topology.ContinuousFunction.Basic @@ -27,15 +28,24 @@ example {g : X → X} (y : Y) : Continuous ((fun _ ↦ y) ∘ g) := by continuit example {f : X → Y} (x : X) : Continuous (fun (_ : X) ↦ f x) := by continuity --- Todo: more interesting examples when more algebra is ported +example [TopologicalSpace X] [TopologicalSpace Y] + (f₁ f₂ : X → Y) (hf₁ : Continuous f₁) (hf₂ : Continuous f₂) + (g : Y → ℝ) (hg : Continuous g) : Continuous (fun x => (max (g (f₁ x)) (g (f₂ x))) + 1) := by + continuity --- Porting note: port the tests from mathlib3 once we have the necessary theory files +example {κ ι : Type} + (K : κ → Type) [∀ k, TopologicalSpace (K k)] (I : ι → Type) [∀ i, TopologicalSpace (I i)] + (e : κ ≃ ι) (F : Π k, Homeomorph (K k) (I (e k))) : + Continuous (fun (f : Π k, K k) (i : ι) => F (e.symm i) (f (e.symm i))) := by + continuity -/- Todo: restore this test -example [TopologicalSpace X] [TopologicalSpace Y] - (f₁ f₂ : X → Y) (hf₁ : Continuous f₁) (hf₂ : Continuous f₂) - (g : Y → ℝ) (hg : Continuous g) : Continuous (fun x => (max (g (f₁ x)) (g (f₂ x))) + 1) := - by continuity -/ +open Real + +example : Continuous (fun x : ℝ => exp ((max x (-x)) + sin x)^2) := by + continuity + +example : Continuous (fun x : ℝ => exp ((max x (-x)) + sin (cos x))^2) := by + continuity -- Examples taken from `Topology.ContinuousFunction.Basic`: diff --git a/test/MfldSetTac.lean b/test/MfldSetTac.lean index 1e0991e781b20..8348f0573b6c1 100644 --- a/test/MfldSetTac.lean +++ b/test/MfldSetTac.lean @@ -4,14 +4,14 @@ Released under Apache 2.0 license as described in the file LICENSE. Author: Heather Macbeth, Frédéric Dupuis -/ -import Mathlib.Logic.Equiv.LocalEquiv +import Mathlib.Logic.Equiv.PartialEquiv private axiom test_sorry : ∀ {α}, α /-! This is a test file for the tactic `mfld_set_tac`. Because this tactic applies a simp-set which mostly contains lemmas in advanced parts of mathlib, it is currently impossible to truly test it in realistic conditions. Instead, we create stub definitions and lemmas on objects such as -`LocalHomeomorph`, label them with `mfld_simps` and run tests on those. +`PartialHomeomorph`, label them with `mfld_simps` and run tests on those. -/ open Lean Meta Elab Tactic @@ -21,38 +21,38 @@ open Lean Meta Elab Tactic set_option autoImplicit true section stub_lemmas -structure LocalHomeomorph (α : Type u) (β : Type u) extends LocalEquiv α β +structure PartialHomeomorph (α : Type u) (β : Type u) extends PartialEquiv α β noncomputable -instance LocalHomeomorph.has_coe_to_fun : CoeFun (LocalHomeomorph α β) (λ _ => α → β) := test_sorry +instance PartialHomeomorph.has_coe_to_fun : CoeFun (PartialHomeomorph α β) (λ _ => α → β) := test_sorry noncomputable -def LocalHomeomorph.symm (_e : LocalHomeomorph α β) : LocalHomeomorph β α := test_sorry +def PartialHomeomorph.symm (_e : PartialHomeomorph α β) : PartialHomeomorph β α := test_sorry -@[mfld_simps] lemma LocalHomeomorph.left_inv (e : LocalHomeomorph α β) {x : α} - (_h : x ∈ e.toLocalEquiv.source) : +@[mfld_simps] lemma PartialHomeomorph.left_inv (e : PartialHomeomorph α β) {x : α} + (_h : x ∈ e.toPartialEquiv.source) : e.symm (e x) = x := test_sorry -@[mfld_simps] theorem LocalHomeomorph.symm_to_LocalEquiv (e : LocalHomeomorph α β) : - e.symm.toLocalEquiv = e.toLocalEquiv.symm := +@[mfld_simps] theorem PartialHomeomorph.symm_to_PartialEquiv (e : PartialHomeomorph α β) : + e.symm.toPartialEquiv = e.toPartialEquiv.symm := test_sorry -@[mfld_simps] lemma LocalHomeomorph.coe_coe (e : LocalHomeomorph α β) : - (e.toLocalEquiv : α → β) = e := +@[mfld_simps] lemma PartialHomeomorph.coe_coe (e : PartialHomeomorph α β) : + (e.toPartialEquiv : α → β) = e := test_sorry -@[mfld_simps] lemma LocalHomeomorph.coe_coe_symm (e : LocalHomeomorph α β) : - (e.toLocalEquiv.symm : β → α) = (e.symm : β → α) := +@[mfld_simps] lemma PartialHomeomorph.coe_coe_symm (e : PartialHomeomorph α β) : + (e.toPartialEquiv.symm : β → α) = (e.symm : β → α) := test_sorry -structure ModelWithCorners (𝕜 E H : Type u) extends LocalEquiv H E := +structure ModelWithCorners (𝕜 E H : Type u) extends PartialEquiv H E := (source_eq : source = Set.univ) attribute [mfld_simps] ModelWithCorners.source_eq noncomputable -def ModelWithCorners.symm (_I : ModelWithCorners 𝕜 E H) : LocalEquiv E H := test_sorry +def ModelWithCorners.symm (_I : ModelWithCorners 𝕜 E H) : PartialEquiv E H := test_sorry noncomputable instance ModelWithCorners.has_coe_to_fun : CoeFun (ModelWithCorners 𝕜 E H) (λ _ => H → E) := test_sorry @@ -62,11 +62,11 @@ instance ModelWithCorners.has_coe_to_fun : CoeFun (ModelWithCorners 𝕜 E H) ( test_sorry @[mfld_simps] lemma ModelWithCorners.to_local_equiv_coe (I : ModelWithCorners 𝕜 E H) : - (I.toLocalEquiv : H → E) = I := + (I.toPartialEquiv : H → E) = I := test_sorry @[mfld_simps] lemma ModelWithCorners.to_local_equiv_coe_symm (I : ModelWithCorners 𝕜 E H) : - (I.toLocalEquiv.symm : E → H) = I.symm := + (I.toPartialEquiv.symm : E → H) = I.symm := test_sorry end stub_lemmas @@ -75,34 +75,34 @@ end stub_lemmas /-! ## Tests for `MfldSetTac` -/ section tests -example (e : LocalEquiv α β) (e' : LocalEquiv β γ) : +example (e : PartialEquiv α β) (e' : PartialEquiv β γ) : (e.trans e').source = e.source ∩ Set.preimage e (e.target ∩ e'.source) := by mfld_set_tac -example (e : LocalEquiv α β) : (e.trans e.symm).source = e.source := by mfld_set_tac +example (e : PartialEquiv α β) : (e.trans e.symm).source = e.source := by mfld_set_tac -example (s : Set α) (f : LocalHomeomorph α β) : - f.symm.toLocalEquiv.source ∩ (f.toLocalEquiv.target ∩ Set.preimage f.symm s) - = f.symm.toLocalEquiv.source ∩ Set.preimage f.symm s := by mfld_set_tac +example (s : Set α) (f : PartialHomeomorph α β) : + f.symm.toPartialEquiv.source ∩ (f.toPartialEquiv.target ∩ Set.preimage f.symm s) + = f.symm.toPartialEquiv.source ∩ Set.preimage f.symm s := by mfld_set_tac example {I : ModelWithCorners 𝕜 E H} {I' : ModelWithCorners 𝕜 E' H'} {I'' : ModelWithCorners 𝕜 E'' H''} - (e₁ : LocalHomeomorph M H) - (e₂ : LocalHomeomorph M' H') - (e₃ : LocalHomeomorph M'' H'') + (e₁ : PartialHomeomorph M H) + (e₂ : PartialHomeomorph M' H') + (e₃ : PartialHomeomorph M'' H'') {f : M → M'} {g : M' → M''} : - (Set.preimage (f ∘ ((e₁.toLocalEquiv.trans I.toLocalEquiv).symm)) - (e₂.toLocalEquiv.trans I'.toLocalEquiv).source) ⊆ + (Set.preimage (f ∘ ((e₁.toPartialEquiv.trans I.toPartialEquiv).symm)) + (e₂.toPartialEquiv.trans I'.toPartialEquiv).source) ⊆ {y : E | - ((e₃.toLocalEquiv.trans I''.toLocalEquiv) ∘ - (g ∘ f) ∘ ((e₁.toLocalEquiv.trans I.toLocalEquiv).symm)) y - = (((e₃.toLocalEquiv.trans I''.toLocalEquiv : M'' → E'') ∘ - g ∘ ((e₂.toLocalEquiv.trans I'.toLocalEquiv).symm)) ∘ - (e₂.toLocalEquiv.trans I'.toLocalEquiv : M' → E') ∘ - f ∘ ((e₁.toLocalEquiv.trans I.toLocalEquiv).symm)) y} := by + ((e₃.toPartialEquiv.trans I''.toPartialEquiv) ∘ + (g ∘ f) ∘ ((e₁.toPartialEquiv.trans I.toPartialEquiv).symm)) y + = (((e₃.toPartialEquiv.trans I''.toPartialEquiv : M'' → E'') ∘ + g ∘ ((e₂.toPartialEquiv.trans I'.toPartialEquiv).symm)) ∘ + (e₂.toPartialEquiv.trans I'.toPartialEquiv : M' → E') ∘ + f ∘ ((e₁.toPartialEquiv.trans I.toPartialEquiv).symm)) y} := by mfld_set_tac end tests diff --git a/test/MkIffOfInductive.lean b/test/MkIffOfInductive.lean index d5a0f07a6daf8..fee05d654b82c 100644 --- a/test/MkIffOfInductive.lean +++ b/test/MkIffOfInductive.lean @@ -37,6 +37,7 @@ mk_iff_of_inductive_prop HEq test.heq_iff example {α : Sort u} (a : α) {β : Sort u} (b : β) : HEq a b ↔ β = α ∧ HEq b a := test.heq_iff a b mk_iff_of_inductive_prop List.Perm test.perm_iff +open scoped List in example {α : Type _} (a b : List α) : a ~ b ↔ a = List.nil ∧ b = List.nil ∨ diff --git a/test/MoveAdd.lean b/test/MoveAdd.lean index 1d63d02846ef4..38a84625f91af 100644 --- a/test/MoveAdd.lean +++ b/test/MoveAdd.lean @@ -55,6 +55,7 @@ example (he : E (C r * D X + D X * h + 7 + 42 + f) = C r * D X + h * D X + 7 + 4 end add +section mul example [CommSemigroup R] (a b c d : R) (h : a * b * c = d) : b * (a * c) = d := by move_mul [← a] assumption @@ -74,6 +75,19 @@ example {R : Type u} [Add R] [CommSemigroup R] {a b c d e f g : R} : move_mul [a, a, b, c, d, e, f] rfl +end mul + +section left_assoc +example {a b c d e : Prop} (h : a ∧ b ∧ c ∧ d ∧ e) : a ∧ c ∧ e ∧ b ∧ d := by + move_oper And [a, b, c, d, e] + exact h + +example {a b c d e : Prop} (h : a ∨ b ∨ c ∨ d ∨ e) : a ∨ c ∨ e ∨ b ∨ d := by + move_oper Or [a, b, c, d, e] + exact h + +end left_assoc + -- Testing internals of the tactic `move_add`. section tactic open Mathlib.MoveAdd diff --git a/test/abel.lean b/test/abel.lean index 873a6732ef674..153832f337024 100644 --- a/test/abel.lean +++ b/test/abel.lean @@ -98,15 +98,8 @@ error: abel_nf made no progress example [AddCommGroup α] (x y z : α) (_w : x = y + z) : False := by abel_nf at * -/-- -error: no goals to be solved --/ --- This error message is confusing: it is saying that it closed the main goal, --- and so then had nothing to do on the hypotheses. --- The user has to guess that they should remove the `at *`. -#guard_msgs in example [AddCommGroup α] (x y z : α) (_w : x = y + z) : x - x = 0 := by - abel_nf at * + abel_nf /-- error: abel_nf made no progress diff --git a/test/congr.lean b/test/congr.lean index 88cefe40cbf93..df4d62c75e386 100644 --- a/test/congr.lean +++ b/test/congr.lean @@ -2,7 +2,7 @@ import Mathlib.Tactic.Congr! import Std.Tactic.GuardExpr import Mathlib.Algebra.Group.Basic import Mathlib.Data.Subtype -import Mathlib.Data.List.Defs +import Mathlib.Data.List.BigOperators.Basic private axiom test_sorry : ∀ {α}, α set_option autoImplicit true diff --git a/test/convert2.lean b/test/convert2.lean index 3c069eb278e71..babf4963662c8 100644 --- a/test/convert2.lean +++ b/test/convert2.lean @@ -1,4 +1,4 @@ -import Mathlib.Data.List.Defs +import Mathlib.Data.List.BigOperators.Defs import Mathlib.Data.Nat.Basic set_option linter.unreachableTactic false diff --git a/test/delaborators.lean b/test/delaborators.lean index 6c85b38890a22..086fe3a9513c1 100644 --- a/test/delaborators.lean +++ b/test/delaborators.lean @@ -45,11 +45,9 @@ variable (P : Nat → Prop) (α : Nat → Type) (s : Set ℕ) #guard_msgs in #check ∀ x, x ∈ s → P x --- TODO: uncomment after bumping past --- https://github.com/leanprover/std4/pull/427 --- /-- info: ∀ x ∉ s, P x : Prop -/ --- #guard_msgs in --- #check ∀ x ∉ s,P x +/-- info: ∀ x ∉ s, P x : Prop -/ +#guard_msgs in +#check ∀ x ∉ s,P x /-- info: ∀ x ∉ s, P x : Prop -/ #guard_msgs in @@ -149,11 +147,9 @@ section existential variable (s : Set ℕ) (P : ℕ → Prop) (Q : Set ℕ → Prop) --- TODO: uncomment after bumping past --- https://github.com/leanprover/std4/pull/427 --- /-- info: ∃ x ∉ s, P x : Prop -/ --- #guard_msgs in --- #check ∃ x ∉ s, P x +/-- info: ∃ x ∉ s, P x : Prop -/ +#guard_msgs in +#check ∃ x ∉ s, P x /-- info: ∃ x ∉ s, P x : Prop -/ #guard_msgs in diff --git a/test/matrix.lean b/test/matrix.lean index deac900999aea..5fcf2ebf07e83 100644 --- a/test/matrix.lean +++ b/test/matrix.lean @@ -1,7 +1,3 @@ -/- -manually ported from -https://github.com/leanprover-community/mathlib/blob/4f4a1c875d0baa92ab5d92f3fb1bb258ad9f3e5b/test/matrix.lean --/ import Mathlib.Data.Matrix.Notation import Mathlib.GroupTheory.Perm.Fin import Mathlib.LinearAlgebra.Matrix.Determinant @@ -10,8 +6,6 @@ import Std.Tactic.GuardExpr open Qq --- TODO: uncomment above imports when they are ported - variable {α β : Type} [Semiring α] [Ring β] namespace Matrix @@ -138,10 +132,10 @@ example {a b c d e f g h : α} : ![a, b, c, d, e, f, g, h] 99 = d := by simp example {α : Type _} [CommRing α] {a b c d : α} : Matrix.det !![a, b; c, d] = a * d - b * c := by simp? [Matrix.det_succ_row_zero, Fin.sum_univ_succ] says - simp only [det_succ_row_zero, Nat.odd_iff_not_even, of_apply, cons_val', empty_val', + simp only [det_succ_row_zero, of_apply, cons_val', empty_val', cons_val_fin_one, cons_val_zero, det_unique, Fin.default_eq_zero, submatrix_apply, - Fin.succ_zero_eq_one, ne_eq, cons_val_one, head_fin_const, Fin.sum_univ_succ, Fin.val_zero, - pow_zero, one_mul, not_true_eq_false, Fin.zero_succAbove, head_cons, Finset.univ_unique, + Fin.succ_zero_eq_one, cons_val_one, head_fin_const, Fin.sum_univ_succ, Fin.val_zero, + pow_zero, one_mul, Fin.zero_succAbove, head_cons, Finset.univ_unique, Fin.val_succ, Fin.coe_fin_one, zero_add, pow_one, cons_val_succ, neg_mul, Fin.succ_succAbove_zero, Finset.sum_const, Finset.card_singleton, smul_neg, one_smul] ring @@ -150,12 +144,12 @@ example {α : Type _} [CommRing α] {a b c d e f g h i : α} : Matrix.det !![a, b, c; d, e, f; g, h, i] = a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g := by simp? [Matrix.det_succ_row_zero, Fin.sum_univ_succ] says - simp only [det_succ_row_zero, Nat.odd_iff_not_even, of_apply, cons_val', empty_val', - cons_val_fin_one, cons_val_zero, submatrix_apply, Fin.succ_zero_eq_one, cons_val_one, head_cons, - submatrix_submatrix, det_unique, Fin.default_eq_zero, Function.comp_apply, Fin.succ_one_eq_two, - ne_eq, cons_val_two, tail_cons, head_fin_const, Fin.sum_univ_succ, Fin.val_zero, pow_zero, - one_mul, not_true_eq_false, Fin.zero_succAbove, Finset.univ_unique, Fin.val_succ, - Fin.coe_fin_one, zero_add, pow_one, neg_mul, Fin.succ_succAbove_zero, Finset.sum_neg_distrib, + simp only [det_succ_row_zero, of_apply, cons_val', empty_val', + cons_val_fin_one, cons_val_zero, submatrix_apply, Fin.succ_zero_eq_one, cons_val_one, + head_cons, submatrix_submatrix, det_unique, Fin.default_eq_zero, Function.comp_apply, + Fin.succ_one_eq_two, cons_val_two, tail_cons, head_fin_const, Fin.sum_univ_succ, Fin.val_zero, + pow_zero, one_mul, Fin.zero_succAbove, Finset.univ_unique, Fin.val_succ, Fin.coe_fin_one, + zero_add, pow_one, neg_mul, Fin.succ_succAbove_zero, Finset.sum_neg_distrib, Finset.sum_singleton, cons_val_succ, Fin.succ_succAbove_one, even_add_self, Even.neg_pow, one_pow, Finset.sum_const, Finset.card_singleton, one_smul] ring diff --git a/test/random.lean b/test/random.lean new file mode 100644 index 0000000000000..693486954c5fa --- /dev/null +++ b/test/random.lean @@ -0,0 +1,77 @@ +import Mathlib.Control.Random +import Mathlib.Tactic.NormNum + +open Random + +section Rand + +/-- +info: 44 +-/ +#guard_msgs in +#eval do + IO.runRandWith 257 (show Rand _ from do + let i ← randBound Int 3 30 (by norm_num) + let j ← randBound Int 4 40 (by norm_num) + return i.1 + j.1) + +-- using higher universes +/-- +info: ULift.up 17 +-/ +#guard_msgs in +#eval do + IO.runRandWith 257 (show Rand _ from do + let i ← rand (ULift.{3} (Fin 20)) + return i) + +end Rand + +-- using the monad transformer +section RandT + +/-- +info: Got 15 +Got 29 +44 +-/ +#guard_msgs in +#eval show IO _ from do + IO.runRandWith 257 (do + let i ← randBound Int 3 30 (by norm_num) + IO.println s!"Got {i}" + let j ← randBound Int 4 40 (by norm_num) + IO.println s!"Got {j}" + return i.1 + j.1) + +/-- +info: Got 15 +Got 29 +44 +-/ +#guard_msgs in +#eval show Lean.Meta.MetaM _ from do + IO.runRandWith 257 (do + let i ← randBound Int 3 30 (by norm_num) + IO.println s!"Got {i}" + let j ← randBound Int 4 40 (by norm_num) + IO.println s!"Got {j}" + return i.1 + j.1) + +-- test that `MetaM` can access the global random number generator +/-- +info: Got 4 +Got 4 +8 +-/ +#guard_msgs in +#eval show Lean.Meta.MetaM _ from do + IO.runRand (do + -- since we don't know the seed, we use a trivial range here for determinism + let i ← randBound Int 4 4 (by norm_num) + IO.println s!"Got {i}" + let j ← randBound Int 4 4 (by norm_num) + IO.println s!"Got {i}" + return i.1 + j.1) + +end RandT diff --git a/test/ring.lean b/test/ring.lean index 96dfc230368dc..5abd490bfa500 100644 --- a/test/ring.lean +++ b/test/ring.lean @@ -158,3 +158,22 @@ example (p : R PUnit.{u+1} PUnit.{v+1}) : p + 0 = p := by ring_nf example (p q : R PUnit.{u+1} PUnit.{v+1}) : p + q = q + p := by ring_nf + +-- https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/ring_nf.20returns.20ugly.20literals/near/400988184 +example {n : ℝ} : + (n + 1 / 2) ^ 2 * (n + 1 + 1 / 3) = 1 / 3 + n * (19 / 12) + n ^ 2 * (7 / 3) + n ^ 3 := by + -- `conv_lhs` prevents `ring_nf` picking a bad normalization for both sides. + conv_lhs => ring_nf + +-- We can't use `guard_target =ₛ` here, as while it does detect stray `OfNat`s, it also complains +-- about differing instance paths. +/-- +info: n : ℝ +_hn : 0 ≤ n +⊢ 1 / 3 + n * (19 / 12) + n ^ 2 * (7 / 3) + n ^ 3 ≤ 1 / 3 + n * (5 / 3) + n ^ 2 * (7 / 3) + n ^ 3 +-/ +#guard_msgs (info) in +example {n : ℝ} (_hn : 0 ≤ n) : (n + 1 / 2) ^ 2 * (n + 1 + 1 / 3) ≤ (n + 1 / 3) * (n + 1) ^ 2 := by + ring_nf + trace_state + exact test_sorry