From 5608064d3be9600af7deea2cbb3955c2805dfc01 Mon Sep 17 00:00:00 2001 From: leanprover-community-bot-assistant Date: Sun, 2 Feb 2025 00:16:49 +0000 Subject: [PATCH 001/103] chore(scripts): update nolints.json (#21334) I am happy to remove some nolints for you! --- scripts/nolints.json | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/scripts/nolints.json b/scripts/nolints.json index d52df230c4996..c7f6d49d1395e 100644 --- a/scripts/nolints.json +++ b/scripts/nolints.json @@ -66,9 +66,6 @@ ["docBlame", "CancelDenoms.synthesizeUsingNormNum"], ["docBlame", "CategoryTheory.«term_⟶[_]_»"], ["docBlame", "ChangeOfRings.«term_⊗ₜ[_,_]_»"], - ["docBlame", "Combinator.I"], - ["docBlame", "Combinator.K"], - ["docBlame", "Combinator.S"], ["docBlame", "CompleteBooleanAlgebra.toCompleteAtomicBooleanAlgebra"], ["docBlame", "Computation.parallelRec"], ["docBlame", "Congr!.elabConfig"], @@ -166,7 +163,6 @@ ["docBlame", "LinearRecurrence.order"], ["docBlame", "MagmaCat.forget_obj_eq_coe"], ["docBlame", "MaximalSpectrum.asIdeal"], - ["docBlame", "MeasureTheory.«term_[_|_]»"], ["docBlame", "MeasureTheory.«term_→₁[_]_»"], ["docBlame", "MeasureTheory.«term_→₂[_]_»"], ["docBlame", "MeasureTheory.«term_≤[_]_»"], @@ -215,7 +211,6 @@ ["docBlame", "Nat.rfind"], ["docBlame", "Nat.rfindOpt"], ["docBlame", "Nat.rfindX"], - ["docBlame", "Nat.subInduction"], ["docBlame", "One.one"], ["docBlame", "OptionT.callCC"], ["docBlame", "OptionT.mkLabel"], @@ -275,7 +270,6 @@ ["docBlame", "Stream'.corec'"], ["docBlame", "Stream'.corecOn"], ["docBlame", "Stream'.unfolds"], - ["docBlame", "StrictWeakOrder.Equiv"], ["docBlame", "Submodule.«term_∙_»"], ["docBlame", "Traversable.foldMap"], ["docBlame", "Traversable.foldl"], @@ -646,5 +640,4 @@ ["docBlame", "Mathlib.Meta.NormNum.evalLT.core.intArm"], ["docBlame", "Mathlib.Meta.NormNum.evalLT.core.ratArm"], ["docBlame", "Mathlib.Meta.NormNum.evalMul.core.intArm"], - ["docBlame", "Mathlib.Meta.NormNum.evalMul.core.ratArm"], - ["unusedArguments", "Combinator.K"]] + ["docBlame", "Mathlib.Meta.NormNum.evalMul.core.ratArm"]] From 702f356c078cfabee840b7b04b8dac7f1f1648a0 Mon Sep 17 00:00:00 2001 From: Johan Commelin Date: Sun, 2 Feb 2025 08:19:32 +0000 Subject: [PATCH 002/103] chore(GroupTheory/SpecificGroups/Cyclic): isCyclic_of_card_le_orderOf (#21297) --- Mathlib/GroupTheory/OrderOfElement.lean | 5 +++++ Mathlib/GroupTheory/SpecificGroups/Cyclic.lean | 13 +++++++++++++ 2 files changed, 18 insertions(+) diff --git a/Mathlib/GroupTheory/OrderOfElement.lean b/Mathlib/GroupTheory/OrderOfElement.lean index a609b7d46308d..67fdde3821c7c 100644 --- a/Mathlib/GroupTheory/OrderOfElement.lean +++ b/Mathlib/GroupTheory/OrderOfElement.lean @@ -697,6 +697,11 @@ theorem sum_card_orderOf_eq_card_pow_eq_one [Fintype G] [DecidableEq G] (hn : n theorem orderOf_le_card_univ [Fintype G] : orderOf x ≤ Fintype.card G := Finset.le_card_of_inj_on_range (x ^ ·) (fun _ _ ↦ Finset.mem_univ _) pow_injOn_Iio_orderOf +@[to_additive] +theorem orderOf_le_card [Finite G] : orderOf x ≤ Nat.card G := by + obtain ⟨⟩ := nonempty_fintype G + simpa using orderOf_le_card_univ + end FiniteMonoid section FiniteCancelMonoid diff --git a/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean b/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean index 028fb46fc8ecb..d548b5dc7293d 100644 --- a/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean +++ b/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean @@ -113,6 +113,14 @@ lemma isCyclic_iff_exists_orderOf_eq_natCard [Finite α] : IsCyclic α ↔ ∃ g : α, orderOf g = Nat.card α := by simp_rw [isCyclic_iff_exists_zpowers_eq_top, ← card_eq_iff_eq_top, Nat.card_zpowers] +@[to_additive] +lemma isCyclic_iff_exists_natCard_le_orderOf [Finite α] : + IsCyclic α ↔ ∃ g : α, Nat.card α ≤ orderOf g := by + rw [isCyclic_iff_exists_orderOf_eq_natCard] + apply exists_congr + intro g + exact ⟨Eq.ge, le_antisymm orderOf_le_card⟩ + @[deprecated (since := "2024-12-20")] alias isCyclic_iff_exists_ofOrder_eq_natCard := isCyclic_iff_exists_orderOf_eq_natCard @@ -132,6 +140,11 @@ theorem isCyclic_of_orderOf_eq_card [Finite α] (x : α) (hx : orderOf x = Nat.c IsCyclic α := isCyclic_iff_exists_orderOf_eq_natCard.mpr ⟨x, hx⟩ +@[to_additive] +theorem isCyclic_of_card_le_orderOf [Finite α] (x : α) (hx : Nat.card α ≤ orderOf x) : + IsCyclic α := + isCyclic_iff_exists_natCard_le_orderOf.mpr ⟨x, hx⟩ + @[to_additive] theorem Subgroup.eq_bot_or_eq_top_of_prime_card (H : Subgroup G) [hp : Fact (Nat.card G).Prime] : H = ⊥ ∨ H = ⊤ := by From 8f1b0576c3aeb2851403b6f5dd56a5ee53e705de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Sun, 2 Feb 2025 10:50:25 +0000 Subject: [PATCH 003/103] =?UTF-8?q?chore:=20make=20`=E2=80=96x=E2=80=96?= =?UTF-8?q?=E2=82=91.toReal=20=3D=20=E2=80=96x=E2=80=96`=20simp=20(#21327)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From LeanAPAP --- Mathlib/Analysis/Normed/Group/Basic.lean | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mathlib/Analysis/Normed/Group/Basic.lean b/Mathlib/Analysis/Normed/Group/Basic.lean index 7bb024ac48135..df7c361a4bcce 100644 --- a/Mathlib/Analysis/Normed/Group/Basic.lean +++ b/Mathlib/Analysis/Normed/Group/Basic.lean @@ -667,14 +667,14 @@ theorem coe_nnnorm' (a : E) : (‖a‖₊ : ℝ) = ‖a‖ := rfl theorem coe_comp_nnnorm' : (toReal : ℝ≥0 → ℝ) ∘ (nnnorm : E → ℝ≥0) = norm := rfl -@[to_additive norm_toNNReal] +@[to_additive (attr := simp) norm_toNNReal] theorem norm_toNNReal' : ‖a‖.toNNReal = ‖a‖₊ := @Real.toNNReal_coe ‖a‖₊ -@[to_additive toReal_enorm] +@[to_additive (attr := simp) toReal_enorm] lemma toReal_enorm' (x : E) : ‖x‖ₑ.toReal = ‖x‖ := by simp [enorm] -@[to_additive ofReal_norm] +@[to_additive (attr := simp) ofReal_norm] lemma ofReal_norm' (x : E) : .ofReal ‖x‖ = ‖x‖ₑ := by simp [enorm, ENNReal.ofReal, Real.toNNReal, nnnorm] From 67a5732f2440aafed03e3b81ede61ff178358458 Mon Sep 17 00:00:00 2001 From: JovanGerb Date: Sun, 2 Feb 2025 12:17:37 +0000 Subject: [PATCH 004/103] perf(CategoryTheory/Shift/Induced): remove `@[simp]` from `shiftFunctor_of_induced` (#21329) This PR removes the `simp` tag from `shiftFunctor_of_induced`. This lemma isn't used, and it has a very unfavourable discrimination tree key, meaning that it is tried every time the constant `shiftFunctor` appears. --- Mathlib/CategoryTheory/Shift/Induced.lean | 1 - 1 file changed, 1 deletion(-) diff --git a/Mathlib/CategoryTheory/Shift/Induced.lean b/Mathlib/CategoryTheory/Shift/Induced.lean index 4ca88e200a2e7..bdef6f11c30ff 100644 --- a/Mathlib/CategoryTheory/Shift/Induced.lean +++ b/Mathlib/CategoryTheory/Shift/Induced.lean @@ -154,7 +154,6 @@ noncomputable def induced : HasShift D A := end HasShift -@[simp] lemma shiftFunctor_of_induced (a : A) : letI := HasShift.induced F A s i shiftFunctor D a = s a := by From 7eeba0a703cf3b316ee30262193158e6c1448561 Mon Sep 17 00:00:00 2001 From: Markus Himmel Date: Sun, 2 Feb 2025 12:28:04 +0000 Subject: [PATCH 005/103] feat: creation of products and equalizers implies creation of limits (#21321) Co-authored-by: Markus Himmel --- Mathlib/Algebra/Category/Grp/Ulift.lean | 3 +- .../LimitsOfProductsAndEqualizers.lean | 146 ++++++++++++++++++ Mathlib/CategoryTheory/Limits/Creates.lean | 36 +++-- .../Limits/Preserves/Finite.lean | 1 - .../Limits/Preserves/Ulift.lean | 3 +- 5 files changed, 170 insertions(+), 19 deletions(-) diff --git a/Mathlib/Algebra/Category/Grp/Ulift.lean b/Mathlib/Algebra/Category/Grp/Ulift.lean index b2b0a285efc94..fb8a66b2919d1 100644 --- a/Mathlib/Algebra/Category/Grp/Ulift.lean +++ b/Mathlib/Algebra/Category/Grp/Ulift.lean @@ -200,6 +200,7 @@ noncomputable instance : PreservesColimitsOfSize.{w', w} uliftFunctor.{v, u} whe The functor `uliftFunctor : AddCommGrp.{u} ⥤ AddCommGrp.{max u v}` creates `u`-small colimits. -/ noncomputable instance : CreatesColimitsOfSize.{w, u} uliftFunctor.{v, u} where - CreatesColimitsOfShape := { CreatesColimit := fun {_} ↦ createsColimitOfFullyFaithfulOfPreserves } + CreatesColimitsOfShape := + { CreatesColimit := fun {_} ↦ createsColimitOfReflectsIsomorphismsOfPreserves } end AddCommGrp diff --git a/Mathlib/CategoryTheory/Limits/Constructions/LimitsOfProductsAndEqualizers.lean b/Mathlib/CategoryTheory/Limits/Constructions/LimitsOfProductsAndEqualizers.lean index 43c2773df6cc1..a8bd0651b3c8b 100644 --- a/Mathlib/CategoryTheory/Limits/Constructions/LimitsOfProductsAndEqualizers.lean +++ b/Mathlib/CategoryTheory/Limits/Constructions/LimitsOfProductsAndEqualizers.lean @@ -7,7 +7,9 @@ import Mathlib.CategoryTheory.Limits.Constructions.BinaryProducts import Mathlib.CategoryTheory.Limits.Constructions.Equalizers import Mathlib.CategoryTheory.Limits.Constructions.FiniteProductsOfBinaryProducts import Mathlib.CategoryTheory.Limits.Preserves.Finite +import Mathlib.CategoryTheory.Limits.Preserves.Creates.Finite import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Equalizers +import Mathlib.CategoryTheory.Limits.Creates import Mathlib.Data.Fintype.Prod import Mathlib.Data.Fintype.Sigma @@ -217,6 +219,60 @@ lemma preservesLimits_of_preservesEqualizers_and_products [HasEqualizers C] [∀ J, PreservesLimitsOfShape (Discrete.{w} J) G] : PreservesLimitsOfSize.{w, w} G where preservesLimitsOfShape := preservesLimit_of_preservesEqualizers_and_product G +section + +variable [HasLimitsOfShape (Discrete J) D] [HasLimitsOfShape (Discrete (Σp : J × J, p.1 ⟶ p.2)) D] + [HasEqualizers D] + +variable (G : C ⥤ D) [G.ReflectsIsomorphisms] [CreatesLimitsOfShape WalkingParallelPair G] + [CreatesLimitsOfShape (Discrete.{w} J) G] + [CreatesLimitsOfShape (Discrete.{w} (Σp : J × J, p.1 ⟶ p.2)) G] + +attribute [local instance] preservesLimit_of_preservesEqualizers_and_product in +/-- If a functor creates equalizers and the appropriate products, it creates limits. + +We additionally require the rather strong condition that the functor reflects isomorphisms. It is +unclear whether the statement remains true without this condition. There are various definitions of +"creating limits" in the literature, and whether or not the condition can be dropped seems to depend +on the specific definition that is used. -/ +noncomputable def createsLimitsOfShapeOfCreatesEqualizersAndProducts : + CreatesLimitsOfShape J G where + CreatesLimit {K} := + have : HasLimitsOfShape (Discrete J) C := + hasLimitsOfShape_of_hasLimitsOfShape_createsLimitsOfShape G + have : HasLimitsOfShape (Discrete (Σp : J × J, p.1 ⟶ p.2)) C := + hasLimitsOfShape_of_hasLimitsOfShape_createsLimitsOfShape G + have : HasEqualizers C := + hasLimitsOfShape_of_hasLimitsOfShape_createsLimitsOfShape G + have : HasLimit K := hasLimit_of_equalizer_and_product K + createsLimitOfReflectsIsomorphismsOfPreserves + +end + +/-- If a functor creates equalizers and finite products, it creates finite limits. + +We additionally require the rather strong condition that the functor reflects isomorphisms. It is +unclear whether the statement remains true without this condition. There are various definitions of +"creating limits" in the literature, and whether or not the condition can be dropped seems to depend +on the specific definition that is used. -/ +noncomputable def createsFiniteLimitsOfCreatesEqualizersAndFiniteProducts [HasEqualizers D] + [HasFiniteProducts D] (G : C ⥤ D) [G.ReflectsIsomorphisms] + [CreatesLimitsOfShape WalkingParallelPair G] + [CreatesFiniteProducts G] : CreatesFiniteLimits G where + createsFiniteLimits _ _ _ := createsLimitsOfShapeOfCreatesEqualizersAndProducts G + +/-- If a functor creates equalizers and products, it creates limits. + +We additionally require the rather strong condition that the functor reflects isomorphisms. It is +unclear whether the statement remains true without this condition. There are various definitions of +"creating limits" in the literature, and whether or not the condition can be dropped seems to depend +on the specific definition that is used. -/ +noncomputable def createsLimitsOfSizeOfCreatesEqualizersAndProducts [HasEqualizers D] + [HasProducts.{w} D] (G : C ⥤ D) [G.ReflectsIsomorphisms] + [CreatesLimitsOfShape WalkingParallelPair G] [∀ J, CreatesLimitsOfShape (Discrete.{w} J) G] : + CreatesLimitsOfSize.{w, w} G where + CreatesLimitsOfShape := createsLimitsOfShapeOfCreatesEqualizersAndProducts G + theorem hasFiniteLimits_of_hasTerminal_and_pullbacks [HasTerminal C] [HasPullbacks C] : HasFiniteLimits C := @hasFiniteLimits_of_hasEqualizers_and_finite_products C _ @@ -239,6 +295,24 @@ lemma preservesFiniteLimits_of_preservesTerminal_and_pullbacks [HasTerminal C] apply PreservesFiniteProducts.mk apply preservesFiniteProducts_of_preserves_binary_and_terminal G +attribute [local instance] preservesFiniteLimits_of_preservesTerminal_and_pullbacks in +/-- If a functor creates terminal objects and pullbacks, it creates finite limits. + +We additionally require the rather strong condition that the functor reflects isomorphisms. It is +unclear whether the statement remains true without this condition. There are various definitions of +"creating limits" in the literature, and whether or not the condition can be dropped seems to depend +on the specific definition that is used. -/ +noncomputable def createsFiniteLimitsOfCreatesTerminalAndPullbacks [HasTerminal D] + [HasPullbacks D] (G : C ⥤ D) [G.ReflectsIsomorphisms] + [CreatesLimitsOfShape (Discrete.{0} PEmpty) G] [CreatesLimitsOfShape WalkingCospan G] : + CreatesFiniteLimits G where + createsFiniteLimits _ _ _ := + { CreatesLimit := + have : HasTerminal C := hasLimitsOfShape_of_hasLimitsOfShape_createsLimitsOfShape G + have : HasPullbacks C := hasLimitsOfShape_of_hasLimitsOfShape_createsLimitsOfShape G + have : HasFiniteLimits C := hasFiniteLimits_of_hasTerminal_and_pullbacks + createsLimitOfReflectsIsomorphismsOfPreserves } + /-! We now dualize the above constructions, resorting to copy-paste. -/ @@ -433,6 +507,60 @@ lemma preservesColimits_of_preservesCoequalizers_and_coproducts [HasCoequalizers [∀ J, PreservesColimitsOfShape (Discrete.{w} J) G] : PreservesColimitsOfSize.{w, w} G where preservesColimitsOfShape := preservesColimit_of_preservesCoequalizers_and_coproduct G +section + +variable [HasColimitsOfShape (Discrete J) D] + [HasColimitsOfShape (Discrete (Σp : J × J, p.1 ⟶ p.2)) D] [HasCoequalizers D] + +variable (G : C ⥤ D) [G.ReflectsIsomorphisms] [CreatesColimitsOfShape WalkingParallelPair G] + [CreatesColimitsOfShape (Discrete.{w} J) G] + [CreatesColimitsOfShape (Discrete.{w} (Σp : J × J, p.1 ⟶ p.2)) G] + +attribute [local instance] preservesColimit_of_preservesCoequalizers_and_coproduct in +/-- If a functor creates coequalizers and the appropriate coproducts, it creates colimits. + +We additionally require the rather strong condition that the functor reflects isomorphisms. It is +unclear whether the statement remains true without this condition. There are various definitions of +"creating colimits" in the literature, and whether or not the condition can be dropped seems to +depend on the specific definition that is used. -/ +noncomputable def createsColimitsOfShapeOfCreatesCoequalizersAndCoproducts : + CreatesColimitsOfShape J G where + CreatesColimit {K} := + have : HasColimitsOfShape (Discrete J) C := + hasColimitsOfShape_of_hasColimitsOfShape_createsColimitsOfShape G + have : HasColimitsOfShape (Discrete (Σp : J × J, p.1 ⟶ p.2)) C := + hasColimitsOfShape_of_hasColimitsOfShape_createsColimitsOfShape G + have : HasCoequalizers C := + hasColimitsOfShape_of_hasColimitsOfShape_createsColimitsOfShape G + have : HasColimit K := hasColimit_of_coequalizer_and_coproduct K + createsColimitOfReflectsIsomorphismsOfPreserves + +end + +/-- If a functor creates coequalizers and finite coproducts, it creates finite colimits. + +We additionally require the rather strong condition that the functor reflects isomorphisms. It is +unclear whether the statement remains true without this condition. There are various definitions of +"creating colimits" in the literature, and whether or not the condition can be dropped seems to +depend on the specific definition that is used. -/ +noncomputable def createsFiniteColimitsOfCreatesCoequalizersAndFiniteCoproducts [HasCoequalizers D] + [HasFiniteCoproducts D] (G : C ⥤ D) [G.ReflectsIsomorphisms] + [CreatesColimitsOfShape WalkingParallelPair G] + [CreatesFiniteCoproducts G] : CreatesFiniteColimits G where + createsFiniteColimits _ _ _ := createsColimitsOfShapeOfCreatesCoequalizersAndCoproducts G + +/-- If a functor creates coequalizers and coproducts, it creates colimits. + +We additionally require the rather strong condition that the functor reflects isomorphisms. It is +unclear whether the statement remains true without this condition. There are various definitions of +"creating colimits" in the literature, and whether or not the condition can be dropped seems to +depend on the specific definition that is used. -/ +noncomputable def createsColimitsOfSizeOfCreatesCoequalizersAndCoproducts [HasCoequalizers D] + [HasCoproducts.{w} D] (G : C ⥤ D) [G.ReflectsIsomorphisms] + [CreatesColimitsOfShape WalkingParallelPair G] + [∀ J, CreatesColimitsOfShape (Discrete.{w} J) G] : CreatesColimitsOfSize.{w, w} G where + CreatesColimitsOfShape := createsColimitsOfShapeOfCreatesCoequalizersAndCoproducts G + theorem hasFiniteColimits_of_hasInitial_and_pushouts [HasInitial C] [HasPushouts C] : HasFiniteColimits C := @hasFiniteColimits_of_hasCoequalizers_and_finite_coproducts C _ @@ -455,4 +583,22 @@ lemma preservesFiniteColimits_of_preservesInitial_and_pushouts [HasInitial C] apply PreservesFiniteCoproducts.mk apply preservesFiniteCoproductsOfPreservesBinaryAndInitial G +attribute [local instance] preservesFiniteColimits_of_preservesInitial_and_pushouts in +/-- If a functor creates initial objects and pushouts, it creates finite colimits. + +We additionally require the rather strong condition that the functor reflects isomorphisms. It is +unclear whether the statement remains true without this condition. There are various definitions of +"creating colimits" in the literature, and whether or not the condition can be dropped seems to +depend on the specific definition that is used. -/ +noncomputable def createsFiniteColimitsOfCreatesInitialAndPushouts [HasInitial D] + [HasPushouts D] (G : C ⥤ D) [G.ReflectsIsomorphisms] + [CreatesColimitsOfShape (Discrete.{0} PEmpty) G] [CreatesColimitsOfShape WalkingSpan G] : + CreatesFiniteColimits G where + createsFiniteColimits _ _ _ := + { CreatesColimit := + have : HasInitial C := hasColimitsOfShape_of_hasColimitsOfShape_createsColimitsOfShape G + have : HasPushouts C := hasColimitsOfShape_of_hasColimitsOfShape_createsColimitsOfShape G + have : HasFiniteColimits C := hasFiniteColimits_of_hasInitial_and_pushouts + createsColimitOfReflectsIsomorphismsOfPreserves } + end CategoryTheory.Limits diff --git a/Mathlib/CategoryTheory/Limits/Creates.lean b/Mathlib/CategoryTheory/Limits/Creates.lean index 2ed9c2de711ca..d8bb0a5989fbe 100644 --- a/Mathlib/CategoryTheory/Limits/Creates.lean +++ b/Mathlib/CategoryTheory/Limits/Creates.lean @@ -263,6 +263,13 @@ def createsLimitOfReflectsIso' {K : J ⥤ C} {F : C ⥤ D} [F.ReflectsIsomorphis validLift := h.validLift ≪≫ IsLimit.uniqueUpToIso hc t makesLimit := h.makesLimit } +/-- If `F` reflects isomorphisms, and we already know that the limit exists in the source and `F` +preserves it, then `F` creates that limit. -/ +def createsLimitOfReflectsIsomorphismsOfPreserves {K : J ⥤ C} {F : C ⥤ D} [F.ReflectsIsomorphisms] + [HasLimit K] [PreservesLimit K F] : CreatesLimit K F := + createsLimitOfReflectsIso' (isLimitOfPreserves F (limit.isLimit _)) + ⟨⟨_, Iso.refl _⟩, limit.isLimit _⟩ + -- Notice however that even if the isomorphism is `Iso.refl _`, -- this construction will insert additional identity morphisms in the cone maps, -- so the constructed limits may not be ideal, definitionally. @@ -273,11 +280,7 @@ of a limit cone for `K ⋙ F`. def createsLimitOfFullyFaithfulOfLift' {K : J ⥤ C} {F : C ⥤ D} [F.Full] [F.Faithful] {l : Cone (K ⋙ F)} (hl : IsLimit l) (c : Cone K) (i : F.mapCone c ≅ l) : CreatesLimit K F := - createsLimitOfReflectsIso fun _ t => - { liftedCone := c - validLift := i ≪≫ IsLimit.uniqueUpToIso hl t - makesLimit := - IsLimit.ofFaithful F (IsLimit.ofIsoLimit hl i.symm) _ fun _ => F.map_preimage _ } + createsLimitOfReflectsIso' hl ⟨⟨c, i⟩, isLimitOfReflects F (IsLimit.ofIsoLimit hl i.symm)⟩ -- Notice however that even if the isomorphism is `Iso.refl _`, -- this construction will insert additional identity morphisms in the cone maps, @@ -392,6 +395,17 @@ def createsColimitOfReflectsIso' {K : J ⥤ C} {F : C ⥤ D} [F.ReflectsIsomorph validLift := h.validLift ≪≫ IsColimit.uniqueUpToIso hc t makesColimit := h.makesColimit } +/-- If `F` reflects isomorphisms, and we already know that the colimit exists in the source and `F` +preserves it, then `F` creates that colimit. -/ +def createsColimitOfReflectsIsomorphismsOfPreserves {K : J ⥤ C} {F : C ⥤ D} + [F.ReflectsIsomorphisms] [HasColimit K] [PreservesColimit K F] : CreatesColimit K F := + createsColimitOfReflectsIso' (isColimitOfPreserves F (colimit.isColimit _)) + ⟨⟨_, Iso.refl _⟩, colimit.isColimit _⟩ + +@[deprecated (since := "2025-02-01")] +noncomputable alias createsColimitOfFullyFaithfulOfPreserves := + createsColimitOfReflectsIsomorphismsOfPreserves + -- Notice however that even if the isomorphism is `Iso.refl _`, -- this construction will insert additional identity morphisms in the cocone maps, -- so the constructed colimits may not be ideal, definitionally. @@ -402,11 +416,7 @@ lift of a colimit cocone for `K ⋙ F`. def createsColimitOfFullyFaithfulOfLift' {K : J ⥤ C} {F : C ⥤ D} [F.Full] [F.Faithful] {l : Cocone (K ⋙ F)} (hl : IsColimit l) (c : Cocone K) (i : F.mapCocone c ≅ l) : CreatesColimit K F := - createsColimitOfReflectsIso fun _ t => - { liftedCocone := c - validLift := i ≪≫ IsColimit.uniqueUpToIso hl t - makesColimit := - IsColimit.ofFaithful F (IsColimit.ofIsoColimit hl i.symm) _ fun _ => F.map_preimage _ } + createsColimitOfReflectsIso' hl ⟨⟨c, i⟩, isColimitOfReflects F (IsColimit.ofIsoColimit hl i.symm)⟩ -- Notice however that even if the isomorphism is `Iso.refl _`, -- this construction will insert additional identity morphisms in the cocone maps, @@ -420,12 +430,6 @@ def createsColimitOfFullyFaithfulOfLift {K : J ⥤ C} {F : C ⥤ D} [F.Full] [F. CreatesColimit K F := createsColimitOfFullyFaithfulOfLift' (colimit.isColimit _) c i -/-- A fully faithful functor that preserves a colimit that exists also creates the colimit. -/ -def createsColimitOfFullyFaithfulOfPreserves {K : J ⥤ C} {F : C ⥤ D} [F.Full] [F.Faithful] - [HasColimit K] [PreservesColimit K F] : CreatesColimit K F := - createsColimitOfFullyFaithfulOfLift' (isColimitOfPreserves _ (colimit.isColimit K)) _ - (Iso.refl _) - -- Notice however that even if the isomorphism is `Iso.refl _`, -- this construction will insert additional identity morphisms in the cocone maps, -- so the constructed colimits may not be ideal, definitionally. diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Finite.lean b/Mathlib/CategoryTheory/Limits/Preserves/Finite.lean index 89f2b68d3e856..2013b3ba3f84f 100644 --- a/Mathlib/CategoryTheory/Limits/Preserves/Finite.lean +++ b/Mathlib/CategoryTheory/Limits/Preserves/Finite.lean @@ -78,7 +78,6 @@ lemma preservesFiniteLimits_of_preservesFiniteLimitsOfSize (F : C ⥤ D) ∀ (J : Type w) {𝒥 : SmallCategory J} (_ : @FinCategory J 𝒥), PreservesLimitsOfShape J F) : PreservesFiniteLimits F where preservesFiniteLimits J (_ : SmallCategory J) _ := by - letI : Category (ULiftHom (ULift J)) := ULiftHom.category haveI := h (ULiftHom (ULift J)) CategoryTheory.finCategoryUlift exact preservesLimitsOfShape_of_equiv (ULiftHomULiftCategory.equiv J).symm F diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Ulift.lean b/Mathlib/CategoryTheory/Limits/Preserves/Ulift.lean index 2b845755423e4..f8819e7377ca7 100644 --- a/Mathlib/CategoryTheory/Limits/Preserves/Ulift.lean +++ b/Mathlib/CategoryTheory/Limits/Preserves/Ulift.lean @@ -72,6 +72,7 @@ noncomputable instance : PreservesColimitsOfSize.{w', w} uliftFunctor.{v, u} whe The functor `uliftFunctor : Type u ⥤ Type (max u v)` creates `u`-small colimits. -/ noncomputable instance : CreatesColimitsOfSize.{w, u} uliftFunctor.{v, u} where - CreatesColimitsOfShape := { CreatesColimit := fun {_} ↦ createsColimitOfFullyFaithfulOfPreserves } + CreatesColimitsOfShape := + { CreatesColimit := fun {_} ↦ createsColimitOfReflectsIsomorphismsOfPreserves } end CategoryTheory.Limits.Types From 794c8dd90c4d18fade3f9ba74065ee47dcac1390 Mon Sep 17 00:00:00 2001 From: JovanGerb Date: Sun, 2 Feb 2025 13:52:14 +0000 Subject: [PATCH 006/103] perf: fix some slow declarations (#21323) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR fixes some slow declarations, by - changing the proof slightly so that unification is happier - giving more arguments in a `rw` theorem - replacing a slow `set` with `let`. - explicitly supplying an autoparam proof, or adding the result to the context to help the autoparam. - fixing a type so that a slow `erw` can become a less slow `rw`. - replacing `‹Ring R›` with `(‹Ring R›:)`, which forces the expression to be fully elaborated immediately, instead of temporarily turning into a synthetic metavariable. - reordering the instances in a spread construction of an instance (so that the ancestor that is represented as a subobject field comes first). See also #21030 for another example of this. To find most of these, I took a look at the declarations that use at least 100000 heartbeats (i.e. at least half of the default maximum). Co-authored-by: JovanGerb <56355248+JovanGerb@users.noreply.github.com> --- .../Algebra/Category/ModuleCat/Monoidal/Closed.lean | 2 +- Mathlib/Algebra/Field/IsField.lean | 9 +++++---- .../ContinuousFunctionalCalculus/Order.lean | 9 +++++---- Mathlib/Analysis/Calculus/ContDiff/Bounds.lean | 11 +++++------ Mathlib/FieldTheory/IsAlgClosed/Basic.lean | 2 +- Mathlib/MeasureTheory/Function/Jacobian.lean | 10 ++++++---- .../Probability/Kernel/Disintegration/Density.lean | 5 +++-- .../GroupCohomology/Resolution.lean | 7 +++---- Mathlib/RingTheory/DedekindDomain/Ideal.lean | 6 +++--- Mathlib/RingTheory/IntegralDomain.lean | 2 +- Mathlib/RingTheory/PowerSeries/Order.lean | 2 +- 11 files changed, 34 insertions(+), 31 deletions(-) diff --git a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Closed.lean b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Closed.lean index 61228a85b17e0..ddcce4f281924 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Closed.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Closed.lean @@ -34,7 +34,7 @@ def monoidalClosedHomEquiv (M N P : ModuleCat.{u} R) : apply TensorProduct.ext' intro m n simp only [Hom.hom₂_ofHom₂, LinearMap.comp_apply, hom_comp, MonoidalCategory.tensorLeft_obj] - erw [MonoidalCategory.braiding_hom_apply, TensorProduct.lift.tmul] + erw [MonoidalCategory.braiding_hom_apply m n, TensorProduct.lift.tmul] right_inv _ := rfl instance : MonoidalClosed (ModuleCat.{u} R) where diff --git a/Mathlib/Algebra/Field/IsField.lean b/Mathlib/Algebra/Field/IsField.lean index f598ad7186426..d0a69f55c8b70 100644 --- a/Mathlib/Algebra/Field/IsField.lean +++ b/Mathlib/Algebra/Field/IsField.lean @@ -65,10 +65,11 @@ noncomputable def IsField.toSemifield {R : Type u} [Semiring R] (h : IsField R) nnqsmul_def _ _ := rfl /-- Transferring from `IsField` to `Field`. -/ -noncomputable def IsField.toField {R : Type u} [Ring R] (h : IsField R) : Field R := - { ‹Ring R›, IsField.toSemifield h with - qsmul := _ - qsmul_def := fun _ _ => rfl } +noncomputable def IsField.toField {R : Type u} [Ring R] (h : IsField R) : Field R where + __ := (‹Ring R›:) -- this also works without the `( :)`, but it's slow + __ := h.toSemifield + qsmul := _ + qsmul_def := fun _ _ => rfl /-- For each field, and for each nonzero element of said field, there is a unique inverse. Since `IsField` doesn't remember the data of an `inv` function and as such, diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean index 62ae49c6840de..bab4c2a4b7b23 100644 --- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean @@ -282,7 +282,7 @@ lemma CStarAlgebra.isUnit_of_le {a b : A} (h₀ : IsUnit a) (ha : 0 ≤ a := by nontriviality A have hb := (show 0 ≤ a from ha).trans hab rw [zero_not_mem_iff, SpectrumRestricts.nnreal_lt_iff (.nnreal_of_nonneg ‹_›), - NNReal.coe_zero, ← CFC.exists_pos_algebraMap_le_iff] at h₀ ⊢ + NNReal.coe_zero, ← CFC.exists_pos_algebraMap_le_iff (.of_nonneg ‹_›)] at h₀ ⊢ peel h₀ with r hr _ exact this.trans hab @@ -399,14 +399,15 @@ lemma norm_le_norm_of_nonneg_of_le {a b : A} (ha : 0 ≤ a := by cfc_tac) (hab : simpa only [ge_iff_le, Unitization.norm_inr] using this a b (by simpa) (by rwa [Unitization.inr_le_iff a b]) intro a b ha hab - have hb_nonneg : 0 ≤ b := ha.trans hab - have : 0 ≤ a := by cfc_tac + have hb : 0 ≤ b := ha.trans hab + -- these two `have`s are just for performance + have := IsSelfAdjoint.of_nonneg ha; have := IsSelfAdjoint.of_nonneg hb have h₂ : cfc (id : ℝ → ℝ) a ≤ cfc (fun _ => ‖b‖) a := by calc _ = a := by rw [cfc_id ℝ a] _ ≤ cfc id b := (cfc_id ℝ b) ▸ hab _ ≤ cfc (fun _ => ‖b‖) b := by refine cfc_mono fun x hx => ?_ - calc x = ‖x‖ := (Real.norm_of_nonneg (spectrum_nonneg_of_nonneg hb_nonneg hx)).symm + calc x = ‖x‖ := (Real.norm_of_nonneg (spectrum_nonneg_of_nonneg hb hx)).symm _ ≤ ‖b‖ := spectrum.norm_le_norm_of_mem hx _ = _ := by rw [cfc_const _ _, cfc_const _ _] rw [cfc_le_iff id (fun _ => ‖b‖) a] at h₂ diff --git a/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean b/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean index e5879e948ab45..7ca5af36fcc5e 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean @@ -140,11 +140,10 @@ theorem ContinuousLinearMap.norm_iteratedFDerivWithin_le_of_bilinear (B : E →L have isoF : Fu ≃ₗᵢ[𝕜] F := LinearIsometryEquiv.ulift 𝕜 F have isoG : Gu ≃ₗᵢ[𝕜] G := LinearIsometryEquiv.ulift 𝕜 G -- lift `f` and `g` to versions `fu` and `gu` on the lifted spaces. - set fu : Du → Eu := isoE.symm ∘ f ∘ isoD with hfu - set gu : Du → Fu := isoF.symm ∘ g ∘ isoD with hgu + let fu : Du → Eu := isoE.symm ∘ f ∘ isoD + let gu : Du → Fu := isoF.symm ∘ g ∘ isoD -- lift the bilinear map `B` to a bilinear map `Bu` on the lifted spaces. - set Bu₀ : Eu →L[𝕜] Fu →L[𝕜] G := ((B.comp (isoE : Eu →L[𝕜] E)).flip.comp (isoF : Fu →L[𝕜] F)).flip - with hBu₀ + let Bu₀ : Eu →L[𝕜] Fu →L[𝕜] G := ((B.comp (isoE : Eu →L[𝕜] E)).flip.comp (isoF : Fu →L[𝕜] F)).flip let Bu : Eu →L[𝕜] Fu →L[𝕜] Gu := ContinuousLinearMap.compL 𝕜 Eu (Fu →L[𝕜] G) (Fu →L[𝕜] Gu) (ContinuousLinearMap.compL 𝕜 Fu G Gu (isoG.symm : G →L[𝕜] Gu)) Bu₀ @@ -152,12 +151,12 @@ theorem ContinuousLinearMap.norm_iteratedFDerivWithin_le_of_bilinear (B : E →L (ContinuousLinearMap.compL 𝕜 Fu G Gu (isoG.symm : G →L[𝕜] Gu)) Bu₀ := rfl have Bu_eq : (fun y => Bu (fu y) (gu y)) = isoG.symm ∘ (fun y => B (f y) (g y)) ∘ isoD := by ext1 y - simp [Du, Eu, Fu, Gu, hBu, hBu₀, hfu, hgu] + simp [Du, Eu, Fu, Gu, hBu, Bu₀, fu, gu] -- All norms are preserved by the lifting process. have Bu_le : ‖Bu‖ ≤ ‖B‖ := by refine ContinuousLinearMap.opNorm_le_bound _ (norm_nonneg B) fun y => ?_ refine ContinuousLinearMap.opNorm_le_bound _ (by positivity) fun x => ?_ - simp only [Du, Eu, Fu, Gu, hBu, hBu₀, compL_apply, coe_comp', Function.comp_apply, + simp only [Du, Eu, Fu, Gu, hBu, Bu₀, compL_apply, coe_comp', Function.comp_apply, ContinuousLinearEquiv.coe_coe, LinearIsometryEquiv.coe_coe, flip_apply, LinearIsometryEquiv.norm_map] calc diff --git a/Mathlib/FieldTheory/IsAlgClosed/Basic.lean b/Mathlib/FieldTheory/IsAlgClosed/Basic.lean index f64c0cb3f0efd..e6f813f438f23 100644 --- a/Mathlib/FieldTheory/IsAlgClosed/Basic.lean +++ b/Mathlib/FieldTheory/IsAlgClosed/Basic.lean @@ -150,7 +150,7 @@ theorem of_ringEquiv (k' : Type u) [Field k'] (e : k ≃+* k') have hpe : degree (p.map e.symm.toRingHom) ≠ 0 := by rw [degree_map] exact ne_of_gt (degree_pos_of_irreducible hp) - rcases IsAlgClosed.exists_root (k := k) (p.map e.symm) hpe with ⟨x, hx⟩ + rcases IsAlgClosed.exists_root (k := k) (p.map e.symm.toRingHom) hpe with ⟨x, hx⟩ use e x rw [IsRoot] at hx apply e.symm.injective diff --git a/Mathlib/MeasureTheory/Function/Jacobian.lean b/Mathlib/MeasureTheory/Function/Jacobian.lean index bfb9326f21a71..b118e35f16fba 100644 --- a/Mathlib/MeasureTheory/Function/Jacobian.lean +++ b/Mathlib/MeasureTheory/Function/Jacobian.lean @@ -798,8 +798,9 @@ theorem addHaar_image_le_lintegral_abs_det_fderiv_aux1 (hs : MeasurableSet s) have I : ENNReal.ofReal |A.det| < m := by simp only [m, ENNReal.ofReal, lt_add_iff_pos_right, εpos, ENNReal.coe_lt_coe] rcases ((addHaar_image_le_mul_of_det_lt μ A I).and self_mem_nhdsWithin).exists with ⟨δ, h, δpos⟩ - obtain ⟨δ', δ'pos, hδ'⟩ : ∃ (δ' : ℝ), 0 < δ' ∧ ∀ B, dist B A < δ' → dist B.det A.det < ↑ε := - continuousAt_iff.1 (ContinuousLinearMap.continuous_det (E := E)).continuousAt ε εpos + obtain ⟨δ', δ'pos, hδ'⟩ : ∃ (δ' : ℝ), 0 < δ' ∧ ∀ B, dist B A < δ' → dist B.det A.det < ↑ε := by + refine continuousAt_iff.1 ?_ ε εpos + exact ContinuousLinearMap.continuous_det.continuousAt let δ'' : ℝ≥0 := ⟨δ' / 2, (half_pos δ'pos).le⟩ refine ⟨min δ δ'', lt_min δpos (half_pos δ'pos), ?_, ?_⟩ · intro B hB @@ -920,8 +921,9 @@ theorem lintegral_abs_det_fderiv_le_addHaar_image_aux1 (hs : MeasurableSet s) ∀ (t : Set E) (g : E → E), ApproximatesLinearOn g A t δ → ENNReal.ofReal |A.det| * μ t ≤ μ (g '' t) + ε * μ t := by intro A - obtain ⟨δ', δ'pos, hδ'⟩ : ∃ (δ' : ℝ), 0 < δ' ∧ ∀ B, dist B A < δ' → dist B.det A.det < ↑ε := - continuousAt_iff.1 (ContinuousLinearMap.continuous_det (E := E)).continuousAt ε εpos + obtain ⟨δ', δ'pos, hδ'⟩ : ∃ (δ' : ℝ), 0 < δ' ∧ ∀ B, dist B A < δ' → dist B.det A.det < ↑ε := by + refine continuousAt_iff.1 ?_ ε εpos + exact ContinuousLinearMap.continuous_det.continuousAt let δ'' : ℝ≥0 := ⟨δ' / 2, (half_pos δ'pos).le⟩ have I'' : ∀ B : E →L[ℝ] E, ‖B - A‖ ≤ ↑δ'' → |B.det - A.det| ≤ ↑ε := by intro B hB diff --git a/Mathlib/Probability/Kernel/Disintegration/Density.lean b/Mathlib/Probability/Kernel/Disintegration/Density.lean index a1aa1648a693e..8197f13c31cc9 100644 --- a/Mathlib/Probability/Kernel/Disintegration/Density.lean +++ b/Mathlib/Probability/Kernel/Disintegration/Density.lean @@ -131,15 +131,16 @@ lemma measurable_densityProcess (κ : Kernel α (γ × β)) (ν : Kernel α γ) Measurable (fun (p : α × γ) ↦ densityProcess κ ν n p.1 p.2 s) := (measurable_densityProcess_aux κ ν n hs).ennreal_toReal +-- The following two lemmas also work without the `( :)`, but they are slow. lemma measurable_densityProcess_left (κ : Kernel α (γ × β)) (ν : Kernel α γ) (n : ℕ) (x : γ) {s : Set β} (hs : MeasurableSet s) : Measurable (fun a ↦ densityProcess κ ν n a x s) := - (measurable_densityProcess κ ν n hs).comp (measurable_id.prod_mk measurable_const) + ((measurable_densityProcess κ ν n hs).comp (measurable_id.prod_mk measurable_const):) lemma measurable_densityProcess_right (κ : Kernel α (γ × β)) (ν : Kernel α γ) (n : ℕ) {s : Set β} (a : α) (hs : MeasurableSet s) : Measurable (fun x ↦ densityProcess κ ν n a x s) := - (measurable_densityProcess κ ν n hs).comp (measurable_const.prod_mk measurable_id) + ((measurable_densityProcess κ ν n hs).comp (measurable_const.prod_mk measurable_id):) lemma measurable_countableFiltration_densityProcess (κ : Kernel α (γ × β)) (ν : Kernel α γ) (n : ℕ) (a : α) {s : Set β} (hs : MeasurableSet s) : diff --git a/Mathlib/RepresentationTheory/GroupCohomology/Resolution.lean b/Mathlib/RepresentationTheory/GroupCohomology/Resolution.lean index b2e5e6476ce21..25eddf3912d4a 100644 --- a/Mathlib/RepresentationTheory/GroupCohomology/Resolution.lean +++ b/Mathlib/RepresentationTheory/GroupCohomology/Resolution.lean @@ -278,7 +278,7 @@ open groupCohomology.resolution /-- Given a `k`-linear `G`-representation `A`, the set of representation morphisms `Hom(k[Gⁿ⁺¹], A)` is `k`-linearly isomorphic to the set of functions `Gⁿ → A`. -/ noncomputable def diagonalHomEquiv : - (Rep.ofMulAction k G (Fin (n + 1) → G) ⟶ A) ≃ₗ[k] (Fin n → G) → A := + (Rep.diagonal k G (n + 1) ⟶ A) ≃ₗ[k] (Fin n → G) → A := Linear.homCongr k ((diagonalSucc k G n).trans ((Representation.ofMulAction k G G).repOfTprodIso 1)) (Iso.refl _) ≪≫ₗ @@ -291,7 +291,7 @@ variable {n A} the set of representation morphisms `Hom(k[Gⁿ⁺¹], A)` with `Fun(Gⁿ, A)`. This lemma says that this sends a morphism of representations `f : k[Gⁿ⁺¹] ⟶ A` to the function `(g₁, ..., gₙ) ↦ f(1, g₁, g₁g₂, ..., g₁g₂...gₙ).` -/ -theorem diagonalHomEquiv_apply (f : Rep.ofMulAction k G (Fin (n + 1) → G) ⟶ A) (x : Fin n → G) : +theorem diagonalHomEquiv_apply (f : Rep.diagonal k G (n + 1) ⟶ A) (x : Fin n → G) : diagonalHomEquiv n A f x = f.hom (Finsupp.single (Fin.partialProd x) 1) := by /- Porting note (https://github.com/leanprover-community/mathlib4/issues/11039): broken proof was unfold diagonalHomEquiv @@ -324,8 +324,7 @@ theorem diagonalHomEquiv_symm_apply (f : (Fin n → G) → A) (x : Fin (n + 1) leftRegularHomEquiv_symm_apply, Linear.homCongr_symm_apply, Iso.trans_hom, Iso.refl_inv, Category.comp_id, Action.comp_hom, MonoidalClosed.linearHomEquivComm_symm_hom, ModuleCat.hom_comp, LinearMap.comp_apply] - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [diagonalSucc_hom_single] + rw [diagonalSucc_hom_single] -- The prototype linter that checks if `erw` could be replaced with `rw` would time out -- if it replaces the next `erw`s with `rw`s. So we focus down on the relevant part. conv_lhs => diff --git a/Mathlib/RingTheory/DedekindDomain/Ideal.lean b/Mathlib/RingTheory/DedekindDomain/Ideal.lean index 6092f3c84aea4..e1b5525792371 100644 --- a/Mathlib/RingTheory/DedekindDomain/Ideal.lean +++ b/Mathlib/RingTheory/DedekindDomain/Ideal.lean @@ -592,9 +592,9 @@ theorem Ideal.dvd_iff_le {I J : Ideal A} : I ∣ J ↔ J ≤ I := · have hJ : J = ⊥ := by rwa [hI, ← eq_bot_iff] at h rw [hI, hJ] have hI' : (I : FractionalIdeal A⁰ (FractionRing A)) ≠ 0 := coeIdeal_ne_zero.mpr hI - have : (I : FractionalIdeal A⁰ (FractionRing A))⁻¹ * J ≤ 1 := - le_trans (mul_left_mono (↑I)⁻¹ ((coeIdeal_le_coeIdeal _).mpr h)) - (le_of_eq (inv_mul_cancel₀ hI')) + have : (I : FractionalIdeal A⁰ (FractionRing A))⁻¹ * J ≤ 1 := by + rw [← inv_mul_cancel₀ hI'] + exact mul_left_mono _ ((coeIdeal_le_coeIdeal _).mpr h) obtain ⟨H, hH⟩ := le_one_iff_exists_coeIdeal.mp this use H refine coeIdeal_injective (show (J : FractionalIdeal A⁰ (FractionRing A)) = ↑(I * H) from ?_) diff --git a/Mathlib/RingTheory/IntegralDomain.lean b/Mathlib/RingTheory/IntegralDomain.lean index d88c930f3e8ee..57d9cf6e6bfb4 100644 --- a/Mathlib/RingTheory/IntegralDomain.lean +++ b/Mathlib/RingTheory/IntegralDomain.lean @@ -89,8 +89,8 @@ variable [Ring R] [IsDomain R] [Fintype R] `Mathlib.RingTheory.LittleWedderburn`. -/ def Fintype.divisionRingOfIsDomain (R : Type*) [Ring R] [IsDomain R] [DecidableEq R] [Fintype R] : DivisionRing R where + __ := (‹Ring R›:) -- this also works without the `( :)`, but it's slightly slow __ := Fintype.groupWithZeroOfCancel R - __ := ‹Ring R› nnqsmul := _ nnqsmul_def := fun _ _ => rfl qsmul := _ diff --git a/Mathlib/RingTheory/PowerSeries/Order.lean b/Mathlib/RingTheory/PowerSeries/Order.lean index 97eaca3724e77..c1ccd93811bc6 100644 --- a/Mathlib/RingTheory/PowerSeries/Order.lean +++ b/Mathlib/RingTheory/PowerSeries/Order.lean @@ -315,7 +315,7 @@ variable [CommRing R] [IsDomain R] theorem order_mul (φ ψ : R⟦X⟧) : order (φ * ψ) = order φ + order ψ := by classical simp only [order_eq_emultiplicity_X] - rw [emultiplicity_mul X_prime] + exact emultiplicity_mul X_prime -- Dividing `X` by the maximal power of `X` dividing it leaves `1`. @[simp] From 72fe8e29d585265ee6bfac7b93764be815e65aa0 Mon Sep 17 00:00:00 2001 From: Matthew Robert Ballard Date: Sun, 2 Feb 2025 14:16:41 +0000 Subject: [PATCH 007/103] perf(Algebra.Quaternion): reorder instances in spread (#21030) As @JovanGerb reminded me, we still have some places where supplied instance ordering can result in an unnecessarily unfolded term. `Quaternion.instDivisionRing` is one such. Co-authored-by: Jovan Gerbscheid --- Mathlib/Algebra/Quaternion.lean | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Mathlib/Algebra/Quaternion.lean b/Mathlib/Algebra/Quaternion.lean index 6a4475fd7cc95..c4f440a147507 100644 --- a/Mathlib/Algebra/Quaternion.lean +++ b/Mathlib/Algebra/Quaternion.lean @@ -1191,8 +1191,7 @@ instance instInv : Inv ℍ[R] := ⟨fun a => (normSq a)⁻¹ • star a⟩ instance instGroupWithZero : GroupWithZero ℍ[R] := - { Quaternion.instNontrivial, - (by infer_instance : MonoidWithZero ℍ[R]) with + { Quaternion.instNontrivial with inv := Inv.inv inv_zero := by rw [instInv_inv, star_zero, smul_zero] mul_inv_cancel := fun a ha => by @@ -1230,14 +1229,14 @@ instance instRatCast : RatCast ℍ[R] where ratCast q := (q : R) @[norm_cast] lemma coe_ratCast (q : ℚ) : ↑(q : R) = (q : ℍ[R]) := rfl instance instDivisionRing : DivisionRing ℍ[R] where - __ := Quaternion.instGroupWithZero __ := Quaternion.instRing + __ := Quaternion.instGroupWithZero nnqsmul := (· • ·) qsmul := (· • ·) - nnratCast_def q := by rw [← coe_nnratCast, NNRat.cast_def, coe_div, coe_natCast, coe_natCast] - ratCast_def q := by rw [← coe_ratCast, Rat.cast_def, coe_div, coe_intCast, coe_natCast] - nnqsmul_def q x := by rw [← coe_nnratCast, coe_mul_eq_smul]; ext <;> exact NNRat.smul_def _ _ - qsmul_def q x := by rw [← coe_ratCast, coe_mul_eq_smul]; ext <;> exact Rat.smul_def _ _ + nnratCast_def _ := by rw [← coe_nnratCast, NNRat.cast_def, coe_div, coe_natCast, coe_natCast] + ratCast_def _ := by rw [← coe_ratCast, Rat.cast_def, coe_div, coe_intCast, coe_natCast] + nnqsmul_def _ _ := by rw [← coe_nnratCast, coe_mul_eq_smul]; ext <;> exact NNRat.smul_def .. + qsmul_def _ _ := by rw [← coe_ratCast, coe_mul_eq_smul]; ext <;> exact Rat.smul_def .. theorem normSq_inv : normSq a⁻¹ = (normSq a)⁻¹ := map_inv₀ normSq _ From edfa348a22701c1f226b8b5a16fc28418b152faf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Sun, 2 Feb 2025 14:25:33 +0000 Subject: [PATCH 008/103] chore: remove references to `_root_.Embedding` (#21345) This was renamed to `Topology.IsEmbedding` in #15993 and #18133 and those docstrings should have been fixed. --- Mathlib/Topology/Algebra/StarSubalgebra.lean | 2 +- Mathlib/Topology/Algebra/Support.lean | 9 ++++----- Mathlib/Topology/Compactness/Compact.lean | 4 ++-- Mathlib/Topology/Compactness/Lindelof.lean | 4 ++-- Mathlib/Topology/Compactness/SigmaCompact.lean | 4 ++-- Mathlib/Topology/Defs/Induced.lean | 2 +- 6 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Mathlib/Topology/Algebra/StarSubalgebra.lean b/Mathlib/Topology/Algebra/StarSubalgebra.lean index 593aedee1802e..3cde0521a3cb3 100644 --- a/Mathlib/Topology/Algebra/StarSubalgebra.lean +++ b/Mathlib/Topology/Algebra/StarSubalgebra.lean @@ -33,7 +33,7 @@ variable [TopologicalSpace A] [Semiring A] [Algebra R A] [StarRing A] [StarModul instance [TopologicalSemiring A] (s : StarSubalgebra R A) : TopologicalSemiring s := s.toSubalgebra.topologicalSemiring -/-- The `StarSubalgebra.inclusion` of a star subalgebra is an `Embedding`. -/ +/-- The `StarSubalgebra.inclusion` of a star subalgebra is an embedding. -/ lemma isEmbedding_inclusion {S₁ S₂ : StarSubalgebra R A} (h : S₁ ≤ S₂) : IsEmbedding (inclusion h) where eq_induced := Eq.symm induced_compose diff --git a/Mathlib/Topology/Algebra/Support.lean b/Mathlib/Topology/Algebra/Support.lean index e255b35efc416..0c96aafbdfcca 100644 --- a/Mathlib/Topology/Algebra/Support.lean +++ b/Mathlib/Topology/Algebra/Support.lean @@ -21,12 +21,11 @@ Furthermore, we say that `f` has compact support if the topological support of ` * `mulTSupport` & `tsupport` * `HasCompactMulSupport` & `HasCompactSupport` -## Implementation Notes +## TODO -* We write all lemmas for multiplicative functions, and use `@[to_additive]` to get the more common - additive versions. -* We do not put the definitions in the `Function` namespace, following many other topological - definitions that are in the root namespace (compare `Embedding` vs `Function.Embedding`). +The definitions have been put in the root namespace following many other topological definitions, +like `Embedding`. Since then, `Embedding` was renamed to `Topology.IsEmbedding`, so it might be +worth reconsidering namespacing the definitions here. -/ diff --git a/Mathlib/Topology/Compactness/Compact.lean b/Mathlib/Topology/Compactness/Compact.lean index d0db78c7c2d29..d83763afd6e29 100644 --- a/Mathlib/Topology/Compactness/Compact.lean +++ b/Mathlib/Topology/Compactness/Compact.lean @@ -906,8 +906,8 @@ theorem Topology.IsInducing.isCompact_iff {f : X → Y} (hf : IsInducing f) : @[deprecated (since := "2024-10-28")] alias Inducing.isCompact_iff := IsInducing.isCompact_iff -/-- If `f : X → Y` is an `Embedding`, the image `f '' s` of a set `s` is compact - if and only if `s` is compact. -/ +/-- If `f : X → Y` is an embedding, the image `f '' s` of a set `s` is compact +if and only if `s` is compact. -/ theorem Topology.IsEmbedding.isCompact_iff {f : X → Y} (hf : IsEmbedding f) : IsCompact s ↔ IsCompact (f '' s) := hf.isInducing.isCompact_iff diff --git a/Mathlib/Topology/Compactness/Lindelof.lean b/Mathlib/Topology/Compactness/Lindelof.lean index 258f4db27756f..d74d5d157ddc5 100644 --- a/Mathlib/Topology/Compactness/Lindelof.lean +++ b/Mathlib/Topology/Compactness/Lindelof.lean @@ -610,8 +610,8 @@ theorem Topology.IsInducing.isLindelof_iff {f : X → Y} (hf : IsInducing f) : @[deprecated (since := "2024-10-28")] alias Inducing.isLindelof_iff := IsInducing.isLindelof_iff -/-- If `f : X → Y` is an `Embedding`, the image `f '' s` of a set `s` is Lindelöf - if and only if `s` is Lindelöf. -/ +/-- If `f : X → Y` is an embedding, the image `f '' s` of a set `s` is Lindelöf +if and only if `s` is Lindelöf. -/ theorem Topology.IsEmbedding.isLindelof_iff {f : X → Y} (hf : IsEmbedding f) : IsLindelof s ↔ IsLindelof (f '' s) := hf.isInducing.isLindelof_iff diff --git a/Mathlib/Topology/Compactness/SigmaCompact.lean b/Mathlib/Topology/Compactness/SigmaCompact.lean index 92f225b9e60be..adf7cf56cc86c 100644 --- a/Mathlib/Topology/Compactness/SigmaCompact.lean +++ b/Mathlib/Topology/Compactness/SigmaCompact.lean @@ -121,8 +121,8 @@ lemma Topology.IsInducing.isSigmaCompact_iff {f : X → Y} {s : Set X} @[deprecated (since := "2024-10-28")] alias Inducing.isSigmaCompact_iff := IsInducing.isSigmaCompact_iff -/-- If `f : X → Y` is an `Embedding`, the image `f '' s` of a set `s` is σ-compact - if and only `s` is σ-compact. -/ +/-- If `f : X → Y` is an embedding, the image `f '' s` of a set `s` is σ-compact +if and only `s` is σ-compact. -/ lemma Topology.IsEmbedding.isSigmaCompact_iff {f : X → Y} {s : Set X} (hf : IsEmbedding f) : IsSigmaCompact s ↔ IsSigmaCompact (f '' s) := hf.isInducing.isSigmaCompact_iff diff --git a/Mathlib/Topology/Defs/Induced.lean b/Mathlib/Topology/Defs/Induced.lean index 338841fc6393b..4e561c7a9e60e 100644 --- a/Mathlib/Topology/Defs/Induced.lean +++ b/Mathlib/Topology/Defs/Induced.lean @@ -25,7 +25,7 @@ as well as topology inducing maps, topological embeddings, and quotient maps. * `IsInducing`: a map `f : X → Y` is called *inducing*, if the topology on the domain is equal to the induced topology. -* `Embedding`: a map `f : X → Y` is an *embedding*, +* `IsEmbedding`: a map `f : X → Y` is an *embedding*, if it is a topology inducing map and it is injective. * `IsOpenEmbedding`: a map `f : X → Y` is an *open embedding*, From be693c252fcc92cbe6dc90521ea9ef8c6cfc5d78 Mon Sep 17 00:00:00 2001 From: Paul Reichert <6992158+datokrat@users.noreply.github.com> Date: Sun, 2 Feb 2025 17:46:16 +0000 Subject: [PATCH 009/103] feat(CategoryTheory/Grothendieck): transport; pre preserves equivalences of categories (#19484) This change proves that `Grothendieck.pre F G` is an equivalence if `G` is an equivalence. An essential ingredient in the proof is the `transport` construction: Given a morphism in the base category, `transport` yields a map between fibers of the Grothendieck construction. This PR is part of the effort to prove the Freyd-Mitchell embedding theorem. Co-authored-by: Jakob von Raumer --- Mathlib/CategoryTheory/EqToHom.lean | 1 + Mathlib/CategoryTheory/Grothendieck.lean | 156 ++++++++++++++++++++++- 2 files changed, 156 insertions(+), 1 deletion(-) diff --git a/Mathlib/CategoryTheory/EqToHom.lean b/Mathlib/CategoryTheory/EqToHom.lean index e9ede8e6dc5e4..d1f6ccdc36a02 100644 --- a/Mathlib/CategoryTheory/EqToHom.lean +++ b/Mathlib/CategoryTheory/EqToHom.lean @@ -252,6 +252,7 @@ theorem hext {F G : C ⥤ D} (h_obj : ∀ X, F.obj X = G.obj X) -- Using equalities between functors. theorem congr_obj {F G : C ⥤ D} (h : F = G) (X) : F.obj X = G.obj X := by rw [h] +@[reassoc] theorem congr_hom {F G : C ⥤ D} (h : F = G) {X Y} (f : X ⟶ Y) : F.map f = eqToHom (congr_obj h X) ≫ G.map f ≫ eqToHom (congr_obj h Y).symm := by subst h; simp diff --git a/Mathlib/CategoryTheory/Grothendieck.lean b/Mathlib/CategoryTheory/Grothendieck.lean index 799069e98d5d9..f3614f0ca47a9 100644 --- a/Mathlib/CategoryTheory/Grothendieck.lean +++ b/Mathlib/CategoryTheory/Grothendieck.lean @@ -28,6 +28,16 @@ Really we should treat `Cat` as a 2-category, and allow `F` to be a 2-functor. There is also a closely related construction starting with `G : Cᵒᵖ ⥤ Cat`, where morphisms consists again of `β : b ⟶ b'` and `φ : f ⟶ (F.map (op β)).obj f'`. +## Notable constructions + +- `Grothendieck F` is the Grothendieck construction. +- Elements of `Grothendieck F` whose base is `c : C` can be transported along `f : c ⟶ d` using +`transport`. +- A natural transformation `α : F ⟶ G` induces `map α : Grothendieck F ⥤ Grothendieck G`. +- The Grothendieck construction and `map` together form a functor (`functor`) from the functor +category `E ⥤ Cat` to the over category `Over E`. +- A functor `G : D ⥤ C` induces `pre F G : Grothendieck (G ⋙ F) ⥤ Grothendieck F`. + ## References See also `CategoryTheory.Functor.Elements` for the category of elements of functor `F : C ⥤ Type`. @@ -144,10 +154,64 @@ theorem congr {X Y : Grothendieck F} {f g : X ⟶ Y} (h : f = g) : dsimp simp +@[simp] +theorem base_eqToHom {X Y : Grothendieck F} (h : X = Y) : + (eqToHom h).base = eqToHom (congrArg Grothendieck.base h) := by subst h; rfl + +@[simp] +theorem fiber_eqToHom {X Y : Grothendieck F} (h : X = Y) : + (eqToHom h).fiber = eqToHom (by subst h; simp) := by subst h; rfl + lemma eqToHom_eq {X Y : Grothendieck F} (hF : X = Y) : eqToHom hF = { base := eqToHom (by subst hF; rfl), fiber := eqToHom (by subst hF; simp) } := by subst hF rfl + +section Transport + +/-- +If `F : C ⥤ Cat` is a functor and `t : c ⟶ d` is a morphism in `C`, then `transport` maps each +`c`-based element of `Grothendieck F` to a `d`-based element. +-/ +@[simps] +def transport (x : Grothendieck F) {c : C} (t : x.base ⟶ c) : Grothendieck F := + ⟨c, (F.map t).obj x.fiber⟩ + +/-- +If `F : C ⥤ Cat` is a functor and `t : c ⟶ d` is a morphism in `C`, then `transport` maps each +`c`-based element `x` of `Grothendieck F` to a `d`-based element `x.transport t`. + +`transport_hom` is the morphism `x ⟶ x.transport t` induced by `t` and the identity on fibers. +-/ +@[simps] +def toTransport (x : Grothendieck F) {c : C} (t : x.base ⟶ c) : x ⟶ x.transport t := + ⟨t, 𝟙 _⟩ + +/-- +Construct an isomorphism in a Grothendieck construction from isomorphisms in its base and fiber. +-/ +@[simps] +def isoMk {X Y : Grothendieck F} (e₁ : X.base ≅ Y.base) + (e₂ : (F.map e₁.hom).obj X.fiber ≅ Y.fiber) : + X ≅ Y where + hom := ⟨e₁.hom, e₂.hom⟩ + inv := ⟨e₁.inv, (F.map e₁.inv).map e₂.inv ≫ + eqToHom (Functor.congr_obj (F.mapIso e₁).hom_inv_id X.fiber)⟩ + hom_inv_id := Grothendieck.ext _ _ (by simp) (by simp) + inv_hom_id := Grothendieck.ext _ _ (by simp) (by + have := Functor.congr_hom (F.mapIso e₁).inv_hom_id e₂.inv + dsimp at this + simp [this]) + +/-- +If `F : C ⥤ Cat` and `x : Grothendieck F`, then every `C`-isomorphism `α : x.base ≅ c` induces +an isomorphism between `x` and its transport along `α` +-/ +@[simps!] +def transportIso (x : Grothendieck F) {c : C} (α : x.base ≅ c) : + x.transport α.hom ≅ x := (isoMk α (Iso.refl _)).symm + +end Transport section variable (F) @@ -355,7 +419,10 @@ def grothendieckTypeToCat : Grothendieck (G ⋙ typeToCat) ≌ G.Elements where simp rfl -variable (F) in +section Pre + +variable (F) + /-- Applying a functor `G : D ⥤ C` to the base of the Grothendieck construction induces a functor `Grothendieck (G ⋙ F) ⥤ Grothendieck F`. -/ @[simps] @@ -365,6 +432,93 @@ def pre (G : D ⥤ C) : Grothendieck (G ⋙ F) ⥤ Grothendieck F where map_id X := Grothendieck.ext _ _ (G.map_id _) (by simp) map_comp f g := Grothendieck.ext _ _ (G.map_comp _ _) (by simp) +@[simp] +theorem pre_id : pre F (𝟭 C) = 𝟭 _ := rfl + +/-- +An natural isomorphism between functors `G ≅ H` induces a natural isomorphism between the canonical +morphism `pre F G` and `pre F H`, up to composition with +`Grothendieck (G ⋙ F) ⥤ Grothendieck (H ⋙ F)`. +-/ +def preNatIso {G H : D ⥤ C} (α : G ≅ H) : + pre F G ≅ map (whiskerRight α.hom F) ⋙ (pre F H) := + NatIso.ofComponents + (fun X => (transportIso ⟨G.obj X.base, X.fiber⟩ (α.app X.base)).symm) + (fun f => by fapply Grothendieck.ext <;> simp) + +/-- +Given an equivalence of categories `G`, `preInv _ G` is the (weak) inverse of the `pre _ G.functor`. +-/ +def preInv (G : D ≌ C) : Grothendieck F ⥤ Grothendieck (G.functor ⋙ F) := + map (whiskerRight G.counitInv F) ⋙ Grothendieck.pre (G.functor ⋙ F) G.inverse + +variable {F} in +lemma pre_comp_map (G: D ⥤ C) {H : C ⥤ Cat} (α : F ⟶ H) : + pre F G ⋙ map α = map (whiskerLeft G α) ⋙ pre H G := rfl + +variable {F} in +lemma pre_comp_map_assoc (G: D ⥤ C) {H : C ⥤ Cat} (α : F ⟶ H) {E : Type*} [Category E] + (K : Grothendieck H ⥤ E) : pre F G ⋙ map α ⋙ K= map (whiskerLeft G α) ⋙ pre H G ⋙ K := rfl + +variable {E : Type*} [Category E] in +@[simp] +lemma pre_comp (G : D ⥤ C) (H : E ⥤ D) : pre F (H ⋙ G) = pre (G ⋙ F) H ⋙ pre F G := rfl + +/-- +Let `G` be an equivalence of categories. The functor induced via `pre` by `G.functor ⋙ G.inverse` +is naturally isomorphic to the functor induced via `map` by a whiskered version of `G`'s inverse +unit. +-/ +protected def preUnitIso (G : D ≌ C) : + map (whiskerRight G.unitInv _) ≅ pre (G.functor ⋙ F) (G.functor ⋙ G.inverse) := + preNatIso _ G.unitIso.symm |>.symm + +/-- +Given a functor `F : C ⥤ Cat` and an equivalence of categories `G : D ≌ C`, the functor +`pre F G.functor` is an equivalence between `Grothendieck (G.functor ⋙ F)` and `Grothendieck F`. +-/ +def preEquivalence (G : D ≌ C) : Grothendieck (G.functor ⋙ F) ≌ Grothendieck F where + functor := pre F G.functor + inverse := preInv F G + unitIso := by + refine (eqToIso ?_) + ≪≫ (Grothendieck.preUnitIso F G |> isoWhiskerLeft (map _)) + ≪≫ (pre_comp_map_assoc G.functor _ _ |> Eq.symm |> eqToIso) + calc + _ = map (𝟙 _) := map_id_eq.symm + _ = map _ := ?_ + _ = map _ ⋙ map _ := map_comp_eq _ _ + congr; ext X + simp only [Functor.comp_obj, Functor.comp_map, ← Functor.map_comp, Functor.id_obj, + Functor.map_id, NatTrans.comp_app, NatTrans.id_app, whiskerLeft_app, whiskerRight_app, + Equivalence.counitInv_functor_comp] + counitIso := preNatIso F G.counitIso.symm |>.symm + functor_unitIso_comp := by + intro X + simp only [preInv, Grothendieck.preUnitIso, eq_mpr_eq_cast, cast_eq, pre_id, id_eq, + Iso.trans_hom, eqToIso.hom, eqToHom_app, eqToHom_refl, isoWhiskerLeft_hom, NatTrans.comp_app] + fapply Grothendieck.ext <;> simp [preNatIso, transportIso] + +variable {F} in +/-- +Let `F, F' : C ⥤ Cat` be functor, `G : D ≌ C` an equivalence and `α : F ⟶ F'` a natural +transformation. + +Left-whiskering `α` by `G` and then taking the Grothendieck construction is, up to isomorphism, +the same as taking the Grothendieck construction of `α` and using the equivalences `pre F G` +and `pre F' G` to match the expected type: + +``` +Grothendieck (G.functor ⋙ F) ≌ Grothendieck F ⥤ Grothendieck F' ≌ Grothendieck (G.functor ⋙ F') +``` +-/ +def mapWhiskerLeftIsoConjPreMap {F' : C ⥤ Cat} (G : D ≌ C) (α : F ⟶ F') : + map (whiskerLeft G.functor α) ≅ + (preEquivalence F G).functor ⋙ map α ⋙ (preEquivalence F' G).inverse := + (Functor.rightUnitor _).symm ≪≫ isoWhiskerLeft _ (preEquivalence F' G).unitIso + +end Pre + section FunctorFrom variable {E : Type*} [Category E] From 3c775790879b6d19b243e0f816683e04e6b0a98b Mon Sep 17 00:00:00 2001 From: "Tristan F.-R." Date: Sun, 2 Feb 2025 18:08:31 +0000 Subject: [PATCH 010/103] fix(Linter/OldObtain): typos (#21335) typos I noticed while reading. Co-authored-by: Tristan F. --- Mathlib/Tactic/Linter/OldObtain.lean | 8 ++++---- MathlibTest/oldObtain.lean | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Mathlib/Tactic/Linter/OldObtain.lean b/Mathlib/Tactic/Linter/OldObtain.lean index f9d77e63e79e8..14e631d59f79a 100644 --- a/Mathlib/Tactic/Linter/OldObtain.lean +++ b/Mathlib/Tactic/Linter/OldObtain.lean @@ -10,9 +10,9 @@ import Lean.Elab.Command import Mathlib.Tactic.Linter.Header /-! -# The `oldObtain` linter, against stream-of-conciousness `obtain` +# The `oldObtain` linter, against stream-of-consciousness `obtain` -The `oldObtain` linter flags any occurrences of "stream-of-conciousness" `obtain`, +The `oldObtain` linter flags any occurrences of "stream-of-consciousness" `obtain`, i.e. uses of the `obtain` tactic which do not immediately provide a proof. ## Example @@ -64,7 +64,7 @@ def isObtainWithoutProof : Syntax → Bool @[deprecated isObtainWithoutProof (since := "2024-12-07")] def is_obtain_without_proof := @isObtainWithoutProof -/-- The `oldObtain` linter emits a warning upon uses of the "stream-of-conciousness" variants +/-- The `oldObtain` linter emits a warning upon uses of the "stream-of-consciousness" variants of the `obtain` tactic, i.e. with the proof postponed. -/ register_option linter.oldObtain : Bool := { defValue := false @@ -78,7 +78,7 @@ def oldObtainLinter : Linter where run := withSetOptionIn fun stx => do if (← MonadState.get).messages.hasErrors then return if let some head := stx.find? isObtainWithoutProof then - Linter.logLint linter.oldObtain head m!"Please remove stream-of-conciousness `obtain` syntax" + Linter.logLint linter.oldObtain head m!"Please remove stream-of-consciousness `obtain` syntax" initialize addLinter oldObtainLinter diff --git a/MathlibTest/oldObtain.lean b/MathlibTest/oldObtain.lean index 5a7bb3201701c..46c0e3f7f44f8 100644 --- a/MathlibTest/oldObtain.lean +++ b/MathlibTest/oldObtain.lean @@ -20,7 +20,7 @@ theorem foo : True := by -- These cases are linted against. /-- -warning: Please remove stream-of-conciousness `obtain` syntax +warning: Please remove stream-of-consciousness `obtain` syntax note: this linter can be disabled with `set_option linter.oldObtain false` -/ #guard_msgs in @@ -30,7 +30,7 @@ theorem foo' : True := by trivial /-- -warning: Please remove stream-of-conciousness `obtain` syntax +warning: Please remove stream-of-consciousness `obtain` syntax note: this linter can be disabled with `set_option linter.oldObtain false` -/ #guard_msgs in From 83b6fa7e091f74be0a76a9021399c0de3ecb9b66 Mon Sep 17 00:00:00 2001 From: Markus Himmel Date: Sun, 2 Feb 2025 19:39:31 +0000 Subject: [PATCH 011/103] feat(CategoryTheory): preservation of coimage-image comparisons (#21348) Co-authored-by: Markus Himmel --- Mathlib.lean | 1 + Mathlib/CategoryTheory/Abelian/Images.lean | 2 +- Mathlib/CategoryTheory/Abelian/Transfer.lean | 93 +++--------------- .../Preserves/Shapes/AbelianImages.lean | 95 +++++++++++++++++++ .../Limits/Preserves/Shapes/Kernels.lean | 11 +++ 5 files changed, 120 insertions(+), 82 deletions(-) create mode 100644 Mathlib/CategoryTheory/Limits/Preserves/Shapes/AbelianImages.lean diff --git a/Mathlib.lean b/Mathlib.lean index 03b67d0a6f8e5..e59346f0e63db 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -1962,6 +1962,7 @@ import Mathlib.CategoryTheory.Limits.Preserves.Grothendieck import Mathlib.CategoryTheory.Limits.Preserves.Limits import Mathlib.CategoryTheory.Limits.Preserves.Opposites import Mathlib.CategoryTheory.Limits.Preserves.Presheaf +import Mathlib.CategoryTheory.Limits.Preserves.Shapes.AbelianImages import Mathlib.CategoryTheory.Limits.Preserves.Shapes.BinaryProducts import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Biproducts import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Equalizers diff --git a/Mathlib/CategoryTheory/Abelian/Images.lean b/Mathlib/CategoryTheory/Abelian/Images.lean index 8c3bf7213ffe1..0b4b6a16873af 100644 --- a/Mathlib/CategoryTheory/Abelian/Images.lean +++ b/Mathlib/CategoryTheory/Abelian/Images.lean @@ -105,7 +105,7 @@ theorem coimage_image_factorisation : coimage.π f ≫ coimageImageComparison f simp [coimageImageComparison] /-- The coimage-image comparison morphism is functorial. -/ -@[simps!] +@[simps! obj map] def coimageImageComparisonFunctor : Arrow C ⥤ Arrow C where obj f := Arrow.mk (coimageImageComparison f.hom) map {f g} η := Arrow.homMk diff --git a/Mathlib/CategoryTheory/Abelian/Transfer.lean b/Mathlib/CategoryTheory/Abelian/Transfer.lean index 114d4d2a53902..bc71c7a1b37c8 100644 --- a/Mathlib/CategoryTheory/Abelian/Transfer.lean +++ b/Mathlib/CategoryTheory/Abelian/Transfer.lean @@ -3,11 +3,9 @@ Copyright (c) 2022 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ -import Mathlib.Algebra.Equiv.TransferInstance import Mathlib.CategoryTheory.Abelian.Basic import Mathlib.CategoryTheory.Adjunction.Limits -import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Kernels -import Mathlib.CategoryTheory.Preadditive.AdditiveFunctor +import Mathlib.CategoryTheory.Limits.Preserves.Shapes.AbelianImages import Mathlib.CategoryTheory.Preadditive.Transfer /-! @@ -73,99 +71,32 @@ theorem hasCokernels (i : F ⋙ G ≅ 𝟭 C) (adj : G ⊣ F) : HasCokernels C : haveI : HasCokernel (G.map (F.map f) ≫ i.hom.app _) := Limits.hasCokernel_comp_iso _ _ apply Limits.hasCokernel_epi_comp } -variable [Limits.HasCokernels C] - -/-- Auxiliary construction for `coimageIsoImage` -/ -def cokernelIso (i : F ⋙ G ≅ 𝟭 C) (adj : G ⊣ F) {X Y : C} (f : X ⟶ Y) : - G.obj (cokernel (F.map f)) ≅ cokernel f := by - -- We have to write an explicit `PreservesColimits` type here, - -- as `leftAdjointPreservesColimits` has universe variables. - have : PreservesColimits G := adj.leftAdjoint_preservesColimits - calc - G.obj (cokernel (F.map f)) ≅ cokernel (G.map (F.map f)) := - (asIso (cokernelComparison _ G)).symm - _ ≅ cokernel (i.hom.app X ≫ f ≫ i.inv.app Y) := cokernelIsoOfEq (NatIso.naturality_2 i f).symm - _ ≅ cokernel (f ≫ i.inv.app Y) := cokernelEpiComp (i.hom.app X) (f ≫ i.inv.app Y) - _ ≅ cokernel f := cokernelCompIsIso f (i.inv.app Y) - -variable [Limits.HasKernels C] [PreservesFiniteLimits G] - -/-- Auxiliary construction for `coimageIsoImage` -/ -def coimageIsoImageAux (i : F ⋙ G ≅ 𝟭 C) (adj : G ⊣ F) {X Y : C} (f : X ⟶ Y) : - kernel (G.map (cokernel.π (F.map f))) ≅ kernel (cokernel.π f) := by - have : PreservesColimits G := adj.leftAdjoint_preservesColimits - calc - kernel (G.map (cokernel.π (F.map f))) ≅ - kernel (cokernel.π (G.map (F.map f)) ≫ cokernelComparison (F.map f) G) := - kernelIsoOfEq (π_comp_cokernelComparison _ _).symm - _ ≅ kernel (cokernel.π (G.map (F.map f))) := kernelCompMono _ _ - _ ≅ kernel (cokernel.π (_ ≫ f ≫ _) ≫ (cokernelIsoOfEq _).hom) := - (kernelIsoOfEq (π_comp_cokernelIsoOfEq_hom (NatIso.naturality_2 i f)).symm) - _ ≅ kernel (cokernel.π (_ ≫ f ≫ _)) := kernelCompMono _ _ - _ ≅ kernel (cokernel.π (f ≫ i.inv.app Y) ≫ (cokernelEpiComp (i.hom.app X) _).inv) := - (kernelIsoOfEq (by simp only [cokernel.π_desc, cokernelEpiComp_inv])) - _ ≅ kernel (cokernel.π (f ≫ _)) := kernelCompMono _ _ - _ ≅ kernel (inv (i.inv.app Y) ≫ cokernel.π f ≫ (cokernelCompIsIso f (i.inv.app Y)).inv) := - (kernelIsoOfEq - (by simp only [cokernel.π_desc, cokernelCompIsIso_inv, Iso.hom_inv_id_app_assoc, - NatIso.inv_inv_app])) - _ ≅ kernel (cokernel.π f ≫ _) := kernelIsIsoComp _ _ - _ ≅ kernel (cokernel.π f) := kernelCompMono _ _ - -variable [Functor.PreservesZeroMorphisms F] - -/-- Auxiliary definition: the abelian coimage and abelian image agree. -We still need to check that this agrees with the canonical morphism. --/ -def coimageIsoImage (i : F ⋙ G ≅ 𝟭 C) (adj : G ⊣ F) {X Y : C} (f : X ⟶ Y) : - Abelian.coimage f ≅ Abelian.image f := by - have : PreservesLimits F := adj.rightAdjoint_preservesLimits - calc - Abelian.coimage f ≅ cokernel (kernel.ι f) := Iso.refl _ - _ ≅ G.obj (cokernel (F.map (kernel.ι f))) := (cokernelIso _ _ i adj _).symm - _ ≅ G.obj (cokernel (kernelComparison f F ≫ kernel.ι (F.map f))) := - (G.mapIso (cokernelIsoOfEq (by simp))) - _ ≅ G.obj (cokernel (kernel.ι (F.map f))) := G.mapIso (cokernelEpiComp _ _) - _ ≅ G.obj (Abelian.coimage (F.map f)) := Iso.refl _ - _ ≅ G.obj (Abelian.image (F.map f)) := G.mapIso (Abelian.coimageIsoImage _) - _ ≅ G.obj (kernel (cokernel.π (F.map f))) := Iso.refl _ - _ ≅ kernel (G.map (cokernel.π (F.map f))) := PreservesKernel.iso _ _ - _ ≅ kernel (cokernel.π f) := coimageIsoImageAux F G i adj f - _ ≅ Abelian.image f := Iso.refl _ - --- The account of this proof in the Stacks project omits this calculation. -theorem coimageIsoImage_hom (i : F ⋙ G ≅ 𝟭 C) (adj : G ⊣ F) {X Y : C} (f : X ⟶ Y) : - (coimageIsoImage F G i adj f).hom = Abelian.coimageImageComparison f := by - dsimp [coimageIsoImage, cokernelIso, cokernelEpiComp, cokernelCompIsIso_inv, - coimageIsoImageAux, kernelCompMono] - simpa only [← cancel_mono (Abelian.image.ι f), ← cancel_epi (Abelian.coimage.π f), - Category.assoc, Category.id_comp, cokernel.π_desc_assoc, - π_comp_cokernelIsoOfEq_inv_assoc, PreservesKernel.iso_hom, - π_comp_cokernelComparison_assoc, ← G.map_comp_assoc, kernel.lift_ι, - Abelian.coimage_image_factorisation, lift_comp_kernelIsoOfEq_hom_assoc, - kernelIsIsoComp_hom, kernel.lift_ι_assoc, kernelIsoOfEq_hom_comp_ι_assoc, - kernelComparison_comp_ι_assoc, π_comp_cokernelIsoOfEq_hom_assoc, - asIso_hom, NatIso.inv_inv_app] using NatIso.naturality_1 i f - end AbelianOfAdjunction open AbelianOfAdjunction /-- If `C` is an additive category, `D` is an abelian category, -we have `F : C ⥤ D` `G : D ⥤ C` (both preserving zero morphisms), +we have `F : C ⥤ D` `G : D ⥤ C` (with `G` preserving zero morphisms), `G` is left exact (that is, preserves finite limits), and further we have `adj : G ⊣ F` and `i : F ⋙ G ≅ 𝟭 C`, then `C` is also abelian. -/ @[stacks 03A3] def abelianOfAdjunction {C : Type u₁} [Category.{v₁} C] [Preadditive C] [HasFiniteProducts C] - {D : Type u₂} [Category.{v₂} D] [Abelian D] (F : C ⥤ D) [Functor.PreservesZeroMorphisms F] + {D : Type u₂} [Category.{v₂} D] [Abelian D] (F : C ⥤ D) (G : D ⥤ C) [Functor.PreservesZeroMorphisms G] [PreservesFiniteLimits G] (i : F ⋙ G ≅ 𝟭 C) (adj : G ⊣ F) : Abelian C := by haveI := hasKernels F G i haveI := hasCokernels F G i adj have : ∀ {X Y : C} (f : X ⟶ Y), IsIso (Abelian.coimageImageComparison f) := by intro X Y f - rw [← coimageIsoImage_hom F G i adj f] + let arrowIso : Arrow.mk (G.map (F.map f)) ≅ Arrow.mk f := + ((Functor.mapArrowFunctor _ _).mapIso i).app (Arrow.mk f) + have : PreservesColimits G := adj.leftAdjoint_preservesColimits + let iso : Arrow.mk (G.map (Abelian.coimageImageComparison (F.map f))) ≅ + Arrow.mk (Abelian.coimageImageComparison f) := + Abelian.PreservesCoimageImageComparison.iso G (F.map f) ≪≫ + Abelian.coimageImageComparisonFunctor.mapIso arrowIso + rw [Arrow.isIso_iff_isIso_of_isIso iso.inv] infer_instance apply Abelian.ofCoimageImageComparisonIsIso @@ -174,7 +105,7 @@ via a functor that preserves zero morphisms, then `C` is also abelian. -/ def abelianOfEquivalence {C : Type u₁} [Category.{v₁} C] [Preadditive C] [HasFiniteProducts C] - {D : Type u₂} [Category.{v₂} D] [Abelian D] (F : C ⥤ D) [Functor.PreservesZeroMorphisms F] + {D : Type u₂} [Category.{v₂} D] [Abelian D] (F : C ⥤ D) [F.IsEquivalence] : Abelian C := abelianOfAdjunction F F.inv F.asEquivalence.unitIso.symm F.asEquivalence.symm.toAdjunction diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Shapes/AbelianImages.lean b/Mathlib/CategoryTheory/Limits/Preserves/Shapes/AbelianImages.lean new file mode 100644 index 0000000000000..6c1057877a816 --- /dev/null +++ b/Mathlib/CategoryTheory/Limits/Preserves/Shapes/AbelianImages.lean @@ -0,0 +1,95 @@ +/- +Copyright (c) 2025 Markus Himmel. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Markus Himmel +-/ +import Mathlib.CategoryTheory.Abelian.Images +import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Kernels + +/-! +# Preservation of coimage-image comparisons + +If a functor preserves kernels and cokernels, then it preserves abelian images, abelian coimages +and coimage-image comparisons. +-/ + +noncomputable section + +universe v₁ v₂ u₁ u₂ + +open CategoryTheory Limits + +namespace CategoryTheory.Abelian + +variable {C : Type u₁} [Category.{v₁} C] [HasZeroMorphisms C] [HasKernels C] [HasCokernels C] +variable {D : Type u₂} [Category.{v₂} D] [HasZeroMorphisms D] [HasKernels D] [HasCokernels D] +variable (F : C ⥤ D) [F.PreservesZeroMorphisms] [PreservesLimitsOfShape WalkingParallelPair F] + [PreservesColimitsOfShape WalkingParallelPair F] +variable {X Y : C} (f : X ⟶ Y) + +/-- If a functor preserves kernels and cokernels, it preserves abelian images. -/ +def PreservesImage.iso : F.obj (Abelian.image f) ≅ Abelian.image (F.map f) := + PreservesKernel.iso F _ ≪≫ kernel.mapIso _ _ (Iso.refl _) (PreservesCokernel.iso F _) (by simp) + +@[reassoc (attr := simp)] +theorem PreservesImage.iso_hom_ι : + (PreservesImage.iso F f).hom ≫ Abelian.image.ι (F.map f) = F.map (Abelian.image.ι f) := by + simp [iso] + +@[reassoc (attr := simp)] +theorem PreservesImage.factorThruImage_iso_hom : + F.map (Abelian.factorThruImage f) ≫ (PreservesImage.iso F f).hom = + Abelian.factorThruImage (F.map f) := by + ext; simp [iso] + +@[reassoc (attr := simp)] +theorem PreservesImage.iso_inv_ι : + (PreservesImage.iso F f).inv ≫ F.map (Abelian.image.ι f) = Abelian.image.ι (F.map f) := by + simp [iso] + +@[reassoc (attr := simp)] +theorem PreservesImage.factorThruImage_iso_inv : + Abelian.factorThruImage (F.map f) ≫ (PreservesImage.iso F f).inv = + F.map (Abelian.factorThruImage f) := by + simp [Iso.comp_inv_eq] + +/-- If a functor preserves kernels and cokernels, it preserves abelian coimages. -/ +def PreservesCoimage.iso : F.obj (Abelian.coimage f) ≅ Abelian.coimage (F.map f) := + PreservesCokernel.iso F _ ≪≫ cokernel.mapIso _ _ (PreservesKernel.iso F _) (Iso.refl _) (by simp) + +@[reassoc (attr := simp)] +theorem PreservesCoimage.iso_hom_π : + F.map (Abelian.coimage.π f) ≫ (PreservesCoimage.iso F f).hom = Abelian.coimage.π (F.map f) := by + simp [iso] + +@[reassoc (attr := simp)] +theorem PreservesCoimage.factorThruCoimage_iso_inv : + (PreservesCoimage.iso F f).inv ≫ F.map (Abelian.factorThruCoimage f) = + Abelian.factorThruCoimage (F.map f) := by + ext; simp [iso] + +@[reassoc (attr := simp)] +theorem PreservesCoimage.factorThruCoimage_iso_hom : + (PreservesCoimage.iso F f).hom ≫ Abelian.factorThruCoimage (F.map f) = + F.map (Abelian.factorThruCoimage f) := by + simp [← Iso.eq_inv_comp] + +@[reassoc (attr := simp)] +theorem PreservesCoimage.iso_inv_π : + Abelian.coimage.π (F.map f) ≫ (PreservesCoimage.iso F f).inv = F.map (Abelian.coimage.π f) := by + simp [Iso.comp_inv_eq] + +theorem PreservesCoimage.hom_coimageImageComparison : + (PreservesCoimage.iso F f).hom ≫ coimageImageComparison (F.map f) = + F.map (coimageImageComparison f) ≫ (PreservesImage.iso F f).hom := by + simp [← Functor.map_comp, ← Iso.eq_inv_comp, ← cancel_epi (Abelian.coimage.π (F.map f)), + ← cancel_mono (Abelian.image.ι (F.map f))] + +/-- If a functor preserves kernels and cokernels, it perserves coimage-image comparisons. -/ +@[simps!] +def PreservesCoimageImageComparison.iso : + Arrow.mk (F.map (coimageImageComparison f)) ≅ Arrow.mk (coimageImageComparison (F.map f)) := + Arrow.isoMk' _ _ (PreservesCoimage.iso F f) (PreservesImage.iso F f) + (PreservesCoimage.hom_coimageImageComparison F f) + +end CategoryTheory.Abelian diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Kernels.lean b/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Kernels.lean index 034c5e96b668a..0bf8b6d24a4e0 100644 --- a/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Kernels.lean +++ b/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Kernels.lean @@ -128,6 +128,12 @@ an isomorphism. def PreservesKernel.iso : G.obj (kernel f) ≅ kernel (G.map f) := IsLimit.conePointUniqueUpToIso (isLimitOfHasKernelOfPreservesLimit G f) (limit.isLimit _) +@[reassoc (attr := simp)] +theorem PreservesKernel.iso_inv_ι : + (PreservesKernel.iso G f).inv ≫ G.map (kernel.ι f) = kernel.ι (G.map f) := + IsLimit.conePointUniqueUpToIso_inv_comp (isLimitOfHasKernelOfPreservesLimit G f) + (limit.isLimit _) (WalkingParallelPair.zero) + @[simp] theorem PreservesKernel.iso_hom : (PreservesKernel.iso G f).hom = kernelComparison f G := by rw [← cancel_mono (kernel.ι _)] @@ -251,6 +257,11 @@ def PreservesCokernel.iso : G.obj (cokernel f) ≅ cokernel (G.map f) := IsColimit.coconePointUniqueUpToIso (isColimitOfHasCokernelOfPreservesColimit G f) (colimit.isColimit _) +@[reassoc (attr := simp)] +theorem PreservesCokernel.π_iso_hom : G.map (cokernel.π f) ≫ (iso G f).hom = cokernel.π (G.map f) := + IsColimit.comp_coconePointUniqueUpToIso_hom (isColimitOfHasCokernelOfPreservesColimit G f) + (colimit.isColimit _) (WalkingParallelPair.one) + @[simp] theorem PreservesCokernel.iso_inv : (PreservesCokernel.iso G f).inv = cokernelComparison f G := by rw [← cancel_epi (cokernel.π _)] From 5c57f97198cbc1377e262ee88fa359e3670e6822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Sun, 2 Feb 2025 20:52:02 +0000 Subject: [PATCH 012/103] feat(CategoryTheory/Limits/Shapes/Preorder): principal segments (#21055) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the study of well order continuous functors, we now use the initial/principal segment API from order theory. Co-authored-by: Joël Riou <37772949+joelriou@users.noreply.github.com> --- Mathlib.lean | 2 + .../Shapes/Preorder/HasIterationOfShape.lean | 55 +++++++++++- .../Limits/Shapes/Preorder/PrincipalSeg.lean | 33 ++++++++ .../Shapes/Preorder/WellOrderContinuous.lean | 58 ++++++------- Mathlib/Order/Interval/Set/InitialSeg.lean | 83 +++++++++++++++++++ 5 files changed, 199 insertions(+), 32 deletions(-) create mode 100644 Mathlib/CategoryTheory/Limits/Shapes/Preorder/PrincipalSeg.lean create mode 100644 Mathlib/Order/Interval/Set/InitialSeg.lean diff --git a/Mathlib.lean b/Mathlib.lean index e59346f0e63db..dcd281bb7adb8 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2001,6 +2001,7 @@ import Mathlib.CategoryTheory.Limits.Shapes.NormalMono.Equalizers import Mathlib.CategoryTheory.Limits.Shapes.PiProd import Mathlib.CategoryTheory.Limits.Shapes.Preorder.Basic import Mathlib.CategoryTheory.Limits.Shapes.Preorder.HasIterationOfShape +import Mathlib.CategoryTheory.Limits.Shapes.Preorder.PrincipalSeg import Mathlib.CategoryTheory.Limits.Shapes.Preorder.WellOrderContinuous import Mathlib.CategoryTheory.Limits.Shapes.Products import Mathlib.CategoryTheory.Limits.Shapes.Pullback.Assoc @@ -4277,6 +4278,7 @@ import Mathlib.Order.Interval.Set.Defs import Mathlib.Order.Interval.Set.Disjoint import Mathlib.Order.Interval.Set.Image import Mathlib.Order.Interval.Set.Infinite +import Mathlib.Order.Interval.Set.InitialSeg import Mathlib.Order.Interval.Set.IsoIoo import Mathlib.Order.Interval.Set.Monotone import Mathlib.Order.Interval.Set.OrdConnected diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Preorder/HasIterationOfShape.lean b/Mathlib/CategoryTheory/Limits/Shapes/Preorder/HasIterationOfShape.lean index b255543b53a02..3992e66f2c72a 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Preorder/HasIterationOfShape.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Preorder/HasIterationOfShape.lean @@ -3,9 +3,11 @@ Copyright (c) 2024 Joël Riou. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Joël Riou -/ -import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic import Mathlib.CategoryTheory.Limits.Comma +import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic +import Mathlib.CategoryTheory.Limits.Shapes.Preorder.Basic import Mathlib.Order.SuccPred.Limit +import Mathlib.Order.Interval.Set.InitialSeg /-! # An assumption for constructions by transfinite induction @@ -20,12 +22,12 @@ universe w v v' u u' namespace CategoryTheory.Limits -variable (J : Type w) [Preorder J] (C : Type u) [Category.{v} C] +variable (J : Type w) [LinearOrder J] (C : Type u) [Category.{v} C] (K : Type u') [Category.{v'} K] -/-- A category `C` has iterations of shape a preordered type `J` +/-- A category `C` has iterations of shape a linearly ordered type `J` when certain specific shapes of colimits exists: colimits indexed by `J`, -and by `Set.Iio j` for `j : J`. -/ +and by `Set.Iio j` for `j : J`. -/ class HasIterationOfShape : Prop where hasColimitsOfShape_of_isSuccLimit (j : J) (hj : Order.IsSuccLimit j) : HasColimitsOfShape (Set.Iio j) C := by infer_instance @@ -41,6 +43,13 @@ lemma hasColimitsOfShape_of_isSuccLimit (j : J) HasColimitsOfShape (Set.Iio j) C := HasIterationOfShape.hasColimitsOfShape_of_isSuccLimit j hj +variable {J} in +lemma hasColimitsOfShape_of_isSuccLimit' + {α : Type*} [PartialOrder α] (h : α + subst hi₀ + exact (hi.not_lt (s.lt_top (Classical.arbitrary _))).elim + | hs i hi _ => + obtain ⟨a, rfl⟩ := (s.mem_range_iff_rel (b := i)).2 (by + simpa only [← hi₀] using Order.lt_succ_of_not_isMax hi) + have : OrderTop α := + { top := a + le_top b := by + rw [← s.le_iff_le] + exact Order.le_of_lt_succ (by simpa only [hi₀] using s.lt_top b) } + infer_instance + | hl i hi => + subst hi₀ + exact hasColimitsOfShape_of_isSuccLimit' C s hi + +lemma hasIterationOfShape_of_initialSeg {α : Type*} [LinearOrder α] + (h : α ≤i J) [Nonempty α] : + HasIterationOfShape α C where + hasColimitsOfShape := hasColimitsOfShape_of_initialSeg C h + hasColimitsOfShape_of_isSuccLimit j hj := by + have : Nonempty (Set.Iio j) := by + obtain ⟨a, ha⟩ := not_isMin_iff.1 hj.1 + exact ⟨⟨a, ha⟩⟩ + exact hasColimitsOfShape_of_initialSeg _ + (InitialSeg.trans (Set.principalSegIio j) h) + end CategoryTheory.Limits diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Preorder/PrincipalSeg.lean b/Mathlib/CategoryTheory/Limits/Shapes/Preorder/PrincipalSeg.lean new file mode 100644 index 0000000000000..bc73cdfb62e8d --- /dev/null +++ b/Mathlib/CategoryTheory/Limits/Shapes/Preorder/PrincipalSeg.lean @@ -0,0 +1,33 @@ +/- +Copyright (c) 2025 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ +import Mathlib.Order.InitialSeg +import Mathlib.CategoryTheory.Category.Preorder +import Mathlib.CategoryTheory.Limits.Cones + +/-! +# Cocones associated to principal segments + +If `f : α Date: Sun, 2 Feb 2025 21:08:38 +0000 Subject: [PATCH 013/103] =?UTF-8?q?feat:=20`vectorSpan=20k=20(v=20+?= =?UTF-8?q?=E1=B5=A5=20s)=20=3D=20vectorSpan=20k=20s`=20(#21305)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From PFR --- Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean b/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean index f3eee53f08930..8556b9f1edbc7 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean @@ -90,6 +90,9 @@ theorem vsub_mem_vectorSpan {s : Set P} {p1 p2 : P} (hp1 : p1 ∈ s) (hp2 : p2 p1 -ᵥ p2 ∈ vectorSpan k s := vsub_set_subset_vectorSpan k s (vsub_mem_vsub hp1 hp2) +@[simp] lemma vectorSpan_vadd (s : Set P) (v : V) : vectorSpan k (v +ᵥ s) = vectorSpan k s := by + simp [vectorSpan] + /-- The points in the affine span of a (possibly empty) set of points. Use `affineSpan` instead to get an `AffineSubspace k P`. -/ def spanPoints (s : Set P) : Set P := From 8926633ff2f80bc096a4f352ef0e77bb723efb7a Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Sun, 2 Feb 2025 22:26:17 +0000 Subject: [PATCH 014/103] chore: tidy various files (#20225) --- Mathlib/Algebra/BigOperators/Associated.lean | 2 +- Mathlib/Algebra/Divisibility/Units.lean | 6 ++--- Mathlib/Algebra/Group/WithOne/Basic.lean | 3 --- Mathlib/Algebra/GroupWithZero/Basic.lean | 2 +- .../Homology/DerivedCategory/Ext/Basic.lean | 2 +- .../Algebra/Module/LocalizedModule/Basic.lean | 2 +- Mathlib/AlgebraicGeometry/OpenImmersion.lean | 4 ++-- Mathlib/Analysis/Analytic/Composition.lean | 3 ++- Mathlib/Analysis/Calculus/FDeriv/Prod.lean | 2 +- .../Analysis/SpecialFunctions/Log/Deriv.lean | 3 +-- .../CategoryTheory/Abelian/Refinements.lean | 2 +- .../SimpleGraph/Connectivity/Subgraph.lean | 4 ++-- Mathlib/Combinatorics/SimpleGraph/Walk.lean | 20 ++++++++-------- Mathlib/Data/Nat/Choose/Lucas.lean | 3 +-- Mathlib/Data/Set/Image.lean | 2 +- Mathlib/Data/Setoid/Basic.lean | 23 +++++++++---------- Mathlib/Geometry/Manifold/ChartedSpace.lean | 22 ++++++++---------- .../Manifold/MFDeriv/UniqueDifferential.lean | 2 +- .../Projectivization/Cardinality.lean | 9 +++----- .../Decomposition/RadonNikodym.lean | 2 +- .../MeasureTheory/Function/SimpleFunc.lean | 8 ++----- .../MeasureTheory/Measure/Haar/Unique.lean | 3 +-- Mathlib/MeasureTheory/Measure/Hausdorff.lean | 2 +- .../VectorMeasure/WithDensity.lean | 10 ++++---- .../NumberField/EquivReindex.lean | 6 ++--- Mathlib/NumberTheory/NumberField/House.lean | 2 +- Mathlib/Probability/Density.lean | 6 ++--- .../Probability/Distributions/Gaussian.lean | 4 ++-- Mathlib/RingTheory/FiniteLength.lean | 8 ++++--- .../RingTheory/Ideal/Quotient/Operations.lean | 4 ++-- Mathlib/RingTheory/LaurentSeries.lean | 11 ++------- Mathlib/RingTheory/Nilpotent/Defs.lean | 14 +++++------ .../RingHom/FinitePresentation.lean | 4 ++-- Mathlib/RingTheory/Spectrum/Prime/Module.lean | 3 +-- Mathlib/RingTheory/Support.lean | 4 ++-- Mathlib/Topology/MetricSpace/HolderNorm.lean | 6 ++--- .../Topology/Order/UpperLowerSetTopology.lean | 6 ++--- 37 files changed, 98 insertions(+), 121 deletions(-) diff --git a/Mathlib/Algebra/BigOperators/Associated.lean b/Mathlib/Algebra/BigOperators/Associated.lean index f6754712f5eea..2178d8c747072 100644 --- a/Mathlib/Algebra/BigOperators/Associated.lean +++ b/Mathlib/Algebra/BigOperators/Associated.lean @@ -188,7 +188,7 @@ variable [CancelCommMonoidWithZero α] theorem exists_mem_multiset_le_of_prime {s : Multiset (Associates α)} {p : Associates α} (hp : Prime p) : p ≤ s.prod → ∃ a ∈ s, p ≤ a := - Multiset.induction_on s (fun ⟨_, Eq⟩ => (hp.ne_one (mul_eq_one.1 Eq.symm).1).elim) + Multiset.induction_on s (fun ⟨_, eq⟩ => (hp.ne_one (mul_eq_one.1 eq.symm).1).elim) fun a s ih h => have : p ≤ a * s.prod := by simpa using h match Prime.le_or_le hp this with diff --git a/Mathlib/Algebra/Divisibility/Units.lean b/Mathlib/Algebra/Divisibility/Units.lean index 4afd288068460..7621849857a01 100644 --- a/Mathlib/Algebra/Divisibility/Units.lean +++ b/Mathlib/Algebra/Divisibility/Units.lean @@ -33,12 +33,12 @@ theorem coe_dvd : ↑u ∣ a := /-- In a monoid, an element `a` divides an element `b` iff `a` divides all associates of `b`. -/ theorem dvd_mul_right : a ∣ b * u ↔ a ∣ b := - Iff.intro (fun ⟨c, Eq⟩ ↦ ⟨c * ↑u⁻¹, by rw [← mul_assoc, ← Eq, Units.mul_inv_cancel_right]⟩) - fun ⟨_, Eq⟩ ↦ Eq.symm ▸ (_root_.dvd_mul_right _ _).mul_right _ + Iff.intro (fun ⟨c, eq⟩ ↦ ⟨c * ↑u⁻¹, by rw [← mul_assoc, ← eq, Units.mul_inv_cancel_right]⟩) + fun ⟨_, eq⟩ ↦ eq.symm ▸ (_root_.dvd_mul_right _ _).mul_right _ /-- In a monoid, an element `a` divides an element `b` iff all associates of `a` divide `b`. -/ theorem mul_right_dvd : a * u ∣ b ↔ a ∣ b := - Iff.intro (fun ⟨c, Eq⟩ => ⟨↑u * c, Eq.trans (mul_assoc _ _ _)⟩) fun h => + Iff.intro (fun ⟨c, eq⟩ => ⟨↑u * c, eq.trans (mul_assoc _ _ _)⟩) fun h => dvd_trans (Dvd.intro (↑u⁻¹) (by rw [mul_assoc, u.mul_inv, mul_one])) h end Monoid diff --git a/Mathlib/Algebra/Group/WithOne/Basic.lean b/Mathlib/Algebra/Group/WithOne/Basic.lean index 5382fd1d0651a..2f1a04997c4ff 100644 --- a/Mathlib/Algebra/Group/WithOne/Basic.lean +++ b/Mathlib/Algebra/Group/WithOne/Basic.lean @@ -65,7 +65,6 @@ def lift : (α →ₙ* β) ≃ (WithOne α →* β) where invFun F := F.toMulHom.comp coeMulHom left_inv _ := MulHom.ext fun _ => rfl right_inv F := MonoidHom.ext fun x => WithOne.cases_on x F.map_one.symm (fun _ => rfl) --- Porting note: the above proofs were broken because they were parenthesized wrong by mathport? variable (f : α →ₙ* β) @@ -119,8 +118,6 @@ def _root_.MulEquiv.withOneCongr (e : α ≃* β) : WithOne α ≃* WithOne β : left_inv := (by induction · <;> simp) right_inv := (by induction · <;> simp) } --- Porting note: for this declaration and the two below I added the `to_additive` attribute because --- it seemed to be missing from mathlib3 @[to_additive (attr := simp)] theorem _root_.MulEquiv.withOneCongr_refl : (MulEquiv.refl α).withOneCongr = MulEquiv.refl _ := MulEquiv.toMonoidHom_injective map_id diff --git a/Mathlib/Algebra/GroupWithZero/Basic.lean b/Mathlib/Algebra/GroupWithZero/Basic.lean index 1222fa35f4af0..936f7cd3c7d9e 100644 --- a/Mathlib/Algebra/GroupWithZero/Basic.lean +++ b/Mathlib/Algebra/GroupWithZero/Basic.lean @@ -149,7 +149,7 @@ lemma zero_pow_eq (n : ℕ) : (0 : M₀) ^ n = if n = 0 then 1 else 0 := by lemma zero_pow_eq_one₀ [Nontrivial M₀] : (0 : M₀) ^ n = 1 ↔ n = 0 := by rw [zero_pow_eq, one_ne_zero.ite_eq_left_iff] -lemma pow_eq_zero_of_le : ∀ {m n} (_ : m ≤ n) (_ : a ^ m = 0), a ^ n = 0 +lemma pow_eq_zero_of_le : ∀ {m n}, m ≤ n → a ^ m = 0 → a ^ n = 0 | _, _, Nat.le.refl, ha => ha | _, _, Nat.le.step hmn, ha => by rw [pow_succ, pow_eq_zero_of_le hmn ha, zero_mul] diff --git a/Mathlib/Algebra/Homology/DerivedCategory/Ext/Basic.lean b/Mathlib/Algebra/Homology/DerivedCategory/Ext/Basic.lean index 4aae573cb738d..4baf8de024530 100644 --- a/Mathlib/Algebra/Homology/DerivedCategory/Ext/Basic.lean +++ b/Mathlib/Algebra/Homology/DerivedCategory/Ext/Basic.lean @@ -364,7 +364,7 @@ noncomputable def extFunctor (n : ℕ) : Cᵒᵖ ⥤ C ⥤ AddCommGrp.{w} where symm apply Ext.comp_assoc all_goals omega } - map_comp {X₁ X₂ X₃} f f' := by + map_comp {X₁ X₂ X₃} f f' := by ext Y α dsimp rw [← Ext.mk₀_comp_mk₀] diff --git a/Mathlib/Algebra/Module/LocalizedModule/Basic.lean b/Mathlib/Algebra/Module/LocalizedModule/Basic.lean index 4a3b1f34b2439..89b681b6bf0d2 100644 --- a/Mathlib/Algebra/Module/LocalizedModule/Basic.lean +++ b/Mathlib/Algebra/Module/LocalizedModule/Basic.lean @@ -1270,7 +1270,7 @@ lemma LocalizedModule.subsingleton_iff_ker_eq_top {S : Submonoid R} : rw [← top_le_iff] refine ⟨fun H m _ ↦ Subsingleton.elim _ _, fun H ↦ (subsingleton_iff_forall_eq 0).mpr fun x ↦ ?_⟩ obtain ⟨⟨x, s⟩, rfl⟩ := IsLocalizedModule.mk'_surjective S (LocalizedModule.mkLinearMap S M) x - simpa using @H x trivial + simpa using @H x Submodule.mem_top lemma LocalizedModule.subsingleton_iff {S : Submonoid R} : Subsingleton (LocalizedModule S M) ↔ ∀ m : M, ∃ r ∈ S, r • m = 0 := by diff --git a/Mathlib/AlgebraicGeometry/OpenImmersion.lean b/Mathlib/AlgebraicGeometry/OpenImmersion.lean index f78bd0243cceb..591a430a5e75b 100644 --- a/Mathlib/AlgebraicGeometry/OpenImmersion.lean +++ b/Mathlib/AlgebraicGeometry/OpenImmersion.lean @@ -397,11 +397,11 @@ lemma of_comp {X Y Z : Scheme.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) [IsOpenImmersion theorem iff_stalk_iso {X Y : Scheme.{u}} (f : X ⟶ Y) : IsOpenImmersion f ↔ IsOpenEmbedding f.base ∧ ∀ x, IsIso (f.stalkMap x) := ⟨fun H => ⟨H.1, fun x ↦ inferInstanceAs <| IsIso (f.toPshHom.stalkMap x)⟩, - fun ⟨h₁, h₂⟩ => @IsOpenImmersion.of_stalk_iso _ _ f h₁ h₂⟩ + fun ⟨h, _⟩ => IsOpenImmersion.of_stalk_iso f h⟩ theorem _root_.AlgebraicGeometry.isIso_iff_isOpenImmersion {X Y : Scheme.{u}} (f : X ⟶ Y) : IsIso f ↔ IsOpenImmersion f ∧ Epi f.base := - ⟨fun _ => ⟨inferInstance, inferInstance⟩, fun ⟨h₁, h₂⟩ => @IsOpenImmersion.to_iso _ _ f h₁ h₂⟩ + ⟨fun _ => ⟨inferInstance, inferInstance⟩, fun ⟨_, _⟩ => IsOpenImmersion.to_iso f⟩ theorem _root_.AlgebraicGeometry.isIso_iff_stalk_iso {X Y : Scheme.{u}} (f : X ⟶ Y) : IsIso f ↔ IsIso f.base ∧ ∀ x, IsIso (f.stalkMap x) := by diff --git a/Mathlib/Analysis/Analytic/Composition.lean b/Mathlib/Analysis/Analytic/Composition.lean index 6844e170f22e9..dea028ad9f747 100644 --- a/Mathlib/Analysis/Analytic/Composition.lean +++ b/Mathlib/Analysis/Analytic/Composition.lean @@ -1062,7 +1062,8 @@ theorem length_sigmaCompositionAux (a : Composition n) (b : Composition a.length Composition.length (Composition.sigmaCompositionAux a b ⟨i, (length_gather a b).symm ▸ i.2⟩) = Composition.blocksFun b i := show List.length ((splitWrtComposition a.blocks b)[i.1]) = blocksFun b i by - rw [getElem_map_rev List.length, getElem_of_eq (map_length_splitWrtComposition _ _)]; rfl + rw [getElem_map_rev List.length, getElem_of_eq (map_length_splitWrtComposition _ _), blocksFun, + get_eq_getElem] theorem blocksFun_sigmaCompositionAux (a : Composition n) (b : Composition a.length) (i : Fin b.length) (j : Fin (blocksFun b i)) : diff --git a/Mathlib/Analysis/Calculus/FDeriv/Prod.lean b/Mathlib/Analysis/Calculus/FDeriv/Prod.lean index 892ed8c6dfa95..1951867327661 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Prod.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Prod.lean @@ -352,7 +352,7 @@ theorem hasStrictFDerivAt_apply (i : ι) (f : ∀ i, F' i) : let id' := ContinuousLinearMap.id 𝕜 (∀ i, F' i) have h := ((hasStrictFDerivAt_pi' (Φ := fun (f : ∀ i, F' i) (i' : ι) => f i') (Φ' := id') (x := f))).1 - have h' : comp (proj i) id' = proj i := by rfl + have h' : comp (proj i) id' = proj i := by ext; simp [id'] rw [← h']; apply h; apply hasStrictFDerivAt_id @[simp 1100] -- Porting note: increased priority to make lint happy diff --git a/Mathlib/Analysis/SpecialFunctions/Log/Deriv.lean b/Mathlib/Analysis/SpecialFunctions/Log/Deriv.lean index 403dd4f36d6f9..95dd9afb25e88 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/Deriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/Deriv.lean @@ -127,8 +127,7 @@ theorem deriv.log (hf : DifferentiableAt ℝ f x) (hx : f x ≠ 0) : `f x ≠ 0`. -/ lemma Real.deriv_log_comp_eq_logDeriv {f : ℝ → ℝ} {x : ℝ} (h₁ : DifferentiableAt ℝ f x) (h₂ : f x ≠ 0) : deriv (log ∘ f) x = logDeriv f x := by - simp only [ne_eq, logDeriv, Pi.div_apply, ← deriv.log h₁ h₂] - rfl + simp only [ne_eq, logDeriv, Pi.div_apply, ← deriv.log h₁ h₂, Function.comp_def] end deriv diff --git a/Mathlib/CategoryTheory/Abelian/Refinements.lean b/Mathlib/CategoryTheory/Abelian/Refinements.lean index 75582a7bcc024..9b37b8436a3d6 100644 --- a/Mathlib/CategoryTheory/Abelian/Refinements.lean +++ b/Mathlib/CategoryTheory/Abelian/Refinements.lean @@ -26,7 +26,7 @@ In this file, the basic result is `epi_iff_surjective_up_to_refinements` which states that `f : X ⟶ Y` is a morphism in an abelian category, then it is an epimorphism if and only if for all `y : A ⟶ Y`, there exists an epimorphism `π : A' ⟶ A` and `x : A' ⟶ X` such -that `π ≫ y = x ≫ f`. In order words, if we allow a precomposition +that `π ≫ y = x ≫ f`. In other words, if we allow a precomposition with an epimorphism, we may lift a morphism to `Y` to a morphism to `X`. Following unpublished notes by George Bergman, we shall say that the precomposition by an epimorphism `π ≫ y` is a refinement of `y`. Then, diff --git a/Mathlib/Combinatorics/SimpleGraph/Connectivity/Subgraph.lean b/Mathlib/Combinatorics/SimpleGraph/Connectivity/Subgraph.lean index 352990904c131..c5b3355cd5192 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Connectivity/Subgraph.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Connectivity/Subgraph.lean @@ -191,9 +191,9 @@ theorem toSubgraph_adj_getVert {u v} (w : G.Walk u v) {i : ℕ} (hi : i < w.leng | cons hxy i' ih => cases i · simp only [Walk.toSubgraph, Walk.getVert_zero, zero_add, getVert_cons_succ, Subgraph.sup_adj, - subgraphOfAdj_adj, true_or] + subgraphOfAdj_adj, true_or] · simp only [Walk.toSubgraph, getVert_cons_succ, Subgraph.sup_adj, subgraphOfAdj_adj, Sym2.eq, - Sym2.rel_iff', Prod.mk.injEq, Prod.swap_prod_mk] + Sym2.rel_iff', Prod.mk.injEq, Prod.swap_prod_mk] right exact ih (Nat.succ_lt_succ_iff.mp hi) diff --git a/Mathlib/Combinatorics/SimpleGraph/Walk.lean b/Mathlib/Combinatorics/SimpleGraph/Walk.lean index 86e1e71cf4a52..947d13e1ebf70 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Walk.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Walk.lean @@ -1149,25 +1149,23 @@ theorem mem_support_iff_exists_getVert {u v w : V} {p : G.Walk v w} : Nat.le_add_right, and_self] · rintro ⟨n, hn⟩ rw [SimpleGraph.Walk.mem_support_iff] - by_cases h0 : n = 0 - · rw [h0, getVert_zero] at hn + cases n with + | zero => + rw [getVert_zero] at hn left exact hn.1.symm - · right + | succ n => + right have hnp : ¬ p.Nil := by rw [nil_iff_length_eq] omega - rw [← support_tail_of_not_nil _ hnp] - rw [mem_support_iff_exists_getVert] - use n - 1 - simp only [Nat.sub_le_iff_le_add] - rw [getVert_tail, length_tail_add_one hnp] - have : (n - 1 + 1) = n := by omega - rwa [this] + rw [← support_tail_of_not_nil _ hnp, mem_support_iff_exists_getVert] + use n + rwa [getVert_tail, ← Nat.add_one_le_add_one_iff, length_tail_add_one hnp] termination_by p.length decreasing_by · simp_wf - rw [@Nat.lt_iff_add_one_le] + rw [Nat.lt_iff_add_one_le] rw [length_tail_add_one hnp] end Walk diff --git a/Mathlib/Data/Nat/Choose/Lucas.lean b/Mathlib/Data/Nat/Choose/Lucas.lean index 8b1f848ab5ca8..937cba89b9763 100644 --- a/Mathlib/Data/Nat/Choose/Lucas.lean +++ b/Mathlib/Data/Nat/Choose/Lucas.lean @@ -77,8 +77,7 @@ theorem choose_modEq_choose_mul_prod_range_choose (a : ℕ) : rw [prod_range_succ, cast_mul, ← mul_assoc, mul_right_comm] gcongr apply choose_modEq_choose_mod_mul_choose_div.trans - simp_rw [pow_succ, Nat.div_div_eq_div_mul, mul_comm] - rfl + simp_rw [pow_succ, Nat.div_div_eq_div_mul, mul_comm, Int.ModEq.refl] /-- **Lucas's Theorem**: For primes `p`, `choose n k` is congruent to the product of `choose (⌊n / p ^ i⌋ % p) (⌊k / p ^ i⌋ % p)` over `i` modulo `p`. -/ diff --git a/Mathlib/Data/Set/Image.lean b/Mathlib/Data/Set/Image.lean index 3a93bcdb1c839..300c6423b58e8 100644 --- a/Mathlib/Data/Set/Image.lean +++ b/Mathlib/Data/Set/Image.lean @@ -689,7 +689,7 @@ theorem exists_subset_range_and_iff {f : α → β} {p : Set β → Prop} : @[simp] theorem forall_subset_range_iff {f : α → β} {p : Set β → Prop} : (∀ s, s ⊆ range f → p s) ↔ ∀ s, p (f '' s) := by - rw [← forall_mem_range, range_image]; rfl + rw [← forall_mem_range, range_image]; simp only [mem_powerset_iff] @[simp] theorem preimage_subset_preimage_iff {s t : Set α} {f : β → α} (hs : s ⊆ range f) : diff --git a/Mathlib/Data/Setoid/Basic.lean b/Mathlib/Data/Setoid/Basic.lean index dac555b84fad5..0759b4e495bcf 100644 --- a/Mathlib/Data/Setoid/Basic.lean +++ b/Mathlib/Data/Setoid/Basic.lean @@ -136,13 +136,13 @@ equivalence relations. -/ @[simps] def prodQuotientEquiv (r : Setoid α) (s : Setoid β) : Quotient r × Quotient s ≃ Quotient (r.prod s) where - toFun := fun (x, y) ↦ Quotient.map₂ Prod.mk (fun _ _ hx _ _ hy ↦ ⟨hx, hy⟩) x y - invFun := fun q ↦ Quotient.liftOn' q (fun xy ↦ (Quotient.mk'' xy.1, Quotient.mk'' xy.2)) + toFun | (x, y) => Quotient.map₂ Prod.mk (fun _ _ hx _ _ hy ↦ ⟨hx, hy⟩) x y + invFun q := Quotient.liftOn' q (fun xy ↦ (Quotient.mk'' xy.1, Quotient.mk'' xy.2)) fun x y hxy ↦ Prod.ext (by simpa using hxy.1) (by simpa using hxy.2) - left_inv := fun q ↦ by + left_inv q := by rcases q with ⟨qa, qb⟩ exact Quotient.inductionOn₂' qa qb fun _ _ ↦ rfl - right_inv := fun q ↦ by + right_inv q := by simp only refine Quotient.inductionOn' q fun _ ↦ rfl @@ -151,14 +151,14 @@ equivalence relations. -/ @[simps] noncomputable def piQuotientEquiv {ι : Sort*} {α : ι → Sort*} (r : ∀ i, Setoid (α i)) : (∀ i, Quotient (r i)) ≃ Quotient (@piSetoid _ _ r) where - toFun := fun x ↦ Quotient.mk'' fun i ↦ (x i).out - invFun := fun q ↦ Quotient.liftOn' q (fun x i ↦ Quotient.mk'' (x i)) fun x y hxy ↦ by + toFun x := Quotient.mk'' fun i ↦ (x i).out + invFun q := Quotient.liftOn' q (fun x i ↦ Quotient.mk'' (x i)) fun x y hxy ↦ by ext i simpa using hxy i - left_inv := fun q ↦ by + left_inv q := by ext i simp - right_inv := fun q ↦ by + right_inv q := by refine Quotient.inductionOn' q fun _ ↦ ?_ simp only [Quotient.liftOn'_mk'', Quotient.eq''] intro i @@ -346,8 +346,7 @@ def liftEquiv (r : Setoid α) : { f : α → β // r ≤ ker f } ≃ (Quotient r theorem lift_unique {r : Setoid α} {f : α → β} (H : r ≤ ker f) (g : Quotient r → β) (Hg : f = g ∘ Quotient.mk'') : Quotient.lift f H = g := by ext ⟨x⟩ - erw [Quotient.lift_mk f H, Hg] - rfl + rw [← Quotient.mk, Quotient.lift_mk f H, Hg, Function.comp_apply, Quotient.mk''_eq_mk] /-- Given a map f from α to β, the natural map from the quotient of α by the kernel of f is injective. -/ @@ -464,8 +463,8 @@ def correspondence (r : Setoid α) : { s // r ≤ s } ≃o Setoid (Quotient r) w toFun s := ⟨Quotient.lift₂ s.1.1 fun _ _ _ _ h₁ h₂ ↦ Eq.propIntro (fun h ↦ s.1.trans' (s.1.trans' (s.1.symm' (s.2 h₁)) h) (s.2 h₂)) (fun h ↦ s.1.trans' (s.1.trans' (s.2 h₁) h) (s.1.symm' (s.2 h₂))), - ⟨Quotient.ind s.1.2.1, @fun x y ↦ Quotient.inductionOn₂ x y fun _ _ ↦ s.1.2.2, - @fun x y z ↦ Quotient.inductionOn₃ x y z fun _ _ _ ↦ s.1.2.3⟩⟩ + ⟨Quotient.ind s.1.2.1, fun {x y} ↦ Quotient.inductionOn₂ x y fun _ _ ↦ s.1.2.2, + fun {x y z} ↦ Quotient.inductionOn₃ x y z fun _ _ _ ↦ s.1.2.3⟩⟩ invFun s := ⟨comap Quotient.mk' s, fun x y h => by rw [comap_rel, Quotient.eq'.2 h]⟩ left_inv _ := rfl right_inv _ := ext fun x y ↦ Quotient.inductionOn₂ x y fun _ _ ↦ Iff.rfl diff --git a/Mathlib/Geometry/Manifold/ChartedSpace.lean b/Mathlib/Geometry/Manifold/ChartedSpace.lean index c5f523f226b65..d430b51986bf6 100644 --- a/Mathlib/Geometry/Manifold/ChartedSpace.lean +++ b/Mathlib/Geometry/Manifold/ChartedSpace.lean @@ -861,26 +861,24 @@ instance ChartedSpace.sum : ChartedSpace H (M ⊕ M') where chartAt := Sum.elim (fun x ↦ (cm.chartAt x).lift_openEmbedding IsOpenEmbedding.inl) (fun x ↦ (cm'.chartAt x).lift_openEmbedding IsOpenEmbedding.inr) mem_chart_source p := by - by_cases h : Sum.isLeft p - · let x := Sum.getLeft p h - rw [Sum.eq_left_getLeft_of_isLeft h, Sum.elim_inl, lift_openEmbedding_source, + cases p with + | inl x => + rw [Sum.elim_inl, lift_openEmbedding_source, ← PartialHomeomorph.lift_openEmbedding_source _ IsOpenEmbedding.inl] use x, cm.mem_chart_source x - · have h' : Sum.isRight p := Sum.not_isLeft.mp h - let x := Sum.getRight p h' - rw [Sum.eq_right_getRight_of_isRight h', Sum.elim_inr, lift_openEmbedding_source, + | inr x => + rw [Sum.elim_inr, lift_openEmbedding_source, ← PartialHomeomorph.lift_openEmbedding_source _ IsOpenEmbedding.inr] use x, cm'.mem_chart_source x chart_mem_atlas p := by - by_cases h : Sum.isLeft p - · rw [Sum.eq_left_getLeft_of_isLeft h, Sum.elim_inl] + cases p with + | inl x => + rw [Sum.elim_inl] left - let x := Sum.getLeft p h use ChartedSpace.chartAt x, cm.chart_mem_atlas x - · have h' : Sum.isRight p := Sum.not_isLeft.mp h - rw [Sum.eq_right_getRight_of_isRight h', Sum.elim_inr] + | inr x => + rw [Sum.elim_inr] right - let x := Sum.getRight p h' use ChartedSpace.chartAt x, cm'.chart_mem_atlas x lemma ChartedSpace.sum_chartAt_inl (x : M) : diff --git a/Mathlib/Geometry/Manifold/MFDeriv/UniqueDifferential.lean b/Mathlib/Geometry/Manifold/MFDeriv/UniqueDifferential.lean index 1c23a54eb9e67..58dad19553fec 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv/UniqueDifferential.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv/UniqueDifferential.lean @@ -82,7 +82,7 @@ theorem UniqueMDiffOn.uniqueMDiffOn_preimage (hs : UniqueMDiffOn I s) {e : Parti (he : e.MDifferentiable I I') : UniqueMDiffOn I' (e.target ∩ e.symm ⁻¹' s) := fun _x hx ↦ e.right_inv hx.1 ▸ (hs _ hx.2).preimage_partialHomeomorph he (e.map_target hx.1) -variable [IsManifold I 1 M] in +variable [IsManifold I 1 M] in /-- If a set in a manifold has the unique derivative property, then its pullback by any extended chart, in the vector space, also has the unique derivative property. -/ theorem UniqueMDiffOn.uniqueMDiffOn_target_inter (hs : UniqueMDiffOn I s) (x : M) : diff --git a/Mathlib/LinearAlgebra/Projectivization/Cardinality.lean b/Mathlib/LinearAlgebra/Projectivization/Cardinality.lean index 6c66f723eb964..e62e38df83ac4 100644 --- a/Mathlib/LinearAlgebra/Projectivization/Cardinality.lean +++ b/Mathlib/LinearAlgebra/Projectivization/Cardinality.lean @@ -91,11 +91,9 @@ variable (k V : Type*) [Field k] [AddCommGroup V] [Module k V] /-- Cardinality formula for the points of `ℙ k V` if `k` and `V` are finite expressed as a fraction. -/ lemma card'' [Finite k] : Nat.card (ℙ k V) = (Nat.card V - 1) / (Nat.card k - 1) := by - haveI : Fintype k := Fintype.ofFinite k - rw [card k] have : 1 < Nat.card k := Finite.one_lt_card - have h : 0 ≠ (Nat.card k - 1) := by omega - exact Nat.eq_div_of_mul_eq_left (Ne.symm h) rfl + rw [card k, Nat.mul_div_cancel] + omega lemma card_of_finrank [Finite k] {n : ℕ} (h : Module.finrank k V = n) : Nat.card (ℙ k V) = ∑ i ∈ Finset.range n, Nat.card k ^ i := by @@ -115,8 +113,7 @@ lemma card_of_finrank [Finite k] {n : ℕ} (h : Module.finrank k V = n) : let e : V ≃ₗ[k] (Fin n → k) := LinearEquiv.ofFinrankEq _ _ (by simpa) have hc : Nat.card V = Nat.card k ^ n := by simp [Nat.card_congr e.toEquiv, Nat.card_fun] zify - have hn : 1 ≤ Nat.card k := Nat.one_le_of_lt Finite.one_lt_card - conv_rhs => rw [Int.natCast_sub hn, Int.natCast_one, geom_sum_mul] + conv_rhs => rw [Int.natCast_sub this.le, Int.natCast_one, geom_sum_mul] rw [← Int.natCast_mul, ← card k V, hc] simp diff --git a/Mathlib/MeasureTheory/Decomposition/RadonNikodym.lean b/Mathlib/MeasureTheory/Decomposition/RadonNikodym.lean index b793c87ee48e0..8591fb29495a5 100644 --- a/Mathlib/MeasureTheory/Decomposition/RadonNikodym.lean +++ b/Mathlib/MeasureTheory/Decomposition/RadonNikodym.lean @@ -511,7 +511,7 @@ theorem lintegral_rnDeriv_mul [HaveLebesgueDecomposition μ ν] (hμν : μ ≪ (hf : AEMeasurable f ν) : ∫⁻ x, μ.rnDeriv ν x * f x ∂ν = ∫⁻ x, f x ∂μ := by nth_rw 2 [← withDensity_rnDeriv_eq μ ν hμν] rw [lintegral_withDensity_eq_lintegral_mul₀ (measurable_rnDeriv μ ν).aemeasurable hf] - rfl + simp only [Pi.mul_apply] lemma setLIntegral_rnDeriv_mul [HaveLebesgueDecomposition μ ν] (hμν : μ ≪ ν) {f : α → ℝ≥0∞} (hf : AEMeasurable f ν) {s : Set α} (hs : MeasurableSet s) : diff --git a/Mathlib/MeasureTheory/Function/SimpleFunc.lean b/Mathlib/MeasureTheory/Function/SimpleFunc.lean index 80239aa069a9a..6d6742753612f 100644 --- a/Mathlib/MeasureTheory/Function/SimpleFunc.lean +++ b/Mathlib/MeasureTheory/Function/SimpleFunc.lean @@ -1185,11 +1185,9 @@ theorem _root_.Measurable.add_simpleFunc induction' f using SimpleFunc.induction with c s hs f f' hff' hf hf' · simp only [SimpleFunc.const_zero, SimpleFunc.coe_piecewise, SimpleFunc.coe_const, SimpleFunc.coe_zero] - change Measurable (g + s.piecewise (Function.const α c) (0 : α → E)) rw [← s.piecewise_same g, ← piecewise_add] exact Measurable.piecewise hs (hg.add_const _) (hg.add_const _) - · have : (g + ↑(f + f')) - = (Function.support f).piecewise (g + (f : α → E)) (g + f') := by + · have : (g + ↑(f + f')) = (Function.support f).piecewise (g + (f : α → E)) (g + f') := by ext x by_cases hx : x ∈ Function.support f · simpa only [SimpleFunc.coe_add, Pi.add_apply, Function.mem_support, ne_eq, not_not, @@ -1210,11 +1208,9 @@ theorem _root_.Measurable.simpleFunc_add induction' f using SimpleFunc.induction with c s hs f f' hff' hf hf' · simp only [SimpleFunc.const_zero, SimpleFunc.coe_piecewise, SimpleFunc.coe_const, SimpleFunc.coe_zero] - change Measurable (s.piecewise (Function.const α c) (0 : α → E) + g) rw [← s.piecewise_same g, ← piecewise_add] exact Measurable.piecewise hs (hg.const_add _) (hg.const_add _) - · have : (↑(f + f') + g) - = (Function.support f).piecewise ((f : α → E) + g) (f' + g) := by + · have : (↑(f + f') + g) = (Function.support f).piecewise ((f : α → E) + g) (f' + g) := by ext x by_cases hx : x ∈ Function.support f · simpa only [coe_add, Pi.add_apply, Function.mem_support, ne_eq, not_not, diff --git a/Mathlib/MeasureTheory/Measure/Haar/Unique.lean b/Mathlib/MeasureTheory/Measure/Haar/Unique.lean index 3a14731891763..ea268bfc743a0 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/Unique.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/Unique.lean @@ -272,8 +272,7 @@ lemma exists_integral_isMulLeftInvariant_eq_smul_of_hasCompactSupport (μ' μ : integral_isMulLeftInvariant_isMulRightInvariant_combo f_cont f_comp g_cont g_comp g_nonneg g_one /- Since the `ν`-factor is the same for `μ` and `μ'`, this gives the result. -/ rw [← A, mul_assoc, mul_comm] at B - simp only [B, integral_smul_nnreal_measure] - rfl + simp [B, integral_smul_nnreal_measure, c, NNReal.smul_def] open scoped Classical in /-- Given two left-invariant measures which are finite on compacts, `haarScalarFactor μ' μ` is a diff --git a/Mathlib/MeasureTheory/Measure/Hausdorff.lean b/Mathlib/MeasureTheory/Measure/Hausdorff.lean index 5bd12b8bc5683..0dceda1950733 100644 --- a/Mathlib/MeasureTheory/Measure/Hausdorff.lean +++ b/Mathlib/MeasureTheory/Measure/Hausdorff.lean @@ -470,7 +470,7 @@ theorem mkMetric_apply (m : ℝ≥0∞ → ℝ≥0∞) (s : Set X) : simp only [← OuterMeasure.coe_mkMetric, OuterMeasure.mkMetric, OuterMeasure.mkMetric', OuterMeasure.iSup_apply, OuterMeasure.mkMetric'.pre, OuterMeasure.boundedBy_apply, extend] refine - surjective_id.iSup_congr (id) fun r => + surjective_id.iSup_congr id fun r => iSup_congr_Prop Iff.rfl fun _ => surjective_id.iInf_congr _ fun t => iInf_congr_Prop Iff.rfl fun ht => ?_ dsimp diff --git a/Mathlib/MeasureTheory/VectorMeasure/WithDensity.lean b/Mathlib/MeasureTheory/VectorMeasure/WithDensity.lean index e0642d458ddf3..5cb49ca9935c6 100644 --- a/Mathlib/MeasureTheory/VectorMeasure/WithDensity.lean +++ b/Mathlib/MeasureTheory/VectorMeasure/WithDensity.lean @@ -67,7 +67,7 @@ theorem withDensityᵥ_neg : μ.withDensityᵥ (-f) = -μ.withDensityᵥ f := by · ext1 i hi rw [VectorMeasure.neg_apply, withDensityᵥ_apply hf hi, ← integral_neg, withDensityᵥ_apply hf.neg hi] - rfl + simp only [Pi.neg_apply] · rw [withDensityᵥ, withDensityᵥ, dif_neg hf, dif_neg, neg_zero] rwa [integrable_neg_iff] @@ -105,7 +105,7 @@ theorem withDensityᵥ_smul {𝕜 : Type*} [NontriviallyNormedField 𝕜] [Norme · ext1 i hi rw [withDensityᵥ_apply (hf.smul r) hi, VectorMeasure.smul_apply, withDensityᵥ_apply hf hi, ← integral_smul r f] - rfl + simp only [Pi.smul_apply] · by_cases hr : r = 0 · rw [hr, zero_smul, zero_smul, withDensityᵥ_zero] · rw [withDensityᵥ, withDensityᵥ, dif_neg hf, dif_neg, smul_zero] @@ -123,7 +123,7 @@ theorem withDensityᵥ_smul_eq_withDensityᵥ_withDensity {f : α → ℝ≥0} { rw [withDensityᵥ_apply hfg hs, withDensityᵥ_apply ((integrable_withDensity_iff_integrable_smul₀ hf).mpr hfg) hs, setIntegral_withDensity_eq_setIntegral_smul₀ hf.restrict _ hs] - rfl + simp only [Pi.smul_apply'] theorem withDensityᵥ_smul_eq_withDensityᵥ_withDensity' {f : α → ℝ≥0∞} {g : α → E} (hf : AEMeasurable f μ) (hflt : ∀ᵐ x ∂μ, f x < ∞) @@ -131,7 +131,9 @@ theorem withDensityᵥ_smul_eq_withDensityᵥ_withDensity' {f : α → ℝ≥0 μ.withDensityᵥ (fun x ↦ (f x).toReal • g x) = (μ.withDensity f).withDensityᵥ g := by rw [← withDensity_congr_ae (coe_toNNReal_ae_eq hflt), ← withDensityᵥ_smul_eq_withDensityᵥ_withDensity hf.ennreal_toNNReal hfg] - rfl + apply congr_arg + ext + simp [NNReal.smul_def, ENNReal.coe_toNNReal_eq_toReal] theorem Measure.withDensityᵥ_absolutelyContinuous (μ : Measure α) (f : α → ℝ) : μ.withDensityᵥ f ≪ᵥ μ.toENNRealVectorMeasure := by diff --git a/Mathlib/NumberTheory/NumberField/EquivReindex.lean b/Mathlib/NumberTheory/NumberField/EquivReindex.lean index 76ece2db3d216..d3862754f4aec 100644 --- a/Mathlib/NumberTheory/NumberField/EquivReindex.lean +++ b/Mathlib/NumberTheory/NumberField/EquivReindex.lean @@ -26,9 +26,9 @@ open Module.Free Module canonicalEmbedding Matrix Finset /-- An equivalence between the set of embeddings of `K` into `ℂ` and the index set of the chosen basis of the ring of integers of `K`. -/ -abbrev equivReindex : (K →+* ℂ) ≃ (ChooseBasisIndex ℤ (𝓞 K)) := - Fintype.equivOfCardEq <| - by rw [Embeddings.card, ← finrank_eq_card_chooseBasisIndex, RingOfIntegers.rank] +abbrev equivReindex : (K →+* ℂ) ≃ ChooseBasisIndex ℤ (𝓞 K) := + Fintype.equivOfCardEq <| by + rw [Embeddings.card, ← finrank_eq_card_chooseBasisIndex, RingOfIntegers.rank] /-- The basis matrix for the embeddings of `K` into `ℂ`. This matrix is formed by taking the lattice basis vectors of `K` and reindexing them according to the diff --git a/Mathlib/NumberTheory/NumberField/House.lean b/Mathlib/NumberTheory/NumberField/House.lean index f5cd7772f5a6a..50211fbf7068c 100644 --- a/Mathlib/NumberTheory/NumberField/House.lean +++ b/Mathlib/NumberTheory/NumberField/House.lean @@ -133,7 +133,7 @@ private theorem asiegel_ne_0 : asiegel K a ≠ 0 := by simp (config := { unfoldPartialApp := true }) only [asiegel, a'] simp only [ne_eq] rw [funext_iff]; intros hs - simp only [Prod.forall] at hs; + simp only [Prod.forall] at hs apply ha rw [← Matrix.ext_iff]; intros k' l specialize hs k' diff --git a/Mathlib/Probability/Density.lean b/Mathlib/Probability/Density.lean index ec410d68a63d8..4703ef101dec4 100644 --- a/Mathlib/Probability/Density.lean +++ b/Mathlib/Probability/Density.lean @@ -219,10 +219,8 @@ variable {F : Type*} [NormedAddCommGroup F] [NormedSpace ℝ F] theorem integrable_pdf_smul_iff [IsFiniteMeasure ℙ] {X : Ω → E} [HasPDF X ℙ μ] {f : E → F} (hf : AEStronglyMeasurable f μ) : Integrable (fun x => (pdf X ℙ μ x).toReal • f x) μ ↔ Integrable (fun x => f (X x)) ℙ := by - -- Porting note: using `erw` because `rw` doesn't recognize `(f <| X ·)` as `f ∘ X` - -- https://github.com/leanprover-community/mathlib4/issues/5164 - erw [← integrable_map_measure (hf.mono_ac HasPDF.absolutelyContinuous) - (HasPDF.aemeasurable X ℙ μ), + rw [← Function.comp_def, + ← integrable_map_measure (hf.mono_ac HasPDF.absolutelyContinuous) (HasPDF.aemeasurable X ℙ μ), map_eq_withDensity_pdf X ℙ μ, pdf_def, integrable_rnDeriv_smul_iff HasPDF.absolutelyContinuous] rw [withDensity_rnDeriv_eq _ _ HasPDF.absolutelyContinuous] diff --git a/Mathlib/Probability/Distributions/Gaussian.lean b/Mathlib/Probability/Distributions/Gaussian.lean index 8b3c99c7d763c..e807d75af5d28 100644 --- a/Mathlib/Probability/Distributions/Gaussian.lean +++ b/Mathlib/Probability/Distributions/Gaussian.lean @@ -283,8 +283,8 @@ lemma gaussianReal_map_const_mul (c : ℝ) : rw [Measure.map_const] simp only [ne_eq, measure_univ, one_smul, mul_eq_zero] convert (gaussianReal_zero_var 0).symm - simp only [ne_eq, zero_pow, mul_eq_zero, hv, or_false, not_false_eq_true, reduceCtorEq] - rfl + simp only [ne_eq, zero_pow, mul_eq_zero, hv, or_false, not_false_eq_true, reduceCtorEq, + NNReal.mk_zero] let e : ℝ ≃ᵐ ℝ := (Homeomorph.mulLeft₀ c hc).symm.toMeasurableEquiv have he' : ∀ x, HasDerivAt e ((fun _ ↦ c⁻¹) x) x := by suffices ∀ x, HasDerivAt (fun x => c⁻¹ * x) (c⁻¹ * 1) x by rwa [mul_one] at this diff --git a/Mathlib/RingTheory/FiniteLength.lean b/Mathlib/RingTheory/FiniteLength.lean index 90ac5c06d9d02..8b866ed99ebde 100644 --- a/Mathlib/RingTheory/FiniteLength.lean +++ b/Mathlib/RingTheory/FiniteLength.lean @@ -34,9 +34,11 @@ variable {R} {M N : Type*} [AddCommGroup M] [Module R M] [AddCommGroup N] [Modul theorem LinearEquiv.isFiniteLength (e : M ≃ₗ[R] N) (h : IsFiniteLength R M) : IsFiniteLength R N := by - induction' h with M _ _ _ M _ _ S _ _ ih generalizing N - · have := e.symm.toEquiv.subsingleton; exact .of_subsingleton - · have : IsSimpleModule R (N ⧸ Submodule.map (e : M →ₗ[R] N) S) := + induction h generalizing N with + | of_subsingleton => + have := e.symm.toEquiv.subsingleton; exact .of_subsingleton + | @of_simple_quotient M _ _ S _ _ ih => + have : IsSimpleModule R (N ⧸ Submodule.map (e : M →ₗ[R] N) S) := IsSimpleModule.congr (Submodule.Quotient.equiv S _ e rfl).symm exact .of_simple_quotient (ih <| e.submoduleMap S) diff --git a/Mathlib/RingTheory/Ideal/Quotient/Operations.lean b/Mathlib/RingTheory/Ideal/Quotient/Operations.lean index a71d12054e32b..8b758cb2564b1 100644 --- a/Mathlib/RingTheory/Ideal/Quotient/Operations.lean +++ b/Mathlib/RingTheory/Ideal/Quotient/Operations.lean @@ -188,11 +188,11 @@ def quotientInfToPiQuotient (I : ι → Ideal R) : (R ⧸ ⨅ i, I i) →+* ∀ lemma quotientInfToPiQuotient_mk (I : ι → Ideal R) (x : R) : quotientInfToPiQuotient I (Quotient.mk _ x) = fun i : ι ↦ Quotient.mk (I i) x := -rfl + rfl lemma quotientInfToPiQuotient_mk' (I : ι → Ideal R) (x : R) (i : ι) : quotientInfToPiQuotient I (Quotient.mk _ x) i = Quotient.mk (I i) x := -rfl + rfl lemma quotientInfToPiQuotient_inj (I : ι → Ideal R) : Injective (quotientInfToPiQuotient I) := by rw [quotientInfToPiQuotient, injective_lift_iff, ker_Pi_Quotient_mk] diff --git a/Mathlib/RingTheory/LaurentSeries.lean b/Mathlib/RingTheory/LaurentSeries.lean index 4ef9b0f8f9357..b1595411dbd27 100644 --- a/Mathlib/RingTheory/LaurentSeries.lean +++ b/Mathlib/RingTheory/LaurentSeries.lean @@ -66,9 +66,9 @@ and the unit ball inside the `X`-adic completion of `RatFunc K`. ## Implementation details -* Since `LaurentSeries` is just an abbreviation of `HahnSeries ℤ _`, the definition of the +* Since `LaurentSeries` is just an abbreviation of `HahnSeries ℤ R`, the definition of the coefficients is given in terms of `HahnSeries.coeff` and this forces sometimes to go back-and-forth -from `X : _⸨X⸩` to `single 1 1 : HahnSeries ℤ _`. +from `X : R⸨X⸩` to `single 1 1 : HahnSeries ℤ R`. * To prove the isomorphism between the `X`-adic completion of `RatFunc K` and `K⸨X⸩` we construct two completions of `RatFunc K`: the first (`LaurentSeries.ratfuncAdicComplPkg`) is its abstract uniform completion; the second (`LaurentSeries.LaurentSeriesPkg`) is simply `K⸨X⸩`, once we prove @@ -198,11 +198,6 @@ variable [Semiring R] instance : Coe R⟦X⟧ R⸨X⸩ := ⟨HahnSeries.ofPowerSeries ℤ R⟩ -/- Porting note: now a syntactic tautology and not needed elsewhere -theorem coe_powerSeries (x : R⟦X⟧) : - (x : R⸨X⸩) = HahnSeries.ofPowerSeries ℤ R x := - rfl -/ - @[simp] theorem coeff_coe_powerSeries (x : R⟦X⟧) (n : ℕ) : HahnSeries.coeff (x : R⸨X⸩) n = PowerSeries.coeff R n x := by @@ -360,8 +355,6 @@ theorem coe_smul {S : Type*} [Semiring S] [Module R S] (r : R) (x : S⟦X⟧) : ext simp [coeff_coe, coeff_smul, smul_ite] --- Porting note: RingHom.map_bit0 and RingHom.map_bit1 no longer exist - @[norm_cast] theorem coe_pow (n : ℕ) : ((f ^ n : R⟦X⟧) : R⸨X⸩) = (ofPowerSeries ℤ R f) ^ n := (ofPowerSeries ℤ R).map_pow _ _ diff --git a/Mathlib/RingTheory/Nilpotent/Defs.lean b/Mathlib/RingTheory/Nilpotent/Defs.lean index cbdde6aab35bc..adebd3a741323 100644 --- a/Mathlib/RingTheory/Nilpotent/Defs.lean +++ b/Mathlib/RingTheory/Nilpotent/Defs.lean @@ -52,26 +52,26 @@ theorem not_isNilpotent_one [MonoidWithZero R] [Nontrivial R] : lemma IsNilpotent.pow_succ (n : ℕ) {S : Type*} [MonoidWithZero S] {x : S} (hx : IsNilpotent x) : IsNilpotent (x ^ n.succ) := by - obtain ⟨N,hN⟩ := hx + obtain ⟨N, hN⟩ := hx use N rw [← pow_mul, Nat.succ_mul, pow_add, hN, mul_zero] -theorem IsNilpotent.of_pow [MonoidWithZero R] {x : R} {m : ℕ} +theorem IsNilpotent.of_pow [MonoidWithZero R] {x : R} {m : ℕ} (h : IsNilpotent (x ^ m)) : IsNilpotent x := by obtain ⟨n, h⟩ := h - use m*n + use m * n rw [← h, pow_mul x m n] lemma IsNilpotent.pow_of_pos {n} {S : Type*} [MonoidWithZero S] {x : S} (hx : IsNilpotent x) (hn : n ≠ 0) : IsNilpotent (x ^ n) := by cases n with | zero => contradiction - | succ => exact IsNilpotent.pow_succ _ hx + | succ => exact IsNilpotent.pow_succ _ hx @[simp] -lemma IsNilpotent.pow_iff_pos {n} {S : Type*} [MonoidWithZero S] {x : S} - (hn : n ≠ 0) : IsNilpotent (x ^ n) ↔ IsNilpotent x := - ⟨fun h => of_pow h, fun h => pow_of_pos h hn⟩ +lemma IsNilpotent.pow_iff_pos {n} {S : Type*} [MonoidWithZero S] {x : S} (hn : n ≠ 0) : + IsNilpotent (x ^ n) ↔ IsNilpotent x := + ⟨of_pow, (pow_of_pos · hn)⟩ theorem IsNilpotent.map [MonoidWithZero R] [MonoidWithZero S] {r : R} {F : Type*} [FunLike F R S] [MonoidWithZeroHomClass F R S] (hr : IsNilpotent r) (f : F) : diff --git a/Mathlib/RingTheory/RingHom/FinitePresentation.lean b/Mathlib/RingTheory/RingHom/FinitePresentation.lean index f2503b3b0b8f9..4aa353d93690d 100644 --- a/Mathlib/RingTheory/RingHom/FinitePresentation.lean +++ b/Mathlib/RingTheory/RingHom/FinitePresentation.lean @@ -58,7 +58,7 @@ theorem finitePresentation_holdsForLocalizationAway : introv R _ suffices Algebra.FinitePresentation R S by rw [RingHom.FinitePresentation] - convert this; ext; + convert this; ext rw [Algebra.smul_def]; rfl exact IsLocalization.Away.finitePresentation r @@ -96,7 +96,7 @@ theorem finitePresentation_ofLocalizationSpanTarget : classical letI := f.toAlgebra replace H : ∀ r : s, Algebra.FinitePresentation R (Localization.Away (r : S)) := by - intro r; simp_rw [RingHom.FinitePresentation] at H; + intro r; simp_rw [RingHom.FinitePresentation] at H convert H r; ext; simp_rw [Algebra.smul_def]; rfl /- We already know that `S` is of finite type over `R`, so we have a surjection diff --git a/Mathlib/RingTheory/Spectrum/Prime/Module.lean b/Mathlib/RingTheory/Spectrum/Prime/Module.lean index e7f608704c4c8..28fe87edbab06 100644 --- a/Mathlib/RingTheory/Spectrum/Prime/Module.lean +++ b/Mathlib/RingTheory/Spectrum/Prime/Module.lean @@ -31,8 +31,7 @@ lemma LocalizedModule.subsingleton_iff_disjoint {f : R} : Subsingleton (LocalizedModule (.powers f) M) ↔ Disjoint ↑(PrimeSpectrum.basicOpen f) (Module.support R M) := by rw [subsingleton_iff_support_subset, PrimeSpectrum.basicOpen_eq_zeroLocus_compl, - disjoint_compl_left_iff] - rfl + disjoint_compl_left_iff, Set.le_iff_subset] lemma Module.stableUnderSpecialization_support : StableUnderSpecialization (Module.support R M) := by diff --git a/Mathlib/RingTheory/Support.lean b/Mathlib/RingTheory/Support.lean index cbb8bb690f8a4..ec284eeb4dd94 100644 --- a/Mathlib/RingTheory/Support.lean +++ b/Mathlib/RingTheory/Support.lean @@ -50,8 +50,8 @@ lemma Module.not_mem_support_iff : lemma Module.not_mem_support_iff' : p ∉ Module.support R M ↔ ∀ m : M, ∃ r ∉ p.asIdeal, r • m = 0 := by - rw [not_mem_support_iff, LocalizedModule.subsingleton_iff] - rfl + simp only [not_mem_support_iff, Ideal.primeCompl, LocalizedModule.subsingleton_iff, + Submonoid.mem_mk, Subsemigroup.mem_mk, Set.mem_compl_iff, SetLike.mem_coe] lemma Module.mem_support_iff' : p ∈ Module.support R M ↔ ∃ m : M, ∀ r ∉ p.asIdeal, r • m ≠ 0 := by diff --git a/Mathlib/Topology/MetricSpace/HolderNorm.lean b/Mathlib/Topology/MetricSpace/HolderNorm.lean index 424128d4adb85..b7fdaf6f47dff 100644 --- a/Mathlib/Topology/MetricSpace/HolderNorm.lean +++ b/Mathlib/Topology/MetricSpace/HolderNorm.lean @@ -61,7 +61,8 @@ lemma HolderWith.memHolder {C : ℝ≥0} (hf : HolderWith C r f) : MemHolder r f refine ⟨fun h => ?_, fun hf => let ⟨C, hC⟩ := hf; iInf_lt_top.2 ⟨C, iInf_lt_top.2 ⟨hC, coe_lt_top⟩⟩⟩ simp_rw [eHolderNorm, iInf_lt_top] at h - exact let ⟨C, hC, _⟩ := h; ⟨C, hC⟩ + let ⟨C, hC, _⟩ := h + exact ⟨C, hC⟩ lemma eHolderNorm_ne_top : eHolderNorm r f ≠ ∞ ↔ MemHolder r f := by rw [← eHolderNorm_lt_top, lt_top_iff_ne_top] @@ -92,8 +93,7 @@ variable (X) in lemma nnHolderNorm_const (r : ℝ≥0) (c : Y) : nnHolderNorm r (Function.const X c) = 0 := by refine le_antisymm (ENNReal.coe_le_coe.1 <| le_trans coe_nnHolderNorm_le_eHolderNorm ?_) (zero_le _) - rw [eHolderNorm_const] - rfl + rw [eHolderNorm_const, ENNReal.coe_zero] variable (X) in @[simp] diff --git a/Mathlib/Topology/Order/UpperLowerSetTopology.lean b/Mathlib/Topology/Order/UpperLowerSetTopology.lean index 1c2c2390d6ebe..a7364240ec272 100644 --- a/Mathlib/Topology/Order/UpperLowerSetTopology.lean +++ b/Mathlib/Topology/Order/UpperLowerSetTopology.lean @@ -54,7 +54,7 @@ namespace Topology /-- Topology whose open sets are upper sets. Note: In general the upper set topology does not coincide with the upper topology. -/ -def upperSet (α : Type*) [Preorder α] : TopologicalSpace α where +def upperSet (α : Type*) [Preorder α] : TopologicalSpace α where IsOpen := IsUpperSet isOpen_univ := isUpperSet_univ isOpen_inter _ _ := IsUpperSet.inter @@ -63,7 +63,7 @@ def upperSet (α : Type*) [Preorder α] : TopologicalSpace α where /-- Topology whose open sets are lower sets. Note: In general the lower set topology does not coincide with the lower topology. -/ -def lowerSet (α : Type*) [Preorder α] : TopologicalSpace α where +def lowerSet (α : Type*) [Preorder α] : TopologicalSpace α where IsOpen := IsLowerSet isOpen_univ := isLowerSet_univ isOpen_inter _ _ := IsLowerSet.inter @@ -407,7 +407,7 @@ def map (f : α →o β) : C(WithLowerSet α, WithLowerSet β) where @[simp] lemma map_comp (g : β →o γ) (f : α →o β) : map (g.comp f) = (map g).comp (map f) := rfl @[simp] lemma toLowerSet_specializes_toLowerSet {a b : α} : - toLowerSet a ⤳ toLowerSet b ↔ a ≤ b := by + toLowerSet a ⤳ toLowerSet b ↔ a ≤ b := by simp_rw [specializes_iff_closure_subset, IsLowerSet.closure_singleton, Ici_subset_Ici, toLowerSet_le_iff] From b76b14cff64dc146e8aaffc91340e5a025001f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Mon, 3 Feb 2025 05:29:21 +0000 Subject: [PATCH 015/103] feat(CategoryTheory): the class of morphisms given by a family of maps (#21354) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Given a family of morphisms `f i : X i ⟶ Y i` in a category `C`, this PR introduces that the class of morphisms `ofHoms f : MorphismProperty C` consisting of these morphisms `f i`. --- Mathlib/CategoryTheory/Comma/Arrow.lean | 58 ++++++++++++++----- .../CategoryTheory/Comma/CardinalArrow.lean | 9 ++- .../Localization/Triangulated.lean | 2 +- .../MorphismProperty/Basic.lean | 54 +++++++++++++++-- 4 files changed, 97 insertions(+), 26 deletions(-) diff --git a/Mathlib/CategoryTheory/Comma/Arrow.lean b/Mathlib/CategoryTheory/Comma/Arrow.lean index 1779eaa423ca1..dedb872367a90 100644 --- a/Mathlib/CategoryTheory/Comma/Arrow.lean +++ b/Mathlib/CategoryTheory/Comma/Arrow.lean @@ -91,6 +91,35 @@ theorem mk_inj (A B : T) {f g : A ⟶ B} : Arrow.mk f = Arrow.mk g ↔ f = g := instance {X Y : T} : CoeOut (X ⟶ Y) (Arrow T) where coe := mk +lemma mk_eq_mk_iff {X Y X' Y' : T} (f : X ⟶ Y) (f' : X' ⟶ Y') : + Arrow.mk f = Arrow.mk f' ↔ + ∃ (hX : X = X') (hY : Y = Y'), f = eqToHom hX ≫ f' ≫ eqToHom hY.symm := by + constructor + · intro h + refine ⟨congr_arg Comma.left h, congr_arg Comma.right h, ?_⟩ + have := (eqToIso h).hom.w + dsimp at this + rw [Comma.eqToHom_left, Comma.eqToHom_right] at this + rw [reassoc_of% this, eqToHom_trans, eqToHom_refl, Category.comp_id] + · rintro ⟨rfl, rfl, h⟩ + simp only [eqToHom_refl, Category.comp_id, Category.id_comp] at h + rw [h] + +lemma ext {f g : Arrow T} + (h₁ : f.left = g.left) (h₂ : f.right = g.right) + (h₃ : f.hom = eqToHom h₁ ≫ g.hom ≫ eqToHom h₂.symm) : f = g := + (mk_eq_mk_iff _ _).2 (by aesop) + +@[simp] +lemma arrow_mk_comp_eqToHom {X Y Y' : T} (f : X ⟶ Y) (h : Y = Y') : + Arrow.mk (f ≫ eqToHom h) = Arrow.mk f := + ext rfl h.symm (by simp) + +@[simp] +lemma arrow_mk_eqToHom_comp {X' X Y : T} (f : X ⟶ Y) (h : X' = X) : + Arrow.mk (eqToHom h ≫ f) = Arrow.mk f := + ext h rfl (by simp) + /-- A morphism in the arrow category is a commutative square connecting two objects of the arrow category. -/ @[simps] @@ -294,16 +323,6 @@ def rightFunc : Arrow C ⥤ C := @[simps] def leftToRight : (leftFunc : Arrow C ⥤ C) ⟶ rightFunc where app f := f.hom -lemma ext {f g : Arrow C} - (h₁ : f.left = g.left) (h₂ : f.right = g.right) - (h₃ : f.hom = eqToHom h₁ ≫ g.hom ≫ eqToHom h₂.symm) : f = g := by - obtain ⟨X, Y, f⟩ := f - obtain ⟨X', Y', g⟩ := g - obtain rfl : X = X' := h₁ - obtain rfl : Y = Y' := h₂ - obtain rfl : f = g := by simpa using h₃ - rfl - end Arrow namespace Functor @@ -315,10 +334,7 @@ variable {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D] /-- A functor `C ⥤ D` induces a functor between the corresponding arrow categories. -/ @[simps] def mapArrow (F : C ⥤ D) : Arrow C ⥤ Arrow D where - obj a := - { left := F.obj a.left - right := F.obj a.right - hom := F.map a.hom } + obj a := Arrow.mk (F.map a.hom) map f := { left := F.map f.left right := F.map f.right @@ -355,9 +371,11 @@ instance isEquivalence_mapArrow (F : C ⥤ D) [IsEquivalence F] : end Functor +variable {C D : Type*} [Category C] [Category D] + /-- The images of `f : Arrow C` by two isomorphic functors `F : C ⥤ D` are isomorphic arrows in `D`. -/ -def Arrow.isoOfNatIso {C D : Type*} [Category C] [Category D] {F G : C ⥤ D} (e : F ≅ G) +def Arrow.isoOfNatIso {F G : C ⥤ D} (e : F ≅ G) (f : Arrow C) : F.mapArrow.obj f ≅ G.mapArrow.obj f := Arrow.isoMk (e.app f.left) (e.app f.right) @@ -382,4 +400,14 @@ def Arrow.discreteEquiv (S : Type u) : Arrow (Discrete S) ≃ S where rfl right_inv _ := rfl +/-- Extensionality lemma for functors `C ⥤ D` which uses as an assumption +that the induced maps `Arrow C → Arrow D` coincide. -/ +lemma Arrow.functor_ext {F G : C ⥤ D} (h : ∀ ⦃X Y : C⦄ (f : X ⟶ Y), + F.mapArrow.obj (Arrow.mk f) = G.mapArrow.obj (Arrow.mk f)) : + F = G := + Functor.ext (fun X ↦ congr_arg Comma.left (h (𝟙 X))) (fun X Y f ↦ by + have := h f + simp only [Functor.mapArrow_obj, mk_eq_mk_iff] at this + tauto) + end CategoryTheory diff --git a/Mathlib/CategoryTheory/Comma/CardinalArrow.lean b/Mathlib/CategoryTheory/Comma/CardinalArrow.lean index 14443de419c69..0f9f4d3bf09c4 100644 --- a/Mathlib/CategoryTheory/Comma/CardinalArrow.lean +++ b/Mathlib/CategoryTheory/Comma/CardinalArrow.lean @@ -77,17 +77,16 @@ noncomputable def Arrow.shrinkHomsEquiv (C : Type u) [Category.{v} C] [LocallySm Arrow.{w} (ShrinkHoms C) ≃ Arrow C where toFun := (ShrinkHoms.equivalence C).inverse.mapArrow.obj invFun := (ShrinkHoms.equivalence C).functor.mapArrow.obj - left_inv _ := by simp [Functor.mapArrow]; rfl - right_inv _ := by simp [Functor.mapArrow]; rfl + left_inv _ := by simp + right_inv _ := by simp /-- The bijection `Arrow (Shrink C) ≃ Arrow C`. -/ noncomputable def Arrow.shrinkEquiv (C : Type u) [Category.{v} C] [Small.{w} C] : Arrow (Shrink.{w} C) ≃ Arrow C where toFun := (Shrink.equivalence C).inverse.mapArrow.obj invFun := (Shrink.equivalence C).functor.mapArrow.obj - left_inv f := by - refine Arrow.ext (Equiv.apply_symm_apply _ _) - ((Equiv.apply_symm_apply _ _)) (by simp; rfl) + left_inv _ := Arrow.ext (Equiv.apply_symm_apply _ _) + ((Equiv.apply_symm_apply _ _)) (by simp ; rfl) right_inv _ := Arrow.ext (by simp [Shrink.equivalence]) (by simp [Shrink.equivalence]) (by simp [Shrink.equivalence]) diff --git a/Mathlib/CategoryTheory/Localization/Triangulated.lean b/Mathlib/CategoryTheory/Localization/Triangulated.lean index 575cad9534bc8..0115ea3573324 100644 --- a/Mathlib/CategoryTheory/Localization/Triangulated.lean +++ b/Mathlib/CategoryTheory/Localization/Triangulated.lean @@ -136,7 +136,7 @@ lemma distinguished_cocone_triangle {X Y : D} (f : X ⟶ Y) : (Iso.refl _) e.inv.w.symm (by simp) ?_ dsimp simp only [assoc, id_comp, ← Functor.map_comp, ← Arrow.comp_left, e.hom_inv_id, Arrow.id_left, - Functor.mapArrow_obj_left, Functor.map_id, comp_id] + Functor.mapArrow_obj, Arrow.mk_left, Functor.map_id, comp_id] section variable [W.IsCompatibleWithTriangulation] diff --git a/Mathlib/CategoryTheory/MorphismProperty/Basic.lean b/Mathlib/CategoryTheory/MorphismProperty/Basic.lean index a54f6901a6672..6ac0e8afdb2cd 100644 --- a/Mathlib/CategoryTheory/MorphismProperty/Basic.lean +++ b/Mathlib/CategoryTheory/MorphismProperty/Basic.lean @@ -115,14 +115,58 @@ lemma monotone_map (F : C ⥤ D) : intro P Q h X Y f ⟨X', Y', f', hf', ⟨e⟩⟩ exact ⟨X', Y', f', h _ hf', ⟨e⟩⟩ -lemma of_eq (P : MorphismProperty C) {X Y : C} {f : X ⟶ Y} (hf : P f) +section + +variable (P : MorphismProperty C) + +/-- The set in `Set (Arrow C)` which corresponds to `P : MorphismProperty C`. -/ +def toSet : Set (Arrow C) := setOf (fun f ↦ P f.hom) + +/-- The family of morphisms indexed by `P.toSet` which corresponds +to `P : MorphismProperty C`, see `MorphismProperty.ofHoms_homFamily`. -/ +def homFamily (f : P.toSet) : f.1.left ⟶ f.1.right := f.1.hom + +lemma homFamily_apply (f : P.toSet) : P.homFamily f = f.1.hom := rfl + +@[simp] +lemma homFamily_arrow_mk {X Y : C} (f : X ⟶ Y) (hf : P f) : + P.homFamily ⟨Arrow.mk f, hf⟩ = f := rfl + +@[simp] +lemma arrow_mk_mem_toSet_iff {X Y : C} (f : X ⟶ Y) : Arrow.mk f ∈ P.toSet ↔ P f := Iff.rfl + +lemma of_eq {X Y : C} {f : X ⟶ Y} (hf : P f) {X' Y' : C} {f' : X' ⟶ Y'} (hX : X = X') (hY : Y = Y') (h : f' = eqToHom hX.symm ≫ f ≫ eqToHom hY) : P f' := by - obtain rfl := hX - obtain rfl := hY - obtain rfl : f' = f := by simpa using h - exact hf + rw [← P.arrow_mk_mem_toSet_iff] at hf ⊢ + rwa [(Arrow.mk_eq_mk_iff f' f).2 ⟨hX.symm, hY.symm, h⟩] + +end + +/-- The class of morphisms given by a family of morphisms `f i : X i ⟶ Y i`. -/ +inductive ofHoms {ι : Type*} {X Y : ι → C} (f : ∀ i, X i ⟶ Y i) : MorphismProperty C + | mk (i : ι) : ofHoms f (f i) + +lemma ofHoms_iff {ι : Type*} {X Y : ι → C} (f : ∀ i, X i ⟶ Y i) {A B : C} (g : A ⟶ B) : + ofHoms f g ↔ ∃ i, Arrow.mk g = Arrow.mk (f i) := by + constructor + · rintro ⟨i⟩ + exact ⟨i, rfl⟩ + · rintro ⟨i, h⟩ + rw [← (ofHoms f).arrow_mk_mem_toSet_iff, h, arrow_mk_mem_toSet_iff] + constructor + +@[simp] +lemma ofHoms_homFamily (P : MorphismProperty C) : ofHoms P.homFamily = P := by + ext _ _ f + constructor + · intro hf + rw [ofHoms_iff] at hf + obtain ⟨⟨f, hf⟩, ⟨_, _⟩⟩ := hf + exact hf + · intro hf + exact ⟨(⟨f, hf⟩ : P.toSet)⟩ /-- A morphism property `P` satisfies `P.RespectsRight Q` if it is stable under post-composition with morphisms satisfying `Q`, i.e. whenever `P` holds for `f` and `Q` holds for `i` then `P` From 13a19003b19363e67ddb86947e4363a78da96ee3 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Mon, 3 Feb 2025 06:30:34 +0000 Subject: [PATCH 016/103] feat: `check_compositions`, a tactic for diagnosing defeq problems in category theory (#21357) --- Mathlib.lean | 1 + Mathlib/CategoryTheory/Functor/Basic.lean | 1 + Mathlib/Tactic.lean | 1 + .../CategoryTheory/CheckCompositions.lean | 70 +++++++++++++++++++ scripts/noshake.json | 7 +- 5 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 Mathlib/Tactic/CategoryTheory/CheckCompositions.lean diff --git a/Mathlib.lean b/Mathlib.lean index dcd281bb7adb8..824b545b1c456 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -4964,6 +4964,7 @@ import Mathlib.Tactic.CategoryTheory.Bicategory.Datatypes import Mathlib.Tactic.CategoryTheory.Bicategory.Normalize import Mathlib.Tactic.CategoryTheory.Bicategory.PureCoherence import Mathlib.Tactic.CategoryTheory.BicategoryCoherence +import Mathlib.Tactic.CategoryTheory.CheckCompositions import Mathlib.Tactic.CategoryTheory.Coherence import Mathlib.Tactic.CategoryTheory.Coherence.Basic import Mathlib.Tactic.CategoryTheory.Coherence.Datatypes diff --git a/Mathlib/CategoryTheory/Functor/Basic.lean b/Mathlib/CategoryTheory/Functor/Basic.lean index 13a3440fd5fb9..59fdcbc05e00c 100644 --- a/Mathlib/CategoryTheory/Functor/Basic.lean +++ b/Mathlib/CategoryTheory/Functor/Basic.lean @@ -5,6 +5,7 @@ Authors: Tim Baumann, Stephen Morgan, Kim Morrison -/ import Mathlib.CategoryTheory.Category.Basic import Mathlib.Combinatorics.Quiver.Prefunctor +import Mathlib.Tactic.CategoryTheory.CheckCompositions /-! # Functors diff --git a/Mathlib/Tactic.lean b/Mathlib/Tactic.lean index fda897921c1fe..988829d93d43a 100644 --- a/Mathlib/Tactic.lean +++ b/Mathlib/Tactic.lean @@ -29,6 +29,7 @@ import Mathlib.Tactic.CategoryTheory.Bicategory.Datatypes import Mathlib.Tactic.CategoryTheory.Bicategory.Normalize import Mathlib.Tactic.CategoryTheory.Bicategory.PureCoherence import Mathlib.Tactic.CategoryTheory.BicategoryCoherence +import Mathlib.Tactic.CategoryTheory.CheckCompositions import Mathlib.Tactic.CategoryTheory.Coherence import Mathlib.Tactic.CategoryTheory.Coherence.Basic import Mathlib.Tactic.CategoryTheory.Coherence.Datatypes diff --git a/Mathlib/Tactic/CategoryTheory/CheckCompositions.lean b/Mathlib/Tactic/CategoryTheory/CheckCompositions.lean new file mode 100644 index 0000000000000..783b4271280b3 --- /dev/null +++ b/Mathlib/Tactic/CategoryTheory/CheckCompositions.lean @@ -0,0 +1,70 @@ +/- +Copyright (c) 2025 Lean FRO, LLC. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kim Morrison +-/ +import Mathlib.CategoryTheory.Category.Basic + +/-! +The `check_compositions` tactic, +which checks the typing of categorical compositions in the goal, +reporting discrepancies at "instances and reducible" transparency. + +Reports from this tactic do not necessarily indicate a problem, +although typically `simp` should reduce rather than increase the reported discrepancies. + +`check_compositions` may be useful in diagnosing uses of `erw` in the category theory library. +-/ + +namespace Mathlib.Tactic.CheckCompositions + +open CategoryTheory + +open Lean Meta Elab Tactic + +/-- Find appearances of `CategoryStruct.comp C inst X Y Z f g`, and apply `f` to each. -/ +def forEachComposition (e : Expr) (f : Expr → MetaM Unit) : MetaM Unit := do + e.forEach (fun e ↦ if e.isAppOfArity ``CategoryStruct.comp 7 then f e else pure ()) + +/-- Given a composition `CategoryStruct.comp _ _ X Y Z f g`, +infer the types of `f` and `g` and check whether their sources and targets agree, +at "instances and reducible" transparency, with `X`, `Y`, and `Z`, +reporting any discrepancies. -/ +def checkComposition (e : Expr) : MetaM Unit := do + match_expr e with + | CategoryStruct.comp _ _ X Y Z f g => + match_expr ← inferType f with + | Quiver.Hom _ _ X' Y' => + withReducibleAndInstances do + if !(← isDefEq X' X) then + logInfo m!"In composition\n {e}\nthe source of\n {f}\nis\n {X'}\nbut should be\n {X}" + if !(← isDefEq Y' Y) then + logInfo m!"In composition\n {e}\nthe target of\n {f}\nis\n {Y'}\nbut should be\n {Y}" + | _ => throwError "In composition\n {e}\nthe type of\n {f}\nis not a morphism." + match_expr ← inferType g with + | Quiver.Hom _ _ Y' Z' => + withReducibleAndInstances do + if !(← isDefEq Y' Y) then + logInfo m!"In composition\n {e}\nthe source of\n {g}\nis\n {Y'}\nbut should be\n {Y}" + if !(← isDefEq Z' Z) then + logInfo m!"In composition\n {e}\nthe target of\n {g}\nis\n {Z'}\nbut should be\n {Z}" + | _ => throwError "In composition\n {e}\nthe type of\n {g}\nis not a morphism." + | _ => throwError "{e} is not a composition." + +/-- Check the typing of categorical compositions in an expression.-/ +def checkCompositions (e : Expr) : MetaM Unit := do + forEachComposition e checkComposition + +/-- Check the typing of categorical compositions in the goal.-/ +def checkCompositionsTac : TacticM Unit := withMainContext do + let e ← getMainTarget + checkCompositions e + +/-- For each composition `f ≫ g` in the goal, +which internally is represented as `CategoryStruct.comp C inst X Y Z f g`, +infer the types of `f` and `g` and check whether their sources and targets agree +with `X`, `Y`, and `Z` at "instances and reducible" transparency, +reporting any discrepancies. -/ +elab "check_compositions" : tactic => checkCompositionsTac + +end Mathlib.Tactic.CheckCompositions diff --git a/scripts/noshake.json b/scripts/noshake.json index 2732e7a608dbe..c41910752e88b 100644 --- a/scripts/noshake.json +++ b/scripts/noshake.json @@ -300,13 +300,14 @@ "Mathlib.Tactic.CategoryTheory.Coherence": ["Mathlib.CategoryTheory.Monoidal.Free.Coherence", "Mathlib.Tactic.CategoryTheory.MonoidalComp"], + "Mathlib.Tactic.CategoryTheory.CheckCompositions": + ["Mathlib.CategoryTheory.Category.Basic"], "Mathlib.Tactic.CategoryTheory.BicategoryCoherence": ["Mathlib.CategoryTheory.Bicategory.Coherence", "Mathlib.Tactic.CategoryTheory.BicategoricalComp"], + "Mathlib.Tactic.CC.MkProof": ["Mathlib.Tactic.CC.Lemmas"], "Mathlib.Tactic.CC.Datatypes": ["Mathlib.Lean.Meta.CongrTheorems", "Mathlib.Lean.Meta.Datatypes"], - "Mathlib.Tactic.CC.MkProof": - ["Mathlib.Tactic.CC.Lemmas"], "Mathlib.Tactic.ByContra": ["Batteries.Tactic.Init"], "Mathlib.Tactic.Bound.Init": ["Aesop.Frontend.Command"], "Mathlib.Tactic.Bound.Attribute": @@ -431,6 +432,8 @@ ["Mathlib.CategoryTheory.Limits.Shapes.Pullback.HasPullback", "Mathlib.CategoryTheory.Limits.Shapes.Pullbacks"], "Mathlib.CategoryTheory.Limits.IsLimit": ["Batteries.Tactic.Congr"], + "Mathlib.CategoryTheory.Functor.Basic": + ["Mathlib.Tactic.CategoryTheory.CheckCompositions"], "Mathlib.CategoryTheory.Bicategory.Functor.Oplax": ["Mathlib.Tactic.CategoryTheory.ToApp"], "Mathlib.CategoryTheory.Bicategory.Functor.Lax": From cd5fbfb76d04ed8b1cf2415c0b869ec3dfb3f087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Mon, 3 Feb 2025 06:56:31 +0000 Subject: [PATCH 017/103] =?UTF-8?q?chore:=20replace=20the=20lemma=20that?= =?UTF-8?q?=20`dist=201=20=3D=20norm`=20by=20`dist=201=20a=20=3D=20?= =?UTF-8?q?=E2=80=96a=E2=80=96`=20(#21340)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is much easier to use in `rw` as one can specify which occurrence to target. --- Mathlib/Analysis/Convex/StrictConvexBetween.lean | 2 +- Mathlib/Analysis/Normed/Group/Basic.lean | 6 ++++-- Mathlib/Analysis/Normed/Group/Uniform.lean | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Mathlib/Analysis/Convex/StrictConvexBetween.lean b/Mathlib/Analysis/Convex/StrictConvexBetween.lean index 08a6eed3ee484..55871c146e156 100644 --- a/Mathlib/Analysis/Convex/StrictConvexBetween.lean +++ b/Mathlib/Analysis/Convex/StrictConvexBetween.lean @@ -104,7 +104,7 @@ variable {E F PE PF : Type*} [NormedAddCommGroup E] [NormedAddCommGroup F] [Norm lemma eq_lineMap_of_dist_eq_mul_of_dist_eq_mul (hxy : dist x y = r * dist x z) (hyz : dist y z = (1 - r) * dist x z) : y = AffineMap.lineMap x z r := by have : y -ᵥ x ∈ [(0 : E) -[ℝ] z -ᵥ x] := by - rw [mem_segment_iff_wbtw, ← dist_add_dist_eq_iff, dist_zero_left, dist_vsub_cancel_right, + rw [mem_segment_iff_wbtw, ← dist_add_dist_eq_iff, dist_zero, dist_vsub_cancel_right, ← dist_eq_norm_vsub', ← dist_eq_norm_vsub', hxy, hyz, ← add_mul, add_sub_cancel, one_mul] obtain rfl | hne := eq_or_ne x z diff --git a/Mathlib/Analysis/Normed/Group/Basic.lean b/Mathlib/Analysis/Normed/Group/Basic.lean index df7c361a4bcce..4373faf39f635 100644 --- a/Mathlib/Analysis/Normed/Group/Basic.lean +++ b/Mathlib/Analysis/Normed/Group/Basic.lean @@ -387,9 +387,11 @@ theorem dist_one_right (a : E) : dist a 1 = ‖a‖ := by rw [dist_eq_norm_div, theorem inseparable_one_iff_norm {a : E} : Inseparable a 1 ↔ ‖a‖ = 0 := by rw [Metric.inseparable_iff, dist_one_right] +@[to_additive] +lemma dist_one_left (a : E) : dist 1 a = ‖a‖ := by rw [dist_comm, dist_one_right] + @[to_additive (attr := simp)] -theorem dist_one_left : dist (1 : E) = norm := - funext fun a => by rw [dist_comm, dist_one_right] +lemma dist_one : dist (1 : E) = norm := funext dist_one_left @[to_additive] theorem norm_div_rev (a b : E) : ‖a / b‖ = ‖b / a‖ := by diff --git a/Mathlib/Analysis/Normed/Group/Uniform.lean b/Mathlib/Analysis/Normed/Group/Uniform.lean index ca6dd25e1c9bb..d2feee682ef6b 100644 --- a/Mathlib/Analysis/Normed/Group/Uniform.lean +++ b/Mathlib/Analysis/Normed/Group/Uniform.lean @@ -159,7 +159,7 @@ end NNNorm @[to_additive lipschitzWith_one_norm] theorem lipschitzWith_one_norm' : LipschitzWith 1 (norm : E → ℝ) := by - simpa only [dist_one_left] using LipschitzWith.dist_right (1 : E) + simpa using LipschitzWith.dist_right (1 : E) @[to_additive lipschitzWith_one_nnnorm] theorem lipschitzWith_one_nnnorm' : LipschitzWith 1 (NNNorm.nnnorm : E → ℝ≥0) := From fd5d8573758e10450f45d06581db2c3b9859f3ad Mon Sep 17 00:00:00 2001 From: Yoh Tanimoto Date: Mon, 3 Feb 2025 07:17:32 +0000 Subject: [PATCH 018/103] feat(Topology/ContinuousMap/CompactlySupported): left-composition with a continuous map (#21205) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add `compLeft` which gives `g ∘ f : C_c(α, γ)` from `g : C(β, γ)`, `f : C_c(α, β))`. Co-authored-by: Yoh Tanimoto <57562556+yoh-tanimoto@users.noreply.github.com> Co-authored-by: Yaël Dillies --- .../ContinuousMap/CompactlySupported.lean | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Mathlib/Topology/ContinuousMap/CompactlySupported.lean b/Mathlib/Topology/ContinuousMap/CompactlySupported.lean index 331fef8c6d101..f5440f2b7df73 100644 --- a/Mathlib/Topology/ContinuousMap/CompactlySupported.lean +++ b/Mathlib/Topology/ContinuousMap/CompactlySupported.lean @@ -124,6 +124,29 @@ def ContinuousMap.liftCompactlySupported [CompactSpace α] : C(α, β) ≃ C_c( left_inv _ := rfl right_inv _ := rfl +variable {γ : Type*} [TopologicalSpace γ] [Zero γ] + +/-- Composition of a continuous function `f` with compact support with another continuous function +`g` sending `0` to `0` from the left yields another continuous function `g ∘ f` with compact +support. + +If `g` doesn't send `0` to `0`, `f.compLeft g` defaults to `0`. -/ +noncomputable def compLeft (g : C(β, γ)) (f : C_c(α, β)) : C_c(α, γ) where + toContinuousMap := by classical exact if g 0 = 0 then g.comp f else 0 + hasCompactSupport' := by + split_ifs with hg + · exact f.hasCompactSupport'.comp_left hg + · exact .zero + +lemma toContinuousMap_compLeft {g : C(β, γ)} (hg : g 0 = 0) (f : C_c(α, β)) : + (f.compLeft g).toContinuousMap = g.comp f := if_pos hg + +lemma coe_compLeft {g : C(β, γ)} (hg : g 0 = 0) (f : C_c(α, β)) : f.compLeft g = g ∘ f := by + simp [compLeft, if_pos hg] + +lemma compLeft_apply {g : C(β, γ)} (hg : g 0 = 0) (f : C_c(α, β)) (a : α) : + f.compLeft g a = g (f a) := by simp [coe_compLeft hg f] + end Basics /-! ### Algebraic structure From d2ce92331c71671fdab34856c9a723cf83836daf Mon Sep 17 00:00:00 2001 From: Yoh Tanimoto Date: Mon, 3 Feb 2025 07:17:33 +0000 Subject: [PATCH 019/103] feat(Topology/ContinuousMap/CompactlySupported): add `partialOrder` (#21206) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add `instance : PartialOrder C_c(α, β)` using pointwise `PartialOrder β`, following [ContinuousMap.partialOrder](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Topology/ContinuousMap/Ordered.html#ContinuousMap.partialOrder) Co-authored-by: Yoh Tanimoto <57562556+yoh-tanimoto@users.noreply.github.com> --- Mathlib.lean | 1 + Mathlib/Topology/Algebra/Order/Support.lean | 46 +++++++++++ .../ContinuousMap/CompactlySupported.lean | 81 ++++++++++++++++++- 3 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 Mathlib/Topology/Algebra/Order/Support.lean diff --git a/Mathlib.lean b/Mathlib.lean index 824b545b1c456..ab2e8c214463f 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -5284,6 +5284,7 @@ import Mathlib.Topology.Algebra.Order.Field import Mathlib.Topology.Algebra.Order.Floor import Mathlib.Topology.Algebra.Order.Group import Mathlib.Topology.Algebra.Order.LiminfLimsup +import Mathlib.Topology.Algebra.Order.Support import Mathlib.Topology.Algebra.Order.UpperLower import Mathlib.Topology.Algebra.Polynomial import Mathlib.Topology.Algebra.PontryaginDual diff --git a/Mathlib/Topology/Algebra/Order/Support.lean b/Mathlib/Topology/Algebra/Order/Support.lean new file mode 100644 index 0000000000000..bae2dcc6e5b15 --- /dev/null +++ b/Mathlib/Topology/Algebra/Order/Support.lean @@ -0,0 +1,46 @@ +/- +Copyright (c) 2025 Yoh Tanimoto. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yoh Tanimoto +-/ +import Mathlib.Algebra.Order.Group.Indicator +import Mathlib.Topology.Algebra.Support + +/-! +# The topological support of sup and inf of functions + +In a topological space `X` and a space `M` with `Sup` structure, for `f g : X → M` with compact +support, we show that `f ⊔ g` has compact support. Similarly, in `β` with `Inf` structure, `f ⊓ g` +has compact support if so do `f` and `g`. + +-/ + +variable {X M : Type*} [TopologicalSpace X] [One M] + +section SemilatticeSup + +variable [SemilatticeSup M] + +@[to_additive] +theorem HasCompactMulSupport.sup {f g : X → M} (hf : HasCompactMulSupport f) + (hg : HasCompactMulSupport g) : HasCompactMulSupport (f ⊔ g) := by + apply IsCompact.of_isClosed_subset (IsCompact.union hf hg) (isClosed_mulTSupport _) + rw [mulTSupport, mulTSupport, mulTSupport, ← closure_union] + apply closure_mono + exact Function.mulSupport_sup f g + +end SemilatticeSup + +section SemilatticeInf + +variable [SemilatticeInf M] + +@[to_additive] +theorem HasCompactMulSupport.inf {f g : X → M} (hf : HasCompactMulSupport f) + (hg : HasCompactMulSupport g) : HasCompactMulSupport (f ⊓ g) := by + apply IsCompact.of_isClosed_subset (IsCompact.union hf hg) (isClosed_mulTSupport _) + rw [mulTSupport, mulTSupport, mulTSupport, ← closure_union] + apply closure_mono + exact Function.mulSupport_inf f g + +end SemilatticeInf diff --git a/Mathlib/Topology/ContinuousMap/CompactlySupported.lean b/Mathlib/Topology/ContinuousMap/CompactlySupported.lean index f5440f2b7df73..1708d589decf1 100644 --- a/Mathlib/Topology/ContinuousMap/CompactlySupported.lean +++ b/Mathlib/Topology/ContinuousMap/CompactlySupported.lean @@ -3,8 +3,7 @@ Copyright (c) 2024 Yoh Tanimoto. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yoh Tanimoto -/ -import Mathlib.Topology.Algebra.Support -import Mathlib.Topology.ContinuousMap.CocompactMap +import Mathlib.Topology.Algebra.Order.Support import Mathlib.Topology.ContinuousMap.ZeroAtInfty /-! @@ -422,6 +421,84 @@ instance : StarRing C_c(α, β) := end StarRing +section PartialOrder + +/-! ### The partial order in `C_c` +When `β` is equipped with a partial order, `C_c(α, β)` is given the pointwise partial order. +-/ + +variable {β : Type*} [TopologicalSpace β] [Zero β] [PartialOrder β] + +instance partialOrder : PartialOrder C_c(α, β) := PartialOrder.lift (⇑) DFunLike.coe_injective + +theorem le_def {f g : C_c(α, β)} : f ≤ g ↔ ∀ a, f a ≤ g a := Pi.le_def + +theorem lt_def {f g : C_c(α, β)} : f < g ↔ (∀ a, f a ≤ g a) ∧ ∃ a, f a < g a := Pi.lt_def + +end PartialOrder + +section SemilatticeSup + +variable [SemilatticeSup β] [Zero β] [TopologicalSpace β] [ContinuousSup β] + +instance instSup : Max C_c(α, β) where max f g := + { toFun := f ⊔ g + continuous_toFun := Continuous.sup f.continuous g.continuous + hasCompactSupport' := f.hasCompactSupport.sup g.hasCompactSupport } + +@[simp, norm_cast] lemma coe_sup (f g : C_c(α, β)) : ⇑(f ⊔ g) = ⇑f ⊔ g := rfl + +@[simp] lemma sup_apply (f g : C_c(α, β)) (a : α) : (f ⊔ g) a = f a ⊔ g a := rfl + +instance semilatticeSup : SemilatticeSup C_c(α, β) := + DFunLike.coe_injective.semilatticeSup _ coe_sup + +lemma finsetSup'_apply {ι : Type*} {s : Finset ι} (H : s.Nonempty) (f : ι → C_c(α, β)) (a : α) : + s.sup' H f a = s.sup' H fun i ↦ f i a := + Finset.comp_sup'_eq_sup'_comp H (fun g : C_c(α, β) ↦ g a) fun _ _ ↦ rfl + +@[simp, norm_cast] +lemma coe_finsetSup' {ι : Type*} {s : Finset ι} (H : s.Nonempty) (f : ι → C_c(α, β)) : + ⇑(s.sup' H f) = s.sup' H fun i ↦ ⇑(f i) := by ext; simp [finsetSup'_apply] + +end SemilatticeSup + +section SemilatticeInf + +variable [SemilatticeInf β] [Zero β] [TopologicalSpace β] [ContinuousInf β] + +instance instInf : Min C_c(α, β) where min f g := + { toFun := f ⊓ g + continuous_toFun := Continuous.inf f.continuous g.continuous + hasCompactSupport' := f.hasCompactSupport.inf g.hasCompactSupport } + +@[simp, norm_cast] lemma coe_inf (f g : C_c(α, β)) : ⇑(f ⊓ g) = ⇑f ⊓ g := rfl + +@[simp] lemma inf_apply (f g : C_c(α, β)) (a : α) : (f ⊓ g) a = f a ⊓ g a := rfl + +instance semilatticeInf : SemilatticeInf C_c(α, β) := + DFunLike.coe_injective.semilatticeInf _ coe_inf + +lemma finsetInf'_apply {ι : Type*} {s : Finset ι} (H : s.Nonempty) (f : ι → C_c(α, β)) (a : α) : + s.inf' H f a = s.inf' H fun i ↦ f i a := + Finset.comp_inf'_eq_inf'_comp H (fun g : C_c(α, β) ↦ g a) fun _ _ ↦ rfl + +@[simp, norm_cast] +lemma coe_finsetInf' {ι : Type*} {s : Finset ι} (H : s.Nonempty) (f : ι → C_c(α, β)) : + ⇑(s.inf' H f) = s.inf' H fun i ↦ ⇑(f i) := by ext; simp [finsetInf'_apply] + +end SemilatticeInf + +section Lattice + +instance [Lattice β] [TopologicalSpace β] [TopologicalLattice β] [Zero β] : + Lattice C_c(α, β) := + DFunLike.coe_injective.lattice _ coe_sup coe_inf + +-- TODO transfer this lattice structure to `BoundedContinuousFunction` + +end Lattice + /-! ### `C_c` as a functor For each `β` with sufficient structure, there is a contravariant functor `C_c(-, β)` from the From 5968bbe1f8fa045551428b9d991057a8c37ea5a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miyahara=20K=C5=8D?= <52843868+Komyyy@users.noreply.github.com> Date: Mon, 3 Feb 2025 07:17:34 +0000 Subject: [PATCH 020/103] doc(docs/1000.yaml): remove incorrect description (#21248) In my previous PR, I added incorrect description to Smn theorem. `Nat.Partrec'` is different from the definition of usual partial recursive functions, because it does't allow recursion on partial recursive functions. --- docs/1000.yaml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/1000.yaml b/docs/1000.yaml index ca2e502ee182b..cbd2a725c1b8a 100644 --- a/docs/1000.yaml +++ b/docs/1000.yaml @@ -1738,12 +1738,9 @@ Q1765521: Q1766814: title: Smn theorem - decls: - - Nat.Partrec.Code.smn - - Nat.Partrec'.part_iff + decl: Nat.Partrec.Code.smn authors: Mario Carneiro date: 2018 - comment: "This theorem is trivial when using Mathlib's computability definition, but this definition is equivalent to the usual one, as shown in `Nat.Partrec'.part_iff`." Q1785610: title: Poncelet's closure theorem From 9d5ba204c30da91c11ecb9b1d26db2d69bd50392 Mon Sep 17 00:00:00 2001 From: John Talbot Date: Mon, 3 Feb 2025 07:17:35 +0000 Subject: [PATCH 021/103] feat(SimpleGraph/Operations): add edge_comm and lt_sup_edge (#21261) Co-authored-by: Lian Tattersall --- Mathlib/Combinatorics/SimpleGraph/Operations.lean | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Mathlib/Combinatorics/SimpleGraph/Operations.lean b/Mathlib/Combinatorics/SimpleGraph/Operations.lean index 4af95c2d77aa8..05d3c1c45655e 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Operations.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Operations.lean @@ -148,6 +148,9 @@ def edge : SimpleGraph V := fromEdgeSet {s(s, t)} lemma edge_adj (v w : V) : (edge s t).Adj v w ↔ (v = s ∧ w = t ∨ v = t ∧ w = s) ∧ v ≠ w := by rw [edge, fromEdgeSet_adj, Set.mem_singleton_iff, Sym2.eq_iff] +lemma edge_comm : edge s t = edge t s := by + rw [edge, edge, Sym2.eq_swap] + variable [DecidableEq V] in instance : DecidableRel (edge s t).Adj := fun _ _ ↦ by rw [edge_adj]; infer_instance @@ -159,6 +162,9 @@ lemma edge_self_eq_bot : edge s s = ⊥ := by lemma sup_edge_self : G ⊔ edge s s = G := by rw [edge_self_eq_bot, sup_of_le_left bot_le] +lemma lt_sup_edge (hne : s ≠ t) (hn : ¬ G.Adj s t) : G < G ⊔ edge s t := + left_lt_sup.2 fun h ↦ hn <| h <| (edge_adj ..).mpr ⟨Or.inl ⟨rfl, rfl⟩, hne⟩ + variable {s t} lemma edge_edgeSet_of_ne (h : s ≠ t) : (edge s t).edgeSet = {s(s, t)} := by From 600654aa2de1401594e7611a9fd9cd16d152aef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Mon, 3 Feb 2025 07:17:36 +0000 Subject: [PATCH 022/103] feat(Order): Fin.succAboveOrderIso (#21303) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR introduces the order isomorphism `Fin.succAboveOrderIso i : Fin (n + 1) ≃o ({i}ᶜ : Finset (Fin (n + 2)))` for `i : Fin (n + 2)`. --- Mathlib.lean | 1 + Mathlib/Data/Fin/Basic.lean | 11 +++++++ Mathlib/Order/Fin/SuccAboveOrderIso.lean | 37 ++++++++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 Mathlib/Order/Fin/SuccAboveOrderIso.lean diff --git a/Mathlib.lean b/Mathlib.lean index ab2e8c214463f..9c7088c5eedb9 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -4247,6 +4247,7 @@ import Mathlib.Order.Filter.Ultrafilter.Defs import Mathlib.Order.Filter.ZeroAndBoundedAtFilter import Mathlib.Order.Fin.Basic import Mathlib.Order.Fin.Finset +import Mathlib.Order.Fin.SuccAboveOrderIso import Mathlib.Order.Fin.Tuple import Mathlib.Order.FixedPoints import Mathlib.Order.GaloisConnection.Basic diff --git a/Mathlib/Data/Fin/Basic.lean b/Mathlib/Data/Fin/Basic.lean index b06760d8dfe35..41d00bd289761 100644 --- a/Mathlib/Data/Fin/Basic.lean +++ b/Mathlib/Data/Fin/Basic.lean @@ -1265,6 +1265,17 @@ lemma succAbove_predAbove {p : Fin n} {i : Fin (n + 1)} (h : i ≠ castSucc p) : · rw [predAbove_of_le_castSucc _ _ (Fin.le_of_lt h), succAbove_castPred_of_lt _ _ h] · rw [predAbove_of_castSucc_lt _ _ h, succAbove_pred_of_lt _ _ h] +/-- Sending `Fin (n+1)` to `Fin n` by subtracting one from anything above `p` +then back to `Fin (n+1)` with a gap around `p.succ` is the identity away from `p.succ`. -/ +@[simp] +lemma succ_succAbove_predAbove {n : ℕ} {p : Fin n} {i : Fin (n + 1)} (h : i ≠ p.succ) : + p.succ.succAbove (p.predAbove i) = i := by + obtain h | h := Fin.lt_or_lt_of_ne h + · rw [predAbove_of_le_castSucc _ _ (le_castSucc_iff.2 h), + succAbove_castPred_of_lt _ _ h] + · rw [predAbove_of_castSucc_lt _ _ (Fin.lt_of_le_of_lt (p.castSucc_le_succ) h), + succAbove_pred_of_lt _ _ h] + /-- Sending `Fin n` into `Fin (n + 1)` with a gap at `p` then back to `Fin n` by subtracting one from anything above `p` is the identity. -/ @[simp] diff --git a/Mathlib/Order/Fin/SuccAboveOrderIso.lean b/Mathlib/Order/Fin/SuccAboveOrderIso.lean new file mode 100644 index 0000000000000..9f02a2b2448f4 --- /dev/null +++ b/Mathlib/Order/Fin/SuccAboveOrderIso.lean @@ -0,0 +1,37 @@ +/- +Copyright (c) 2024 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ + +import Mathlib.Order.Fin.Basic +import Mathlib.Data.Fintype.Basic +import Mathlib.Tactic.FinCases + +/-! +# The order isomorphism `Fin (n + 1) ≃o {i}ᶜ` + +Given `i : Fin (n + 2)`, we show that `Fin.succAboveOrderEmb` induces +an order isomorphism `Fin (n + 1) ≃o ({i}ᶜ : Finset (Fin (n + 2)))`. + +-/ + +open Finset + +/-- Given `i : Fin (n + 2)`, this is the order isomorphism +between `Fin (n + 1)` and the finite set `{i}ᶜ`. -/ +noncomputable def Fin.succAboveOrderIso {n : ℕ} (i : Fin (n + 2)) : + Fin (n + 1) ≃o ({i}ᶜ : Finset (Fin (n + 2))) where + toEquiv := + Equiv.ofBijective (f := fun a ↦ ⟨Fin.succAboveOrderEmb i a, + by simpa using Fin.succAbove_ne i a⟩) (by + constructor + · intro a b h + exact (Fin.succAboveOrderEmb i).injective (by simpa using h) + · rintro ⟨j, hj⟩ + simp only [mem_compl, mem_singleton] at hj + obtain rfl | ⟨i, rfl⟩ := Fin.eq_zero_or_eq_succ i + · exact ⟨j.pred hj, by simp⟩ + · exact ⟨i.predAbove j, by aesop⟩) + map_rel_iff' {a b} := by + simp only [Equiv.ofBijective_apply, Subtype.mk_le_mk, OrderEmbedding.le_iff_le] From ec5b3790f95d0e5b287046766094c63d68612788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Mon, 3 Feb 2025 07:17:38 +0000 Subject: [PATCH 023/103] refactor(Topology/Constructible): use `QuasiSeparatedSpace` (#21325) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A few lemmas took assumptions of the form`IsTopologicalBasis (range b)` + `∀ i j, IsCompact (b i ∩ b j)`. But this is equivalent to the more natural set of assumptions `IsTopologicalBasis (range b)` + `∀ i, IsCompact (b i)` + `QuasiSeparatedSpace X`. Also link to [Stacks 0069](https://stacks.math.columbia.edu/tag/0069). --- Mathlib/Topology/Constructible.lean | 48 +++++++++++++++------------- Mathlib/Topology/QuasiSeparated.lean | 33 ++++++++++++++----- 2 files changed, 51 insertions(+), 30 deletions(-) diff --git a/Mathlib/Topology/Constructible.lean b/Mathlib/Topology/Constructible.lean index 4ad63357cdd71..5fcb1b6feb84f 100644 --- a/Mathlib/Topology/Constructible.lean +++ b/Mathlib/Topology/Constructible.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ import Mathlib.Order.BooleanSubalgebra +import Mathlib.Topology.QuasiSeparated import Mathlib.Topology.Spectral.Hom /-! @@ -296,10 +297,13 @@ variable [CompactSpace X] {P : ∀ s : Set X, IsConstructible s → Prop} {B : S lemma _root_.IsRetrocompact.isCompact (hs : IsRetrocompact s) : IsCompact s := by simpa using hs CompactSpace.isCompact_univ +variable [QuasiSeparatedSpace X] + /-- Variant of `TopologicalSpace.IsTopologicalBasis.isRetrocompact_iff_isCompact` for a non-indexed topological basis. -/ +@[stacks 0069 "Iff form of (2). Note that Stacks doesn't define quasi-separated spaces."] lemma _root_.TopologicalSpace.IsTopologicalBasis.isRetrocompact_iff_isCompact' - (basis : IsTopologicalBasis B) (compact_inter : ∀ U ∈ B, ∀ V ∈ B, IsCompact (U ∩ V)) + (basis : IsTopologicalBasis B) (isCompact_basis : ∀ U ∈ B, IsCompact U) (hU : IsOpen U) : IsRetrocompact U ↔ IsCompact U := by refine ⟨IsRetrocompact.isCompact, fun hU' {V} hV' hV ↦ ?_⟩ obtain ⟨s, rfl⟩ := eq_sUnion_finset_of_isTopologicalBasis_of_isCompact_open _ basis _ hU' hU @@ -308,43 +312,44 @@ lemma _root_.TopologicalSpace.IsTopologicalBasis.isRetrocompact_iff_isCompact' refine ((s.finite_toSet.image _).prod (t.finite_toSet.image _)).isCompact_biUnion ?_ simp only [mem_prod, mem_image, Finset.mem_coe, Subtype.exists, exists_and_right, exists_eq_right, and_imp, forall_exists_index, Prod.forall] - exact fun u v hu _ hv _ ↦ compact_inter _ hu _ hv + exact fun u v hu _ hv _ ↦ (isCompact_basis _ hu).inter_of_isOpen (isCompact_basis _ hv) + (basis.isOpen hu) (basis.isOpen hv) +@[stacks 0069 "Iff form of (2). Note that Stacks doesn't define quasi-separated spaces."] lemma _root_.TopologicalSpace.IsTopologicalBasis.isRetrocompact_iff_isCompact - (basis : IsTopologicalBasis (range b)) (compact_inter : ∀ i j, IsCompact (b i ∩ b j)) + (basis : IsTopologicalBasis (range b)) (isCompact_basis : ∀ i, IsCompact (b i)) (hU : IsOpen U) : IsRetrocompact U ↔ IsCompact U := - basis.isRetrocompact_iff_isCompact' (by simpa using compact_inter) hU + basis.isRetrocompact_iff_isCompact' (by simpa using isCompact_basis) hU /-- Variant of `TopologicalSpace.IsTopologicalBasis.isRetrocompact` for a non-indexed topological basis. -/ lemma _root_.TopologicalSpace.IsTopologicalBasis.isRetrocompact' (basis : IsTopologicalBasis B) - (compact_inter : ∀ U ∈ B, ∀ V ∈ B, IsCompact (U ∩ V)) (hU : U ∈ B) : IsRetrocompact U := - (basis.isRetrocompact_iff_isCompact' compact_inter <| basis.isOpen hU).2 <| by - simpa using compact_inter _ hU _ hU + (isCompact_basis : ∀ U ∈ B, IsCompact U) (hU : U ∈ B) : IsRetrocompact U := + (basis.isRetrocompact_iff_isCompact' isCompact_basis <| basis.isOpen hU).2 <| isCompact_basis _ hU lemma _root_.TopologicalSpace.IsTopologicalBasis.isRetrocompact - (basis : IsTopologicalBasis (range b)) (compact_inter : ∀ i j, IsCompact (b i ∩ b j)) (i : ι) : + (basis : IsTopologicalBasis (range b)) (isCompact_basis : ∀ i, IsCompact (b i)) (i : ι) : IsRetrocompact (b i) := - (basis.isRetrocompact_iff_isCompact compact_inter <| basis.isOpen <| mem_range_self _).2 <| by - simpa using compact_inter i i + (basis.isRetrocompact_iff_isCompact isCompact_basis <| basis.isOpen <| mem_range_self _).2 <| + isCompact_basis _ /-- Variant of `TopologicalSpace.IsTopologicalBasis.isConstructible` for a non-indexed topological basis. -/ lemma _root_.TopologicalSpace.IsTopologicalBasis.isConstructible' (basis : IsTopologicalBasis B) - (compact_inter : ∀ U ∈ B, ∀ V ∈ B, IsCompact (U ∩ V)) (hU : U ∈ B) : IsConstructible U := - (basis.isRetrocompact' compact_inter hU).isConstructible <| basis.isOpen hU + (isCompact_basis : ∀ U ∈ B, IsCompact U) (hU : U ∈ B) : IsConstructible U := + (basis.isRetrocompact' isCompact_basis hU).isConstructible <| basis.isOpen hU lemma _root_.TopologicalSpace.IsTopologicalBasis.isConstructible - (basis : IsTopologicalBasis (range b)) (compact_inter : ∀ i j, IsCompact (b i ∩ b j)) (i : ι) : + (basis : IsTopologicalBasis (range b)) (isCompact_basis : ∀ i, IsCompact (b i)) (i : ι) : IsConstructible (b i) := - (basis.isRetrocompact compact_inter _).isConstructible <| basis.isOpen <| mem_range_self _ + (basis.isRetrocompact isCompact_basis _).isConstructible <| basis.isOpen <| mem_range_self _ @[elab_as_elim] lemma IsConstructible.induction_of_isTopologicalBasis {ι : Type*} [Nonempty ι] (b : ι → Set X) - (basis : IsTopologicalBasis (range b)) (compact_inter : ∀ i j, IsCompact (b i ∩ b j)) + (basis : IsTopologicalBasis (range b)) (isCompact_basis : ∀ i, IsCompact (b i)) (sdiff : ∀ i s (hs : Set.Finite s), P (b i \ ⋃ j ∈ s, b j) - ((basis.isConstructible compact_inter _).sdiff <| .biUnion hs fun _ _ ↦ - basis.isConstructible compact_inter _)) + ((basis.isConstructible isCompact_basis _).sdiff <| .biUnion hs fun _ _ ↦ + basis.isConstructible isCompact_basis _)) (union : ∀ s hs t ht, P s hs → P t ht → P (s ∪ t) (hs.union ht)) (s : Set X) (hs : IsConstructible s) : P s hs := by induction s, hs using BooleanSubalgebra.closure_sdiff_sup_induction with @@ -354,8 +359,7 @@ lemma IsConstructible.induction_of_isTopologicalBasis {ι : Type*} [Nonempty ι] | bot_mem => exact ⟨isOpen_empty, .empty⟩ | top_mem => exact ⟨isOpen_univ, .univ⟩ | sdiff U hU V hV => - have := isCompact_open_iff_eq_finite_iUnion_of_isTopologicalBasis _ basis - fun i ↦ by simpa using compact_inter i i + have := isCompact_open_iff_eq_finite_iUnion_of_isTopologicalBasis _ basis isCompact_basis obtain ⟨s, hs, rfl⟩ := (this _).1 ⟨hU.2.isCompact, hU.1⟩ obtain ⟨t, ht, rfl⟩ := (this _).1 ⟨hV.2.isCompact, hV.1⟩ simp_rw [iUnion_diff] @@ -364,11 +368,11 @@ lemma IsConstructible.induction_of_isTopologicalBasis {ι : Type*} [Nonempty ι] | @insert i s hi hs ih => simp_rw [biUnion_insert] exact union _ _ _ - (.biUnion hs fun i _ ↦ (basis.isConstructible compact_inter _).sdiff <| - .biUnion ht fun j _ ↦ basis.isConstructible compact_inter _) + (.biUnion hs fun i _ ↦ (basis.isConstructible isCompact_basis _).sdiff <| + .biUnion ht fun j _ ↦ basis.isConstructible isCompact_basis _) (sdiff _ _ ht) (ih ⟨isOpen_biUnion fun _ _ ↦ basis.isOpen ⟨_, rfl⟩, .biUnion hs - fun i _ ↦ basis.isRetrocompact compact_inter _⟩) + fun i _ ↦ basis.isRetrocompact isCompact_basis _⟩) | sup s _ t _ hs' ht' => exact union _ _ _ _ hs' ht' end CompactSpace diff --git a/Mathlib/Topology/QuasiSeparated.lean b/Mathlib/Topology/QuasiSeparated.lean index 26da564a4682f..154b7fe4c1901 100644 --- a/Mathlib/Topology/QuasiSeparated.lean +++ b/Mathlib/Topology/QuasiSeparated.lean @@ -25,8 +25,7 @@ of compact open subsets are still compact. a quasi-separated space, then so is `α`. -/ - -open TopologicalSpace Topology +open Set TopologicalSpace Topology variable {α β : Type*} [TopologicalSpace α] [TopologicalSpace β] {f : α → β} @@ -111,14 +110,32 @@ instance (priority := 100) NoetherianSpace.to_quasiSeparatedSpace [NoetherianSpa QuasiSeparatedSpace α := ⟨fun _ _ _ _ _ _ => NoetherianSpace.isCompact _⟩ -theorem IsQuasiSeparated.of_quasiSeparatedSpace (s : Set α) [QuasiSeparatedSpace α] : - IsQuasiSeparated s := +lemma QuasiSeparatedSpace.of_isTopologicalBasis {ι : Type*} {b : ι → Set α} + (basis : IsTopologicalBasis (range b)) (isCompact_inter : ∀ i j, IsCompact (b i ∩ b j)) : + QuasiSeparatedSpace α where + inter_isCompact U V hUopen hUcomp hVopen hVcomp := by + have aux := isCompact_open_iff_eq_finite_iUnion_of_isTopologicalBasis b basis fun i ↦ by + simpa using isCompact_inter i i + obtain ⟨s, hs, rfl⟩ := (aux _).1 ⟨hUcomp, hUopen⟩ + obtain ⟨t, ht, rfl⟩ := (aux _).1 ⟨hVcomp, hVopen⟩ + rw [iUnion₂_inter_iUnion₂] + exact hs.isCompact_biUnion fun i hi ↦ ht.isCompact_biUnion fun j hj ↦ isCompact_inter .. + +section QuasiSeparatedSpace +variable [QuasiSeparatedSpace α] {U V : Set α} + +lemma IsQuasiSeparated.of_quasiSeparatedSpace (s : Set α) : IsQuasiSeparated s := isQuasiSeparated_univ.of_subset (Set.subset_univ _) -theorem QuasiSeparatedSpace.of_isOpenEmbedding (h : IsOpenEmbedding f) [QuasiSeparatedSpace β] : - QuasiSeparatedSpace α := - isQuasiSeparated_univ_iff.mp - (h.isQuasiSeparated_iff.mpr <| IsQuasiSeparated.of_quasiSeparatedSpace _) +lemma QuasiSeparatedSpace.of_isOpenEmbedding {f : β → α} (h : IsOpenEmbedding f) : + QuasiSeparatedSpace β := + isQuasiSeparated_univ_iff.mp (h.isQuasiSeparated_iff.mpr <| .of_quasiSeparatedSpace _) @[deprecated (since := "2024-10-18")] alias QuasiSeparatedSpace.of_openEmbedding := QuasiSeparatedSpace.of_isOpenEmbedding + +lemma IsCompact.inter_of_isOpen (hUcomp : IsCompact U) (hVcomp : IsCompact V) (hUopen : IsOpen U) + (hVopen : IsOpen V) : IsCompact (U ∩ V) := + QuasiSeparatedSpace.inter_isCompact _ _ hUopen hUcomp hVopen hVcomp + +end QuasiSeparatedSpace From da0385c6b53c7c67ae697b0bc833f0d47e5d007f Mon Sep 17 00:00:00 2001 From: Chris Wong Date: Mon, 3 Feb 2025 07:17:39 +0000 Subject: [PATCH 024/103] chore(Logic/Equiv): change type of `sumEquivSigmaBool` to simp normal form (#21338) `simp` eagerly rewrites `Bool.casesOn` to `Bool.rec`, so using the former in the type signature prevents related `simp` lemmas from firing. See [Zulip discussion](https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/.60.40.5Bsimp.5D.60.20lemmas.20about.20Equiv.2EsumEquivSigmaBool.20don't.20fire). --- Mathlib/Logic/Equiv/Basic.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Logic/Equiv/Basic.lean b/Mathlib/Logic/Equiv/Basic.lean index 42d71d763a324..75b4bbbc81288 100644 --- a/Mathlib/Logic/Equiv/Basic.lean +++ b/Mathlib/Logic/Equiv/Basic.lean @@ -27,7 +27,7 @@ In this file we continue the work on equivalences begun in `Mathlib/Logic/Equiv/ * canonical isomorphisms between various types: e.g., - `Equiv.sumEquivSigmaBool` is the canonical equivalence between the sum of two types `α ⊕ β` - and the sigma-type `Σ b : Bool, b.casesOn α β`; + and the sigma-type `Σ b, bif b then β else α`; - `Equiv.prodSumDistrib : α × (β ⊕ γ) ≃ (α × β) ⊕ (α × γ)` shows that type product and type sum satisfy the distributive law up to a canonical equivalence; @@ -476,7 +476,7 @@ def piOptionEquivProd {α} {β : Option α → Type*} : `β` to be types from the same universe, so it cannot be used directly to transfer theorems about sigma types to theorems about sum types. In many cases one can use `ULift` to work around this difficulty. -/ -def sumEquivSigmaBool (α β) : α ⊕ β ≃ Σ b : Bool, b.casesOn α β := +def sumEquivSigmaBool (α β) : α ⊕ β ≃ Σ b, bif b then β else α := ⟨fun s => s.elim (fun x => ⟨false, x⟩) fun x => ⟨true, x⟩, fun s => match s with | ⟨false, a⟩ => inl a From e6775eae2c7970308672a1674b9dcadb042047ab Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Mon, 3 Feb 2025 08:31:19 +0000 Subject: [PATCH 025/103] feat: principle of isolated zeros for meromorphic functions (#21083) Establish a principle of isolated zeros and show that the set where a meromorphic function has infinite order is clopen in the domain of meromorphy. These theorems are used in [Project VD](https://github.com/kebekus/ProjectVD), which aims to formalize Value Distribution Theory for meromorphic functions on the complex plane. --- Mathlib/Analysis/Analytic/IsolatedZeros.lean | 43 +++++++++ Mathlib/Analysis/Analytic/Meromorphic.lean | 95 +++++++++++++++++++- 2 files changed, 137 insertions(+), 1 deletion(-) diff --git a/Mathlib/Analysis/Analytic/IsolatedZeros.lean b/Mathlib/Analysis/Analytic/IsolatedZeros.lean index 0c12a9fea2373..477f764d36f0e 100644 --- a/Mathlib/Analysis/Analytic/IsolatedZeros.lean +++ b/Mathlib/Analysis/Analytic/IsolatedZeros.lean @@ -345,6 +345,49 @@ theorem eq_of_frequently_eq [ConnectedSpace 𝕜] (hf : AnalyticOnNhd 𝕜 f uni @[deprecated (since := "2024-09-26")] alias _root_.AnalyticOn.eq_of_frequently_eq := eq_of_frequently_eq +/-- The set where an analytic function has infinite order is clopen in its domain of analyticity. -/ +theorem isClopen_setOf_order_eq_top (h₁f : AnalyticOnNhd 𝕜 f U) : + IsClopen { u : U | (h₁f u.1 u.2).order = ⊤ } := by + constructor + · rw [← isOpen_compl_iff, isOpen_iff_forall_mem_open] + intro z hz + rcases (h₁f z.1 z.2).eventually_eq_zero_or_eventually_ne_zero with h | h + · -- Case: f is locally zero in a punctured neighborhood of z + rw [← (h₁f z.1 z.2).order_eq_top_iff] at h + tauto + · -- Case: f is locally nonzero in a punctured neighborhood of z + obtain ⟨t', h₁t', h₂t', h₃t'⟩ := eventually_nhds_iff.1 (eventually_nhdsWithin_iff.1 h) + use Subtype.val ⁻¹' t' + constructor + · intro w hw + simp only [mem_compl_iff, mem_setOf_eq] + by_cases h₁w : w = z + · rwa [h₁w] + · rw [(h₁f _ w.2).order_eq_zero_iff.2 ((h₁t' w hw) (Subtype.coe_ne_coe.mpr h₁w))] + exact ENat.zero_ne_top + · exact ⟨isOpen_induced h₂t', h₃t'⟩ + · apply isOpen_iff_forall_mem_open.mpr + intro z hz + conv => + arg 1; intro; left; right; arg 1; intro + rw [AnalyticAt.order_eq_top_iff, eventually_nhds_iff] + simp only [Set.mem_setOf_eq] at hz + rw [AnalyticAt.order_eq_top_iff, eventually_nhds_iff] at hz + obtain ⟨t', h₁t', h₂t', h₃t'⟩ := hz + use Subtype.val ⁻¹' t' + simp only [Set.mem_compl_iff, Set.mem_singleton_iff, isOpen_induced h₂t', Set.mem_preimage, + h₃t', and_self, and_true] + intro w hw + simp only [mem_setOf_eq] + -- Trivial case: w = z + by_cases h₁w : w = z + · rw [h₁w] + tauto + -- Nontrivial case: w ≠ z + use t' \ {z.1}, fun y h₁y ↦ h₁t' y h₁y.1, h₂t'.sdiff isClosed_singleton + apply (Set.mem_diff w).1 + exact ⟨hw, Set.mem_singleton_iff.not.1 (Subtype.coe_ne_coe.2 h₁w)⟩ + section Mul /-! ### Vanishing of products of analytic functions diff --git a/Mathlib/Analysis/Analytic/Meromorphic.lean b/Mathlib/Analysis/Analytic/Meromorphic.lean index ff69888be1dc2..caf3414b30d5f 100644 --- a/Mathlib/Analysis/Analytic/Meromorphic.lean +++ b/Mathlib/Analysis/Analytic/Meromorphic.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2024 David Loeffler. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: David Loeffler +Authors: David Loeffler, Stefan Kebekus -/ import Mathlib.Analysis.Analytic.IsolatedZeros import Mathlib.Algebra.Order.AddGroupWithTop @@ -35,6 +35,23 @@ lemma AnalyticAt.meromorphicAt {f : 𝕜 → E} {x : 𝕜} (hf : AnalyticAt 𝕜 MeromorphicAt f x := ⟨0, by simpa only [pow_zero, one_smul]⟩ +/- Analogue of the principle of isolated zeros for an analytic function: if a function is +meromorphic at `z₀`, then either it is identically zero in a punctured neighborhood of `z₀`, or it +does not vanish there at all. -/ +theorem MeromorphicAt.eventually_eq_zero_or_eventually_ne_zero {f : 𝕜 → E} {z₀ : 𝕜} + (hf : MeromorphicAt f z₀) : + (∀ᶠ z in 𝓝[≠] z₀, f z = 0) ∨ (∀ᶠ z in 𝓝[≠] z₀, f z ≠ 0) := by + obtain ⟨n, h⟩ := hf + rcases h.eventually_eq_zero_or_eventually_ne_zero with h₁ | h₂ + · left + filter_upwards [nhdsWithin_le_nhds h₁, self_mem_nhdsWithin] with y h₁y h₂y + rcases (smul_eq_zero.1 h₁y) with h₃ | h₄ + · exact False.elim (h₂y (sub_eq_zero.1 (pow_eq_zero_iff'.1 h₃).1)) + · assumption + · right + filter_upwards [h₂, self_mem_nhdsWithin] with y h₁y h₂y + exact (smul_ne_zero_iff.1 h₁y).2 + namespace MeromorphicAt lemma id (x : 𝕜) : MeromorphicAt id x := analyticAt_id.meromorphicAt @@ -334,6 +351,82 @@ lemma id {U : Set 𝕜} : MeromorphicOn id U := fun x _ ↦ .id x lemma const (e : E) {U : Set 𝕜} : MeromorphicOn (fun _ ↦ e) U := fun x _ ↦ .const e x +/-- The set where a meromorphic function has infinite order is clopen in its domain of meromorphy. +-/ +theorem isClopen_setOf_order_eq_top {U : Set 𝕜} (hf : MeromorphicOn f U) : + IsClopen { u : U | (hf u.1 u.2).order = ⊤ } := by + constructor + · rw [← isOpen_compl_iff, isOpen_iff_forall_mem_open] + intro z hz + rcases (hf z.1 z.2).eventually_eq_zero_or_eventually_ne_zero with h | h + · -- Case: f is locally zero in a punctured neighborhood of z + rw [← (hf z.1 z.2).order_eq_top_iff] at h + tauto + · -- Case: f is locally nonzero in a punctured neighborhood of z + obtain ⟨t', h₁t', h₂t', h₃t'⟩ := eventually_nhds_iff.1 (eventually_nhdsWithin_iff.1 h) + use Subtype.val ⁻¹' t' + constructor + · intro w hw + simp only [Set.mem_compl_iff, Set.mem_setOf_eq] + by_cases h₁w : w = z + · rwa [h₁w] + · rw [MeromorphicAt.order_eq_top_iff, not_eventually] + apply Filter.Eventually.frequently + rw [eventually_nhdsWithin_iff, eventually_nhds_iff] + use t' \ {z.1}, fun y h₁y h₂y ↦ h₁t' y h₁y.1 h₁y.2, h₂t'.sdiff isClosed_singleton, hw, + Set.mem_singleton_iff.not.2 (Subtype.coe_ne_coe.mpr h₁w) + · exact ⟨isOpen_induced h₂t', h₃t'⟩ + · apply isOpen_iff_forall_mem_open.mpr + intro z hz + conv => + arg 1; intro; left; right; arg 1; intro + rw [MeromorphicAt.order_eq_top_iff, eventually_nhdsWithin_iff, eventually_nhds_iff] + simp only [Set.mem_setOf_eq] at hz + rw [MeromorphicAt.order_eq_top_iff, eventually_nhdsWithin_iff, eventually_nhds_iff] at hz + obtain ⟨t', h₁t', h₂t', h₃t'⟩ := hz + use Subtype.val ⁻¹' t' + simp only [Set.mem_compl_iff, Set.mem_singleton_iff, isOpen_induced h₂t', Set.mem_preimage, + h₃t', and_self, and_true] + intro w hw + simp only [Set.mem_setOf_eq] + -- Trivial case: w = z + by_cases h₁w : w = z + · rw [h₁w] + tauto + -- Nontrivial case: w ≠ z + use t' \ {z.1}, fun y h₁y _ ↦ h₁t' y (Set.mem_of_mem_diff h₁y) (Set.mem_of_mem_inter_right h₁y) + constructor + · exact h₂t'.sdiff isClosed_singleton + · apply (Set.mem_diff w).1 + exact ⟨hw, Set.mem_singleton_iff.not.1 (Subtype.coe_ne_coe.2 h₁w)⟩ + +/-- On a connected set, there exists a point where a meromorphic function `f` has finite order iff +`f` has finite order at every point. -/ +theorem exists_order_ne_top_iff_forall {U : Set 𝕜} (hf : MeromorphicOn f U) (hU : IsConnected U) : + (∃ u : U, (hf u u.2).order ≠ ⊤) ↔ (∀ u : U, (hf u u.2).order ≠ ⊤) := by + constructor + · intro h₂f + have := isPreconnected_iff_preconnectedSpace.1 hU.isPreconnected + rcases isClopen_iff.1 hf.isClopen_setOf_order_eq_top with h | h + · intro u + have : u ∉ (∅ : Set U) := by exact fun a => a + rw [← h] at this + tauto + · obtain ⟨u, hU⟩ := h₂f + have : u ∈ Set.univ := by trivial + rw [← h] at this + tauto + · intro h₂f + obtain ⟨v, hv⟩ := hU.nonempty + use ⟨v, hv⟩, h₂f ⟨v, hv⟩ + +/-- On a preconnected set, a meromorphic function has finite order at one point if it has finite +order at another point. -/ +theorem order_ne_top_of_isPreconnected {U : Set 𝕜} {x y : 𝕜} (hf : MeromorphicOn f U) + (hU : IsPreconnected U) (h₁x : x ∈ U) (hy : y ∈ U) (h₂x : (hf x h₁x).order ≠ ⊤) : + (hf y hy).order ≠ ⊤ := + (hf.exists_order_ne_top_iff_forall ⟨Set.nonempty_of_mem h₁x, hU⟩).1 (by use ⟨x, h₁x⟩) ⟨y, hy⟩ + section arithmetic include hf in From 347a323db691f7dccd175ebc3d6fab8d0c8b1d82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Staromiejski?= Date: Mon, 3 Feb 2025 08:48:03 +0000 Subject: [PATCH 026/103] refactor(FieldTheory): split `Mathlib.FieldTheory.Purelyinseparable` (#21343) --- Mathlib.lean | 4 +- Mathlib/FieldTheory/CardinalEmb.lean | 2 +- Mathlib/FieldTheory/IsPerfectClosure.lean | 2 +- Mathlib/FieldTheory/JacobsonNoether.lean | 2 +- Mathlib/FieldTheory/PurelyInseparable.lean | 1180 ----------------- .../FieldTheory/PurelyInseparable/Basic.lean | 593 +++++++++ .../PurelyInseparable/PerfectClosure.lean | 410 ++++++ .../FieldTheory/PurelyInseparable/Tower.lean | 242 ++++ Mathlib/RingTheory/Unramified/Field.lean | 2 +- 9 files changed, 1252 insertions(+), 1185 deletions(-) delete mode 100644 Mathlib/FieldTheory/PurelyInseparable.lean create mode 100644 Mathlib/FieldTheory/PurelyInseparable/Basic.lean create mode 100644 Mathlib/FieldTheory/PurelyInseparable/PerfectClosure.lean create mode 100644 Mathlib/FieldTheory/PurelyInseparable/Tower.lean diff --git a/Mathlib.lean b/Mathlib.lean index 9c7088c5eedb9..d8898f42b7fd9 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -3185,7 +3185,9 @@ import Mathlib.FieldTheory.Perfect import Mathlib.FieldTheory.PerfectClosure import Mathlib.FieldTheory.PolynomialGaloisGroup import Mathlib.FieldTheory.PrimitiveElement -import Mathlib.FieldTheory.PurelyInseparable +import Mathlib.FieldTheory.PurelyInseparable.Basic +import Mathlib.FieldTheory.PurelyInseparable.PerfectClosure +import Mathlib.FieldTheory.PurelyInseparable.Tower import Mathlib.FieldTheory.RatFunc.AsPolynomial import Mathlib.FieldTheory.RatFunc.Basic import Mathlib.FieldTheory.RatFunc.Defs diff --git a/Mathlib/FieldTheory/CardinalEmb.lean b/Mathlib/FieldTheory/CardinalEmb.lean index 3f51c66e061a4..307b1bf0c022c 100644 --- a/Mathlib/FieldTheory/CardinalEmb.lean +++ b/Mathlib/FieldTheory/CardinalEmb.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Junyan Xu -/ import Mathlib.FieldTheory.SeparableClosure -import Mathlib.FieldTheory.PurelyInseparable +import Mathlib.FieldTheory.PurelyInseparable.Basic import Mathlib.LinearAlgebra.FreeAlgebra import Mathlib.Order.Interval.Set.WithBotTop import Mathlib.Order.DirectedInverseSystem diff --git a/Mathlib/FieldTheory/IsPerfectClosure.lean b/Mathlib/FieldTheory/IsPerfectClosure.lean index db75df108ee8c..247993e778f5f 100644 --- a/Mathlib/FieldTheory/IsPerfectClosure.lean +++ b/Mathlib/FieldTheory/IsPerfectClosure.lean @@ -3,7 +3,7 @@ Copyright (c) 2024 Jz Pan. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jz Pan -/ -import Mathlib.FieldTheory.PurelyInseparable +import Mathlib.FieldTheory.PurelyInseparable.Basic import Mathlib.FieldTheory.PerfectClosure /-! diff --git a/Mathlib/FieldTheory/JacobsonNoether.lean b/Mathlib/FieldTheory/JacobsonNoether.lean index e019eaf9f4231..44f523cd54a23 100644 --- a/Mathlib/FieldTheory/JacobsonNoether.lean +++ b/Mathlib/FieldTheory/JacobsonNoether.lean @@ -8,7 +8,7 @@ import Mathlib.Algebra.CharP.LinearMaps import Mathlib.Algebra.CharP.Subring import Mathlib.Algebra.GroupWithZero.Conj import Mathlib.Algebra.Lie.OfAssociative -import Mathlib.FieldTheory.PurelyInseparable +import Mathlib.FieldTheory.PurelyInseparable.Basic /-! # The Jacobson-Noether theorem diff --git a/Mathlib/FieldTheory/PurelyInseparable.lean b/Mathlib/FieldTheory/PurelyInseparable.lean deleted file mode 100644 index e38f330fe860d..0000000000000 --- a/Mathlib/FieldTheory/PurelyInseparable.lean +++ /dev/null @@ -1,1180 +0,0 @@ -/- -Copyright (c) 2024 Jz Pan. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Jz Pan --/ -import Mathlib.Algebra.CharP.ExpChar -import Mathlib.Algebra.CharP.IntermediateField -import Mathlib.FieldTheory.SeparableClosure - -/-! - -# Purely inseparable extension and relative perfect closure - -This file contains basics about purely inseparable extensions and the relative perfect closure -of fields. - -## Main definitions - -- `IsPurelyInseparable`: typeclass for purely inseparable field extensions: an algebraic extension - `E / F` is purely inseparable if and only if the minimal polynomial of every element of `E ∖ F` - is not separable. - -- `perfectClosure`: the relative perfect closure of `F` in `E`, it consists of the elements - `x` of `E` such that there exists a natural number `n` such that `x ^ (ringExpChar F) ^ n` - is contained in `F`, where `ringExpChar F` is the exponential characteristic of `F`. - It is also the maximal purely inseparable subextension of `E / F` (`le_perfectClosure_iff`). - -## Main results - -- `IsPurelyInseparable.surjective_algebraMap_of_isSeparable`, - `IsPurelyInseparable.bijective_algebraMap_of_isSeparable`, - `IntermediateField.eq_bot_of_isPurelyInseparable_of_isSeparable`: - if `E / F` is both purely inseparable and separable, then `algebraMap F E` is surjective - (hence bijective). In particular, if an intermediate field of `E / F` is both purely inseparable - and separable, then it is equal to `F`. - -- `isPurelyInseparable_iff_pow_mem`: a field extension `E / F` of exponential characteristic `q` is - purely inseparable if and only if for every element `x` of `E`, there exists a natural number `n` - such that `x ^ (q ^ n)` is contained in `F`. - -- `IsPurelyInseparable.trans`: if `E / F` and `K / E` are both purely inseparable extensions, then - `K / F` is also purely inseparable. - -- `isPurelyInseparable_iff_natSepDegree_eq_one`: `E / F` is purely inseparable if and only if for - every element `x` of `E`, its minimal polynomial has separable degree one. - -- `isPurelyInseparable_iff_minpoly_eq_X_pow_sub_C`: a field extension `E / F` of exponential - characteristic `q` is purely inseparable if and only if for every element `x` of `E`, the minimal - polynomial of `x` over `F` is of form `X ^ (q ^ n) - y` for some natural number `n` and some - element `y` of `F`. - -- `isPurelyInseparable_iff_minpoly_eq_X_sub_C_pow`: a field extension `E / F` of exponential - characteristic `q` is purely inseparable if and only if for every element `x` of `E`, the minimal - polynomial of `x` over `F` is of form `(X - x) ^ (q ^ n)` for some natural number `n`. - -- `isPurelyInseparable_iff_finSepDegree_eq_one`: an extension is purely inseparable - if and only if it has finite separable degree (`Field.finSepDegree`) one. - -- `IsPurelyInseparable.normal`: a purely inseparable extension is normal. - -- `separableClosure.isPurelyInseparable`: if `E / F` is algebraic, then `E` is purely inseparable - over the separable closure of `F` in `E`. - -- `separableClosure_le_iff`: if `E / F` is algebraic, then an intermediate field of `E / F` contains - the separable closure of `F` in `E` if and only if `E` is purely inseparable over it. - -- `eq_separableClosure_iff`: if `E / F` is algebraic, then an intermediate field of `E / F` is equal - to the separable closure of `F` in `E` if and only if it is separable over `F`, and `E` - is purely inseparable over it. - -- `le_perfectClosure_iff`: an intermediate field of `E / F` is contained in the relative perfect - closure of `F` in `E` if and only if it is purely inseparable over `F`. - -- `perfectClosure.perfectRing`, `perfectClosure.perfectField`: if `E` is a perfect field, then the - (relative) perfect closure `perfectClosure F E` is perfect. - -- `IsPurelyInseparable.injective_comp_algebraMap`: if `E / F` is purely inseparable, then for any - reduced ring `L`, the map `(E →+* L) → (F →+* L)` induced by `algebraMap F E` is injective. - In particular, a purely inseparable field extension is an epimorphism in the category of fields. - -- `IsPurelyInseparable.of_injective_comp_algebraMap`: if `L` is an algebraically closed field - containing `E`, such that the map `(E →+* L) → (F →+* L)` induced by `algebraMap F E` is - injective, then `E / F` is purely inseparable. As a corollary, epimorphisms in the category of - fields must be purely inseparable extensions. - -- `IntermediateField.isPurelyInseparable_adjoin_iff_pow_mem`: if `F` is of exponential - characteristic `q`, then `F(S) / F` is a purely inseparable extension if and only if for any - `x ∈ S`, `x ^ (q ^ n)` is contained in `F` for some `n : ℕ`. - -- `Field.finSepDegree_eq`: if `E / F` is algebraic, then the `Field.finSepDegree F E` is equal to - `Field.sepDegree F E` as a natural number. This means that the cardinality of `Field.Emb F E` - and the degree of `(separableClosure F E) / F` are both finite or infinite, and when they are - finite, they coincide. - -- `Field.finSepDegree_mul_finInsepDegree`: the finite separable degree multiply by the finite - inseparable degree is equal to the (finite) field extension degree. - -- `Field.lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic`: the separable degrees satisfy the - tower law: $[E:F]_s [K:E]_s = [K:F]_s$. - -- `IntermediateField.sepDegree_adjoin_eq_of_isAlgebraic_of_isPurelyInseparable`, - `IntermediateField.sepDegree_adjoin_eq_of_isAlgebraic_of_isPurelyInseparable'`: - if `K / E / F` is a field extension tower, such that `E / F` is purely inseparable, then - for any subset `S` of `K` such that `F(S) / F` is algebraic, the `E(S) / E` and `F(S) / F` have - the same separable degree. In particular, if `S` is an intermediate field of `K / F` such that - `S / F` is algebraic, the `E(S) / E` and `S / F` have the same separable degree. - -- `minpoly.map_eq_of_isSeparable_of_isPurelyInseparable`: if `K / E / F` is a field extension tower, - such that `E / F` is purely inseparable, then for any element `x` of `K` separable over `F`, - it has the same minimal polynomials over `F` and over `E`. - -- `Polynomial.Separable.map_irreducible_of_isPurelyInseparable`: if `E / F` is purely inseparable, - `f` is a separable irreducible polynomial over `F`, then it is also irreducible over `E`. - -## Tags - -separable degree, degree, separable closure, purely inseparable - -## TODO - -- Restate some intermediate result in terms of linearly disjointness. - -- Prove that the inseparable degrees satisfy the tower law: $[E:F]_i [K:E]_i = [K:F]_i$. - Probably an argument using linearly disjointness is needed. - --/ - -open Module Polynomial IntermediateField Field Finsupp - -noncomputable section - -universe u v w - -section IsPurelyInseparable - -variable (F : Type u) (E : Type v) [CommRing F] [Ring E] [Algebra F E] -variable (K : Type w) [Ring K] [Algebra F K] - -/-- Typeclass for purely inseparable field extensions: an algebraic extension `E / F` is purely -inseparable if and only if the minimal polynomial of every element of `E ∖ F` is not separable. - -We define this for general (commutative) rings and only assume `F` and `E` are fields -if this is needed for a proof. -/ -class IsPurelyInseparable : Prop where - isIntegral : Algebra.IsIntegral F E - inseparable' (x : E) : IsSeparable F x → x ∈ (algebraMap F E).range - -attribute [instance] IsPurelyInseparable.isIntegral - -variable {E} in -theorem IsPurelyInseparable.isIntegral' [IsPurelyInseparable F E] (x : E) : IsIntegral F x := - Algebra.IsIntegral.isIntegral _ - -theorem IsPurelyInseparable.isAlgebraic [Nontrivial F] [IsPurelyInseparable F E] : - Algebra.IsAlgebraic F E := inferInstance - -variable {E} - -theorem IsPurelyInseparable.inseparable [IsPurelyInseparable F E] : - ∀ x : E, IsSeparable F x → x ∈ (algebraMap F E).range := - IsPurelyInseparable.inseparable' - -variable {F K} - -theorem isPurelyInseparable_iff : IsPurelyInseparable F E ↔ ∀ x : E, - IsIntegral F x ∧ (IsSeparable F x → x ∈ (algebraMap F E).range) := - ⟨fun h x ↦ ⟨h.isIntegral' _ x, h.inseparable' x⟩, fun h ↦ ⟨⟨fun x ↦ (h x).1⟩, fun x ↦ (h x).2⟩⟩ - -/-- Transfer `IsPurelyInseparable` across an `AlgEquiv`. -/ -theorem AlgEquiv.isPurelyInseparable (e : K ≃ₐ[F] E) [IsPurelyInseparable F K] : - IsPurelyInseparable F E := by - refine ⟨⟨fun _ ↦ by rw [← isIntegral_algEquiv e.symm]; exact IsPurelyInseparable.isIntegral' F _⟩, - fun x h ↦ ?_⟩ - rw [IsSeparable, ← minpoly.algEquiv_eq e.symm] at h - simpa only [RingHom.mem_range, algebraMap_eq_apply] using IsPurelyInseparable.inseparable F _ h - -theorem AlgEquiv.isPurelyInseparable_iff (e : K ≃ₐ[F] E) : - IsPurelyInseparable F K ↔ IsPurelyInseparable F E := - ⟨fun _ ↦ e.isPurelyInseparable, fun _ ↦ e.symm.isPurelyInseparable⟩ - -/-- If `E / F` is an algebraic extension, `F` is separably closed, -then `E / F` is purely inseparable. -/ -instance Algebra.IsAlgebraic.isPurelyInseparable_of_isSepClosed - {F : Type u} {E : Type v} [Field F] [Ring E] [IsDomain E] [Algebra F E] - [Algebra.IsAlgebraic F E] - [IsSepClosed F] : IsPurelyInseparable F E := - ⟨inferInstance, fun x h ↦ minpoly.mem_range_of_degree_eq_one F x <| - IsSepClosed.degree_eq_one_of_irreducible F (minpoly.irreducible - (Algebra.IsIntegral.isIntegral _)) h⟩ - -variable (F E K) - -/-- If `E / F` is both purely inseparable and separable, then `algebraMap F E` is surjective. -/ -theorem IsPurelyInseparable.surjective_algebraMap_of_isSeparable - [IsPurelyInseparable F E] [Algebra.IsSeparable F E] : Function.Surjective (algebraMap F E) := - fun x ↦ IsPurelyInseparable.inseparable F x (Algebra.IsSeparable.isSeparable F x) - -/-- If `E / F` is both purely inseparable and separable, then `algebraMap F E` is bijective. -/ -theorem IsPurelyInseparable.bijective_algebraMap_of_isSeparable - [Nontrivial E] [NoZeroSMulDivisors F E] - [IsPurelyInseparable F E] [Algebra.IsSeparable F E] : Function.Bijective (algebraMap F E) := - ⟨NoZeroSMulDivisors.algebraMap_injective F E, surjective_algebraMap_of_isSeparable F E⟩ - -variable {F E} in -/-- If a subalgebra of `E / F` is both purely inseparable and separable, then it is equal -to `F`. -/ -theorem Subalgebra.eq_bot_of_isPurelyInseparable_of_isSeparable (L : Subalgebra F E) - [IsPurelyInseparable F L] [Algebra.IsSeparable F L] : L = ⊥ := bot_unique fun x hx ↦ by - obtain ⟨y, hy⟩ := IsPurelyInseparable.surjective_algebraMap_of_isSeparable F L ⟨x, hx⟩ - exact ⟨y, congr_arg (Subalgebra.val _) hy⟩ - -/-- If an intermediate field of `E / F` is both purely inseparable and separable, then it is equal -to `F`. -/ -theorem IntermediateField.eq_bot_of_isPurelyInseparable_of_isSeparable - {F : Type u} {E : Type v} [Field F] [Field E] [Algebra F E] (L : IntermediateField F E) - [IsPurelyInseparable F L] [Algebra.IsSeparable F L] : L = ⊥ := bot_unique fun x hx ↦ by - obtain ⟨y, hy⟩ := IsPurelyInseparable.surjective_algebraMap_of_isSeparable F L ⟨x, hx⟩ - exact ⟨y, congr_arg (algebraMap L E) hy⟩ - -/-- If `E / F` is purely inseparable, then the separable closure of `F` in `E` is -equal to `F`. -/ -theorem separableClosure.eq_bot_of_isPurelyInseparable - (F : Type u) (E : Type v) [Field F] [Field E] [Algebra F E] [IsPurelyInseparable F E] : - separableClosure F E = ⊥ := - bot_unique fun x h ↦ IsPurelyInseparable.inseparable F x (mem_separableClosure_iff.1 h) - -/-- If `E / F` is an algebraic extension, then the separable closure of `F` in `E` is -equal to `F` if and only if `E / F` is purely inseparable. -/ -theorem separableClosure.eq_bot_iff - {F : Type u} {E : Type v} [Field F] [Field E] [Algebra F E] [Algebra.IsAlgebraic F E] : - separableClosure F E = ⊥ ↔ IsPurelyInseparable F E := - ⟨fun h ↦ isPurelyInseparable_iff.2 fun x ↦ ⟨Algebra.IsIntegral.isIntegral x, fun hs ↦ by - simpa only [h] using mem_separableClosure_iff.2 hs⟩, fun _ ↦ eq_bot_of_isPurelyInseparable F E⟩ - -instance isPurelyInseparable_self : IsPurelyInseparable F F := - ⟨inferInstance, fun x _ ↦ ⟨x, rfl⟩⟩ - -section - -variable (F : Type u) {E : Type v} [Field F] [Ring E] [IsDomain E] [Algebra F E] -variable (q : ℕ) [ExpChar F q] (x : E) - -/-- A field extension `E / F` of exponential characteristic `q` is purely inseparable -if and only if for every element `x` of `E`, there exists a natural number `n` such that -`x ^ (q ^ n)` is contained in `F`. -/ -@[stacks 09HE] -theorem isPurelyInseparable_iff_pow_mem : - IsPurelyInseparable F E ↔ ∀ x : E, ∃ n : ℕ, x ^ q ^ n ∈ (algebraMap F E).range := by - rw [isPurelyInseparable_iff] - refine ⟨fun h x ↦ ?_, fun h x ↦ ?_⟩ - · obtain ⟨g, h1, n, h2⟩ := (minpoly.irreducible (h x).1).hasSeparableContraction q - exact ⟨n, (h _).2 <| h1.of_dvd <| minpoly.dvd F _ <| by - simpa only [expand_aeval, minpoly.aeval] using congr_arg (aeval x) h2⟩ - have hdeg := (minpoly.natSepDegree_eq_one_iff_pow_mem q).2 (h x) - have halg : IsIntegral F x := by_contra fun h' ↦ by - simp only [minpoly.eq_zero h', natSepDegree_zero, zero_ne_one] at hdeg - refine ⟨halg, fun hsep ↦ ?_⟩ - rwa [hsep.natSepDegree_eq_natDegree, minpoly.natDegree_eq_one_iff] at hdeg - -theorem IsPurelyInseparable.pow_mem [IsPurelyInseparable F E] : - ∃ n : ℕ, x ^ q ^ n ∈ (algebraMap F E).range := - (isPurelyInseparable_iff_pow_mem F q).1 ‹_› x - -end - -end IsPurelyInseparable - -variable (F : Type u) (E : Type v) [Field F] [Field E] [Algebra F E] -variable (K : Type w) [Field K] [Algebra F K] - -section perfectClosure - -/-- The relative perfect closure of `F` in `E`, consists of the elements `x` of `E` such that there -exists a natural number `n` such that `x ^ (ringExpChar F) ^ n` is contained in `F`, where -`ringExpChar F` is the exponential characteristic of `F`. It is also the maximal purely inseparable -subextension of `E / F` (`le_perfectClosure_iff`). -/ -@[stacks 09HH] -def perfectClosure : IntermediateField F E where - carrier := {x : E | ∃ n : ℕ, x ^ (ringExpChar F) ^ n ∈ (algebraMap F E).range} - add_mem' := by - rintro x y ⟨n, hx⟩ ⟨m, hy⟩ - use n + m - have := expChar_of_injective_algebraMap (algebraMap F E).injective (ringExpChar F) - rw [add_pow_expChar_pow, pow_add, pow_mul, mul_comm (_ ^ n), pow_mul] - exact add_mem (pow_mem hx _) (pow_mem hy _) - mul_mem' := by - rintro x y ⟨n, hx⟩ ⟨m, hy⟩ - use n + m - rw [mul_pow, pow_add, pow_mul, mul_comm (_ ^ n), pow_mul] - exact mul_mem (pow_mem hx _) (pow_mem hy _) - inv_mem' := by - rintro x ⟨n, hx⟩ - use n; rw [inv_pow] - apply inv_mem (id hx : _ ∈ (⊥ : IntermediateField F E)) - algebraMap_mem' := fun x ↦ ⟨0, by rw [pow_zero, pow_one]; exact ⟨x, rfl⟩⟩ - -variable {F E} - -theorem mem_perfectClosure_iff {x : E} : - x ∈ perfectClosure F E ↔ ∃ n : ℕ, x ^ (ringExpChar F) ^ n ∈ (algebraMap F E).range := Iff.rfl - -theorem mem_perfectClosure_iff_pow_mem (q : ℕ) [ExpChar F q] {x : E} : - x ∈ perfectClosure F E ↔ ∃ n : ℕ, x ^ q ^ n ∈ (algebraMap F E).range := by - rw [mem_perfectClosure_iff, ringExpChar.eq F q] - -/-- An element is contained in the relative perfect closure if and only if its minimal polynomial -has separable degree one. -/ -theorem mem_perfectClosure_iff_natSepDegree_eq_one {x : E} : - x ∈ perfectClosure F E ↔ (minpoly F x).natSepDegree = 1 := by - rw [mem_perfectClosure_iff, minpoly.natSepDegree_eq_one_iff_pow_mem (ringExpChar F)] - -/-- A field extension `E / F` is purely inseparable if and only if the relative perfect closure of -`F` in `E` is equal to `E`. -/ -theorem isPurelyInseparable_iff_perfectClosure_eq_top : - IsPurelyInseparable F E ↔ perfectClosure F E = ⊤ := by - rw [isPurelyInseparable_iff_pow_mem F (ringExpChar F)] - exact ⟨fun H ↦ top_unique fun x _ ↦ H x, fun H _ ↦ H.ge trivial⟩ - -variable (F E) - -/-- The relative perfect closure of `F` in `E` is purely inseparable over `F`. -/ -instance perfectClosure.isPurelyInseparable : IsPurelyInseparable F (perfectClosure F E) := by - rw [isPurelyInseparable_iff_pow_mem F (ringExpChar F)] - exact fun ⟨_, n, y, h⟩ ↦ ⟨n, y, (algebraMap _ E).injective h⟩ - -/-- The relative perfect closure of `F` in `E` is algebraic over `F`. -/ -instance perfectClosure.isAlgebraic : Algebra.IsAlgebraic F (perfectClosure F E) := - IsPurelyInseparable.isAlgebraic F _ - -/-- If `E / F` is separable, then the perfect closure of `F` in `E` is equal to `F`. Note that - the converse is not necessarily true (see https://math.stackexchange.com/a/3009197) - even when `E / F` is algebraic. -/ -theorem perfectClosure.eq_bot_of_isSeparable [Algebra.IsSeparable F E] : perfectClosure F E = ⊥ := - haveI := Algebra.isSeparable_tower_bot_of_isSeparable F (perfectClosure F E) E - eq_bot_of_isPurelyInseparable_of_isSeparable _ - -/-- An intermediate field of `E / F` is contained in the relative perfect closure of `F` in `E` -if it is purely inseparable over `F`. -/ -theorem le_perfectClosure (L : IntermediateField F E) [h : IsPurelyInseparable F L] : - L ≤ perfectClosure F E := by - rw [isPurelyInseparable_iff_pow_mem F (ringExpChar F)] at h - intro x hx - obtain ⟨n, y, hy⟩ := h ⟨x, hx⟩ - exact ⟨n, y, congr_arg (algebraMap L E) hy⟩ - -/-- An intermediate field of `E / F` is contained in the relative perfect closure of `F` in `E` -if and only if it is purely inseparable over `F`. -/ -theorem le_perfectClosure_iff (L : IntermediateField F E) : - L ≤ perfectClosure F E ↔ IsPurelyInseparable F L := by - refine ⟨fun h ↦ (isPurelyInseparable_iff_pow_mem F (ringExpChar F)).2 fun x ↦ ?_, - fun _ ↦ le_perfectClosure F E L⟩ - obtain ⟨n, y, hy⟩ := h x.2 - exact ⟨n, y, (algebraMap L E).injective hy⟩ - -theorem separableClosure_inf_perfectClosure : separableClosure F E ⊓ perfectClosure F E = ⊥ := - haveI := (le_separableClosure_iff F E _).mp (inf_le_left (b := perfectClosure F E)) - haveI := (le_perfectClosure_iff F E _).mp (inf_le_right (a := separableClosure F E)) - eq_bot_of_isPurelyInseparable_of_isSeparable _ - -section map - -variable {F E K} - -/-- If `i` is an `F`-algebra homomorphism from `E` to `K`, then `i x` is contained in -`perfectClosure F K` if and only if `x` is contained in `perfectClosure F E`. -/ -theorem map_mem_perfectClosure_iff (i : E →ₐ[F] K) {x : E} : - i x ∈ perfectClosure F K ↔ x ∈ perfectClosure F E := by - simp_rw [mem_perfectClosure_iff] - refine ⟨fun ⟨n, y, h⟩ ↦ ⟨n, y, ?_⟩, fun ⟨n, y, h⟩ ↦ ⟨n, y, ?_⟩⟩ - · apply_fun i using i.injective - rwa [AlgHom.commutes, map_pow] - simpa only [AlgHom.commutes, map_pow] using congr_arg i h - -/-- If `i` is an `F`-algebra homomorphism from `E` to `K`, then the preimage of `perfectClosure F K` -under the map `i` is equal to `perfectClosure F E`. -/ -theorem perfectClosure.comap_eq_of_algHom (i : E →ₐ[F] K) : - (perfectClosure F K).comap i = perfectClosure F E := by - ext x - exact map_mem_perfectClosure_iff i - -/-- If `i` is an `F`-algebra homomorphism from `E` to `K`, then the image of `perfectClosure F E` -under the map `i` is contained in `perfectClosure F K`. -/ -theorem perfectClosure.map_le_of_algHom (i : E →ₐ[F] K) : - (perfectClosure F E).map i ≤ perfectClosure F K := - map_le_iff_le_comap.mpr (perfectClosure.comap_eq_of_algHom i).ge - -/-- If `i` is an `F`-algebra isomorphism of `E` and `K`, then the image of `perfectClosure F E` -under the map `i` is equal to in `perfectClosure F K`. -/ -theorem perfectClosure.map_eq_of_algEquiv (i : E ≃ₐ[F] K) : - (perfectClosure F E).map i.toAlgHom = perfectClosure F K := - (map_le_of_algHom i.toAlgHom).antisymm (fun x hx ↦ ⟨i.symm x, - (map_mem_perfectClosure_iff i.symm.toAlgHom).2 hx, i.right_inv x⟩) - -/-- If `E` and `K` are isomorphic as `F`-algebras, then `perfectClosure F E` and -`perfectClosure F K` are also isomorphic as `F`-algebras. -/ -def perfectClosure.algEquivOfAlgEquiv (i : E ≃ₐ[F] K) : - perfectClosure F E ≃ₐ[F] perfectClosure F K := - (intermediateFieldMap i _).trans (equivOfEq (map_eq_of_algEquiv i)) - -alias AlgEquiv.perfectClosure := perfectClosure.algEquivOfAlgEquiv - -end map - -/-- If `E` is a perfect field of exponential characteristic `p`, then the (relative) perfect closure -`perfectClosure F E` is perfect. -/ -instance perfectClosure.perfectRing (p : ℕ) [ExpChar E p] - [PerfectRing E p] : PerfectRing (perfectClosure F E) p := .ofSurjective _ p fun x ↦ by - haveI := RingHom.expChar _ (algebraMap F E).injective p - obtain ⟨x', hx⟩ := surjective_frobenius E p x.1 - obtain ⟨n, y, hy⟩ := (mem_perfectClosure_iff_pow_mem p).1 x.2 - rw [frobenius_def] at hx - rw [← hx, ← pow_mul, ← pow_succ'] at hy - exact ⟨⟨x', (mem_perfectClosure_iff_pow_mem p).2 ⟨n + 1, y, hy⟩⟩, by - simp_rw [frobenius_def, SubmonoidClass.mk_pow, hx]⟩ - -/-- If `E` is a perfect field, then the (relative) perfect closure -`perfectClosure F E` is perfect. -/ -instance perfectClosure.perfectField [PerfectField E] : PerfectField (perfectClosure F E) := - PerfectRing.toPerfectField _ (ringExpChar E) - -end perfectClosure - -section IsPurelyInseparable - -/-- If `K / E / F` is a field extension tower such that `K / F` is purely inseparable, -then `E / F` is also purely inseparable. -/ -theorem IsPurelyInseparable.tower_bot [Algebra E K] [IsScalarTower F E K] - [IsPurelyInseparable F K] : IsPurelyInseparable F E := by - refine ⟨⟨fun x ↦ (isIntegral' F (algebraMap E K x)).tower_bot_of_field⟩, fun x h ↦ ?_⟩ - rw [IsSeparable, ← minpoly.algebraMap_eq (algebraMap E K).injective] at h - obtain ⟨y, h⟩ := inseparable F _ h - exact ⟨y, (algebraMap E K).injective (h.symm ▸ (IsScalarTower.algebraMap_apply F E K y).symm)⟩ - -/-- If `K / E / F` is a field extension tower such that `K / F` is purely inseparable, -then `K / E` is also purely inseparable. -/ -theorem IsPurelyInseparable.tower_top [Algebra E K] [IsScalarTower F E K] - [h : IsPurelyInseparable F K] : IsPurelyInseparable E K := by - obtain ⟨q, _⟩ := ExpChar.exists F - haveI := expChar_of_injective_algebraMap (algebraMap F E).injective q - rw [isPurelyInseparable_iff_pow_mem _ q] at h ⊢ - intro x - obtain ⟨n, y, h⟩ := h x - exact ⟨n, (algebraMap F E) y, h.symm ▸ (IsScalarTower.algebraMap_apply F E K y).symm⟩ - -/-- If `E / F` and `K / E` are both purely inseparable extensions, then `K / F` is also -purely inseparable. -/ -@[stacks 02JJ "See also 00GM"] -theorem IsPurelyInseparable.trans [Algebra E K] [IsScalarTower F E K] - [h1 : IsPurelyInseparable F E] [h2 : IsPurelyInseparable E K] : IsPurelyInseparable F K := by - obtain ⟨q, _⟩ := ExpChar.exists F - haveI := expChar_of_injective_algebraMap (algebraMap F E).injective q - rw [isPurelyInseparable_iff_pow_mem _ q] at h1 h2 ⊢ - intro x - obtain ⟨n, y, h2⟩ := h2 x - obtain ⟨m, z, h1⟩ := h1 y - refine ⟨n + m, z, ?_⟩ - rw [IsScalarTower.algebraMap_apply F E K, h1, map_pow, h2, ← pow_mul, ← pow_add] - -namespace IntermediateField - -variable (M : IntermediateField F K) - -instance isPurelyInseparable_tower_bot [IsPurelyInseparable F K] : IsPurelyInseparable F M := - IsPurelyInseparable.tower_bot F M K - -instance isPurelyInseparable_tower_top [IsPurelyInseparable F K] : IsPurelyInseparable M K := - IsPurelyInseparable.tower_top F M K - -end IntermediateField - -variable {E} - -/-- A field extension `E / F` is purely inseparable if and only if for every element `x` of `E`, -its minimal polynomial has separable degree one. -/ -theorem isPurelyInseparable_iff_natSepDegree_eq_one : - IsPurelyInseparable F E ↔ ∀ x : E, (minpoly F x).natSepDegree = 1 := by - obtain ⟨q, _⟩ := ExpChar.exists F - simp_rw [isPurelyInseparable_iff_pow_mem F q, minpoly.natSepDegree_eq_one_iff_pow_mem q] - -theorem IsPurelyInseparable.natSepDegree_eq_one [IsPurelyInseparable F E] (x : E) : - (minpoly F x).natSepDegree = 1 := - (isPurelyInseparable_iff_natSepDegree_eq_one F).1 ‹_› x - -/-- A field extension `E / F` of exponential characteristic `q` is purely inseparable -if and only if for every element `x` of `E`, the minimal polynomial of `x` over `F` is of form -`X ^ (q ^ n) - y` for some natural number `n` and some element `y` of `F`. -/ -theorem isPurelyInseparable_iff_minpoly_eq_X_pow_sub_C (q : ℕ) [hF : ExpChar F q] : - IsPurelyInseparable F E ↔ ∀ x : E, ∃ (n : ℕ) (y : F), minpoly F x = X ^ q ^ n - C y := by - simp_rw [isPurelyInseparable_iff_natSepDegree_eq_one, - minpoly.natSepDegree_eq_one_iff_eq_X_pow_sub_C q] - -theorem IsPurelyInseparable.minpoly_eq_X_pow_sub_C (q : ℕ) [ExpChar F q] [IsPurelyInseparable F E] - (x : E) : ∃ (n : ℕ) (y : F), minpoly F x = X ^ q ^ n - C y := - (isPurelyInseparable_iff_minpoly_eq_X_pow_sub_C F q).1 ‹_› x - -/-- A field extension `E / F` of exponential characteristic `q` is purely inseparable -if and only if for every element `x` of `E`, the minimal polynomial of `x` over `F` is of form -`(X - x) ^ (q ^ n)` for some natural number `n`. -/ -theorem isPurelyInseparable_iff_minpoly_eq_X_sub_C_pow (q : ℕ) [hF : ExpChar F q] : - IsPurelyInseparable F E ↔ - ∀ x : E, ∃ n : ℕ, (minpoly F x).map (algebraMap F E) = (X - C x) ^ q ^ n := by - simp_rw [isPurelyInseparable_iff_natSepDegree_eq_one, - minpoly.natSepDegree_eq_one_iff_eq_X_sub_C_pow q] - -theorem IsPurelyInseparable.minpoly_eq_X_sub_C_pow (q : ℕ) [ExpChar F q] [IsPurelyInseparable F E] - (x : E) : ∃ n : ℕ, (minpoly F x).map (algebraMap F E) = (X - C x) ^ q ^ n := - (isPurelyInseparable_iff_minpoly_eq_X_sub_C_pow F q).1 ‹_› x - -variable (E) - -variable {F E} in -/-- If an extension has finite separable degree one, then it is purely inseparable. -/ -theorem isPurelyInseparable_of_finSepDegree_eq_one - (hdeg : finSepDegree F E = 1) : IsPurelyInseparable F E := by - by_cases H : Algebra.IsAlgebraic F E - · rw [isPurelyInseparable_iff] - refine fun x ↦ ⟨Algebra.IsIntegral.isIntegral x, fun hsep ↦ ?_⟩ - have : Algebra.IsAlgebraic F⟮x⟯ E := Algebra.IsAlgebraic.tower_top (K := F) F⟮x⟯ - have := finSepDegree_mul_finSepDegree_of_isAlgebraic F F⟮x⟯ E - rw [hdeg, mul_eq_one, (finSepDegree_adjoin_simple_eq_finrank_iff F E x - (Algebra.IsAlgebraic.isAlgebraic x)).2 hsep, - IntermediateField.finrank_eq_one_iff] at this - simpa only [this.1] using mem_adjoin_simple_self F x - · rw [← Algebra.transcendental_iff_not_isAlgebraic] at H - simp [finSepDegree_eq_zero_of_transcendental F E] at hdeg - -namespace IsPurelyInseparable - -variable [IsPurelyInseparable F E] (R L : Type*) [CommSemiring R] [Algebra R F] [Algebra R E] - -/-- If `E / F` is purely inseparable, then for any reduced ring `L`, the map `(E →+* L) → (F →+* L)` -induced by `algebraMap F E` is injective. In particular, a purely inseparable field extension -is an epimorphism in the category of fields. -/ -theorem injective_comp_algebraMap [CommRing L] [IsReduced L] : - Function.Injective fun f : E →+* L ↦ f.comp (algebraMap F E) := fun f g heq ↦ by - ext x - let q := ringExpChar F - obtain ⟨n, y, h⟩ := IsPurelyInseparable.pow_mem F q x - replace heq := congr($heq y) - simp_rw [RingHom.comp_apply, h, map_pow] at heq - nontriviality L - haveI := expChar_of_injective_ringHom (f.comp (algebraMap F E)).injective q - exact iterateFrobenius_inj L q n heq - -theorem injective_restrictDomain [CommRing L] [IsReduced L] [Algebra R L] [IsScalarTower R F E] : - Function.Injective (AlgHom.restrictDomain (A := R) F (C := E) (D := L)) := fun _ _ eq ↦ - AlgHom.coe_ringHom_injective <| injective_comp_algebraMap F E L <| congr_arg AlgHom.toRingHom eq - -instance [Field L] [PerfectField L] [Algebra F L] : Nonempty (E →ₐ[F] L) := - nonempty_algHom_of_splits fun x ↦ ⟨IsPurelyInseparable.isIntegral' _ _, - have ⟨q, _⟩ := ExpChar.exists F - PerfectField.splits_of_natSepDegree_eq_one (algebraMap F L) - ((minpoly.natSepDegree_eq_one_iff_eq_X_pow_sub_C q).mpr <| - IsPurelyInseparable.minpoly_eq_X_pow_sub_C F q x)⟩ - -theorem bijective_comp_algebraMap [Field L] [PerfectField L] : - Function.Bijective fun f : E →+* L ↦ f.comp (algebraMap F E) := - ⟨injective_comp_algebraMap F E L, fun g ↦ let _ := g.toAlgebra - ⟨_, (Classical.arbitrary <| E →ₐ[F] L).comp_algebraMap⟩⟩ - -theorem bijective_restrictDomain [Field L] [PerfectField L] [Algebra R L] [IsScalarTower R F E] : - Function.Bijective (AlgHom.restrictDomain (A := R) F (C := E) (D := L)) := - ⟨injective_restrictDomain F E R L, fun g ↦ let _ := g.toAlgebra - let f := Classical.arbitrary (E →ₐ[F] L) - ⟨f.restrictScalars R, AlgHom.coe_ringHom_injective f.comp_algebraMap⟩⟩ - -end IsPurelyInseparable - -/-- If `E / F` is purely inseparable, then for any reduced `F`-algebra `L`, there exists at most one -`F`-algebra homomorphism from `E` to `L`. -/ -instance instSubsingletonAlgHomOfIsPurelyInseparable [IsPurelyInseparable F E] (L : Type w) - [CommRing L] [IsReduced L] [Algebra F L] : Subsingleton (E →ₐ[F] L) where - allEq f g := AlgHom.coe_ringHom_injective <| - IsPurelyInseparable.injective_comp_algebraMap F E L (by simp_rw [AlgHom.comp_algebraMap]) - -instance instUniqueAlgHomOfIsPurelyInseparable [IsPurelyInseparable F E] (L : Type w) - [CommRing L] [IsReduced L] [Algebra F L] [Algebra E L] [IsScalarTower F E L] : - Unique (E →ₐ[F] L) := uniqueOfSubsingleton (IsScalarTower.toAlgHom F E L) - -/-- If `E / F` is purely inseparable, then `Field.Emb F E` has exactly one element. -/ -instance instUniqueEmbOfIsPurelyInseparable [IsPurelyInseparable F E] : - Unique (Emb F E) := instUniqueAlgHomOfIsPurelyInseparable F E _ - -/-- A purely inseparable extension has finite separable degree one. -/ -theorem IsPurelyInseparable.finSepDegree_eq_one [IsPurelyInseparable F E] : - finSepDegree F E = 1 := Nat.card_unique - -/-- A purely inseparable extension has separable degree one. -/ -theorem IsPurelyInseparable.sepDegree_eq_one [IsPurelyInseparable F E] : - sepDegree F E = 1 := by - rw [sepDegree, separableClosure.eq_bot_of_isPurelyInseparable, IntermediateField.rank_bot] - -/-- A purely inseparable extension has inseparable degree equal to degree. -/ -theorem IsPurelyInseparable.insepDegree_eq [IsPurelyInseparable F E] : - insepDegree F E = Module.rank F E := by - rw [insepDegree, separableClosure.eq_bot_of_isPurelyInseparable, rank_bot'] - -/-- A purely inseparable extension has finite inseparable degree equal to degree. -/ -theorem IsPurelyInseparable.finInsepDegree_eq [IsPurelyInseparable F E] : - finInsepDegree F E = finrank F E := congr(Cardinal.toNat $(insepDegree_eq F E)) - -/-- An extension is purely inseparable if and only if it has finite separable degree one. -/ -theorem isPurelyInseparable_iff_finSepDegree_eq_one : - IsPurelyInseparable F E ↔ finSepDegree F E = 1 := - ⟨fun _ ↦ IsPurelyInseparable.finSepDegree_eq_one F E, - fun h ↦ isPurelyInseparable_of_finSepDegree_eq_one h⟩ - -variable {F E} in -/-- An algebraic extension is purely inseparable if and only if all of its finite dimensional -subextensions are purely inseparable. -/ -theorem isPurelyInseparable_iff_fd_isPurelyInseparable [Algebra.IsAlgebraic F E] : - IsPurelyInseparable F E ↔ - ∀ L : IntermediateField F E, FiniteDimensional F L → IsPurelyInseparable F L := by - refine ⟨fun _ _ _ ↦ IsPurelyInseparable.tower_bot F _ E, - fun h ↦ isPurelyInseparable_iff.2 fun x ↦ ?_⟩ - have hx : IsIntegral F x := Algebra.IsIntegral.isIntegral x - refine ⟨hx, fun _ ↦ ?_⟩ - obtain ⟨y, h⟩ := (h _ (adjoin.finiteDimensional hx)).inseparable' _ <| - show Separable (minpoly F (AdjoinSimple.gen F x)) by rwa [minpoly_eq] - exact ⟨y, congr_arg (algebraMap _ E) h⟩ - -/-- A purely inseparable extension is normal. -/ -instance IsPurelyInseparable.normal [IsPurelyInseparable F E] : Normal F E where - toIsAlgebraic := isAlgebraic F E - splits' x := by - obtain ⟨n, h⟩ := IsPurelyInseparable.minpoly_eq_X_sub_C_pow F (ringExpChar F) x - rw [← splits_id_iff_splits, h] - exact splits_pow _ (splits_X_sub_C _) _ - -/-- If `E / F` is algebraic, then `E` is purely inseparable over the -separable closure of `F` in `E`. -/ -@[stacks 030K "$E/E_{sep}$ is purely inseparable."] -instance separableClosure.isPurelyInseparable [Algebra.IsAlgebraic F E] : - IsPurelyInseparable (separableClosure F E) E := isPurelyInseparable_iff.2 fun x ↦ by - set L := separableClosure F E - refine ⟨(IsAlgebraic.tower_top L (Algebra.IsAlgebraic.isAlgebraic (R := F) x)).isIntegral, - fun h ↦ ?_⟩ - haveI := (isSeparable_adjoin_simple_iff_isSeparable L E).2 h - haveI : Algebra.IsSeparable F (restrictScalars F L⟮x⟯) := Algebra.IsSeparable.trans F L L⟮x⟯ - have hx : x ∈ restrictScalars F L⟮x⟯ := mem_adjoin_simple_self _ x - exact ⟨⟨x, mem_separableClosure_iff.2 <| isSeparable_of_mem_isSeparable F E hx⟩, rfl⟩ - -open Cardinal in -theorem Field.Emb.cardinal_separableClosure [Algebra.IsAlgebraic F E] : - #(Field.Emb F <| separableClosure F E) = #(Field.Emb F E) := by - rw [← (embProdEmbOfIsAlgebraic F (separableClosure F E) E).cardinal_eq, - mk_prod, mk_eq_one (Emb _ E), lift_one, mul_one, lift_id] - -/-- An intermediate field of `E / F` contains the separable closure of `F` in `E` -if `E` is purely inseparable over it. -/ -theorem separableClosure_le (L : IntermediateField F E) - [h : IsPurelyInseparable L E] : separableClosure F E ≤ L := fun x hx ↦ by - obtain ⟨y, rfl⟩ := h.inseparable' _ <| - IsSeparable.tower_top L (mem_separableClosure_iff.1 hx) - exact y.2 - -/-- If `E / F` is algebraic, then an intermediate field of `E / F` contains the -separable closure of `F` in `E` if and only if `E` is purely inseparable over it. -/ -theorem separableClosure_le_iff [Algebra.IsAlgebraic F E] (L : IntermediateField F E) : - separableClosure F E ≤ L ↔ IsPurelyInseparable L E := by - refine ⟨fun h ↦ ?_, fun _ ↦ separableClosure_le F E L⟩ - have := separableClosure.isPurelyInseparable F E - letI := (inclusion h).toAlgebra - letI : SMul (separableClosure F E) L := Algebra.toSMul - haveI : IsScalarTower (separableClosure F E) L E := IsScalarTower.of_algebraMap_eq (congrFun rfl) - exact IsPurelyInseparable.tower_top (separableClosure F E) L E - -/-- If an intermediate field of `E / F` is separable over `F`, and `E` is purely inseparable -over it, then it is equal to the separable closure of `F` in `E`. -/ -theorem eq_separableClosure (L : IntermediateField F E) - [Algebra.IsSeparable F L] [IsPurelyInseparable L E] : L = separableClosure F E := - le_antisymm (le_separableClosure F E L) (separableClosure_le F E L) - -open separableClosure in -/-- If `E / F` is algebraic, then an intermediate field of `E / F` is equal to the separable closure -of `F` in `E` if and only if it is separable over `F`, and `E` is purely inseparable -over it. -/ -theorem eq_separableClosure_iff [Algebra.IsAlgebraic F E] (L : IntermediateField F E) : - L = separableClosure F E ↔ Algebra.IsSeparable F L ∧ IsPurelyInseparable L E := - ⟨by rintro rfl; exact ⟨isSeparable F E, isPurelyInseparable F E⟩, - fun ⟨_, _⟩ ↦ eq_separableClosure F E L⟩ - -/-- If `L` is an algebraically closed field containing `E`, such that the map -`(E →+* L) → (F →+* L)` induced by `algebraMap F E` is injective, then `E / F` is -purely inseparable. As a corollary, epimorphisms in the category of fields must be -purely inseparable extensions. -/ -theorem IsPurelyInseparable.of_injective_comp_algebraMap (L : Type w) [Field L] [IsAlgClosed L] - [Nonempty (E →+* L)] (h : Function.Injective fun f : E →+* L ↦ f.comp (algebraMap F E)) : - IsPurelyInseparable F E := by - rw [isPurelyInseparable_iff_finSepDegree_eq_one, finSepDegree, Nat.card_eq_one_iff_unique] - letI := (Classical.arbitrary (E →+* L)).toAlgebra - let j : AlgebraicClosure E →ₐ[E] L := IsAlgClosed.lift - exact ⟨⟨fun f g ↦ DFunLike.ext' <| j.injective.comp_left (congr_arg (⇑) <| - @h (j.toRingHom.comp f) (j.toRingHom.comp g) (by ext; simp))⟩, inferInstance⟩ - -end IsPurelyInseparable - -namespace IntermediateField - -instance isPurelyInseparable_bot : IsPurelyInseparable F (⊥ : IntermediateField F E) := - (botEquiv F E).symm.isPurelyInseparable - -/-- `F⟮x⟯ / F` is a purely inseparable extension if and only if the minimal polynomial of `x` -has separable degree one. -/ -theorem isPurelyInseparable_adjoin_simple_iff_natSepDegree_eq_one {x : E} : - IsPurelyInseparable F F⟮x⟯ ↔ (minpoly F x).natSepDegree = 1 := by - rw [← le_perfectClosure_iff, adjoin_simple_le_iff, mem_perfectClosure_iff_natSepDegree_eq_one] - -/-- If `F` is of exponential characteristic `q`, then `F⟮x⟯ / F` is a purely inseparable extension -if and only if `x ^ (q ^ n)` is contained in `F` for some `n : ℕ`. -/ -theorem isPurelyInseparable_adjoin_simple_iff_pow_mem (q : ℕ) [hF : ExpChar F q] {x : E} : - IsPurelyInseparable F F⟮x⟯ ↔ ∃ n : ℕ, x ^ q ^ n ∈ (algebraMap F E).range := by - rw [← le_perfectClosure_iff, adjoin_simple_le_iff, mem_perfectClosure_iff_pow_mem q] - -/-- If `F` is of exponential characteristic `q`, then `F(S) / F` is a purely inseparable extension -if and only if for any `x ∈ S`, `x ^ (q ^ n)` is contained in `F` for some `n : ℕ`. -/ -theorem isPurelyInseparable_adjoin_iff_pow_mem (q : ℕ) [hF : ExpChar F q] {S : Set E} : - IsPurelyInseparable F (adjoin F S) ↔ ∀ x ∈ S, ∃ n : ℕ, x ^ q ^ n ∈ (algebraMap F E).range := by - simp_rw [← le_perfectClosure_iff, adjoin_le_iff, ← mem_perfectClosure_iff_pow_mem q, - Set.subset_def, SetLike.mem_coe] - -/-- A compositum of two purely inseparable extensions is purely inseparable. -/ -instance isPurelyInseparable_sup (L1 L2 : IntermediateField F E) - [h1 : IsPurelyInseparable F L1] [h2 : IsPurelyInseparable F L2] : - IsPurelyInseparable F (L1 ⊔ L2 : IntermediateField F E) := by - rw [← le_perfectClosure_iff] at h1 h2 ⊢ - exact sup_le h1 h2 - -/-- A compositum of purely inseparable extensions is purely inseparable. -/ -instance isPurelyInseparable_iSup {ι : Sort*} {t : ι → IntermediateField F E} - [h : ∀ i, IsPurelyInseparable F (t i)] : - IsPurelyInseparable F (⨆ i, t i : IntermediateField F E) := by - simp_rw [← le_perfectClosure_iff] at h ⊢ - exact iSup_le h - -/-- If `F` is a field of exponential characteristic `q`, `F(S) / F` is separable, then -`F(S) = F(S ^ (q ^ n))` for any natural number `n`. -/ -theorem adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable (S : Set E) - [Algebra.IsSeparable F (adjoin F S)] (q : ℕ) [ExpChar F q] (n : ℕ) : - adjoin F S = adjoin F ((· ^ q ^ n) '' S) := by - set L := adjoin F S - set M := adjoin F ((· ^ q ^ n) '' S) - have hi : M ≤ L := by - rw [adjoin_le_iff] - rintro _ ⟨y, hy, rfl⟩ - exact pow_mem (subset_adjoin F S hy) _ - letI := (inclusion hi).toAlgebra - haveI : Algebra.IsSeparable M (extendScalars hi) := - Algebra.isSeparable_tower_top_of_isSeparable F M L - haveI : IsPurelyInseparable M (extendScalars hi) := by - haveI := expChar_of_injective_algebraMap (algebraMap F M).injective q - rw [extendScalars_adjoin hi, isPurelyInseparable_adjoin_iff_pow_mem M _ q] - exact fun x hx ↦ ⟨n, ⟨x ^ q ^ n, subset_adjoin F _ ⟨x, hx, rfl⟩⟩, rfl⟩ - simpa only [extendScalars_restrictScalars, restrictScalars_bot_eq_self] using congr_arg - (restrictScalars F) (extendScalars hi).eq_bot_of_isPurelyInseparable_of_isSeparable - -/-- If `E / F` is a separable field extension of exponential characteristic `q`, then -`F(S) = F(S ^ (q ^ n))` for any subset `S` of `E` and any natural number `n`. -/ -theorem adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable' [Algebra.IsSeparable F E] (S : Set E) - (q : ℕ) [ExpChar F q] (n : ℕ) : adjoin F S = adjoin F ((· ^ q ^ n) '' S) := - haveI := Algebra.isSeparable_tower_bot_of_isSeparable F (adjoin F S) E - adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable F E S q n - --- TODO: prove the converse when `F(S) / F` is finite -/-- If `F` is a field of exponential characteristic `q`, `F(S) / F` is separable, then -`F(S) = F(S ^ q)`. -/ -theorem adjoin_eq_adjoin_pow_expChar_of_isSeparable (S : Set E) [Algebra.IsSeparable F (adjoin F S)] - (q : ℕ) [ExpChar F q] : adjoin F S = adjoin F ((· ^ q) '' S) := - pow_one q ▸ adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable F E S q 1 - -/-- If `E / F` is a separable field extension of exponential characteristic `q`, then -`F(S) = F(S ^ q)` for any subset `S` of `E`. -/ -theorem adjoin_eq_adjoin_pow_expChar_of_isSeparable' [Algebra.IsSeparable F E] (S : Set E) - (q : ℕ) [ExpChar F q] : adjoin F S = adjoin F ((· ^ q) '' S) := - pow_one q ▸ adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable' F E S q 1 - --- Special cases for simple adjoin - -/-- If `F` is a field of exponential characteristic `q`, `a : E` is separable over `F`, then -`F⟮a⟯ = F⟮a ^ q ^ n⟯` for any natural number `n`. -/ -theorem adjoin_simple_eq_adjoin_pow_expChar_pow_of_isSeparable {a : E} (ha : IsSeparable F a) - (q : ℕ) [ExpChar F q] (n : ℕ) : F⟮a⟯ = F⟮a ^ q ^ n⟯ := by - haveI := (isSeparable_adjoin_simple_iff_isSeparable F E).mpr ha - simpa using adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable F E {a} q n - -/-- If `E / F` is a separable field extension of exponential characteristic `q`, then -`F⟮a⟯ = F⟮a ^ q ^ n⟯` for any subset `a : E` and any natural number `n`. -/ -theorem adjoin_simple_eq_adjoin_pow_expChar_pow_of_isSeparable' [Algebra.IsSeparable F E] (a : E) - (q : ℕ) [ExpChar F q] (n : ℕ) : F⟮a⟯ = F⟮a ^ q ^ n⟯ := by - haveI := Algebra.isSeparable_tower_bot_of_isSeparable F F⟮a⟯ E - simpa using adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable F E {a} q n - -/-- If `F` is a field of exponential characteristic `q`, `a : E` is separable over `F`, then -`F⟮a⟯ = F⟮a ^ q⟯`. -/ -theorem adjoin_simple_eq_adjoin_pow_expChar_of_isSeparable {a : E} (ha : IsSeparable F a) - (q : ℕ) [ExpChar F q] : F⟮a⟯ = F⟮a ^ q⟯ := - pow_one q ▸ adjoin_simple_eq_adjoin_pow_expChar_pow_of_isSeparable F E ha q 1 - -/-- If `E / F` is a separable field extension of exponential characteristic `q`, then -`F⟮a⟯ = F⟮a ^ q⟯` for any `a : E`. -/ -theorem adjoin_simple_eq_adjoin_pow_expChar_of_isSeparable' [Algebra.IsSeparable F E] (a : E) - (q : ℕ) [ExpChar F q] : F⟮a⟯ = F⟮a ^ q⟯ := - pow_one q ▸ adjoin_simple_eq_adjoin_pow_expChar_pow_of_isSeparable' F E a q 1 - -end IntermediateField - -section - -variable (q n : ℕ) [hF : ExpChar F q] {ι : Type*} {v : ι → E} {F E} - -/-- If `E / F` is a separable extension of exponential characteristic `q`, if `{ u_i }` is a family -of elements of `E` which `F`-linearly spans `E`, then `{ u_i ^ (q ^ n) }` also `F`-linearly spans -`E` for any natural number `n`. -/ -theorem Field.span_map_pow_expChar_pow_eq_top_of_isSeparable [Algebra.IsSeparable F E] - (h : Submodule.span F (Set.range v) = ⊤) : - Submodule.span F (Set.range (v · ^ q ^ n)) = ⊤ := by - erw [← Algebra.top_toSubmodule, ← top_toSubalgebra, ← adjoin_univ, - adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable' F E _ q n, - adjoin_algebraic_toSubalgebra fun x _ ↦ Algebra.IsAlgebraic.isAlgebraic x, - Set.image_univ, Algebra.adjoin_eq_span, (powMonoidHom _).mrange.closure_eq] - refine (Submodule.span_mono <| Set.range_comp_subset_range _ _).antisymm (Submodule.span_le.2 ?_) - rw [Set.range_comp, ← Set.image_univ] - haveI := expChar_of_injective_algebraMap (algebraMap F E).injective q - apply h ▸ Submodule.image_span_subset_span (LinearMap.iterateFrobenius F E q n) _ - -/-- If `E / F` is a finite separable extension of exponential characteristic `q`, if `{ u_i }` is a -family of elements of `E` which is `F`-linearly independent, then `{ u_i ^ (q ^ n) }` is also -`F`-linearly independent for any natural number `n`. A special case of -`LinearIndependent.map_pow_expChar_pow_of_isSeparable` -and is an intermediate result used to prove it. -/ -private theorem LinearIndependent.map_pow_expChar_pow_of_fd_isSeparable - [FiniteDimensional F E] [Algebra.IsSeparable F E] - (h : LinearIndependent F v) : LinearIndependent F (v · ^ q ^ n) := by - have h' := h.coe_range - let ι' := h'.extend (Set.range v).subset_univ - let b : Basis ι' F E := Basis.extend h' - letI : Fintype ι' := FiniteDimensional.fintypeBasisIndex b - have H := linearIndependent_of_top_le_span_of_card_eq_finrank - (span_map_pow_expChar_pow_eq_top_of_isSeparable q n b.span_eq).ge - (finrank_eq_card_basis b).symm - let f (i : ι) : ι' := ⟨v i, h'.subset_extend _ ⟨i, rfl⟩⟩ - convert H.comp f fun _ _ heq ↦ h.injective (by simpa only [f, Subtype.mk.injEq] using heq) - simp_rw [Function.comp_apply, b] - rw [Basis.extend_apply_self] - -/-- If `E / F` is a separable extension of exponential characteristic `q`, if `{ u_i }` is a -family of elements of `E` which is `F`-linearly independent, then `{ u_i ^ (q ^ n) }` is also -`F`-linearly independent for any natural number `n`. -/ -theorem LinearIndependent.map_pow_expChar_pow_of_isSeparable [Algebra.IsSeparable F E] - (h : LinearIndependent F v) : LinearIndependent F (v · ^ q ^ n) := by - classical - have halg := Algebra.IsSeparable.isAlgebraic F E - rw [linearIndependent_iff_finset_linearIndependent] at h ⊢ - intro s - let E' := adjoin F (s.image v : Set E) - haveI : FiniteDimensional F E' := finiteDimensional_adjoin - fun x _ ↦ Algebra.IsIntegral.isIntegral x - haveI : Algebra.IsSeparable F E' := Algebra.isSeparable_tower_bot_of_isSeparable F E' E - let v' (i : s) : E' := ⟨v i.1, subset_adjoin F _ (Finset.mem_image.2 ⟨i.1, i.2, rfl⟩)⟩ - have h' : LinearIndependent F v' := (h s).of_comp E'.val.toLinearMap - exact (h'.map_pow_expChar_pow_of_fd_isSeparable q n).map' - E'.val.toLinearMap (LinearMap.ker_eq_bot_of_injective E'.val.injective) - -/-- If `E / F` is a field extension of exponential characteristic `q`, if `{ u_i }` is a -family of separable elements of `E` which is `F`-linearly independent, then `{ u_i ^ (q ^ n) }` -is also `F`-linearly independent for any natural number `n`. -/ -theorem LinearIndependent.map_pow_expChar_pow_of_isSeparable' - (hsep : ∀ i : ι, IsSeparable F (v i)) - (h : LinearIndependent F v) : LinearIndependent F (v · ^ q ^ n) := by - let E' := adjoin F (Set.range v) - haveI : Algebra.IsSeparable F E' := (isSeparable_adjoin_iff_isSeparable F _).2 <| by - rintro _ ⟨y, rfl⟩; exact hsep y - let v' (i : ι) : E' := ⟨v i, subset_adjoin F _ ⟨i, rfl⟩⟩ - have h' : LinearIndependent F v' := h.of_comp E'.val.toLinearMap - exact (h'.map_pow_expChar_pow_of_isSeparable q n).map' - E'.val.toLinearMap (LinearMap.ker_eq_bot_of_injective E'.val.injective) - -/-- If `E / F` is a separable extension of exponential characteristic `q`, if `{ u_i }` is an -`F`-basis of `E`, then `{ u_i ^ (q ^ n) }` is also an `F`-basis of `E` -for any natural number `n`. -/ -def Basis.mapPowExpCharPowOfIsSeparable [Algebra.IsSeparable F E] - (b : Basis ι F E) : Basis ι F E := - Basis.mk (b.linearIndependent.map_pow_expChar_pow_of_isSeparable q n) - (span_map_pow_expChar_pow_eq_top_of_isSeparable q n b.span_eq).ge - -end - -/-- If `E` is an algebraic closure of `F`, then `F` is separably closed if and only if `E / F` is -purely inseparable. -/ -theorem isSepClosed_iff_isPurelyInseparable_algebraicClosure [IsAlgClosure F E] : - IsSepClosed F ↔ IsPurelyInseparable F E := - ⟨fun _ ↦ inferInstance, fun H ↦ by - haveI := IsAlgClosure.isAlgClosed F (K := E) - rwa [← separableClosure.eq_bot_iff, IsSepClosed.separableClosure_eq_bot_iff] at H⟩ - -variable {F E} in -/-- If `E / F` is an algebraic extension, `F` is separably closed, -then `E` is also separably closed. -/ -theorem Algebra.IsAlgebraic.isSepClosed [Algebra.IsAlgebraic F E] - [IsSepClosed F] : IsSepClosed E := - have : Algebra.IsAlgebraic F (AlgebraicClosure E) := Algebra.IsAlgebraic.trans (L := E) - (isSepClosed_iff_isPurelyInseparable_algebraicClosure E _).mpr - (IsPurelyInseparable.tower_top F E <| AlgebraicClosure E) - -theorem perfectField_of_perfectClosure_eq_bot [h : PerfectField E] (eq : perfectClosure F E = ⊥) : - PerfectField F := by - let p := ringExpChar F - haveI := expChar_of_injective_algebraMap (algebraMap F E).injective p - haveI := PerfectRing.ofSurjective F p fun x ↦ by - obtain ⟨y, h⟩ := surjective_frobenius E p (algebraMap F E x) - have : y ∈ perfectClosure F E := ⟨1, x, by rw [← h, pow_one, frobenius_def, ringExpChar.eq F p]⟩ - obtain ⟨z, rfl⟩ := eq ▸ this - exact ⟨z, (algebraMap F E).injective (by erw [RingHom.map_frobenius, h])⟩ - exact PerfectRing.toPerfectField F p - -/-- If `E / F` is a separable extension, `E` is perfect, then `F` is also prefect. -/ -theorem perfectField_of_isSeparable_of_perfectField_top [Algebra.IsSeparable F E] [PerfectField E] : - PerfectField F := - perfectField_of_perfectClosure_eq_bot F E (perfectClosure.eq_bot_of_isSeparable F E) - -/-- If `E` is an algebraic closure of `F`, then `F` is perfect if and only if `E / F` is -separable. -/ -theorem perfectField_iff_isSeparable_algebraicClosure [IsAlgClosure F E] : - PerfectField F ↔ Algebra.IsSeparable F E := - ⟨fun _ ↦ IsSepClosure.separable, fun _ ↦ haveI : IsAlgClosed E := IsAlgClosure.isAlgClosed F - perfectField_of_isSeparable_of_perfectField_top F E⟩ - -namespace Field - -/-- If `E / F` is algebraic, then the `Field.finSepDegree F E` is equal to `Field.sepDegree F E` -as a natural number. This means that the cardinality of `Field.Emb F E` and the degree of -`(separableClosure F E) / F` are both finite or infinite, and when they are finite, they -coincide. -/ -@[stacks 09HJ "`sepDegree` is defined as the right hand side of 09HJ"] -theorem finSepDegree_eq [Algebra.IsAlgebraic F E] : - finSepDegree F E = Cardinal.toNat (sepDegree F E) := by - have : Algebra.IsAlgebraic (separableClosure F E) E := Algebra.IsAlgebraic.tower_top (K := F) _ - have h := finSepDegree_mul_finSepDegree_of_isAlgebraic F (separableClosure F E) E |>.symm - haveI := separableClosure.isSeparable F E - haveI := separableClosure.isPurelyInseparable F E - rwa [finSepDegree_eq_finrank_of_isSeparable F (separableClosure F E), - IsPurelyInseparable.finSepDegree_eq_one (separableClosure F E) E, mul_one] at h - -/-- The finite separable degree multiply by the finite inseparable degree is equal -to the (finite) field extension degree. -/ -theorem finSepDegree_mul_finInsepDegree : finSepDegree F E * finInsepDegree F E = finrank F E := by - by_cases halg : Algebra.IsAlgebraic F E - · have := congr_arg Cardinal.toNat (sepDegree_mul_insepDegree F E) - rwa [Cardinal.toNat_mul, ← finSepDegree_eq F E] at this - rw [finInsepDegree, finrank_of_infinite_dimensional (K := F) (V := E) fun _ ↦ - halg (Algebra.IsAlgebraic.of_finite F E), - finrank_of_infinite_dimensional (K := separableClosure F E) (V := E) fun _ ↦ - halg ((separableClosure.isAlgebraic F E).trans), - mul_zero] - -end Field - -namespace separableClosure - -variable [Algebra E K] [IsScalarTower F E K] {F E} - -/-- If `K / E / F` is a field extension tower, such that `E / F` is algebraic and `K / E` -is separable, then `E` adjoin `separableClosure F K` is equal to `K`. It is a special case of -`separableClosure.adjoin_eq_of_isAlgebraic`, and is an intermediate result used to prove it. -/ -lemma adjoin_eq_of_isAlgebraic_of_isSeparable [Algebra.IsAlgebraic F E] - [Algebra.IsSeparable E K] : adjoin E (separableClosure F K : Set K) = ⊤ := - top_unique fun x _ ↦ by - set S := separableClosure F K - set L := adjoin E (S : Set K) - have := Algebra.isSeparable_tower_top_of_isSeparable E L K - let i : S →+* L := Subsemiring.inclusion fun x hx ↦ subset_adjoin E (S : Set K) hx - let _ : Algebra S L := i.toAlgebra - let _ : SMul S L := Algebra.toSMul - have : IsScalarTower S L K := IsScalarTower.of_algebraMap_eq (congrFun rfl) - have : Algebra.IsAlgebraic F K := Algebra.IsAlgebraic.trans (L := E) - have : IsPurelyInseparable S K := separableClosure.isPurelyInseparable F K - have := IsPurelyInseparable.tower_top S L K - obtain ⟨y, rfl⟩ := IsPurelyInseparable.surjective_algebraMap_of_isSeparable L K x - exact y.2 - -/-- If `K / E / F` is a field extension tower, such that `E / F` is algebraic, then -`E` adjoin `separableClosure F K` is equal to `separableClosure E K`. -/ -theorem adjoin_eq_of_isAlgebraic [Algebra.IsAlgebraic F E] : - adjoin E (separableClosure F K) = separableClosure E K := by - set S := separableClosure E K - have h := congr_arg lift (adjoin_eq_of_isAlgebraic_of_isSeparable (F := F) S) - rw [lift_top, lift_adjoin] at h - haveI : IsScalarTower F S K := IsScalarTower.of_algebraMap_eq (congrFun rfl) - rw [← h, ← map_eq_of_separableClosure_eq_bot F (separableClosure_eq_bot E K)] - simp only [S, coe_map, IsScalarTower.coe_toAlgHom', IntermediateField.algebraMap_apply] - -end separableClosure - -section TowerLaw - -variable [Algebra E K] [IsScalarTower F E K] - -variable {F K} in -/-- If `K / E / F` is a field extension tower such that `E / F` is purely inseparable, -if `{ u_i }` is a family of separable elements of `K` which is `F`-linearly independent, -then it is also `E`-linearly independent. -/ -theorem LinearIndependent.map_of_isPurelyInseparable_of_isSeparable [IsPurelyInseparable F E] - {ι : Type*} {v : ι → K} (hsep : ∀ i : ι, IsSeparable F (v i)) - (h : LinearIndependent F v) : LinearIndependent E v := by - obtain ⟨q, _⟩ := ExpChar.exists F - haveI := expChar_of_injective_algebraMap (algebraMap F K).injective q - refine linearIndependent_iff.mpr fun l hl ↦ Finsupp.ext fun i ↦ ?_ - choose f hf using fun i ↦ (isPurelyInseparable_iff_pow_mem F q).1 ‹_› (l i) - let n := l.support.sup f - have := (expChar_pow_pos F q n).ne' - replace hf (i : ι) : l i ^ q ^ n ∈ (algebraMap F E).range := by - by_cases hs : i ∈ l.support - · convert pow_mem (hf i) (q ^ (n - f i)) using 1 - rw [← pow_mul, ← pow_add, Nat.add_sub_of_le (Finset.le_sup hs)] - exact ⟨0, by rw [map_zero, Finsupp.not_mem_support_iff.1 hs, zero_pow this]⟩ - choose lF hlF using hf - let lF₀ := Finsupp.onFinset l.support lF fun i ↦ by - contrapose! - refine fun hs ↦ (injective_iff_map_eq_zero _).mp (algebraMap F E).injective _ ?_ - rw [hlF, Finsupp.not_mem_support_iff.1 hs, zero_pow this] - replace h := linearIndependent_iff.1 (h.map_pow_expChar_pow_of_isSeparable' q n hsep) lF₀ <| by - replace hl := congr($hl ^ q ^ n) - rw [linearCombination_apply, Finsupp.sum, sum_pow_char_pow, zero_pow this] at hl - rw [← hl, linearCombination_apply, onFinset_sum _ (fun _ ↦ by exact zero_smul _ _)] - refine Finset.sum_congr rfl fun i _ ↦ ?_ - simp_rw [Algebra.smul_def, mul_pow, IsScalarTower.algebraMap_apply F E K, hlF, map_pow] - refine pow_eq_zero ((hlF _).symm.trans ?_) - convert map_zero (algebraMap F E) - exact congr($h i) - -namespace Field - -/-- If `K / E / F` is a field extension tower, such that `E / F` is purely inseparable and `K / E` -is separable, then the separable degree of `K / F` is equal to the degree of `K / E`. -It is a special case of `Field.lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic`, and is an -intermediate result used to prove it. -/ -lemma sepDegree_eq_of_isPurelyInseparable_of_isSeparable - [IsPurelyInseparable F E] [Algebra.IsSeparable E K] : sepDegree F K = Module.rank E K := by - let S := separableClosure F K - have h := S.adjoin_rank_le_of_isAlgebraic_right E - rw [separableClosure.adjoin_eq_of_isAlgebraic_of_isSeparable K, rank_top'] at h - obtain ⟨ι, ⟨b⟩⟩ := Basis.exists_basis F S - exact h.antisymm' (b.mk_eq_rank'' ▸ (b.linearIndependent.map' S.val.toLinearMap - (LinearMap.ker_eq_bot_of_injective S.val.injective) - |>.map_of_isPurelyInseparable_of_isSeparable E (fun i ↦ - by simpa only [IsSeparable, minpoly_eq] using Algebra.IsSeparable.isSeparable F (b i)) - |>.cardinal_le_rank)) - -/-- If `K / E / F` is a field extension tower, such that `E / F` is separable, -then $[E:F] [K:E]_s = [K:F]_s$. -It is a special case of `Field.lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic`, and is an -intermediate result used to prove it. -/ -lemma lift_rank_mul_lift_sepDegree_of_isSeparable [Algebra.IsSeparable F E] : - Cardinal.lift.{w} (Module.rank F E) * Cardinal.lift.{v} (sepDegree E K) = - Cardinal.lift.{v} (sepDegree F K) := by - rw [sepDegree, sepDegree, separableClosure.eq_restrictScalars_of_isSeparable F E K] - exact lift_rank_mul_lift_rank F E (separableClosure E K) - -/-- The same-universe version of `Field.lift_rank_mul_lift_sepDegree_of_isSeparable`. -/ -lemma rank_mul_sepDegree_of_isSeparable (K : Type v) [Field K] [Algebra F K] - [Algebra E K] [IsScalarTower F E K] [Algebra.IsSeparable F E] : - Module.rank F E * sepDegree E K = sepDegree F K := by - simpa only [Cardinal.lift_id] using lift_rank_mul_lift_sepDegree_of_isSeparable F E K - -/-- If `K / E / F` is a field extension tower, such that `E / F` is purely inseparable, -then $[K:F]_s = [K:E]_s$. -It is a special case of `Field.lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic`, and is an -intermediate result used to prove it. -/ -lemma sepDegree_eq_of_isPurelyInseparable [IsPurelyInseparable F E] : - sepDegree F K = sepDegree E K := by - convert sepDegree_eq_of_isPurelyInseparable_of_isSeparable F E (separableClosure E K) - haveI : IsScalarTower F (separableClosure E K) K := IsScalarTower.of_algebraMap_eq (congrFun rfl) - rw [sepDegree, ← separableClosure.map_eq_of_separableClosure_eq_bot F - (separableClosure.separableClosure_eq_bot E K)] - exact (separableClosure F (separableClosure E K)).equivMap - (IsScalarTower.toAlgHom F (separableClosure E K) K) |>.symm.toLinearEquiv.rank_eq - -/-- If `K / E / F` is a field extension tower, such that `E / F` is algebraic, then their -separable degrees satisfy the tower law: $[E:F]_s [K:E]_s = [K:F]_s$. -/ -theorem lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic [Algebra.IsAlgebraic F E] : - Cardinal.lift.{w} (sepDegree F E) * Cardinal.lift.{v} (sepDegree E K) = - Cardinal.lift.{v} (sepDegree F K) := by - have h := lift_rank_mul_lift_sepDegree_of_isSeparable F (separableClosure F E) K - haveI := separableClosure.isPurelyInseparable F E - rwa [sepDegree_eq_of_isPurelyInseparable (separableClosure F E) E K] at h - -/-- The same-universe version of `Field.lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic`. -/ -@[stacks 09HK "Part 1"] -theorem sepDegree_mul_sepDegree_of_isAlgebraic (K : Type v) [Field K] [Algebra F K] - [Algebra E K] [IsScalarTower F E K] [Algebra.IsAlgebraic F E] : - sepDegree F E * sepDegree E K = sepDegree F K := by - simpa only [Cardinal.lift_id] using lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic F E K - -end Field - -variable {F K} in -/-- If `K / E / F` is a field extension tower, such that `E / F` is purely inseparable, then -for any subset `S` of `K` such that `F(S) / F` is algebraic, the `E(S) / E` and `F(S) / F` have -the same separable degree. -/ -theorem IntermediateField.sepDegree_adjoin_eq_of_isAlgebraic_of_isPurelyInseparable - (S : Set K) [Algebra.IsAlgebraic F (adjoin F S)] [IsPurelyInseparable F E] : - sepDegree E (adjoin E S) = sepDegree F (adjoin F S) := by - set M := adjoin F S - set L := adjoin E S - let E' := (IsScalarTower.toAlgHom F E K).fieldRange - let j : E ≃ₐ[F] E' := AlgEquiv.ofInjectiveField (IsScalarTower.toAlgHom F E K) - have hi : M ≤ L.restrictScalars F := by - rw [restrictScalars_adjoin_of_algEquiv (E := K) j rfl, restrictScalars_adjoin] - exact adjoin.mono _ _ _ Set.subset_union_right - let i : M →+* L := Subsemiring.inclusion hi - letI : Algebra M L := i.toAlgebra - letI : SMul M L := Algebra.toSMul - haveI : IsScalarTower F M L := IsScalarTower.of_algebraMap_eq (congrFun rfl) - haveI : IsPurelyInseparable M L := by - change IsPurelyInseparable M (extendScalars hi) - obtain ⟨q, _⟩ := ExpChar.exists F - have : extendScalars hi = adjoin M (E' : Set K) := restrictScalars_injective F <| by - conv_lhs => rw [extendScalars_restrictScalars, restrictScalars_adjoin_of_algEquiv - (E := K) j rfl, ← adjoin_self F E', adjoin_adjoin_comm] - rw [this, isPurelyInseparable_adjoin_iff_pow_mem _ _ q] - rintro x ⟨y, hy⟩ - obtain ⟨n, z, hz⟩ := IsPurelyInseparable.pow_mem F q y - refine ⟨n, algebraMap F M z, ?_⟩ - rw [← IsScalarTower.algebraMap_apply, IsScalarTower.algebraMap_apply F E K, hz, ← hy, map_pow, - AlgHom.toRingHom_eq_coe, IsScalarTower.coe_toAlgHom] - have h := lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic F E L - rw [IsPurelyInseparable.sepDegree_eq_one F E, Cardinal.lift_one, one_mul] at h - rw [Cardinal.lift_injective h, ← sepDegree_mul_sepDegree_of_isAlgebraic F M L, - IsPurelyInseparable.sepDegree_eq_one M L, mul_one] - -variable {F K} in -/-- If `K / E / F` is a field extension tower, such that `E / F` is purely inseparable, then -for any intermediate field `S` of `K / F` such that `S / F` is algebraic, the `E(S) / E` and -`S / F` have the same separable degree. -/ -theorem IntermediateField.sepDegree_adjoin_eq_of_isAlgebraic_of_isPurelyInseparable' - (S : IntermediateField F K) [Algebra.IsAlgebraic F S] [IsPurelyInseparable F E] : - sepDegree E (adjoin E (S : Set K)) = sepDegree F S := by - have : Algebra.IsAlgebraic F (adjoin F (S : Set K)) := by rwa [adjoin_self] - have := sepDegree_adjoin_eq_of_isAlgebraic_of_isPurelyInseparable (F := F) E (S : Set K) - rwa [adjoin_self] at this - -variable {F K} in -/-- If `K / E / F` is a field extension tower, such that `E / F` is purely inseparable, then -for any element `x` of `K` separable over `F`, it has the same minimal polynomials over `F` and -over `E`. -/ -theorem minpoly.map_eq_of_isSeparable_of_isPurelyInseparable (x : K) - (hsep : IsSeparable F x) [IsPurelyInseparable F E] : - (minpoly F x).map (algebraMap F E) = minpoly E x := by - have hi := IsSeparable.isIntegral hsep - have hi' : IsIntegral E x := IsIntegral.tower_top hi - refine eq_of_monic_of_dvd_of_natDegree_le (monic hi') ((monic hi).map (algebraMap F E)) - (dvd_map_of_isScalarTower F E x) (le_of_eq ?_) - have hsep' := IsSeparable.tower_top E hsep - haveI := (isSeparable_adjoin_simple_iff_isSeparable _ _).2 hsep - haveI := (isSeparable_adjoin_simple_iff_isSeparable _ _).2 hsep' - have := Algebra.IsSeparable.isAlgebraic F F⟮x⟯ - have := Algebra.IsSeparable.isAlgebraic E E⟮x⟯ - rw [Polynomial.natDegree_map, ← adjoin.finrank hi, ← adjoin.finrank hi', - ← finSepDegree_eq_finrank_of_isSeparable F _, ← finSepDegree_eq_finrank_of_isSeparable E _, - finSepDegree_eq, finSepDegree_eq, - sepDegree_adjoin_eq_of_isAlgebraic_of_isPurelyInseparable (F := F) E] - -variable {F} in -/-- If `E / F` is a purely inseparable field extension, `f` is a separable irreducible polynomial -over `F`, then it is also irreducible over `E`. -/ -theorem Polynomial.Separable.map_irreducible_of_isPurelyInseparable {f : F[X]} (hsep : f.Separable) - (hirr : Irreducible f) [IsPurelyInseparable F E] : Irreducible (f.map (algebraMap F E)) := by - let K := AlgebraicClosure E - obtain ⟨x, hx⟩ := IsAlgClosed.exists_aeval_eq_zero K f - (natDegree_pos_iff_degree_pos.1 hirr.natDegree_pos).ne' - have ha : Associated f (minpoly F x) := by - have := isUnit_C.2 (leadingCoeff_ne_zero.2 hirr.ne_zero).isUnit.inv - exact ⟨this.unit, by rw [IsUnit.unit_spec, minpoly.eq_of_irreducible hirr hx]⟩ - have ha' : Associated (f.map (algebraMap F E)) ((minpoly F x).map (algebraMap F E)) := - ha.map (mapRingHom (algebraMap F E)).toMonoidHom - have heq := minpoly.map_eq_of_isSeparable_of_isPurelyInseparable E x (ha.separable hsep) - rw [ha'.irreducible_iff, heq] - exact minpoly.irreducible (Algebra.IsIntegral.isIntegral x) - -end TowerLaw diff --git a/Mathlib/FieldTheory/PurelyInseparable/Basic.lean b/Mathlib/FieldTheory/PurelyInseparable/Basic.lean new file mode 100644 index 0000000000000..30cc4d0c2701c --- /dev/null +++ b/Mathlib/FieldTheory/PurelyInseparable/Basic.lean @@ -0,0 +1,593 @@ +/- +Copyright (c) 2024 Jz Pan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jz Pan +-/ +import Mathlib.FieldTheory.SeparableClosure + +/-! + +# Basic results about purely inseparable extensions + +This file contains basic definitions and results about purely inseparable extensions. + +## Main definitions + +- `IsPurelyInseparable`: typeclass for purely inseparable field extensions: an algebraic extension + `E / F` is purely inseparable if and only if the minimal polynomial of every element of `E ∖ F` + is not separable. + +## Main results + +- `IsPurelyInseparable.surjective_algebraMap_of_isSeparable`, + `IsPurelyInseparable.bijective_algebraMap_of_isSeparable`, + `IntermediateField.eq_bot_of_isPurelyInseparable_of_isSeparable`: + if `E / F` is both purely inseparable and separable, then `algebraMap F E` is surjective + (hence bijective). In particular, if an intermediate field of `E / F` is both purely inseparable + and separable, then it is equal to `F`. + +- `isPurelyInseparable_iff_pow_mem`: a field extension `E / F` of exponential characteristic `q` is + purely inseparable if and only if for every element `x` of `E`, there exists a natural number `n` + such that `x ^ (q ^ n)` is contained in `F`. + +- `IsPurelyInseparable.trans`: if `E / F` and `K / E` are both purely inseparable extensions, then + `K / F` is also purely inseparable. + +- `isPurelyInseparable_iff_natSepDegree_eq_one`: `E / F` is purely inseparable if and only if for + every element `x` of `E`, its minimal polynomial has separable degree one. + +- `isPurelyInseparable_iff_minpoly_eq_X_pow_sub_C`: a field extension `E / F` of exponential + characteristic `q` is purely inseparable if and only if for every element `x` of `E`, the minimal + polynomial of `x` over `F` is of form `X ^ (q ^ n) - y` for some natural number `n` and some + element `y` of `F`. + +- `isPurelyInseparable_iff_minpoly_eq_X_sub_C_pow`: a field extension `E / F` of exponential + characteristic `q` is purely inseparable if and only if for every element `x` of `E`, the minimal + polynomial of `x` over `F` is of form `(X - x) ^ (q ^ n)` for some natural number `n`. + +- `isPurelyInseparable_iff_finSepDegree_eq_one`: an extension is purely inseparable + if and only if it has finite separable degree (`Field.finSepDegree`) one. + +- `IsPurelyInseparable.normal`: a purely inseparable extension is normal. + +- `separableClosure.isPurelyInseparable`: if `E / F` is algebraic, then `E` is purely inseparable + over the separable closure of `F` in `E`. + +- `separableClosure_le_iff`: if `E / F` is algebraic, then an intermediate field of `E / F` contains + the separable closure of `F` in `E` if and only if `E` is purely inseparable over it. + +- `eq_separableClosure_iff`: if `E / F` is algebraic, then an intermediate field of `E / F` is equal + to the separable closure of `F` in `E` if and only if it is separable over `F`, and `E` + is purely inseparable over it. + +- `IsPurelyInseparable.injective_comp_algebraMap`: if `E / F` is purely inseparable, then for any + reduced ring `L`, the map `(E →+* L) → (F →+* L)` induced by `algebraMap F E` is injective. + In particular, a purely inseparable field extension is an epimorphism in the category of fields. + +- `IsPurelyInseparable.of_injective_comp_algebraMap`: if `L` is an algebraically closed field + containing `E`, such that the map `(E →+* L) → (F →+* L)` induced by `algebraMap F E` is + injective, then `E / F` is purely inseparable. As a corollary, epimorphisms in the category of + fields must be purely inseparable extensions. + +- `Field.finSepDegree_eq`: if `E / F` is algebraic, then the `Field.finSepDegree F E` is equal to + `Field.sepDegree F E` as a natural number. This means that the cardinality of `Field.Emb F E` + and the degree of `(separableClosure F E) / F` are both finite or infinite, and when they are + finite, they coincide. + +- `Field.finSepDegree_mul_finInsepDegree`: the finite separable degree multiply by the finite + inseparable degree is equal to the (finite) field extension degree. + +## Tags + +separable degree, degree, separable closure, purely inseparable + +-/ + +open Module Polynomial IntermediateField Field + +noncomputable section + +universe u v w + +section General + +variable (F E : Type*) [CommRing F] [Ring E] [Algebra F E] +variable (K : Type*) [Ring K] [Algebra F K] + +/-- Typeclass for purely inseparable field extensions: an algebraic extension `E / F` is purely +inseparable if and only if the minimal polynomial of every element of `E ∖ F` is not separable. + +We define this for general (commutative) rings and only assume `F` and `E` are fields +if this is needed for a proof. -/ +class IsPurelyInseparable : Prop where + isIntegral : Algebra.IsIntegral F E + inseparable' (x : E) : IsSeparable F x → x ∈ (algebraMap F E).range + +attribute [instance] IsPurelyInseparable.isIntegral + +variable {E} in +theorem IsPurelyInseparable.isIntegral' [IsPurelyInseparable F E] (x : E) : IsIntegral F x := + Algebra.IsIntegral.isIntegral _ + +theorem IsPurelyInseparable.isAlgebraic [Nontrivial F] [IsPurelyInseparable F E] : + Algebra.IsAlgebraic F E := inferInstance + +variable {E} + +theorem IsPurelyInseparable.inseparable [IsPurelyInseparable F E] : + ∀ x : E, IsSeparable F x → x ∈ (algebraMap F E).range := + IsPurelyInseparable.inseparable' + +variable {F} + +theorem isPurelyInseparable_iff : IsPurelyInseparable F E ↔ ∀ x : E, + IsIntegral F x ∧ (IsSeparable F x → x ∈ (algebraMap F E).range) := + ⟨fun h x ↦ ⟨h.isIntegral' _ x, h.inseparable' x⟩, fun h ↦ ⟨⟨fun x ↦ (h x).1⟩, fun x ↦ (h x).2⟩⟩ + +variable {K} + +/-- Transfer `IsPurelyInseparable` across an `AlgEquiv`. -/ +theorem AlgEquiv.isPurelyInseparable (e : K ≃ₐ[F] E) [IsPurelyInseparable F K] : + IsPurelyInseparable F E := by + refine ⟨⟨fun _ ↦ by rw [← isIntegral_algEquiv e.symm]; exact IsPurelyInseparable.isIntegral' F _⟩, + fun x h ↦ ?_⟩ + rw [IsSeparable, ← minpoly.algEquiv_eq e.symm] at h + simpa only [RingHom.mem_range, algebraMap_eq_apply] using IsPurelyInseparable.inseparable F _ h + +theorem AlgEquiv.isPurelyInseparable_iff (e : K ≃ₐ[F] E) : + IsPurelyInseparable F K ↔ IsPurelyInseparable F E := + ⟨fun _ ↦ e.isPurelyInseparable, fun _ ↦ e.symm.isPurelyInseparable⟩ + +/-- If `E / F` is an algebraic extension, `F` is separably closed, +then `E / F` is purely inseparable. -/ +instance Algebra.IsAlgebraic.isPurelyInseparable_of_isSepClosed + {F : Type u} {E : Type v} [Field F] [Ring E] [IsDomain E] [Algebra F E] + [Algebra.IsAlgebraic F E] [IsSepClosed F] : IsPurelyInseparable F E := + ⟨inferInstance, fun x h ↦ minpoly.mem_range_of_degree_eq_one F x <| + IsSepClosed.degree_eq_one_of_irreducible F (minpoly.irreducible + (Algebra.IsIntegral.isIntegral _)) h⟩ + +variable (F E K) + +/-- If `E / F` is both purely inseparable and separable, then `algebraMap F E` is surjective. -/ +theorem IsPurelyInseparable.surjective_algebraMap_of_isSeparable + [IsPurelyInseparable F E] [Algebra.IsSeparable F E] : Function.Surjective (algebraMap F E) := + fun x ↦ IsPurelyInseparable.inseparable F x (Algebra.IsSeparable.isSeparable F x) + +/-- If `E / F` is both purely inseparable and separable, then `algebraMap F E` is bijective. -/ +theorem IsPurelyInseparable.bijective_algebraMap_of_isSeparable + [Nontrivial E] [NoZeroSMulDivisors F E] + [IsPurelyInseparable F E] [Algebra.IsSeparable F E] : Function.Bijective (algebraMap F E) := + ⟨NoZeroSMulDivisors.algebraMap_injective F E, surjective_algebraMap_of_isSeparable F E⟩ + +variable {F E} in +/-- If a subalgebra of `E / F` is both purely inseparable and separable, then it is equal +to `F`. -/ +theorem Subalgebra.eq_bot_of_isPurelyInseparable_of_isSeparable (L : Subalgebra F E) + [IsPurelyInseparable F L] [Algebra.IsSeparable F L] : L = ⊥ := bot_unique fun x hx ↦ by + obtain ⟨y, hy⟩ := IsPurelyInseparable.surjective_algebraMap_of_isSeparable F L ⟨x, hx⟩ + exact ⟨y, congr_arg (Subalgebra.val _) hy⟩ + +/-- If an intermediate field of `E / F` is both purely inseparable and separable, then it is equal +to `F`. -/ +theorem IntermediateField.eq_bot_of_isPurelyInseparable_of_isSeparable + {F : Type u} {E : Type v} [Field F] [Field E] [Algebra F E] (L : IntermediateField F E) + [IsPurelyInseparable F L] [Algebra.IsSeparable F L] : L = ⊥ := bot_unique fun x hx ↦ by + obtain ⟨y, hy⟩ := IsPurelyInseparable.surjective_algebraMap_of_isSeparable F L ⟨x, hx⟩ + exact ⟨y, congr_arg (algebraMap L E) hy⟩ + +/-- If `E / F` is purely inseparable, then the separable closure of `F` in `E` is +equal to `F`. -/ +theorem separableClosure.eq_bot_of_isPurelyInseparable + (F : Type u) (E : Type v) [Field F] [Field E] [Algebra F E] [IsPurelyInseparable F E] : + separableClosure F E = ⊥ := + bot_unique fun x h ↦ IsPurelyInseparable.inseparable F x (mem_separableClosure_iff.1 h) + +/-- If `E / F` is an algebraic extension, then the separable closure of `F` in `E` is +equal to `F` if and only if `E / F` is purely inseparable. -/ +theorem separableClosure.eq_bot_iff + {F : Type u} {E : Type v} [Field F] [Field E] [Algebra F E] [Algebra.IsAlgebraic F E] : + separableClosure F E = ⊥ ↔ IsPurelyInseparable F E := + ⟨fun h ↦ isPurelyInseparable_iff.2 fun x ↦ ⟨Algebra.IsIntegral.isIntegral x, fun hs ↦ by + simpa only [h] using mem_separableClosure_iff.2 hs⟩, fun _ ↦ eq_bot_of_isPurelyInseparable F E⟩ + +instance isPurelyInseparable_self : IsPurelyInseparable F F := + ⟨inferInstance, fun x _ ↦ ⟨x, rfl⟩⟩ + +section + +variable (F : Type u) {E : Type v} [Field F] [Ring E] [IsDomain E] [Algebra F E] +variable (q : ℕ) [ExpChar F q] (x : E) + +/-- A field extension `E / F` of exponential characteristic `q` is purely inseparable +if and only if for every element `x` of `E`, there exists a natural number `n` such that +`x ^ (q ^ n)` is contained in `F`. -/ +@[stacks 09HE] +theorem isPurelyInseparable_iff_pow_mem : + IsPurelyInseparable F E ↔ ∀ x : E, ∃ n : ℕ, x ^ q ^ n ∈ (algebraMap F E).range := by + rw [isPurelyInseparable_iff] + refine ⟨fun h x ↦ ?_, fun h x ↦ ?_⟩ + · obtain ⟨g, h1, n, h2⟩ := (minpoly.irreducible (h x).1).hasSeparableContraction q + exact ⟨n, (h _).2 <| h1.of_dvd <| minpoly.dvd F _ <| by + simpa only [expand_aeval, minpoly.aeval] using congr_arg (aeval x) h2⟩ + have hdeg := (minpoly.natSepDegree_eq_one_iff_pow_mem q).2 (h x) + have halg : IsIntegral F x := by_contra fun h' ↦ by + simp only [minpoly.eq_zero h', natSepDegree_zero, zero_ne_one] at hdeg + refine ⟨halg, fun hsep ↦ ?_⟩ + rwa [hsep.natSepDegree_eq_natDegree, minpoly.natDegree_eq_one_iff] at hdeg + +theorem IsPurelyInseparable.pow_mem [IsPurelyInseparable F E] : + ∃ n : ℕ, x ^ q ^ n ∈ (algebraMap F E).range := + (isPurelyInseparable_iff_pow_mem F q).1 ‹_› x + +end + +end General + +variable (F : Type u) (E : Type v) [Field F] [Field E] [Algebra F E] +variable (K : Type w) [Field K] [Algebra F K] + +section Field + +/-- If `K / E / F` is a field extension tower such that `K / F` is purely inseparable, +then `E / F` is also purely inseparable. -/ +theorem IsPurelyInseparable.tower_bot [Algebra E K] [IsScalarTower F E K] + [IsPurelyInseparable F K] : IsPurelyInseparable F E := by + refine ⟨⟨fun x ↦ (isIntegral' F (algebraMap E K x)).tower_bot_of_field⟩, fun x h ↦ ?_⟩ + rw [IsSeparable, ← minpoly.algebraMap_eq (algebraMap E K).injective] at h + obtain ⟨y, h⟩ := inseparable F _ h + exact ⟨y, (algebraMap E K).injective (h.symm ▸ (IsScalarTower.algebraMap_apply F E K y).symm)⟩ + +/-- If `K / E / F` is a field extension tower such that `K / F` is purely inseparable, +then `K / E` is also purely inseparable. -/ +theorem IsPurelyInseparable.tower_top [Algebra E K] [IsScalarTower F E K] + [h : IsPurelyInseparable F K] : IsPurelyInseparable E K := by + obtain ⟨q, _⟩ := ExpChar.exists F + haveI := expChar_of_injective_algebraMap (algebraMap F E).injective q + rw [isPurelyInseparable_iff_pow_mem _ q] at h ⊢ + intro x + obtain ⟨n, y, h⟩ := h x + exact ⟨n, (algebraMap F E) y, h.symm ▸ (IsScalarTower.algebraMap_apply F E K y).symm⟩ + +/-- If `E / F` and `K / E` are both purely inseparable extensions, then `K / F` is also +purely inseparable. -/ +@[stacks 02JJ "See also 00GM"] +theorem IsPurelyInseparable.trans [Algebra E K] [IsScalarTower F E K] + [h1 : IsPurelyInseparable F E] [h2 : IsPurelyInseparable E K] : IsPurelyInseparable F K := by + obtain ⟨q, _⟩ := ExpChar.exists F + haveI := expChar_of_injective_algebraMap (algebraMap F E).injective q + rw [isPurelyInseparable_iff_pow_mem _ q] at h1 h2 ⊢ + intro x + obtain ⟨n, y, h2⟩ := h2 x + obtain ⟨m, z, h1⟩ := h1 y + refine ⟨n + m, z, ?_⟩ + rw [IsScalarTower.algebraMap_apply F E K, h1, map_pow, h2, ← pow_mul, ← pow_add] + +namespace IntermediateField + +variable (M : IntermediateField F K) + +instance isPurelyInseparable_tower_bot [IsPurelyInseparable F K] : IsPurelyInseparable F M := + IsPurelyInseparable.tower_bot F M K + +instance isPurelyInseparable_tower_top [IsPurelyInseparable F K] : IsPurelyInseparable M K := + IsPurelyInseparable.tower_top F M K + +end IntermediateField + +variable {E} + +/-- A field extension `E / F` is purely inseparable if and only if for every element `x` of `E`, +its minimal polynomial has separable degree one. -/ +theorem isPurelyInseparable_iff_natSepDegree_eq_one : + IsPurelyInseparable F E ↔ ∀ x : E, (minpoly F x).natSepDegree = 1 := by + obtain ⟨q, _⟩ := ExpChar.exists F + simp_rw [isPurelyInseparable_iff_pow_mem F q, minpoly.natSepDegree_eq_one_iff_pow_mem q] + +theorem IsPurelyInseparable.natSepDegree_eq_one [IsPurelyInseparable F E] (x : E) : + (minpoly F x).natSepDegree = 1 := + (isPurelyInseparable_iff_natSepDegree_eq_one F).1 ‹_› x + +/-- A field extension `E / F` of exponential characteristic `q` is purely inseparable +if and only if for every element `x` of `E`, the minimal polynomial of `x` over `F` is of form +`X ^ (q ^ n) - y` for some natural number `n` and some element `y` of `F`. -/ +theorem isPurelyInseparable_iff_minpoly_eq_X_pow_sub_C (q : ℕ) [hF : ExpChar F q] : + IsPurelyInseparable F E ↔ ∀ x : E, ∃ (n : ℕ) (y : F), minpoly F x = X ^ q ^ n - C y := by + simp_rw [isPurelyInseparable_iff_natSepDegree_eq_one, + minpoly.natSepDegree_eq_one_iff_eq_X_pow_sub_C q] + +theorem IsPurelyInseparable.minpoly_eq_X_pow_sub_C (q : ℕ) [ExpChar F q] [IsPurelyInseparable F E] + (x : E) : ∃ (n : ℕ) (y : F), minpoly F x = X ^ q ^ n - C y := + (isPurelyInseparable_iff_minpoly_eq_X_pow_sub_C F q).1 ‹_› x + +/-- A field extension `E / F` of exponential characteristic `q` is purely inseparable +if and only if for every element `x` of `E`, the minimal polynomial of `x` over `F` is of form +`(X - x) ^ (q ^ n)` for some natural number `n`. -/ +theorem isPurelyInseparable_iff_minpoly_eq_X_sub_C_pow (q : ℕ) [hF : ExpChar F q] : + IsPurelyInseparable F E ↔ + ∀ x : E, ∃ n : ℕ, (minpoly F x).map (algebraMap F E) = (X - C x) ^ q ^ n := by + simp_rw [isPurelyInseparable_iff_natSepDegree_eq_one, + minpoly.natSepDegree_eq_one_iff_eq_X_sub_C_pow q] + +theorem IsPurelyInseparable.minpoly_eq_X_sub_C_pow (q : ℕ) [ExpChar F q] [IsPurelyInseparable F E] + (x : E) : ∃ n : ℕ, (minpoly F x).map (algebraMap F E) = (X - C x) ^ q ^ n := + (isPurelyInseparable_iff_minpoly_eq_X_sub_C_pow F q).1 ‹_› x + +variable (E) + +variable {F E} in +/-- If an extension has finite separable degree one, then it is purely inseparable. -/ +theorem isPurelyInseparable_of_finSepDegree_eq_one + (hdeg : finSepDegree F E = 1) : IsPurelyInseparable F E := by + by_cases H : Algebra.IsAlgebraic F E + · rw [isPurelyInseparable_iff] + refine fun x ↦ ⟨Algebra.IsIntegral.isIntegral x, fun hsep ↦ ?_⟩ + have : Algebra.IsAlgebraic F⟮x⟯ E := Algebra.IsAlgebraic.tower_top (K := F) F⟮x⟯ + have := finSepDegree_mul_finSepDegree_of_isAlgebraic F F⟮x⟯ E + rw [hdeg, mul_eq_one, (finSepDegree_adjoin_simple_eq_finrank_iff F E x + (Algebra.IsAlgebraic.isAlgebraic x)).2 hsep, + IntermediateField.finrank_eq_one_iff] at this + simpa only [this.1] using mem_adjoin_simple_self F x + · rw [← Algebra.transcendental_iff_not_isAlgebraic] at H + simp [finSepDegree_eq_zero_of_transcendental F E] at hdeg + +namespace IsPurelyInseparable + +variable [IsPurelyInseparable F E] (R L : Type*) [CommSemiring R] [Algebra R F] [Algebra R E] + +/-- If `E / F` is purely inseparable, then for any reduced ring `L`, the map `(E →+* L) → (F →+* L)` +induced by `algebraMap F E` is injective. In particular, a purely inseparable field extension +is an epimorphism in the category of fields. -/ +theorem injective_comp_algebraMap [CommRing L] [IsReduced L] : + Function.Injective fun f : E →+* L ↦ f.comp (algebraMap F E) := fun f g heq ↦ by + ext x + let q := ringExpChar F + obtain ⟨n, y, h⟩ := IsPurelyInseparable.pow_mem F q x + replace heq := congr($heq y) + simp_rw [RingHom.comp_apply, h, map_pow] at heq + nontriviality L + haveI := expChar_of_injective_ringHom (f.comp (algebraMap F E)).injective q + exact iterateFrobenius_inj L q n heq + +theorem injective_restrictDomain [CommRing L] [IsReduced L] [Algebra R L] [IsScalarTower R F E] : + Function.Injective (AlgHom.restrictDomain (A := R) F (C := E) (D := L)) := fun _ _ eq ↦ + AlgHom.coe_ringHom_injective <| injective_comp_algebraMap F E L <| congr_arg AlgHom.toRingHom eq + +instance [Field L] [PerfectField L] [Algebra F L] : Nonempty (E →ₐ[F] L) := + nonempty_algHom_of_splits fun x ↦ ⟨IsPurelyInseparable.isIntegral' _ _, + have ⟨q, _⟩ := ExpChar.exists F + PerfectField.splits_of_natSepDegree_eq_one (algebraMap F L) + ((minpoly.natSepDegree_eq_one_iff_eq_X_pow_sub_C q).mpr <| + IsPurelyInseparable.minpoly_eq_X_pow_sub_C F q x)⟩ + +theorem bijective_comp_algebraMap [Field L] [PerfectField L] : + Function.Bijective fun f : E →+* L ↦ f.comp (algebraMap F E) := + ⟨injective_comp_algebraMap F E L, fun g ↦ let _ := g.toAlgebra + ⟨_, (Classical.arbitrary <| E →ₐ[F] L).comp_algebraMap⟩⟩ + +theorem bijective_restrictDomain [Field L] [PerfectField L] [Algebra R L] [IsScalarTower R F E] : + Function.Bijective (AlgHom.restrictDomain (A := R) F (C := E) (D := L)) := + ⟨injective_restrictDomain F E R L, fun g ↦ let _ := g.toAlgebra + let f := Classical.arbitrary (E →ₐ[F] L) + ⟨f.restrictScalars R, AlgHom.coe_ringHom_injective f.comp_algebraMap⟩⟩ + +end IsPurelyInseparable + +/-- If `E / F` is purely inseparable, then for any reduced `F`-algebra `L`, there exists at most one +`F`-algebra homomorphism from `E` to `L`. -/ +instance instSubsingletonAlgHomOfIsPurelyInseparable [IsPurelyInseparable F E] (L : Type w) + [CommRing L] [IsReduced L] [Algebra F L] : Subsingleton (E →ₐ[F] L) where + allEq f g := AlgHom.coe_ringHom_injective <| + IsPurelyInseparable.injective_comp_algebraMap F E L (by simp_rw [AlgHom.comp_algebraMap]) + +instance instUniqueAlgHomOfIsPurelyInseparable [IsPurelyInseparable F E] (L : Type w) + [CommRing L] [IsReduced L] [Algebra F L] [Algebra E L] [IsScalarTower F E L] : + Unique (E →ₐ[F] L) := uniqueOfSubsingleton (IsScalarTower.toAlgHom F E L) + +/-- If `E / F` is purely inseparable, then `Field.Emb F E` has exactly one element. -/ +instance instUniqueEmbOfIsPurelyInseparable [IsPurelyInseparable F E] : + Unique (Emb F E) := instUniqueAlgHomOfIsPurelyInseparable F E _ + +/-- A purely inseparable extension has finite separable degree one. -/ +theorem IsPurelyInseparable.finSepDegree_eq_one [IsPurelyInseparable F E] : + finSepDegree F E = 1 := Nat.card_unique + +/-- A purely inseparable extension has separable degree one. -/ +theorem IsPurelyInseparable.sepDegree_eq_one [IsPurelyInseparable F E] : + sepDegree F E = 1 := by + rw [sepDegree, separableClosure.eq_bot_of_isPurelyInseparable, IntermediateField.rank_bot] + +/-- A purely inseparable extension has inseparable degree equal to degree. -/ +theorem IsPurelyInseparable.insepDegree_eq [IsPurelyInseparable F E] : + insepDegree F E = Module.rank F E := by + rw [insepDegree, separableClosure.eq_bot_of_isPurelyInseparable, rank_bot'] + +/-- A purely inseparable extension has finite inseparable degree equal to degree. -/ +theorem IsPurelyInseparable.finInsepDegree_eq [IsPurelyInseparable F E] : + finInsepDegree F E = finrank F E := congr(Cardinal.toNat $(insepDegree_eq F E)) + +/-- An extension is purely inseparable if and only if it has finite separable degree one. -/ +theorem isPurelyInseparable_iff_finSepDegree_eq_one : + IsPurelyInseparable F E ↔ finSepDegree F E = 1 := + ⟨fun _ ↦ IsPurelyInseparable.finSepDegree_eq_one F E, + fun h ↦ isPurelyInseparable_of_finSepDegree_eq_one h⟩ + +variable {F E} in +/-- An algebraic extension is purely inseparable if and only if all of its finite dimensional +subextensions are purely inseparable. -/ +theorem isPurelyInseparable_iff_fd_isPurelyInseparable [Algebra.IsAlgebraic F E] : + IsPurelyInseparable F E ↔ + ∀ L : IntermediateField F E, FiniteDimensional F L → IsPurelyInseparable F L := by + refine ⟨fun _ _ _ ↦ IsPurelyInseparable.tower_bot F _ E, + fun h ↦ isPurelyInseparable_iff.2 fun x ↦ ?_⟩ + have hx : IsIntegral F x := Algebra.IsIntegral.isIntegral x + refine ⟨hx, fun _ ↦ ?_⟩ + obtain ⟨y, h⟩ := (h _ (adjoin.finiteDimensional hx)).inseparable' _ <| + show Separable (minpoly F (AdjoinSimple.gen F x)) by rwa [minpoly_eq] + exact ⟨y, congr_arg (algebraMap _ E) h⟩ + +/-- A purely inseparable extension is normal. -/ +instance IsPurelyInseparable.normal [IsPurelyInseparable F E] : Normal F E where + toIsAlgebraic := isAlgebraic F E + splits' x := by + obtain ⟨n, h⟩ := IsPurelyInseparable.minpoly_eq_X_sub_C_pow F (ringExpChar F) x + rw [← splits_id_iff_splits, h] + exact splits_pow _ (splits_X_sub_C _) _ + +/-- If `E / F` is algebraic, then `E` is purely inseparable over the +separable closure of `F` in `E`. -/ +@[stacks 030K "$E/E_{sep}$ is purely inseparable."] +instance separableClosure.isPurelyInseparable [Algebra.IsAlgebraic F E] : + IsPurelyInseparable (separableClosure F E) E := isPurelyInseparable_iff.2 fun x ↦ by + set L := separableClosure F E + refine ⟨(IsAlgebraic.tower_top L (Algebra.IsAlgebraic.isAlgebraic (R := F) x)).isIntegral, + fun h ↦ ?_⟩ + haveI := (isSeparable_adjoin_simple_iff_isSeparable L E).2 h + haveI : Algebra.IsSeparable F (restrictScalars F L⟮x⟯) := Algebra.IsSeparable.trans F L L⟮x⟯ + have hx : x ∈ restrictScalars F L⟮x⟯ := mem_adjoin_simple_self _ x + exact ⟨⟨x, mem_separableClosure_iff.2 <| isSeparable_of_mem_isSeparable F E hx⟩, rfl⟩ + +open Cardinal in +theorem Field.Emb.cardinal_separableClosure [Algebra.IsAlgebraic F E] : + #(Field.Emb F <| separableClosure F E) = #(Field.Emb F E) := by + rw [← (embProdEmbOfIsAlgebraic F (separableClosure F E) E).cardinal_eq, + mk_prod, mk_eq_one (Emb _ E), lift_one, mul_one, lift_id] + +/-- An intermediate field of `E / F` contains the separable closure of `F` in `E` +if `E` is purely inseparable over it. -/ +theorem separableClosure_le (L : IntermediateField F E) + [h : IsPurelyInseparable L E] : separableClosure F E ≤ L := fun x hx ↦ by + obtain ⟨y, rfl⟩ := h.inseparable' _ <| + IsSeparable.tower_top L (mem_separableClosure_iff.1 hx) + exact y.2 + +/-- If `E / F` is algebraic, then an intermediate field of `E / F` contains the +separable closure of `F` in `E` if and only if `E` is purely inseparable over it. -/ +theorem separableClosure_le_iff [Algebra.IsAlgebraic F E] (L : IntermediateField F E) : + separableClosure F E ≤ L ↔ IsPurelyInseparable L E := by + refine ⟨fun h ↦ ?_, fun _ ↦ separableClosure_le F E L⟩ + have := separableClosure.isPurelyInseparable F E + letI := (inclusion h).toAlgebra + letI : SMul (separableClosure F E) L := Algebra.toSMul + haveI : IsScalarTower (separableClosure F E) L E := IsScalarTower.of_algebraMap_eq (congrFun rfl) + exact IsPurelyInseparable.tower_top (separableClosure F E) L E + +/-- If an intermediate field of `E / F` is separable over `F`, and `E` is purely inseparable +over it, then it is equal to the separable closure of `F` in `E`. -/ +theorem eq_separableClosure (L : IntermediateField F E) + [Algebra.IsSeparable F L] [IsPurelyInseparable L E] : L = separableClosure F E := + le_antisymm (le_separableClosure F E L) (separableClosure_le F E L) + +open separableClosure in +/-- If `E / F` is algebraic, then an intermediate field of `E / F` is equal to the separable closure +of `F` in `E` if and only if it is separable over `F`, and `E` is purely inseparable +over it. -/ +theorem eq_separableClosure_iff [Algebra.IsAlgebraic F E] (L : IntermediateField F E) : + L = separableClosure F E ↔ Algebra.IsSeparable F L ∧ IsPurelyInseparable L E := + ⟨by rintro rfl; exact ⟨isSeparable F E, isPurelyInseparable F E⟩, + fun ⟨_, _⟩ ↦ eq_separableClosure F E L⟩ + +/-- If `L` is an algebraically closed field containing `E`, such that the map +`(E →+* L) → (F →+* L)` induced by `algebraMap F E` is injective, then `E / F` is +purely inseparable. As a corollary, epimorphisms in the category of fields must be +purely inseparable extensions. -/ +theorem IsPurelyInseparable.of_injective_comp_algebraMap (L : Type w) [Field L] [IsAlgClosed L] + [Nonempty (E →+* L)] (h : Function.Injective fun f : E →+* L ↦ f.comp (algebraMap F E)) : + IsPurelyInseparable F E := by + rw [isPurelyInseparable_iff_finSepDegree_eq_one, finSepDegree, Nat.card_eq_one_iff_unique] + letI := (Classical.arbitrary (E →+* L)).toAlgebra + let j : AlgebraicClosure E →ₐ[E] L := IsAlgClosed.lift + exact ⟨⟨fun f g ↦ DFunLike.ext' <| j.injective.comp_left (congr_arg (⇑) <| + @h (j.toRingHom.comp f) (j.toRingHom.comp g) (by ext; simp))⟩, inferInstance⟩ + +end Field + +namespace IntermediateField + +instance isPurelyInseparable_bot : IsPurelyInseparable F (⊥ : IntermediateField F E) := + (botEquiv F E).symm.isPurelyInseparable + +end IntermediateField + +/-- If `E` is an algebraic closure of `F`, then `F` is separably closed if and only if `E / F` is +purely inseparable. -/ +theorem isSepClosed_iff_isPurelyInseparable_algebraicClosure [IsAlgClosure F E] : + IsSepClosed F ↔ IsPurelyInseparable F E := + ⟨fun _ ↦ inferInstance, fun H ↦ by + haveI := IsAlgClosure.isAlgClosed F (K := E) + rwa [← separableClosure.eq_bot_iff, IsSepClosed.separableClosure_eq_bot_iff] at H⟩ + +variable {F E} in +/-- If `E / F` is an algebraic extension, `F` is separably closed, +then `E` is also separably closed. -/ +theorem Algebra.IsAlgebraic.isSepClosed [Algebra.IsAlgebraic F E] + [IsSepClosed F] : IsSepClosed E := + have : Algebra.IsAlgebraic F (AlgebraicClosure E) := Algebra.IsAlgebraic.trans (L := E) + (isSepClosed_iff_isPurelyInseparable_algebraicClosure E _).mpr + (IsPurelyInseparable.tower_top F E <| AlgebraicClosure E) + +namespace Field + +/-- If `E / F` is algebraic, then the `Field.finSepDegree F E` is equal to `Field.sepDegree F E` +as a natural number. This means that the cardinality of `Field.Emb F E` and the degree of +`(separableClosure F E) / F` are both finite or infinite, and when they are finite, they +coincide. -/ +@[stacks 09HJ "`sepDegree` is defined as the right hand side of 09HJ"] +theorem finSepDegree_eq [Algebra.IsAlgebraic F E] : + finSepDegree F E = Cardinal.toNat (sepDegree F E) := by + have : Algebra.IsAlgebraic (separableClosure F E) E := Algebra.IsAlgebraic.tower_top (K := F) _ + have h := finSepDegree_mul_finSepDegree_of_isAlgebraic F (separableClosure F E) E |>.symm + haveI := separableClosure.isSeparable F E + haveI := separableClosure.isPurelyInseparable F E + rwa [finSepDegree_eq_finrank_of_isSeparable F (separableClosure F E), + IsPurelyInseparable.finSepDegree_eq_one (separableClosure F E) E, mul_one] at h + +/-- The finite separable degree multiply by the finite inseparable degree is equal +to the (finite) field extension degree. -/ +theorem finSepDegree_mul_finInsepDegree : finSepDegree F E * finInsepDegree F E = finrank F E := by + by_cases halg : Algebra.IsAlgebraic F E + · have := congr_arg Cardinal.toNat (sepDegree_mul_insepDegree F E) + rwa [Cardinal.toNat_mul, ← finSepDegree_eq F E] at this + rw [finInsepDegree, finrank_of_infinite_dimensional (K := F) (V := E) fun _ ↦ + halg (Algebra.IsAlgebraic.of_finite F E), + finrank_of_infinite_dimensional (K := separableClosure F E) (V := E) fun _ ↦ + halg ((separableClosure.isAlgebraic F E).trans), + mul_zero] + +end Field + +namespace separableClosure + +variable [Algebra E K] [IsScalarTower F E K] {F E} + +/-- If `K / E / F` is a field extension tower, such that `E / F` is algebraic and `K / E` +is separable, then `E` adjoin `separableClosure F K` is equal to `K`. It is a special case of +`separableClosure.adjoin_eq_of_isAlgebraic`, and is an intermediate result used to prove it. -/ +lemma adjoin_eq_of_isAlgebraic_of_isSeparable [Algebra.IsAlgebraic F E] + [Algebra.IsSeparable E K] : adjoin E (separableClosure F K : Set K) = ⊤ := + top_unique fun x _ ↦ by + set S := separableClosure F K + set L := adjoin E (S : Set K) + have := Algebra.isSeparable_tower_top_of_isSeparable E L K + let i : S →+* L := Subsemiring.inclusion fun x hx ↦ subset_adjoin E (S : Set K) hx + let _ : Algebra S L := i.toAlgebra + let _ : SMul S L := Algebra.toSMul + have : IsScalarTower S L K := IsScalarTower.of_algebraMap_eq (congrFun rfl) + have : Algebra.IsAlgebraic F K := Algebra.IsAlgebraic.trans (L := E) + have : IsPurelyInseparable S K := separableClosure.isPurelyInseparable F K + have := IsPurelyInseparable.tower_top S L K + obtain ⟨y, rfl⟩ := IsPurelyInseparable.surjective_algebraMap_of_isSeparable L K x + exact y.2 + +/-- If `K / E / F` is a field extension tower, such that `E / F` is algebraic, then +`E` adjoin `separableClosure F K` is equal to `separableClosure E K`. -/ +theorem adjoin_eq_of_isAlgebraic [Algebra.IsAlgebraic F E] : + adjoin E (separableClosure F K) = separableClosure E K := by + set S := separableClosure E K + have h := congr_arg lift (adjoin_eq_of_isAlgebraic_of_isSeparable (F := F) S) + rw [lift_top, lift_adjoin] at h + haveI : IsScalarTower F S K := IsScalarTower.of_algebraMap_eq (congrFun rfl) + rw [← h, ← map_eq_of_separableClosure_eq_bot F (separableClosure_eq_bot E K)] + simp only [S, coe_map, IsScalarTower.coe_toAlgHom', IntermediateField.algebraMap_apply] + +end separableClosure diff --git a/Mathlib/FieldTheory/PurelyInseparable/PerfectClosure.lean b/Mathlib/FieldTheory/PurelyInseparable/PerfectClosure.lean new file mode 100644 index 0000000000000..fb3adb8fe2e6a --- /dev/null +++ b/Mathlib/FieldTheory/PurelyInseparable/PerfectClosure.lean @@ -0,0 +1,410 @@ +/- +Copyright (c) 2024 Jz Pan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jz Pan +-/ +import Mathlib.Algebra.CharP.ExpChar +import Mathlib.Algebra.CharP.IntermediateField +import Mathlib.FieldTheory.PurelyInseparable.Basic + +/-! + +# Basic results about relative perfect closure + +This file contains basic results about relative perfect closures. + +## Main definitions + +- `perfectClosure`: the relative perfect closure of `F` in `E`, it consists of the elements + `x` of `E` such that there exists a natural number `n` such that `x ^ (ringExpChar F) ^ n` + is contained in `F`, where `ringExpChar F` is the exponential characteristic of `F`. + It is also the maximal purely inseparable subextension of `E / F` (`le_perfectClosure_iff`). + +## Main results + +- `le_perfectClosure_iff`: an intermediate field of `E / F` is contained in the relative perfect + closure of `F` in `E` if and only if it is purely inseparable over `F`. + +- `perfectClosure.perfectRing`, `perfectClosure.perfectField`: if `E` is a perfect field, then the + (relative) perfect closure `perfectClosure F E` is perfect. + +- `IntermediateField.isPurelyInseparable_adjoin_iff_pow_mem`: if `F` is of exponential + characteristic `q`, then `F(S) / F` is a purely inseparable extension if and only if for any + `x ∈ S`, `x ^ (q ^ n)` is contained in `F` for some `n : ℕ`. + +## Tags + +separable degree, degree, separable closure, purely inseparable + +-/ + +open IntermediateField + +noncomputable section + +universe u v w + +variable (F : Type u) (E : Type v) [Field F] [Field E] [Algebra F E] +variable (K : Type w) [Field K] [Algebra F K] + +section perfectClosure + +/-- The relative perfect closure of `F` in `E`, consists of the elements `x` of `E` such that there +exists a natural number `n` such that `x ^ (ringExpChar F) ^ n` is contained in `F`, where +`ringExpChar F` is the exponential characteristic of `F`. It is also the maximal purely inseparable +subextension of `E / F` (`le_perfectClosure_iff`). -/ +@[stacks 09HH] +def perfectClosure : IntermediateField F E where + carrier := {x : E | ∃ n : ℕ, x ^ (ringExpChar F) ^ n ∈ (algebraMap F E).range} + add_mem' := by + rintro x y ⟨n, hx⟩ ⟨m, hy⟩ + use n + m + have := expChar_of_injective_algebraMap (algebraMap F E).injective (ringExpChar F) + rw [add_pow_expChar_pow, pow_add, pow_mul, mul_comm (_ ^ n), pow_mul] + exact add_mem (pow_mem hx _) (pow_mem hy _) + mul_mem' := by + rintro x y ⟨n, hx⟩ ⟨m, hy⟩ + use n + m + rw [mul_pow, pow_add, pow_mul, mul_comm (_ ^ n), pow_mul] + exact mul_mem (pow_mem hx _) (pow_mem hy _) + inv_mem' := by + rintro x ⟨n, hx⟩ + use n; rw [inv_pow] + apply inv_mem (id hx : _ ∈ (⊥ : IntermediateField F E)) + algebraMap_mem' := fun x ↦ ⟨0, by rw [pow_zero, pow_one]; exact ⟨x, rfl⟩⟩ + +variable {F E} + +theorem mem_perfectClosure_iff {x : E} : + x ∈ perfectClosure F E ↔ ∃ n : ℕ, x ^ (ringExpChar F) ^ n ∈ (algebraMap F E).range := Iff.rfl + +theorem mem_perfectClosure_iff_pow_mem (q : ℕ) [ExpChar F q] {x : E} : + x ∈ perfectClosure F E ↔ ∃ n : ℕ, x ^ q ^ n ∈ (algebraMap F E).range := by + rw [mem_perfectClosure_iff, ringExpChar.eq F q] + +/-- An element is contained in the relative perfect closure if and only if its minimal polynomial +has separable degree one. -/ +theorem mem_perfectClosure_iff_natSepDegree_eq_one {x : E} : + x ∈ perfectClosure F E ↔ (minpoly F x).natSepDegree = 1 := by + rw [mem_perfectClosure_iff, minpoly.natSepDegree_eq_one_iff_pow_mem (ringExpChar F)] + +/-- A field extension `E / F` is purely inseparable if and only if the relative perfect closure of +`F` in `E` is equal to `E`. -/ +theorem isPurelyInseparable_iff_perfectClosure_eq_top : + IsPurelyInseparable F E ↔ perfectClosure F E = ⊤ := by + rw [isPurelyInseparable_iff_pow_mem F (ringExpChar F)] + exact ⟨fun H ↦ top_unique fun x _ ↦ H x, fun H _ ↦ H.ge trivial⟩ + +variable (F E) + +/-- The relative perfect closure of `F` in `E` is purely inseparable over `F`. -/ +instance perfectClosure.isPurelyInseparable : IsPurelyInseparable F (perfectClosure F E) := by + rw [isPurelyInseparable_iff_pow_mem F (ringExpChar F)] + exact fun ⟨_, n, y, h⟩ ↦ ⟨n, y, (algebraMap _ E).injective h⟩ + +/-- The relative perfect closure of `F` in `E` is algebraic over `F`. -/ +instance perfectClosure.isAlgebraic : Algebra.IsAlgebraic F (perfectClosure F E) := + IsPurelyInseparable.isAlgebraic F _ + +/-- If `E / F` is separable, then the perfect closure of `F` in `E` is equal to `F`. Note that + the converse is not necessarily true (see https://math.stackexchange.com/a/3009197) + even when `E / F` is algebraic. -/ +theorem perfectClosure.eq_bot_of_isSeparable [Algebra.IsSeparable F E] : perfectClosure F E = ⊥ := + haveI := Algebra.isSeparable_tower_bot_of_isSeparable F (perfectClosure F E) E + eq_bot_of_isPurelyInseparable_of_isSeparable _ + +/-- An intermediate field of `E / F` is contained in the relative perfect closure of `F` in `E` +if it is purely inseparable over `F`. -/ +theorem le_perfectClosure (L : IntermediateField F E) [h : IsPurelyInseparable F L] : + L ≤ perfectClosure F E := by + rw [isPurelyInseparable_iff_pow_mem F (ringExpChar F)] at h + intro x hx + obtain ⟨n, y, hy⟩ := h ⟨x, hx⟩ + exact ⟨n, y, congr_arg (algebraMap L E) hy⟩ + +/-- An intermediate field of `E / F` is contained in the relative perfect closure of `F` in `E` +if and only if it is purely inseparable over `F`. -/ +theorem le_perfectClosure_iff (L : IntermediateField F E) : + L ≤ perfectClosure F E ↔ IsPurelyInseparable F L := by + refine ⟨fun h ↦ (isPurelyInseparable_iff_pow_mem F (ringExpChar F)).2 fun x ↦ ?_, + fun _ ↦ le_perfectClosure F E L⟩ + obtain ⟨n, y, hy⟩ := h x.2 + exact ⟨n, y, (algebraMap L E).injective hy⟩ + +theorem separableClosure_inf_perfectClosure : separableClosure F E ⊓ perfectClosure F E = ⊥ := + haveI := (le_separableClosure_iff F E _).mp (inf_le_left (b := perfectClosure F E)) + haveI := (le_perfectClosure_iff F E _).mp (inf_le_right (a := separableClosure F E)) + eq_bot_of_isPurelyInseparable_of_isSeparable _ + +section map + +variable {F E K} + +/-- If `i` is an `F`-algebra homomorphism from `E` to `K`, then `i x` is contained in +`perfectClosure F K` if and only if `x` is contained in `perfectClosure F E`. -/ +theorem map_mem_perfectClosure_iff (i : E →ₐ[F] K) {x : E} : + i x ∈ perfectClosure F K ↔ x ∈ perfectClosure F E := by + simp_rw [mem_perfectClosure_iff] + refine ⟨fun ⟨n, y, h⟩ ↦ ⟨n, y, ?_⟩, fun ⟨n, y, h⟩ ↦ ⟨n, y, ?_⟩⟩ + · apply_fun i using i.injective + rwa [AlgHom.commutes, map_pow] + simpa only [AlgHom.commutes, map_pow] using congr_arg i h + +/-- If `i` is an `F`-algebra homomorphism from `E` to `K`, then the preimage of `perfectClosure F K` +under the map `i` is equal to `perfectClosure F E`. -/ +theorem perfectClosure.comap_eq_of_algHom (i : E →ₐ[F] K) : + (perfectClosure F K).comap i = perfectClosure F E := by + ext x + exact map_mem_perfectClosure_iff i + +/-- If `i` is an `F`-algebra homomorphism from `E` to `K`, then the image of `perfectClosure F E` +under the map `i` is contained in `perfectClosure F K`. -/ +theorem perfectClosure.map_le_of_algHom (i : E →ₐ[F] K) : + (perfectClosure F E).map i ≤ perfectClosure F K := + map_le_iff_le_comap.mpr (perfectClosure.comap_eq_of_algHom i).ge + +/-- If `i` is an `F`-algebra isomorphism of `E` and `K`, then the image of `perfectClosure F E` +under the map `i` is equal to in `perfectClosure F K`. -/ +theorem perfectClosure.map_eq_of_algEquiv (i : E ≃ₐ[F] K) : + (perfectClosure F E).map i.toAlgHom = perfectClosure F K := + (map_le_of_algHom i.toAlgHom).antisymm (fun x hx ↦ ⟨i.symm x, + (map_mem_perfectClosure_iff i.symm.toAlgHom).2 hx, i.right_inv x⟩) + +/-- If `E` and `K` are isomorphic as `F`-algebras, then `perfectClosure F E` and +`perfectClosure F K` are also isomorphic as `F`-algebras. -/ +def perfectClosure.algEquivOfAlgEquiv (i : E ≃ₐ[F] K) : + perfectClosure F E ≃ₐ[F] perfectClosure F K := + (intermediateFieldMap i _).trans (equivOfEq (map_eq_of_algEquiv i)) + +alias AlgEquiv.perfectClosure := perfectClosure.algEquivOfAlgEquiv + +end map + +/-- If `E` is a perfect field of exponential characteristic `p`, then the (relative) perfect closure +`perfectClosure F E` is perfect. -/ +instance perfectClosure.perfectRing (p : ℕ) [ExpChar E p] + [PerfectRing E p] : PerfectRing (perfectClosure F E) p := .ofSurjective _ p fun x ↦ by + haveI := RingHom.expChar _ (algebraMap F E).injective p + obtain ⟨x', hx⟩ := surjective_frobenius E p x.1 + obtain ⟨n, y, hy⟩ := (mem_perfectClosure_iff_pow_mem p).1 x.2 + rw [frobenius_def] at hx + rw [← hx, ← pow_mul, ← pow_succ'] at hy + exact ⟨⟨x', (mem_perfectClosure_iff_pow_mem p).2 ⟨n + 1, y, hy⟩⟩, by + simp_rw [frobenius_def, SubmonoidClass.mk_pow, hx]⟩ + +/-- If `E` is a perfect field, then the (relative) perfect closure +`perfectClosure F E` is perfect. -/ +instance perfectClosure.perfectField [PerfectField E] : PerfectField (perfectClosure F E) := + PerfectRing.toPerfectField _ (ringExpChar E) + +end perfectClosure + +namespace IntermediateField + +/-- `F⟮x⟯ / F` is a purely inseparable extension if and only if the minimal polynomial of `x` +has separable degree one. -/ +theorem isPurelyInseparable_adjoin_simple_iff_natSepDegree_eq_one {x : E} : + IsPurelyInseparable F F⟮x⟯ ↔ (minpoly F x).natSepDegree = 1 := by + rw [← le_perfectClosure_iff, adjoin_simple_le_iff, mem_perfectClosure_iff_natSepDegree_eq_one] + +/-- If `F` is of exponential characteristic `q`, then `F⟮x⟯ / F` is a purely inseparable extension +if and only if `x ^ (q ^ n)` is contained in `F` for some `n : ℕ`. -/ +theorem isPurelyInseparable_adjoin_simple_iff_pow_mem (q : ℕ) [hF : ExpChar F q] {x : E} : + IsPurelyInseparable F F⟮x⟯ ↔ ∃ n : ℕ, x ^ q ^ n ∈ (algebraMap F E).range := by + rw [← le_perfectClosure_iff, adjoin_simple_le_iff, mem_perfectClosure_iff_pow_mem q] + +/-- If `F` is of exponential characteristic `q`, then `F(S) / F` is a purely inseparable extension +if and only if for any `x ∈ S`, `x ^ (q ^ n)` is contained in `F` for some `n : ℕ`. -/ +theorem isPurelyInseparable_adjoin_iff_pow_mem (q : ℕ) [hF : ExpChar F q] {S : Set E} : + IsPurelyInseparable F (adjoin F S) ↔ ∀ x ∈ S, ∃ n : ℕ, x ^ q ^ n ∈ (algebraMap F E).range := by + simp_rw [← le_perfectClosure_iff, adjoin_le_iff, ← mem_perfectClosure_iff_pow_mem q, + Set.subset_def, SetLike.mem_coe] + +/-- A compositum of two purely inseparable extensions is purely inseparable. -/ +instance isPurelyInseparable_sup (L1 L2 : IntermediateField F E) + [h1 : IsPurelyInseparable F L1] [h2 : IsPurelyInseparable F L2] : + IsPurelyInseparable F (L1 ⊔ L2 : IntermediateField F E) := by + rw [← le_perfectClosure_iff] at h1 h2 ⊢ + exact sup_le h1 h2 + +/-- A compositum of purely inseparable extensions is purely inseparable. -/ +instance isPurelyInseparable_iSup {ι : Sort*} {t : ι → IntermediateField F E} + [h : ∀ i, IsPurelyInseparable F (t i)] : + IsPurelyInseparable F (⨆ i, t i : IntermediateField F E) := by + simp_rw [← le_perfectClosure_iff] at h ⊢ + exact iSup_le h + +/-- If `F` is a field of exponential characteristic `q`, `F(S) / F` is separable, then +`F(S) = F(S ^ (q ^ n))` for any natural number `n`. -/ +theorem adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable (S : Set E) + [Algebra.IsSeparable F (adjoin F S)] (q : ℕ) [ExpChar F q] (n : ℕ) : + adjoin F S = adjoin F ((· ^ q ^ n) '' S) := by + set L := adjoin F S + set M := adjoin F ((· ^ q ^ n) '' S) + have hi : M ≤ L := by + rw [adjoin_le_iff] + rintro _ ⟨y, hy, rfl⟩ + exact pow_mem (subset_adjoin F S hy) _ + letI := (inclusion hi).toAlgebra + haveI : Algebra.IsSeparable M (extendScalars hi) := + Algebra.isSeparable_tower_top_of_isSeparable F M L + haveI : IsPurelyInseparable M (extendScalars hi) := by + haveI := expChar_of_injective_algebraMap (algebraMap F M).injective q + rw [extendScalars_adjoin hi, isPurelyInseparable_adjoin_iff_pow_mem M _ q] + exact fun x hx ↦ ⟨n, ⟨x ^ q ^ n, subset_adjoin F _ ⟨x, hx, rfl⟩⟩, rfl⟩ + simpa only [extendScalars_restrictScalars, restrictScalars_bot_eq_self] using congr_arg + (restrictScalars F) (extendScalars hi).eq_bot_of_isPurelyInseparable_of_isSeparable + +/-- If `E / F` is a separable field extension of exponential characteristic `q`, then +`F(S) = F(S ^ (q ^ n))` for any subset `S` of `E` and any natural number `n`. -/ +theorem adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable' [Algebra.IsSeparable F E] (S : Set E) + (q : ℕ) [ExpChar F q] (n : ℕ) : adjoin F S = adjoin F ((· ^ q ^ n) '' S) := + haveI := Algebra.isSeparable_tower_bot_of_isSeparable F (adjoin F S) E + adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable F E S q n + +-- TODO: prove the converse when `F(S) / F` is finite +/-- If `F` is a field of exponential characteristic `q`, `F(S) / F` is separable, then +`F(S) = F(S ^ q)`. -/ +theorem adjoin_eq_adjoin_pow_expChar_of_isSeparable (S : Set E) [Algebra.IsSeparable F (adjoin F S)] + (q : ℕ) [ExpChar F q] : adjoin F S = adjoin F ((· ^ q) '' S) := + pow_one q ▸ adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable F E S q 1 + +/-- If `E / F` is a separable field extension of exponential characteristic `q`, then +`F(S) = F(S ^ q)` for any subset `S` of `E`. -/ +theorem adjoin_eq_adjoin_pow_expChar_of_isSeparable' [Algebra.IsSeparable F E] (S : Set E) + (q : ℕ) [ExpChar F q] : adjoin F S = adjoin F ((· ^ q) '' S) := + pow_one q ▸ adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable' F E S q 1 + +-- Special cases for simple adjoin + +/-- If `F` is a field of exponential characteristic `q`, `a : E` is separable over `F`, then +`F⟮a⟯ = F⟮a ^ q ^ n⟯` for any natural number `n`. -/ +theorem adjoin_simple_eq_adjoin_pow_expChar_pow_of_isSeparable {a : E} (ha : IsSeparable F a) + (q : ℕ) [ExpChar F q] (n : ℕ) : F⟮a⟯ = F⟮a ^ q ^ n⟯ := by + haveI := (isSeparable_adjoin_simple_iff_isSeparable F E).mpr ha + simpa using adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable F E {a} q n + +/-- If `E / F` is a separable field extension of exponential characteristic `q`, then +`F⟮a⟯ = F⟮a ^ q ^ n⟯` for any subset `a : E` and any natural number `n`. -/ +theorem adjoin_simple_eq_adjoin_pow_expChar_pow_of_isSeparable' [Algebra.IsSeparable F E] (a : E) + (q : ℕ) [ExpChar F q] (n : ℕ) : F⟮a⟯ = F⟮a ^ q ^ n⟯ := by + haveI := Algebra.isSeparable_tower_bot_of_isSeparable F F⟮a⟯ E + simpa using adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable F E {a} q n + +/-- If `F` is a field of exponential characteristic `q`, `a : E` is separable over `F`, then +`F⟮a⟯ = F⟮a ^ q⟯`. -/ +theorem adjoin_simple_eq_adjoin_pow_expChar_of_isSeparable {a : E} (ha : IsSeparable F a) + (q : ℕ) [ExpChar F q] : F⟮a⟯ = F⟮a ^ q⟯ := + pow_one q ▸ adjoin_simple_eq_adjoin_pow_expChar_pow_of_isSeparable F E ha q 1 + +/-- If `E / F` is a separable field extension of exponential characteristic `q`, then +`F⟮a⟯ = F⟮a ^ q⟯` for any `a : E`. -/ +theorem adjoin_simple_eq_adjoin_pow_expChar_of_isSeparable' [Algebra.IsSeparable F E] (a : E) + (q : ℕ) [ExpChar F q] : F⟮a⟯ = F⟮a ^ q⟯ := + pow_one q ▸ adjoin_simple_eq_adjoin_pow_expChar_pow_of_isSeparable' F E a q 1 + +end IntermediateField + +section + +variable (q n : ℕ) [hF : ExpChar F q] {ι : Type*} {v : ι → E} {F E} + +/-- If `E / F` is a separable extension of exponential characteristic `q`, if `{ u_i }` is a family +of elements of `E` which `F`-linearly spans `E`, then `{ u_i ^ (q ^ n) }` also `F`-linearly spans +`E` for any natural number `n`. -/ +theorem Field.span_map_pow_expChar_pow_eq_top_of_isSeparable [Algebra.IsSeparable F E] + (h : Submodule.span F (Set.range v) = ⊤) : + Submodule.span F (Set.range (v · ^ q ^ n)) = ⊤ := by + erw [← Algebra.top_toSubmodule, ← top_toSubalgebra, ← adjoin_univ, + adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable' F E _ q n, + adjoin_algebraic_toSubalgebra fun x _ ↦ Algebra.IsAlgebraic.isAlgebraic x, + Set.image_univ, Algebra.adjoin_eq_span, (powMonoidHom _).mrange.closure_eq] + refine (Submodule.span_mono <| Set.range_comp_subset_range _ _).antisymm (Submodule.span_le.2 ?_) + rw [Set.range_comp, ← Set.image_univ] + haveI := expChar_of_injective_algebraMap (algebraMap F E).injective q + apply h ▸ Submodule.image_span_subset_span (LinearMap.iterateFrobenius F E q n) _ + +/-- If `E / F` is a finite separable extension of exponential characteristic `q`, if `{ u_i }` is a +family of elements of `E` which is `F`-linearly independent, then `{ u_i ^ (q ^ n) }` is also +`F`-linearly independent for any natural number `n`. A special case of +`LinearIndependent.map_pow_expChar_pow_of_isSeparable` +and is an intermediate result used to prove it. -/ +private theorem LinearIndependent.map_pow_expChar_pow_of_fd_isSeparable + [FiniteDimensional F E] [Algebra.IsSeparable F E] + (h : LinearIndependent F v) : LinearIndependent F (v · ^ q ^ n) := by + have h' := h.coe_range + let ι' := h'.extend (Set.range v).subset_univ + let b : Basis ι' F E := Basis.extend h' + letI : Fintype ι' := FiniteDimensional.fintypeBasisIndex b + have H := linearIndependent_of_top_le_span_of_card_eq_finrank + (Field.span_map_pow_expChar_pow_eq_top_of_isSeparable q n b.span_eq).ge + (Module.finrank_eq_card_basis b).symm + let f (i : ι) : ι' := ⟨v i, h'.subset_extend _ ⟨i, rfl⟩⟩ + convert H.comp f fun _ _ heq ↦ h.injective (by simpa only [f, Subtype.mk.injEq] using heq) + simp_rw [Function.comp_apply, b] + rw [Basis.extend_apply_self] + +/-- If `E / F` is a separable extension of exponential characteristic `q`, if `{ u_i }` is a +family of elements of `E` which is `F`-linearly independent, then `{ u_i ^ (q ^ n) }` is also +`F`-linearly independent for any natural number `n`. -/ +theorem LinearIndependent.map_pow_expChar_pow_of_isSeparable [Algebra.IsSeparable F E] + (h : LinearIndependent F v) : LinearIndependent F (v · ^ q ^ n) := by + classical + have halg := Algebra.IsSeparable.isAlgebraic F E + rw [linearIndependent_iff_finset_linearIndependent] at h ⊢ + intro s + let E' := adjoin F (s.image v : Set E) + haveI : FiniteDimensional F E' := finiteDimensional_adjoin + fun x _ ↦ Algebra.IsIntegral.isIntegral x + haveI : Algebra.IsSeparable F E' := Algebra.isSeparable_tower_bot_of_isSeparable F E' E + let v' (i : s) : E' := ⟨v i.1, subset_adjoin F _ (Finset.mem_image.2 ⟨i.1, i.2, rfl⟩)⟩ + have h' : LinearIndependent F v' := (h s).of_comp E'.val.toLinearMap + exact (h'.map_pow_expChar_pow_of_fd_isSeparable q n).map' + E'.val.toLinearMap (LinearMap.ker_eq_bot_of_injective E'.val.injective) + +/-- If `E / F` is a field extension of exponential characteristic `q`, if `{ u_i }` is a +family of separable elements of `E` which is `F`-linearly independent, then `{ u_i ^ (q ^ n) }` +is also `F`-linearly independent for any natural number `n`. -/ +theorem LinearIndependent.map_pow_expChar_pow_of_isSeparable' + (hsep : ∀ i : ι, IsSeparable F (v i)) + (h : LinearIndependent F v) : LinearIndependent F (v · ^ q ^ n) := by + let E' := adjoin F (Set.range v) + haveI : Algebra.IsSeparable F E' := (isSeparable_adjoin_iff_isSeparable F _).2 <| by + rintro _ ⟨y, rfl⟩; exact hsep y + let v' (i : ι) : E' := ⟨v i, subset_adjoin F _ ⟨i, rfl⟩⟩ + have h' : LinearIndependent F v' := h.of_comp E'.val.toLinearMap + exact (h'.map_pow_expChar_pow_of_isSeparable q n).map' + E'.val.toLinearMap (LinearMap.ker_eq_bot_of_injective E'.val.injective) + +/-- If `E / F` is a separable extension of exponential characteristic `q`, if `{ u_i }` is an +`F`-basis of `E`, then `{ u_i ^ (q ^ n) }` is also an `F`-basis of `E` +for any natural number `n`. -/ +def Basis.mapPowExpCharPowOfIsSeparable [Algebra.IsSeparable F E] + (b : Basis ι F E) : Basis ι F E := + Basis.mk (b.linearIndependent.map_pow_expChar_pow_of_isSeparable q n) + (Field.span_map_pow_expChar_pow_eq_top_of_isSeparable q n b.span_eq).ge + +end + +theorem perfectField_of_perfectClosure_eq_bot [h : PerfectField E] (eq : perfectClosure F E = ⊥) : + PerfectField F := by + let p := ringExpChar F + haveI := expChar_of_injective_algebraMap (algebraMap F E).injective p + haveI := PerfectRing.ofSurjective F p fun x ↦ by + obtain ⟨y, h⟩ := surjective_frobenius E p (algebraMap F E x) + have : y ∈ perfectClosure F E := ⟨1, x, by rw [← h, pow_one, frobenius_def, ringExpChar.eq F p]⟩ + obtain ⟨z, rfl⟩ := eq ▸ this + exact ⟨z, (algebraMap F E).injective (by erw [RingHom.map_frobenius, h])⟩ + exact PerfectRing.toPerfectField F p + +/-- If `E / F` is a separable extension, `E` is perfect, then `F` is also prefect. -/ +theorem perfectField_of_isSeparable_of_perfectField_top [Algebra.IsSeparable F E] [PerfectField E] : + PerfectField F := + perfectField_of_perfectClosure_eq_bot F E (perfectClosure.eq_bot_of_isSeparable F E) + +/-- If `E` is an algebraic closure of `F`, then `F` is perfect if and only if `E / F` is +separable. -/ +theorem perfectField_iff_isSeparable_algebraicClosure [IsAlgClosure F E] : + PerfectField F ↔ Algebra.IsSeparable F E := + ⟨fun _ ↦ IsSepClosure.separable, fun _ ↦ haveI : IsAlgClosed E := IsAlgClosure.isAlgClosed F + perfectField_of_isSeparable_of_perfectField_top F E⟩ diff --git a/Mathlib/FieldTheory/PurelyInseparable/Tower.lean b/Mathlib/FieldTheory/PurelyInseparable/Tower.lean new file mode 100644 index 0000000000000..715d67ee39e47 --- /dev/null +++ b/Mathlib/FieldTheory/PurelyInseparable/Tower.lean @@ -0,0 +1,242 @@ +/- +Copyright (c) 2024 Jz Pan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jz Pan +-/ +import Mathlib.FieldTheory.PurelyInseparable.PerfectClosure + +/-! + +# Tower law for purely inseparable extensions + +This file contains results related to `Field.finIsepDegree` and the tower law. + +## Main results + +- `Field.lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic`: the separable degrees satisfy the + tower law: $[E:F]_s [K:E]_s = [K:F]_s$. + +- `IntermediateField.sepDegree_adjoin_eq_of_isAlgebraic_of_isPurelyInseparable`, + `IntermediateField.sepDegree_adjoin_eq_of_isAlgebraic_of_isPurelyInseparable'`: + if `K / E / F` is a field extension tower, such that `E / F` is purely inseparable, then + for any subset `S` of `K` such that `F(S) / F` is algebraic, the `E(S) / E` and `F(S) / F` have + the same separable degree. In particular, if `S` is an intermediate field of `K / F` such that + `S / F` is algebraic, the `E(S) / E` and `S / F` have the same separable degree. + +- `minpoly.map_eq_of_isSeparable_of_isPurelyInseparable`: if `K / E / F` is a field extension tower, + such that `E / F` is purely inseparable, then for any element `x` of `K` separable over `F`, + it has the same minimal polynomials over `F` and over `E`. + +- `Polynomial.Separable.map_irreducible_of_isPurelyInseparable`: if `E / F` is purely inseparable, + `f` is a separable irreducible polynomial over `F`, then it is also irreducible over `E`. + +## Tags + +separable degree, degree, separable closure, purely inseparable + +## TODO + +- Restate some intermediate result in terms of linearly disjointness. + +- Prove that the inseparable degrees satisfy the tower law: $[E:F]_i [K:E]_i = [K:F]_i$. + Probably an argument using linearly disjointness is needed. + +-/ + +open Polynomial IntermediateField Field + +noncomputable section + +universe u v w + +section TowerLaw + +variable (F : Type u) (E : Type v) [Field F] [Field E] [Algebra F E] +variable (K : Type w) [Field K] [Algebra F K] + +variable [Algebra E K] [IsScalarTower F E K] + +variable {F K} in +/-- If `K / E / F` is a field extension tower such that `E / F` is purely inseparable, +if `{ u_i }` is a family of separable elements of `K` which is `F`-linearly independent, +then it is also `E`-linearly independent. -/ +theorem LinearIndependent.map_of_isPurelyInseparable_of_isSeparable [IsPurelyInseparable F E] + {ι : Type*} {v : ι → K} (hsep : ∀ i : ι, IsSeparable F (v i)) + (h : LinearIndependent F v) : LinearIndependent E v := by + obtain ⟨q, _⟩ := ExpChar.exists F + haveI := expChar_of_injective_algebraMap (algebraMap F K).injective q + refine linearIndependent_iff.mpr fun l hl ↦ Finsupp.ext fun i ↦ ?_ + choose f hf using fun i ↦ (isPurelyInseparable_iff_pow_mem F q).1 ‹_› (l i) + let n := l.support.sup f + have := (expChar_pow_pos F q n).ne' + replace hf (i : ι) : l i ^ q ^ n ∈ (algebraMap F E).range := by + by_cases hs : i ∈ l.support + · convert pow_mem (hf i) (q ^ (n - f i)) using 1 + rw [← pow_mul, ← pow_add, Nat.add_sub_of_le (Finset.le_sup hs)] + exact ⟨0, by rw [map_zero, Finsupp.not_mem_support_iff.1 hs, zero_pow this]⟩ + choose lF hlF using hf + let lF₀ := Finsupp.onFinset l.support lF fun i ↦ by + contrapose! + refine fun hs ↦ (injective_iff_map_eq_zero _).mp (algebraMap F E).injective _ ?_ + rw [hlF, Finsupp.not_mem_support_iff.1 hs, zero_pow this] + replace h := linearIndependent_iff.1 (h.map_pow_expChar_pow_of_isSeparable' q n hsep) lF₀ <| by + replace hl := congr($hl ^ q ^ n) + rw [Finsupp.linearCombination_apply, Finsupp.sum, sum_pow_char_pow, zero_pow this] at hl + rw [← hl, Finsupp.linearCombination_apply, + Finsupp.onFinset_sum _ (fun _ ↦ by exact zero_smul _ _)] + refine Finset.sum_congr rfl fun i _ ↦ ?_ + simp_rw [Algebra.smul_def, mul_pow, IsScalarTower.algebraMap_apply F E K, hlF, map_pow] + refine pow_eq_zero ((hlF _).symm.trans ?_) + convert map_zero (algebraMap F E) + exact congr($h i) + +namespace Field + +/-- If `K / E / F` is a field extension tower, such that `E / F` is purely inseparable and `K / E` +is separable, then the separable degree of `K / F` is equal to the degree of `K / E`. +It is a special case of `Field.lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic`, and is an +intermediate result used to prove it. -/ +lemma sepDegree_eq_of_isPurelyInseparable_of_isSeparable + [IsPurelyInseparable F E] [Algebra.IsSeparable E K] : sepDegree F K = Module.rank E K := by + let S := separableClosure F K + have h := S.adjoin_rank_le_of_isAlgebraic_right E + rw [separableClosure.adjoin_eq_of_isAlgebraic_of_isSeparable K, rank_top'] at h + obtain ⟨ι, ⟨b⟩⟩ := Basis.exists_basis F S + exact h.antisymm' (b.mk_eq_rank'' ▸ (b.linearIndependent.map' S.val.toLinearMap + (LinearMap.ker_eq_bot_of_injective S.val.injective) + |>.map_of_isPurelyInseparable_of_isSeparable E (fun i ↦ + by simpa only [IsSeparable, minpoly_eq] using Algebra.IsSeparable.isSeparable F (b i)) + |>.cardinal_le_rank)) + +/-- If `K / E / F` is a field extension tower, such that `E / F` is separable, +then $[E:F] [K:E]_s = [K:F]_s$. +It is a special case of `Field.lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic`, and is an +intermediate result used to prove it. -/ +lemma lift_rank_mul_lift_sepDegree_of_isSeparable [Algebra.IsSeparable F E] : + Cardinal.lift.{w} (Module.rank F E) * Cardinal.lift.{v} (sepDegree E K) = + Cardinal.lift.{v} (sepDegree F K) := by + rw [sepDegree, sepDegree, separableClosure.eq_restrictScalars_of_isSeparable F E K] + exact lift_rank_mul_lift_rank F E (separableClosure E K) + +/-- The same-universe version of `Field.lift_rank_mul_lift_sepDegree_of_isSeparable`. -/ +lemma rank_mul_sepDegree_of_isSeparable (K : Type v) [Field K] [Algebra F K] + [Algebra E K] [IsScalarTower F E K] [Algebra.IsSeparable F E] : + Module.rank F E * sepDegree E K = sepDegree F K := by + simpa only [Cardinal.lift_id] using lift_rank_mul_lift_sepDegree_of_isSeparable F E K + +/-- If `K / E / F` is a field extension tower, such that `E / F` is purely inseparable, +then $[K:F]_s = [K:E]_s$. +It is a special case of `Field.lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic`, and is an +intermediate result used to prove it. -/ +lemma sepDegree_eq_of_isPurelyInseparable [IsPurelyInseparable F E] : + sepDegree F K = sepDegree E K := by + convert sepDegree_eq_of_isPurelyInseparable_of_isSeparable F E (separableClosure E K) + haveI : IsScalarTower F (separableClosure E K) K := IsScalarTower.of_algebraMap_eq (congrFun rfl) + rw [sepDegree, ← separableClosure.map_eq_of_separableClosure_eq_bot F + (separableClosure.separableClosure_eq_bot E K)] + exact (separableClosure F (separableClosure E K)).equivMap + (IsScalarTower.toAlgHom F (separableClosure E K) K) |>.symm.toLinearEquiv.rank_eq + +/-- If `K / E / F` is a field extension tower, such that `E / F` is algebraic, then their +separable degrees satisfy the tower law: $[E:F]_s [K:E]_s = [K:F]_s$. -/ +theorem lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic [Algebra.IsAlgebraic F E] : + Cardinal.lift.{w} (sepDegree F E) * Cardinal.lift.{v} (sepDegree E K) = + Cardinal.lift.{v} (sepDegree F K) := by + have h := lift_rank_mul_lift_sepDegree_of_isSeparable F (separableClosure F E) K + haveI := separableClosure.isPurelyInseparable F E + rwa [sepDegree_eq_of_isPurelyInseparable (separableClosure F E) E K] at h + +/-- The same-universe version of `Field.lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic`. -/ +@[stacks 09HK "Part 1"] +theorem sepDegree_mul_sepDegree_of_isAlgebraic (K : Type v) [Field K] [Algebra F K] + [Algebra E K] [IsScalarTower F E K] [Algebra.IsAlgebraic F E] : + sepDegree F E * sepDegree E K = sepDegree F K := by + simpa only [Cardinal.lift_id] using lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic F E K + +end Field + +variable {F K} in +/-- If `K / E / F` is a field extension tower, such that `E / F` is purely inseparable, then +for any subset `S` of `K` such that `F(S) / F` is algebraic, the `E(S) / E` and `F(S) / F` have +the same separable degree. -/ +theorem IntermediateField.sepDegree_adjoin_eq_of_isAlgebraic_of_isPurelyInseparable + (S : Set K) [Algebra.IsAlgebraic F (adjoin F S)] [IsPurelyInseparable F E] : + sepDegree E (adjoin E S) = sepDegree F (adjoin F S) := by + set M := adjoin F S + set L := adjoin E S + let E' := (IsScalarTower.toAlgHom F E K).fieldRange + let j : E ≃ₐ[F] E' := AlgEquiv.ofInjectiveField (IsScalarTower.toAlgHom F E K) + have hi : M ≤ L.restrictScalars F := by + rw [restrictScalars_adjoin_of_algEquiv (E := K) j rfl, restrictScalars_adjoin] + exact adjoin.mono _ _ _ Set.subset_union_right + let i : M →+* L := Subsemiring.inclusion hi + letI : Algebra M L := i.toAlgebra + letI : SMul M L := Algebra.toSMul + haveI : IsScalarTower F M L := IsScalarTower.of_algebraMap_eq (congrFun rfl) + haveI : IsPurelyInseparable M L := by + change IsPurelyInseparable M (extendScalars hi) + obtain ⟨q, _⟩ := ExpChar.exists F + have : extendScalars hi = adjoin M (E' : Set K) := restrictScalars_injective F <| by + conv_lhs => rw [extendScalars_restrictScalars, restrictScalars_adjoin_of_algEquiv + (E := K) j rfl, ← adjoin_self F E', adjoin_adjoin_comm] + rw [this, isPurelyInseparable_adjoin_iff_pow_mem _ _ q] + rintro x ⟨y, hy⟩ + obtain ⟨n, z, hz⟩ := IsPurelyInseparable.pow_mem F q y + refine ⟨n, algebraMap F M z, ?_⟩ + rw [← IsScalarTower.algebraMap_apply, IsScalarTower.algebraMap_apply F E K, hz, ← hy, map_pow, + AlgHom.toRingHom_eq_coe, IsScalarTower.coe_toAlgHom] + have h := lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic F E L + rw [IsPurelyInseparable.sepDegree_eq_one F E, Cardinal.lift_one, one_mul] at h + rw [Cardinal.lift_injective h, ← sepDegree_mul_sepDegree_of_isAlgebraic F M L, + IsPurelyInseparable.sepDegree_eq_one M L, mul_one] + +variable {F K} in +/-- If `K / E / F` is a field extension tower, such that `E / F` is purely inseparable, then +for any intermediate field `S` of `K / F` such that `S / F` is algebraic, the `E(S) / E` and +`S / F` have the same separable degree. -/ +theorem IntermediateField.sepDegree_adjoin_eq_of_isAlgebraic_of_isPurelyInseparable' + (S : IntermediateField F K) [Algebra.IsAlgebraic F S] [IsPurelyInseparable F E] : + sepDegree E (adjoin E (S : Set K)) = sepDegree F S := by + have : Algebra.IsAlgebraic F (adjoin F (S : Set K)) := by rwa [adjoin_self] + have := sepDegree_adjoin_eq_of_isAlgebraic_of_isPurelyInseparable (F := F) E (S : Set K) + rwa [adjoin_self] at this + +variable {F K} in +/-- If `K / E / F` is a field extension tower, such that `E / F` is purely inseparable, then +for any element `x` of `K` separable over `F`, it has the same minimal polynomials over `F` and +over `E`. -/ +theorem minpoly.map_eq_of_isSeparable_of_isPurelyInseparable (x : K) + (hsep : IsSeparable F x) [IsPurelyInseparable F E] : + (minpoly F x).map (algebraMap F E) = minpoly E x := by + have hi := IsSeparable.isIntegral hsep + have hi' : IsIntegral E x := IsIntegral.tower_top hi + refine eq_of_monic_of_dvd_of_natDegree_le (monic hi') ((monic hi).map (algebraMap F E)) + (dvd_map_of_isScalarTower F E x) (le_of_eq ?_) + have hsep' := IsSeparable.tower_top E hsep + haveI := (isSeparable_adjoin_simple_iff_isSeparable _ _).2 hsep + haveI := (isSeparable_adjoin_simple_iff_isSeparable _ _).2 hsep' + have := Algebra.IsSeparable.isAlgebraic F F⟮x⟯ + have := Algebra.IsSeparable.isAlgebraic E E⟮x⟯ + rw [Polynomial.natDegree_map, ← adjoin.finrank hi, ← adjoin.finrank hi', + ← finSepDegree_eq_finrank_of_isSeparable F _, ← finSepDegree_eq_finrank_of_isSeparable E _, + finSepDegree_eq, finSepDegree_eq, + sepDegree_adjoin_eq_of_isAlgebraic_of_isPurelyInseparable (F := F) E] + +variable {F} in +/-- If `E / F` is a purely inseparable field extension, `f` is a separable irreducible polynomial +over `F`, then it is also irreducible over `E`. -/ +theorem Polynomial.Separable.map_irreducible_of_isPurelyInseparable {f : F[X]} (hsep : f.Separable) + (hirr : Irreducible f) [IsPurelyInseparable F E] : Irreducible (f.map (algebraMap F E)) := by + let K := AlgebraicClosure E + obtain ⟨x, hx⟩ := IsAlgClosed.exists_aeval_eq_zero K f + (natDegree_pos_iff_degree_pos.1 hirr.natDegree_pos).ne' + have ha : Associated f (minpoly F x) := by + have := isUnit_C.2 (leadingCoeff_ne_zero.2 hirr.ne_zero).isUnit.inv + exact ⟨this.unit, by rw [IsUnit.unit_spec, minpoly.eq_of_irreducible hirr hx]⟩ + have ha' : Associated (f.map (algebraMap F E)) ((minpoly F x).map (algebraMap F E)) := + ha.map (mapRingHom (algebraMap F E)).toMonoidHom + have heq := minpoly.map_eq_of_isSeparable_of_isPurelyInseparable E x (ha.separable hsep) + rw [ha'.irreducible_iff, heq] + exact minpoly.irreducible (Algebra.IsIntegral.isIntegral x) + +end TowerLaw diff --git a/Mathlib/RingTheory/Unramified/Field.lean b/Mathlib/RingTheory/Unramified/Field.lean index d2ba91b1bb3d9..35b6536cfcb58 100644 --- a/Mathlib/RingTheory/Unramified/Field.lean +++ b/Mathlib/RingTheory/Unramified/Field.lean @@ -3,7 +3,7 @@ Copyright (c) 2024 Andrew Yang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ -import Mathlib.FieldTheory.PurelyInseparable +import Mathlib.FieldTheory.PurelyInseparable.Basic import Mathlib.RingTheory.Artinian.Ring import Mathlib.RingTheory.LocalProperties.Basic import Mathlib.Algebra.Polynomial.Taylor From 4eafc86ea5a6c81fc9d4fc4519f577ded214015c Mon Sep 17 00:00:00 2001 From: Peter Pfaffelhuber Date: Mon, 3 Feb 2025 09:44:57 +0000 Subject: [PATCH 027/103] (sub-)additivity of an addContent on a (semi-)ring of sets (#21036) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (sub-)additivity of an addContent on a (semi-)ring of sets 2nd PR on the way to Caratheodorys extension theorem. Show monotonicity, additivity, and sub-additivity ↔ additivity (where mpr requires the content to be defined on a ring). Co-authored-by: Rémy Degenne - depends on: - #20931 - #15294 --> [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/from-referrer/) Co-authored-by: pfaffelh Co-authored-by: sgouezel Co-authored-by: RemyDegenne --- .../Order/BigOperators/Group/Finset.lean | 11 ++ Mathlib/Data/Set/Accumulate.lean | 4 + Mathlib/MeasureTheory/Measure/AddContent.lean | 139 +++++++++++++++++- Mathlib/MeasureTheory/SetSemiring.lean | 4 +- 4 files changed, 150 insertions(+), 8 deletions(-) diff --git a/Mathlib/Algebra/Order/BigOperators/Group/Finset.lean b/Mathlib/Algebra/Order/BigOperators/Group/Finset.lean index 411fb19700d73..f137d7941bb7d 100644 --- a/Mathlib/Algebra/Order/BigOperators/Group/Finset.lean +++ b/Mathlib/Algebra/Order/BigOperators/Group/Finset.lean @@ -207,6 +207,17 @@ theorem prod_le_prod_fiberwise_of_prod_fiber_le_one' {t : Finset ι'} {g : ι ∏ x ∈ s, f x ≤ ∏ y ∈ t, ∏ x ∈ s with g x = y, f x := @prod_fiberwise_le_prod_of_one_le_prod_fiber' _ Nᵒᵈ _ _ _ _ _ _ _ h +@[to_additive] +lemma prod_image_le_of_one_le + {g : ι → ι'} {f : ι' → N} (hf : ∀ u ∈ s.image g, 1 ≤ f u) : + ∏ u ∈ s.image g, f u ≤ ∏ u ∈ s, f (g u) := by + rw [prod_comp f g] + refine prod_le_prod' fun a hag ↦ ?_ + obtain ⟨i, hi, hig⟩ := Finset.mem_image.mp hag + apply le_self_pow (hf a hag) + rw [← Nat.pos_iff_ne_zero, card_pos] + exact ⟨i, mem_filter.mpr ⟨hi, hig⟩⟩ + end OrderedCommMonoid @[to_additive] diff --git a/Mathlib/Data/Set/Accumulate.lean b/Mathlib/Data/Set/Accumulate.lean index 72726156c5014..962b0e6cd928b 100644 --- a/Mathlib/Data/Set/Accumulate.lean +++ b/Mathlib/Data/Set/Accumulate.lean @@ -52,6 +52,10 @@ theorem iUnion_accumulate [Preorder α] : ⋃ x, Accumulate s x = ⋃ x, s x := exact ⟨x', hz⟩ · exact iUnion_mono fun i => subset_accumulate +@[simp] +lemma accumulate_bot [PartialOrder α] [OrderBot α] (s : α → Set β) : Accumulate s ⊥ = s ⊥ := by + simp [Set.accumulate_def] + @[simp] lemma accumulate_zero_nat (s : ℕ → Set β) : Accumulate s 0 = s 0 := by simp [accumulate_def] diff --git a/Mathlib/MeasureTheory/Measure/AddContent.lean b/Mathlib/MeasureTheory/Measure/AddContent.lean index 986010b3e928a..e64dc4d0e948d 100644 --- a/Mathlib/MeasureTheory/Measure/AddContent.lean +++ b/Mathlib/MeasureTheory/Measure/AddContent.lean @@ -4,8 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Rémy Degenne, Peter Pfaffelhuber -/ import Mathlib.MeasureTheory.SetSemiring -import Mathlib.Topology.Algebra.InfiniteSum.Defs -import Mathlib.Topology.Instances.ENNReal.Lemmas +import Mathlib.MeasureTheory.OuterMeasure.Induced /-! # Additive Contents @@ -28,25 +27,31 @@ Let `m` be an `AddContent C`. If `C` is a set semi-ring (`IsSetSemiring C`) we h * `MeasureTheory.sum_addContent_le_of_subset`: if `I` is a finset of pairwise disjoint sets in `C` and `⋃₀ I ⊆ t` for `t ∈ C`, then `∑ s ∈ I, m s ≤ m t`. * `MeasureTheory.addContent_mono`: if `s ⊆ t` for two sets in `C`, then `m s ≤ m t`. +* `MeasureTheory.addContent_sUnion_le_sum`: an `addContent C` on a `SetSemiring C` is + sub-additive. +* `MeasureTheory.addContent_iUnion_eq_tsum_of_disjoint_of_addContent_iUnion_le`: if an + `AddContent` is σ-subadditive on a semi-ring of sets, then it is σ-additive. * `MeasureTheory.addContent_union'`: if `s, t ∈ C` are disjoint and `s ∪ t ∈ C`, then `m (s ∪ t) = m s + m t`. If `C` is a set ring (`IsSetRing`), then `addContent_union` gives the same conclusion without the hypothesis `s ∪ t ∈ C` (since it is a consequence of `IsSetRing C`). -If `C` is a set ring (`MeasureTheory.IsSetRing C`), we have, for `s, t ∈ C`, +If `C` is a set ring (`MeasureTheory.IsSetRing C`), we have -* `MeasureTheory.addContent_union_le`: `m (s ∪ t) ≤ m s + m t` -* `MeasureTheory.addContent_le_diff`: `m s - m t ≤ m (s \ t)` +* `MeasureTheory.addContent_union_le`: for `s, t ∈ C`, `m (s ∪ t) ≤ m s + m t` +* `MeasureTheory.addContent_le_diff`: for `s, t ∈ C`, `m s - m t ≤ m (s \ t)` * `IsSetRing.addContent_of_union`: a function on a ring of sets which is additive on pairs of disjoint sets defines an additive content * `addContent_iUnion_eq_sum_of_tendsto_zero`: if an additive content is continuous at `∅`, then its value on a countable disjoint union is the sum of the values +* `MeasureTheory.addContent_iUnion_le_of_addContent_iUnion_eq_tsum`: if an `AddContent` is + σ-additive on a set ring, then it is σ-subadditive. -/ open Set Finset Function Filter -open scoped ENNReal Topology +open scoped ENNReal Topology Function namespace MeasureTheory @@ -124,6 +129,8 @@ lemma addContent_eq_add_disjointOfDiffUnion_of_subset (hC : IsSetSemiring C) exact hC.pairwiseDisjoint_union_disjointOfDiffUnion hs hI h_dis · rwa [hC.sUnion_union_disjointOfDiffUnion_of_subset hs hI hI_ss] +/-- For an `m : addContent C` on a `SetSemiring C`, if `I` is a `Finset` of pairwise disjoint + sets in `C` and `⋃₀ I ⊆ t` for `t ∈ C`, then `∑ s ∈ I, m s ≤ m t`.-/ lemma sum_addContent_le_of_subset (hC : IsSetSemiring C) (h_ss : ↑I ⊆ C) (h_dis : PairwiseDisjoint (I : Set (Set α)) id) (ht : t ∈ C) (hJt : ∀ s ∈ I, s ⊆ t) : @@ -132,6 +139,7 @@ lemma sum_addContent_le_of_subset (hC : IsSetSemiring C) rw [addContent_eq_add_disjointOfDiffUnion_of_subset hC ht h_ss hJt h_dis] exact le_add_right le_rfl +/-- An `addContent C` on a `SetSemiring C` is monotone. -/ lemma addContent_mono (hC : IsSetSemiring C) (hs : s ∈ C) (ht : t ∈ C) (hst : s ⊆ t) : m s ≤ m t := by @@ -141,8 +149,127 @@ lemma addContent_mono (hC : IsSetSemiring C) (hs : s ∈ C) (ht : t ∈ C) · simp only [coe_singleton, pairwiseDisjoint_singleton] · simp [hst] +/-- For an `m : addContent C` on a `SetSemiring C` and `s t : Set α` with `s ⊆ t`, we can write +`m t = m s + ∑ i in hC.disjointOfDiff ht hs, m i`.-/ +theorem eq_add_disjointOfDiff_of_subset (hC : IsSetSemiring C) + (hs : s ∈ C) (ht : t ∈ C) (hst : s ⊆ t) : + m t = m s + ∑ i ∈ hC.disjointOfDiff ht hs, m i := by + classical + conv_lhs => rw [← hC.sUnion_insert_disjointOfDiff ht hs hst] + rw [← coe_insert, addContent_sUnion] + · rw [sum_insert] + exact hC.nmem_disjointOfDiff ht hs + · rw [coe_insert] + exact Set.insert_subset hs (hC.subset_disjointOfDiff ht hs) + · rw [coe_insert] + exact hC.pairwiseDisjoint_insert_disjointOfDiff ht hs + · rw [coe_insert] + rwa [hC.sUnion_insert_disjointOfDiff ht hs hst] + +/-- An `addContent C` on a `SetSemiring C` is sub-additive.-/ +lemma addContent_sUnion_le_sum {m : AddContent C} (hC : IsSetSemiring C) + (J : Finset (Set α)) (h_ss : ↑J ⊆ C) (h_mem : ⋃₀ ↑J ∈ C) : + m (⋃₀ ↑J) ≤ ∑ u ∈ J, m u := by + classical + have h1 : (disjiUnion J (hC.disjointOfUnion h_ss) + (hC.pairwiseDisjoint_disjointOfUnion h_ss) : Set (Set α)) ⊆ C := by + simp only [disjiUnion_eq_biUnion, coe_biUnion, mem_coe, iUnion_subset_iff] + exact fun _ x ↦ hC.disjointOfUnion_subset h_ss x + have h2 : PairwiseDisjoint (disjiUnion J (hC.disjointOfUnion h_ss) + ((hC.pairwiseDisjoint_disjointOfUnion h_ss)) : Set (Set α)) id := by + simp only [disjiUnion_eq_biUnion, coe_biUnion, mem_coe] + exact hC.pairwiseDisjoint_biUnion_disjointOfUnion h_ss + have h3 : ⋃₀ J = ⋃₀ ((disjiUnion J (hC.disjointOfUnion h_ss) + (hC.pairwiseDisjoint_disjointOfUnion h_ss)) : Set (Set α)) := by + simp only [disjiUnion_eq_biUnion, coe_biUnion, mem_coe] + exact (Exists.choose_spec (hC.disjointOfUnion_props h_ss)).2.2.2.2.2 + rw [h3, addContent_sUnion h1 h2, sum_disjiUnion] + · apply sum_le_sum + intro x hx + refine sum_addContent_le_of_subset hC (hC.disjointOfUnion_subset h_ss hx) + (hC.pairwiseDisjoint_disjointOfUnion_of_mem h_ss hx) (h_ss hx) + (fun _ s ↦ hC.subset_of_mem_disjointOfUnion h_ss hx s) + · simp only [disjiUnion_eq_biUnion, coe_biUnion, mem_coe] at * + exact h3.symm ▸ h_mem + +lemma addContent_le_sum_of_subset_sUnion {m : AddContent C} (hC : IsSetSemiring C) + {J : Finset (Set α)} (h_ss : ↑J ⊆ C) (ht : t ∈ C) (htJ : t ⊆ ⋃₀ ↑J) : + m t ≤ ∑ u ∈ J, m u := by + -- we can't apply `addContent_mono` and `addContent_sUnion_le_sum` because `⋃₀ ↑J` might not + -- be in `C` + classical + let Jt := J.image (fun u ↦ t ∩ u) + have ht_eq : t = ⋃₀ Jt := by + rw [coe_image, sUnion_image, ← inter_iUnion₂, inter_eq_self_of_subset_left] + rwa [← sUnion_eq_biUnion] + rw [ht_eq] + refine (addContent_sUnion_le_sum hC Jt ?_ ?_).trans ?_ + · intro s + simp only [Jt, coe_image, Set.mem_image, mem_coe, forall_exists_index, and_imp] + rintro u hu rfl + exact hC.inter_mem _ ht _ (h_ss hu) + · rwa [← ht_eq] + · refine (Finset.sum_image_le_of_nonneg fun _ _ ↦ zero_le _).trans (sum_le_sum fun u hu ↦ ?_) + exact addContent_mono hC (hC.inter_mem _ ht _ (h_ss hu)) (h_ss hu) inter_subset_right + +/-- If an `AddContent` is σ-subadditive on a semi-ring of sets, then it is σ-additive. -/ +theorem addContent_iUnion_eq_tsum_of_disjoint_of_addContent_iUnion_le {m : AddContent C} + (hC : IsSetSemiring C) + (m_subadd : ∀ (f : ℕ → Set α) (_ : ∀ i, f i ∈ C) (_ : ⋃ i, f i ∈ C) + (_hf_disj : Pairwise (Disjoint on f)), m (⋃ i, f i) ≤ ∑' i, m (f i)) + (f : ℕ → Set α) (hf : ∀ i, f i ∈ C) (hf_Union : (⋃ i, f i) ∈ C) + (hf_disj : Pairwise (Disjoint on f)) : + m (⋃ i, f i) = ∑' i, m (f i) := by + refine le_antisymm (m_subadd f hf hf_Union hf_disj) ?_ + refine tsum_le_of_sum_le ENNReal.summable fun I ↦ ?_ + classical + rw [← Finset.sum_image_of_disjoint addContent_empty (hf_disj.pairwiseDisjoint _)] + refine sum_addContent_le_of_subset hC (I := I.image f) ?_ ?_ hf_Union ?_ + · simp only [coe_image, Set.image_subset_iff] + refine (subset_preimage_image f I).trans (preimage_mono ?_) + rintro i ⟨j, _, rfl⟩ + exact hf j + · simp only [coe_image] + intro s hs t ht hst + rw [Set.mem_image] at hs ht + obtain ⟨i, _, rfl⟩ := hs + obtain ⟨j, _, rfl⟩ := ht + have hij : i ≠ j := by intro h_eq; rw [h_eq] at hst; exact hst rfl + exact hf_disj hij + · simp only [Finset.mem_image, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂] + exact fun i _ ↦ subset_iUnion _ i + end IsSetSemiring +section AddContentExtend + +/-- An additive content obtained from another one on the same semiring of sets by setting the value +of each set not in the semiring at `∞`. -/ +protected noncomputable +def AddContent.extend (hC : IsSetSemiring C) (m : AddContent C) : AddContent C where + toFun := extend (fun x (_ : x ∈ C) ↦ m x) + empty' := by rw [extend_eq, addContent_empty]; exact hC.empty_mem + sUnion' I h_ss h_dis h_mem := by + rw [extend_eq] + swap; · exact h_mem + rw [addContent_sUnion h_ss h_dis h_mem] + refine Finset.sum_congr rfl (fun s hs ↦ ?_) + rw [extend_eq] + exact h_ss hs + +protected theorem AddContent.extend_eq_extend (hC : IsSetSemiring C) (m : AddContent C) : + m.extend hC = extend (fun x (_ : x ∈ C) ↦ m x) := rfl + +protected theorem AddContent.extend_eq (hC : IsSetSemiring C) (m : AddContent C) (hs : s ∈ C) : + m.extend hC s = m s := by + rwa [m.extend_eq_extend, extend_eq] + +protected theorem AddContent.extend_eq_top (hC : IsSetSemiring C) (m : AddContent C) (hs : s ∉ C) : + m.extend hC s = ∞ := by + rwa [m.extend_eq_extend, extend_eq_top] + +end AddContentExtend + section IsSetRing lemma addContent_union (hC : IsSetRing C) (hs : s ∈ C) (ht : t ∈ C) diff --git a/Mathlib/MeasureTheory/SetSemiring.lean b/Mathlib/MeasureTheory/SetSemiring.lean index 976dcb2c87dc3..21a16de95ad05 100644 --- a/Mathlib/MeasureTheory/SetSemiring.lean +++ b/Mathlib/MeasureTheory/SetSemiring.lean @@ -431,8 +431,8 @@ lemma empty_nmem_disjointOfUnion (hC : IsSetSemiring C) (hJ : ↑J ⊆ C) (hj : (Exists.choose_spec (hC.disjointOfUnion_props hJ)).2.2.2.2.1 j hj lemma sUnion_disjointOfUnion (hC : IsSetSemiring C) (hJ : ↑J ⊆ C) : - ⋃₀ ⋃ x ∈ J, (hC.disjointOfUnion hJ x : Set (Set α)) = ⋃₀ J - := (Exists.choose_spec (hC.disjointOfUnion_props hJ)).2.2.2.2.2.symm + ⋃₀ ⋃ x ∈ J, (hC.disjointOfUnion hJ x : Set (Set α)) = ⋃₀ J := + (Exists.choose_spec (hC.disjointOfUnion_props hJ)).2.2.2.2.2.symm end disjointOfUnion From 65da8aa1409fa2239439c4a1a79df9e422974630 Mon Sep 17 00:00:00 2001 From: Riccardo Brasca Date: Mon, 3 Feb 2025 10:21:42 +0000 Subject: [PATCH 028/103] feat: generalize `Ideal.spanNorm` to allow non free extensions (#19244) We generalize [Ideal.spanNorm](https://leanprover-community.github.io/mathlib4_docs/Mathlib/RingTheory/Ideal/Norm/RelNorm.html#Ideal.spanNorm) to allow non-free extensions. Currently, `spanNorm`, is defined as ```lean def spanNorm (R : Type*) [CommRing R] {S : Type*} [CommRing S] [Algebra R S] (I : Ideal S) : Ideal R := Ideal.span (Algebra.norm R '' (I : Set S)) ``` but the definition is mathematically meaningless unless `[Module.Finite R S]` and `[Module.Free R S]`. We change this to ```lean def spanNorm (R : Type*) [CommRing R] [IsDomain R] {S : Type*} [CommRing S] [IsDomain S] [IsIntegrallyClosed R] [IsIntegrallyClosed S] [Algebra R S] [Module.Finite R S] [NoZeroSMulDivisors R S] [Algebra.IsSeparable (FractionRing R) (FractionRing S)] (I : Ideal S) : Ideal R := Ideal.span (Algebra.intNorm R S '' (I : Set S)) ``` that is the mathematically correct definition, notably in the case `R` and `S` are the rings of integers in an extension of number fields. From flt-regular Co-authored-by: Andrew Yang --- .../DedekindDomain/IntegralClosure.lean | 5 + Mathlib/RingTheory/DedekindDomain/PID.lean | 2 +- Mathlib/RingTheory/Ideal/Norm/RelNorm.lean | 200 +++++++++++------- Mathlib/RingTheory/Localization/Ideal.lean | 27 +++ 4 files changed, 161 insertions(+), 73 deletions(-) diff --git a/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean b/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean index 22c54ebc36736..3a11fa700b7ff 100644 --- a/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean +++ b/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean @@ -247,4 +247,9 @@ instance integralClosure.isDedekindDomain_fractionRing [IsDedekindDomain A] : IsDedekindDomain (integralClosure A L) := integralClosure.isDedekindDomain A (FractionRing A) L +attribute [local instance] FractionRing.liftAlgebra in +instance [NoZeroSMulDivisors A C] [Module.Finite A C] [IsIntegrallyClosed C] : + IsLocalization (Algebra.algebraMapSubmonoid C A⁰) (FractionRing C) := + IsIntegralClosure.isLocalization _ (FractionRing A) _ _ + end IsIntegralClosure diff --git a/Mathlib/RingTheory/DedekindDomain/PID.lean b/Mathlib/RingTheory/DedekindDomain/PID.lean index b9bad1bafa86b..960686d153fe9 100644 --- a/Mathlib/RingTheory/DedekindDomain/PID.lean +++ b/Mathlib/RingTheory/DedekindDomain/PID.lean @@ -183,7 +183,7 @@ theorem IsPrincipalIdealRing.of_finite_primes [IsDedekindDomain R] variable [IsDedekindDomain R] variable (S : Type*) [CommRing S] -variable [Algebra R S] [Module.Free R S] [Module.Finite R S] +variable [Algebra R S] [NoZeroSMulDivisors R S] [Module.Finite R S] variable (p : Ideal R) (hp0 : p ≠ ⊥) [IsPrime p] variable {Sₚ : Type*} [CommRing Sₚ] [Algebra S Sₚ] variable [IsLocalization (Algebra.algebraMapSubmonoid S p.primeCompl) Sₚ] diff --git a/Mathlib/RingTheory/Ideal/Norm/RelNorm.lean b/Mathlib/RingTheory/Ideal/Norm/RelNorm.lean index ccb7c0362da1e..2dcc0e755445c 100644 --- a/Mathlib/RingTheory/Ideal/Norm/RelNorm.lean +++ b/Mathlib/RingTheory/Ideal/Norm/RelNorm.lean @@ -6,6 +6,7 @@ Authors: Anne Baanen, Alex J. Best import Mathlib.LinearAlgebra.FreeModule.PID import Mathlib.RingTheory.DedekindDomain.PID import Mathlib.RingTheory.Localization.NormTrace +import Mathlib.RingTheory.IntegralClosure.IntegralRestrict /-! @@ -34,92 +35,132 @@ namespace Ideal open Submodule -variable (R : Type*) [CommRing R] {S : Type*} [CommRing S] [Algebra R S] +attribute [local instance] FractionRing.liftAlgebra -/-- `Ideal.spanNorm R (I : Ideal S)` is the ideal generated by mapping `Algebra.norm R` over `I`. +variable (R S : Type*) [CommRing R] [IsDomain R] {S : Type*} [CommRing S] [IsDomain S] +variable [IsIntegrallyClosed R] [IsIntegrallyClosed S] [Algebra R S] [Module.Finite R S] +variable [NoZeroSMulDivisors R S] [Algebra.IsSeparable (FractionRing R) (FractionRing S)] + +/-- `Ideal.spanNorm R (I : Ideal S)` is the ideal generated by mapping `Algebra.intNorm R S` +over `I`. See also `Ideal.relNorm`. -/ def spanNorm (I : Ideal S) : Ideal R := - Ideal.span (Algebra.norm R '' (I : Set S)) + Ideal.map (Algebra.intNorm R S) I @[simp] -theorem spanNorm_bot [Nontrivial S] [Module.Free R S] [Module.Finite R S] : +theorem spanNorm_bot : spanNorm R (⊥ : Ideal S) = ⊥ := span_eq_bot.mpr fun x hx => by simpa using hx variable {R} @[simp] -theorem spanNorm_eq_bot_iff [IsDomain R] [IsDomain S] [Module.Free R S] [Module.Finite R S] - {I : Ideal S} : spanNorm R I = ⊥ ↔ I = ⊥ := by - simp only [spanNorm, Ideal.span_eq_bot, Set.mem_image, SetLike.mem_coe, forall_exists_index, - and_imp, forall_apply_eq_imp_iff₂, - Algebra.norm_eq_zero_iff_of_basis (Module.Free.chooseBasis R S), @eq_bot_iff _ _ _ I, - SetLike.le_def] +theorem spanNorm_eq_bot_iff {I : Ideal S} : spanNorm R I = ⊥ ↔ I = ⊥ := by + simp only [spanNorm, span_eq_bot, Set.mem_image, SetLike.mem_coe, forall_exists_index, and_imp, + forall_apply_eq_imp_iff₂, Algebra.intNorm_eq_zero, @eq_bot_iff _ _ _ I, SetLike.le_def, map] rfl variable (R) -theorem norm_mem_spanNorm {I : Ideal S} (x : S) (hx : x ∈ I) : Algebra.norm R x ∈ I.spanNorm R := +theorem intNorm_mem_spanNorm {I : Ideal S} {x : S} (hx : x ∈ I) : + Algebra.intNorm R S x ∈ I.spanNorm R := subset_span (Set.mem_image_of_mem _ hx) +theorem norm_mem_spanNorm [Module.Free R S] {I : Ideal S} (x : S) (hx : x ∈ I) : + Algebra.norm R x ∈ I.spanNorm R := by + refine subset_span ⟨x, hx, ?_⟩ + rw [Algebra.intNorm_eq_norm] + @[simp] -theorem spanNorm_singleton {r : S} : spanNorm R (span ({r} : Set S)) = span {Algebra.norm R r} := +theorem spanNorm_singleton {r : S} : + spanNorm R (span ({r} : Set S)) = span {Algebra.intNorm R S r} := le_antisymm (span_le.mpr fun x hx => mem_span_singleton.mpr (by obtain ⟨x, hx', rfl⟩ := (Set.mem_image _ _ _).mp hx exact map_dvd _ (mem_span_singleton.mp hx'))) - ((span_singleton_le_iff_mem _).mpr (norm_mem_spanNorm _ _ (mem_span_singleton_self _))) + ((span_singleton_le_iff_mem _).mpr (intNorm_mem_spanNorm _ (mem_span_singleton_self _))) @[simp] theorem spanNorm_top : spanNorm R (⊤ : Ideal S) = ⊤ := by - -- Porting note: was - -- simp [← Ideal.span_singleton_one] - rw [← Ideal.span_singleton_one, spanNorm_singleton] - simp - -theorem map_spanNorm (I : Ideal S) {T : Type*} [CommRing T] (f : R →+* T) : - map f (spanNorm R I) = span (f ∘ Algebra.norm R '' (I : Set S)) := by - rw [spanNorm, map_span, Set.image_image] - -- Porting note: `Function.comp` reducibility - rfl + simp [← Ideal.span_singleton_one] + +theorem map_spanIntNorm (I : Ideal S) {T : Type*} [CommRing T] (f : R →+* T) : + map f (spanNorm R I) = span (f ∘ Algebra.intNorm R S '' (I : Set S)) := by + rw [spanNorm] + nth_rw 2 [map] + simp [map_span, Set.image_image] @[mono] theorem spanNorm_mono {I J : Ideal S} (h : I ≤ J) : spanNorm R I ≤ spanNorm R J := Ideal.span_mono (Set.monotone_image h) -theorem spanNorm_localization (I : Ideal S) [Module.Finite R S] [Module.Free R S] (M : Submonoid R) +theorem spanIntNorm_localization (I : Ideal S) (M : Submonoid R) (hM : M ≤ R⁰) {Rₘ : Type*} (Sₘ : Type*) [CommRing Rₘ] [Algebra R Rₘ] [CommRing Sₘ] [Algebra S Sₘ] [Algebra Rₘ Sₘ] [Algebra R Sₘ] [IsScalarTower R Rₘ Sₘ] [IsScalarTower R S Sₘ] - [IsLocalization M Rₘ] [IsLocalization (Algebra.algebraMapSubmonoid S M) Sₘ] : + [IsLocalization M Rₘ] [IsLocalization (Algebra.algebraMapSubmonoid S M) Sₘ] + [IsIntegrallyClosed Rₘ] [IsDomain Rₘ] [IsDomain Sₘ] [NoZeroSMulDivisors Rₘ Sₘ] + [Module.Finite Rₘ Sₘ] [IsIntegrallyClosed Sₘ] + [Algebra.IsSeparable (FractionRing Rₘ) (FractionRing Sₘ)] : spanNorm Rₘ (I.map (algebraMap S Sₘ)) = (spanNorm R I).map (algebraMap R Rₘ) := by - cases subsingleton_or_nontrivial R - · haveI := IsLocalization.unique R Rₘ M - simp [eq_iff_true_of_subsingleton] - let b := Module.Free.chooseBasis R S - rw [map_spanNorm] + let K := FractionRing R + let f : Rₘ →+* K := IsLocalization.map _ (T := R⁰) (RingHom.id R) hM + let L := FractionRing S + let g : Sₘ →+* L := IsLocalization.map _ (M := Algebra.algebraMapSubmonoid S M) (T := S⁰) + (RingHom.id S) (Submonoid.map_le_of_le_comap _ <| hM.trans + (nonZeroDivisors_le_comap_nonZeroDivisors_of_injective _ + (NoZeroSMulDivisors.algebraMap_injective _ _))) + algebraize [f, g, (algebraMap K L).comp f] + have : IsScalarTower R Rₘ K := IsScalarTower.of_algebraMap_eq' + (by rw [RingHom.algebraMap_toAlgebra, IsLocalization.map_comp, RingHomCompTriple.comp_eq]) + let _ := IsFractionRing.isFractionRing_of_isDomain_of_isLocalization M Rₘ K + have : IsScalarTower S Sₘ L := IsScalarTower.of_algebraMap_eq' + (by rw [RingHom.algebraMap_toAlgebra, IsLocalization.map_comp, RingHomCompTriple.comp_eq]) + have : IsScalarTower Rₘ Sₘ L := by + apply IsScalarTower.of_algebraMap_eq' + apply IsLocalization.ringHom_ext M + rw [RingHom.algebraMap_toAlgebra, RingHom.algebraMap_toAlgebra (R := Sₘ), RingHom.comp_assoc, + RingHom.comp_assoc, ← IsScalarTower.algebraMap_eq, IsScalarTower.algebraMap_eq R S Sₘ, + IsLocalization.map_comp, RingHom.comp_id, ← RingHom.comp_assoc, IsLocalization.map_comp, + RingHom.comp_id, ← IsScalarTower.algebraMap_eq, ← IsScalarTower.algebraMap_eq] + let _ := IsFractionRing.isFractionRing_of_isDomain_of_isLocalization + (Algebra.algebraMapSubmonoid S M) Sₘ L + have : IsIntegralClosure Sₘ Rₘ L := + IsIntegralClosure.of_isIntegrallyClosed _ _ _ + rw [map_spanIntNorm] refine span_eq_span (Set.image_subset_iff.mpr ?_) (Set.image_subset_iff.mpr ?_) - · rintro a' ha' - simp only [Set.mem_preimage, submodule_span_eq, ← map_spanNorm, SetLike.mem_coe, + · intro a' ha' + simp only [Set.mem_preimage, submodule_span_eq, ← map_spanIntNorm, SetLike.mem_coe, IsLocalization.mem_map_algebraMap_iff (Algebra.algebraMapSubmonoid S M) Sₘ, IsLocalization.mem_map_algebraMap_iff M Rₘ, Prod.exists] at ha' ⊢ obtain ⟨⟨a, ha⟩, ⟨_, ⟨s, hs, rfl⟩⟩, has⟩ := ha' - refine ⟨⟨Algebra.norm R a, norm_mem_spanNorm _ _ ha⟩, - ⟨s ^ Fintype.card (Module.Free.ChooseBasisIndex R S), pow_mem hs _⟩, ?_⟩ + refine ⟨⟨Algebra.intNorm R S a, intNorm_mem_spanNorm _ ha⟩, + ⟨s ^ Module.finrank K L, pow_mem hs _⟩, ?_⟩ simp only [Submodule.coe_mk, Subtype.coe_mk, map_pow] at has ⊢ - apply_fun Algebra.norm Rₘ at has - rwa [_root_.map_mul, ← IsScalarTower.algebraMap_apply, IsScalarTower.algebraMap_apply R Rₘ, - Algebra.norm_algebraMap_of_basis (b.localizationLocalization Rₘ M Sₘ), - Algebra.norm_localization R M a] at has + apply_fun algebraMap _ L at has + apply_fun Algebra.norm K at has + simp only [_root_.map_mul, IsScalarTower.algebraMap_apply R Rₘ Sₘ] at has + rw [← IsScalarTower.algebraMap_apply, ← IsScalarTower.algebraMap_apply, + ← IsScalarTower.algebraMap_apply, + IsScalarTower.algebraMap_apply R K L, + Algebra.norm_algebraMap] at has + apply IsFractionRing.injective Rₘ K + simp only [_root_.map_mul, map_pow] + have : FiniteDimensional K L := Module.Finite_of_isLocalization R S _ _ R⁰ + rwa [Algebra.algebraMap_intNorm (L := L), ← IsScalarTower.algebraMap_apply, + ← IsScalarTower.algebraMap_apply, Algebra.algebraMap_intNorm (L := L)] · intro a ha - rw [Set.mem_preimage, Function.comp_apply, ← Algebra.norm_localization (Sₘ := Sₘ) R M a] + rw [Set.mem_preimage, Function.comp_apply, Algebra.intNorm_eq_of_isLocalization + (A := R) (B := S) M (Aₘ := Rₘ) (Bₘ := Sₘ)] exact subset_span (Set.mem_image_of_mem _ (mem_map_of_mem _ ha)) theorem spanNorm_mul_spanNorm_le (I J : Ideal S) : spanNorm R I * spanNorm R J ≤ spanNorm R (I * J) := by - rw [spanNorm, spanNorm, spanNorm, Ideal.span_mul_span', ← Set.image_mul] + rw [spanNorm, spanNorm, spanNorm] + nth_rw 1 [map]; nth_rw 1 [map] + rw [Ideal.span_mul_span', ← Set.image_mul] refine Ideal.span_mono (Set.monotone_image ?_) rintro _ ⟨x, hxI, y, hyJ, rfl⟩ exact Ideal.mul_mem_mul hxI hyJ @@ -127,60 +168,73 @@ theorem spanNorm_mul_spanNorm_le (I J : Ideal S) : /-- This condition `eq_bot_or_top` is equivalent to being a field. However, `Ideal.spanNorm_mul_of_field` is harder to apply since we'd need to upgrade a `CommRing R` instance to a `Field R` instance. -/ -theorem spanNorm_mul_of_bot_or_top [IsDomain R] [IsDomain S] [Module.Free R S] [Module.Finite R S] - (eq_bot_or_top : ∀ I : Ideal R, I = ⊥ ∨ I = ⊤) (I J : Ideal S) : +theorem spanNorm_mul_of_bot_or_top (eq_bot_or_top : ∀ I : Ideal R, I = ⊥ ∨ I = ⊤) (I J : Ideal S) : spanNorm R (I * J) = spanNorm R I * spanNorm R J := by refine le_antisymm ?_ (spanNorm_mul_spanNorm_le R _ _) - cases' eq_bot_or_top (spanNorm R I) with hI hI + rcases eq_bot_or_top (spanNorm R I) with hI | hI · rw [hI, spanNorm_eq_bot_iff.mp hI, bot_mul, spanNorm_bot] exact bot_le rw [hI, Ideal.top_mul] - cases' eq_bot_or_top (spanNorm R J) with hJ hJ + rcases eq_bot_or_top (spanNorm R J) with hJ | hJ · rw [hJ, spanNorm_eq_bot_iff.mp hJ, mul_bot, spanNorm_bot] rw [hJ] exact le_top -@[simp] -theorem spanNorm_mul_of_field {K : Type*} [Field K] [Algebra K S] [IsDomain S] [Module.Finite K S] - (I J : Ideal S) : spanNorm K (I * J) = spanNorm K I * spanNorm K J := - spanNorm_mul_of_bot_or_top K eq_bot_or_top I J - -variable [IsDomain R] [IsDomain S] [IsDedekindDomain R] [IsDedekindDomain S] -variable [Module.Finite R S] [Module.Free R S] +variable [IsDedekindDomain R] [IsDedekindDomain S] /-- Multiplicativity of `Ideal.spanNorm`. simp-normal form is `map_mul (Ideal.relNorm R)`. -/ theorem spanNorm_mul (I J : Ideal S) : spanNorm R (I * J) = spanNorm R I * spanNorm R J := by nontriviality R cases subsingleton_or_nontrivial S - · have : ∀ I : Ideal S, I = ⊤ := fun I => Subsingleton.elim I ⊤ + · have : ∀ I : Ideal S, I = ⊤ := fun I ↦ Subsingleton.elim I ⊤ simp [this I, this J, this (I * J)] - refine eq_of_localization_maximal ?_ - intro P hP + refine eq_of_localization_maximal (fun P hP ↦ ?_) by_cases hP0 : P = ⊥ · subst hP0 rw [spanNorm_mul_of_bot_or_top] intro I - refine or_iff_not_imp_right.mpr fun hI => ?_ - exact (hP.eq_of_le hI bot_le).symm + exact or_iff_not_imp_right.mpr fun hI ↦ (hP.eq_of_le hI bot_le).symm let P' := Algebra.algebraMapSubmonoid S P.primeCompl - letI : Algebra (Localization.AtPrime P) (Localization P') := localizationAlgebra P.primeCompl S - haveI : IsScalarTower R (Localization.AtPrime P) (Localization P') := + let Rₚ := Localization.AtPrime P + let Sₚ := Localization P' + let _ : Algebra Rₚ Sₚ := localizationAlgebra P.primeCompl S + have : IsScalarTower R Rₚ Sₚ := IsScalarTower.of_algebraMap_eq (fun x => (IsLocalization.map_eq (T := P') (Q := Localization P') P.primeCompl.le_comap_map x).symm) have h : P' ≤ S⁰ := map_le_nonZeroDivisors_of_injective _ (NoZeroSMulDivisors.algebraMap_injective _ _) P.primeCompl_le_nonZeroDivisors - haveI : IsDomain (Localization P') := IsLocalization.isDomain_localization h - haveI : IsDedekindDomain (Localization P') := IsLocalization.isDedekindDomain S h _ - letI := Classical.decEq (Ideal (Localization P')) - haveI : IsPrincipalIdealRing (Localization P') := + have : IsDomain Sₚ := IsLocalization.isDomain_localization h + have : IsDedekindDomain Sₚ := IsLocalization.isDedekindDomain S h _ + have : IsPrincipalIdealRing Sₚ := IsDedekindDomain.isPrincipalIdealRing_localization_over_prime S P hP0 - rw [Ideal.map_mul, ← spanNorm_localization R I P.primeCompl (Localization P'), - ← spanNorm_localization R J P.primeCompl (Localization P'), - ← spanNorm_localization R (I * J) P.primeCompl (Localization P'), Ideal.map_mul, - ← (I.map _).span_singleton_generator, ← (J.map _).span_singleton_generator, + have := NoZeroSMulDivisors_of_isLocalization R S Rₚ Sₚ P.primeCompl_le_nonZeroDivisors + have := Module.Finite_of_isLocalization R S Rₚ Sₚ P.primeCompl + let L := FractionRing S + let g : Sₚ →+* L := IsLocalization.map _ (M := P') (T := S⁰) (RingHom.id S) h + algebraize [g] + have : IsScalarTower S Sₚ (FractionRing S) := IsScalarTower.of_algebraMap_eq' + (by rw [RingHom.algebraMap_toAlgebra, IsLocalization.map_comp, RingHom.comp_id]) + have := IsFractionRing.isFractionRing_of_isDomain_of_isLocalization P' Sₚ (FractionRing S) + have : Algebra.IsSeparable (FractionRing Rₚ) (FractionRing Sₚ) := by + apply Algebra.IsSeparable.of_equiv_equiv + (FractionRing.algEquiv Rₚ (FractionRing R)).symm.toRingEquiv + (FractionRing.algEquiv Sₚ (FractionRing S)).symm.toRingEquiv + apply IsLocalization.ringHom_ext R⁰ + ext + simp only [AlgEquiv.toRingEquiv_eq_coe, RingHom.coe_comp, + RingHom.coe_coe, Function.comp_apply, ← IsScalarTower.algebraMap_apply] + rw [IsScalarTower.algebraMap_apply R Rₚ (FractionRing R), AlgEquiv.coe_ringEquiv, + AlgEquiv.commutes, IsScalarTower.algebraMap_apply R S L, + IsScalarTower.algebraMap_apply S Sₚ L, AlgEquiv.coe_ringEquiv, AlgEquiv.commutes] + simp only [← IsScalarTower.algebraMap_apply] + rw [IsScalarTower.algebraMap_apply R Rₚ (FractionRing Rₚ), + ← IsScalarTower.algebraMap_apply Rₚ, ← IsScalarTower.algebraMap_apply] + simp only [Ideal.map_mul, ← spanIntNorm_localization (R := R) (S := S) + (Rₘ := Localization.AtPrime P) (Sₘ := Localization P') _ _ P.primeCompl_le_nonZeroDivisors] + rw [← (I.map _).span_singleton_generator, ← (J.map _).span_singleton_generator, span_singleton_mul_span_singleton, spanNorm_singleton, spanNorm_singleton, - spanNorm_singleton, span_singleton_mul_span_singleton, _root_.map_mul] + spanNorm_singleton, span_singleton_mul_span_singleton, _root_.map_mul] /-- The relative norm `Ideal.relNorm R (I : Ideal S)`, where `R` and `S` are Dedekind domains, and `S` is an extension of `R` that is finite and free as a module. -/ @@ -190,7 +244,8 @@ def relNorm : Ideal S →*₀ Ideal R where map_one' := by dsimp only; rw [one_eq_top, spanNorm_top R, one_eq_top] map_mul' := spanNorm_mul R -theorem relNorm_apply (I : Ideal S) : relNorm R I = span (Algebra.norm R '' (I : Set S) : Set R) := +theorem relNorm_apply (I : Ideal S) : + relNorm R I = span (Algebra.intNorm R S '' (I : Set S) : Set R) := rfl @[simp] @@ -212,16 +267,17 @@ theorem relNorm_eq_bot_iff {I : Ideal S} : relNorm R I = ⊥ ↔ I = ⊥ := variable (R) -theorem norm_mem_relNorm (I : Ideal S) {x : S} (hx : x ∈ I) : Algebra.norm R x ∈ relNorm R I := +theorem norm_mem_relNorm [Module.Free R S] (I : Ideal S) {x : S} (hx : x ∈ I) : + Algebra.norm R x ∈ relNorm R I := norm_mem_spanNorm R x hx @[simp] -theorem relNorm_singleton (r : S) : relNorm R (span ({r} : Set S)) = span {Algebra.norm R r} := +theorem relNorm_singleton (r : S) : relNorm R (span ({r} : Set S)) = span {Algebra.intNorm R S r} := spanNorm_singleton R theorem map_relNorm (I : Ideal S) {T : Type*} [CommRing T] (f : R →+* T) : - map f (relNorm R I) = span (f ∘ Algebra.norm R '' (I : Set S)) := - map_spanNorm R I f + map f (relNorm R I) = span (f ∘ Algebra.intNorm R S '' (I : Set S)) := + map_spanIntNorm R I f @[mono] theorem relNorm_mono {I J : Ideal S} (h : I ≤ J) : relNorm R I ≤ relNorm R J := diff --git a/Mathlib/RingTheory/Localization/Ideal.lean b/Mathlib/RingTheory/Localization/Ideal.lean index 5238e642ff74e..d96fa14d7d23e 100644 --- a/Mathlib/RingTheory/Localization/Ideal.lean +++ b/Mathlib/RingTheory/Localization/Ideal.lean @@ -6,6 +6,7 @@ Authors: Kenny Lau, Mario Carneiro, Johan Commelin, Amelia Livingston, Anne Baan import Mathlib.GroupTheory.MonoidLocalization.Away import Mathlib.RingTheory.Ideal.Quotient.Operations import Mathlib.RingTheory.Localization.Defs +import Mathlib.Algebra.Algebra.Tower /-! # Ideals in localizations of commutative rings @@ -253,6 +254,32 @@ theorem ideal_eq_iInf_comap_map_away {S : Finset R} (hS : Ideal.span (α := R) S rw [pow_add, mul_assoc, ← mul_comm x, e] exact I.mul_mem_left _ y.2 +variable (R) in +lemma _root_.NoZeroSMulDivisors_of_isLocalization (Rₚ Sₚ : Type*) [CommRing Rₚ] [CommRing Sₚ] + [Algebra R Rₚ] [Algebra R Sₚ] [Algebra S Sₚ] [Algebra Rₚ Sₚ] [IsScalarTower R S Sₚ] + [IsScalarTower R Rₚ Sₚ] {M : Submonoid R} (hM : M ≤ R⁰) [IsLocalization M Rₚ] + [IsLocalization (Algebra.algebraMapSubmonoid S M) Sₚ] [NoZeroSMulDivisors R S] [IsDomain S] : + NoZeroSMulDivisors Rₚ Sₚ := by + have e : Algebra.algebraMapSubmonoid S M ≤ S⁰ := + Submonoid.map_le_of_le_comap _ <| hM.trans + (nonZeroDivisors_le_comap_nonZeroDivisors_of_injective _ + (NoZeroSMulDivisors.algebraMap_injective _ _)) + have : IsDomain Sₚ := IsLocalization.isDomain_of_le_nonZeroDivisors S e + have : algebraMap Rₚ Sₚ = IsLocalization.map (T := Algebra.algebraMapSubmonoid S M) Sₚ + (algebraMap R S) (Submonoid.le_comap_map M) := by + apply IsLocalization.ringHom_ext M + simp only [IsLocalization.map_comp, ← IsScalarTower.algebraMap_eq] + rw [NoZeroSMulDivisors.iff_algebraMap_injective, RingHom.injective_iff_ker_eq_bot, + RingHom.ker_eq_bot_iff_eq_zero] + intro x hx + obtain ⟨x, s, rfl⟩ := IsLocalization.mk'_surjective M x + simp only [RingHom.algebraMap_toAlgebra, IsLocalization.map_mk', IsLocalization.mk'_eq_zero_iff, + Subtype.exists, exists_prop, this] at hx ⊢ + obtain ⟨_, ⟨a, ha, rfl⟩, H⟩ := hx + simp only [← _root_.map_mul, + (injective_iff_map_eq_zero' _).mp (NoZeroSMulDivisors.algebraMap_injective R S)] at H + exact ⟨a, ha, H⟩ + end CommRing end IsLocalization From 5fe5b35523252cb62f99b6eb5984a824074a9ef9 Mon Sep 17 00:00:00 2001 From: mathlib4-update-dependencies-bot <150093616+mathlib-bors@users.noreply.github.com> Date: Mon, 3 Feb 2025 10:21:43 +0000 Subject: [PATCH 029/103] chore: update Mathlib dependencies 2025-02-03 (#21363) This PR updates the Mathlib dependencies. --- lake-manifest.json | 2 +- lean-toolchain | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lake-manifest.json b/lake-manifest.json index bb97b3f6d209a..7e0d9576d369c 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -65,7 +65,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "43dc9fd41505ba34dd359550c94706b4f4abefec", + "rev": "01006c9e86bf9e397c026fef4190478dd1fd897e", "name": "batteries", "manifestFile": "lake-manifest.json", "inputRev": "main", diff --git a/lean-toolchain b/lean-toolchain index 2ffc30ceba59b..8b4f470c73e01 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.16.0-rc2 \ No newline at end of file +leanprover/lean4:v4.16.0 \ No newline at end of file From 35279e839577140a58a9c23f7c31379155f93f93 Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Mon, 3 Feb 2025 11:03:19 +0000 Subject: [PATCH 030/103] feature(Order/Monotone/Basic): Separately monotone iff jointly monotone (#20254) A function on a product space is separately monotone if and only if it is jointly monotone. Similarly for antitone functions. Inspired by #15412 Co-authored-by: Christopher Hoskin --- Mathlib/Order/Monotone/Basic.lean | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Mathlib/Order/Monotone/Basic.lean b/Mathlib/Order/Monotone/Basic.lean index 4210837c3e715..0adce71cb1c93 100644 --- a/Mathlib/Order/Monotone/Basic.lean +++ b/Mathlib/Order/Monotone/Basic.lean @@ -1068,6 +1068,18 @@ theorem Monotone.prod_map (hf : Monotone f) (hg : Monotone g) : Monotone (Prod.m theorem Antitone.prod_map (hf : Antitone f) (hg : Antitone g) : Antitone (Prod.map f g) := fun _ _ h ↦ ⟨hf h.1, hg h.2⟩ +lemma monotone_prod_iff {h : α × β → γ} : + Monotone h ↔ (∀ a, Monotone (fun b => h (a, b))) ∧ (∀ b, Monotone (fun a => h (a, b))) where + mp h := ⟨fun _ _ _ hab => h (Prod.mk_le_mk_iff_right.mpr hab), + fun _ _ _ hab => h (Prod.mk_le_mk_iff_left.mpr hab)⟩ + mpr h _ _ hab := le_trans (h.1 _ (Prod.mk_le_mk.mp hab).2) (h.2 _ (Prod.mk_le_mk.mp hab).1) + +lemma antitone_prod_iff {h : α × β → γ} : + Antitone h ↔ (∀ a, Antitone (fun b => h (a, b))) ∧ (∀ b, Antitone (fun a => h (a, b))) where + mp h := ⟨fun _ _ _ hab => h (Prod.mk_le_mk_iff_right.mpr hab), + fun _ _ _ hab => h (Prod.mk_le_mk_iff_left.mpr hab)⟩ + mpr h _ _ hab:= le_trans (h.1 _ (Prod.mk_le_mk.mp hab).2) (h.2 _ (Prod.mk_le_mk.mp hab).1) + end Preorder section PartialOrder From e8eea565037a545e6c29688539c2da6cd1ff6edf Mon Sep 17 00:00:00 2001 From: Nailin Guan <150537269+Thmoas-Guan@users.noreply.github.com> Date: Mon, 3 Feb 2025 11:50:39 +0000 Subject: [PATCH 031/103] feat(Topology/Group): Forgetful functor of ProfiniteGrp reflects isomorphism (#20764) Proved that the forgetful functor of profinite grp reflects isomorphism. Be able to fix `ContinuousMulEquiv` -> `Category.Iso` in `ProfiniteGrp` --- .../Algebra/Category/ProfiniteGrp/Basic.lean | 23 ++++++++++++++----- .../Algebra/Category/ProfiniteGrp/Limits.lean | 20 ++++++---------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Basic.lean b/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Basic.lean index d71d9584de471..3f060225021bb 100644 --- a/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Basic.lean +++ b/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Basic.lean @@ -25,12 +25,6 @@ disconnected. * `ofClosedSubgroup` : A closed subgroup of a profinite group is profinite. -# TODO - -As discussion in `https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/Refactor.20 -Category.20of.20ProfiniteGrp.20and.20ContinuousMulEquiv/near/493290115` - -* Prove `(forget ProfiniteGrp.{u}).ReflectsIsomorphisms` using `profiniteGrpToProfinite` -/ universe u v @@ -249,6 +243,12 @@ def ofContinuousMulEquiv {G : ProfiniteGrp.{u}} {H : Type v} [TopologicalSpace H let _ : TotallyDisconnectedSpace H := Homeomorph.totallyDisconnectedSpace e.toHomeomorph .of H +/-- Build an isomorphism in the category `ProfiniteGrp` from +a `ContinuousMulEquiv` between `ProfiniteGrp`s. -/ +def ContinuousMulEquiv.toProfiniteGrpIso {X Y : ProfiniteGrp} (e : X ≃ₜ* Y) : X ≅ Y where + hom := ⟨e⟩ + inv := ⟨e.symm⟩ + /-- The functor mapping a profinite group to its underlying profinite space. -/ @[to_additive] instance : HasForget₂ ProfiniteGrp Profinite where @@ -261,6 +261,17 @@ instance : (forget₂ ProfiniteGrp Profinite).Faithful := { map_injective := fun {_ _} _ _ h => ConcreteCategory.hom_ext_iff.mpr (congrFun (congrArg ContinuousMap.toFun h)) } +instance : (forget₂ ProfiniteGrp Profinite).ReflectsIsomorphisms where + reflects {X Y} f _ := by + let i := asIso ((forget₂ ProfiniteGrp Profinite).map f) + let e : X ≃ₜ* Y := + { CompHausLike.homeoOfIso i with + map_mul' := map_mul f.hom } + exact (ContinuousMulEquiv.toProfiniteGrpIso e).isIso_hom + +instance : (forget ProfiniteGrp.{u}).ReflectsIsomorphisms := + CategoryTheory.reflectsIsomorphisms_comp (forget₂ ProfiniteGrp Profinite) (forget Profinite) + end ProfiniteGrp /-! diff --git a/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Limits.lean b/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Limits.lean index d6277f4439ca6..795f0f357875d 100644 --- a/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Limits.lean +++ b/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Limits.lean @@ -3,6 +3,7 @@ Copyright (c) 2024 Nailin Guan. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Nailin Guan, Youle Fang, Jujian Zhang, Yuyang Zhao -/ +import Mathlib.CategoryTheory.ConcreteCategory.EpiMono import Mathlib.Topology.Algebra.Category.ProfiniteGrp.Basic import Mathlib.Topology.Algebra.ClopenNhdofOne @@ -129,21 +130,14 @@ noncomputable def continuousMulEquivLimittoFiniteQuotientFunctor (P : ProfiniteG with map_mul' := (toLimit P).hom.map_mul' } ---TODO : Refactor using `(forget ProfiniteGrp.{u}).ReflectsIsomorphisms` after it is proved. +instance isIso_toLimit (P : ProfiniteGrp.{u}) : IsIso (toLimit P) := by + rw [CategoryTheory.ConcreteCategory.isIso_iff_bijective] + exact ⟨toLimit_injective P, toLimit_surjective P⟩ + /-- The isomorphism in the category of profinite group between a profinite group and the projective limit of its quotients by open normal subgroups -/ noncomputable def isoLimittoFiniteQuotientFunctor (P : ProfiniteGrp.{u}) : - P ≅ (limit (toFiniteQuotientFunctor P ⋙ forget₂ FiniteGrp ProfiniteGrp)) where - hom := P.toLimit - inv := ofHom { (continuousMulEquivLimittoFiniteQuotientFunctor P).symm.toMonoidHom with - continuous_toFun := (continuousMulEquivLimittoFiniteQuotientFunctor P).continuous_invFun} - hom_inv_id := by - ext x - exact ContinuousMulEquiv.symm_apply_apply - (continuousMulEquivLimittoFiniteQuotientFunctor P) x - inv_hom_id := by - ext x - exact ContinuousMulEquiv.apply_symm_apply - (continuousMulEquivLimittoFiniteQuotientFunctor P) x + P ≅ (limit (toFiniteQuotientFunctor P ⋙ forget₂ FiniteGrp ProfiniteGrp)) := + ContinuousMulEquiv.toProfiniteGrpIso (continuousMulEquivLimittoFiniteQuotientFunctor P) end ProfiniteGrp From 2215329622f9980d7e0f148521b2db8a355acb7f Mon Sep 17 00:00:00 2001 From: Yakov Pechersky Date: Mon, 3 Feb 2025 11:50:40 +0000 Subject: [PATCH 032/103] feat(Algebra/Order): `{WithTop,ENat}.addLECancellable_coe` (#21358) --- Mathlib/Algebra/Order/Monoid/Unbundled/WithTop.lean | 3 +++ Mathlib/Data/ENat/Basic.lean | 1 + 2 files changed, 4 insertions(+) diff --git a/Mathlib/Algebra/Order/Monoid/Unbundled/WithTop.lean b/Mathlib/Algebra/Order/Monoid/Unbundled/WithTop.lean index 6d9fc46645bc1..6b90d6bb4808f 100644 --- a/Mathlib/Algebra/Order/Monoid/Unbundled/WithTop.lean +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/WithTop.lean @@ -241,6 +241,9 @@ lemma addLECancellable_of_ne_top [Preorder α] [ContravariantClass α α (· + lemma addLECancellable_of_lt_top [Preorder α] [ContravariantClass α α (· + ·) (· ≤ ·)] (ha : a < ⊤) : AddLECancellable a := addLECancellable_of_ne_top ha.ne +lemma addLECancellable_coe [Preorder α] [ContravariantClass α α (· + ·) (· ≤ ·)] (a : α) : + AddLECancellable (a : WithTop α) := addLECancellable_of_ne_top coe_ne_top + lemma addLECancellable_iff_ne_top [Nonempty α] [Preorder α] [ContravariantClass α α (· + ·) (· ≤ ·)] : AddLECancellable a ↔ a ≠ ⊤ where mp := by rintro h rfl; exact (coe_lt_top <| Classical.arbitrary _).not_le <| h <| by simp diff --git a/Mathlib/Data/ENat/Basic.lean b/Mathlib/Data/ENat/Basic.lean index 24f664b0250d9..6de87c5125c52 100644 --- a/Mathlib/Data/ENat/Basic.lean +++ b/Mathlib/Data/ENat/Basic.lean @@ -311,6 +311,7 @@ lemma sub_ne_top_iff : a - b ≠ ⊤ ↔ a ≠ ⊤ ∨ b = ⊤ := WithTop.sub_ne lemma addLECancellable_of_ne_top : a ≠ ⊤ → AddLECancellable a := WithTop.addLECancellable_of_ne_top lemma addLECancellable_of_lt_top : a < ⊤ → AddLECancellable a := WithTop.addLECancellable_of_lt_top +lemma addLECancellable_coe (a : ℕ) : AddLECancellable (a : ℕ∞) := WithTop.addLECancellable_coe _ protected lemma le_sub_of_add_le_left (ha : a ≠ ⊤) : a + b ≤ c → b ≤ c - a := (addLECancellable_of_ne_top ha).le_tsub_of_add_le_left From e1f1958ca9c54776f683266b3f80bde0ca03b6e5 Mon Sep 17 00:00:00 2001 From: mathlib4-update-dependencies-bot <150093616+mathlib-bors@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:26:47 +0000 Subject: [PATCH 033/103] chore: update Mathlib dependencies 2025-02-03 (#21369) This PR updates the Mathlib dependencies. --- lake-manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lake-manifest.json b/lake-manifest.json index 7e0d9576d369c..66930a3e30c7a 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -25,7 +25,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "f72319c9686788305a8ab059f3c4d8c724785c83", + "rev": "1a6613663c3eb08c401ce0fd1a408412f2c2321e", "name": "importGraph", "manifestFile": "lake-manifest.json", "inputRev": "main", From 0770956a5269358923b1b0098d3827da9f19ad3b Mon Sep 17 00:00:00 2001 From: Bergschaf Date: Mon, 3 Feb 2025 13:31:43 +0000 Subject: [PATCH 034/103] feat(Order/Nucleus): coe_mk simp lemma (#21346) Add `Nucleus.coe_mk`. Co-authored-by: Bergschaf <86738237+Bergschaf@users.noreply.github.com> --- Mathlib/Order/Nucleus.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/Mathlib/Order/Nucleus.lean b/Mathlib/Order/Nucleus.lean index e867d9f21930b..8f3b54ef36a4e 100644 --- a/Mathlib/Order/Nucleus.lean +++ b/Mathlib/Order/Nucleus.lean @@ -55,6 +55,7 @@ instance : FunLike (Nucleus X) X X where lemma toFun_eq_coe (n : Nucleus X) : n.toFun = n := rfl @[simp] lemma coe_toInfHom (n : Nucleus X) : ⇑n.toInfHom = n := rfl +@[simp] lemma coe_mk (f : InfHom X X) (h1 h2) : ⇑(mk f h1 h2) = f := rfl instance : NucleusClass (Nucleus X) X where idempotent _ _ := idempotent' .. From a6276f4c6097675b1cf5ebd49b1146b735f38c02 Mon Sep 17 00:00:00 2001 From: Andrew Yang Date: Mon, 3 Feb 2025 13:40:49 +0000 Subject: [PATCH 035/103] feat(RingTheory): index of power of ideal (#20290) Co-authored-by: Andrew Yang <36414270+erdOne@users.noreply.github.com> --- Mathlib.lean | 1 + Mathlib/RingTheory/Ideal/Quotient/Index.lean | 104 +++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 Mathlib/RingTheory/Ideal/Quotient/Index.lean diff --git a/Mathlib.lean b/Mathlib.lean index d8898f42b7fd9..60a6904ec63fe 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -4598,6 +4598,7 @@ import Mathlib.RingTheory.Ideal.Prime import Mathlib.RingTheory.Ideal.Prod import Mathlib.RingTheory.Ideal.Quotient.Basic import Mathlib.RingTheory.Ideal.Quotient.Defs +import Mathlib.RingTheory.Ideal.Quotient.Index import Mathlib.RingTheory.Ideal.Quotient.Nilpotent import Mathlib.RingTheory.Ideal.Quotient.Noetherian import Mathlib.RingTheory.Ideal.Quotient.Operations diff --git a/Mathlib/RingTheory/Ideal/Quotient/Index.lean b/Mathlib/RingTheory/Ideal/Quotient/Index.lean new file mode 100644 index 0000000000000..d4f8ace34aac5 --- /dev/null +++ b/Mathlib/RingTheory/Ideal/Quotient/Index.lean @@ -0,0 +1,104 @@ +/- +Copyright (c) 2024 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.Algebra.GeomSum +import Mathlib.Data.Finsupp.Fintype +import Mathlib.GroupTheory.Index +import Mathlib.LinearAlgebra.DirectSum.Finsupp +import Mathlib.LinearAlgebra.TensorProduct.Quotient +import Mathlib.LinearAlgebra.TensorProduct.RightExactness +import Mathlib.RingTheory.Finiteness.Cardinality +import Mathlib.RingTheory.Finiteness.TensorProduct +import Mathlib.RingTheory.Ideal.Quotient.Operations + +/-! +# Indices of ideals + +## Main result +- `Submodule.finite_quotient_smul`: + Let `N` be a finite index f.g. `R`-submodule, and `I` be a finite index ideal. + Then `I • N` also has finite index. +- `Ideal.index_quotient_pow_le`: + If `I` is generated by `k` elements, + the index of `I ^ n` is bounded by `#(R ⧸ I) ^ (k⁰ + k¹ + ⋯ + kⁿ⁻¹)`. + +-/ + +variable {R M : Type*} [CommRing R] [AddCommGroup M] [Module R M] +variable (I : Ideal R) {N : Submodule R M} + +open TensorProduct in +/-- Let `N` be a finite index f.g. `R`-submodule, and `I` be a finite index ideal. +Then `I • N` also has finite index. -/ +lemma Submodule.finite_quotient_smul [Finite (R ⧸ I)] [Finite (M ⧸ N)] (hN : N.FG) : + Finite (M ⧸ I • N) := by + suffices (I • N).toAddSubgroup.FiniteIndex by + exact (I • N).toAddSubgroup.finite_quotient_of_finiteIndex + suffices Nat.card (N ⧸ (I • N).comap N.subtype) ≠ 0 by + constructor + rw [← AddSubgroup.relindex_mul_index + (H := (I • N).toAddSubgroup) (K := N.toAddSubgroup) Submodule.smul_le_right] + have inst : Finite (M ⧸ N.toAddSubgroup) := ‹_› + exact mul_ne_zero this AddSubgroup.index_ne_zero_of_finite + let e : (N ⧸ (I • N).comap N.subtype) ≃ₗ[R] (R ⧸ I) ⊗[R] N := + Submodule.quotEquivOfEq _ (I • (⊤ : Submodule R N)) (Submodule.map_injective_of_injective + N.injective_subtype (by simp [Submodule.smul_le_right])) ≪≫ₗ + (quotTensorEquivQuotSMul N I).symm + rw [Nat.card_congr e.toEquiv] + have : Module.Finite R N := Module.Finite.iff_fg.mpr hN + have : Finite ((R ⧸ I) ⊗[R] N) := Module.finite_of_finite (R ⧸ I) + exact Nat.card_pos.ne' + +-- We have `hs` and `N` instead of using `span R s` in the goal to make it easier to use. +-- Usually we would like to bound the index of some abstract `I • N`, and we may construct `s` while +-- applying this lemma instead of having to provide it beforehand. +open TensorProduct in +lemma Submodule.index_smul_le [Finite (R ⧸ I)] + (s : Finset M) (hs : Submodule.span R s = N) : + (I • N).toAddSubgroup.index ≤ I.toAddSubgroup.index ^ s.card * N.toAddSubgroup.index := by + classical + cases nonempty_fintype (R ⧸ I) + rw [← AddSubgroup.relindex_mul_index + (H := (I • N).toAddSubgroup) (K := N.toAddSubgroup) Submodule.smul_le_right] + gcongr + show (Nat.card (N ⧸ (I • N).comap N.subtype)) ≤ Nat.card (R ⧸ I) ^ s.card + let e : (N ⧸ (I • N).comap N.subtype) ≃ₗ[R] (R ⧸ I) ⊗[R] N := + Submodule.quotEquivOfEq _ (I • (⊤ : Submodule R N)) (Submodule.map_injective_of_injective + N.injective_subtype (by simp [Submodule.smul_le_right])) ≪≫ₗ + (quotTensorEquivQuotSMul N I).symm + rw [Nat.card_congr e.toEquiv] + have H : LinearMap.range (Finsupp.linearCombination R (α := s) (↑)) = N := by + rw [Finsupp.range_linearCombination, ← hs, Subtype.range_val]; rfl + let f : (s →₀ R) →ₗ[R] N := (Finsupp.linearCombination R (↑)).codRestrict _ + (Set.range_subset_iff (s := N.carrier).mp <| by exact H.le) + have hf : Function.Surjective f := fun x ↦ by + obtain ⟨y, hy⟩ := H.ge x.2; exact ⟨y, Subtype.ext hy⟩ + have : Function.Surjective + (f.lTensor (R ⧸ I) ∘ₗ (finsuppScalarRight R (R ⧸ I) s).symm.toLinearMap) := + (LinearMap.lTensor_surjective (R ⧸ I) hf).comp (LinearEquiv.surjective _) + refine (Nat.card_le_card_of_surjective _ this).trans ?_ + simp only [Nat.card_eq_fintype_card, Fintype.card_finsupp, Fintype.card_coe, le_rfl] + +variable {I} + +lemma Ideal.finite_quotient_pow (hI : I.FG) [Finite (R ⧸ I)] (n) : Finite (R ⧸ I ^ n) := by + induction n with + | zero => + simp only [pow_zero, Ideal.one_eq_top] + infer_instance + | succ n _ => + exact Submodule.finite_quotient_smul (I ^ n) hI + +lemma Ideal.index_pow_le + (s : Finset R) (hs : Ideal.span s = I) [Finite (R ⧸ I)] (n) : + (I ^ n).toAddSubgroup.index ≤ I.toAddSubgroup.index ^ ∑ i ∈ Finset.range n, s.card ^ i := by + have := Ideal.finite_quotient_pow ⟨s, hs⟩ + induction n with + | zero => + simp + | succ n IH => + refine (Submodule.index_smul_le (I ^ n) s hs).trans ?_ + refine (Nat.mul_le_mul (Nat.pow_le_pow_left IH _) le_rfl).trans ?_ + rw [← pow_mul, ← pow_succ, geom_sum_succ, mul_comm] From 3e6a2f1569c2d35d053154cc30342cee5e66eecc Mon Sep 17 00:00:00 2001 From: Oliver Nash Date: Mon, 3 Feb 2025 14:49:26 +0000 Subject: [PATCH 036/103] feat: generalise `algebraMap_injective` by weakening its typeclass assumptions (#21287) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As shown in the new lemma `faithfulSMul_iff_algebraMap_injective`, injectivity of `algebraMap R A` is equivalent to the typeclass hypothesis `[FaithfulSMul R A]`. We thus generalise (and rename) the existing lemma `NoZeroSMulDivisors.algebraMap_injective` to `FaithfulSMul.algebraMap_injective`. The rename is responsible for much of the diff. By weakening the assumptions `[Nontrivial A] [NoZeroSMulDivisors R A]` to just `[FaithfulSMul R A]`, results which need to use `algebraMap_injective` can be applied in the case that we have `[Ring A] [CharZero A]` but fail to have `[NoZeroSMulDivisors ℤ A]`. This is the motivation for these changes. There are quite a few places in the library where a lemma consumes an explicit argument of the form `Injective (algebraMap R A)`. Most / all of these should probably be restated to accept the typeclass argument `[FaithfulSMul R A]` but we do not attempt such a refactor here. Co-authored-by: Oliver Nash <7734364+ocfnash@users.noreply.github.com> --- Mathlib/Algebra/Algebra/Basic.lean | 159 ++++++++++++------ Mathlib/Algebra/AlgebraicCard.lean | 2 +- Mathlib/Algebra/Central/Basic.lean | 2 +- Mathlib/Algebra/Central/TensorProduct.lean | 4 +- Mathlib/Algebra/Lie/TraceForm.lean | 4 +- Mathlib/Algebra/Module/Lattice.lean | 4 +- Mathlib/Algebra/Polynomial/Roots.lean | 12 +- .../AlgebraicGeometry/ValuativeCriterion.lean | 2 +- .../FieldTheory/Differential/Liouville.lean | 6 +- Mathlib/FieldTheory/IsAlgClosed/Basic.lean | 19 +-- Mathlib/FieldTheory/KummerExtension.lean | 2 +- Mathlib/FieldTheory/Normal/Defs.lean | 2 +- .../FieldTheory/PurelyInseparable/Basic.lean | 2 +- Mathlib/FieldTheory/RatFunc/Basic.lean | 2 +- .../BilinearForm/DualLattice.lean | 8 +- Mathlib/LinearAlgebra/Dual.lean | 3 +- Mathlib/LinearAlgebra/Eigenspace/Basic.lean | 2 +- Mathlib/LinearAlgebra/LinearIndependent.lean | 2 +- .../Matrix/HermitianFunctionalCalculus.lean | 2 +- .../PerfectPairing/Restrict.lean | 10 +- .../LinearAlgebra/RootSystem/BaseChange.lean | 2 +- .../RootSystem/CartanMatrix.lean | 2 +- Mathlib/NumberTheory/Cyclotomic/Basic.lean | 17 +- .../NumberTheory/Cyclotomic/Discriminant.lean | 2 +- .../Cyclotomic/PrimitiveRoots.lean | 6 +- Mathlib/NumberTheory/FunctionField.lean | 6 +- Mathlib/NumberTheory/KummerDedekind.lean | 12 +- Mathlib/NumberTheory/NumberField/Basic.lean | 12 +- .../NumberField/FinitePlaces.lean | 5 +- .../RamificationInertia/Basic.lean | 2 +- Mathlib/RingTheory/AlgebraTower.lean | 2 +- Mathlib/RingTheory/Algebraic/Cardinality.lean | 2 +- Mathlib/RingTheory/Algebraic/Integral.lean | 2 +- .../RingTheory/DedekindDomain/Different.lean | 4 +- Mathlib/RingTheory/DedekindDomain/Ideal.lean | 6 +- .../DedekindDomain/IntegralClosure.lean | 4 +- Mathlib/RingTheory/DedekindDomain/PID.lean | 4 +- .../DedekindDomain/SelmerGroup.lean | 6 +- Mathlib/RingTheory/FractionalIdeal/Basic.lean | 2 +- Mathlib/RingTheory/Ideal/Maps.lean | 24 ++- Mathlib/RingTheory/Ideal/Norm/RelNorm.lean | 4 +- Mathlib/RingTheory/Ideal/Over.lean | 12 +- .../IntegralClosure/IntegralRestrict.lean | 4 +- .../IntegralClosure/IntegrallyClosed.lean | 2 +- .../IsIntegralClosure/Basic.lean | 2 +- Mathlib/RingTheory/Invariant.lean | 8 +- .../LocalProperties/IntegrallyClosed.lean | 2 +- .../RingTheory/Localization/FractionRing.lean | 35 ++-- Mathlib/RingTheory/Localization/Ideal.lean | 4 +- Mathlib/RingTheory/Localization/Integral.lean | 8 +- Mathlib/RingTheory/Localization/NumDen.lean | 12 +- Mathlib/RingTheory/Norm/Basic.lean | 2 +- Mathlib/RingTheory/Polynomial/Content.lean | 2 +- .../Polynomial/Cyclotomic/Basic.lean | 8 +- .../Polynomial/Cyclotomic/Roots.lean | 2 +- .../Polynomial/Eisenstein/Basic.lean | 2 +- .../Polynomial/Eisenstein/IsIntegral.lean | 2 +- Mathlib/RingTheory/Trace/Basic.lean | 2 +- Mathlib/RingTheory/Trace/Quotient.lean | 4 +- .../Valuation/AlgebraInstances.lean | 2 +- .../RingTheory/Valuation/LocalSubring.lean | 3 +- .../Algebra/Module/FiniteDimension.lean | 1 - 62 files changed, 269 insertions(+), 225 deletions(-) diff --git a/Mathlib/Algebra/Algebra/Basic.lean b/Mathlib/Algebra/Algebra/Basic.lean index 303fe02c038bc..12e4743eb11b9 100644 --- a/Mathlib/Algebra/Algebra/Basic.lean +++ b/Mathlib/Algebra/Algebra/Basic.lean @@ -9,7 +9,6 @@ import Mathlib.Algebra.Module.Equiv.Basic import Mathlib.Algebra.Module.Submodule.Ker import Mathlib.Algebra.Module.Submodule.RestrictScalars import Mathlib.Algebra.Module.ULift -import Mathlib.Algebra.NoZeroSMulDivisors.Basic import Mathlib.Algebra.Ring.Subring.Basic import Mathlib.Data.Nat.Cast.Order.Basic import Mathlib.Data.Int.CharZero @@ -22,6 +21,8 @@ This file could usefully be split further. universe u v w u₁ v₁ +open Function + namespace Algebra variable {R : Type u} {A : Type w} @@ -243,6 +244,11 @@ instance (priority := 99) Semiring.toNatAlgebra : Algebra ℕ R where instance nat_algebra_subsingleton : Subsingleton (Algebra ℕ R) := ⟨fun P Q => by ext; simp⟩ +@[simp] +lemma algebraMap_comp_natCast (R A : Type*) [CommSemiring R] [Semiring A] [Algebra R A] : + algebraMap R A ∘ Nat.cast = Nat.cast := by + ext; simp + end Nat section Int @@ -268,59 +274,105 @@ variable {R} instance int_algebra_subsingleton : Subsingleton (Algebra ℤ R) := ⟨fun P Q => Algebra.algebra_ext P Q <| RingHom.congr_fun <| Subsingleton.elim _ _⟩ +@[simp] +lemma algebraMap_comp_intCast (R A : Type*) [CommRing R] [Ring A] [Algebra R A] : + algebraMap R A ∘ Int.cast = Int.cast := by + ext; simp + end Int -namespace NoZeroSMulDivisors +section FaithfulSMul -variable {R A : Type*} +instance (R : Type*) [NonAssocSemiring R] : FaithfulSMul R R := ⟨fun {r₁ r₂} h ↦ by simpa using h 1⟩ -open Algebra +variable (R A : Type*) [CommSemiring R] [Semiring A] -/-- If `algebraMap R A` is injective and `A` has no zero divisors, -`R`-multiples in `A` are zero only if one of the factors is zero. +lemma faithfulSMul_iff_injective_smul_one [Module R A] [IsScalarTower R A A] : + FaithfulSMul R A ↔ Injective (fun r : R ↦ r • (1 : A)) := by + refine ⟨fun ⟨h⟩ {r₁ r₂} hr ↦ h fun a ↦ ?_, fun h ↦ ⟨fun {r₁ r₂} hr ↦ h ?_⟩⟩ + · simp only at hr + rw [← one_mul a, ← smul_mul_assoc, ← smul_mul_assoc, hr] + · simpa using hr 1 -Cannot be an instance because there is no `Injective (algebraMap R A)` typeclass. --/ -theorem of_algebraMap_injective [CommSemiring R] [Semiring A] [Algebra R A] [NoZeroDivisors A] - (h : Function.Injective (algebraMap R A)) : NoZeroSMulDivisors R A := - ⟨fun hcx => (mul_eq_zero.mp ((smul_def _ _).symm.trans hcx)).imp_left - (map_eq_zero_iff (algebraMap R A) h).mp⟩ +variable [Algebra R A] + +lemma faithfulSMul_iff_algebraMap_injective : FaithfulSMul R A ↔ Injective (algebraMap R A) := by + rw [faithfulSMul_iff_injective_smul_one, Algebra.algebraMap_eq_smul_one'] + +variable [FaithfulSMul R A] -variable (R A) +namespace FaithfulSMul -theorem algebraMap_injective [CommRing R] [Ring A] [Nontrivial A] [Algebra R A] - [NoZeroSMulDivisors R A] : Function.Injective (algebraMap R A) := by - simpa only [algebraMap_eq_smul_one'] using smul_left_injective R one_ne_zero +lemma algebraMap_injective : Injective (algebraMap R A) := + (faithfulSMul_iff_algebraMap_injective R A).mp inferInstance + +@[deprecated (since := "2025-01-31")] +alias _root_.NoZeroSMulDivisors.algebraMap_injective := algebraMap_injective @[simp] -lemma algebraMap_eq_zero_iff [CommRing R] [Ring A] [Nontrivial A] [Algebra R A] - [NoZeroSMulDivisors R A] {r : R} : algebraMap R A r = 0 ↔ r = 0 := - map_eq_zero_iff _ <| algebraMap_injective R A +lemma algebraMap_eq_zero_iff {r : R} : algebraMap R A r = 0 ↔ r = 0 := + map_eq_zero_iff (algebraMap R A) <| algebraMap_injective R A + +@[deprecated (since := "2025-01-31")] +alias _root_.NoZeroSMulDivisors.algebraMap_eq_zero_iff := algebraMap_eq_zero_iff @[simp] -lemma algebraMap_eq_one_iff [CommRing R] [Ring A] [Nontrivial A] [Algebra R A] - [NoZeroSMulDivisors R A] {r : R} : algebraMap R A r = 1 ↔ r = 1 := - map_eq_one_iff _ <| algebraMap_injective R A +lemma algebraMap_eq_one_iff {r : R} : algebraMap R A r = 1 ↔ r = 1 := + map_eq_one_iff _ <| FaithfulSMul.algebraMap_injective R A + +@[deprecated (since := "2025-01-31")] +alias _root_.NoZeroSMulDivisors.algebraMap_eq_one_iff := algebraMap_eq_one_iff -theorem _root_.NeZero.of_noZeroSMulDivisors (n : ℕ) [CommRing R] [NeZero (n : R)] [Ring A] - [Nontrivial A] [Algebra R A] [NoZeroSMulDivisors R A] : NeZero (n : A) := - NeZero.nat_of_injective <| NoZeroSMulDivisors.algebraMap_injective R A +theorem _root_.NeZero.of_faithfulSMul (n : ℕ) [NeZero (n : R)] : + NeZero (n : A) := + NeZero.nat_of_injective <| FaithfulSMul.algebraMap_injective R A -variable {R A} +@[deprecated (since := "2025-01-31")] +alias _root_.NeZero.of_noZeroSMulDivisors := NeZero.of_faithfulSMul -theorem iff_algebraMap_injective [CommRing R] [Ring A] [IsDomain A] [Algebra R A] : - NoZeroSMulDivisors R A ↔ Function.Injective (algebraMap R A) := - ⟨@NoZeroSMulDivisors.algebraMap_injective R A _ _ _ _, NoZeroSMulDivisors.of_algebraMap_injective⟩ +end FaithfulSMul + +lemma Algebra.charZero_of_charZero [CharZero R] : CharZero A := + have := algebraMap_comp_natCast R A + ⟨this ▸ (FaithfulSMul.algebraMap_injective R A).comp CharZero.cast_injective⟩ -- see note [lower instance priority] -instance (priority := 100) CharZero.noZeroSMulDivisors_nat [Semiring R] [NoZeroDivisors R] - [CharZero R] : NoZeroSMulDivisors ℕ R := - NoZeroSMulDivisors.of_algebraMap_injective <| (algebraMap ℕ R).injective_nat +instance (priority := 100) [CharZero R] : FaithfulSMul ℕ R := by + simpa only [faithfulSMul_iff_algebraMap_injective] using (algebraMap ℕ R).injective_nat -- see note [lower instance priority] -instance (priority := 100) CharZero.noZeroSMulDivisors_int [Ring R] [NoZeroDivisors R] - [CharZero R] : NoZeroSMulDivisors ℤ R := - NoZeroSMulDivisors.of_algebraMap_injective <| (algebraMap ℤ R).injective_int +instance (priority := 100) (R : Type*) [Ring R] [CharZero R] : FaithfulSMul ℤ R := by + simpa only [faithfulSMul_iff_algebraMap_injective] using (algebraMap ℤ R).injective_int + +end FaithfulSMul + +namespace NoZeroSMulDivisors + +-- see Note [lower instance priority] +instance (priority := 100) instOfFaithfulSMul {R A : Type*} + [CommSemiring R] [Semiring A] [Algebra R A] [NoZeroDivisors A] [FaithfulSMul R A] : + NoZeroSMulDivisors R A := + ⟨fun hcx => (mul_eq_zero.mp ((Algebra.smul_def _ _).symm.trans hcx)).imp_left + (map_eq_zero_iff (algebraMap R A) <| FaithfulSMul.algebraMap_injective R A).mp⟩ + +@[deprecated (since := "2025-01-31")] +alias of_algebraMap_injective := instOfFaithfulSMul + +variable {R A : Type*} [CommRing R] [Ring A] [Algebra R A] + +instance [Nontrivial A] [NoZeroSMulDivisors R A] : FaithfulSMul R A where + eq_of_smul_eq_smul {r₁ r₂} h := by + specialize h 1 + rw [← sub_eq_zero, ← sub_smul, smul_eq_zero, sub_eq_zero] at h + exact h.resolve_right one_ne_zero + +theorem iff_faithfulSMul [IsDomain A] : NoZeroSMulDivisors R A ↔ FaithfulSMul R A := + ⟨fun _ ↦ inferInstance, fun _ ↦ inferInstance⟩ + +theorem iff_algebraMap_injective [IsDomain A] : + NoZeroSMulDivisors R A ↔ Injective (algebraMap R A) := by + rw [iff_faithfulSMul] + exact faithfulSMul_iff_algebraMap_injective R A end NoZeroSMulDivisors @@ -338,20 +390,17 @@ theorem algebraMap_smul (r : R) (m : M) : (algebraMap R A) r • m = r • m := (algebra_compatible_smul A r m).symm /-- If `M` is `A`-torsion free and `algebraMap R A` is injective, `M` is also `R`-torsion free. -/ -lemma NoZeroSMulDivisors.of_algebraMap_injective' {R A M : Type*} [CommSemiring R] [Semiring A] - [Algebra R A] [AddCommMonoid M] [Module R M] [Module A M] [IsScalarTower R A M] - [NoZeroSMulDivisors A M] (h : Function.Injective (algebraMap R A)) : - NoZeroSMulDivisors R M where +theorem NoZeroSMulDivisors.trans_faithfulSMul (R A M : Type*) [CommRing R] [Ring A] [Algebra R A] + [FaithfulSMul R A] [AddCommGroup M] [Module R M] [Module A M] [IsScalarTower R A M] + [NoZeroSMulDivisors A M] : NoZeroSMulDivisors R M where eq_zero_or_eq_zero_of_smul_eq_zero hx := by rw [← algebraMap_smul (A := A)] at hx obtain (hc|hx) := eq_zero_or_eq_zero_of_smul_eq_zero hx - · exact Or.inl <| (map_eq_zero_iff _ h).mp hc + · exact Or.inl <| (map_eq_zero_iff _ <| FaithfulSMul.algebraMap_injective R A).mp hc · exact Or.inr hx -theorem NoZeroSMulDivisors.trans (R A M : Type*) [CommRing R] [Ring A] [IsDomain A] [Algebra R A] - [AddCommGroup M] [Module R M] [Module A M] [IsScalarTower R A M] [NoZeroSMulDivisors R A] - [NoZeroSMulDivisors A M] : NoZeroSMulDivisors R M := - of_algebraMap_injective' (A := A) (NoZeroSMulDivisors.iff_algebraMap_injective.1 inferInstance) +@[deprecated (since := "2025-01-31")] +alias NoZeroSMulDivisors.of_algebraMap_injective' := NoZeroSMulDivisors.trans_faithfulSMul variable {A} @@ -443,15 +492,15 @@ variable {F E : Type*} [CommSemiring F] [Semiring E] [Algebra F E] (b : F →ₗ /-- If `E` is an `F`-algebra, and there exists an injective `F`-linear map from `F` to `E`, then the algebra map from `F` to `E` is also injective. -/ -theorem injective_algebraMap_of_linearMap (hb : Function.Injective b) : - Function.Injective (algebraMap F E) := fun x y e ↦ hb <| by +theorem injective_algebraMap_of_linearMap (hb : Injective b) : + Injective (algebraMap F E) := fun x y e ↦ hb <| by rw [← mul_one x, ← mul_one y, ← smul_eq_mul, ← smul_eq_mul, map_smul, map_smul, Algebra.smul_def, Algebra.smul_def, e] /-- If `E` is an `F`-algebra, and there exists a surjective `F`-linear map from `F` to `E`, then the algebra map from `F` to `E` is also surjective. -/ -theorem surjective_algebraMap_of_linearMap (hb : Function.Surjective b) : - Function.Surjective (algebraMap F E) := fun x ↦ by +theorem surjective_algebraMap_of_linearMap (hb : Surjective b) : + Surjective (algebraMap F E) := fun x ↦ by obtain ⟨x, rfl⟩ := hb x obtain ⟨y, hy⟩ := hb (b 1 * b 1) refine ⟨x * y, ?_⟩ @@ -467,14 +516,14 @@ then the algebra map from `F` to `E` is also bijective. NOTE: The same result can also be obtained if there are two `F`-linear maps from `F` to `E`, one is injective, the other one is surjective. In this case, use `injective_algebraMap_of_linearMap` and `surjective_algebraMap_of_linearMap` separately. -/ -theorem bijective_algebraMap_of_linearMap (hb : Function.Bijective b) : - Function.Bijective (algebraMap F E) := +theorem bijective_algebraMap_of_linearMap (hb : Bijective b) : + Bijective (algebraMap F E) := ⟨injective_algebraMap_of_linearMap b hb.1, surjective_algebraMap_of_linearMap b hb.2⟩ /-- If `E` is an `F`-algebra, there exists an `F`-linear isomorphism from `F` to `E` (namely, `E` is a free `F`-module of rank one), then the algebra map from `F` to `E` is bijective. -/ theorem bijective_algebraMap_of_linearEquiv (b : F ≃ₗ[F] E) : - Function.Bijective (algebraMap F E) := + Bijective (algebraMap F E) := bijective_algebraMap_of_linearMap _ b.bijective end algebraMap @@ -486,7 +535,7 @@ variable {M N} [AddCommMonoid M] [AddCommMonoid N] [Module R M] [Module S M] [Is variable [Module R N] [Module S N] [IsScalarTower R S N] /-- If `R →+* S` is surjective, then `S`-linear maps between modules are exactly `R`-linear maps. -/ -def LinearMap.extendScalarsOfSurjectiveEquiv (h : Function.Surjective (algebraMap R S)) : +def LinearMap.extendScalarsOfSurjectiveEquiv (h : Surjective (algebraMap R S)) : (M →ₗ[R] N) ≃ₗ[R] (M →ₗ[S] N) where toFun f := { __ := f, map_smul' := fun r x ↦ by obtain ⟨r, rfl⟩ := h r; simp } map_add' _ _ := rfl @@ -496,17 +545,17 @@ def LinearMap.extendScalarsOfSurjectiveEquiv (h : Function.Surjective (algebraMa right_inv _ := rfl /-- If `R →+* S` is surjective, then `R`-linear maps are also `S`-linear. -/ -abbrev LinearMap.extendScalarsOfSurjective (h : Function.Surjective (algebraMap R S)) +abbrev LinearMap.extendScalarsOfSurjective (h : Surjective (algebraMap R S)) (l : M →ₗ[R] N) : M →ₗ[S] N := extendScalarsOfSurjectiveEquiv h l /-- If `R →+* S` is surjective, then `R`-linear isomorphisms are also `S`-linear. -/ -def LinearEquiv.extendScalarsOfSurjective (h : Function.Surjective (algebraMap R S)) +def LinearEquiv.extendScalarsOfSurjective (h : Surjective (algebraMap R S)) (f : M ≃ₗ[R] N) : M ≃ₗ[S] N where __ := f map_smul' r x := by obtain ⟨r, rfl⟩ := h r; simp -variable (h : Function.Surjective (algebraMap R S)) +variable (h : Surjective (algebraMap R S)) @[simp] lemma LinearMap.extendScalarsOfSurjective_apply (l : M →ₗ[R] N) (x) : diff --git a/Mathlib/Algebra/AlgebraicCard.lean b/Mathlib/Algebra/AlgebraicCard.lean index c9fce882650c0..1d01bc5efa729 100644 --- a/Mathlib/Algebra/AlgebraicCard.lean +++ b/Mathlib/Algebra/AlgebraicCard.lean @@ -66,7 +66,7 @@ theorem cardinalMk_lift_of_infinite [Infinite R] : Cardinal.lift.{u} #{ x : A // IsAlgebraic R x } = Cardinal.lift.{v} #R := ((cardinalMk_lift_le_max R A).trans_eq (max_eq_left <| aleph0_le_mk _)).antisymm <| lift_mk_le'.2 ⟨⟨fun x => ⟨algebraMap R A x, isAlgebraic_algebraMap _⟩, fun _ _ h => - NoZeroSMulDivisors.algebraMap_injective R A (Subtype.ext_iff.1 h)⟩⟩ + FaithfulSMul.algebraMap_injective R A (Subtype.ext_iff.1 h)⟩⟩ @[deprecated (since := "2024-11-10")] alias cardinal_mk_lift_of_infinite := cardinalMk_lift_of_infinite diff --git a/Mathlib/Algebra/Central/Basic.lean b/Mathlib/Algebra/Central/Basic.lean index e0386ab247eab..ef13a87438e02 100644 --- a/Mathlib/Algebra/Central/Basic.lean +++ b/Mathlib/Algebra/Central/Basic.lean @@ -47,7 +47,7 @@ lemma baseField_essentially_unique simp only [center_eq_bot, mem_bot, Set.mem_range, forall_exists_index] rintro x rfl exact ⟨algebraMap k K x, by simp [algebraMap_eq_smul_one, smul_assoc]⟩ } - refine ⟨NoZeroSMulDivisors.algebraMap_injective k K, fun x => ?_⟩ + refine ⟨FaithfulSMul.algebraMap_injective k K, fun x => ?_⟩ have H : algebraMap K D x ∈ (Subalgebra.center K D : Set D) := Subalgebra.algebraMap_mem _ _ rw [show (Subalgebra.center K D : Set D) = Subalgebra.center k D by rfl] at H simp only [center_eq_bot, coe_bot, Set.mem_range] at H diff --git a/Mathlib/Algebra/Central/TensorProduct.lean b/Mathlib/Algebra/Central/TensorProduct.lean index fc53bce1773ba..0b9cfec58fd42 100644 --- a/Mathlib/Algebra/Central/TensorProduct.lean +++ b/Mathlib/Algebra/Central/TensorProduct.lean @@ -72,13 +72,13 @@ lemma right_of_tensor (inj : Function.Injective (algebraMap K B)) [Module.Flat K non-trivial, then `B` is central. -/ lemma left_of_tensor_of_field (K B C : Type*) [Field K] [Ring B] [Ring C] [Nontrivial C] [Algebra K B] [Algebra K C] [IsCentral K (B ⊗[K] C)] : IsCentral K B := - left_of_tensor K B C <| NoZeroSMulDivisors.algebraMap_injective K C + left_of_tensor K B C <| FaithfulSMul.algebraMap_injective K C /-- Let `B` and `C` be two algebras over a field `K`, if `B ⊗[K] C` is central and `A` is non-trivial, then `B` is central. -/ lemma right_of_tensor_of_field (K B C : Type*) [Field K] [Ring B] [Ring C] [Nontrivial B] [Algebra K B] [Algebra K C] [IsCentral K (B ⊗[K] C)] : IsCentral K C := - right_of_tensor K B C <| NoZeroSMulDivisors.algebraMap_injective K B + right_of_tensor K B C <| FaithfulSMul.algebraMap_injective K B end Algebra.IsCentral diff --git a/Mathlib/Algebra/Lie/TraceForm.lean b/Mathlib/Algebra/Lie/TraceForm.lean index 5f4f3fc236c8a..6db04a3d047af 100644 --- a/Mathlib/Algebra/Lie/TraceForm.lean +++ b/Mathlib/Algebra/Lie/TraceForm.lean @@ -262,9 +262,9 @@ lemma lowerCentralSeries_one_inf_center_le_ker_traceForm [Module.Free R M] [Modu rw [traceForm_apply_apply, LinearMap.zero_apply] let A := AlgebraicClosure (FractionRing R) suffices algebraMap R A (trace R _ ((φ z).comp (φ x))) = 0 by - have _i : NoZeroSMulDivisors R A := NoZeroSMulDivisors.trans R (FractionRing R) A + have _i : NoZeroSMulDivisors R A := NoZeroSMulDivisors.trans_faithfulSMul R (FractionRing R) A rw [← map_zero (algebraMap R A)] at this - exact NoZeroSMulDivisors.algebraMap_injective R A this + exact FaithfulSMul.algebraMap_injective R A this rw [← LinearMap.trace_baseChange, LinearMap.baseChange_comp, ← toEnd_baseChange, ← toEnd_baseChange] replace hz : 1 ⊗ₜ z ∈ lowerCentralSeries A (A ⊗[R] L) (A ⊗[R] L) 1 := by diff --git a/Mathlib/Algebra/Module/Lattice.lean b/Mathlib/Algebra/Module/Lattice.lean index b05bf47a40a73..a4aae942ec827 100644 --- a/Mathlib/Algebra/Module/Lattice.lean +++ b/Mathlib/Algebra/Module/Lattice.lean @@ -164,9 +164,7 @@ variable [IsPrincipalIdealRing R] Note that under our conditions, `NoZeroSMulDivisors R K` simply says that `algebraMap R K` is injective. -/ instance free [NoZeroSMulDivisors R K] (M : Submodule R V) [IsLattice K M] : Module.Free R M := by - haveI : NoZeroSMulDivisors R V := by - apply NoZeroSMulDivisors.of_algebraMap_injective' (A := K) - exact NoZeroSMulDivisors.algebraMap_injective R K + have := NoZeroSMulDivisors.trans_faithfulSMul R K V -- any torsion free finite module over a PID is free infer_instance diff --git a/Mathlib/Algebra/Polynomial/Roots.lean b/Mathlib/Algebra/Polynomial/Roots.lean index 3a5f5ab6b5d84..620416ce8fc9e 100644 --- a/Mathlib/Algebra/Polynomial/Roots.lean +++ b/Mathlib/Algebra/Polynomial/Roots.lean @@ -117,7 +117,7 @@ theorem mem_roots_map_of_injective [Semiring S] {p : S[X]} {f : S →+* R} rw [mem_roots ((Polynomial.map_ne_zero_iff hf).mpr hp), IsRoot, eval_map] lemma mem_roots_iff_aeval_eq_zero {x : R} (w : p ≠ 0) : x ∈ roots p ↔ aeval x p = 0 := by - rw [aeval_def, ← mem_roots_map_of_injective (NoZeroSMulDivisors.algebraMap_injective _ _) w, + rw [aeval_def, ← mem_roots_map_of_injective (FaithfulSMul.algebraMap_injective _ _) w, Algebra.id.map_eq_id, map_id] theorem card_le_degree_of_subset_roots {p : R[X]} {Z : Finset R} (h : Z.val ⊆ p.roots) : @@ -392,7 +392,7 @@ theorem mem_aroots' [CommRing S] [IsDomain S] [Algebra T S] {p : T[X]} {a : S} : theorem mem_aroots [CommRing S] [IsDomain S] [Algebra T S] [NoZeroSMulDivisors T S] {p : T[X]} {a : S} : a ∈ p.aroots S ↔ p ≠ 0 ∧ aeval a p = 0 := by rw [mem_aroots', Polynomial.map_ne_zero_iff] - exact NoZeroSMulDivisors.algebraMap_injective T S + exact FaithfulSMul.algebraMap_injective T S theorem aroots_mul [CommRing S] [IsDomain S] [Algebra T S] [NoZeroSMulDivisors T S] {p q : T[X]} (hpq : p * q ≠ 0) : @@ -400,7 +400,7 @@ theorem aroots_mul [CommRing S] [IsDomain S] [Algebra T S] suffices map (algebraMap T S) p * map (algebraMap T S) q ≠ 0 by rw [aroots_def, Polynomial.map_mul, roots_mul this] rwa [← Polynomial.map_mul, Polynomial.map_ne_zero_iff - (NoZeroSMulDivisors.algebraMap_injective T S)] + (FaithfulSMul.algebraMap_injective T S)] @[simp] theorem aroots_X_sub_C [CommRing S] [IsDomain S] [Algebra T S] @@ -436,7 +436,7 @@ theorem aroots_C_mul [CommRing S] [IsDomain S] [Algebra T S] (C a * p).aroots S = p.aroots S := by rw [aroots_def, Polynomial.map_mul, map_C, roots_C_mul] rwa [map_ne_zero_iff] - exact NoZeroSMulDivisors.algebraMap_injective T S + exact FaithfulSMul.algebraMap_injective T S @[simp] theorem aroots_smul_nonzero [CommRing S] [IsDomain S] [Algebra T S] @@ -534,7 +534,7 @@ theorem mem_rootSet' {p : T[X]} {S : Type*} [CommRing S] [IsDomain S] [Algebra T theorem mem_rootSet {p : T[X]} {S : Type*} [CommRing S] [IsDomain S] [Algebra T S] [NoZeroSMulDivisors T S] {a : S} : a ∈ p.rootSet S ↔ p ≠ 0 ∧ aeval a p = 0 := by - rw [mem_rootSet', Polynomial.map_ne_zero_iff (NoZeroSMulDivisors.algebraMap_injective T S)] + rw [mem_rootSet', Polynomial.map_ne_zero_iff (FaithfulSMul.algebraMap_injective T S)] theorem mem_rootSet_of_ne {p : T[X]} {S : Type*} [CommRing S] [IsDomain S] [Algebra T S] [NoZeroSMulDivisors T S] (hp : p ≠ 0) {a : S} : a ∈ p.rootSet S ↔ aeval a p = 0 := @@ -559,7 +559,7 @@ theorem rootSet_mapsTo {p : T[X]} {S S'} [CommRing S] [IsDomain S] [Algebra T S] (p.rootSet S).MapsTo f (p.rootSet S') := by refine rootSet_maps_to' (fun h₀ => ?_) f obtain rfl : p = 0 := - map_injective _ (NoZeroSMulDivisors.algebraMap_injective T S') (by rwa [Polynomial.map_zero]) + map_injective _ (FaithfulSMul.algebraMap_injective T S') (by rwa [Polynomial.map_zero]) exact Polynomial.map_zero _ theorem mem_rootSet_of_injective [CommRing S] {p : S[X]} [Algebra S R] diff --git a/Mathlib/AlgebraicGeometry/ValuativeCriterion.lean b/Mathlib/AlgebraicGeometry/ValuativeCriterion.lean index 46b7c013d0ec1..779bb1acde6bf 100644 --- a/Mathlib/AlgebraicGeometry/ValuativeCriterion.lean +++ b/Mathlib/AlgebraicGeometry/ValuativeCriterion.lean @@ -304,7 +304,7 @@ lemma IsSeparated.valuativeCriterion [IsSeparated f] : ValuativeCriterion.Unique RingHom.toMorphismProperty_respectsIso_iff.mp RingHom.injective_respectsIso show P _ rw [← MorphismProperty.arrow_mk_iso_iff (P := P) e] - exact NoZeroSMulDivisors.algebraMap_injective S.R S.K + exact FaithfulSMul.algebraMap_injective S.R S.K rw [Scheme.comp_appTop] at this exact Function.Injective.of_comp this · rw [@HasAffineProperty.iff_of_isAffine @IsClosedImmersion] at this diff --git a/Mathlib/FieldTheory/Differential/Liouville.lean b/Mathlib/FieldTheory/Differential/Liouville.lean index cf9795aae7da6..4d84efa15e401 100644 --- a/Mathlib/FieldTheory/Differential/Liouville.lean +++ b/Mathlib/FieldTheory/Differential/Liouville.lean @@ -66,7 +66,7 @@ lemma IsLiouville.trans {A : Type*} [Field A] [Algebra K A] [Algebra F A] apply_fun ((↑) : F → K) · simp only [Function.comp_apply, coe_deriv, hc, algebraMap.coe_zero] apply hc₀ - · apply NoZeroSMulDivisors.algebraMap_injective + · apply FaithfulSMul.algebraMap_injective section Algebraic /- @@ -120,7 +120,7 @@ private local instance isLiouville_of_finiteDimensional_galois [FiniteDimensiona isLiouville (a : F) (ι : Type) [Fintype ι] (c : ι → F) (hc : ∀ x, (c x)′ = 0) (u : ι → K) (v : K) (h : a = ∑ x, c x * logDeriv (u x) + v′) := by haveI : CharZero K := charZero_of_injective_algebraMap - (NoZeroSMulDivisors.algebraMap_injective F K) + (FaithfulSMul.algebraMap_injective F K) -- We sum `e x` over all isomorphisms `e : K ≃ₐ[F] K`. -- Because this is a Galois extension each of the relevant values will be in `F`. -- We need to divide by `Fintype.card (K ≃ₐ[F] K)` to get the original answer. @@ -159,7 +159,7 @@ private local instance isLiouville_of_finiteDimensional_galois [FiniteDimensiona · -- Proving that this works is mostly straightforward algebraic manipulation, apply_fun (algebraMap F K) case inj => - exact NoZeroSMulDivisors.algebraMap_injective F K + exact FaithfulSMul.algebraMap_injective F K simp only [map_add, map_sum, map_mul, ← logDeriv_algebraMap, hu₀, ← deriv_algebraMap, hv₀] unfold u₁ v₁ c₀ clear c₀ u₁ u₀ hu₀ v₁ v₀ hv₀ diff --git a/Mathlib/FieldTheory/IsAlgClosed/Basic.lean b/Mathlib/FieldTheory/IsAlgClosed/Basic.lean index e6f813f438f23..a691ac27315c1 100644 --- a/Mathlib/FieldTheory/IsAlgClosed/Basic.lean +++ b/Mathlib/FieldTheory/IsAlgClosed/Basic.lean @@ -279,10 +279,10 @@ variable {S : Type v} [CommRing S] [IsDomain S] [Algebra R S] [Algebra R M] [NoZ variable {M} private instance FractionRing.isAlgebraic : - letI : IsDomain R := (NoZeroSMulDivisors.algebraMap_injective R S).isDomain _ + letI : IsDomain R := (FaithfulSMul.algebraMap_injective R S).isDomain _ letI : Algebra (FractionRing R) (FractionRing S) := FractionRing.liftAlgebra R _ Algebra.IsAlgebraic (FractionRing R) (FractionRing S) := by - letI : IsDomain R := (NoZeroSMulDivisors.algebraMap_injective R S).isDomain _ + letI : IsDomain R := (FaithfulSMul.algebraMap_injective R S).isDomain _ letI : Algebra (FractionRing R) (FractionRing S) := FractionRing.liftAlgebra R _ have := FractionRing.isScalarTower_liftAlgebra R (FractionRing S) have := (IsFractionRing.isAlgebraic_iff' R S (FractionRing S)).1 inferInstance @@ -295,7 +295,7 @@ private instance FractionRing.isAlgebraic : closed extension of R. -/ @[stacks 09GU] noncomputable irreducible_def lift : S →ₐ[R] M := by - letI : IsDomain R := (NoZeroSMulDivisors.algebraMap_injective R S).isDomain _ + letI : IsDomain R := (FaithfulSMul.algebraMap_injective R S).isDomain _ letI := FractionRing.liftAlgebra R M letI := FractionRing.liftAlgebra R (FractionRing S) have := FractionRing.isScalarTower_liftAlgebra R M @@ -370,11 +370,8 @@ theorem ofAlgebraic [hKJ : Algebra.IsAlgebraic K J] : IsAlgClosure K L := an algebraic extension of `R` -/ noncomputable def equivOfAlgebraic' [Nontrivial S] [NoZeroSMulDivisors R S] [Algebra.IsAlgebraic R L] : L ≃ₐ[R] M := by - letI : NoZeroSMulDivisors R L := NoZeroSMulDivisors.of_algebraMap_injective <| by - rw [IsScalarTower.algebraMap_eq R S L] - exact (Function.Injective.comp (NoZeroSMulDivisors.algebraMap_injective S L) - (NoZeroSMulDivisors.algebraMap_injective R S) :) - letI : IsAlgClosure R L := + have : NoZeroSMulDivisors R L := NoZeroSMulDivisors.trans_faithfulSMul R S L + have : IsAlgClosure R L := { isAlgClosed := IsAlgClosure.isAlgClosed S isAlgebraic := ‹_› } exact IsAlgClosure.equiv _ _ _ @@ -396,13 +393,13 @@ noncomputable def equivOfEquivAux (hSR : S ≃+* R) : { e : L ≃+* M // e.toRingHom.comp (algebraMap S L) = (algebraMap R M).comp hSR.toRingHom } := by letI : Algebra R S := RingHom.toAlgebra hSR.symm.toRingHom letI : Algebra S R := RingHom.toAlgebra hSR.toRingHom - letI : IsDomain R := (NoZeroSMulDivisors.algebraMap_injective R M).isDomain _ - letI : IsDomain S := (NoZeroSMulDivisors.algebraMap_injective S L).isDomain _ + letI : IsDomain R := (FaithfulSMul.algebraMap_injective R M).isDomain _ + letI : IsDomain S := (FaithfulSMul.algebraMap_injective S L).isDomain _ letI : Algebra R L := RingHom.toAlgebra ((algebraMap S L).comp (algebraMap R S)) haveI : IsScalarTower R S L := IsScalarTower.of_algebraMap_eq fun _ => rfl haveI : IsScalarTower S R L := IsScalarTower.of_algebraMap_eq (by simp [RingHom.algebraMap_toAlgebra]) - haveI : NoZeroSMulDivisors R S := NoZeroSMulDivisors.of_algebraMap_injective hSR.symm.injective + have : FaithfulSMul R S := (faithfulSMul_iff_algebraMap_injective R S).mpr hSR.symm.injective have : Algebra.IsAlgebraic R L := (IsAlgClosure.isAlgebraic.extendScalars (show Function.Injective (algebraMap S R) from hSR.injective)) refine diff --git a/Mathlib/FieldTheory/KummerExtension.lean b/Mathlib/FieldTheory/KummerExtension.lean index 352ba6623e838..21d45c381d28d 100644 --- a/Mathlib/FieldTheory/KummerExtension.lean +++ b/Mathlib/FieldTheory/KummerExtension.lean @@ -73,7 +73,7 @@ lemma X_pow_sub_C_eq_prod {R : Type*} [CommRing R] [IsDomain R] (X ^ n - C a) = ∏ i ∈ Finset.range n, (X - C (ζ ^ i * α)) := by let K := FractionRing R let i := algebraMap R K - have h := NoZeroSMulDivisors.algebraMap_injective R K + have h := FaithfulSMul.algebraMap_injective R K apply_fun Polynomial.map i using map_injective i h simpa only [Polynomial.map_sub, Polynomial.map_pow, map_X, map_C, map_mul, map_pow, Polynomial.map_prod, Polynomial.map_mul] diff --git a/Mathlib/FieldTheory/Normal/Defs.lean b/Mathlib/FieldTheory/Normal/Defs.lean index a8977634afdf3..7d3a150c43952 100644 --- a/Mathlib/FieldTheory/Normal/Defs.lean +++ b/Mathlib/FieldTheory/Normal/Defs.lean @@ -188,7 +188,7 @@ def Normal.algHomEquivAut [Normal F E] : (E →ₐ[F] K₁) ≃ E ≃ₐ[F] E wh right_inv σ := by ext simp only [AlgHom.restrictNormal', AlgEquiv.toAlgHom_eq_coe, AlgEquiv.coe_ofBijective] - apply NoZeroSMulDivisors.algebraMap_injective E K₁ + apply FaithfulSMul.algebraMap_injective E K₁ rw [AlgHom.restrictNormal_commutes] simp diff --git a/Mathlib/FieldTheory/PurelyInseparable/Basic.lean b/Mathlib/FieldTheory/PurelyInseparable/Basic.lean index 30cc4d0c2701c..5db00ddb901d6 100644 --- a/Mathlib/FieldTheory/PurelyInseparable/Basic.lean +++ b/Mathlib/FieldTheory/PurelyInseparable/Basic.lean @@ -158,7 +158,7 @@ theorem IsPurelyInseparable.surjective_algebraMap_of_isSeparable theorem IsPurelyInseparable.bijective_algebraMap_of_isSeparable [Nontrivial E] [NoZeroSMulDivisors F E] [IsPurelyInseparable F E] [Algebra.IsSeparable F E] : Function.Bijective (algebraMap F E) := - ⟨NoZeroSMulDivisors.algebraMap_injective F E, surjective_algebraMap_of_isSeparable F E⟩ + ⟨FaithfulSMul.algebraMap_injective F E, surjective_algebraMap_of_isSeparable F E⟩ variable {F E} in /-- If a subalgebra of `E / F` is both purely inseparable and separable, then it is equal diff --git a/Mathlib/FieldTheory/RatFunc/Basic.lean b/Mathlib/FieldTheory/RatFunc/Basic.lean index 9a1cde7fbd08b..badeed639d44e 100644 --- a/Mathlib/FieldTheory/RatFunc/Basic.lean +++ b/Mathlib/FieldTheory/RatFunc/Basic.lean @@ -663,7 +663,7 @@ instance : IsFractionRing K[X] (RatFunc K) where simp only [← ofFractionRing_algebraMap, Function.comp_apply, ← ofFractionRing_mul, ofFractionRing.injEq] -@[deprecated "Use NoZeroSMulDivisors.algebraMap_eq_zero_iff instead." (since := "2024-09-08")] +@[deprecated "Use FaithfulSMul.algebraMap_eq_zero_iff instead." (since := "2024-09-08")] theorem algebraMap_eq_zero_iff {x : K[X]} : algebraMap K[X] (RatFunc K) x = 0 ↔ x = 0 := by simp diff --git a/Mathlib/LinearAlgebra/BilinearForm/DualLattice.lean b/Mathlib/LinearAlgebra/BilinearForm/DualLattice.lean index 8fba55a7ccff6..7bfb7c488ce3b 100644 --- a/Mathlib/LinearAlgebra/BilinearForm/DualLattice.lean +++ b/Mathlib/LinearAlgebra/BilinearForm/DualLattice.lean @@ -66,12 +66,12 @@ 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 + map_add' := fun x y ↦ FaithfulSMul.algebraMap_injective R S (by simp) + map_smul' := fun r m ↦ FaithfulSMul.algebraMap_injective R S (by simp [← Algebra.smul_def]) } - map_add' := fun x y ↦ LinearMap.ext fun z ↦ NoZeroSMulDivisors.algebraMap_injective R S + map_add' := fun x y ↦ LinearMap.ext fun z ↦ FaithfulSMul.algebraMap_injective R S (by simp) - map_smul' := fun r x ↦ LinearMap.ext fun y ↦ NoZeroSMulDivisors.algebraMap_injective R S + map_smul' := fun r x ↦ LinearMap.ext fun y ↦ FaithfulSMul.algebraMap_injective R S (by simp [← Algebra.smul_def]) } lemma dualSubmoduleToDual_injective (hB : B.Nondegenerate) [NoZeroSMulDivisors R S] diff --git a/Mathlib/LinearAlgebra/Dual.lean b/Mathlib/LinearAlgebra/Dual.lean index 295a03c7af209..fe66eb87c9846 100644 --- a/Mathlib/LinearAlgebra/Dual.lean +++ b/Mathlib/LinearAlgebra/Dual.lean @@ -716,7 +716,8 @@ instance instFiniteDimensionalOfIsReflexive (K V : Type*) rw [lift_id'] exact lt_trans h₁ h₂ -instance [IsDomain R] : NoZeroSMulDivisors R M := by +-- see Note [lower instance priority] +instance (priority := 100) [IsDomain R] : NoZeroSMulDivisors R M := by refine (noZeroSMulDivisors_iff R M).mpr ?_ intro r m hrm rw [or_iff_not_imp_left] diff --git a/Mathlib/LinearAlgebra/Eigenspace/Basic.lean b/Mathlib/LinearAlgebra/Eigenspace/Basic.lean index 5aeea273a0985..c4adfb4fb4c3b 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Basic.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Basic.lean @@ -639,7 +639,7 @@ lemma disjoint_genEigenspace [NoZeroSMulDivisors R M] apply mapsTo_genEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f _) apply isNilpotent_restrict_genEigenspace_nat have hf₁₂ : f₂ - f₁ = algebraMap R (End R p) (μ₁ - μ₂) := by ext; simp [f₁, f₂, sub_smul] - rw [hf₁₂, IsNilpotent.map_iff (NoZeroSMulDivisors.algebraMap_injective R (End R p)), + rw [hf₁₂, IsNilpotent.map_iff (FaithfulSMul.algebraMap_injective R (End R p)), isNilpotent_iff_eq_zero, sub_eq_zero] at this contradiction diff --git a/Mathlib/LinearAlgebra/LinearIndependent.lean b/Mathlib/LinearAlgebra/LinearIndependent.lean index 1b216c6e08dc5..cf92c3c6fe93a 100644 --- a/Mathlib/LinearAlgebra/LinearIndependent.lean +++ b/Mathlib/LinearAlgebra/LinearIndependent.lean @@ -1300,7 +1300,7 @@ lemma linearIndependent_algHom_toLinearMap' (K M L) [CommRing K] LinearIndependent K (AlgHom.toLinearMap : (M →ₐ[K] L) → M →ₗ[K] L) := by apply (linearIndependent_algHom_toLinearMap K M L).restrict_scalars simp_rw [Algebra.smul_def, mul_one] - exact NoZeroSMulDivisors.algebraMap_injective K L + exact FaithfulSMul.algebraMap_injective K L end Module diff --git a/Mathlib/LinearAlgebra/Matrix/HermitianFunctionalCalculus.lean b/Mathlib/LinearAlgebra/Matrix/HermitianFunctionalCalculus.lean index 5248086346b66..947720038a3db 100644 --- a/Mathlib/LinearAlgebra/Matrix/HermitianFunctionalCalculus.lean +++ b/Mathlib/LinearAlgebra/Matrix/HermitianFunctionalCalculus.lean @@ -39,7 +39,7 @@ variable {n 𝕜 : Type*} [RCLike 𝕜] [Fintype n] [DecidableEq n] {A : Matrix lemma finite_real_spectrum : (spectrum ℝ A).Finite := by rw [← spectrum.preimage_algebraMap 𝕜] - exact A.finite_spectrum.preimage (NoZeroSMulDivisors.algebraMap_injective ℝ 𝕜).injOn + exact A.finite_spectrum.preimage (FaithfulSMul.algebraMap_injective ℝ 𝕜).injOn instance : Finite (spectrum ℝ A) := A.finite_real_spectrum diff --git a/Mathlib/LinearAlgebra/PerfectPairing/Restrict.lean b/Mathlib/LinearAlgebra/PerfectPairing/Restrict.lean index f9b217399a977..91153233ec4dc 100644 --- a/Mathlib/LinearAlgebra/PerfectPairing/Restrict.lean +++ b/Mathlib/LinearAlgebra/PerfectPairing/Restrict.lean @@ -95,7 +95,7 @@ private def restrictScalarsAux (hp : ∀ m n, p (i m) (j n) ∈ (algebraMap S R).range) : M' →ₗ[S] N' →ₗ[S] S := LinearMap.restrictScalarsRange i j (Algebra.linearMap S R) - (NoZeroSMulDivisors.algebraMap_injective S R) p.toLin hp + (FaithfulSMul.algebraMap_injective S R) p.toLin hp private lemma restrictScalarsAux_injective (hi : Injective i) @@ -103,7 +103,7 @@ private lemma restrictScalarsAux_injective (hp : ∀ m n, p (i m) (j n) ∈ (algebraMap S R).range) : Injective (p.restrictScalarsAux i j hp) := by let f := LinearMap.restrictScalarsRange i j (Algebra.linearMap S R) - (NoZeroSMulDivisors.algebraMap_injective S R) p.toLin hp + (FaithfulSMul.algebraMap_injective S R) p.toLin hp rw [← LinearMap.ker_eq_bot] refine (Submodule.eq_bot_iff _).mpr fun x (hx : f x = 0) ↦ ?_ replace hx (n : N) : p (i x) n = 0 := by @@ -128,7 +128,7 @@ private lemma restrictScalarsAux_surjective obtain ⟨m, hm⟩ := h g refine ⟨m, ?_⟩ ext n - apply NoZeroSMulDivisors.algebraMap_injective S R + apply FaithfulSMul.algebraMap_injective S R change Algebra.linearMap S R _ = _ simpa [restrictScalarsAux] using LinearMap.congr_fun hm n @@ -180,7 +180,7 @@ lemma exists_basis_basis_of_span_eq_top_of_mem_algebraMap have hv' : LinearIndependent K v' := by replace hv₃ := hv₃.restrict_scalars (R := K) <| by simp_rw [← Algebra.algebraMap_eq_smul_one] - exact NoZeroSMulDivisors.algebraMap_injective K L + exact FaithfulSMul.algebraMap_injective K L rw [show ((↑) : v → M) = M'.subtype ∘ v' from rfl] at hv₃ exact hv₃.of_comp suffices span K (Set.range v') = ⊤ by @@ -259,7 +259,7 @@ def restrictScalarsField (x : M') (y : N') : algebraMap K L (p.restrictScalarsField i j hi hj hij hp x y) = p (i x) (j y) := LinearMap.restrictScalarsRange_apply i j (Algebra.linearMap K L) - (NoZeroSMulDivisors.algebraMap_injective K L) p.toLin hp x y + (FaithfulSMul.algebraMap_injective K L) p.toLin hp x y end Field diff --git a/Mathlib/LinearAlgebra/RootSystem/BaseChange.lean b/Mathlib/LinearAlgebra/RootSystem/BaseChange.lean index 60e98abdd2d75..759fcc3bb473a 100644 --- a/Mathlib/LinearAlgebra/RootSystem/BaseChange.lean +++ b/Mathlib/LinearAlgebra/RootSystem/BaseChange.lean @@ -75,7 +75,7 @@ def restrictScalars' : root_coroot_two i := by have : algebraMap K L 2 = 2 := by rw [← Int.cast_two (R := K), ← Int.cast_two (R := L), map_intCast] - exact NoZeroSMulDivisors.algebraMap_injective K L <| by simp [this] + exact FaithfulSMul.algebraMap_injective K L <| by simp [this] reflection_perm := P.reflection_perm reflection_perm_root i j := by ext; simpa [algebra_compatible_smul L] using P.reflection_perm_root i j diff --git a/Mathlib/LinearAlgebra/RootSystem/CartanMatrix.lean b/Mathlib/LinearAlgebra/RootSystem/CartanMatrix.lean index 3c23104e4e2bb..863271814fe03 100644 --- a/Mathlib/LinearAlgebra/RootSystem/CartanMatrix.lean +++ b/Mathlib/LinearAlgebra/RootSystem/CartanMatrix.lean @@ -48,6 +48,6 @@ variable [Nontrivial R] [NoZeroSMulDivisors S R] @[simp] lemma cartanMatrixIn_apply_same (i : b.support) : b.cartanMatrixIn S i i = 2 := - NoZeroSMulDivisors.algebraMap_injective S R <| by simp [cartanMatrixIn_def, map_ofNat] + FaithfulSMul.algebraMap_injective S R <| by simp [cartanMatrixIn_def, map_ofNat] end RootPairing.Base diff --git a/Mathlib/NumberTheory/Cyclotomic/Basic.lean b/Mathlib/NumberTheory/Cyclotomic/Basic.lean index 5d5e4e175bd03..21891b2e19a60 100644 --- a/Mathlib/NumberTheory/Cyclotomic/Basic.lean +++ b/Mathlib/NumberTheory/Cyclotomic/Basic.lean @@ -542,12 +542,11 @@ instance CyclotomicField.algebra' {R : Type*} [CommRing R] [Algebra R K] : instance {R : Type*} [CommRing R] [Algebra R K] : IsScalarTower R K (CyclotomicField n K) := SplittingField.isScalarTower _ -instance CyclotomicField.noZeroSMulDivisors [IsFractionRing A K] : - NoZeroSMulDivisors A (CyclotomicField n K) := by - refine NoZeroSMulDivisors.of_algebraMap_injective ?_ - rw [IsScalarTower.algebraMap_eq A K (CyclotomicField n K)] +instance [IsFractionRing A K] : NoZeroSMulDivisors A (CyclotomicField n K) := by + rw [NoZeroSMulDivisors.iff_faithfulSMul, faithfulSMul_iff_algebraMap_injective, + IsScalarTower.algebraMap_eq A K (CyclotomicField n K)] exact - (Function.Injective.comp (NoZeroSMulDivisors.algebraMap_injective K (CyclotomicField n K)) + (Function.Injective.comp (FaithfulSMul.algebraMap_injective K (CyclotomicField n K)) (IsFractionRing.injective A K) :) /-- If `A` is a domain with fraction field `K` and `n : ℕ+`, we define `CyclotomicRing n A K` as @@ -586,7 +585,7 @@ instance [IsFractionRing A K] : theorem algebraBase_injective [IsFractionRing A K] : Function.Injective <| algebraMap A (CyclotomicRing n A K) := - NoZeroSMulDivisors.algebraMap_injective _ _ + FaithfulSMul.algebraMap_injective _ _ instance : Algebra (CyclotomicRing n A K) (CyclotomicField n K) := (adjoin A _).toAlgebra @@ -596,7 +595,7 @@ theorem adjoin_algebra_injective : Subtype.val_injective instance : NoZeroSMulDivisors (CyclotomicRing n A K) (CyclotomicField n K) := - NoZeroSMulDivisors.of_algebraMap_injective (adjoin_algebra_injective n A K) + NoZeroSMulDivisors.iff_algebraMap_injective.mpr (adjoin_algebra_injective n A K) instance : IsScalarTower A (CyclotomicRing n A K) (CyclotomicField n K) := IsScalarTower.subalgebra' _ _ _ _ @@ -606,8 +605,8 @@ instance isCyclotomicExtension [IsFractionRing A K] [NeZero ((n : ℕ) : A)] : exists_prim_root := @fun a han => by rw [mem_singleton_iff] at han subst a - haveI := NeZero.of_noZeroSMulDivisors A K n - haveI := NeZero.of_noZeroSMulDivisors A (CyclotomicField n K) n + have := NeZero.of_faithfulSMul A K n + have := NeZero.of_faithfulSMul A (CyclotomicField n K) n obtain ⟨μ, hμ⟩ := (CyclotomicField.isCyclotomicExtension n K).exists_prim_root (mem_singleton n) refine ⟨⟨μ, subset_adjoin ?_⟩, ?_⟩ · apply (isRoot_of_unity_iff n.pos (CyclotomicField n K)).mpr diff --git a/Mathlib/NumberTheory/Cyclotomic/Discriminant.lean b/Mathlib/NumberTheory/Cyclotomic/Discriminant.lean index 0e61f7398af63..e15aabe4533a7 100644 --- a/Mathlib/NumberTheory/Cyclotomic/Discriminant.lean +++ b/Mathlib/NumberTheory/Cyclotomic/Discriminant.lean @@ -161,7 +161,7 @@ theorem discr_prime_pow [hcycl : IsCyclotomicExtension {p ^ k} K L] [hp : Fact ( rw [pow_one] at hζ hcycl have : natDegree (minpoly K ζ) = 1 := by rw [hζ.eq_neg_one_of_two_right, show (-1 : L) = algebraMap K L (-1) by simp, - minpoly.eq_X_sub_C_of_algebraMap_inj _ (NoZeroSMulDivisors.algebraMap_injective K L)] + minpoly.eq_X_sub_C_of_algebraMap_inj _ (FaithfulSMul.algebraMap_injective K L)] exact natDegree_X_sub_C (-1) rcases Fin.equiv_iff_eq.2 this with ⟨e⟩ rw [← Algebra.discr_reindex K (hζ.powerBasis K).basis e, coe_basis, powerBasis_gen]; norm_num diff --git a/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean b/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean index 2767a4973edb3..2b096f9991047 100644 --- a/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean +++ b/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean @@ -139,7 +139,7 @@ noncomputable def embeddingsEquivPrimitiveRoots (C : Type*) [CommRing C] [IsDoma (hζ.powerBasis K).liftEquiv.trans { toFun := fun x => by haveI := IsCyclotomicExtension.neZero' n K L - haveI hn := NeZero.of_noZeroSMulDivisors K C n + haveI hn := NeZero.of_faithfulSMul K C n refine ⟨x.1, ?_⟩ cases x rwa [mem_primitiveRoots n.pos, ← isRoot_cyclotomic_iff, IsRoot.def, @@ -147,7 +147,7 @@ noncomputable def embeddingsEquivPrimitiveRoots (C : Type*) [CommRing C] [IsDoma ← eval₂_eq_eval_map, ← aeval_def] invFun := fun x => by haveI := IsCyclotomicExtension.neZero' n K L - haveI hn := NeZero.of_noZeroSMulDivisors K C n + haveI hn := NeZero.of_faithfulSMul K C n refine ⟨x.1, ?_⟩ cases x rwa [aeval_def, eval₂_eq_eval_map, hζ.powerBasis_gen K, ← @@ -347,7 +347,7 @@ theorem sub_one_norm_eq_eval_cyclotomic [IsCyclotomicExtension {n} K L] (h : 2 < rw [cyclotomic', eval_prod, ← @Finset.prod_attach E E, ← univ_eq_attach] refine Fintype.prod_equiv (hζ.embeddingsEquivPrimitiveRoots E hirr) _ _ fun σ => ?_ simp - haveI : NeZero ((n : ℕ) : E) := NeZero.of_noZeroSMulDivisors K _ (n : ℕ) + haveI : NeZero ((n : ℕ) : E) := NeZero.of_faithfulSMul K _ (n : ℕ) rw [Hprod, cyclotomic', ← cyclotomic_eq_prod_X_sub_primitiveRoots (isRoot_cyclotomic_iff.1 hz), ← map_cyclotomic_int, _root_.map_intCast, ← Int.cast_one, eval_intCast_map, eq_intCast, Int.cast_id] diff --git a/Mathlib/NumberTheory/FunctionField.lean b/Mathlib/NumberTheory/FunctionField.lean index cd2a6cc65454d..28a58c87bd73f 100644 --- a/Mathlib/NumberTheory/FunctionField.lean +++ b/Mathlib/NumberTheory/FunctionField.lean @@ -207,12 +207,12 @@ theorem inftyValuation.C {k : Fq} (hk : k ≠ 0) : theorem inftyValuation.X : inftyValuationDef Fq RatFunc.X = Multiplicative.ofAdd (1 : ℤ) := by rw [inftyValuationDef, if_neg RatFunc.X_ne_zero, RatFunc.intDegree_X] -@[simp] +-- Dropped attribute `@[simp]` due to issue described here: +-- https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/.60synthInstance.2EmaxHeartbeats.60.20error.20but.20only.20in.20.60simpNF.60 theorem inftyValuation.polynomial {p : Fq[X]} (hp : p ≠ 0) : inftyValuationDef Fq (algebraMap Fq[X] (RatFunc Fq) p) = Multiplicative.ofAdd (p.natDegree : ℤ) := by - have hp' : algebraMap Fq[X] (RatFunc Fq) p ≠ 0 := by - rw [Ne, NoZeroSMulDivisors.algebraMap_eq_zero_iff]; exact hp + have hp' : algebraMap Fq[X] (RatFunc Fq) p ≠ 0 := by simpa rw [inftyValuationDef, if_neg hp', RatFunc.intDegree_polynomial] /-- The valued field `Fq(t)` with the valuation at infinity. -/ diff --git a/Mathlib/NumberTheory/KummerDedekind.lean b/Mathlib/NumberTheory/KummerDedekind.lean index 664ad5684a29a..37e5831f0e6d3 100644 --- a/Mathlib/NumberTheory/KummerDedekind.lean +++ b/Mathlib/NumberTheory/KummerDedekind.lean @@ -100,7 +100,7 @@ lemma mem_coeSubmodule_conductor {L} [CommRing L] [Algebra S L] [Algebra R L] obtain ⟨y, _, e⟩ := H 1 rw [map_one, mul_one] at e subst e - simp only [← _root_.map_mul, (NoZeroSMulDivisors.algebraMap_injective S L).eq_iff, + simp only [← _root_.map_mul, (FaithfulSMul.algebraMap_injective S L).eq_iff, exists_eq_right] at H exact ⟨_, H, rfl⟩ · rw [AlgHom.map_adjoin, Set.image_singleton]; rfl @@ -233,7 +233,7 @@ attribute [local instance] Ideal.Quotient.field private noncomputable def f (hx : (conductor R x).comap (algebraMap R S) ⊔ I = ⊤) (hx' : IsIntegral R x) : S ⧸ I.map (algebraMap R S) ≃+* (R ⧸ I)[X] ⧸ span {(minpoly R x).map (Ideal.Quotient.mk I)} := - (quotAdjoinEquivQuotMap hx (NoZeroSMulDivisors.algebraMap_injective + (quotAdjoinEquivQuotMap hx (FaithfulSMul.algebraMap_injective (Algebra.adjoin R {x}) S)).symm.trans <| ((Algebra.adjoin.powerBasis' hx').quotientEquivQuotientMinpolyMap I).toRingEquiv.trans <| quotEquivOfEq (by rw [Algebra.adjoin.powerBasis'_minpoly_gen hx']) @@ -248,7 +248,7 @@ private lemma f_symm_aux (hx : (conductor R x).comap (algebraMap R S) ⊔ I = congr convert (adjoin.powerBasis' hx').quotientEquivQuotientMinpolyMap_symm_apply_mk I Q apply (quotAdjoinEquivQuotMap hx - (NoZeroSMulDivisors.algebraMap_injective ((adjoin R {x})) S)).injective + (FaithfulSMul.algebraMap_injective ((adjoin R {x})) S)).injective simp only [RingEquiv.apply_symm_apply, adjoin.powerBasis'_gen, quotAdjoinEquivQuotMap_apply_mk, coe_aeval_mk_apply] @@ -262,7 +262,7 @@ noncomputable def normalizedFactorsMapEquivNormalizedFactorsMinPolyMk (hI : IsMa {d : (R ⧸ I)[X] | d ∈ normalizedFactors (Polynomial.map (Ideal.Quotient.mk I) (minpoly R x))} := by refine (normalizedFactorsEquivOfQuotEquiv (f hx hx') ?_ ?_).trans ?_ - · rwa [Ne, map_eq_bot_iff_of_injective (NoZeroSMulDivisors.algebraMap_injective R S), ← Ne] + · rwa [Ne, map_eq_bot_iff_of_injective (FaithfulSMul.algebraMap_injective R S), ← Ne] · by_contra h exact (show Polynomial.map (Ideal.Quotient.mk I) (minpoly R x) ≠ 0 from Polynomial.map_monic_ne_zero (minpoly.monic hx')) (span_singleton_eq_bot.mp h) @@ -326,7 +326,7 @@ theorem normalizedFactors_ideal_map_eq_normalizedFactors_min_poly_mk_map (hI : I · exact Polynomial.map_monic_ne_zero (minpoly.monic hx') · exact irreducible_of_normalized_factor _ hJ · rwa [← bot_eq_zero, Ne, - map_eq_bot_iff_of_injective (NoZeroSMulDivisors.algebraMap_injective R S)] + map_eq_bot_iff_of_injective (FaithfulSMul.algebraMap_injective R S)] theorem Ideal.irreducible_map_of_irreducible_minpoly (hI : IsMaximal I) (hI' : I ≠ ⊥) (hx : (conductor R x).comap (algebraMap R S) ⊔ I = ⊤) (hx' : IsIntegral R x) @@ -340,7 +340,7 @@ theorem Ideal.irreducible_map_of_irreducible_minpoly (hI : IsMaximal I) (hI' : I obtain ⟨y, hy⟩ := this have h := prod_normalizedFactors (show I.map (algebraMap R S) ≠ 0 by rwa [← bot_eq_zero, Ne, - map_eq_bot_iff_of_injective (NoZeroSMulDivisors.algebraMap_injective R S)]) + map_eq_bot_iff_of_injective (FaithfulSMul.algebraMap_injective R S)]) rw [associated_iff_eq, hy, Multiset.prod_singleton] at h rw [← h] exact diff --git a/Mathlib/NumberTheory/NumberField/Basic.lean b/Mathlib/NumberTheory/NumberField/Basic.lean index 65ce05f28dc8e..e0b835f9c10c8 100644 --- a/Mathlib/NumberTheory/NumberField/Basic.lean +++ b/Mathlib/NumberTheory/NumberField/Basic.lean @@ -206,15 +206,15 @@ variable {K} /-- The canonical map from `𝓞 K` to `K` is injective. -This is a convenient abbreviation for `NoZeroSMulDivisors.algebraMap_injective`. +This is a convenient abbreviation for `FaithfulSMul.algebraMap_injective`. -/ lemma coe_injective : Function.Injective (algebraMap (𝓞 K) K) := - NoZeroSMulDivisors.algebraMap_injective _ _ + FaithfulSMul.algebraMap_injective _ _ /-- The canonical map from `𝓞 K` to `K` is injective. This is a convenient abbreviation for `map_eq_zero_iff` applied to -`NoZeroSMulDivisors.algebraMap_injective`. +`FaithfulSMul.algebraMap_injective`. -/ lemma coe_eq_zero_iff {x : 𝓞 K} : algebraMap _ K x = 0 ↔ x = 0 := map_eq_zero_iff _ coe_injective @@ -222,7 +222,7 @@ lemma coe_eq_zero_iff {x : 𝓞 K} : algebraMap _ K x = 0 ↔ x = 0 := /-- The canonical map from `𝓞 K` to `K` is injective. This is a convenient abbreviation for `map_ne_zero_iff` applied to -`NoZeroSMulDivisors.algebraMap_injective`. +`FaithfulSMul.algebraMap_injective`. -/ lemma coe_ne_zero_iff {x : 𝓞 K} : algebraMap _ K x ≠ 0 ↔ x ≠ 0 := map_ne_zero_iff _ coe_injective @@ -340,10 +340,10 @@ theorem algebraMap.injective : Function.Injective (algebraMap (𝓞 K) (𝓞 L)) (RingHom.injective_iff_ker_eq_bot (algebraMap (𝓞 K) (𝓞 L))).mpr (ker_algebraMap_eq_bot K L) instance : NoZeroSMulDivisors (𝓞 K) (𝓞 L) := - NoZeroSMulDivisors.of_algebraMap_injective (algebraMap.injective K L) + NoZeroSMulDivisors.iff_algebraMap_injective.mpr <| algebraMap.injective K L instance : NoZeroSMulDivisors (𝓞 K) L := - NoZeroSMulDivisors.trans (𝓞 K) (𝓞 L) L + NoZeroSMulDivisors.trans_faithfulSMul (𝓞 K) (𝓞 L) L end extension diff --git a/Mathlib/NumberTheory/NumberField/FinitePlaces.lean b/Mathlib/NumberTheory/NumberField/FinitePlaces.lean index 5d5cf658791b0..cd928c8084a1c 100644 --- a/Mathlib/NumberTheory/NumberField/FinitePlaces.lean +++ b/Mathlib/NumberTheory/NumberField/FinitePlaces.lean @@ -91,7 +91,7 @@ noncomputable instance instRankOneValuedAdicCompletion : dsimp [adicCompletion] rw [valuedAdicCompletion_eq_valuation' v (x : K)] constructor - · simpa only [ne_eq, map_eq_zero, NoZeroSMulDivisors.algebraMap_eq_zero_iff] + · simpa only [ne_eq, map_eq_zero, FaithfulSMul.algebraMap_eq_zero_iff] · apply ne_of_lt rw [valuation_eq_intValuationDef, intValuation_lt_one_iff_dvd] exact dvd_span_singleton.mpr hx1 @@ -235,8 +235,7 @@ theorem mulSupport_finite_int {x : 𝓞 K} (h_x_nezero : x ≠ 0) : theorem mulSupport_finite {x : K} (h_x_nezero : x ≠ 0) : (Function.mulSupport fun w : FinitePlace K ↦ w x).Finite := by rcases IsFractionRing.div_surjective (A := 𝓞 K) x with ⟨a, b, hb, rfl⟩ - simp_all only [ne_eq, div_eq_zero_iff, NoZeroSMulDivisors.algebraMap_eq_zero_iff, not_or, - map_div₀] + simp_all only [ne_eq, div_eq_zero_iff, FaithfulSMul.algebraMap_eq_zero_iff, not_or, map_div₀] obtain ⟨ha, hb⟩ := h_x_nezero simp_rw [← RingOfIntegers.coe_eq_algebraMap] apply ((mulSupport_finite_int ha).union (mulSupport_finite_int hb)).subset diff --git a/Mathlib/NumberTheory/RamificationInertia/Basic.lean b/Mathlib/NumberTheory/RamificationInertia/Basic.lean index 137fee8752dbb..4c8addfccce8a 100644 --- a/Mathlib/NumberTheory/RamificationInertia/Basic.lean +++ b/Mathlib/NumberTheory/RamificationInertia/Basic.lean @@ -271,7 +271,7 @@ theorem FinrankQuotientMap.span_eq_top [IsDomain R] [IsDomain S] [Algebra K L] [ Submodule.span K (algebraMap S L '' b) = ⊤ := by have hRL : Function.Injective (algebraMap R L) := by rw [IsScalarTower.algebraMap_eq R K L] - exact (algebraMap K L).injective.comp (NoZeroSMulDivisors.algebraMap_injective R K) + exact (algebraMap K L).injective.comp (FaithfulSMul.algebraMap_injective R K) -- Let `M` be the `R`-module spanned by the proposed basis elements. let M : Submodule R S := Submodule.span R b -- Then `S / M` is generated by some finite set of `n` vectors `a`. diff --git a/Mathlib/RingTheory/AlgebraTower.lean b/Mathlib/RingTheory/AlgebraTower.lean index ef70b261a1645..0b9fce27c1b70 100644 --- a/Mathlib/RingTheory/AlgebraTower.lean +++ b/Mathlib/RingTheory/AlgebraTower.lean @@ -167,7 +167,7 @@ variable [CommRing R] [Ring S] [Algebra R S] theorem Basis.algebraMap_injective {ι : Type*} [NoZeroDivisors R] [Nontrivial S] (b : @Basis ι R S _ _ Algebra.toModule) : Function.Injective (algebraMap R S) := have : NoZeroSMulDivisors R S := b.noZeroSMulDivisors - NoZeroSMulDivisors.algebraMap_injective R S + FaithfulSMul.algebraMap_injective R S end Ring diff --git a/Mathlib/RingTheory/Algebraic/Cardinality.lean b/Mathlib/RingTheory/Algebraic/Cardinality.lean index 84f3f265104fc..eef75eac83d8f 100644 --- a/Mathlib/RingTheory/Algebraic/Cardinality.lean +++ b/Mathlib/RingTheory/Algebraic/Cardinality.lean @@ -32,7 +32,7 @@ theorem lift_cardinalMk_le_sigma_polynomial : let p := Classical.indefiniteDescription _ (Algebra.IsAlgebraic.isAlgebraic x) ⟨p.1, x, by dsimp - have := (Polynomial.map_ne_zero_iff (NoZeroSMulDivisors.algebraMap_injective R L)).2 p.2.1 + have := (Polynomial.map_ne_zero_iff (FaithfulSMul.algebraMap_injective R L)).2 p.2.1 rw [Polynomial.mem_roots this, Polynomial.IsRoot, Polynomial.eval_map, ← Polynomial.aeval_def, p.2.2]⟩) fun x y => by diff --git a/Mathlib/RingTheory/Algebraic/Integral.lean b/Mathlib/RingTheory/Algebraic/Integral.lean index 625d736514f0f..6dc35de98b4bd 100644 --- a/Mathlib/RingTheory/Algebraic/Integral.lean +++ b/Mathlib/RingTheory/Algebraic/Integral.lean @@ -251,7 +251,7 @@ theorem restrictScalars [Algebra.IsAlgebraic R S] exact int _ (Finset.mem_image_of_mem _ <| support_smul _ _ hn) have : IsAlgebraic (integralClosure R S) a := by refine ⟨p, ?_, ?_⟩ - · have := NoZeroSMulDivisors.of_algebraMap_injective hRS + · have : FaithfulSMul R S := (faithfulSMul_iff_algebraMap_injective R S).mpr hRS simpa only [← Polynomial.map_ne_zero_iff (f := Subring.subtype _) Subtype.val_injective, p, map_toSubring, smul_ne_zero_iff] using And.intro hr hp rw [← eval_map_algebraMap, Subalgebra.algebraMap_eq, ← map_map, ← Subalgebra.toSubring_subtype, diff --git a/Mathlib/RingTheory/DedekindDomain/Different.lean b/Mathlib/RingTheory/DedekindDomain/Different.lean index 5ab55f608ea3d..5295cf6eec2d4 100644 --- a/Mathlib/RingTheory/DedekindDomain/Different.lean +++ b/Mathlib/RingTheory/DedekindDomain/Different.lean @@ -120,7 +120,7 @@ variable [IsFractionRing A K] variable (A K) in lemma map_equiv_traceDual [IsDomain A] [IsFractionRing B L] [IsDomain B] - [NoZeroSMulDivisors A B] (I : Submodule B (FractionRing B)) : + [FaithfulSMul A B] (I : Submodule B (FractionRing B)) : (traceDual A (FractionRing A) I).map (FractionRing.algEquiv B L) = traceDual A K (I.map (FractionRing.algEquiv B L)) := by show Submodule.map (FractionRing.algEquiv B L).toLinearEquiv.toLinearMap _ = @@ -580,7 +580,7 @@ lemma pow_sub_one_dvd_differentIdeal_aux [IsFractionRing B L] [IsDedekindDomain (hP : P ^ e ∣ p.map (algebraMap A B)) : P ^ (e - 1) ∣ differentIdeal A B := by obtain ⟨a, ha⟩ := (pow_dvd_pow _ (Nat.sub_le e 1)).trans hP have hp' := (Ideal.map_eq_bot_iff_of_injective - (NoZeroSMulDivisors.algebraMap_injective A B)).not.mpr hp + (FaithfulSMul.algebraMap_injective A B)).not.mpr hp have habot : a ≠ ⊥ := fun ha' ↦ hp' (by simpa [ha'] using ha) have hPbot : P ≠ ⊥ := by rintro rfl; apply hp' diff --git a/Mathlib/RingTheory/DedekindDomain/Ideal.lean b/Mathlib/RingTheory/DedekindDomain/Ideal.lean index e1b5525792371..fb14158a971a9 100644 --- a/Mathlib/RingTheory/DedekindDomain/Ideal.lean +++ b/Mathlib/RingTheory/DedekindDomain/Ideal.lean @@ -142,7 +142,7 @@ theorem coe_ideal_span_singleton_div_self {x : R₁} (hx : x ≠ 0) : (Ideal.span ({x} : Set R₁) : FractionalIdeal R₁⁰ K) / Ideal.span ({x} : Set R₁) = 1 := by rw [coeIdeal_span_singleton, spanSingleton_div_self K <| - (map_ne_zero_iff _ <| NoZeroSMulDivisors.algebraMap_injective R₁ K).mpr hx] + (map_ne_zero_iff _ <| FaithfulSMul.algebraMap_injective R₁ K).mpr hx] theorem spanSingleton_mul_inv {x : K} (hx : x ≠ 0) : spanSingleton R₁⁰ x * (spanSingleton R₁⁰ x)⁻¹ = 1 := by @@ -153,7 +153,7 @@ theorem coe_ideal_span_singleton_mul_inv {x : R₁} (hx : x ≠ 0) : (Ideal.span ({x} : Set R₁) : FractionalIdeal R₁⁰ K)⁻¹ = 1 := by rw [coeIdeal_span_singleton, spanSingleton_mul_inv K <| - (map_ne_zero_iff _ <| NoZeroSMulDivisors.algebraMap_injective R₁ K).mpr hx] + (map_ne_zero_iff _ <| FaithfulSMul.algebraMap_injective R₁ K).mpr hx] theorem spanSingleton_inv_mul {x : K} (hx : x ≠ 0) : (spanSingleton R₁⁰ x)⁻¹ * spanSingleton R₁⁰ x = 1 := by @@ -215,7 +215,7 @@ lemma den_mem_inv {I : FractionalIdeal R₁⁰ K} (hI : I ≠ ⊥) : lemma num_le_mul_inv (I : FractionalIdeal R₁⁰ K) : I.num ≤ I * I⁻¹ := by by_cases hI : I = 0 - · rw [hI, num_zero_eq <| NoZeroSMulDivisors.algebraMap_injective R₁ K, zero_mul, zero_eq_bot, + · rw [hI, num_zero_eq <| FaithfulSMul.algebraMap_injective R₁ K, zero_mul, zero_eq_bot, coeIdeal_bot] · rw [mul_comm, ← den_mul_self_eq_num'] exact mul_right_mono I <| spanSingleton_le_iff_mem.2 (den_mem_inv hI) diff --git a/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean b/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean index 3a11fa700b7ff..d6361c0e303a4 100644 --- a/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean +++ b/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean @@ -63,12 +63,12 @@ theorem IsIntegralClosure.isLocalization [IsDomain A] [Algebra.IsAlgebraic K L] IsLocalization (Algebra.algebraMapSubmonoid C A⁰) L := by haveI : IsDomain C := (IsIntegralClosure.equiv A C L (integralClosure A L)).toMulEquiv.isDomain (integralClosure A L) - haveI : NoZeroSMulDivisors A L := NoZeroSMulDivisors.trans A K L + haveI : NoZeroSMulDivisors A L := NoZeroSMulDivisors.trans_faithfulSMul A K L haveI : NoZeroSMulDivisors A C := IsIntegralClosure.noZeroSMulDivisors A L refine ⟨?_, fun z => ?_, fun {x y} h => ⟨1, ?_⟩⟩ · rintro ⟨_, x, hx, rfl⟩ rw [isUnit_iff_ne_zero, map_ne_zero_iff _ (IsIntegralClosure.algebraMap_injective C A L), - Subtype.coe_mk, map_ne_zero_iff _ (NoZeroSMulDivisors.algebraMap_injective A C)] + Subtype.coe_mk, map_ne_zero_iff _ (FaithfulSMul.algebraMap_injective A C)] exact mem_nonZeroDivisors_iff_ne_zero.mp hx · obtain ⟨m, hm⟩ := IsIntegral.exists_multiple_integral_of_isLocalization A⁰ z diff --git a/Mathlib/RingTheory/DedekindDomain/PID.lean b/Mathlib/RingTheory/DedekindDomain/PID.lean index 960686d153fe9..393d049b6791e 100644 --- a/Mathlib/RingTheory/DedekindDomain/PID.lean +++ b/Mathlib/RingTheory/DedekindDomain/PID.lean @@ -200,7 +200,7 @@ theorem IsLocalization.OverPrime.mem_normalizedFactors_of_isPrime [IsDomain S] {P : Ideal Sₚ} (hP : IsPrime P) (hP0 : P ≠ ⊥) : P ∈ normalizedFactors (Ideal.map (algebraMap R Sₚ) p) := by have non_zero_div : Algebra.algebraMapSubmonoid S p.primeCompl ≤ S⁰ := - map_le_nonZeroDivisors_of_injective _ (NoZeroSMulDivisors.algebraMap_injective _ _) + map_le_nonZeroDivisors_of_injective _ (FaithfulSMul.algebraMap_injective _ _) p.primeCompl_le_nonZeroDivisors letI : Algebra (Localization.AtPrime p) Sₚ := localizationAlgebra p.primeCompl S haveI : IsScalarTower R (Localization.AtPrime p) Sₚ := @@ -233,7 +233,7 @@ theorem IsLocalization.OverPrime.mem_normalizedFactors_of_isPrime [IsDomain S] · assumption rw [IsScalarTower.algebraMap_eq R S Sₚ] exact - (IsLocalization.injective Sₚ non_zero_div).comp (NoZeroSMulDivisors.algebraMap_injective _ _) + (IsLocalization.injective Sₚ non_zero_div).comp (FaithfulSMul.algebraMap_injective _ _) /-- Let `p` be a prime in the Dedekind domain `R` and `S` be an integral extension of `R`, then the localization `Sₚ` of `S` at `p` is a PID. -/ diff --git a/Mathlib/RingTheory/DedekindDomain/SelmerGroup.lean b/Mathlib/RingTheory/DedekindDomain/SelmerGroup.lean index 95dc12c2a9341..63e7b60137c54 100644 --- a/Mathlib/RingTheory/DedekindDomain/SelmerGroup.lean +++ b/Mathlib/RingTheory/DedekindDomain/SelmerGroup.lean @@ -211,12 +211,12 @@ theorem fromUnit_ker [hn : Fact <| 0 < n] : rcases IsIntegrallyClosed.exists_algebraMap_eq_of_isIntegral_pow (R := R) (x := i) hn.out (hi.symm ▸ isIntegral_algebraMap) with ⟨i', rfl⟩ - rw [← map_mul, map_eq_one_iff _ <| NoZeroSMulDivisors.algebraMap_injective R K] at vi - rw [← map_mul, map_eq_one_iff _ <| NoZeroSMulDivisors.algebraMap_injective R K] at iv + rw [← map_mul, map_eq_one_iff _ <| FaithfulSMul.algebraMap_injective R K] at vi + rw [← map_mul, map_eq_one_iff _ <| FaithfulSMul.algebraMap_injective R K] at iv rw [Units.val_mk, ← map_pow] at hv exact ⟨⟨v', i', vi, iv⟩, by simpa only [Units.ext_iff, powMonoidHom_apply, Units.val_pow_eq_pow_val] using - NoZeroSMulDivisors.algebraMap_injective R K hv⟩ + FaithfulSMul.algebraMap_injective R K hv⟩ · rintro ⟨x, hx⟩ rw [← hx] exact Subtype.mk_eq_mk.mpr <| (QuotientGroup.eq_one_iff _).mpr ⟨Units.map (algebraMap R K) x, diff --git a/Mathlib/RingTheory/FractionalIdeal/Basic.lean b/Mathlib/RingTheory/FractionalIdeal/Basic.lean index 17d1057a60b9b..c508c05e3b406 100644 --- a/Mathlib/RingTheory/FractionalIdeal/Basic.lean +++ b/Mathlib/RingTheory/FractionalIdeal/Basic.lean @@ -132,7 +132,7 @@ noncomputable def equivNum [Nontrivial P] [NoZeroSMulDivisors R P] (LinearEquiv.ofBijective ((DistribMulAction.toLinearMap R P I.den).restrict fun _ hx ↦ ?_) ⟨fun _ _ hxy ↦ ?_, fun ⟨y, hy⟩ ↦ ?_⟩) (Submodule.equivMapOfInjective (Algebra.linearMap R P) - (NoZeroSMulDivisors.algebraMap_injective R P) (num I)).symm + (FaithfulSMul.algebraMap_injective R P) (num I)).symm · rw [← den_mul_self_eq_num] exact Submodule.smul_mem_pointwise_smul _ _ _ hx · simp_rw [LinearMap.restrict_apply, DistribMulAction.toLinearMap_apply, Subtype.mk.injEq] at hxy diff --git a/Mathlib/RingTheory/Ideal/Maps.lean b/Mathlib/RingTheory/Ideal/Maps.lean index 67dad3b20e060..4ef12677ebde3 100644 --- a/Mathlib/RingTheory/Ideal/Maps.lean +++ b/Mathlib/RingTheory/Ideal/Maps.lean @@ -903,7 +903,7 @@ variable [CommRing R] [CommRing S] theorem map_ne_bot_of_ne_bot {S : Type*} [Ring S] [Nontrivial S] [Algebra R S] [NoZeroSMulDivisors R S] {I : Ideal R} (h : I ≠ ⊥) : map (algebraMap R S) I ≠ ⊥ := - (map_eq_bot_iff_of_injective (NoZeroSMulDivisors.algebraMap_injective R S)).mp.mt h + (map_eq_bot_iff_of_injective (FaithfulSMul.algebraMap_injective R S)).mp.mt h theorem map_eq_iff_sup_ker_eq_of_surjective {I J : Ideal R} (f : R →+* S) (hf : Function.Surjective f) : map f I = map f J ↔ I ⊔ RingHom.ker f = J ⊔ RingHom.ker f := by @@ -1039,18 +1039,16 @@ def idealMap (I : Ideal R) : I →ₗ[R] I.map (algebraMap R S) := end Algebra -namespace NoZeroSMulDivisors - -theorem of_ker_algebraMap_eq_bot (R A : Type*) [CommRing R] [Semiring A] [Algebra R A] - [NoZeroDivisors A] (h : RingHom.ker (algebraMap R A) = ⊥) : NoZeroSMulDivisors R A := - of_algebraMap_injective ((RingHom.injective_iff_ker_eq_bot _).mpr h) +@[simp] +theorem FaithfulSMul.ker_algebraMap_eq_bot (R A : Type*) [CommSemiring R] [Semiring A] + [Algebra R A] [FaithfulSMul R A] : RingHom.ker (algebraMap R A) = ⊥ := by + ext; simp -theorem ker_algebraMap_eq_bot (R A : Type*) [CommSemiring R] [Semiring A] [Nontrivial A] - [Algebra R A] [NoZeroSMulDivisors R A] : RingHom.ker (algebraMap R A) = ⊥ := by - ext; simp [Algebra.algebraMap_eq_smul_one'] +@[deprecated (since := "2025-01-31")] +alias NoZeroSMulDivisors.iff_ker_algebraMap_eq_bot := FaithfulSMul.ker_algebraMap_eq_bot -theorem iff_ker_algebraMap_eq_bot {R A : Type*} [CommRing R] [Ring A] [IsDomain A] [Algebra R A] : - NoZeroSMulDivisors R A ↔ RingHom.ker (algebraMap R A) = ⊥ := - iff_algebraMap_injective.trans (RingHom.injective_iff_ker_eq_bot (algebraMap R A)) +@[deprecated (since := "2025-01-31")] +alias NoZeroSMulDivisors.of_ker_algebraMap_eq_bot := FaithfulSMul.ker_algebraMap_eq_bot -end NoZeroSMulDivisors +@[deprecated (since := "2025-01-31")] +alias NoZeroSMulDivisors.ker_algebraMap_eq_bot := FaithfulSMul.ker_algebraMap_eq_bot diff --git a/Mathlib/RingTheory/Ideal/Norm/RelNorm.lean b/Mathlib/RingTheory/Ideal/Norm/RelNorm.lean index 2dcc0e755445c..a650aa9e98e15 100644 --- a/Mathlib/RingTheory/Ideal/Norm/RelNorm.lean +++ b/Mathlib/RingTheory/Ideal/Norm/RelNorm.lean @@ -111,7 +111,7 @@ theorem spanIntNorm_localization (I : Ideal S) (M : Submonoid R) (hM : M ≤ R let g : Sₘ →+* L := IsLocalization.map _ (M := Algebra.algebraMapSubmonoid S M) (T := S⁰) (RingHom.id S) (Submonoid.map_le_of_le_comap _ <| hM.trans (nonZeroDivisors_le_comap_nonZeroDivisors_of_injective _ - (NoZeroSMulDivisors.algebraMap_injective _ _))) + (FaithfulSMul.algebraMap_injective _ _))) algebraize [f, g, (algebraMap K L).comp f] have : IsScalarTower R Rₘ K := IsScalarTower.of_algebraMap_eq' (by rw [RingHom.algebraMap_toAlgebra, IsLocalization.map_comp, RingHomCompTriple.comp_eq]) @@ -202,7 +202,7 @@ theorem spanNorm_mul (I J : Ideal S) : spanNorm R (I * J) = spanNorm R I * spanN IsScalarTower.of_algebraMap_eq (fun x => (IsLocalization.map_eq (T := P') (Q := Localization P') P.primeCompl.le_comap_map x).symm) have h : P' ≤ S⁰ := - map_le_nonZeroDivisors_of_injective _ (NoZeroSMulDivisors.algebraMap_injective _ _) + map_le_nonZeroDivisors_of_injective _ (FaithfulSMul.algebraMap_injective _ _) P.primeCompl_le_nonZeroDivisors have : IsDomain Sₚ := IsLocalization.isDomain_localization h have : IsDedekindDomain Sₚ := IsLocalization.isDedekindDomain S h _ diff --git a/Mathlib/RingTheory/Ideal/Over.lean b/Mathlib/RingTheory/Ideal/Over.lean index 48ef1022ba6d0..a48fdd2dbd260 100644 --- a/Mathlib/RingTheory/Ideal/Over.lean +++ b/Mathlib/RingTheory/Ideal/Over.lean @@ -541,7 +541,7 @@ variable (A : Type*) [CommRing A] (B : Type*) [Ring B] [Nontrivial B] @[simp] theorem under_bot : under A (⊥ : Ideal B) = ⊥ := - comap_bot_of_injective (algebraMap A B) (NoZeroSMulDivisors.algebraMap_injective A B) + comap_bot_of_injective (algebraMap A B) (FaithfulSMul.algebraMap_injective A B) instance bot_liesOver_bot : (⊥ : Ideal B).LiesOver (⊥ : Ideal A) where over := (under_bot A B).symm @@ -583,14 +583,15 @@ instance algebra_finiteType_of_liesOver [Algebra.FiniteType A B] : instance isNoetherian_of_liesOver [IsNoetherian A B] : IsNoetherian (A ⧸ p) (B ⧸ P) := isNoetherian_of_tower A inferInstance -theorem algebraMap_injective_of_liesOver : Function.Injective (algebraMap (A ⧸ p) (B ⧸ P)) := by +instance instFaithfulSMul : FaithfulSMul (A ⧸ p) (B ⧸ P) := by + rw [faithfulSMul_iff_algebraMap_injective] rintro ⟨a⟩ ⟨b⟩ hab apply Quotient.eq.mpr ((mem_of_liesOver P p (a - b)).mpr _) rw [RingHom.map_sub] exact Quotient.eq.mp hab -instance [P.IsPrime] : NoZeroSMulDivisors (A ⧸ p) (B ⧸ P) := - NoZeroSMulDivisors.of_algebraMap_injective (algebraMap_injective_of_liesOver P p) +@[deprecated (since := "2025-01-31")] +alias algebraMap_injective_of_liesOver := instFaithfulSMul variable {p} in theorem nontrivial_of_liesOver_of_ne_top (hp : p ≠ ⊤) : Nontrivial (B ⧸ P) := @@ -668,8 +669,7 @@ instance Quotient.algebra_isIntegral_of_liesOver : Algebra.IsIntegral (A ⧸ p) theorem exists_ideal_liesOver_maximal_of_isIntegral [p.IsMaximal] (B : Type*) [CommRing B] [Nontrivial B] [Algebra A B] [NoZeroSMulDivisors A B] [Algebra.IsIntegral A B] : ∃ P : Ideal B, P.IsMaximal ∧ P.LiesOver p := by - rcases exists_ideal_over_maximal_of_isIntegral p <| - (NoZeroSMulDivisors.ker_algebraMap_eq_bot A B).trans_le bot_le with ⟨P, hm, hP⟩ + obtain ⟨P, hm, hP⟩ := exists_ideal_over_maximal_of_isIntegral (S := B) p <| by simp exact ⟨P, hm, ⟨hP.symm⟩⟩ end IsIntegral diff --git a/Mathlib/RingTheory/IntegralClosure/IntegralRestrict.lean b/Mathlib/RingTheory/IntegralClosure/IntegralRestrict.lean index b820b75229efd..63f417f2adbe5 100644 --- a/Mathlib/RingTheory/IntegralClosure/IntegralRestrict.lean +++ b/Mathlib/RingTheory/IntegralClosure/IntegralRestrict.lean @@ -39,13 +39,13 @@ This is inverse to the restriction. See `galRestrictHom`. -/ noncomputable def galLift (σ : B →ₐ[A] B) : L →ₐ[K] L := haveI := (IsFractionRing.injective A K).isDomain - haveI := NoZeroSMulDivisors.trans A K L + haveI := NoZeroSMulDivisors.trans_faithfulSMul A K L haveI := IsIntegralClosure.isLocalization A K L B haveI H : ∀ (y : Algebra.algebraMapSubmonoid B A⁰), IsUnit (((algebraMap B L).comp σ) (y : B)) := by rintro ⟨_, x, hx, rfl⟩ simpa only [RingHom.coe_comp, RingHom.coe_coe, Function.comp_apply, AlgHom.commutes, - isUnit_iff_ne_zero, ne_eq, map_eq_zero_iff _ (NoZeroSMulDivisors.algebraMap_injective _ _), + isUnit_iff_ne_zero, ne_eq, map_eq_zero_iff _ (FaithfulSMul.algebraMap_injective _ _), ← IsScalarTower.algebraMap_apply] using nonZeroDivisors.ne_zero hx haveI H_eq : (IsLocalization.lift (S := L) H).comp (algebraMap K L) = (algebraMap K L) := by apply IsLocalization.ringHom_ext A⁰ diff --git a/Mathlib/RingTheory/IntegralClosure/IntegrallyClosed.lean b/Mathlib/RingTheory/IntegralClosure/IntegrallyClosed.lean index 42fff4d0e0234..f567814549c9d 100644 --- a/Mathlib/RingTheory/IntegralClosure/IntegrallyClosed.lean +++ b/Mathlib/RingTheory/IntegralClosure/IntegrallyClosed.lean @@ -165,7 +165,7 @@ variable (R) @[simp] theorem integralClosure_eq_bot [IsIntegrallyClosedIn R A] [NoZeroSMulDivisors R A] [Nontrivial A] : integralClosure R A = ⊥ := - (integralClosure_eq_bot_iff A (NoZeroSMulDivisors.algebraMap_injective _ _)).mpr ‹_› + (integralClosure_eq_bot_iff A (FaithfulSMul.algebraMap_injective _ _)).mpr ‹_› variable {A} {B : Type*} [CommRing B] diff --git a/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean b/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean index ff4bf59739f94..abfec7850aa3d 100644 --- a/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean +++ b/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean @@ -551,7 +551,7 @@ theorem Algebra.IsIntegral.tower_bot [Algebra R S] [Algebra R T] [Algebra S T] [h : Algebra.IsIntegral R T] : Algebra.IsIntegral R S where isIntegral := by apply RingHom.IsIntegral.tower_bot (algebraMap R S) (algebraMap S T) - (NoZeroSMulDivisors.algebraMap_injective S T) + (FaithfulSMul.algebraMap_injective S T) rw [← IsScalarTower.algebraMap_eq R S T] exact h.isIntegral diff --git a/Mathlib/RingTheory/Invariant.lean b/Mathlib/RingTheory/Invariant.lean index fe8623572f750..1da0a8bb04211 100644 --- a/Mathlib/RingTheory/Invariant.lean +++ b/Mathlib/RingTheory/Invariant.lean @@ -72,11 +72,11 @@ theorem Algebra.isInvariant_of_isGalois [FiniteDimensional K L] [h : IsGalois K rw [h, IntermediateField.mem_bot] at hb obtain ⟨k, hk⟩ := hb have hb : IsIntegral A b := IsIntegralClosure.isIntegral A L b - rw [← isIntegral_algebraMap_iff (NoZeroSMulDivisors.algebraMap_injective B L), ← hk, - isIntegral_algebraMap_iff (NoZeroSMulDivisors.algebraMap_injective K L)] at hb + rw [← isIntegral_algebraMap_iff (FaithfulSMul.algebraMap_injective B L), ← hk, + isIntegral_algebraMap_iff (FaithfulSMul.algebraMap_injective K L)] at hb obtain ⟨a, rfl⟩ := IsIntegrallyClosed.algebraMap_eq_of_integral hb rw [← IsScalarTower.algebraMap_apply, IsScalarTower.algebraMap_apply A B L, - (NoZeroSMulDivisors.algebraMap_injective B L).eq_iff] at hk + (FaithfulSMul.algebraMap_injective B L).eq_iff] at hk exact ⟨a, hk⟩ end Galois @@ -163,7 +163,7 @@ end transitivity section surjectivity -open IsScalarTower NoZeroSMulDivisors Polynomial +open FaithfulSMul IsScalarTower Polynomial variable {A B : Type*} [CommRing A] [CommRing B] [Algebra A B] (G : Type*) [Group G] [Finite G] [MulSemiringAction G B] [SMulCommClass G A B] diff --git a/Mathlib/RingTheory/LocalProperties/IntegrallyClosed.lean b/Mathlib/RingTheory/LocalProperties/IntegrallyClosed.lean index 3753f3c70b5be..bb0b3fd60f8d2 100644 --- a/Mathlib/RingTheory/LocalProperties/IntegrallyClosed.lean +++ b/Mathlib/RingTheory/LocalProperties/IntegrallyClosed.lean @@ -54,7 +54,7 @@ theorem IsIntegrallyClosed.of_localization_maximal {R : Type*} [CommRing R] [IsD apply mem_span_singleton'.mpr ⟨b * y.1, _⟩ rw [← hb, ← mul_assoc, mul_comm y.2.1 b, mul_assoc, mul_assoc] exact congrArg (HMul.hMul b) <| (mul_comm y.1 x.2.1).trans <| - NoZeroSMulDivisors.algebraMap_injective R (Localization R⁰) <| mk'_eq_iff_eq.mp <| + FaithfulSMul.algebraMap_injective R (Localization R⁰) <| mk'_eq_iff_eq.mp <| (mk'_eq_algebraMap_mk'_of_submonoid_le _ _ p.primeCompl_le_nonZeroDivisors y.1 y.2).trans <| show algebraMap (Localization.AtPrime p) _ (mk' _ y.1 y.2) = mk' _ x.1 x.2 by simpa only [← mk_eq_mk', ← hy] using by rfl diff --git a/Mathlib/RingTheory/Localization/FractionRing.lean b/Mathlib/RingTheory/Localization/FractionRing.lean index 309f147722deb..3fc7f9b8d2bd8 100644 --- a/Mathlib/RingTheory/Localization/FractionRing.lean +++ b/Mathlib/RingTheory/Localization/FractionRing.lean @@ -81,6 +81,9 @@ variable (R K) protected theorem injective : Function.Injective (algebraMap R K) := IsLocalization.injective _ (le_of_eq rfl) +instance (priority := 100) : FaithfulSMul R K := + (faithfulSMul_iff_algebraMap_injective R K).mpr <| IsFractionRing.injective R K + variable {R K} @[norm_cast, simp] @@ -88,9 +91,6 @@ variable {R K} theorem coe_inj {a b : R} : (Algebra.cast a : K) = Algebra.cast b ↔ a = b := (IsFractionRing.injective R K).eq_iff -instance (priority := 100) [NoZeroDivisors K] : NoZeroSMulDivisors R K := - NoZeroSMulDivisors.of_algebraMap_injective <| IsFractionRing.injective R K - protected theorem to_map_ne_zero_of_mem_nonZeroDivisors [Nontrivial R] {x : R} (hx : x ∈ nonZeroDivisors R) : algebraMap R K x ≠ 0 := IsLocalization.to_map_ne_zero_of_mem_nonZeroDivisors _ le_rfl hx @@ -468,10 +468,14 @@ theorem algebraMap_injective_of_field_isFractionRing (K L : Type*) [Field K] [Se rw [← RingHom.coe_comp, ← IsScalarTower.algebraMap_eq, IsScalarTower.algebraMap_eq R K L] exact (algebraMap K L).injective.comp (IsFractionRing.injective R K) -theorem NoZeroSMulDivisors.of_field_isFractionRing [NoZeroDivisors S] (K L : Type*) [Field K] - [Semiring L] [Nontrivial L] [Algebra R K] [IsFractionRing R K] [Algebra S L] [Algebra K L] - [Algebra R L] [IsScalarTower R S L] [IsScalarTower R K L] : NoZeroSMulDivisors R S := - of_algebraMap_injective (algebraMap_injective_of_field_isFractionRing R S K L) +theorem FaithfulSMul.of_field_isFractionRing (K L : Type*) [Field K] [Semiring L] + [Nontrivial L] [Algebra R K] [IsFractionRing R K] [Algebra S L] [Algebra K L] [Algebra R L] + [IsScalarTower R S L] [IsScalarTower R K L] : FaithfulSMul R S := + (faithfulSMul_iff_algebraMap_injective R S).mpr <| + algebraMap_injective_of_field_isFractionRing R S K L + +@[deprecated (since := "2025-01-31")] +alias NoZeroSMulDivisors.of_field_isFractionRing := FaithfulSMul.of_field_isFractionRing end algebraMap_injective @@ -509,15 +513,15 @@ theorem mk_eq_div {r s} : Should usually be introduced locally along with `isScalarTower_liftAlgebra` See note [reducible non-instances]. -/ noncomputable abbrev liftAlgebra [IsDomain R] [Field K] [Algebra R K] - [NoZeroSMulDivisors R K] : Algebra (FractionRing R) K := - RingHom.toAlgebra (IsFractionRing.lift (NoZeroSMulDivisors.algebraMap_injective R _)) + [FaithfulSMul R K] : Algebra (FractionRing R) K := + RingHom.toAlgebra (IsFractionRing.lift (FaithfulSMul.algebraMap_injective R _)) -- Porting note: had to fill in the `_` by hand for this instance -instance isScalarTower_liftAlgebra [IsDomain R] [Field K] [Algebra R K] [NoZeroSMulDivisors R K] : +instance isScalarTower_liftAlgebra [IsDomain R] [Field K] [Algebra R K] [FaithfulSMul R K] : by letI := liftAlgebra R K; exact IsScalarTower R (FractionRing R) K := by letI := liftAlgebra R K exact IsScalarTower.of_algebraMap_eq fun x => - (IsFractionRing.lift_algebraMap (NoZeroSMulDivisors.algebraMap_injective R K) x).symm + (IsFractionRing.lift_algebraMap (FaithfulSMul.algebraMap_injective R K) x).symm /-- Given a ring `A` and a localization map to a fraction ring `f : A →+* K`, we get an `A`-isomorphism between the fraction ring of `A` as a quotient @@ -526,10 +530,9 @@ noncomputable def algEquiv (K : Type*) [CommRing K] [Algebra A K] [IsFractionRin FractionRing A ≃ₐ[A] K := Localization.algEquiv (nonZeroDivisors A) K -instance [Algebra R A] [NoZeroSMulDivisors R A] : NoZeroSMulDivisors R (FractionRing A) := by - apply NoZeroSMulDivisors.of_algebraMap_injective - rw [IsScalarTower.algebraMap_eq R A] - apply Function.Injective.comp (NoZeroSMulDivisors.algebraMap_injective A (FractionRing A)) - (NoZeroSMulDivisors.algebraMap_injective R A) +instance [Algebra R A] [FaithfulSMul R A] : FaithfulSMul R (FractionRing A) := by + rw [faithfulSMul_iff_algebraMap_injective, IsScalarTower.algebraMap_eq R A] + exact (FaithfulSMul.algebraMap_injective A (FractionRing A)).comp + (FaithfulSMul.algebraMap_injective R A) end FractionRing diff --git a/Mathlib/RingTheory/Localization/Ideal.lean b/Mathlib/RingTheory/Localization/Ideal.lean index d96fa14d7d23e..17ab0c536c1ad 100644 --- a/Mathlib/RingTheory/Localization/Ideal.lean +++ b/Mathlib/RingTheory/Localization/Ideal.lean @@ -263,7 +263,7 @@ lemma _root_.NoZeroSMulDivisors_of_isLocalization (Rₚ Sₚ : Type*) [CommRing have e : Algebra.algebraMapSubmonoid S M ≤ S⁰ := Submonoid.map_le_of_le_comap _ <| hM.trans (nonZeroDivisors_le_comap_nonZeroDivisors_of_injective _ - (NoZeroSMulDivisors.algebraMap_injective _ _)) + (FaithfulSMul.algebraMap_injective _ _)) have : IsDomain Sₚ := IsLocalization.isDomain_of_le_nonZeroDivisors S e have : algebraMap Rₚ Sₚ = IsLocalization.map (T := Algebra.algebraMapSubmonoid S M) Sₚ (algebraMap R S) (Submonoid.le_comap_map M) := by @@ -277,7 +277,7 @@ lemma _root_.NoZeroSMulDivisors_of_isLocalization (Rₚ Sₚ : Type*) [CommRing Subtype.exists, exists_prop, this] at hx ⊢ obtain ⟨_, ⟨a, ha, rfl⟩, H⟩ := hx simp only [← _root_.map_mul, - (injective_iff_map_eq_zero' _).mp (NoZeroSMulDivisors.algebraMap_injective R S)] at H + (injective_iff_map_eq_zero' _).mp (FaithfulSMul.algebraMap_injective R S)] at H exact ⟨a, ha, H⟩ end CommRing diff --git a/Mathlib/RingTheory/Localization/Integral.lean b/Mathlib/RingTheory/Localization/Integral.lean index 5e9059d15096e..abf87d3d9d06d 100644 --- a/Mathlib/RingTheory/Localization/Integral.lean +++ b/Mathlib/RingTheory/Localization/Integral.lean @@ -364,14 +364,14 @@ theorem isAlgebraic_iff' [Field K] [IsDomain R] [IsDomain S] [Algebra R K] [Alge refine IsIntegral.mul ?_ ?_ · rw [← isAlgebraic_iff_isIntegral] refine .extendScalars - (NoZeroSMulDivisors.algebraMap_injective R (FractionRing R)) ?_ + (FaithfulSMul.algebraMap_injective R (FractionRing R)) ?_ exact .algebraMap (h a) · rw [← isAlgebraic_iff_isIntegral] use (f.map (algebraMap R (FractionRing R))).reverse constructor · rwa [Ne, Polynomial.reverse_eq_zero, ← Polynomial.degree_eq_bot, Polynomial.degree_map_eq_of_injective - (NoZeroSMulDivisors.algebraMap_injective R (FractionRing R)), + (FaithfulSMul.algebraMap_injective R (FractionRing R)), Polynomial.degree_eq_bot] · have : Invertible (algebraMap S K b) := IsUnit.invertible @@ -379,7 +379,7 @@ theorem isAlgebraic_iff' [Field K] [IsDomain R] [IsDomain S] [Algebra R K] [Alge (mem_nonZeroDivisors_iff_ne_zero.2 fun h => nonZeroDivisors.ne_zero ha ((injective_iff_map_eq_zero (algebraMap S K)).1 - (NoZeroSMulDivisors.algebraMap_injective _ _) b h))) + (FaithfulSMul.algebraMap_injective _ _) b h))) rw [Polynomial.aeval_def, ← invOf_eq_inv, Polynomial.eval₂_reverse_eq_zero_iff, Polynomial.eval₂_map, ← IsScalarTower.algebraMap_eq, ← Polynomial.aeval_def, Polynomial.aeval_algebraMap_apply, hf₂, RingHom.map_zero] @@ -388,7 +388,7 @@ theorem isAlgebraic_iff' [Field K] [IsDomain R] [IsDomain S] [Algebra R K] [Alge use f, hf₁ rw [Polynomial.aeval_algebraMap_apply] at hf₂ exact - (injective_iff_map_eq_zero (algebraMap S K)).1 (NoZeroSMulDivisors.algebraMap_injective _ _) _ + (injective_iff_map_eq_zero (algebraMap S K)).1 (FaithfulSMul.algebraMap_injective _ _) _ hf₂ open nonZeroDivisors diff --git a/Mathlib/RingTheory/Localization/NumDen.lean b/Mathlib/RingTheory/Localization/NumDen.lean index 4b94d345d32e9..44d30a02b6e6e 100644 --- a/Mathlib/RingTheory/Localization/NumDen.lean +++ b/Mathlib/RingTheory/Localization/NumDen.lean @@ -85,9 +85,9 @@ lemma num_zero : IsFractionRing.num A (0 : K) = 0 := by have := mk'_num_den' A (0 : K) simp only [div_eq_zero_iff] at this rcases this with h | h - · exact NoZeroSMulDivisors.algebraMap_injective A K (by convert h; simp) + · exact FaithfulSMul.algebraMap_injective A K (by convert h; simp) · replace h : algebraMap A K (den A (0 : K)) = algebraMap A K 0 := by convert h; simp - absurd NoZeroSMulDivisors.algebraMap_injective A K h + absurd FaithfulSMul.algebraMap_injective A K h apply nonZeroDivisors.coe_ne_zero @[simp] @@ -116,8 +116,8 @@ theorem isUnit_den_iff (x : K) : IsUnit (den A x : A) ↔ IsLocalization.IsInteg · simp only [mk'_num_den'] intro h replace h : algebraMap A K (den A x : A) = algebraMap A K 0 := by convert h; simp - exact nonZeroDivisors.coe_ne_zero _ <| NoZeroSMulDivisors.algebraMap_injective A K h - exact NoZeroSMulDivisors.algebraMap_injective A K + exact nonZeroDivisors.coe_ne_zero _ <| FaithfulSMul.algebraMap_injective A K h + exact FaithfulSMul.algebraMap_injective A K theorem isUnit_den_zero : IsUnit (den A (0 : K) : A) := by simp [isUnit_den_iff, IsLocalization.isInteger_zero] @@ -126,11 +126,11 @@ lemma associated_den_num_inv (x : K) (hx : x ≠ 0) : Associated (den A x : A) ( associated_of_dvd_dvd (IsRelPrime.dvd_of_dvd_mul_right (IsFractionRing.num_den_reduced A x).symm <| dvd_of_mul_left_dvd (a := (den A x⁻¹ : A)) <| dvd_of_eq <| - NoZeroSMulDivisors.algebraMap_injective A K <| Eq.symm <| eq_of_div_eq_one + FaithfulSMul.algebraMap_injective A K <| Eq.symm <| eq_of_div_eq_one (by simp [mul_div_mul_comm, hx])) (IsRelPrime.dvd_of_dvd_mul_right (IsFractionRing.num_den_reduced A x⁻¹) <| dvd_of_mul_left_dvd (a := (num A x : A)) <| dvd_of_eq <| - NoZeroSMulDivisors.algebraMap_injective A K <| eq_of_div_eq_one + FaithfulSMul.algebraMap_injective A K <| eq_of_div_eq_one (by simp [mul_div_mul_comm, hx])) lemma associated_num_den_inv (x : K) (hx : x ≠ 0) : Associated (num A x : A) (den A x⁻¹) := by diff --git a/Mathlib/RingTheory/Norm/Basic.lean b/Mathlib/RingTheory/Norm/Basic.lean index 77ed251d0b111..2b04897d0af56 100644 --- a/Mathlib/RingTheory/Norm/Basic.lean +++ b/Mathlib/RingTheory/Norm/Basic.lean @@ -230,7 +230,7 @@ theorem norm_eq_prod_embeddings [FiniteDimensional K L] [Algebra.IsSeparable K L theorem norm_eq_prod_automorphisms [FiniteDimensional K L] [IsGalois K L] (x : L) : algebraMap K L (norm K x) = ∏ σ : L ≃ₐ[K] L, σ x := by - apply NoZeroSMulDivisors.algebraMap_injective L (AlgebraicClosure L) + apply FaithfulSMul.algebraMap_injective L (AlgebraicClosure L) rw [map_prod (algebraMap L (AlgebraicClosure L))] rw [← Fintype.prod_equiv (Normal.algHomEquivAut K (AlgebraicClosure L) L)] · rw [← norm_eq_prod_embeddings _ _ x, ← IsScalarTower.algebraMap_apply] diff --git a/Mathlib/RingTheory/Polynomial/Content.lean b/Mathlib/RingTheory/Polynomial/Content.lean index 394d392597e7b..003050fdd07b2 100644 --- a/Mathlib/RingTheory/Polynomial/Content.lean +++ b/Mathlib/RingTheory/Polynomial/Content.lean @@ -264,7 +264,7 @@ theorem aeval_primPart_eq_zero {S : Type*} [Ring S] [IsDomain S] [Algebra R S] aeval s p.primPart = 0 := by rw [eq_C_content_mul_primPart p, map_mul, aeval_C] at hp have hcont : p.content ≠ 0 := fun h => hpzero (content_eq_zero_iff.1 h) - replace hcont := Function.Injective.ne (NoZeroSMulDivisors.algebraMap_injective R S) hcont + replace hcont := Function.Injective.ne (FaithfulSMul.algebraMap_injective R S) hcont rw [map_zero] at hcont exact eq_zero_of_ne_zero_of_mul_left_eq_zero hcont hp diff --git a/Mathlib/RingTheory/Polynomial/Cyclotomic/Basic.lean b/Mathlib/RingTheory/Polynomial/Cyclotomic/Basic.lean index 198c98c81527b..fd90e039de176 100644 --- a/Mathlib/RingTheory/Polynomial/Cyclotomic/Basic.lean +++ b/Mathlib/RingTheory/Polynomial/Cyclotomic/Basic.lean @@ -616,17 +616,17 @@ where `μ` varies over the `n`-th roots of unity. -/ theorem _root_.IsPrimitiveRoot.pow_sub_pow_eq_prod_sub_mul (hpos : 0 < n) (h : IsPrimitiveRoot ζ n) : x ^ n - y ^ n = ∏ ζ ∈ nthRootsFinset n R, (x - ζ * y) := by let K := FractionRing R - apply NoZeroSMulDivisors.algebraMap_injective R K + apply FaithfulSMul.algebraMap_injective R K rw [map_sub, map_pow, map_pow, map_prod] simp_rw [map_sub, map_mul] have h' : IsPrimitiveRoot (algebraMap R K ζ) n := - h.map_of_injective <| NoZeroSMulDivisors.algebraMap_injective R K + h.map_of_injective <| FaithfulSMul.algebraMap_injective R K rw [h'.pow_sub_pow_eq_prod_sub_mul_field _ _ hpos] refine (prod_nbij (algebraMap R K) (fun a ha ↦ map_mem_nthRootsFinset ha _) (fun a _ b _ H ↦ - NoZeroSMulDivisors.algebraMap_injective R K H) (fun a ha ↦ ?_) (fun _ _ ↦ rfl)).symm + FaithfulSMul.algebraMap_injective R K H) (fun a ha ↦ ?_) (fun _ _ ↦ rfl)).symm have := Set.surj_on_of_inj_on_of_ncard_le (s := nthRootsFinset n R) (t := nthRootsFinset n K) _ (fun _ hr ↦ map_mem_nthRootsFinset hr _) - (fun a _ b _ H ↦ NoZeroSMulDivisors.algebraMap_injective R K H) + (fun a _ b _ H ↦ FaithfulSMul.algebraMap_injective R K H) (by simp [h.card_nthRootsFinset, h'.card_nthRootsFinset]) obtain ⟨x, hx, hx1⟩ := this _ ha exact ⟨x, hx, hx1.symm⟩ diff --git a/Mathlib/RingTheory/Polynomial/Cyclotomic/Roots.lean b/Mathlib/RingTheory/Polynomial/Cyclotomic/Roots.lean index 74c4705dddc41..e82cfc397703d 100644 --- a/Mathlib/RingTheory/Polynomial/Cyclotomic/Roots.lean +++ b/Mathlib/RingTheory/Polynomial/Cyclotomic/Roots.lean @@ -163,7 +163,7 @@ open IsPrimitiveRoot Complex theorem _root_.IsPrimitiveRoot.minpoly_eq_cyclotomic_of_irreducible {K : Type*} [Field K] {R : Type*} [CommRing R] [IsDomain R] {μ : R} {n : ℕ} [Algebra K R] (hμ : IsPrimitiveRoot μ n) (h : Irreducible <| cyclotomic n K) [NeZero (n : K)] : cyclotomic n K = minpoly K μ := by - haveI := NeZero.of_noZeroSMulDivisors K R n + haveI := NeZero.of_faithfulSMul K R n refine minpoly.eq_of_irreducible_of_monic h ?_ (cyclotomic.monic n K) rwa [aeval_def, eval₂_eq_eval_map, map_cyclotomic, ← IsRoot.def, isRoot_cyclotomic_iff] diff --git a/Mathlib/RingTheory/Polynomial/Eisenstein/Basic.lean b/Mathlib/RingTheory/Polynomial/Eisenstein/Basic.lean index a1e63fad9a328..e5bb59e900c6a 100644 --- a/Mathlib/RingTheory/Polynomial/Eisenstein/Basic.lean +++ b/Mathlib/RingTheory/Polynomial/Eisenstein/Basic.lean @@ -173,7 +173,7 @@ theorem dvd_pow_natDegree_of_eval₂_eq_zero {f : R →+* A} (hf : Function.Inje theorem dvd_pow_natDegree_of_aeval_eq_zero [Algebra R A] [Nontrivial A] [NoZeroSMulDivisors R A] {p : R[X]} (hp : p.Monic) (x y : R) (z : A) (h : Polynomial.aeval z p = 0) (hz : z * algebraMap R A x = algebraMap R A y) : x ∣ y ^ p.natDegree := - dvd_pow_natDegree_of_eval₂_eq_zero (NoZeroSMulDivisors.algebraMap_injective R A) hp x y z h + dvd_pow_natDegree_of_eval₂_eq_zero (FaithfulSMul.algebraMap_injective R A) hp x y z h ((mul_comm _ _).trans hz) end ScaleRoots diff --git a/Mathlib/RingTheory/Polynomial/Eisenstein/IsIntegral.lean b/Mathlib/RingTheory/Polynomial/Eisenstein/IsIntegral.lean index ca5b849f7101c..b72c8d4e3eee8 100644 --- a/Mathlib/RingTheory/Polynomial/Eisenstein/IsIntegral.lean +++ b/Mathlib/RingTheory/Polynomial/Eisenstein/IsIntegral.lean @@ -238,7 +238,7 @@ theorem mem_adjoin_of_smul_prime_smul_of_minpoly_isEisensteinAt {B : PowerBasis have := B.finite set P := minpoly R B.gen with hP obtain ⟨n, hn⟩ := Nat.exists_eq_succ_of_ne_zero B.dim_pos.ne' - haveI : NoZeroSMulDivisors R L := NoZeroSMulDivisors.trans R K L + haveI : NoZeroSMulDivisors R L := NoZeroSMulDivisors.trans_faithfulSMul R K L let _ := P.map (algebraMap R L) -- There is a polynomial `Q` such that `p • z = aeval B.gen Q`. We can assume that -- `Q.degree < P.degree` and `Q ≠ 0`. diff --git a/Mathlib/RingTheory/Trace/Basic.lean b/Mathlib/RingTheory/Trace/Basic.lean index 5b322e66a5a7b..849dcdfa2234c 100644 --- a/Mathlib/RingTheory/Trace/Basic.lean +++ b/Mathlib/RingTheory/Trace/Basic.lean @@ -263,7 +263,7 @@ theorem trace_eq_sum_embeddings [FiniteDimensional K L] [Algebra.IsSeparable K L theorem trace_eq_sum_automorphisms (x : L) [FiniteDimensional K L] [IsGalois K L] : algebraMap K L (Algebra.trace K L x) = ∑ σ : L ≃ₐ[K] L, σ x := by - apply NoZeroSMulDivisors.algebraMap_injective L (AlgebraicClosure L) + apply FaithfulSMul.algebraMap_injective L (AlgebraicClosure L) rw [_root_.map_sum (algebraMap L (AlgebraicClosure L))] rw [← Fintype.sum_equiv (Normal.algHomEquivAut K (AlgebraicClosure L) L)] · rw [← trace_eq_sum_embeddings (AlgebraicClosure L) (x := x)] diff --git a/Mathlib/RingTheory/Trace/Quotient.lean b/Mathlib/RingTheory/Trace/Quotient.lean index 2ab1cd6fe80de..54bb340675a08 100644 --- a/Mathlib/RingTheory/Trace/Quotient.lean +++ b/Mathlib/RingTheory/Trace/Quotient.lean @@ -200,7 +200,7 @@ lemma Algebra.trace_quotient_eq_of_isDedekindDomain (x) [IsDedekindDomain R] [Is have e : Algebra.algebraMapSubmonoid S p.primeCompl ≤ S⁰ := Submonoid.map_le_of_le_comap _ <| p.primeCompl_le_nonZeroDivisors.trans (nonZeroDivisors_le_comap_nonZeroDivisors_of_injective _ - (NoZeroSMulDivisors.algebraMap_injective _ _)) + (FaithfulSMul.algebraMap_injective _ _)) haveI : IsDomain Sₚ := IsLocalization.isDomain_of_le_nonZeroDivisors S e haveI : NoZeroSMulDivisors Rₚ Sₚ := by rw [NoZeroSMulDivisors.iff_algebraMap_injective, RingHom.injective_iff_ker_eq_bot, @@ -210,7 +210,7 @@ lemma Algebra.trace_quotient_eq_of_isDedekindDomain (x) [IsDedekindDomain R] [Is simp only [Sₚ, RingHom.algebraMap_toAlgebra, IsLocalization.map_mk', IsLocalization.mk'_eq_zero_iff, mul_eq_zero, Subtype.exists, exists_prop] at hx ⊢ obtain ⟨_, ⟨a, ha, rfl⟩, H⟩ := hx - simp only [(injective_iff_map_eq_zero' _).mp (NoZeroSMulDivisors.algebraMap_injective R S)] at H + simp only [(injective_iff_map_eq_zero' _).mp (FaithfulSMul.algebraMap_injective R S)] at H refine ⟨a, ha, H⟩ haveI : Module.Finite Rₚ Sₚ := Module.Finite_of_isLocalization R S _ _ p.primeCompl haveI : IsIntegrallyClosed Sₚ := isIntegrallyClosed_of_isLocalization _ _ e diff --git a/Mathlib/RingTheory/Valuation/AlgebraInstances.lean b/Mathlib/RingTheory/Valuation/AlgebraInstances.lean index 91ff35d526b16..58b8aafadc579 100644 --- a/Mathlib/RingTheory/Valuation/AlgebraInstances.lean +++ b/Mathlib/RingTheory/Valuation/AlgebraInstances.lean @@ -35,7 +35,7 @@ namespace ValuationSubring instance : Algebra v.valuationSubring L := Algebra.ofSubring v.valuationSubring.toSubring theorem algebraMap_injective : Injective (algebraMap v.valuationSubring L) := - (NoZeroSMulDivisors.algebraMap_injective K L).comp (IsFractionRing.injective _ _) + (FaithfulSMul.algebraMap_injective K L).comp (IsFractionRing.injective _ _) theorem isIntegral_of_mem_ringOfIntegers {x : L} (hx : x ∈ integralClosure v.valuationSubring L) : IsIntegral v.valuationSubring (⟨x, hx⟩ : integralClosure v.valuationSubring L) := by diff --git a/Mathlib/RingTheory/Valuation/LocalSubring.lean b/Mathlib/RingTheory/Valuation/LocalSubring.lean index ac0c4253b0f3e..ee34567001f69 100644 --- a/Mathlib/RingTheory/Valuation/LocalSubring.lean +++ b/Mathlib/RingTheory/Valuation/LocalSubring.lean @@ -54,8 +54,9 @@ lemma LocalSubring.mem_of_isMax_of_isIntegral {R : LocalSubring K} (hR : IsMax R) {x : K} (hx : IsIntegral R.toSubring x) : x ∈ R.toSubring := by let S := Algebra.adjoin R.toSubring {x} have : Algebra.IsIntegral R.toSubring S := Algebra.IsIntegral.adjoin (by simpa) + have : FaithfulSMul R.toSubring S := NoZeroSMulDivisors.instFaithfulSMulOfNontrivial obtain ⟨Q : Ideal S.toSubring, hQ, e⟩ := Ideal.exists_ideal_over_maximal_of_isIntegral - (R := R.toSubring) (S := S) (maximalIdeal _) (le_maximalIdeal (by simp [Ideal.eq_top_iff_one])) + (R := R.toSubring) (S := S) (maximalIdeal _) (le_maximalIdeal (by simp)) have : R = .ofPrime S.toSubring Q := by have hRS : R.toSubring ≤ S.toSubring := fun r hr ↦ algebraMap_mem S ⟨r, hr⟩ apply hR.eq_of_le ⟨hRS.trans (LocalSubring.le_ofPrime _ _), ⟨?_⟩⟩ diff --git a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean index 46fa435868f93..e3d1356d4a232 100644 --- a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean +++ b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean @@ -8,7 +8,6 @@ import Mathlib.LinearAlgebra.FreeModule.Finite.Matrix import Mathlib.Topology.Algebra.Module.Simple import Mathlib.Topology.Algebra.Module.Determinant import Mathlib.RingTheory.LocalRing.Basic -import Mathlib.RingTheory.Localization.FractionRing /-! # Finite dimensional topological vector spaces over complete fields From 04dabcff0c28847261c631ce60028d4fe037e8b4 Mon Sep 17 00:00:00 2001 From: Johan Commelin Date: Mon, 3 Feb 2025 15:02:23 +0000 Subject: [PATCH 037/103] chore: bump toolchain to v4.16.0 (#21365) --- lake-manifest.json | 16 ++++++++-------- lakefile.lean | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lake-manifest.json b/lake-manifest.json index 66930a3e30c7a..029c55215aa62 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -5,10 +5,10 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "1622a8693b31523c8f82db48e01b14c74bc1f155", + "rev": "e104724db91693a3a088c5fdd76cff4fac331739", "name": "plausible", "manifestFile": "lake-manifest.json", - "inputRev": "v4.16.0-rc1", + "inputRev": "main", "inherited": false, "configFile": "lakefile.toml"}, {"url": "https://github.com/leanprover-community/LeanSearchClient", @@ -35,30 +35,30 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "07f60e90998dfd6592688a14cd67bd4e384b77b2", + "rev": "dafff53912eac07a1a983080df61df10f622fe25", "name": "proofwidgets", "manifestFile": "lake-manifest.json", - "inputRev": "v0.0.50", + "inputRev": "main", "inherited": false, "configFile": "lakefile.lean"}, {"url": "https://github.com/leanprover-community/aesop", "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "79402ad9ab4be9a2286701a9880697e2351e4955", + "rev": "44dab9f36aa73d5f789629b55528c5a1501877a6", "name": "aesop", "manifestFile": "lake-manifest.json", - "inputRev": "v4.16.0-rc1", + "inputRev": "master", "inherited": false, "configFile": "lakefile.toml"}, {"url": "https://github.com/leanprover-community/quote4", "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "f0c584bcb14c5adfb53079781eeea75b26ebbd32", + "rev": "b1311119f5f7c79c818d3e06621cc81f4bb8973f", "name": "Qq", "manifestFile": "lake-manifest.json", - "inputRev": "v4.15.0", + "inputRev": "master", "inherited": false, "configFile": "lakefile.toml"}, {"url": "https://github.com/leanprover-community/batteries", diff --git a/lakefile.lean b/lakefile.lean index 90f9004561b01..d465b3738a9bd 100644 --- a/lakefile.lean +++ b/lakefile.lean @@ -8,12 +8,12 @@ open Lake DSL -/ require "leanprover-community" / "batteries" @ git "main" -require "leanprover-community" / "Qq" @ git "v4.15.0" -require "leanprover-community" / "aesop" @ git "v4.16.0-rc1" -require "leanprover-community" / "proofwidgets" @ git "v0.0.50" +require "leanprover-community" / "Qq" @ git "master" +require "leanprover-community" / "aesop" @ git "master" +require "leanprover-community" / "proofwidgets" @ git "main" require "leanprover-community" / "importGraph" @ git "main" require "leanprover-community" / "LeanSearchClient" @ git "main" -require "leanprover-community" / "plausible" @ git "v4.16.0-rc1" +require "leanprover-community" / "plausible" @ git "main" /-! ## Options for building mathlib From c4f3a47814debb17aaf7a97e7db1b0e92a78be06 Mon Sep 17 00:00:00 2001 From: Johan Commelin Date: Mon, 3 Feb 2025 16:00:40 +0000 Subject: [PATCH 038/103] chore(Logic): process a batch of porting notes (#21226) --- Mathlib/Logic/Denumerable.lean | 5 +---- Mathlib/Logic/Embedding/Basic.lean | 6 +----- Mathlib/Logic/Encodable/Basic.lean | 7 ------- Mathlib/Logic/Equiv/Basic.lean | 5 +---- Mathlib/Logic/Equiv/Defs.lean | 6 ------ Mathlib/Logic/Equiv/Fin.lean | 3 +-- Mathlib/Logic/Equiv/Option.lean | 5 +---- Mathlib/Logic/Equiv/PartialEquiv.lean | 10 ++-------- Mathlib/Logic/Function/Basic.lean | 2 -- Mathlib/Logic/Function/Defs.lean | 3 --- 10 files changed, 7 insertions(+), 45 deletions(-) diff --git a/Mathlib/Logic/Denumerable.lean b/Mathlib/Logic/Denumerable.lean index a71bc3defb551..494bda6e3b380 100644 --- a/Mathlib/Logic/Denumerable.lean +++ b/Mathlib/Logic/Denumerable.lean @@ -84,10 +84,7 @@ way. -/ def ofEquiv (α) {β} [Denumerable α] (e : β ≃ α) : Denumerable β := { Encodable.ofEquiv _ e with decode_inv := fun n => by - -- Porting note: replaced `simp` - simp_rw [Option.mem_def, decode_ofEquiv e, encode_ofEquiv e, decode_eq_ofNat, - Option.map_some', Option.some_inj, exists_eq_left', Equiv.apply_symm_apply, - Denumerable.encode_ofNat] } + simp [decode_ofEquiv, encode_ofEquiv] } @[simp] theorem ofEquiv_ofNat (α) {β} [Denumerable α] (e : β ≃ α) (n) : diff --git a/Mathlib/Logic/Embedding/Basic.lean b/Mathlib/Logic/Embedding/Basic.lean index 4e516587e5f5a..bb90812cec01d 100644 --- a/Mathlib/Logic/Embedding/Basic.lean +++ b/Mathlib/Logic/Embedding/Basic.lean @@ -34,8 +34,7 @@ instance {α : Sort u} {β : Sort v} : EmbeddingLike (α ↪ β) α β where initialize_simps_projections Embedding (toFun → apply) --- Porting note: this needs `tactic.lift`. ---instance {α β : Sort*} : CanLift (α → β) (α ↪ β) coeFn Injective where prf f hf := ⟨⟨f, hf⟩, rfl⟩ +instance {α β : Sort*} : CanLift (α → β) (α ↪ β) (↑) Injective where prf f hf := ⟨⟨f, hf⟩, rfl⟩ theorem exists_surjective_iff {α β : Sort*} : (∃ f : α → β, Surjective f) ↔ Nonempty (α → β) ∧ Nonempty (β ↪ α) := @@ -197,9 +196,6 @@ lemma setValue_right_apply_eq {α β} (f : α ↪ β) (a c : α) [∀ a', Decida protected def some {α} : α ↪ Option α := ⟨some, Option.some_injective α⟩ --- Porting note: Lean 4 unfolds coercion `α → Option α` to `some`, so there is no separate --- `Function.Embedding.coeOption`. - /-- A version of `Option.map` for `Function.Embedding`s. -/ @[simps (config := .asFn)] def optionMap {α β} (f : α ↪ β) : Option α ↪ Option β := diff --git a/Mathlib/Logic/Encodable/Basic.lean b/Mathlib/Logic/Encodable/Basic.lean index e1558f646d24a..2504ac90134c1 100644 --- a/Mathlib/Logic/Encodable/Basic.lean +++ b/Mathlib/Logic/Encodable/Basic.lean @@ -43,8 +43,6 @@ wish to enforce infiniteness. -/ class Encodable (α : Type*) where /-- Encoding from Type α to ℕ -/ encode : α → ℕ - -- Porting note: was `decode [] : ℕ → Option α`. This means that `decode` does not take the type - --explicitly in Lean4 /-- Decoding from ℕ to Option α-/ decode : ℕ → Option α /-- Invariant relationship between encoding and decoding -/ @@ -94,12 +92,10 @@ def ofLeftInverse [Encodable α] (f : β → α) (finv : α → β) (linv : ∀ def ofEquiv (α) [Encodable α] (e : β ≃ α) : Encodable β := ofLeftInverse e e.symm e.left_inv --- Porting note: removing @[simp], too powerful theorem encode_ofEquiv {α β} [Encodable α] (e : β ≃ α) (b : β) : @encode _ (ofEquiv _ e) b = encode (e b) := rfl --- Porting note: removing @[simp], too powerful theorem decode_ofEquiv {α β} [Encodable α] (e : β ≃ α) (n : ℕ) : @decode _ (ofEquiv _ e) n = (decode n).map e.symm := show Option.bind _ _ = Option.map _ _ @@ -224,7 +220,6 @@ section Sum variable [Encodable α] [Encodable β] --- Porting note: removing bit0 and bit1 /-- Explicit encoding function for the sum of two encodable types. -/ def encodeSum : α ⊕ β → ℕ | Sum.inl a => 2 * encode a @@ -240,12 +235,10 @@ def decodeSum (n : ℕ) : Option (α ⊕ β) := instance _root_.Sum.encodable : Encodable (α ⊕ β) := ⟨encodeSum, decodeSum, fun s => by cases s <;> simp [encodeSum, div2_val, decodeSum, encodek]⟩ --- Porting note: removing bit0 and bit1 from statement @[simp] theorem encode_inl (a : α) : @encode (α ⊕ β) _ (Sum.inl a) = 2 * (encode a) := rfl --- Porting note: removing bit0 and bit1 from statement @[simp] theorem encode_inr (b : β) : @encode (α ⊕ β) _ (Sum.inr b) = 2 * (encode b) + 1 := rfl diff --git a/Mathlib/Logic/Equiv/Basic.lean b/Mathlib/Logic/Equiv/Basic.lean index 75b4bbbc81288..dd6b85f1b2040 100644 --- a/Mathlib/Logic/Equiv/Basic.lean +++ b/Mathlib/Logic/Equiv/Basic.lean @@ -1429,10 +1429,7 @@ theorem swapCore_swapCore (r a b : α) : swapCore a b (swapCore a b r) = r := by unfold swapCore; split_ifs <;> cc theorem swapCore_comm (r a b : α) : swapCore a b r = swapCore b a r := by - unfold swapCore - -- Porting note: whatever solution works for `swapCore_swapCore` will work here too. - split_ifs with h₁ h₂ h₃ <;> try simp - · cases h₁; cases h₂; rfl + unfold swapCore; split_ifs <;> cc /-- `swap a b` is the permutation that swaps `a` and `b` and leaves other values as is. -/ diff --git a/Mathlib/Logic/Equiv/Defs.lean b/Mathlib/Logic/Equiv/Defs.lean index b3ca33b7c9ca3..59336397cf0f6 100644 --- a/Mathlib/Logic/Equiv/Defs.lean +++ b/Mathlib/Logic/Equiv/Defs.lean @@ -164,8 +164,6 @@ protected def trans (e₁ : α ≃ β) (e₂ : β ≃ γ) : α ≃ γ := instance : Trans Equiv Equiv Equiv where trans := Equiv.trans --- Porting note: this is not a syntactic tautology any more because --- the coercion from `e` to a function is now `DFunLike.coe` not `e.toFun` @[simp, mfld_simps] theorem toFun_as_coe (e : α ≃ β) : e.toFun = e := rfl @[simp, mfld_simps] theorem invFun_as_coe (e : α ≃ β) : e.invFun = e.symm := rfl @@ -224,14 +222,10 @@ protected def cast {α β : Sort _} (h : α = β) : α ≃ β := theorem Perm.coe_subsingleton {α : Type*} [Subsingleton α] (e : Perm α) : (e : α → α) = id := by rw [Perm.subsingleton_eq_refl e, coe_refl] --- Porting note: marking this as `@[simp]` because `simp` doesn't fire on `coe_refl` --- in an expression such as `Equiv.refl a x` @[simp] theorem refl_apply (x : α) : Equiv.refl α x = x := rfl @[simp] theorem coe_trans (f : α ≃ β) (g : β ≃ γ) : (f.trans g : α → γ) = g ∘ f := rfl --- Porting note: marking this as `@[simp]` because `simp` doesn't fire on `coe_trans` --- in an expression such as `Equiv.trans f g x` @[simp] theorem trans_apply (f : α ≃ β) (g : β ≃ γ) (a : α) : (f.trans g) a = g (f a) := rfl @[simp] theorem apply_symm_apply (e : α ≃ β) (x : β) : e (e.symm x) = x := e.right_inv x diff --git a/Mathlib/Logic/Equiv/Fin.lean b/Mathlib/Logic/Equiv/Fin.lean index c3622dc3f66bf..02a7f1a2a6d22 100644 --- a/Mathlib/Logic/Equiv/Fin.lean +++ b/Mathlib/Logic/Equiv/Fin.lean @@ -303,9 +303,8 @@ theorem finRotate_one : finRotate 1 = Equiv.refl _ := simp only [Fin.lt_iff_val_lt_val, Fin.val_last, Fin.val_mk] at h simp [finRotate_of_lt h, Fin.ext_iff, Fin.add_def, Nat.mod_eq_of_lt (Nat.succ_lt_succ h)] --- Porting note: was a @[simp] theorem finRotate_apply_zero : finRotate n.succ 0 = 1 := by - rw [finRotate_succ_apply, Fin.zero_add] + simp theorem coe_finRotate_of_ne_last {i : Fin n.succ} (h : i ≠ Fin.last n) : (finRotate (n + 1) i : ℕ) = i + 1 := by diff --git a/Mathlib/Logic/Equiv/Option.lean b/Mathlib/Logic/Equiv/Option.lean index 9c0c3d02003ee..231ce6a316449 100644 --- a/Mathlib/Logic/Equiv/Option.lean +++ b/Mathlib/Logic/Equiv/Option.lean @@ -177,10 +177,7 @@ def optionSubtype [DecidableEq β] (x : β) : ext a cases a · simpa using e.property.symm - -- Porting note: this cases had been by `simpa`, - -- but `simp` here is mysteriously slow, even after squeezing. - -- `rfl` closes the goal quickly, so we use that. - · rfl + · simp right_inv e := by ext a rfl diff --git a/Mathlib/Logic/Equiv/PartialEquiv.lean b/Mathlib/Logic/Equiv/PartialEquiv.lean index 753807e85c86e..8355147d52dbe 100644 --- a/Mathlib/Logic/Equiv/PartialEquiv.lean +++ b/Mathlib/Logic/Equiv/PartialEquiv.lean @@ -164,20 +164,14 @@ def Simps.symm_apply (e : PartialEquiv α β) : β → α := 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) : --- (PartialEquiv.mk f g s t ml mr il ir : α → β) = f := by dsimp only +theorem coe_mk (f : α → β) (g s t ml mr il ir) : + (PartialEquiv.mk f g s t ml mr il ir : α → β) = f := rfl @[simp, mfld_simps] theorem coe_symm_mk (f : α → β) (g s t ml mr il ir) : ((PartialEquiv.mk f g s t ml mr il ir).symm : β → α) = g := rfl --- Porting note: this is now a syntactic tautology --- @[simp, mfld_simps] --- theorem toFun_as_coe : e.toFun = e := rfl - @[simp, mfld_simps] theorem invFun_as_coe : e.invFun = e.symm := rfl diff --git a/Mathlib/Logic/Function/Basic.lean b/Mathlib/Logic/Function/Basic.lean index 1eee4fc7e8759..5bbe6198e2a15 100644 --- a/Mathlib/Logic/Function/Basic.lean +++ b/Mathlib/Logic/Function/Basic.lean @@ -43,8 +43,6 @@ theorem const_injective [Nonempty α] : Injective (const α : β → α → β) theorem const_inj [Nonempty α] {y₁ y₂ : β} : const α y₁ = const α y₂ ↔ y₁ = y₂ := ⟨fun h ↦ const_injective h, fun h ↦ h ▸ rfl⟩ --- Porting note: `Function.onFun` is now reducible --- @[simp] theorem onFun_apply (f : β → β → γ) (g : α → β) (a b : α) : onFun f g a b = f (g a) (g b) := rfl diff --git a/Mathlib/Logic/Function/Defs.lean b/Mathlib/Logic/Function/Defs.lean index 8196c2377e17e..79adace923e87 100644 --- a/Mathlib/Logic/Function/Defs.lean +++ b/Mathlib/Logic/Function/Defs.lean @@ -50,9 +50,6 @@ abbrev swap {φ : α → β → Sort u₃} (f : ∀ x y, φ x y) : ∀ y x, φ x theorem swap_def {φ : α → β → Sort u₃} (f : ∀ x y, φ x y) : swap f = fun y x => f x y := rfl --- Porting note: removed, it was never used --- notation f " -[" op "]- " g => combine f op g - @[simp, mfld_simps] theorem id_comp (f : α → β) : id ∘ f = f := rfl From 7305307dd170d636a9c51a6edfa09612dd02cd5a Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Mon, 3 Feb 2025 16:00:41 +0000 Subject: [PATCH 039/103] chore: tidy various files (#21367) --- Mathlib/Algebra/Algebra/Basic.lean | 5 ++-- Mathlib/Algebra/CharP/LinearMaps.lean | 5 +--- Mathlib/Algebra/Group/Subgroup/Basic.lean | 2 +- Mathlib/Algebra/Module/CharacterModule.lean | 4 ++-- .../Algebra/Order/AbsoluteValue/Basic.lean | 3 +-- .../Algebra/Order/GroupWithZero/Bounds.lean | 15 ++++++------ .../Order/GroupWithZero/Unbundled.lean | 2 +- Mathlib/Algebra/Polynomial/Div.lean | 6 ++--- Mathlib/Algebra/Ring/Parity.lean | 4 ++-- Mathlib/Algebra/Ring/Subsemiring/Basic.lean | 3 +-- Mathlib/Analysis/MeanInequalities.lean | 3 ++- .../SpecialFunctions/Pow/Asymptotics.lean | 6 ++--- Mathlib/CategoryTheory/Shift/Opposite.lean | 4 ++-- Mathlib/CategoryTheory/Shift/Pullback.lean | 6 ++--- Mathlib/Combinatorics/SimpleGraph/Clique.lean | 4 ++-- Mathlib/Combinatorics/SimpleGraph/Path.lean | 18 +++++++-------- Mathlib/Data/DFinsupp/Small.lean | 5 ++-- Mathlib/Data/ENNReal/Operations.lean | 5 ++-- Mathlib/Data/List/ReduceOption.lean | 13 +++-------- Mathlib/Data/Multiset/Basic.lean | 6 ++--- .../IntermediateField/Adjoin/Basic.lean | 10 ++++---- Mathlib/LinearAlgebra/Basis/Exact.lean | 2 +- .../Function/LpSeminorm/Basic.lean | 10 ++++---- Mathlib/NumberTheory/Cyclotomic/Basic.lean | 13 +++++------ .../DedekindDomain/FiniteAdeleRing.lean | 18 +++++++++------ .../Algebra/Category/ProfiniteGrp/Limits.lean | 23 +++++++++---------- Mathlib/Topology/Algebra/LinearTopology.lean | 4 ++-- .../Algebra/Module/ModuleTopology.lean | 2 +- Mathlib/Topology/PartialHomeomorph.lean | 2 +- 29 files changed, 92 insertions(+), 111 deletions(-) diff --git a/Mathlib/Algebra/Algebra/Basic.lean b/Mathlib/Algebra/Algebra/Basic.lean index 12e4743eb11b9..d4c16489c62cf 100644 --- a/Mathlib/Algebra/Algebra/Basic.lean +++ b/Mathlib/Algebra/Algebra/Basic.lean @@ -395,9 +395,8 @@ theorem NoZeroSMulDivisors.trans_faithfulSMul (R A M : Type*) [CommRing R] [Ring [NoZeroSMulDivisors A M] : NoZeroSMulDivisors R M where eq_zero_or_eq_zero_of_smul_eq_zero hx := by rw [← algebraMap_smul (A := A)] at hx - obtain (hc|hx) := eq_zero_or_eq_zero_of_smul_eq_zero hx - · exact Or.inl <| (map_eq_zero_iff _ <| FaithfulSMul.algebraMap_injective R A).mp hc - · exact Or.inr hx + simpa only [map_eq_zero_iff _ <| FaithfulSMul.algebraMap_injective R A] using + eq_zero_or_eq_zero_of_smul_eq_zero hx @[deprecated (since := "2025-01-31")] alias NoZeroSMulDivisors.of_algebraMap_injective' := NoZeroSMulDivisors.trans_faithfulSMul diff --git a/Mathlib/Algebra/CharP/LinearMaps.lean b/Mathlib/Algebra/CharP/LinearMaps.lean index 93009eaa7324f..744919935cef1 100644 --- a/Mathlib/Algebra/CharP/LinearMaps.lean +++ b/Mathlib/Algebra/CharP/LinearMaps.lean @@ -40,13 +40,10 @@ variable {R M : Type*} [CommSemiring R] [AddCommMonoid M] [Module R M] theorem charP_end {p : ℕ} [hchar : CharP R p] (htorsion : ∃ x : M, Ideal.torsionOf R M x = ⊥) : CharP (M →ₗ[R] M) p where cast_eq_zero_iff' n := by - have hreduction : ∃ x : M, ∀ r : R, r • x = 0 → r = 0 := - Exists.casesOn htorsion fun x hx ↦ - Exists.intro x fun r a ↦ (hx ▸ Ideal.mem_torsionOf_iff x r).mpr a have exact : (n : M →ₗ[R] M) = (n : R) • 1 := by simp only [Nat.cast_smul_eq_nsmul, nsmul_eq_mul, mul_one] rw [exact, LinearMap.ext_iff, ← hchar.1] - exact ⟨fun h ↦ Exists.casesOn hreduction fun x hx ↦ hx n (h x), + exact ⟨fun h ↦ htorsion.casesOn fun x hx ↦ by simpa [← Ideal.mem_torsionOf_iff, hx] using h x, fun h ↦ (congrArg (fun t ↦ ∀ x, t • x = 0) h).mpr fun x ↦ zero_smul R x⟩ end Module diff --git a/Mathlib/Algebra/Group/Subgroup/Basic.lean b/Mathlib/Algebra/Group/Subgroup/Basic.lean index 24c0f1946cbfa..86fccdf74e237 100644 --- a/Mathlib/Algebra/Group/Subgroup/Basic.lean +++ b/Mathlib/Algebra/Group/Subgroup/Basic.lean @@ -851,7 +851,7 @@ instance normal_inf_normal (H K : Subgroup G) [hH : H.Normal] [hK : K.Normal] : @[to_additive] theorem normal_iInf_normal {ι : Type*} {a : ι → Subgroup G} - (norm : ∀ i : ι , (a i).Normal) : (iInf a).Normal := by + (norm : ∀ i : ι, (a i).Normal) : (iInf a).Normal := by constructor intro g g_in_iInf h rw [Subgroup.mem_iInf] at g_in_iInf ⊢ diff --git a/Mathlib/Algebra/Module/CharacterModule.lean b/Mathlib/Algebra/Module/CharacterModule.lean index b4146d2497f6a..ea00edf9b0735 100644 --- a/Mathlib/Algebra/Module/CharacterModule.lean +++ b/Mathlib/Algebra/Module/CharacterModule.lean @@ -236,8 +236,8 @@ lemma surjective_of_dual_injective (f : A →ₗ[R] A') (hf : Function.Injective obtain ⟨b, rfl⟩ := QuotientAddGroup.mk'_surjective _ a suffices eq : dual (Submodule.mkQ _) c = 0 from congr($eq b) refine hf ?_ - rw [← LinearMap.comp_apply, ← dual_comp, LinearMap.range_mkQ_comp, dual_zero] - rfl + rw [← LinearMap.comp_apply, ← dual_comp, LinearMap.range_mkQ_comp, dual_zero, + LinearMap.zero_apply, dual_apply, AddMonoidHom.zero_comp] lemma dual_injective_iff_surjective {f : A →ₗ[R] A'} : Function.Injective (dual f) ↔ Function.Surjective f := diff --git a/Mathlib/Algebra/Order/AbsoluteValue/Basic.lean b/Mathlib/Algebra/Order/AbsoluteValue/Basic.lean index 39413e7dcbea8..218fb19a9985b 100644 --- a/Mathlib/Algebra/Order/AbsoluteValue/Basic.lean +++ b/Mathlib/Algebra/Order/AbsoluteValue/Basic.lean @@ -328,9 +328,8 @@ lemma isNontrivial_iff_ne_trivial [DecidablePred fun x : R ↦ x = 0] [NoZeroDiv [Nontrivial S] (v : AbsoluteValue R S) : v.IsNontrivial ↔ v ≠ .trivial := by refine ⟨fun ⟨x, hx₀, hx₁⟩ h ↦ hx₁ <| h.symm ▸ trivial_apply hx₀, fun H ↦ ?_⟩ + simp only [IsNontrivial] contrapose! H - simp only [IsNontrivial] at H - push_neg at H ext1 x rcases eq_or_ne x 0 with rfl | hx · simp diff --git a/Mathlib/Algebra/Order/GroupWithZero/Bounds.lean b/Mathlib/Algebra/Order/GroupWithZero/Bounds.lean index a697535c76292..ebe1f4440187c 100644 --- a/Mathlib/Algebra/Order/GroupWithZero/Bounds.lean +++ b/Mathlib/Algebra/Order/GroupWithZero/Bounds.lean @@ -18,14 +18,13 @@ open Set lemma BddAbove.range_comp_of_nonneg {α β γ : Type*} [Nonempty α] [Preorder β] [Zero β] [Preorder γ] {f : α → β} {g : β → γ} (hf : BddAbove (range f)) (hf0 : 0 ≤ f) (hg : MonotoneOn g {x : β | 0 ≤ x}) : BddAbove (range (fun x => g (f x))) := by - have hg' : BddAbove (g '' (range f)) := by - apply hg.map_bddAbove (by rintro x ⟨a, rfl⟩; exact hf0 a) - · obtain ⟨b, hb⟩ := hf - use b, hb - simp only [mem_upperBounds, mem_range, forall_exists_index, forall_apply_eq_imp_iff] at hb - exact le_trans (hf0 Classical.ofNonempty) (hb Classical.ofNonempty) - change BddAbove (range (g ∘ f)) - simpa only [Set.range_comp] using hg' + suffices hg' : BddAbove (g '' range f) by + rwa [← Function.comp_def, Set.range_comp] + apply hg.map_bddAbove (by rintro x ⟨a, rfl⟩; exact hf0 a) + obtain ⟨b, hb⟩ := hf + use b, hb + simp only [mem_upperBounds, mem_range, forall_exists_index, forall_apply_eq_imp_iff] at hb + exact le_trans (hf0 Classical.ofNonempty) (hb Classical.ofNonempty) /-- If `u v : α → β` are nonnegative and bounded above, then `u * v` is bounded above. -/ theorem bddAbove_range_mul {α β : Type*} [Nonempty α] {u v : α → β} [Preorder β] [Zero β] [Mul β] diff --git a/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean b/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean index f538946d0fc94..8330f67d0078d 100644 --- a/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean +++ b/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean @@ -950,7 +950,7 @@ lemma Monotone.mul [PosMulMono M₀] [MulPosMono M₀] (hf : Monotone f) (hg : M (hf₀ : ∀ x, 0 ≤ f x) (hg₀ : ∀ x, 0 ≤ g x) : Monotone (f * g) := fun _ _ h ↦ mul_le_mul (hf h) (hg h) (hg₀ _) (hf₀ _) -lemma MonotoneOn.mul [PosMulMono M₀] [MulPosMono M₀] {s : Set α } (hf : MonotoneOn f s) +lemma MonotoneOn.mul [PosMulMono M₀] [MulPosMono M₀] {s : Set α} (hf : MonotoneOn f s) (hg : MonotoneOn g s) (hf₀ : ∀ x ∈ s, 0 ≤ f x) (hg₀ : ∀ x ∈ s, 0 ≤ g x) : MonotoneOn (f * g) s := fun _ ha _ hb h ↦ mul_le_mul (hf ha hb h) (hg ha hb h) (hg₀ _ ha) (hf₀ _ hb) diff --git a/Mathlib/Algebra/Polynomial/Div.lean b/Mathlib/Algebra/Polynomial/Div.lean index 1047af9fab54a..430e2e91cbe67 100644 --- a/Mathlib/Algebra/Polynomial/Div.lean +++ b/Mathlib/Algebra/Polynomial/Div.lean @@ -397,7 +397,7 @@ theorem modByMonic_eq_zero_iff_dvd (hq : Monic q) : p %ₘ q = 0 ↔ q ∣ p := exact not_lt_of_ge (Nat.le_add_right _ _) (WithBot.coe_lt_coe.1 this)⟩ -/-- See `Polynomial.mul_left_modByMonic` for the other multiplication order. That version, unlike +/-- See `Polynomial.mul_self_modByMonic` for the other multiplication order. That version, unlike this one, requires commutativity. -/ @[simp] lemma self_mul_modByMonic (hq : q.Monic) : (q * p) %ₘ q = 0 := by @@ -476,7 +476,7 @@ section multiplicity /-- An algorithm for deciding polynomial divisibility. The algorithm is "compute `p %ₘ q` and compare to `0`". -See `polynomial.modByMonic` for the algorithm that computes `%ₘ`. +See `Polynomial.modByMonic` for the algorithm that computes `%ₘ`. -/ def decidableDvdMonic [DecidableEq R] (p : R[X]) (hq : Monic q) : Decidable (q ∣ p) := decidable_of_iff (p %ₘ q = 0) (modByMonic_eq_zero_iff_dvd hq) @@ -652,7 +652,7 @@ theorem eval_divByMonic_pow_rootMultiplicity_ne_zero {p : R[X]} (a : R) (hp : p (monic_X_sub_C _) hp).not_pow_dvd_of_multiplicity_lt (Nat.lt_succ_self _) (dvd_of_mul_right_eq _ this) -/-- See `Polynomial.mul_right_modByMonic` for the other multiplication order. This version, unlike +/-- See `Polynomial.self_mul_modByMonic` for the other multiplication order. This version, unlike that one, requires commutativity. -/ @[simp] lemma mul_self_modByMonic (hq : q.Monic) : (p * q) %ₘ q = 0 := by diff --git a/Mathlib/Algebra/Ring/Parity.lean b/Mathlib/Algebra/Ring/Parity.lean index f5b3128adee62..b6889e5283406 100644 --- a/Mathlib/Algebra/Ring/Parity.lean +++ b/Mathlib/Algebra/Ring/Parity.lean @@ -20,11 +20,11 @@ As opposed to `Even`, `Odd` does not have a multiplicative counterpart. Try to generalize `Even` lemmas further. For example, there are still a few lemmas whose `Semiring` assumptions I (DT) am not convinced are necessary. If that turns out to be true, they could be moved -to `Algebra.Group.Even`. +to `Mathlib.Algebra.Group.Even`. ## See also -`Algebra.Group.Even` for the definition of even elements. +`Mathlib.Algebra.Group.Even` for the definition of even elements. -/ assert_not_exists DenselyOrdered OrderedRing diff --git a/Mathlib/Algebra/Ring/Subsemiring/Basic.lean b/Mathlib/Algebra/Ring/Subsemiring/Basic.lean index c1789b31e7cc8..64b6695b7b536 100644 --- a/Mathlib/Algebra/Ring/Subsemiring/Basic.lean +++ b/Mathlib/Algebra/Ring/Subsemiring/Basic.lean @@ -812,7 +812,7 @@ theorem ofLeftInverseS_symm_apply {g : S → R} {f : R →+* S} (h : Function.Le rfl /-- Given an equivalence `e : R ≃+* S` of semirings and a subsemiring `s` of `R`, -`subsemiring_map e s` is the induced equivalence between `s` and `s.map e` -/ +`subsemiringMap e s` is the induced equivalence between `s` and `s.map e` -/ def subsemiringMap (e : R ≃+* S) (s : Subsemiring R) : s ≃+* s.map (e : R →+* S) := { e.toAddEquiv.addSubmonoidMap s.toAddSubmonoid, e.toMulEquiv.submonoidMap s.toSubmonoid with } @@ -899,7 +899,6 @@ instance mulActionWithZero [Zero α] [MulActionWithZero R' α] (S : Subsemiring MulActionWithZero S α := MulActionWithZero.compHom _ S.subtype.toMonoidWithZeroHom --- Porting note: instance named explicitly for use in `RingTheory/Subring/Basic` /-- The action by a subsemiring is the action by the underlying semiring. -/ instance module [AddCommMonoid α] [Module R' α] (S : Subsemiring R') : Module S α := -- Porting note: copying over the `smul` field causes a timeout diff --git a/Mathlib/Analysis/MeanInequalities.lean b/Mathlib/Analysis/MeanInequalities.lean index 09b5b24238fb4..a4062257ae2d4 100644 --- a/Mathlib/Analysis/MeanInequalities.lean +++ b/Mathlib/Analysis/MeanInequalities.lean @@ -14,7 +14,8 @@ import Mathlib.Data.Real.ConjExponents In this file we prove several inequalities for finite sums, including AM-GM inequality, HM-GM inequality, Young's inequality, Hölder inequality, and Minkowski inequality. Versions for -integrals of some of these inequalities are available in `MeasureTheory.Integral.MeanInequalities`. +integrals of some of these inequalities are available in +`Mathlib.MeasureTheory.Integral.MeanInequalities`. ## Main theorems diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Asymptotics.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Asymptotics.lean index 1e9791803def9..f66f37fbb5a9c 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/Asymptotics.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/Asymptotics.lean @@ -199,8 +199,7 @@ theorem isBigO_cpow_rpow (hl : IsBoundedUnder (· ≤ ·) l fun x => |(g x).im|) _ =Θ[l] (show α → ℝ from fun x => abs (f x) ^ (g x).re / (1 : ℝ)) := ((isTheta_refl _ _).div (isTheta_exp_arg_mul_im hl)) _ =ᶠ[l] (show α → ℝ from fun x => abs (f x) ^ (g x).re) := by - simp only [ofReal_one, div_one] - rfl + simp only [ofReal_one, div_one, EventuallyEq.rfl] theorem isTheta_cpow_rpow (hl_im : IsBoundedUnder (· ≤ ·) l fun x => |(g x).im|) (hl : ∀ᶠ x in l, f x = 0 → re (g x) = 0 → g x = 0) : @@ -212,8 +211,7 @@ theorem isTheta_cpow_rpow (hl_im : IsBoundedUnder (· ≤ ·) l fun x => |(g x). _ =Θ[l] fun x => abs (f x) ^ (g x).re / (1 : ℝ) := (isTheta_refl _ _).div (isTheta_exp_arg_mul_im hl_im) _ =ᶠ[l] (fun x => abs (f x) ^ (g x).re) := by - simp only [ofReal_one, div_one] - rfl + simp only [ofReal_one, div_one, EventuallyEq.rfl] theorem isTheta_cpow_const_rpow {b : ℂ} (hl : b.re = 0 → b ≠ 0 → ∀ᶠ x in l, f x ≠ 0) : (fun x => f x ^ b) =Θ[l] fun x => abs (f x) ^ b.re := diff --git a/Mathlib/CategoryTheory/Shift/Opposite.lean b/Mathlib/CategoryTheory/Shift/Opposite.lean index 683367784e9b6..90eaa8c7887fa 100644 --- a/Mathlib/CategoryTheory/Shift/Opposite.lean +++ b/Mathlib/CategoryTheory/Shift/Opposite.lean @@ -26,14 +26,14 @@ by `A`, we define a `CommShift` structure by `A` on `OppositeShift.functor A F`. way, we can make this an instance and reserve `F.op` for the `CommShift` instance by the modified shift in the case of (pre)triangulated categories. -Similarly,if `τ` is a natural transformation between functors `F,G : C ⥤ D`, we define +Similarly, if `τ` is a natural transformation between functors `F,G : C ⥤ D`, we define a type synonym for `τ.op` called `OppositeShift.natTrans A τ : OppositeShift.functor A F ⟶ OppositeShift.functor A G`. When `τ` has a `CommShift` structure by `A` (i.e. is compatible with `CommShift` structures on `F` and `G`), we define a `CommShift` structure by `A` on `OppositeShift.natTrans A τ`. Finally, if we have an adjunction `F ⊣ G` (with `G : D ⥤ C`), we define a type synonym -`OppositeShift.adjunction A adj : OppositeShift.functor A G ⊣ OppositeShift.functor A F` +`OppositeShift.adjunction A adj : OppositeShift.functor A G ⊣ OppositeShift.functor A F` for `adj.op`, and we show that, if `adj` compatible with `CommShift` structures on `F` and `G`, then `OppositeShift.adjunction A adj` is also compatible with the pulled back `CommShift` structures. diff --git a/Mathlib/CategoryTheory/Shift/Pullback.lean b/Mathlib/CategoryTheory/Shift/Pullback.lean index 914f3a24544d6..1a9572903fb98 100644 --- a/Mathlib/CategoryTheory/Shift/Pullback.lean +++ b/Mathlib/CategoryTheory/Shift/Pullback.lean @@ -16,7 +16,7 @@ If `F : C ⥤ D` is a functor between categories equipped with shifts by `B`, we a type synonym `PullbackShift.functor F φ` for `F`. When `F` has a `CommShift` structure by `B`, we define a pulled back `CommShift` structure by `A` on `PullbackShift.functor F φ`. -Similarly,if `τ` is a natural transformation between functors `F,G : C ⥤ D`, we define +Similarly, if `τ` is a natural transformation between functors `F,G : C ⥤ D`, we define a type synonym `PullbackShift.natTrans τ φ : PullbackShift.functor F φ ⟶ PullbackShift.functor G φ`. When `τ` has a `CommShift` structure by `B` (i.e. is compatible with `CommShift` structures @@ -24,7 +24,7 @@ on `F` and `G`), we define a pulled back `CommShift` structure by `A` on `PullbackShift.natTrans τ φ`. Finally, if we have an adjunction `F ⊣ G` (with `G : D ⥤ C`), we define a type synonym -`PullbackShift.adjunction adj φ : PullbackShift.functor F φ ⊣ PullbackShift.functor G φ` +`PullbackShift.adjunction adj φ : PullbackShift.functor F φ ⊣ PullbackShift.functor G φ` and we show that, if `adj` compatible with `CommShift` structures on `F` and `G`, then `PullbackShift.adjunction adj φ` iis also compatible with the pulled back `CommShift` structures. @@ -113,7 +113,7 @@ lemma pullbackShiftFunctorAdd'_inv_app : (pullbackShiftIso C φ a₃ b₃ h₃).inv.app X := by subst h₁ h₂ h obtain rfl : b₃ = φ a₁ + φ a₂ := by rw [h₃, φ.map_add] - simp + simp only [Functor.comp_obj, NatTrans.naturality_assoc] erw [Functor.map_id, id_comp, id_comp, shiftFunctorAdd'_eq_shiftFunctorAdd, shiftFunctorAdd'_eq_shiftFunctorAdd] change _ ≫ _ = _ diff --git a/Mathlib/Combinatorics/SimpleGraph/Clique.lean b/Mathlib/Combinatorics/SimpleGraph/Clique.lean index 433d517a5cba7..b429fc0d4e6fd 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Clique.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Clique.lean @@ -685,7 +685,7 @@ instance [DecidableEq α] [DecidableRel G.Adj] {s : Finset α} : Decidable (G.Is /-- If `s` is an independent set, its complement meets every edge of `G`. -/ lemma IsIndepSet.nonempty_mem_compl_mem_edge [Fintype α] [DecidableEq α] {s : Finset α} (indA : G.IsIndepSet s) {e} (he : e ∈ G.edgeSet) : - { b ∈ sᶜ | b ∈ e }.Nonempty := by + { b ∈ sᶜ | b ∈ e }.Nonempty := by obtain ⟨v , w⟩ := e by_contra c rw [IsIndepSet] at indA @@ -800,7 +800,7 @@ noncomputable def indepNum (G : SimpleGraph α) : ℕ := sSup {n | ∃ s, G.IsNI theorem IsIndepSet.card_le_indepNum [Fintype α] {t : Finset α} (tc : G.IsIndepSet t) : #t ≤ G.indepNum := by - rw[← isClique_compl] at tc + rw [← isClique_compl] at tc simp_rw [indepNum, ← isNClique_compl] exact tc.card_le_cliqueNum diff --git a/Mathlib/Combinatorics/SimpleGraph/Path.lean b/Mathlib/Combinatorics/SimpleGraph/Path.lean index d016e6d94ad99..a8747f5def9c0 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Path.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Path.lean @@ -312,8 +312,8 @@ lemma IsCycle.getVert_injOn {p : G.Walk u u} (hpc : p.IsCycle) : (p.not_nil_of_tail_not_nil (not_nil_of_isCycle_cons hpc)), Set.mem_setOf] at hn hm have := ((Walk.cons_isCycle_iff _ _).mp hpc).1.getVert_injOn (by omega : n - 1 ≤ p.tail.length) (by omega : m - 1 ≤ p.tail.length) - (by simp_all [SimpleGraph.Walk.getVert_tail, show n - 1 + 1 = n from by omega, - show m - 1 + 1 = m from by omega]) + (by simp_all [SimpleGraph.Walk.getVert_tail, show n - 1 + 1 = n by omega, + show m - 1 + 1 = m by omega]) omega lemma IsCycle.getVert_injOn' {p : G.Walk u u} (hpc : p.IsCycle) : @@ -324,8 +324,8 @@ lemma IsCycle.getVert_injOn' {p : G.Walk u u} (hpc : p.IsCycle) : have : p.length - n = p.length - m := Walk.length_reverse _ ▸ hpc.reverse.getVert_injOn (by simp only [Walk.length_reverse, Set.mem_setOf_eq]; omega) (by simp only [Walk.length_reverse, Set.mem_setOf_eq]; omega) - (by simp [Walk.getVert_reverse, show p.length - (p.length - n) = n from by omega, hnm, - show p.length - (p.length - m) = m from by omega]) + (by simp [Walk.getVert_reverse, show p.length - (p.length - n) = n by omega, hnm, + show p.length - (p.length - m) = m by omega]) omega lemma IsCycle.snd_ne_penultimate {p : G.Walk u u} (hp : p.IsCycle) : p.snd ≠ p.penultimate := by @@ -337,12 +337,10 @@ lemma IsCycle.snd_ne_penultimate {p : G.Walk u u} (hp : p.IsCycle) : p.snd ≠ p lemma IsCycle.getVert_endpoint_iff {i : ℕ} {p : G.Walk u u} (hpc : p.IsCycle) (hl : i ≤ p.length) : p.getVert i = u ↔ i = 0 ∨ i = p.length := by refine ⟨?_, by aesop⟩ - intro h - by_cases hi : i = 0 - · left; exact hi - · right - exact hpc.getVert_injOn (by simp only [Set.mem_setOf_eq]; omega) - (by simp only [Set.mem_setOf_eq]; omega) (h.symm ▸ (Walk.getVert_length p).symm) + rw [or_iff_not_imp_left] + intro h hi + exact hpc.getVert_injOn (by simp only [Set.mem_setOf_eq]; omega) + (by simp only [Set.mem_setOf_eq]; omega) (h.symm ▸ (Walk.getVert_length p).symm) lemma IsCycle.getVert_sub_one_neq_getVert_add_one {i : ℕ} {p : G.Walk u u} (hpc : p.IsCycle) (h : i ≤ p.length) : p.getVert (i - 1) ≠ p.getVert (i + 1) := by diff --git a/Mathlib/Data/DFinsupp/Small.lean b/Mathlib/Data/DFinsupp/Small.lean index 04278d86c6531..a0779ecf449e7 100644 --- a/Mathlib/Data/DFinsupp/Small.lean +++ b/Mathlib/Data/DFinsupp/Small.lean @@ -21,8 +21,7 @@ variable {ι : Type u} {π : ι → Type v} [∀ i, Zero (π i)] section Small instance DFinsupp.small [Small.{w} ι] [∀ (i : ι), Small.{w} (π i)] : - Small.{w} (DFinsupp π) := small_of_injective (f := fun x j ↦ x j) (fun f f' eq ↦ by - ext j - exact congr_fun eq j) + Small.{w} (DFinsupp π) := + small_of_injective (f := fun x j ↦ x j) (fun f f' eq ↦ by ext j; exact congr_fun eq j) end Small diff --git a/Mathlib/Data/ENNReal/Operations.lean b/Mathlib/Data/ENNReal/Operations.lean index 835dd0a62d9f3..621606be58e0e 100644 --- a/Mathlib/Data/ENNReal/Operations.lean +++ b/Mathlib/Data/ENNReal/Operations.lean @@ -14,9 +14,10 @@ import Mathlib.Data.NNReal.Basic In this file we prove elementary properties of algebraic operations on `ℝ≥0∞`, including addition, multiplication, natural powers and truncated subtraction, as well as how these interact with the order structure on `ℝ≥0∞`. Notably excluded from this list are inversion and division, the -definitions and properties of which can be found in `Data.ENNReal.Inv`. +definitions and properties of which can be found in `Mathlib.Data.ENNReal.Inv`. -Note: the definitions of the operations included in this file can be found in `Data.ENNReal.Basic`. +Note: the definitions of the operations included in this file can be found in +`Mathlib.Data.ENNReal.Basic`. -/ open Set NNReal ENNReal diff --git a/Mathlib/Data/List/ReduceOption.lean b/Mathlib/Data/List/ReduceOption.lean index 4e1c64731f5ac..63f75871fb36c 100644 --- a/Mathlib/Data/List/ReduceOption.lean +++ b/Mathlib/Data/List/ReduceOption.lean @@ -43,8 +43,7 @@ theorem reduceOption_append (l l' : List (Option α)) : @[simp] theorem reduceOption_replicate_none {n : ℕ} : (replicate n (@none α)).reduceOption = [] := by dsimp [reduceOption] - rw [filterMap_replicate_of_none] - rfl + rw [filterMap_replicate_of_none (id_def _)] theorem reduceOption_eq_nil_iff (l : List (Option α)) : l.reduceOption = [] ↔ ∃ n, l = replicate n none := by @@ -77,12 +76,7 @@ theorem reduceOption_eq_append_iff (l : List (Option α)) (l'₁ l'₂ : List α l.reduceOption = l'₁ ++ l'₂ ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ l₁.reduceOption = l'₁ ∧ l₂.reduceOption = l'₂ := by dsimp [reduceOption] - constructor - · intro h - rw [filterMap_eq_append_iff] at h - trivial - · intro ⟨_, _, h, hl₁, hl₂⟩ - rw [h, filterMap_append, hl₁, hl₂] + exact filterMap_eq_append_iff theorem reduceOption_eq_concat_iff (l : List (Option α)) (l' : List α) (a : α) : l.reduceOption = l'.concat a ↔ @@ -96,8 +90,7 @@ theorem reduceOption_eq_concat_iff (l : List (Option α)) (l' : List α) (a : α obtain ⟨m, n, hl₂⟩ := hl₂ use l₁ ++ replicate m none, replicate n none simp_rw [h, reduceOption_append, reduceOption_replicate_none, append_assoc, append_nil, hl₁, - hl₂] - trivial + hl₂, and_self] · intro ⟨_, _, h, hl₁, hl₂⟩ rw [h, reduceOption_append, reduceOption_cons_of_some, hl₁, hl₂] diff --git a/Mathlib/Data/Multiset/Basic.lean b/Mathlib/Data/Multiset/Basic.lean index d3c3bf82924e0..b9c45b65d4de3 100644 --- a/Mathlib/Data/Multiset/Basic.lean +++ b/Mathlib/Data/Multiset/Basic.lean @@ -1963,9 +1963,9 @@ lemma count_sub (a : α) (s t : Multiset α) : count a (s - t) = count a s - cou /-- This is a special case of `tsub_le_iff_right`, which should be used instead of this. This is needed to prove `OrderedSub (Multiset α)`. -/ protected lemma sub_le_iff_le_add : s - t ≤ u ↔ s ≤ u + t := by - revert s - exact @(Multiset.induction_on t (by simp [Multiset.sub_zero]) fun a t IH s => by - simp [IH, erase_le_iff_le_cons]) + induction t using Multiset.induction_on generalizing s with + | empty => simp [Multiset.sub_zero] + | cons a s IH => simp [IH, erase_le_iff_le_cons] /-- This is a special case of `tsub_le_iff_left`, which should be used instead of this. -/ protected lemma sub_le_iff_le_add' : s - t ≤ u ↔ s ≤ t + u := by diff --git a/Mathlib/FieldTheory/IntermediateField/Adjoin/Basic.lean b/Mathlib/FieldTheory/IntermediateField/Adjoin/Basic.lean index b7716cd854478..0852aad6f9be5 100644 --- a/Mathlib/FieldTheory/IntermediateField/Adjoin/Basic.lean +++ b/Mathlib/FieldTheory/IntermediateField/Adjoin/Basic.lean @@ -110,13 +110,11 @@ theorem toSubalgebra_iSup_of_directed (dir : Directed (· ≤ ·) t) : instance finiteDimensional_iSup_of_finite [h : Finite ι] [∀ i, FiniteDimensional K (t i)] : FiniteDimensional K (⨆ i, t i : IntermediateField K L) := by rw [← iSup_univ] - refine Set.Finite.induction_on - (motive := fun s _ => FiniteDimensional K (⨆ i ∈ s, t i : IntermediateField K L)) - _ Set.finite_univ ?_ ?_ - all_goals dsimp - · rw [iSup_emptyset] + induction Set.univ, Set.finite_univ (α := ι) using Set.Finite.induction_on with + | empty => + rw [iSup_emptyset] exact (botEquiv K L).symm.toLinearEquiv.finiteDimensional - · intro _ s _ _ hs + | insert s hs => rw [iSup_insert] exact IntermediateField.finiteDimensional_sup _ _ diff --git a/Mathlib/LinearAlgebra/Basis/Exact.lean b/Mathlib/LinearAlgebra/Basis/Exact.lean index 88e09f3929bbd..896513a905aca 100644 --- a/Mathlib/LinearAlgebra/Basis/Exact.lean +++ b/Mathlib/LinearAlgebra/Basis/Exact.lean @@ -57,7 +57,7 @@ private lemma top_le_span_of_aux (v : κ ⊕ σ → M) replace hs := DFunLike.congr_fun hs (s m) simp only [LinearMap.coe_comp, Function.comp_apply, LinearMap.id_coe, id_eq] at hs simp [hs] - have : m ∈ Submodule.span R (Set.range v) := hsp trivial + have : m ∈ Submodule.span R (Set.range v) := hsp Submodule.mem_top obtain ⟨c, rfl⟩ := Finsupp.mem_span_range_iff_exists_finsupp.mp this simp only [LinearMap.mem_ker, Finsupp.sum, map_sum, map_smul, Finset.sum_sum_eq_sum_toLeft_add_sum_toRight, map_add, hslzero, smul_zero, diff --git a/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean b/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean index dcb4374b447f5..99a81102f651b 100644 --- a/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean +++ b/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean @@ -592,11 +592,9 @@ lemma eLpNorm_indicator_eq_eLpNorm_restrict (hs : MeasurableSet s) : rw [← lintegral_indicator hs] congr simp_rw [enorm_indicator_eq_indicator_enorm] - have h_zero : (fun x => x ^ p.toReal) (0 : ℝ≥0∞) = 0 := by - simp [ENNReal.toReal_pos hp_zero hp_top] - -- Porting note: The implicit argument should be specified because the elaborator can't deal with - -- `∘` well. - exact (Set.indicator_comp_of_zero (g := fun x : ℝ≥0∞ => x ^ p.toReal) h_zero).symm + rw [eq_comm, ← Function.comp_def (fun x : ℝ≥0∞ => x ^ p.toReal), Set.indicator_comp_of_zero, + Function.comp_def] + simp [ENNReal.toReal_pos hp_zero hp_top] @[deprecated (since := "2025-01-07")] alias eLpNorm_indicator_eq_restrict := eLpNorm_indicator_eq_eLpNorm_restrict @@ -611,7 +609,7 @@ lemma eLpNorm_restrict_le (f : α → F) (p : ℝ≥0∞) (μ : Measure α) (s : lemma eLpNorm_indicator_le (f : α → E) : eLpNorm (s.indicator f) p μ ≤ eLpNorm f p μ := by refine eLpNorm_mono_ae <| .of_forall fun x ↦ ?_ - suffices ‖s.indicator f x‖₊ ≤ ‖f x‖₊ by exact NNReal.coe_mono this + suffices ‖s.indicator f x‖₊ ≤ ‖f x‖₊ from NNReal.coe_mono this rw [nnnorm_indicator_eq_indicator_nnnorm] exact s.indicator_le_self _ x diff --git a/Mathlib/NumberTheory/Cyclotomic/Basic.lean b/Mathlib/NumberTheory/Cyclotomic/Basic.lean index 21891b2e19a60..4f5d86bc154e4 100644 --- a/Mathlib/NumberTheory/Cyclotomic/Basic.lean +++ b/Mathlib/NumberTheory/Cyclotomic/Basic.lean @@ -299,19 +299,18 @@ theorem finite_of_singleton [IsDomain B] [h : IsCyclotomicExtension {n} A B] : /-- If `S` is finite and `IsCyclotomicExtension S A B`, then `B` is a finite `A`-algebra. -/ protected theorem finite [IsDomain B] [h₁ : Finite S] [h₂ : IsCyclotomicExtension S A B] : Module.Finite A B := by - cases' nonempty_fintype S with h - revert h₂ A B - refine Set.Finite.induction_on _ h₁ (fun A B => ?_) @fun n S _ _ H A B => ?_ - · intro _ _ _ _ _ + rw [finite_coe_iff] at h₁ + induction S, h₁ using Set.Finite.induction_on generalizing h₂ A B with + | empty => refine Module.finite_def.2 ⟨({1} : Finset B), ?_⟩ simp [← top_toSubmodule, ← empty, toSubmodule_bot, Submodule.one_eq_span] - · intro _ _ _ _ h + | @insert n S _ _ H => haveI : IsCyclotomicExtension S A (adjoin A {b : B | ∃ n : ℕ+, n ∈ S ∧ b ^ (n : ℕ) = 1}) := union_left _ (insert n S) _ _ (subset_insert n S) haveI := H A (adjoin A {b : B | ∃ n : ℕ+, n ∈ S ∧ b ^ (n : ℕ) = 1}) have : Module.Finite (adjoin A {b : B | ∃ n : ℕ+, n ∈ S ∧ b ^ (n : ℕ) = 1}) B := by - rw [← union_singleton] at h - letI := @union_right S {n} A B _ _ _ h + rw [← union_singleton] at h₂ + let _ := union_right S {n} A B exact finite_of_singleton n _ _ exact Module.Finite.trans (adjoin A {b : B | ∃ n : ℕ+, n ∈ S ∧ b ^ (n : ℕ) = 1}) _ diff --git a/Mathlib/RingTheory/DedekindDomain/FiniteAdeleRing.lean b/Mathlib/RingTheory/DedekindDomain/FiniteAdeleRing.lean index 45e9ac50e0e50..12909e9439495 100644 --- a/Mathlib/RingTheory/DedekindDomain/FiniteAdeleRing.lean +++ b/Mathlib/RingTheory/DedekindDomain/FiniteAdeleRing.lean @@ -343,19 +343,23 @@ instance : Coe (FiniteAdeleRing R K) (K_hat R K) where theorem coe_one : (1 : FiniteAdeleRing R K) = (1 : K_hat R K) := rfl @[simp, norm_cast] -theorem coe_zero: (0 : FiniteAdeleRing R K) = (0 : K_hat R K) := rfl +theorem coe_zero : (0 : FiniteAdeleRing R K) = (0 : K_hat R K) := rfl @[simp, norm_cast] -theorem coe_add (x y : FiniteAdeleRing R K) : (x + y : FiniteAdeleRing R K) = - (x : K_hat R K) + (y : K_hat R K) := rfl +theorem coe_add (x y : FiniteAdeleRing R K) : + (x + y : FiniteAdeleRing R K) = (x : K_hat R K) + (y : K_hat R K) := + rfl @[simp, norm_cast] -theorem coe_mul (x y : FiniteAdeleRing R K) : (x * y : FiniteAdeleRing R K) = - (x : K_hat R K) * (y : K_hat R K) := rfl +theorem coe_mul (x y : FiniteAdeleRing R K) : + (x * y : FiniteAdeleRing R K) = (x : K_hat R K) * (y : K_hat R K) := + rfl @[simp, norm_cast] -theorem coe_algebraMap (x : K) : (((algebraMap K (FiniteAdeleRing R K)) x) : K_hat R K) = - (algebraMap K (ProdAdicCompletions R K)) x := rfl +theorem coe_algebraMap (x : K) : + (((algebraMap K (FiniteAdeleRing R K)) x) : K_hat R K) = + (algebraMap K (ProdAdicCompletions R K)) x := + rfl @[ext] lemma ext {a₁ a₂ : FiniteAdeleRing R K} (h : (a₁ : K_hat R K) = a₂) : a₁ = a₂ := diff --git a/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Limits.lean b/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Limits.lean index 795f0f357875d..47ceb0a6bf6bf 100644 --- a/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Limits.lean +++ b/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Limits.lean @@ -42,14 +42,14 @@ instance (P : ProfiniteGrp) : SmallCategory (OpenNormalSubgroup P) := /-- The functor from `OpenNormalSubgroup P` to `FiniteGrp` sending `U` to `P ⧸ U`, where `P : ProfiniteGrp`. -/ -def toFiniteQuotientFunctor (P : ProfiniteGrp) : OpenNormalSubgroup P ⥤ FiniteGrp := { - obj := fun H => FiniteGrp.of (P ⧸ H.toSubgroup) - map := fun fHK => FiniteGrp.ofHom (QuotientGroup.map _ _ (.id _) (leOfHom fHK)) - map_id _ := ConcreteCategory.ext <| QuotientGroup.map_id _ - map_comp f g := ConcreteCategory.ext <| (QuotientGroup.map_comp_map - _ _ _ (.id _) (.id _) (leOfHom f) (leOfHom g)).symm } - -/--The `MonoidHom` from a profinite group `P` to the projective limit of its quotients by +def toFiniteQuotientFunctor (P : ProfiniteGrp) : OpenNormalSubgroup P ⥤ FiniteGrp where + obj := fun H => FiniteGrp.of (P ⧸ H.toSubgroup) + map := fun fHK => FiniteGrp.ofHom (QuotientGroup.map _ _ (.id _) (leOfHom fHK)) + map_id _ := ConcreteCategory.ext <| QuotientGroup.map_id _ + map_comp f g := ConcreteCategory.ext <| (QuotientGroup.map_comp_map + _ _ _ (.id _) (.id _) (leOfHom f) (leOfHom g)).symm + +/-- The `MonoidHom` from a profinite group `P` to the projective limit of its quotients by open normal subgroups ordered by inclusion.-/ def toLimit_fun (P : ProfiniteGrp.{u}) : P →* limit (toFiniteQuotientFunctor P ⋙ forget₂ FiniteGrp ProfiniteGrp) where @@ -124,10 +124,9 @@ theorem toLimit_injective (P : ProfiniteGrp.{u}) : Function.Injective (toLimit P its quotients by open normal subgroups -/ noncomputable def continuousMulEquivLimittoFiniteQuotientFunctor (P : ProfiniteGrp.{u}) : P ≃ₜ* (limit (toFiniteQuotientFunctor P ⋙ forget₂ FiniteGrp ProfiniteGrp)) := { - (Continuous.homeoOfEquivCompactToT2 (f := Equiv.ofBijective _ - ⟨toLimit_injective P, toLimit_surjective P⟩) - P.toLimit.hom.continuous_toFun) - with + (Continuous.homeoOfEquivCompactToT2 + (f := Equiv.ofBijective _ ⟨toLimit_injective P, toLimit_surjective P⟩) + P.toLimit.hom.continuous_toFun) with map_mul' := (toLimit P).hom.map_mul' } instance isIso_toLimit (P : ProfiniteGrp.{u}) : IsIso (toLimit P) := by diff --git a/Mathlib/Topology/Algebra/LinearTopology.lean b/Mathlib/Topology/Algebra/LinearTopology.lean index b89ad49aba859..4c30c6e05f89e 100644 --- a/Mathlib/Topology/Algebra/LinearTopology.lean +++ b/Mathlib/Topology/Algebra/LinearTopology.lean @@ -28,7 +28,7 @@ hence our definition agrees with [N. Bourbaki, *Algebra II*, chapter 4, §2, n° * `IsLinearTopology R M`: the topology on `M` is `R`-linear, meaning that there exists a basis of neighborhoods of 0 consisting of `R`-submodules. Note that we don't impose that the topology is invariant by translation, so you'll often want to add `ContinuousConstVAdd M M` to get -something meaningless. To express that the topology of a ring `R` is linear, use +something meaningful. To express that the topology of a ring `R` is linear, use `[IsLinearTopology R R] [IsLinearTopology Rᵐᵒᵖ R]`. * `IsLinearTopology.mk_of_hasBasis`: a convenient constructor for `IsLinearTopology`. See also `IsLinearTopology.mk_of_hasBasis'`. @@ -134,7 +134,7 @@ variable (R) in /-- To show that `M` is linearly-topologized as an `R`-module, it suffices to show that it has a basis of neighborhoods of zero made of `R`-submodules. -Note: for technical reasons detailed in the module docstring, Lean sometimes struggle to find the +Note: for technical reasons detailed in the module docstring, Lean sometimes struggles to find the right `SMulMemClass` instance. See `IsLinearTopology.mk_of_hasBasis'` for a more explicit variant. -/ lemma mk_of_hasBasis {ι : Sort*} {S : Type*} [SetLike S M] diff --git a/Mathlib/Topology/Algebra/Module/ModuleTopology.lean b/Mathlib/Topology/Algebra/Module/ModuleTopology.lean index d93e0243f2c58..f0e637c7c1fdf 100644 --- a/Mathlib/Topology/Algebra/Module/ModuleTopology.lean +++ b/Mathlib/Topology/Algebra/Module/ModuleTopology.lean @@ -448,7 +448,7 @@ instance instProd : IsModuleTopology R (M × N) := by let i₂ : N →ₗ[R] P := LinearMap.inr R M N rw [show (i : M × N → P) = (fun abcd ↦ abcd.1 + abcd.2 : P × P → P) ∘ - (fun ab ↦ (i₁ ab.1,i₂ ab.2)) by + (fun ab ↦ (i₁ ab.1, i₂ ab.2)) by ext ⟨a, b⟩ <;> aesop] -- and these maps are all continuous, hence `i` is too fun_prop diff --git a/Mathlib/Topology/PartialHomeomorph.lean b/Mathlib/Topology/PartialHomeomorph.lean index c0004b4df3cba..956f5b021f441 100644 --- a/Mathlib/Topology/PartialHomeomorph.lean +++ b/Mathlib/Topology/PartialHomeomorph.lean @@ -1363,7 +1363,7 @@ noncomputable def lift_openEmbedding (e : PartialHomeomorph X Z) (hf : IsOpenEmb rw [← hx'x, hf.toPartialHomeomorph_left_inv]; exact hx have : ContinuousOn (hf.toPartialHomeomorph).symm (f '' univ) := (hf.toPartialHomeomorph).continuousOn_invFun - apply this.mono; gcongr; exact fun ⦃a⦄ a ↦ trivial + exact this.mono <| image_mono <| subset_univ _ exact ContinuousOn.congr this heq continuousOn_invFun := hf.continuous.comp_continuousOn e.continuousOn_invFun From 8a75bbf659cd92b4d214e67895f00e0794f09428 Mon Sep 17 00:00:00 2001 From: Markus Himmel Date: Mon, 3 Feb 2025 16:00:42 +0000 Subject: [PATCH 040/103] chore: add example for `check_compositions` (#21378) Co-authored-by: Markus Himmel --- .../CategoryTheory/CheckCompositions.lean | 46 ++++++++++++++++- .../CategoryTheory/CheckCompositions.lean | 49 +++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 MathlibTest/CategoryTheory/CheckCompositions.lean diff --git a/Mathlib/Tactic/CategoryTheory/CheckCompositions.lean b/Mathlib/Tactic/CategoryTheory/CheckCompositions.lean index 783b4271280b3..8f346c55bbdbc 100644 --- a/Mathlib/Tactic/CategoryTheory/CheckCompositions.lean +++ b/Mathlib/Tactic/CategoryTheory/CheckCompositions.lean @@ -64,7 +64,51 @@ def checkCompositionsTac : TacticM Unit := withMainContext do which internally is represented as `CategoryStruct.comp C inst X Y Z f g`, infer the types of `f` and `g` and check whether their sources and targets agree with `X`, `Y`, and `Z` at "instances and reducible" transparency, -reporting any discrepancies. -/ +reporting any discrepancies. + +An example: + +``` +example (j : J) : + colimit.ι ((F ⋙ G) ⋙ H) j ≫ (preservesColimitIso (G ⋙ H) F).inv = + H.map (G.map (colimit.ι F j)) := by + + -- We know which lemma we want to use, and it's even a simp lemma, but `rw` + -- won't let us apply it + fail_if_success rw [ι_preservesColimitIso_inv] + fail_if_success rw [ι_preservesColimitIso_inv (G ⋙ H)] + fail_if_success simp only [ι_preservesColimitIso_inv] + + -- This would work: + -- erw [ι_preservesColimitIso_inv (G ⋙ H)] + + -- `check_compositions` checks if the two morphisms we're composing are + -- composed by abusing defeq, and indeed it tells us that we are abusing + -- definitional associativity of composition of functors here: it prints + -- the following. + + -- info: In composition + -- colimit.ι ((F ⋙ G) ⋙ H) j ≫ (preservesColimitIso (G ⋙ H) F).inv + -- the source of + -- (preservesColimitIso (G ⋙ H) F).inv + -- is + -- colimit (F ⋙ G ⋙ H) + -- but should be + -- colimit ((F ⋙ G) ⋙ H) + + check_compositions + + -- In this case, we can "fix" this by reassociating in the goal, but + -- usually at this point the right thing to do is to back off and + -- check how we ended up with a bad goal in the first place. + dsimp only [Functor.assoc] + + -- This would work now, but it is not needed, because simp works as well + -- rw [ι_preservesColimitIso_inv] + + simp +``` +-/ elab "check_compositions" : tactic => checkCompositionsTac end Mathlib.Tactic.CheckCompositions diff --git a/MathlibTest/CategoryTheory/CheckCompositions.lean b/MathlibTest/CategoryTheory/CheckCompositions.lean new file mode 100644 index 0000000000000..2598018866aed --- /dev/null +++ b/MathlibTest/CategoryTheory/CheckCompositions.lean @@ -0,0 +1,49 @@ +import Mathlib.CategoryTheory.Limits.Preserves.Limits +import Mathlib.Tactic.Recall + +universe v₁ v₂ v₃ v u₁ u₂ u₃ u + +open CategoryTheory Limits + +variable {J : Type u} [Category.{v} J] {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D] + {E : Type u₃} [Category.{v₃} E] (F : J ⥤ C) (G : C ⥤ D) (H : D ⥤ E) + +variable [HasColimitsOfShape J C] [HasColimitsOfShape J E] [PreservesColimit F (G ⋙ H)] + +/-- +info: In composition + colimit.ι ((F ⋙ G) ⋙ H) j ≫ (preservesColimitIso (G ⋙ H) F).inv +the source of + (preservesColimitIso (G ⋙ H) F).inv +is + colimit (F ⋙ G ⋙ H) +but should be + colimit ((F ⋙ G) ⋙ H) +-/ +#guard_msgs in +set_option linter.unusedTactic false in +example (j : J) : + colimit.ι ((F ⋙ G) ⋙ H) j ≫ (preservesColimitIso (G ⋙ H) F).inv = + H.map (G.map (colimit.ι F j)) := by + + -- We know which lemma we want to use, and it's even a simp lemma, but `rw` won't let us apply it + fail_if_success rw [ι_preservesColimitIso_inv] + fail_if_success rw [ι_preservesColimitIso_inv (G ⋙ H)] + fail_if_success simp only [ι_preservesColimitIso_inv] + + -- This would work: + -- erw [ι_preservesColimitIso_inv (G ⋙ H)] + + -- `check_compositions` checks if the two morphisms we're composing are composed by abusing defeq, + -- and indeed it tells us that we are abusing definitional associativity of composition of + -- functors here! + check_compositions + + -- In this case, we can "fix" this by reassociating in the goal, but usually at this point the + -- right thing to do is to back off and check how we ended up with a bad goal in the first place. + dsimp only [Functor.assoc] + + -- This would work now, but it is not needed, because simp works as well + -- rw [ι_preservesColimitIso_inv] + + simp From 71f75037056f896028a1cb427484453ce0cf068c Mon Sep 17 00:00:00 2001 From: Anne Baanen Date: Mon, 3 Feb 2025 16:47:37 +0000 Subject: [PATCH 041/103] feat(Topology/Category): concrete category refactor for topological spaces (#21302) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a step towards a concrete category redesign, as outlined in this Zulip post: https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/Concrete.20category.20class.20redesign/near/493903980 This PR updates the category definitions of `TopCat` and some of its descendants to match the new `ConcreteCategory` style: * Package objects and homs into structures. * Replace `HasForget` with `ConcreteCategory`. * Set up a good @[simp] set. * Ensure constructors and projections are reducible. I found many places where proofs could be cleaned up, even without looking particularly hard. 🎉 Once all the concrete category instances are in we can get rid of even more workarounds. Co-authored-by: Anne Baanen --- .../Category/ModuleCat/Presheaf/Sheafify.lean | 2 - Mathlib/AlgebraicGeometry/AffineScheme.lean | 6 +- .../Cover/MorphismProperty.lean | 2 +- Mathlib/AlgebraicGeometry/Cover/Open.lean | 4 +- .../GammaSpecAdjunction.lean | 9 +- Mathlib/AlgebraicGeometry/Gluing.lean | 14 +- Mathlib/AlgebraicGeometry/Limits.lean | 10 +- .../Morphisms/Constructors.lean | 4 +- .../Morphisms/Immersion.lean | 2 +- .../Morphisms/QuasiCompact.lean | 2 +- .../Morphisms/Separated.lean | 2 +- .../Morphisms/SurjectiveOnStalks.lean | 4 +- .../Morphisms/UnderlyingMap.lean | 2 +- Mathlib/AlgebraicGeometry/PointsPi.lean | 4 +- .../ProjectiveSpectrum/Scheme.lean | 52 +++--- Mathlib/AlgebraicGeometry/Restrict.lean | 2 +- Mathlib/AlgebraicGeometry/Scheme.lean | 8 +- Mathlib/AlgebraicGeometry/Spec.lean | 2 +- Mathlib/AlgebraicGeometry/Stalk.lean | 2 +- .../AlgebraicGeometry/ValuativeCriterion.lean | 2 +- .../FundamentalGroupoid/Basic.lean | 4 +- .../FundamentalGroupoid/InducedMaps.lean | 45 +++-- .../FundamentalGroupoid/Product.lean | 6 +- .../AlgebraicTopology/TopologicalSimplex.lean | 6 +- Mathlib/CategoryTheory/Extensive.lean | 18 +- .../Condensed/Discrete/Characterization.lean | 2 - Mathlib/Condensed/Discrete/Colimit.lean | 26 ++- .../Condensed/Discrete/LocallyConstant.lean | 41 ++--- Mathlib/Condensed/Discrete/Module.lean | 4 +- Mathlib/Condensed/Light/Epi.lean | 2 +- Mathlib/Condensed/Light/TopCatAdjunction.lean | 45 +++-- Mathlib/Condensed/TopCatAdjunction.lean | 55 +++--- Mathlib/Condensed/TopComparison.lean | 6 +- Mathlib/Geometry/Manifold/Sheaf/Basic.lean | 2 +- .../RingedSpace/LocallyRingedSpace.lean | 6 +- .../LocallyRingedSpace/HasColimits.lean | 2 +- .../Geometry/RingedSpace/OpenImmersion.lean | 14 +- .../Geometry/RingedSpace/PresheafedSpace.lean | 39 +--- .../RingedSpace/PresheafedSpace/Gluing.lean | 39 ++-- .../PresheafedSpace/HasColimits.lean | 4 +- Mathlib/Geometry/RingedSpace/Stalks.lean | 2 +- Mathlib/MeasureTheory/Category/MeasCat.lean | 5 +- .../Algebra/Category/ProfiniteGrp/Basic.lean | 61 ++++--- .../Algebra/Category/ProfiniteGrp/Limits.lean | 7 +- Mathlib/Topology/CWComplex.lean | 11 +- Mathlib/Topology/Category/CompHaus/Basic.lean | 49 ++--- .../Category/CompHaus/EffectiveEpi.lean | 2 - Mathlib/Topology/Category/CompHaus/Frm.lean | 5 +- .../Category/CompHaus/Projective.lean | 16 +- .../Topology/Category/CompHausLike/Basic.lean | 51 ++++-- .../Category/CompHausLike/EffectiveEpi.lean | 34 ++-- .../Category/CompHausLike/Limits.lean | 55 +++--- .../CompHausLike/SigmaComparison.lean | 2 +- .../Topology/Category/CompactlyGenerated.lean | 29 +-- Mathlib/Topology/Category/Compactum.lean | 12 +- Mathlib/Topology/Category/DeltaGenerated.lean | 16 +- Mathlib/Topology/Category/FinTopCat.lean | 16 +- .../Category/LightProfinite/AsLimit.lean | 4 +- .../Category/LightProfinite/Basic.lean | 35 ++-- .../Category/LightProfinite/EffectiveEpi.lean | 2 - Mathlib/Topology/Category/Locale.lean | 2 +- .../Topology/Category/Profinite/AsLimit.lean | 3 +- .../Topology/Category/Profinite/Basic.lean | 32 ++-- .../Category/Profinite/CofilteredLimit.lean | 32 ++-- .../Category/Profinite/EffectiveEpi.lean | 2 - .../Topology/Category/Profinite/Extend.lean | 4 +- .../Topology/Category/Profinite/Nobeling.lean | 7 +- .../Topology/Category/Profinite/Product.lean | 4 +- .../Category/Profinite/Projective.lean | 17 +- Mathlib/Topology/Category/Sequential.lean | 24 ++- Mathlib/Topology/Category/Stonean/Basic.lean | 38 ++-- .../Category/Stonean/EffectiveEpi.lean | 2 - Mathlib/Topology/Category/Stonean/Limits.lean | 8 +- .../Topology/Category/TopCat/Adjunctions.lean | 4 +- Mathlib/Topology/Category/TopCat/Basic.lean | 170 +++++++++++------- .../Category/TopCat/EffectiveEpi.lean | 25 ++- .../Category/TopCat/Limits/Basic.lean | 69 ++++--- .../Category/TopCat/Limits/Konig.lean | 9 +- .../Category/TopCat/Limits/Products.lean | 91 ++++------ .../Category/TopCat/Limits/Pullbacks.lean | 91 +++++----- Mathlib/Topology/Category/TopCat/Opens.lean | 20 ++- Mathlib/Topology/Category/TopCat/Yoneda.lean | 4 +- Mathlib/Topology/Category/TopCommRingCat.lean | 4 +- Mathlib/Topology/Category/UniformSpace.lean | 2 +- Mathlib/Topology/Gluing.lean | 57 +++--- Mathlib/Topology/Order/Category/AlexDisc.lean | 46 ++--- .../Order/Category/FrameAdjunction.lean | 7 +- Mathlib/Topology/Sheaves/CommRingCat.lean | 74 +++++--- Mathlib/Topology/Sheaves/LocalPredicate.lean | 2 +- .../Sheaves/SheafCondition/UniqueGluing.lean | 2 - Mathlib/Topology/Sheaves/Skyscraper.lean | 5 +- Mathlib/Topology/Sheaves/Stalks.lean | 2 +- Mathlib/Topology/Specialization.lean | 2 +- MathlibTest/slow_simp.lean | 6 +- 94 files changed, 909 insertions(+), 873 deletions(-) diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafify.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafify.lean index 1cd71c7594c0a..1e74ff70e1013 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafify.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafify.lean @@ -32,8 +32,6 @@ namespace CategoryTheory namespace Presieve.FamilyOfElements -attribute [local instance] HasForget.hasCoeToSort HasForget.instFunLike - section smul variable {R : Cᵒᵖ ⥤ RingCat.{u}} {M : PresheafOfModules.{v} R} {X : C} {P : Presieve X} diff --git a/Mathlib/AlgebraicGeometry/AffineScheme.lean b/Mathlib/AlgebraicGeometry/AffineScheme.lean index cc8afa1e32204..b4abde67aa374 100644 --- a/Mathlib/AlgebraicGeometry/AffineScheme.lean +++ b/Mathlib/AlgebraicGeometry/AffineScheme.lean @@ -374,7 +374,7 @@ theorem range_fromSpec : delta IsAffineOpen.fromSpec; dsimp [IsAffineOpen.isoSpec_inv] rw [Set.range_comp, Set.range_eq_univ.mpr, Set.image_univ] · exact Subtype.range_coe - rw [← coe_comp, ← TopCat.epi_iff_surjective] + rw [← TopCat.coe_comp, ← TopCat.epi_iff_surjective] infer_instance @[simp] @@ -448,9 +448,9 @@ theorem _root_.AlgebraicGeometry.Scheme.Hom.isAffineOpen_iff_of_isOpenImmersion refine ⟨fun hU => @isAffine_of_isIso _ _ (IsOpenImmersion.isoOfRangeEq (X.ofRestrict U.isOpenEmbedding ≫ f) (Y.ofRestrict _) ?_).hom ?_ hU, fun hU => hU.image_of_isOpenImmersion f⟩ - · rw [Scheme.comp_base, coe_comp, Set.range_comp] + · rw [Scheme.comp_base, TopCat.coe_comp, Set.range_comp] dsimp [Opens.coe_inclusion', Scheme.restrict] - erw [Subtype.range_coe, Subtype.range_coe] -- now `erw` after https://github.com/leanprover-community/mathlib4/pull/13170 + rw [Subtype.range_coe, Subtype.range_coe] rfl · infer_instance diff --git a/Mathlib/AlgebraicGeometry/Cover/MorphismProperty.lean b/Mathlib/AlgebraicGeometry/Cover/MorphismProperty.lean index 042468ac880d9..57cf17e2d2e93 100644 --- a/Mathlib/AlgebraicGeometry/Cover/MorphismProperty.lean +++ b/Mathlib/AlgebraicGeometry/Cover/MorphismProperty.lean @@ -113,7 +113,7 @@ def Cover.bind [P.IsStableUnderComposition] (f : ∀ x : 𝒰.J, (𝒰.obj x).Co rcases (f (𝒰.f x)).covers y with ⟨z, hz⟩ change x ∈ Set.range ((f (𝒰.f x)).map ((f (𝒰.f x)).f y) ≫ 𝒰.map (𝒰.f x)).base use z - erw [CategoryTheory.comp_apply] + simp only [comp_coeBase, TopCat.hom_comp, ContinuousMap.comp_apply] rw [hz, hy] map_prop _ := P.comp_mem _ _ ((f _).map_prop _) (𝒰.map_prop _) diff --git a/Mathlib/AlgebraicGeometry/Cover/Open.lean b/Mathlib/AlgebraicGeometry/Cover/Open.lean index a6ec6c2082cb2..c21c1e5f1caab 100644 --- a/Mathlib/AlgebraicGeometry/Cover/Open.lean +++ b/Mathlib/AlgebraicGeometry/Cover/Open.lean @@ -274,7 +274,7 @@ theorem affineBasisCover_map_range (X : Scheme.{u}) (x : X) (r : (X.local_affine x).choose_spec.choose) : Set.range (X.affineBasisCover.map ⟨x, r⟩).base = (X.affineCover.map x).base '' (PrimeSpectrum.basicOpen r).1 := by - erw [coe_comp, Set.range_comp] + erw [TopCat.coe_comp, Set.range_comp] -- Porting note: `congr` fails to see the goal is comparing image of the same function refine congr_arg (_ '' ·) ?_ exact (PrimeSpectrum.localization_away_comap_range (Localization.Away r) r :) @@ -291,7 +291,7 @@ theorem affineBasisCover_is_basis (X : Scheme.{u}) : let U' := (X.affineCover.map (X.affineCover.f a)).base ⁻¹' U have hxU' : x ∈ U' := by rw [← e] at haU; exact haU rcases PrimeSpectrum.isBasis_basic_opens.exists_subset_of_mem_open hxU' - ((X.affineCover.map (X.affineCover.f a)).base.continuous_toFun.isOpen_preimage _ + ((X.affineCover.map (X.affineCover.f a)).base.hom.continuous_toFun.isOpen_preimage _ hU) with ⟨_, ⟨_, ⟨s, rfl⟩, rfl⟩, hxV, hVU⟩ refine ⟨_, ⟨⟨_, s⟩, rfl⟩, ?_, ?_⟩ <;> rw [affineBasisCover_map_range] diff --git a/Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean b/Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean index b897c89abc30f..dd66da6f92dd1 100644 --- a/Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean +++ b/Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean @@ -88,9 +88,10 @@ theorem toΓSpec_continuous : Continuous X.toΓSpecFun := by /-- The canonical (bundled) continuous map from the underlying topological space of `X` to the prime spectrum of its global sections. -/ -def toΓSpecBase : X.toTopCat ⟶ Spec.topObj (Γ.obj (op X)) where - toFun := X.toΓSpecFun - continuous_toFun := X.toΓSpec_continuous +def toΓSpecBase : X.toTopCat ⟶ Spec.topObj (Γ.obj (op X)) := + TopCat.ofHom + { toFun := X.toΓSpecFun + continuous_toFun := X.toΓSpec_continuous } variable (r : Γ.obj (op X)) @@ -300,7 +301,7 @@ theorem right_triangle (R : CommRingCat) : apply LocallyRingedSpace.comp_ring_hom_ext · ext (p : PrimeSpectrum R) dsimp - ext x + refine PrimeSpectrum.ext (Ideal.ext fun x => ?_) erw [← IsLocalization.AtPrime.to_map_mem_maximal_iff ((structureSheaf R).presheaf.stalk p) p.asIdeal x] rfl diff --git a/Mathlib/AlgebraicGeometry/Gluing.lean b/Mathlib/AlgebraicGeometry/Gluing.lean index 2fd42825b08b6..32baf4533398b 100644 --- a/Mathlib/AlgebraicGeometry/Gluing.lean +++ b/Mathlib/AlgebraicGeometry/Gluing.lean @@ -226,7 +226,7 @@ theorem ι_eq_iff (i j : D.J) (x : (D.U i).carrier) (y : (D.U j).carrier) : (TopCat.GlueData.ι_eq_iff_rel D.toLocallyRingedSpaceGlueData.toSheafedSpaceGlueData.toPresheafedSpaceGlueData.toTopGlueData i j x y) - rw [← ((TopCat.mono_iff_injective D.isoCarrier.inv).mp _).eq_iff, ← CategoryTheory.comp_apply] + rw [← ((TopCat.mono_iff_injective D.isoCarrier.inv).mp _).eq_iff, ← ConcreteCategory.comp_apply] · simp_rw [← D.ι_isoCarrier_inv] rfl -- `rfl` was not needed before https://github.com/leanprover-community/mathlib4/pull/13170 · infer_instance @@ -338,7 +338,7 @@ theorem fromGlued_injective : Function.Injective 𝒰.fromGlued.base := by intro x y h obtain ⟨i, x, rfl⟩ := 𝒰.gluedCover.ι_jointly_surjective x obtain ⟨j, y, rfl⟩ := 𝒰.gluedCover.ι_jointly_surjective y - rw [← CategoryTheory.comp_apply, ← CategoryTheory.comp_apply] at h + rw [← ConcreteCategory.comp_apply, ← ConcreteCategory.comp_apply] at h simp_rw [← Scheme.comp_base] at h rw [ι_fromGlued, ι_fromGlued] at h let e := @@ -347,8 +347,10 @@ theorem fromGlued_injective : Function.Injective 𝒰.fromGlued.base := by rw [𝒰.gluedCover.ι_eq_iff] use e.hom ⟨⟨x, y⟩, h⟩ constructor - · erw [← comp_apply e.hom, IsLimit.conePointUniqueUpToIso_hom_comp _ _ WalkingCospan.left]; rfl - · erw [← comp_apply e.hom, pullbackSymmetry_hom_comp_fst, + · erw [← ConcreteCategory.comp_apply e.hom, + IsLimit.conePointUniqueUpToIso_hom_comp _ _ WalkingCospan.left] + rfl + · erw [← ConcreteCategory.comp_apply e.hom, pullbackSymmetry_hom_comp_fst, IsLimit.conePointUniqueUpToIso_hom_comp _ _ WalkingCospan.right] rfl @@ -371,7 +373,7 @@ theorem fromGlued_open_map : IsOpenMap 𝒰.fromGlued.base := by · rw [← Set.image_preimage_eq_inter_range] apply (show IsOpenImmersion (𝒰.map (𝒰.f x)) from inferInstance).base_open.isOpenMap convert hU (𝒰.f x) using 1 - rw [← ι_fromGlued]; erw [coe_comp]; rw [Set.preimage_comp] + rw [← ι_fromGlued]; erw [TopCat.coe_comp]; rw [Set.preimage_comp] congr! 1 exact Set.preimage_image_eq _ 𝒰.fromGlued_injective · exact ⟨hx, 𝒰.covers x⟩ @@ -387,7 +389,7 @@ instance : Epi 𝒰.fromGlued.base := by intro x obtain ⟨y, h⟩ := 𝒰.covers x use (𝒰.gluedCover.ι (𝒰.f x)).base y - rw [← CategoryTheory.comp_apply] + rw [← ConcreteCategory.comp_apply] rw [← 𝒰.ι_fromGlued (𝒰.f x)] at h exact h diff --git a/Mathlib/AlgebraicGeometry/Limits.lean b/Mathlib/AlgebraicGeometry/Limits.lean index e28bfdee6c290..a6d3e6d69c558 100644 --- a/Mathlib/AlgebraicGeometry/Limits.lean +++ b/Mathlib/AlgebraicGeometry/Limits.lean @@ -64,7 +64,7 @@ section Initial /-- The map from the empty scheme. -/ @[simps] def Scheme.emptyTo (X : Scheme.{u}) : ∅ ⟶ X := - ⟨{ base := ⟨fun x => PEmpty.elim x, by fun_prop⟩ + ⟨{ base := TopCat.ofHom ⟨fun x => PEmpty.elim x, by fun_prop⟩ c := { app := fun _ => CommRingCat.punitIsTerminal.from _ } }, fun x => PEmpty.elim x⟩ @[ext] @@ -99,7 +99,7 @@ instance (priority := 100) isOpenImmersion_of_isEmpty {X Y : Scheme} (f : X ⟶ instance (priority := 100) isIso_of_isEmpty {X Y : Scheme} (f : X ⟶ Y) [IsEmpty Y] : IsIso f := by - haveI : IsEmpty X := f.base.1.isEmpty + haveI : IsEmpty X := f.base.hom.1.isEmpty have : Epi f.base := by rw [TopCat.epi_iff_surjective]; rintro (x : Y) exact isEmptyElim x @@ -310,7 +310,7 @@ lemma sigmaMk_mk (i) (x : f i) : show ((TopCat.sigmaCofan (fun x ↦ (f x).toTopCat)).inj i ≫ (colimit.isoColimitCocone ⟨_, TopCat.sigmaCofanIsColimit _⟩).inv ≫ _) x = Scheme.forgetToTop.map (Sigma.ι f i) x - congr 1 + congr 2 refine (colimit.isoColimitCocone_ι_inv_assoc ⟨_, TopCat.sigmaCofanIsColimit _⟩ _ _).trans ?_ exact ι_comp_sigmaComparison Scheme.forgetToTop _ _ @@ -388,7 +388,7 @@ lemma coprodMk_inl (x : X) : show ((TopCat.binaryCofan X Y).inl ≫ (colimit.isoColimitCocone ⟨_, TopCat.binaryCofanIsColimit _ _⟩).inv ≫ _) x = Scheme.forgetToTop.map coprod.inl x - congr 1 + congr 2 refine (colimit.isoColimitCocone_ι_inv_assoc ⟨_, TopCat.binaryCofanIsColimit _ _⟩ _ _).trans ?_ exact coprodComparison_inl Scheme.forgetToTop @@ -398,7 +398,7 @@ lemma coprodMk_inr (x : Y) : show ((TopCat.binaryCofan X Y).inr ≫ (colimit.isoColimitCocone ⟨_, TopCat.binaryCofanIsColimit _ _⟩).inv ≫ _) x = Scheme.forgetToTop.map coprod.inr x - congr 1 + congr 2 refine (colimit.isoColimitCocone_ι_inv_assoc ⟨_, TopCat.binaryCofanIsColimit _ _⟩ _ _).trans ?_ exact coprodComparison_inr Scheme.forgetToTop diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Constructors.lean b/Mathlib/AlgebraicGeometry/Morphisms/Constructors.lean index 3cd9d1cbcdddb..dff41458fbd25 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Constructors.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Constructors.lean @@ -229,9 +229,9 @@ lemma topologically_isLocalAtTarget apply IsLocalAtTarget.mk' · intro X Y f U hf simp_rw [topologically, morphismRestrict_base] - exact hP₂ f.base U.carrier f.base.2 U.2 hf + exact hP₂ f.base U.carrier f.base.hom.2 U.2 hf · intro X Y f ι U hU hf - apply hP₃ f.base U hU f.base.continuous fun i ↦ ?_ + apply hP₃ f.base U hU f.base.hom.continuous fun i ↦ ?_ rw [← morphismRestrict_base] exact hf i diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Immersion.lean b/Mathlib/AlgebraicGeometry/Morphisms/Immersion.lean index a03d46fd9e830..f3fc346cc6c07 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Immersion.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Immersion.lean @@ -137,7 +137,7 @@ theorem of_comp {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [IsImmersion g] __ := IsPreimmersion.of_comp f g isLocallyClosed_range := by rw [← Set.preimage_image_eq (Set.range _) g.isEmbedding.injective] - have := (f ≫ g).isLocallyClosed_range.preimage g.base.2 + have := (f ≫ g).isLocallyClosed_range.preimage g.base.hom.2 simpa only [Scheme.comp_coeBase, TopCat.coe_comp, Set.range_comp] using this theorem comp_iff {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [IsImmersion g] : diff --git a/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean b/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean index a941013a085e5..63fb1ec953a18 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean @@ -47,7 +47,7 @@ instance (priority := 900) quasiCompact_of_isIso {X Y : Scheme} (f : X ⟶ Y) [I QuasiCompact f := by constructor intro U _ hU' - convert hU'.image (inv f.base).continuous_toFun using 1 + convert hU'.image (inv f.base).hom.continuous_toFun using 1 rw [Set.image_eq_preimage_of_inverse] · delta Function.LeftInverse exact IsIso.inv_hom_id_apply f.base diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Separated.lean b/Mathlib/AlgebraicGeometry/Morphisms/Separated.lean index 6c6b1821adf90..96f3f41857075 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Separated.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Separated.lean @@ -158,7 +158,7 @@ lemma Scheme.Pullback.range_diagonal_subset_diagonalCoverDiagonalRange : rw [← hz₁, ← hy, ← Scheme.comp_base_apply, ← Scheme.comp_base_apply] dsimp only [diagonalCover, Cover.pullbackHom, Cover.bind_obj, openCoverOfLeftRight_obj] rw [← Scheme.comp_base_apply] - congr 4 + congr 5 apply pullback.hom_ext <;> simp lemma isClosedImmersion_diagonal_restrict_diagonalCoverDiagonalRange diff --git a/Mathlib/AlgebraicGeometry/Morphisms/SurjectiveOnStalks.lean b/Mathlib/AlgebraicGeometry/Morphisms/SurjectiveOnStalks.lean index 3d2e4bc11f7d8..56e5c8780547a 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/SurjectiveOnStalks.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/SurjectiveOnStalks.lean @@ -166,7 +166,7 @@ lemma isEmbedding_pullback {X Y S : Scheme.{u}} (f : X ⟶ S) (g : Y ⟶ S) [Sur · dsimp only rw [← hx₁', ← hz, ← Scheme.comp_base_apply] erw [← Scheme.comp_base_apply] - congr 4 + congr 5 apply pullback.hom_ext <;> simp [𝓤, ← pullback.condition, ← pullback.condition_assoc] · intro i have := H (S.affineOpenCover.obj i.1) (((𝒰.pullbackCover f).obj i.1).affineOpenCover.obj i.2.1) @@ -177,7 +177,7 @@ lemma isEmbedding_pullback {X Y S : Scheme.{u}} (f : X ⟶ S) (g : Y ⟶ S) [Sur ((𝒲 i.1).map i.2.2 ≫ (𝒰.pullbackCover g).map i.1) (𝒰.map i.1) (by simp [pullback.condition]) (by simp [pullback.condition]) inferInstance inferInstance inferInstance - convert this using 6 + convert this using 7 apply pullback.hom_ext <;> simp [𝓤, ← pullback.condition, ← pullback.condition_assoc, Scheme.Cover.pullbackHom] diff --git a/Mathlib/AlgebraicGeometry/Morphisms/UnderlyingMap.lean b/Mathlib/AlgebraicGeometry/Morphisms/UnderlyingMap.lean index 261a9341b50e4..7e46b285cec38 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/UnderlyingMap.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/UnderlyingMap.lean @@ -174,7 +174,7 @@ lemma Scheme.Hom.denseRange (f : X.Hom Y) [IsDominant f] : DenseRange f.base := instance (priority := 100) [Surjective f] : IsDominant f := ⟨f.surjective.denseRange⟩ instance [IsDominant f] [IsDominant g] : IsDominant (f ≫ g) := - ⟨g.denseRange.comp f.denseRange g.base.2⟩ + ⟨g.denseRange.comp f.denseRange g.base.hom.2⟩ instance : MorphismProperty.IsMultiplicative @IsDominant where id_mem := fun _ ↦ inferInstance diff --git a/Mathlib/AlgebraicGeometry/PointsPi.lean b/Mathlib/AlgebraicGeometry/PointsPi.lean index f430d0a60fda2..a9ebeba3e62e1 100644 --- a/Mathlib/AlgebraicGeometry/PointsPi.lean +++ b/Mathlib/AlgebraicGeometry/PointsPi.lean @@ -76,7 +76,7 @@ lemma isIso_of_comp_eq_sigmaSpec {V : Scheme} have : g.coborderRange = ⊤ := by apply eq_top_of_sigmaSpec_subset_of_isCompact (hVU := subset_coborder) · simpa only [← hU'] using Set.range_comp_subset_range f.base g.base - · exact isCompact_range g.base.2 + · exact isCompact_range g.base.hom.2 have : IsClosedImmersion g := by have : IsIso g.coborderRange.ι := by rw [this, ← Scheme.topIso_hom]; infer_instance rw [← g.liftCoborder_ι] @@ -118,7 +118,7 @@ lemma pointsPi_surjective [CompactSpace X] [∀ i, IsLocalRing (R i)] : have (i) : ∃ j, Set.range (f i).base ⊆ (𝒰.map j).opensRange := by refine ⟨𝒰.f ((f i).base (IsLocalRing.closedPoint (R i))), ?_⟩ rintro _ ⟨x, rfl⟩ - exact ((IsLocalRing.specializes_closedPoint x).map (f i).base.2).mem_open + exact ((IsLocalRing.specializes_closedPoint x).map (f i).base.hom.2).mem_open (𝒰.map _).opensRange.2 (𝒰.covers _) choose j hj using this have (j₀) := pointsPi_surjective_of_isAffine (ι := { i // j i = j₀ }) (R ·) (𝒰.obj j₀) diff --git a/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean index 91892e6714502..c496fa978f0bb 100644 --- a/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean +++ b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean @@ -212,15 +212,16 @@ section /-- The continuous function from the basic open set `D(f)` in `Proj` to the corresponding basic open set in `Spec A⁰_f`. -/ -@[simps! (config := .lemmasOnly) apply_asIdeal] -def toSpec (f : A) : (Proj.T| pbo f) ⟶ Spec.T A⁰_ f where - toFun := ToSpec.toFun f - continuous_toFun := by - rw [PrimeSpectrum.isTopologicalBasis_basic_opens.continuous_iff] - rintro _ ⟨x, rfl⟩ - obtain ⟨x, rfl⟩ := Quotient.mk''_surjective x - rw [ToSpec.preimage_basicOpen] - exact (pbo x.num).2.preimage continuous_subtype_val +@[simps! (config := .lemmasOnly) hom_apply_asIdeal] +def toSpec (f : A) : (Proj.T| pbo f) ⟶ Spec.T A⁰_ f := + TopCat.ofHom + { toFun := ToSpec.toFun f + continuous_toFun := by + rw [PrimeSpectrum.isTopologicalBasis_basic_opens.continuous_iff] + rintro _ ⟨x, rfl⟩ + obtain ⟨x, rfl⟩ := Quotient.mk''_surjective x + rw [ToSpec.preimage_basicOpen] + exact (pbo x.num).2.preimage continuous_subtype_val } variable {𝒜} in lemma toSpec_preimage_basicOpen {f} (z : HomogeneousLocalization.NumDenSameDeg 𝒜 (.powers f)) : @@ -543,21 +544,22 @@ variable {𝒜} in /-- The continuous function `Spec A⁰_f → Proj|D(f)` sending `q` to `{a | aᵢᵐ/fⁱ ∈ q}` where `m` is the degree of `f` -/ def fromSpec {f : A} {m : ℕ} (f_deg : f ∈ 𝒜 m) (hm : 0 < m) : - (Spec.T (A⁰_ f)) ⟶ (Proj.T| (pbo f)) where - toFun := FromSpec.toFun f_deg hm - continuous_toFun := by - rw [isTopologicalBasis_subtype (ProjectiveSpectrum.isTopologicalBasis_basic_opens 𝒜) (pbo f).1 - |>.continuous_iff] - rintro s ⟨_, ⟨a, rfl⟩, rfl⟩ - have h₁ : Subtype.val (p := (pbo f).1) ⁻¹' (pbo a) = - ⋃ i : ℕ, Subtype.val (p := (pbo f).1) ⁻¹' (pbo (decompose 𝒜 a i)) := by - simp [ProjectiveSpectrum.basicOpen_eq_union_of_projection 𝒜 a] - let e : _ ≃ _ := - ⟨FromSpec.toFun f_deg hm, ToSpec.toFun f, toSpec_fromSpec _ _ _, fromSpec_toSpec _ _ _⟩ - change IsOpen <| e ⁻¹' _ - rw [Set.preimage_equiv_eq_image_symm, h₁, Set.image_iUnion] - exact isOpen_iUnion fun i ↦ toSpec.image_basicOpen_eq_basicOpen f_deg hm a i ▸ - PrimeSpectrum.isOpen_basicOpen + (Spec.T (A⁰_ f)) ⟶ (Proj.T| (pbo f)) := + TopCat.ofHom + { toFun := FromSpec.toFun f_deg hm + continuous_toFun := by + rw [isTopologicalBasis_subtype (ProjectiveSpectrum.isTopologicalBasis_basic_opens 𝒜) (pbo f).1 + |>.continuous_iff] + rintro s ⟨_, ⟨a, rfl⟩, rfl⟩ + have h₁ : Subtype.val (p := (pbo f).1) ⁻¹' (pbo a) = + ⋃ i : ℕ, Subtype.val (p := (pbo f).1) ⁻¹' (pbo (decompose 𝒜 a i)) := by + simp [ProjectiveSpectrum.basicOpen_eq_union_of_projection 𝒜 a] + let e : _ ≃ _ := + ⟨FromSpec.toFun f_deg hm, ToSpec.toFun f, toSpec_fromSpec _ _ _, fromSpec_toSpec _ _ _⟩ + change IsOpen <| e ⁻¹' _ + rw [Set.preimage_equiv_eq_image_symm, h₁, Set.image_iUnion] + exact isOpen_iUnion fun i ↦ toSpec.image_basicOpen_eq_basicOpen f_deg hm a i ▸ + PrimeSpectrum.isOpen_basicOpen } end ProjIsoSpecTopComponent @@ -672,7 +674,7 @@ lemma toSpec_base_apply_eq {f} (x : Proj| pbo f) : lemma toSpec_base_isIso {f} {m} (f_deg : f ∈ 𝒜 m) (hm : 0 < m) : IsIso (toSpec 𝒜 f).base := by convert (projIsoSpecTopComponent f_deg hm).isIso_hom - exact DFunLike.ext _ _ <| toSpec_base_apply_eq 𝒜 + exact ConcreteCategory.hom_ext _ _ <| toSpec_base_apply_eq 𝒜 lemma mk_mem_toSpec_base_apply {f} (x : Proj| pbo f) (z : NumDenSameDeg 𝒜 (.powers f)) : diff --git a/Mathlib/AlgebraicGeometry/Restrict.lean b/Mathlib/AlgebraicGeometry/Restrict.lean index d82bc0979eb00..ad0701e07ad58 100644 --- a/Mathlib/AlgebraicGeometry/Restrict.lean +++ b/Mathlib/AlgebraicGeometry/Restrict.lean @@ -243,7 +243,7 @@ theorem Scheme.homOfLE_apply {U V : X.Opens} (e : U ≤ V) (x : U) : theorem Scheme.ι_image_homOfLE_le_ι_image {U V : X.Opens} (e : U ≤ V) (W : Opens V) : U.ι ''ᵁ (X.homOfLE e ⁻¹ᵁ W) ≤ V.ι ''ᵁ W := by simp only [← SetLike.coe_subset_coe, IsOpenMap.coe_functor_obj, Set.image_subset_iff, - Scheme.homOfLE_base, Opens.map_coe, Opens.inclusion'_apply] + Scheme.homOfLE_base, Opens.map_coe, Opens.inclusion'_hom_apply] rintro _ h exact ⟨_, h, rfl⟩ diff --git a/Mathlib/AlgebraicGeometry/Scheme.lean b/Mathlib/AlgebraicGeometry/Scheme.lean index ef49d929d8d24..4d83cc76b9ee3 100644 --- a/Mathlib/AlgebraicGeometry/Scheme.lean +++ b/Mathlib/AlgebraicGeometry/Scheme.lean @@ -93,7 +93,7 @@ instance {X : Scheme.{u}} : Subsingleton Γ(X, ⊥) := CommRingCat.subsingleton_of_isTerminal X.sheaf.isTerminalOfEmpty @[continuity, fun_prop] -lemma Hom.continuous {X Y : Scheme} (f : X.Hom Y) : Continuous f.base := f.base.2 +lemma Hom.continuous {X Y : Scheme} (f : X.Hom Y) : Continuous f.base := f.base.hom.2 /-- The structure sheaf of a scheme. -/ protected abbrev sheaf (X : Scheme) := @@ -407,7 +407,7 @@ variable {R S : CommRingCat.{u}} (f : R ⟶ S) lemma Spec_carrier (R : CommRingCat.{u}) : (Spec R).carrier = PrimeSpectrum R := rfl lemma Spec_sheaf (R : CommRingCat.{u}) : (Spec R).sheaf = Spec.structureSheaf R := rfl lemma Spec_presheaf (R : CommRingCat.{u}) : (Spec R).presheaf = (Spec.structureSheaf R).1 := rfl -lemma Spec.map_base : (Spec.map f).base = PrimeSpectrum.comap f.hom := rfl +lemma Spec.map_base : (Spec.map f).base = ofHom (PrimeSpectrum.comap f.hom) := rfl lemma Spec.map_base_apply (x : Spec S) : (Spec.map f).base x = PrimeSpectrum.comap f.hom x := rfl lemma Spec.map_app (U) : @@ -765,12 +765,12 @@ lemma stalkMap_comp {X Y Z : Scheme.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) (x : X) : @[reassoc] lemma stalkSpecializes_stalkMap (x x' : X) - (h : x ⤳ x') : Y.presheaf.stalkSpecializes (f.base.map_specializes h) ≫ f.stalkMap x = + (h : x ⤳ x') : Y.presheaf.stalkSpecializes (f.base.hom.map_specializes h) ≫ f.stalkMap x = f.stalkMap x' ≫ X.presheaf.stalkSpecializes h := PresheafedSpace.stalkMap.stalkSpecializes_stalkMap f.toPshHom h lemma stalkSpecializes_stalkMap_apply (x x' : X) (h : x ⤳ x') (y) : - f.stalkMap x (Y.presheaf.stalkSpecializes (f.base.map_specializes h) y) = + f.stalkMap x (Y.presheaf.stalkSpecializes (f.base.hom.map_specializes h) y) = (X.presheaf.stalkSpecializes h (f.stalkMap x' y)) := DFunLike.congr_fun (CommRingCat.hom_ext_iff.mp (stalkSpecializes_stalkMap f x x' h)) y diff --git a/Mathlib/AlgebraicGeometry/Spec.lean b/Mathlib/AlgebraicGeometry/Spec.lean index 26b9f817d1bf5..702a4628cbccd 100644 --- a/Mathlib/AlgebraicGeometry/Spec.lean +++ b/Mathlib/AlgebraicGeometry/Spec.lean @@ -60,7 +60,7 @@ def Spec.topObj (R : CommRingCat.{u}) : TopCat := /-- The induced map of a ring homomorphism on the ring spectra, as a morphism of topological spaces. -/ def Spec.topMap {R S : CommRingCat.{u}} (f : R ⟶ S) : Spec.topObj S ⟶ Spec.topObj R := - PrimeSpectrum.comap f.hom + TopCat.ofHom (PrimeSpectrum.comap f.hom) @[simp] theorem Spec.topMap_id (R : CommRingCat.{u}) : Spec.topMap (𝟙 R) = 𝟙 (Spec.topObj R) := diff --git a/Mathlib/AlgebraicGeometry/Stalk.lean b/Mathlib/AlgebraicGeometry/Stalk.lean index 54411c0594348..bb906440d7167 100644 --- a/Mathlib/AlgebraicGeometry/Stalk.lean +++ b/Mathlib/AlgebraicGeometry/Stalk.lean @@ -165,7 +165,7 @@ lemma range_fromSpecStalk {x : X} : ext y constructor · rintro ⟨y, rfl⟩ - exact ((IsLocalRing.specializes_closedPoint y).map (X.fromSpecStalk x).base.2).trans + exact ((IsLocalRing.specializes_closedPoint y).map (X.fromSpecStalk x).base.hom.2).trans (specializes_of_eq fromSpecStalk_closedPoint) · rintro (hy : y ⤳ x) have := fromSpecStalk_closedPoint (x := y) diff --git a/Mathlib/AlgebraicGeometry/ValuativeCriterion.lean b/Mathlib/AlgebraicGeometry/ValuativeCriterion.lean index 779bb1acde6bf..56011e0fdefa0 100644 --- a/Mathlib/AlgebraicGeometry/ValuativeCriterion.lean +++ b/Mathlib/AlgebraicGeometry/ValuativeCriterion.lean @@ -126,7 +126,7 @@ lemma specializingMap (H : ValuativeCriterion.Existence f) : dsimp only at hl₁ hl₂ refine ⟨l.base (closedPoint A), ?_, ?_⟩ · simp_rw [← Scheme.fromSpecResidueField_apply x' (closedPoint (X.residueField x')), ← hl₁] - exact (specializes_closedPoint _).map l.base.2 + exact (specializes_closedPoint _).map l.base.hom.2 · rw [← Scheme.comp_base_apply, hl₂] simp only [Scheme.comp_coeBase, TopCat.coe_comp, Function.comp_apply] have : (Spec.map stalk_y_to_A).base (closedPoint A) = closedPoint (Y.presheaf.stalk y) := diff --git a/Mathlib/AlgebraicTopology/FundamentalGroupoid/Basic.lean b/Mathlib/AlgebraicTopology/FundamentalGroupoid/Basic.lean index 441b8fdab6dd2..8921a14938819 100644 --- a/Mathlib/AlgebraicTopology/FundamentalGroupoid/Basic.lean +++ b/Mathlib/AlgebraicTopology/FundamentalGroupoid/Basic.lean @@ -336,7 +336,7 @@ def fundamentalGroupoidFunctor : TopCat ⥤ CategoryTheory.Grpd where obj X := { α := FundamentalGroupoid X } map f := { obj := fun x => ⟨f x.as⟩ - map := fun {X Y} p => by exact Path.Homotopic.Quotient.mapFn p f + map := fun {X Y} p => by exact Path.Homotopic.Quotient.mapFn p f.hom map_id := fun _ => rfl map_comp := fun {x y z} p q => by refine Quotient.inductionOn₂ p q fun a b => ?_ @@ -367,7 +367,7 @@ scoped notation "πₓ" => FundamentalGroupoid.fundamentalGroupoidFunctor.obj scoped notation "πₘ" => FundamentalGroupoid.fundamentalGroupoidFunctor.map theorem map_eq {X Y : TopCat} {x₀ x₁ : X} (f : C(X, Y)) (p : Path.Homotopic.Quotient x₀ x₁) : - (πₘ f).map p = p.mapFn f := rfl + (πₘ (TopCat.ofHom f)).map p = p.mapFn f := rfl /-- Help the typechecker by converting a point in a groupoid back to a point in the underlying topological space. -/ diff --git a/Mathlib/AlgebraicTopology/FundamentalGroupoid/InducedMaps.lean b/Mathlib/AlgebraicTopology/FundamentalGroupoid/InducedMaps.lean index 4ba7cc3bd0912..a4536f3e7d25e 100644 --- a/Mathlib/AlgebraicTopology/FundamentalGroupoid/InducedMaps.lean +++ b/Mathlib/AlgebraicTopology/FundamentalGroupoid/InducedMaps.lean @@ -87,7 +87,8 @@ include hfg /-- If `f(p(t) = g(q(t))` for two paths `p` and `q`, then the induced path homotopy classes `f(p)` and `g(p)` are the same as well, despite having a priori different types -/ -theorem heq_path_of_eq_image : HEq ((πₘ f).map ⟦p⟧) ((πₘ g).map ⟦q⟧) := by +theorem heq_path_of_eq_image : + HEq ((πₘ (TopCat.ofHom f)).map ⟦p⟧) ((πₘ (TopCat.ofHom g)).map ⟦q⟧) := by simp only [map_eq, ← Path.Homotopic.map_lift]; apply Path.Homotopic.hpath_hext; exact hfg private theorem start_path : f x₀ = g x₂ := by convert hfg 0 <;> simp only [Path.source] @@ -95,9 +96,10 @@ private theorem start_path : f x₀ = g x₂ := by convert hfg 0 <;> simp only [ private theorem end_path : f x₁ = g x₃ := by convert hfg 1 <;> simp only [Path.target] theorem eq_path_of_eq_image : - (πₘ f).map ⟦p⟧ = hcast (start_path hfg) ≫ (πₘ g).map ⟦q⟧ ≫ hcast (end_path hfg).symm := by + (πₘ (TopCat.ofHom f)).map ⟦p⟧ = + hcast (start_path hfg) ≫ (πₘ (TopCat.ofHom g)).map ⟦q⟧ ≫ hcast (end_path hfg).symm := by rw [conj_eqToHom_iff_heq - ((πₘ f).map ⟦p⟧) ((πₘ g).map ⟦q⟧) + ((πₘ (TopCat.ofHom f)).map ⟦p⟧) ((πₘ (TopCat.ofHom g)).map ⟦q⟧) (FundamentalGroupoid.ext <| start_path hfg) (FundamentalGroupoid.ext <| end_path hfg)] exact heq_path_of_eq_image hfg @@ -147,33 +149,37 @@ abbrev prodToProdTopI {a₁ a₂ : TopCat.of (ULift I)} {b₁ b₂ : X} (p₁ : /-- The diagonal path `d` of a homotopy `H` on a path `p` -/ def diagonalPath : fromTop (H (0, x₀)) ⟶ fromTop (H (1, x₁)) := - (πₘ H.uliftMap).map (prodToProdTopI uhpath01 p) + (πₘ (TopCat.ofHom H.uliftMap)).map (prodToProdTopI uhpath01 p) /-- The diagonal path, but starting from `f x₀` and going to `g x₁` -/ def diagonalPath' : fromTop (f x₀) ⟶ fromTop (g x₁) := hcast (H.apply_zero x₀).symm ≫ H.diagonalPath p ≫ hcast (H.apply_one x₁) /-- Proof that `f(p) = H(0 ⟶ 0, p)`, with the appropriate casts -/ -theorem apply_zero_path : (πₘ f).map p = hcast (H.apply_zero x₀).symm ≫ - (πₘ H.uliftMap).map (prodToProdTopI (𝟙 (@fromTop (TopCat.of _) (ULift.up 0))) p) ≫ +theorem apply_zero_path : (πₘ (TopCat.ofHom f)).map p = hcast (H.apply_zero x₀).symm ≫ + (πₘ (TopCat.ofHom H.uliftMap)).map + (prodToProdTopI (𝟙 (@fromTop (TopCat.of _) (ULift.up 0))) p) ≫ hcast (H.apply_zero x₁) := Quotient.inductionOn p fun p' => by apply @eq_path_of_eq_image _ _ _ _ H.uliftMap _ _ _ _ _ ((Path.refl (ULift.up _)).prod p') - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [Path.prod_coe]; simp_rw [ulift_apply]; simp + intros + rw [Path.prod_coe, ulift_apply H] + simp /-- Proof that `g(p) = H(1 ⟶ 1, p)`, with the appropriate casts -/ -theorem apply_one_path : (πₘ g).map p = hcast (H.apply_one x₀).symm ≫ - (πₘ H.uliftMap).map (prodToProdTopI (𝟙 (@fromTop (TopCat.of _) (ULift.up 1))) p) ≫ +theorem apply_one_path : (πₘ (TopCat.ofHom g)).map p = hcast (H.apply_one x₀).symm ≫ + (πₘ (TopCat.ofHom H.uliftMap)).map + (prodToProdTopI (𝟙 (@fromTop (TopCat.of _) (ULift.up 1))) p) ≫ hcast (H.apply_one x₁) := Quotient.inductionOn p fun p' => by apply @eq_path_of_eq_image _ _ _ _ H.uliftMap _ _ _ _ _ ((Path.refl (ULift.up _)).prod p') - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [Path.prod_coe]; simp_rw [ulift_apply]; simp + intros + rw [Path.prod_coe, ulift_apply H] + simp /-- Proof that `H.evalAt x = H(0 ⟶ 1, x ⟶ x)`, with the appropriate casts -/ theorem evalAt_eq (x : X) : ⟦H.evalAt x⟧ = hcast (H.apply_zero x).symm ≫ - (πₘ H.uliftMap).map (prodToProdTopI uhpath01 (𝟙 (fromTop x))) ≫ + (πₘ (TopCat.ofHom H.uliftMap)).map (prodToProdTopI uhpath01 (𝟙 (fromTop x))) ≫ hcast (H.apply_one x).symm.symm := by dsimp only [prodToProdTopI, uhpath01, hcast] refine (@conj_eqToHom_iff_heq (πₓ Y) _ _ _ _ _ _ _ _ @@ -183,8 +189,9 @@ theorem evalAt_eq (x : X) : ⟦H.evalAt x⟧ = hcast (H.apply_zero x).symm ≫ apply Path.Homotopic.hpath_hext; intro; rfl -- Finally, we show `d = f(p) ≫ H₁ = H₀ ≫ g(p)` -theorem eq_diag_path : (πₘ f).map p ≫ ⟦H.evalAt x₁⟧ = H.diagonalPath' p ∧ - (⟦H.evalAt x₀⟧ ≫ (πₘ g).map p : fromTop (f x₀) ⟶ fromTop (g x₁)) = H.diagonalPath' p := by +theorem eq_diag_path : (πₘ (TopCat.ofHom f)).map p ≫ ⟦H.evalAt x₁⟧ = H.diagonalPath' p ∧ + (⟦H.evalAt x₀⟧ ≫ (πₘ (TopCat.ofHom g)).map p : + fromTop (f x₀) ⟶ fromTop (g x₁)) = H.diagonalPath' p := by rw [H.apply_zero_path, H.apply_one_path, H.evalAt_eq] erw [H.evalAt_eq] -- Porting note: `rw` didn't work, so using `erw` dsimp only [prodToProdTopI] @@ -211,7 +218,9 @@ variable {X Y : TopCat.{u}} {f g : C(X, Y)} (H : ContinuousMap.Homotopy f g) /-- Given a homotopy H : f ∼ g, we have an associated natural isomorphism between the induced functors `f` and `g` -/ -- Porting note: couldn't use category arrow `\hom` in statement, needed to expand -def homotopicMapsNatIso : @Quiver.Hom _ Functor.category.toQuiver (πₘ f) (πₘ g) where +def homotopicMapsNatIso : @Quiver.Hom _ Functor.category.toQuiver + (πₘ (TopCat.ofHom f)) + (πₘ (TopCat.ofHom g)) where app x := ⟦H.evalAt x.as⟧ -- Porting note: Turned `rw` into `erw` in the line below naturality x y p := by erw [(H.eq_diag_path p).1, (H.eq_diag_path p).2] @@ -222,8 +231,8 @@ open scoped ContinuousMap /-- Homotopy equivalent topological spaces have equivalent fundamental groupoids. -/ def equivOfHomotopyEquiv (hequiv : X ≃ₕ Y) : πₓ X ≌ πₓ Y := by - apply CategoryTheory.Equivalence.mk (πₘ hequiv.toFun : πₓ X ⥤ πₓ Y) - (πₘ hequiv.invFun : πₓ Y ⥤ πₓ X) <;> + apply CategoryTheory.Equivalence.mk (πₘ (TopCat.ofHom hequiv.toFun) : πₓ X ⥤ πₓ Y) + (πₘ (TopCat.ofHom hequiv.invFun) : πₓ Y ⥤ πₓ X) <;> simp only [Grpd.hom_to_functor, Grpd.id_to_functor] · convert (asIso (homotopicMapsNatIso hequiv.left_inv.some)).symm exacts [((π).map_id X).symm, ((π).map_comp _ _).symm] diff --git a/Mathlib/AlgebraicTopology/FundamentalGroupoid/Product.lean b/Mathlib/AlgebraicTopology/FundamentalGroupoid/Product.lean index 2877b1ad5f01d..6578d88c6565e 100644 --- a/Mathlib/AlgebraicTopology/FundamentalGroupoid/Product.lean +++ b/Mathlib/AlgebraicTopology/FundamentalGroupoid/Product.lean @@ -40,7 +40,7 @@ variable {I : Type u} (X : I → TopCat.{u}) /-- The projection map Π i, X i → X i induces a map π(Π i, X i) ⟶ π(X i). -/ def proj (i : I) : πₓ (TopCat.of (∀ i, X i)) ⥤ πₓ (X i) := - πₘ ⟨_, continuous_apply i⟩ + πₘ (TopCat.ofHom ⟨_, continuous_apply i⟩) /-- The projection map is precisely `Path.Homotopic.proj` interpreted as a functor -/ @[simp] @@ -125,11 +125,11 @@ variable (A B : TopCat.{u}) /-- The induced map of the left projection map X × Y → X -/ def projLeft : πₓ (TopCat.of (A × B)) ⥤ πₓ A := - πₘ ⟨_, continuous_fst⟩ + πₘ (TopCat.ofHom ⟨_, continuous_fst⟩) /-- The induced map of the right projection map X × Y → Y -/ def projRight : πₓ (TopCat.of (A × B)) ⥤ πₓ B := - πₘ ⟨_, continuous_snd⟩ + πₘ (TopCat.ofHom ⟨_, continuous_snd⟩) @[simp] theorem projLeft_map (x₀ x₁ : πₓ (TopCat.of (A × B))) (p : x₀ ⟶ x₁) : diff --git a/Mathlib/AlgebraicTopology/TopologicalSimplex.lean b/Mathlib/AlgebraicTopology/TopologicalSimplex.lean index a3767b7e54152..9e03d618ef964 100644 --- a/Mathlib/AlgebraicTopology/TopologicalSimplex.lean +++ b/Mathlib/AlgebraicTopology/TopologicalSimplex.lean @@ -66,18 +66,18 @@ theorem continuous_toTopMap {x y : SimplexCategory} (f : x ⟶ y) : Continuous ( @[simps obj map] def toTop : SimplexCategory ⥤ TopCat where obj x := TopCat.of x.toTopObj - map f := ⟨toTopMap f, by continuity⟩ + map f := TopCat.ofHom ⟨toTopMap f, by continuity⟩ map_id := by classical intro Δ - ext f + ext f : 1 apply toTopObj.ext funext i change (Finset.univ.filter (· = i)).sum _ = _ simp [Finset.sum_filter, CategoryTheory.id_apply] map_comp := fun f g => by classical - ext h + ext h : 1 apply toTopObj.ext funext i dsimp diff --git a/Mathlib/CategoryTheory/Extensive.lean b/Mathlib/CategoryTheory/Extensive.lean index f7766dcde513a..73bd7f0e18a9d 100644 --- a/Mathlib/CategoryTheory/Extensive.lean +++ b/Mathlib/CategoryTheory/Extensive.lean @@ -294,9 +294,9 @@ noncomputable def finitaryExtensiveTopCatAux (Z : TopCat.{u}) · rintro x ⟨⟨⟩, hx⟩; refine ⟨⟨⟨x, PUnit.unit⟩, hx.symm⟩, rfl⟩ refine ((TopCat.binaryCofan_isColimit_iff _).mpr ⟨?_, ?_, ?_⟩).some · refine ⟨(Homeomorph.prodPUnit Z).isEmbedding.comp .subtypeVal, ?_⟩ - convert f.2.1 _ isOpen_range_inl + convert f.hom.2.1 _ isOpen_range_inl · refine ⟨(Homeomorph.prodPUnit Z).isEmbedding.comp .subtypeVal, ?_⟩ - convert f.2.1 _ isOpen_range_inr + convert f.hom.2.1 _ isOpen_range_inr · convert Set.isCompl_range_inl_range_inr.preimage f instance finitaryExtensive_TopCat : FinitaryExtensive TopCat.{u} := by @@ -317,11 +317,12 @@ instance finitaryExtensive_TopCat : FinitaryExtensive TopCat.{u} := by (ConcreteCategory.congr_hom hαY val :).symm delta ExistsUnique at this choose l hl hl' using this - refine ⟨⟨l, ?_⟩, ContinuousMap.ext fun a => (hl a).symm, TopCat.isTerminalPUnit.hom_ext _ _, - fun {l'} h₁ _ => ContinuousMap.ext fun x => + refine ⟨TopCat.ofHom ⟨l, ?_⟩, TopCat.ext fun a => (hl a).symm, + TopCat.isTerminalPUnit.hom_ext _ _, + fun {l'} h₁ _ => TopCat.ext fun x => hl' x (l' x) (ConcreteCategory.congr_hom h₁ x).symm⟩ apply (IsEmbedding.inl (X := X') (Y := Y')).isInducing.continuous_iff.mpr - convert s.fst.2 using 1 + convert s.fst.hom.2 using 1 exact (funext hl).symm · refine ⟨⟨hαY.symm⟩, ⟨PullbackCone.isLimitAux' _ ?_⟩⟩ intro s @@ -334,11 +335,12 @@ instance finitaryExtensive_TopCat : FinitaryExtensive TopCat.{u} := by · exact ⟨val, rfl, fun y h => Sum.inr_injective h.symm⟩ delta ExistsUnique at this choose l hl hl' using this - refine ⟨⟨l, ?_⟩, ContinuousMap.ext fun a => (hl a).symm, TopCat.isTerminalPUnit.hom_ext _ _, + refine ⟨TopCat.ofHom ⟨l, ?_⟩, TopCat.ext fun a => (hl a).symm, + TopCat.isTerminalPUnit.hom_ext _ _, fun {l'} h₁ _ => - ContinuousMap.ext fun x => hl' x (l' x) (ConcreteCategory.congr_hom h₁ x).symm⟩ + TopCat.ext fun x => hl' x (l' x) (ConcreteCategory.congr_hom h₁ x).symm⟩ apply (IsEmbedding.inr (X := X') (Y := Y')).isInducing.continuous_iff.mpr - convert s.fst.2 using 1 + convert s.fst.hom.2 using 1 exact (funext hl).symm · intro Z f exact finitaryExtensiveTopCatAux Z f diff --git a/Mathlib/Condensed/Discrete/Characterization.lean b/Mathlib/Condensed/Discrete/Characterization.lean index 166add8efd026..67da90011bbd0 100644 --- a/Mathlib/Condensed/Discrete/Characterization.lean +++ b/Mathlib/Condensed/Discrete/Characterization.lean @@ -33,8 +33,6 @@ universe u open CategoryTheory Limits Functor FintypeCat -attribute [local instance] HasForget.instFunLike - namespace Condensed variable {C : Type*} [Category C] [HasWeakSheafify (coherentTopology CompHaus.{u}) C] diff --git a/Mathlib/Condensed/Discrete/Colimit.lean b/Mathlib/Condensed/Discrete/Colimit.lean index fd62250dd9340..9d8180a466bf6 100644 --- a/Mathlib/Condensed/Discrete/Colimit.lean +++ b/Mathlib/Condensed/Discrete/Colimit.lean @@ -21,8 +21,6 @@ noncomputable section open CategoryTheory Functor Limits FintypeCat CompHausLike.LocallyConstant -attribute [local instance] HasForget.instFunLike - namespace Condensed section LocallyConstantAsColimit @@ -45,7 +43,7 @@ noncomputable def isColimitLocallyConstantPresheaf (hc : IsLimit c) [∀ i, Epi obtain ⟨j, h⟩ := Profinite.exists_locallyConstant.{_, u} c hc f exact ⟨⟨j⟩, h⟩ · intro ⟨i⟩ ⟨j⟩ (fi : LocallyConstant _ _) (fj : LocallyConstant _ _) - (h : fi.comap (c.π.app i) = fj.comap (c.π.app j)) + (h : fi.comap (c.π.app i).hom = fj.comap (c.π.app j).hom) obtain ⟨k, ki, kj, _⟩ := IsCofilteredOrEmpty.cone_objs i j refine ⟨⟨k⟩, ki.op, kj.op, ?_⟩ dsimp @@ -61,7 +59,7 @@ noncomputable def isColimitLocallyConstantPresheaf (hc : IsLimit c) [∀ i, Epi lemma isColimitLocallyConstantPresheaf_desc_apply (hc : IsLimit c) [∀ i, Epi (c.π.app i)] (s : Cocone ((F ⋙ toProfinite).op ⋙ locallyConstantPresheaf X)) (i : I) (f : LocallyConstant (toProfinite.obj (F.obj i)) X) : - (isColimitLocallyConstantPresheaf c X hc).desc s (f.comap (c.π.app i)) = s.ι.app ⟨i⟩ f := by + (isColimitLocallyConstantPresheaf c X hc).desc s (f.comap (c.π.app i).hom) = s.ι.app ⟨i⟩ f := by change ((((locallyConstantPresheaf X).mapCocone c.op).ι.app ⟨i⟩) ≫ (isColimitLocallyConstantPresheaf c X hc).desc s) _ = _ rw [(isColimitLocallyConstantPresheaf c X hc).fac] @@ -75,7 +73,7 @@ noncomputable def isColimitLocallyConstantPresheafDiagram (S : Profinite) : lemma isColimitLocallyConstantPresheafDiagram_desc_apply (S : Profinite) (s : Cocone (S.diagram.op ⋙ locallyConstantPresheaf X)) (i : DiscreteQuotient S) (f : LocallyConstant (S.diagram.obj i) X) : - (isColimitLocallyConstantPresheafDiagram X S).desc s (f.comap (S.asLimitCone.π.app i)) = + (isColimitLocallyConstantPresheafDiagram X S).desc s (f.comap (S.asLimitCone.π.app i).hom) = s.ι.app ⟨i⟩ f := isColimitLocallyConstantPresheaf_desc_apply S.asLimitCone X S.asLimit s i f @@ -185,13 +183,13 @@ def locallyConstantIsoFinYoneda : /-- A finite set as a coproduct cocone in `Profinite` over itself. -/ def fintypeCatAsCofan (X : Profinite) : Cofan (fun (_ : X) ↦ (Profinite.of (PUnit.{u+1}))) := - Cofan.mk X (fun x ↦ (ContinuousMap.const _ x)) + Cofan.mk X (fun x ↦ TopCat.ofHom (ContinuousMap.const _ x)) /-- A finite set is the coproduct of its points in `Profinite`. -/ def fintypeCatAsCofanIsColimit (X : Profinite) [Finite X] : IsColimit (fintypeCatAsCofan X) := by - refine mkCofanColimit _ (fun t ↦ ⟨fun x ↦ t.inj x PUnit.unit, ?_⟩) ?_ - (fun _ _ h ↦ by ext x; exact ContinuousMap.congr_fun (h x) _) + refine mkCofanColimit _ (fun t ↦ TopCat.ofHom ⟨fun x ↦ t.inj x PUnit.unit, ?_⟩) ?_ + (fun _ _ h ↦ by ext x; exact CategoryTheory.congr_fun (h x) _) · apply continuous_of_discreteTopology (α := X) · aesop @@ -311,7 +309,7 @@ noncomputable def isColimitLocallyConstantPresheaf (hc : IsLimit c) [∀ i, Epi (isLimitOfPreserves lightToProfinite hc) f exact ⟨⟨j⟩, h⟩ · intro ⟨i⟩ ⟨j⟩ (fi : LocallyConstant _ _) (fj : LocallyConstant _ _) - (h : fi.comap (c.π.app i) = fj.comap (c.π.app j)) + (h : fi.comap (c.π.app i).hom = fj.comap (c.π.app j).hom) obtain ⟨k, ki, kj, _⟩ := IsCofilteredOrEmpty.cone_objs i j refine ⟨⟨k⟩, ki.op, kj.op, ?_⟩ dsimp @@ -327,7 +325,7 @@ noncomputable def isColimitLocallyConstantPresheaf (hc : IsLimit c) [∀ i, Epi lemma isColimitLocallyConstantPresheaf_desc_apply (hc : IsLimit c) [∀ i, Epi (c.π.app i)] (s : Cocone ((F ⋙ toLightProfinite).op ⋙ locallyConstantPresheaf X)) (n : ℕᵒᵖ) (f : LocallyConstant (toLightProfinite.obj (F.obj n)) X) : - (isColimitLocallyConstantPresheaf c X hc).desc s (f.comap (c.π.app n)) = s.ι.app ⟨n⟩ f := by + (isColimitLocallyConstantPresheaf c X hc).desc s (f.comap (c.π.app n).hom) = s.ι.app ⟨n⟩ f := by change ((((locallyConstantPresheaf X).mapCocone c.op).ι.app ⟨n⟩) ≫ (isColimitLocallyConstantPresheaf c X hc).desc s) _ = _ rw [(isColimitLocallyConstantPresheaf c X hc).fac] @@ -342,7 +340,7 @@ noncomputable def isColimitLocallyConstantPresheafDiagram (S : LightProfinite) : lemma isColimitLocallyConstantPresheafDiagram_desc_apply (S : LightProfinite) (s : Cocone (S.diagram.rightOp ⋙ locallyConstantPresheaf X)) (n : ℕ) (f : LocallyConstant (S.diagram.obj ⟨n⟩) X) : - (isColimitLocallyConstantPresheafDiagram X S).desc s (f.comap (S.asLimitCone.π.app ⟨n⟩)) = + (isColimitLocallyConstantPresheafDiagram X S).desc s (f.comap (S.asLimitCone.π.app ⟨n⟩).hom) = s.ι.app n f := by change ((((locallyConstantPresheaf X).mapCocone (coconeRightOpOfCone S.asLimitCone)).ι.app n) ≫ (isColimitLocallyConstantPresheafDiagram X S).desc s) _ = _ @@ -457,13 +455,13 @@ def locallyConstantIsoFinYoneda : toLightProfinite.op ⋙ /-- A finite set as a coproduct cocone in `LightProfinite` over itself. -/ def fintypeCatAsCofan (X : LightProfinite) : Cofan (fun (_ : X) ↦ (LightProfinite.of (PUnit.{u+1}))) := - Cofan.mk X (fun x ↦ (ContinuousMap.const _ x)) + Cofan.mk X (fun x ↦ TopCat.ofHom (ContinuousMap.const _ x)) /-- A finite set is the coproduct of its points in `LightProfinite`. -/ def fintypeCatAsCofanIsColimit (X : LightProfinite) [Finite X] : IsColimit (fintypeCatAsCofan X) := by - refine mkCofanColimit _ (fun t ↦ ⟨fun x ↦ t.inj x PUnit.unit, ?_⟩) ?_ - (fun _ _ h ↦ by ext x; exact ContinuousMap.congr_fun (h x) _) + refine mkCofanColimit _ (fun t ↦ TopCat.ofHom ⟨fun x ↦ t.inj x PUnit.unit, ?_⟩) ?_ + (fun _ _ h ↦ by ext x; exact CategoryTheory.congr_fun (h x) _) · apply continuous_of_discreteTopology (α := X) · aesop diff --git a/Mathlib/Condensed/Discrete/LocallyConstant.lean b/Mathlib/Condensed/Discrete/LocallyConstant.lean index bec3c4eba5068..e31971393c97f 100644 --- a/Mathlib/Condensed/Discrete/LocallyConstant.lean +++ b/Mathlib/Condensed/Discrete/LocallyConstant.lean @@ -69,8 +69,6 @@ universe u w open CategoryTheory Limits LocallyConstant TopologicalSpace.Fiber Opposite Function Fiber -attribute [local instance] HasForget.instFunLike - variable {P : TopCat.{u} → Prop} namespace CompHausLike.LocallyConstant @@ -83,7 +81,7 @@ maps. def functorToPresheaves : Type (max u w) ⥤ ((CompHausLike.{u} P)ᵒᵖ ⥤ Type max u w) where obj X := { obj := fun ⟨S⟩ ↦ LocallyConstant S X - map := fun f g ↦ g.comap f.unop } + map := fun f g ↦ g.comap f.unop.hom } map f := { app := fun _ t ↦ t.map f } /-- @@ -112,12 +110,12 @@ def fiber : CompHausLike.{u} P := CompHausLike.of P a.val instance : HasProp P (fiber r a) := inferInstanceAs (HasProp P (Subtype _)) /-- The inclusion map from a component of the coproduct induced by `f` into `S`. -/ -def sigmaIncl : fiber r a ⟶ Q := TopologicalSpace.Fiber.sigmaIncl _ a +def sigmaIncl : fiber r a ⟶ Q := ofHom _ (TopologicalSpace.Fiber.sigmaIncl _ a) /-- The canonical map from the coproduct induced by `f` to `S` as an isomorphism in `CompHausLike P`. -/ noncomputable def sigmaIso [HasExplicitFiniteCoproducts.{u} P] : (finiteCoproduct (fiber r)) ≅ Q := - isoOfBijective (sigmaIsoHom r) ⟨sigmaIsoHom_inj r, sigmaIsoHom_surj r⟩ + isoOfBijective (ofHom _ (sigmaIsoHom r)) ⟨sigmaIsoHom_inj r, sigmaIsoHom_surj r⟩ lemma sigmaComparison_comp_sigmaIso [HasExplicitFiniteCoproducts.{u} P] (X : (CompHausLike.{u} P)ᵒᵖ ⥤ Type max u w) : @@ -180,19 +178,21 @@ variable {T : CompHausLike.{u} P} (g : T ⟶ S) This is an auxiliary definition, the details do not matter. What's important is that this map exists so that the lemma `incl_comap` works. -/ -def componentHom (a : Fiber (f.comap g)) : - fiber _ a ⟶ fiber _ (Fiber.mk f (g a.preimage)) where - toFun x := ⟨g x.val, by - simp only [Fiber.mk, Set.mem_preimage, Set.mem_singleton_iff] - convert map_eq_image _ _ x - exact map_preimage_eq_image_map _ _ a⟩ - continuous_toFun := by exact Continuous.subtype_mk (g.continuous.comp continuous_subtype_val) _ - -- term mode gives "unknown free variable" error. +def componentHom (a : Fiber (f.comap g.hom)) : + fiber _ a ⟶ fiber _ (Fiber.mk f (g a.preimage)) := + TopCat.ofHom + { toFun x := ⟨g x.val, by + simp only [Fiber.mk, Set.mem_preimage, Set.mem_singleton_iff] + convert map_eq_image _ _ x + exact map_preimage_eq_image_map _ _ a⟩ + continuous_toFun := by + exact Continuous.subtype_mk (g.hom.continuous.comp continuous_subtype_val) _ } + -- term mode gives "unknown free variable" error. lemma incl_comap {S T : (CompHausLike P)ᵒᵖ} (f : LocallyConstant S.unop (Y.obj (op (CompHausLike.of P PUnit.{u+1})))) - (g : S ⟶ T) (a : Fiber (f.comap g.unop)) : - g ≫ (sigmaIncl (f.comap g.unop) a).op = + (g : S ⟶ T) (a : Fiber (f.comap g.unop.hom)) : + g ≫ (sigmaIncl (f.comap g.unop.hom) a).op = (sigmaIncl f _).op ≫ (componentHom f g.unop a).op := rfl @@ -205,7 +205,7 @@ noncomputable def counitApp [HasExplicitFiniteCoproducts.{u} P] naturality := by intro S T g ext f - apply presheaf_ext (f.comap g.unop) + apply presheaf_ext (f.comap g.unop.hom) intro a simp only [op_unop, functorToPresheaves_obj_obj, types_comp_apply, functorToPresheaves_obj_map, incl_of_counitAppApp, ← FunctorToTypes.map_comp_apply, incl_comap] @@ -264,14 +264,15 @@ noncomputable def counit [HasExplicitFiniteCoproducts.{u} P] : haveI := CompHaus apply presheaf_ext (f.map (g.val.app (op (CompHausLike.of P PUnit.{u+1})))) intro a simp only [op_unop, functorToPresheaves_map_app, incl_of_counitAppApp] - apply presheaf_ext (f.comap (sigmaIncl _ _)) + apply presheaf_ext (f.comap (sigmaIncl _ _).hom) intro b simp only [counitAppAppImage, ← FunctorToTypes.map_comp_apply, ← op_comp, CompHausLike.coe_of, map_apply, IsTerminal.comp_from, ← map_preimage_eq_image_map] change (_ ≫ Y.val.map _) _ = (_ ≫ Y.val.map _) _ - simp only [← g.val.naturality, - show sigmaIncl (f.comap (sigmaIncl (f.map _) a)) b ≫ sigmaIncl (f.map _) a = - (sigmaInclIncl f _ a b) ≫ sigmaIncl f (Fiber.mk f _) from rfl] + simp only [← g.val.naturality] + rw [show sigmaIncl (f.comap (sigmaIncl (f.map _) a).hom) b ≫ sigmaIncl (f.map _) a = + CompHausLike.ofHom P (X := fiber _ b) (sigmaInclIncl f _ a b) ≫ sigmaIncl f (Fiber.mk f _) + by ext; rfl] simp only [op_comp, Functor.map_comp, types_comp_apply, incl_of_counitAppApp] simp only [counitAppAppImage, ← FunctorToTypes.map_comp_apply, ← op_comp, terminal.comp_from] rw [mk_image] diff --git a/Mathlib/Condensed/Discrete/Module.lean b/Mathlib/Condensed/Discrete/Module.lean index 79c0f44b9350d..eb153f31358e0 100644 --- a/Mathlib/Condensed/Discrete/Module.lean +++ b/Mathlib/Condensed/Discrete/Module.lean @@ -24,8 +24,6 @@ universe w u open CategoryTheory LocallyConstant CompHausLike Functor Category Functor Opposite -attribute [local instance] HasForget.instFunLike - variable {P : TopCat.{u} → Prop} namespace CompHausLike.LocallyConstantModule @@ -40,7 +38,7 @@ constant maps. def functorToPresheaves : ModuleCat.{max u w} R ⥤ ((CompHausLike.{u} P)ᵒᵖ ⥤ ModuleCat R) where obj X := { obj := fun ⟨S⟩ ↦ ModuleCat.of R (LocallyConstant S X) - map := fun f ↦ ModuleCat.ofHom (comapₗ R f.unop) } + map := fun f ↦ ModuleCat.ofHom (comapₗ R f.unop.hom) } map f := { app := fun S ↦ ModuleCat.ofHom (mapₗ R f.hom) } variable [HasExplicitFiniteCoproducts.{0} P] [HasExplicitPullbacks.{u} P] diff --git a/Mathlib/Condensed/Light/Epi.lean b/Mathlib/Condensed/Light/Epi.lean index 5f757b75530ca..e5c1c087d4b4f 100644 --- a/Mathlib/Condensed/Light/Epi.lean +++ b/Mathlib/Condensed/Light/Epi.lean @@ -88,7 +88,7 @@ lemma epi_π_app_zero_of_epi : Epi (c.π.app ⟨0⟩) := by change Epi (((forget R).mapCone c).π.app ⟨0⟩) apply coherentTopology.epi_π_app_zero_of_epi · simp only [LightProfinite.effectiveEpi_iff_surjective] - exact fun _ h ↦ Concrete.surjective_π_app_zero_of_surjective_map (limit.isLimit _) h + exact fun x h ↦ Concrete.surjective_π_app_zero_of_surjective_map (limit.isLimit x) h · have := (freeForgetAdjunction R).isRightAdjoint exact isLimitOfPreserves _ hc · exact fun _ ↦ (forget R).map_epi _ diff --git a/Mathlib/Condensed/Light/TopCatAdjunction.lean b/Mathlib/Condensed/Light/TopCatAdjunction.lean index 2201055ab0ffc..9a7834ba22ed7 100644 --- a/Mathlib/Condensed/Light/TopCatAdjunction.lean +++ b/Mathlib/Condensed/Light/TopCatAdjunction.lean @@ -22,8 +22,6 @@ universe u open LightCondensed LightCondSet CategoryTheory LightProfinite -attribute [local instance] HasForget.instFunLike - namespace LightCondSet variable (X : LightCondSet.{u}) @@ -42,7 +40,7 @@ local instance underlyingTopologicalSpace : TopologicalSpace.coinduced (coinducingCoprod X) inferInstance /-- The object part of the functor `LightCondSet ⥤ TopCat` -/ -def toTopCat : TopCat.{u} := TopCat.of (X.val.obj ⟨LightProfinite.of PUnit⟩) +abbrev toTopCat : TopCat.{u} := TopCat.of (X.val.obj ⟨LightProfinite.of PUnit⟩) lemma continuous_coinducingCoprod {S : LightProfinite.{u}} (x : X.val.obj ⟨S⟩) : Continuous fun a ↦ (X.coinducingCoprod ⟨⟨S, x⟩, a⟩) := by @@ -54,17 +52,18 @@ lemma continuous_coinducingCoprod {S : LightProfinite.{u}} (x : X.val.obj ⟨S variable {X} {Y : LightCondSet} (f : X ⟶ Y) /-- The map part of the functor `LightCondSet ⥤ TopCat` -/ -@[simps] -def toTopCatMap : X.toTopCat ⟶ Y.toTopCat where - toFun := f.val.app ⟨LightProfinite.of PUnit⟩ - continuous_toFun := by - rw [continuous_coinduced_dom] - apply continuous_sigma - intro ⟨S, x⟩ - simp only [Function.comp_apply, coinducingCoprod] - rw [show (fun (a : S) ↦ f.val.app ⟨of PUnit⟩ (X.val.map ((of PUnit.{u+1}).const a).op x)) = _ - from funext fun a ↦ NatTrans.naturality_apply f.val ((of PUnit.{u+1}).const a).op x] - exact continuous_coinducingCoprod _ _ +@[simps!] +def toTopCatMap : X.toTopCat ⟶ Y.toTopCat := + TopCat.ofHom + { toFun := f.val.app ⟨LightProfinite.of PUnit⟩ + continuous_toFun := by + rw [continuous_coinduced_dom] + apply continuous_sigma + intro ⟨S, x⟩ + simp only [Function.comp_apply, coinducingCoprod] + rw [show (fun (a : S) ↦ f.val.app ⟨of PUnit⟩ (X.val.map ((of PUnit.{u+1}).const a).op x)) = _ + from funext fun a ↦ NatTrans.naturality_apply f.val ((of PUnit.{u+1}).const a).op x] + exact continuous_coinducingCoprod _ _ } /-- The functor `LightCondSet ⥤ TopCat` -/ @[simps] @@ -73,11 +72,12 @@ def _root_.lightCondSetToTopCat : LightCondSet.{u} ⥤ TopCat.{u} where map f := toTopCatMap f /-- The counit of the adjunction `lightCondSetToTopCat ⊣ topCatToLightCondSet` -/ -def topCatAdjunctionCounit (X : TopCat.{u}) : X.toLightCondSet.toTopCat ⟶ X where - toFun x := x.1 PUnit.unit - continuous_toFun := by - rw [continuous_coinduced_dom] - continuity +def topCatAdjunctionCounit (X : TopCat.{u}) : X.toLightCondSet.toTopCat ⟶ X := + TopCat.ofHom + { toFun x := x.1 PUnit.unit + continuous_toFun := by + rw [continuous_coinduced_dom] + continuity } /-- The counit of the adjunction `lightCondSetToTopCat ⊣ topCatToLightCondSet` is always bijective, but not an isomorphism in general (the inverse isn't continuous unless `X` is sequential). @@ -105,9 +105,8 @@ def topCatAdjunctionUnit (X : LightCondSet.{u}) : X ⟶ X.toTopCat.toLightCondSe apply continuous_coinduced_rng } naturality := fun _ _ _ ↦ by ext - simp only [TopCat.toSheafCompHausLike_val_obj, CompHausLike.compHausLikeToTop_obj, - Opposite.op_unop, types_comp_apply, TopCat.toSheafCompHausLike_val_map, - ← FunctorToTypes.map_comp_apply] + simp only [TopCat.toSheafCompHausLike_val_obj, Opposite.op_unop, types_comp_apply, + TopCat.toSheafCompHausLike_val_map, ← FunctorToTypes.map_comp_apply] rfl } /-- The adjunction `lightCondSetToTopCat ⊣ topCatToLightCondSet` -/ @@ -165,7 +164,7 @@ can only prove this for `X : TopCat.{0}`. def sequentialAdjunctionHomeo (X : TopCat.{0}) [SequentialSpace X] : X.toLightCondSet.toTopCat ≃ₜ X where toEquiv := topCatAdjunctionCounitEquiv X - continuous_toFun := (topCatAdjunctionCounit X).continuous + continuous_toFun := (topCatAdjunctionCounit X).hom.continuous continuous_invFun := by apply SeqContinuous.continuous unfold SeqContinuous diff --git a/Mathlib/Condensed/TopCatAdjunction.lean b/Mathlib/Condensed/TopCatAdjunction.lean index af00f6cd79179..8dfbaaa415b0b 100644 --- a/Mathlib/Condensed/TopCatAdjunction.lean +++ b/Mathlib/Condensed/TopCatAdjunction.lean @@ -21,8 +21,6 @@ universe u open Condensed CondensedSet CategoryTheory CompHaus -attribute [local instance] HasForget.instFunLike - variable (X : CondensedSet.{u}) /-- Auxiliary definition to define the topology on `X(*)` for a condensed set `X`. -/ @@ -37,7 +35,7 @@ local instance : TopologicalSpace (X.val.obj ⟨CompHaus.of PUnit⟩) := TopologicalSpace.coinduced (coinducingCoprod X) inferInstance /-- The object part of the functor `CondensedSet ⥤ TopCat` -/ -def CondensedSet.toTopCat : TopCat.{u+1} := TopCat.of (X.val.obj ⟨of PUnit⟩) +abbrev CondensedSet.toTopCat : TopCat.{u+1} := TopCat.of (X.val.obj ⟨of PUnit⟩) namespace CondensedSet @@ -51,17 +49,18 @@ lemma continuous_coinducingCoprod {S : CompHaus.{u}} (x : X.val.obj ⟨S⟩) : variable {X} {Y : CondensedSet} (f : X ⟶ Y) /-- The map part of the functor `CondensedSet ⥤ TopCat` -/ -@[simps] -def toTopCatMap : X.toTopCat ⟶ Y.toTopCat where - toFun := f.val.app ⟨of PUnit⟩ - continuous_toFun := by - rw [continuous_coinduced_dom] - apply continuous_sigma - intro ⟨S, x⟩ - simp only [Function.comp_apply, coinducingCoprod] - rw [show (fun (a : S) ↦ f.val.app ⟨of PUnit⟩ (X.val.map ((of PUnit.{u+1}).const a).op x)) = _ - from funext fun a ↦ NatTrans.naturality_apply f.val ((of PUnit.{u+1}).const a).op x] - exact continuous_coinducingCoprod Y _ +@[simps!] +def toTopCatMap : X.toTopCat ⟶ Y.toTopCat := + TopCat.ofHom + { toFun := f.val.app ⟨of PUnit⟩ + continuous_toFun := by + rw [continuous_coinduced_dom] + apply continuous_sigma + intro ⟨S, x⟩ + simp only [Function.comp_apply, coinducingCoprod] + rw [show (fun (a : S) ↦ f.val.app ⟨of PUnit⟩ (X.val.map ((of PUnit.{u+1}).const a).op x)) = _ + from funext fun a ↦ NatTrans.naturality_apply f.val ((of PUnit.{u+1}).const a).op x] + exact continuous_coinducingCoprod Y _ } end CondensedSet @@ -74,12 +73,20 @@ def condensedSetToTopCat : CondensedSet.{u} ⥤ TopCat.{u+1} where namespace CondensedSet /-- The counit of the adjunction `condensedSetToTopCat ⊣ topCatToCondensedSet` -/ -@[simps] -def topCatAdjunctionCounit (X : TopCat.{u+1}) : X.toCondensedSet.toTopCat ⟶ X where - toFun x := x.1 PUnit.unit - continuous_toFun := by - rw [continuous_coinduced_dom] - continuity +def topCatAdjunctionCounit (X : TopCat.{u+1}) : X.toCondensedSet.toTopCat ⟶ X := + TopCat.ofHom + { toFun x := x.1 PUnit.unit + continuous_toFun := by + rw [continuous_coinduced_dom] + continuity } + +/-- `simp`-normal form of the lemma that `@[simps]` would generate. -/ +@[simp] lemma topCatAdjunctionCounit_hom_apply (X : TopCat) (x) : + -- We have to specify here to not infer the `TopologicalSpace` instance on `C(PUnit, X)`, + -- which suggests type synonyms are being unfolded too far somewhere. + DFunLike.coe (F := @ContinuousMap C(PUnit, X) X (_) _) + (TopCat.Hom.hom (topCatAdjunctionCounit X)) x = + x PUnit.unit := rfl /-- The counit of the adjunction `condensedSetToTopCat ⊣ topCatToCondensedSet` is always bijective, but not an isomorphism in general (the inverse isn't continuous unless `X` is compactly generated). @@ -107,15 +114,15 @@ def topCatAdjunctionUnit (X : CondensedSet.{u}) : X ⟶ X.toTopCat.toCondensedSe apply continuous_coinduced_rng } naturality := fun _ _ _ ↦ by ext - simp only [TopCat.toSheafCompHausLike_val_obj, CompHausLike.compHausLikeToTop_obj, + simp only [TopCat.toSheafCompHausLike_val_obj, Opposite.op_unop, types_comp_apply, TopCat.toSheafCompHausLike_val_map, ← FunctorToTypes.map_comp_apply] rfl } /-- The adjunction `condensedSetToTopCat ⊣ topCatToCondensedSet` -/ noncomputable def topCatAdjunction : condensedSetToTopCat.{u} ⊣ topCatToCondensedSet where - unit := { app := topCatAdjunctionUnit } - counit := { app := topCatAdjunctionCounit } + unit.app := topCatAdjunctionUnit + counit.app := topCatAdjunctionCounit left_triangle_components Y := by ext change Y.val.map (𝟙 _) _ = _ @@ -168,7 +175,7 @@ is a homeomorphism. def compactlyGeneratedAdjunctionCounitHomeo (X : TopCat.{u+1}) [UCompactlyGeneratedSpace.{u} X] : X.toCondensedSet.toTopCat ≃ₜ X where toEquiv := topCatAdjunctionCounitEquiv X - continuous_toFun := (topCatAdjunctionCounit X).continuous + continuous_toFun := (topCatAdjunctionCounit X).hom.continuous continuous_invFun := by apply continuous_from_uCompactlyGeneratedSpace exact fun _ _ ↦ continuous_coinducingCoprod X.toCondensedSet _ diff --git a/Mathlib/Condensed/TopComparison.lean b/Mathlib/Condensed/TopComparison.lean index b849bc48d6588..d8ea3491adde1 100644 --- a/Mathlib/Condensed/TopComparison.lean +++ b/Mathlib/Condensed/TopComparison.lean @@ -25,8 +25,6 @@ universe w w' v u open CategoryTheory Opposite Limits regularTopology ContinuousMap Topology -attribute [local instance] HasForget.instFunLike - variable {C : Type u} [Category.{v} C] (G : C ⥤ TopCat.{w}) (X : Type w') [TopologicalSpace X] @@ -113,7 +111,7 @@ def TopCat.toSheafCompHausLike : apply (config := { allowSynthFailures := true }) equalizerCondition_yonedaPresheaf (CompHausLike.compHausLikeToTop.{u} P) X intro Z B π he - apply IsQuotientMap.of_surjective_continuous (hs _ he) π.continuous + apply IsQuotientMap.of_surjective_continuous (hs _ he) π.hom.continuous /-- `TopCat.toSheafCompHausLike` yields a functor from `TopCat.{max u w}` to @@ -124,7 +122,7 @@ noncomputable def topCatToSheafCompHausLike : have := CompHausLike.preregular hs TopCat.{max u w} ⥤ Sheaf (coherentTopology (CompHausLike.{u} P)) (Type (max u w)) where obj X := X.toSheafCompHausLike P hs - map f := ⟨⟨fun _ g ↦ f.comp g, by aesop⟩⟩ + map f := ⟨⟨fun _ g ↦ f.hom.comp g, by aesop⟩⟩ end diff --git a/Mathlib/Geometry/Manifold/Sheaf/Basic.lean b/Mathlib/Geometry/Manifold/Sheaf/Basic.lean index 2368052ad3acf..4df8d6b6d2a5c 100644 --- a/Mathlib/Geometry/Manifold/Sheaf/Basic.lean +++ b/Mathlib/Geometry/Manifold/Sheaf/Basic.lean @@ -60,7 +60,7 @@ def StructureGroupoid.LocalInvariantProp.localPredicate (hG : LocalInvariantProp apply h locality := by intro V f h x - obtain ⟨U, hxU, i, hU : ChartedSpace.LiftProp P (f ∘ i)⟩ := h x + obtain ⟨U, hxU, i, hU : ChartedSpace.LiftProp P (f ∘ _)⟩ := h x let x' : U := ⟨x, hxU⟩ have hUV : U ≤ V := CategoryTheory.leOfHom i have : ChartedSpace.LiftPropAt P f (Opens.inclusion hUV x') := by diff --git a/Mathlib/Geometry/RingedSpace/LocallyRingedSpace.lean b/Mathlib/Geometry/RingedSpace/LocallyRingedSpace.lean index 36647bd9a55ca..537ff7ff313b8 100644 --- a/Mathlib/Geometry/RingedSpace/LocallyRingedSpace.lean +++ b/Mathlib/Geometry/RingedSpace/LocallyRingedSpace.lean @@ -273,7 +273,7 @@ instance : EmptyCollection LocallyRingedSpace.{u} := ⟨LocallyRingedSpace.empty /-- The canonical map from the empty locally ringed space. -/ def emptyTo (X : LocallyRingedSpace.{u}) : ∅ ⟶ X := - ⟨⟨⟨fun x => PEmpty.elim x, by fun_prop⟩, + ⟨⟨ofHom ⟨fun x => PEmpty.elim x, by fun_prop⟩, { app := fun U => CommRingCat.ofHom <| by refine ⟨⟨⟨0, ?_⟩, ?_⟩, ?_, ?_⟩ <;> intros <;> rfl }⟩, fun x => PEmpty.elim x⟩ @@ -354,12 +354,12 @@ lemma stalkMap_comp (x : X) : @[reassoc] lemma stalkSpecializes_stalkMap (x x' : X) (h : x ⤳ x') : - Y.presheaf.stalkSpecializes (f.base.map_specializes h) ≫ f.stalkMap x = + Y.presheaf.stalkSpecializes (f.base.hom.map_specializes h) ≫ f.stalkMap x = f.stalkMap x' ≫ X.presheaf.stalkSpecializes h := PresheafedSpace.stalkMap.stalkSpecializes_stalkMap f.toShHom h lemma stalkSpecializes_stalkMap_apply (x x' : X) (h : x ⤳ x') (y) : - f.stalkMap x (Y.presheaf.stalkSpecializes (f.base.map_specializes h) y) = + f.stalkMap x (Y.presheaf.stalkSpecializes (f.base.hom.map_specializes h) y) = (X.presheaf.stalkSpecializes h (f.stalkMap x' y)) := DFunLike.congr_fun (CommRingCat.hom_ext_iff.mp (stalkSpecializes_stalkMap f x x' h)) y diff --git a/Mathlib/Geometry/RingedSpace/LocallyRingedSpace/HasColimits.lean b/Mathlib/Geometry/RingedSpace/LocallyRingedSpace/HasColimits.lean index a4c26869dcdfe..154dc93a8b6e6 100644 --- a/Mathlib/Geometry/RingedSpace/LocallyRingedSpace/HasColimits.lean +++ b/Mathlib/Geometry/RingedSpace/LocallyRingedSpace/HasColimits.lean @@ -189,7 +189,7 @@ theorem imageBasicOpen_image_preimage : (g.base : X.carrier.1 ⟶ Y.carrier.1) · ext simp_rw [types_comp_apply, ← TopCat.comp_app, ← PresheafedSpace.comp_base] - congr 2 + congr 3 exact coequalizer.condition f.toShHom g.toShHom · apply isColimitCoforkMapOfIsColimit (forget TopCat) apply isColimitCoforkMapOfIsColimit (SheafedSpace.forget _) diff --git a/Mathlib/Geometry/RingedSpace/OpenImmersion.lean b/Mathlib/Geometry/RingedSpace/OpenImmersion.lean index aa63a2c5e4a93..8d53322f85c51 100644 --- a/Mathlib/Geometry/RingedSpace/OpenImmersion.lean +++ b/Mathlib/Geometry/RingedSpace/OpenImmersion.lean @@ -311,12 +311,7 @@ def pullbackConeOfLeftFst : erw [TopCat.pullbackIsoProdSubtype_inv_fst_apply] · erw [TopCat.pullbackIsoProdSubtype_inv_snd_apply] · rintro _ ⟨x, h₁, rfl⟩ - -- next line used to be - -- `exact ⟨_, h₁, ConcreteCategory.congr_hom pullback.condition x⟩))` - -- before https://github.com/leanprover-community/mathlib4/pull/13170 - refine ⟨_, h₁, ?_⟩ - change (_ ≫ f.base) _ = (_ ≫ g.base) _ - rw [pullback.condition])) + exact ⟨_, h₁, CategoryTheory.congr_fun pullback.condition x⟩)) naturality := by intro U V i induction U using Opposite.rec' @@ -855,7 +850,7 @@ theorem sigma_ι_isOpenEmbedding : IsOpenEmbedding (colimit.ι F i).base := by -- Porting note: `simp_rw` can't use `TopCat.isOpenEmbedding_iff_comp_isIso` and -- `TopCat.isOpenEmbedding_iff_isIso_comp`. -- See https://github.com/leanprover-community/mathlib4/issues/5026 - erw [TopCat.isOpenEmbedding_iff_comp_isIso, TopCat.isOpenEmbedding_iff_comp_isIso, + rw [TopCat.isOpenEmbedding_iff_comp_isIso, TopCat.isOpenEmbedding_iff_comp_isIso, TopCat.isOpenEmbedding_iff_comp_isIso, TopCat.isOpenEmbedding_iff_isIso_comp] exact .sigmaMk @@ -1126,10 +1121,9 @@ theorem lift_range (H' : Set.range g.base ⊆ Set.range f.base) : have : _ = (pullback.fst f g).base := PreservesPullback.iso_hom_fst (LocallyRingedSpace.forgetToSheafedSpace ⋙ SheafedSpace.forget _) f g - rw [LocallyRingedSpace.comp_base, ← this, ← Category.assoc, coe_comp, Set.range_comp, + rw [LocallyRingedSpace.comp_base, ← this, ← Category.assoc, TopCat.coe_comp, Set.range_comp, Set.range_eq_univ.mpr, Set.image_univ] - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11224): change `rw` to `erw` on this lemma - · erw [TopCat.pullback_fst_range] + · rw [TopCat.pullback_fst_range] ext constructor · rintro ⟨y, eq⟩; exact ⟨y, eq.symm⟩ diff --git a/Mathlib/Geometry/RingedSpace/PresheafedSpace.lean b/Mathlib/Geometry/RingedSpace/PresheafedSpace.lean index 2edeb618bd422..818fe3e6d019b 100644 --- a/Mathlib/Geometry/RingedSpace/PresheafedSpace.lean +++ b/Mathlib/Geometry/RingedSpace/PresheafedSpace.lean @@ -3,8 +3,9 @@ Copyright (c) 2019 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ -import Mathlib.Topology.Sheaves.Presheaf import Mathlib.CategoryTheory.Adjunction.FullyFaithful +import Mathlib.CategoryTheory.Elementwise +import Mathlib.Topology.Sheaves.Presheaf /-! # Presheafed spaces @@ -52,22 +53,12 @@ variable {C} namespace PresheafedSpace --- Porting note: using `Coe` here triggers an error, `CoeOut` seems an acceptable alternative instance coeCarrier : CoeOut (PresheafedSpace C) TopCat where coe X := X.carrier attribute [coe] PresheafedSpace.carrier --- Porting note: we add this instance, as Lean does not reliably use the `CoeOut` instance above --- in downstream files. instance : CoeSort (PresheafedSpace C) Type* where coe X := X.carrier --- Porting note: the following lemma is removed because it is a syntactic tauto -/-@[simp] -theorem as_coe (X : PresheafedSpace.{w, v, u} C) : X.carrier = (X : TopCat.{w}) := - rfl-/ - --- Porting note: removed @[simp] as the `simpVarHead` linter complains --- @[simp] theorem mk_coe (carrier) (presheaf) : (({ carrier presheaf } : PresheafedSpace C) : TopCat) = carrier := @@ -91,10 +82,6 @@ structure Hom (X Y : PresheafedSpace C) where base : (X : TopCat) ⟶ (Y : TopCat) c : Y.presheaf ⟶ base _* X.presheaf --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11041): eventually, the `ext` lemma shall be applied to terms in `X ⟶ Y` --- rather than `Hom X Y`, this one was renamed `Hom.ext` instead of `ext`, --- and the more practical lemma `ext` is defined just after the definition --- of the `Category` instance @[ext (iff := false)] theorem Hom.ext {X Y : PresheafedSpace C} (α β : Hom X Y) (w : α.base = β.base) (h : α.c ≫ whiskerRight (eqToHom (by rw [w])) _ = β.c) : α = β := by @@ -114,7 +101,6 @@ theorem hext {X Y : PresheafedSpace C} (α β : Hom X Y) (w : α.base = β.base) cases β congr --- Porting note: `eqToHom` is no longer necessary in the definition of `c` /-- The identity morphism of a `PresheafedSpace`. -/ def id (X : PresheafedSpace C) : Hom X X where base := 𝟙 (X : TopCat) @@ -138,23 +124,12 @@ section attribute [local simp] id comp --- Porting note: in mathlib3, `tidy` could (almost) prove the category axioms, but proofs --- were included because `tidy` was slow. Here, `aesop_cat` succeeds reasonably quickly --- for `comp_id` and `assoc` /-- The category of PresheafedSpaces. Morphisms are pairs, a continuous map and a presheaf map from the presheaf on the target to the pushforward of the presheaf on the source. -/ instance categoryOfPresheafedSpaces : Category (PresheafedSpace C) where Hom := Hom id := id comp := comp - id_comp _ := by - dsimp - ext - · dsimp - simp - · dsimp - simp only [map_id, whiskerRight_id', assoc] - erw [comp_id, comp_id] variable {C} @@ -176,7 +151,6 @@ attribute [local simp] eqToHom_map theorem id_base (X : PresheafedSpace C) : (𝟙 X : X ⟶ X).base = 𝟙 (X : TopCat) := rfl --- Porting note: `eqToHom` is no longer needed in the statements of `id_c` and `id_c_app` theorem id_c (X : PresheafedSpace C) : (𝟙 X : X ⟶ X).c = 𝟙 X.presheaf := rfl @@ -195,9 +169,10 @@ theorem comp_base {X Y Z : PresheafedSpace C} (f : X ⟶ Y) (g : Y ⟶ Z) : instance (X Y : PresheafedSpace C) : CoeFun (X ⟶ Y) fun _ => (↑X → ↑Y) := ⟨fun f => f.base⟩ --- Porting note: removed as this is a syntactic tauto ---theorem coe_to_fun_eq {X Y : PresheafedSpace.{v, v, u} C} (f : X ⟶ Y) : (f : ↑X → ↑Y) = f.base := --- rfl +/-! +Note that we don't include a `ConcreteCategory` instance, since equality of morphisms `X ⟶ Y` +does not follow from equality of their coercions `X → Y`. +-/ -- The `reassoc` attribute was added despite the LHS not being a composition of two homs, -- for the reasons explained in the docstring. @@ -247,7 +222,7 @@ def isoOfComponents (H : X.1 ≅ Y.1) (α : H.hom _* X.2 ≅ Y.2) : X ≅ Y wher inv_hom_id := by ext · dsimp - rw [H.inv_hom_id] + exact H.inv_hom_id_apply _ dsimp simp only [Presheaf.toPushforwardOfIso_app, assoc, ← α.hom.naturality] simp only [eqToHom_map, eqToHom_app, eqToHom_trans_assoc, eqToHom_refl, id_comp] diff --git a/Mathlib/Geometry/RingedSpace/PresheafedSpace/Gluing.lean b/Mathlib/Geometry/RingedSpace/PresheafedSpace/Gluing.lean index 912cb224dd41a..0a1ef6d97b543 100644 --- a/Mathlib/Geometry/RingedSpace/PresheafedSpace/Gluing.lean +++ b/Mathlib/Geometry/RingedSpace/PresheafedSpace/Gluing.lean @@ -120,9 +120,7 @@ abbrev toTopGlueData : TopCat.GlueData := toGlueData := 𝖣.mapGlueData (forget C) } theorem ι_isOpenEmbedding [HasLimits C] (i : D.J) : IsOpenEmbedding (𝖣.ι i).base := by - rw [← show _ = (𝖣.ι i).base from 𝖣.ι_gluedIso_inv (PresheafedSpace.forget _) _] - -- Porting note: added this erewrite - erw [coe_comp] + rw [← show _ = (𝖣.ι i).base from 𝖣.ι_gluedIso_inv (PresheafedSpace.forget _) _, TopCat.coe_comp] exact (TopCat.homeoOfIso (𝖣.gluedIso (PresheafedSpace.forget _)).symm).isOpenEmbedding.comp (D.toTopGlueData.ι_isOpenEmbedding i) @@ -133,14 +131,9 @@ theorem pullback_base (i j k : D.J) (S : Set (D.V (i, j)).carrier) : (π₂ i, j, k) '' ((π₁ i, j, k) ⁻¹' S) = D.f i k ⁻¹' (D.f i j '' S) := by have eq₁ : _ = (π₁ i, j, k).base := PreservesPullback.iso_hom_fst (forget C) _ _ have eq₂ : _ = (π₂ i, j, k).base := PreservesPullback.iso_hom_snd (forget C) _ _ - rw [← eq₁, ← eq₂] - -- Porting note: `rw` to `erw` on `coe_comp` - erw [coe_comp] - rw [Set.image_comp] - -- Porting note: `rw` to `erw` on `coe_comp` - erw [coe_comp] - rw [Set.preimage_comp, Set.image_preimage_eq, TopCat.pullback_snd_image_fst_preimage] - · rfl + rw [← eq₁, ← eq₂, TopCat.coe_comp, Set.image_comp, TopCat.coe_comp, Set.preimage_comp, + Set.image_preimage_eq] + · simp only [forget_obj, forget_map, TopCat.pullback_snd_image_fst_preimage] rw [← TopCat.epi_iff_surjective] infer_instance @@ -186,22 +179,22 @@ theorem snd_invApp_t_app' (i j k : D.J) (U : Opens (pullback (D.f i j) (D.f i k) have := (𝖣.t_fac k i j).symm rw [← IsIso.inv_comp_eq] at this replace this := (congr_arg ((PresheafedSpace.Hom.base ·)) this).symm + replace this := congr_arg (TopCat.Hom.hom ·) this replace this := congr_arg (ContinuousMap.toFun ·) this dsimp at this - rw [coe_comp, coe_comp] at this rw [this, Set.image_comp, Set.image_comp, Set.preimage_image_eq] swap · refine Function.HasLeftInverse.injective ⟨(D.t i k).base, fun x => ?_⟩ - rw [← CategoryTheory.comp_apply, ← comp_base, D.t_inv, id_base, CategoryTheory.id_apply] + rw [← ConcreteCategory.comp_apply, ← comp_base, D.t_inv, id_base, ConcreteCategory.id_apply] refine congr_arg (_ '' ·) ?_ refine congr_fun ?_ _ refine Set.image_eq_preimage_of_inverse ?_ ?_ · intro x - rw [← CategoryTheory.comp_apply, ← comp_base, IsIso.inv_hom_id, id_base, - CategoryTheory.id_apply] + rw [← ConcreteCategory.comp_apply, ← comp_base, IsIso.inv_hom_id, id_base, + ConcreteCategory.id_apply] · intro x - rw [← CategoryTheory.comp_apply, ← comp_base, IsIso.hom_inv_id, id_base, - CategoryTheory.id_apply] + rw [← ConcreteCategory.comp_apply, ← comp_base, IsIso.hom_inv_id, id_base, + ConcreteCategory.id_apply] · rw [← IsIso.eq_inv_comp, IsOpenImmersion.inv_invApp, Category.assoc, (D.t' k i j).c.naturality_assoc] simp_rw [← Category.assoc] @@ -219,7 +212,7 @@ theorem snd_invApp_t_app' (i j k : D.J) (U : Opens (pullback (D.f i j) (D.f i k) subst eq use (inv (D.t' k i j)).base y change (inv (D.t' k i j) ≫ π₁ k, i, j).base y = _ - congr 2 + congr 3 rw [IsIso.inv_comp_eq, 𝖣.t_fac_assoc, 𝖣.t_inv, Category.comp_id] /-- The red and the blue arrows in ![this diagram](https://i.imgur.com/q6X1GJ9.png) commute. -/ @@ -245,7 +238,7 @@ theorem ι_image_preimage_eq (i j : D.J) (U : Opens (D.U i).carrier) : rw [← show _ = (𝖣.ι i).base from 𝖣.ι_gluedIso_inv (PresheafedSpace.forget _) i, ← show _ = (𝖣.ι j).base from 𝖣.ι_gluedIso_inv (PresheafedSpace.forget _) j] -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11224): change `rw` to `erw` on `coe_comp` - erw [coe_comp, coe_comp, coe_comp] + erw [TopCat.coe_comp, TopCat.coe_comp, TopCat.coe_comp] rw [Set.image_comp, Set.preimage_comp] erw [Set.preimage_image_eq] · refine Eq.trans (D.toTopGlueData.preimage_image_eq_image' _ _ _) ?_ @@ -258,7 +251,7 @@ theorem ι_image_preimage_eq (i j : D.J) (U : Opens (D.U i).carrier) : change (D.t i j ≫ D.t j i).base '' _ = _ rw [𝖣.t_inv] simp - · rw [← coe_comp, ← TopCat.mono_iff_injective] + · rw [← TopCat.coe_comp, ← TopCat.mono_iff_injective] infer_instance /-- (Implementation). The map `Γ(𝒪_{U_i}, U) ⟶ Γ(𝒪_{U_j}, 𝖣.ι j ⁻¹' (𝖣.ι i '' U))` -/ @@ -409,7 +402,7 @@ theorem ιInvApp_π {i : D.J} (U : Opens (D.U i).carrier) : · exact h2.symm · have := D.ι_gluedIso_inv (PresheafedSpace.forget _) i dsimp at this - rw [← this, coe_comp] + rw [← this, TopCat.coe_comp] refine Function.Injective.comp ?_ (TopCat.GlueData.ι_injective D.toTopGlueData i) rw [← TopCat.mono_iff_injective] infer_instance @@ -515,8 +508,8 @@ def vPullbackConeIsLimit (i j : D.J) : IsLimit (𝖣.vPullbackCone i j) := exact this _ rw [← Set.image_subset_iff, ← Set.image_univ, ← Set.image_comp, Set.image_univ] -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11224): change `rw` to `erw` - erw [← coe_comp] - rw [this, coe_comp, ← Set.image_univ, Set.image_comp] + erw [← TopCat.coe_comp] + rw [this, TopCat.coe_comp, ← Set.image_univ, Set.image_comp] exact Set.image_subset_range _ _ · apply IsOpenImmersion.lift_fac · rw [← cancel_mono (𝖣.ι j), Category.assoc, ← (𝖣.vPullbackCone i j).condition] diff --git a/Mathlib/Geometry/RingedSpace/PresheafedSpace/HasColimits.lean b/Mathlib/Geometry/RingedSpace/PresheafedSpace/HasColimits.lean index 1f4e389113201..1d1a708437702 100644 --- a/Mathlib/Geometry/RingedSpace/PresheafedSpace/HasColimits.lean +++ b/Mathlib/Geometry/RingedSpace/PresheafedSpace/HasColimits.lean @@ -248,7 +248,9 @@ def colimitCoconeIsColimit (F : J ⥤ PresheafedSpace.{_, _, v} C) : m.base = colimit.desc (F ⋙ PresheafedSpace.forget C) ((PresheafedSpace.forget C).mapCocone s) := by dsimp - ext j + -- `colimit.hom_ext` used to be automatically applied by `ext` before https://github.com/leanprover-community/mathlib4/pull/21302 + apply colimit.hom_ext fun j => ?_ + ext rw [colimit.ι_desc, mapCocone_ι_app, ← w j] simp ext : 1 diff --git a/Mathlib/Geometry/RingedSpace/Stalks.lean b/Mathlib/Geometry/RingedSpace/Stalks.lean index 9574828c1ed89..828a1f82add07 100644 --- a/Mathlib/Geometry/RingedSpace/Stalks.lean +++ b/Mathlib/Geometry/RingedSpace/Stalks.lean @@ -185,7 +185,7 @@ def stalkIso {X Y : PresheafedSpace.{_, _, v} C} (α : X ≅ Y) (x : X) : @[reassoc, elementwise, simp, nolint simpNF] theorem stalkSpecializes_stalkMap {X Y : PresheafedSpace.{_, _, v} C} (f : X ⟶ Y) {x y : X} (h : x ⤳ y) : - Y.presheaf.stalkSpecializes (f.base.map_specializes h) ≫ f.stalkMap x = + Y.presheaf.stalkSpecializes (f.base.hom.map_specializes h) ≫ f.stalkMap x = f.stalkMap y ≫ X.presheaf.stalkSpecializes h := by -- Porting note: the original one liner `dsimp [stalkMap]; simp [stalkMap]` doesn't work, -- I had to uglify this diff --git a/Mathlib/MeasureTheory/Category/MeasCat.lean b/Mathlib/MeasureTheory/Category/MeasCat.lean index 1d461ae522957..ed9cde0e7bb8f 100644 --- a/Mathlib/MeasureTheory/Category/MeasCat.lean +++ b/Mathlib/MeasureTheory/Category/MeasCat.lean @@ -114,8 +114,9 @@ def Integral : Giry.Algebra where end MeasCat -instance TopCat.hasForgetToMeasCat : HasForget₂ TopCat.{u} MeasCat.{u} := - BundledHom.mkHasForget₂ borel (fun f => ⟨f.1, f.2.borel_measurable⟩) (fun _ => rfl) +instance TopCat.hasForgetToMeasCat : HasForget₂ TopCat.{u} MeasCat.{u} where + forget₂.obj X := @MeasCat.of _ (borel X) + forget₂.map f := ⟨f.1, f.hom.2.borel_measurable⟩ /-- The Borel functor, the canonical embedding of topological spaces into measurable spaces. -/ abbrev Borel : TopCat.{u} ⥤ MeasCat.{u} := diff --git a/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Basic.lean b/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Basic.lean index 3f060225021bb..534a4dbf5c1c6 100644 --- a/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Basic.lean +++ b/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Basic.lean @@ -74,13 +74,13 @@ is a closed set, thus implying Hausdorff in a topological group.)-/ compact and totally disconnected topological additive group. (The condition of being Hausdorff can be omitted here because totally disconnected implies that {0} is a closed set, thus implying Hausdorff in a topological additive group.)"] -def ProfiniteGrp.of (G : Type u) [Group G] [TopologicalSpace G] [TopologicalGroup G] +abbrev ProfiniteGrp.of (G : Type u) [Group G] [TopologicalSpace G] [TopologicalGroup G] [CompactSpace G] [TotallyDisconnectedSpace G] : ProfiniteGrp.{u} where toProfinite := .of G group := ‹_› topologicalGroup := ‹_› -@[to_additive (attr := simp)] +@[to_additive] lemma ProfiniteGrp.coe_of (G : Type u) [Group G] [TopologicalSpace G] [TopologicalGroup G] [CompactSpace G] [TotallyDisconnectedSpace G] : (ProfiniteGrp.of G : Type u) = G := rfl @@ -90,14 +90,14 @@ lemma ProfiniteGrp.coe_of (G : Type u) [Group G] [TopologicalSpace G] [Topologic structure ProfiniteAddGrp.Hom (A B : ProfiniteAddGrp.{u}) where private mk :: /-- The underlying `ContinuousAddMonoidHom`. -/ - hom : ContinuousAddMonoidHom A B + hom' : ContinuousAddMonoidHom A B /-- The type of morphisms in `ProfiniteGrp`. -/ @[to_additive (attr := ext) existing] structure ProfiniteGrp.Hom (A B : ProfiniteGrp.{u}) where private mk :: /-- The underlying `ContinuousMonoidHom`. -/ - hom : ContinuousMonoidHom A B + hom' : ContinuousMonoidHom A B attribute [to_additive existing ProfiniteAddGrp.Hom.mk] ProfiniteGrp.Hom.mk @@ -105,14 +105,26 @@ attribute [to_additive existing ProfiniteAddGrp.Hom.mk] ProfiniteGrp.Hom.mk instance : Category ProfiniteGrp where Hom A B := ProfiniteGrp.Hom A B id A := ⟨ContinuousMonoidHom.id A⟩ - comp f g := ⟨g.hom.comp f.hom⟩ + comp f g := ⟨g.hom'.comp f.hom'⟩ + +@[to_additive] +instance : ConcreteCategory ProfiniteGrp (fun X Y => ContinuousMonoidHom X Y) where + hom f := f.hom' + ofHom f := ⟨f⟩ + + /-- The underlying `ContinuousMonoidHom`. -/ +@[to_additive "The underlying `ContinuousAddMonoidHom`."] +abbrev ProfiniteGrp.Hom.hom {M N : ProfiniteGrp.{u}} (f : ProfiniteGrp.Hom M N) : + ContinuousMonoidHom M N := + ConcreteCategory.hom (C := ProfiniteGrp) f /-- Typecheck a `ContinuousMonoidHom` as a morphism in `ProfiniteGrp`. -/ @[to_additive "Typecheck a `ContinuousAddMonoidHom` as a morphism in `ProfiniteAddGrp`."] -abbrev ProfiniteGrp.ofHom {X Y: Type u} [Group X] [TopologicalSpace X] [TopologicalGroup X] +abbrev ProfiniteGrp.ofHom {X Y : Type u} [Group X] [TopologicalSpace X] [TopologicalGroup X] [CompactSpace X] [TotallyDisconnectedSpace X] [Group Y] [TopologicalSpace Y] [TopologicalGroup Y] [CompactSpace Y] [TotallyDisconnectedSpace Y] - (f : ContinuousMonoidHom X Y) : ProfiniteGrp.of X ⟶ ProfiniteGrp.of Y := ⟨f⟩ + (f : ContinuousMonoidHom X Y) : ProfiniteGrp.of X ⟶ ProfiniteGrp.of Y := + ConcreteCategory.ofHom f namespace ProfiniteGrp @@ -147,7 +159,7 @@ variable {X Y Z : Type u} [Group X] [TopologicalSpace X] [TopologicalGroup X] [TopologicalGroup Y] [CompactSpace Y] [TotallyDisconnectedSpace Y] [Group Z] [TopologicalSpace Z] [TopologicalGroup Z] [CompactSpace Z] [TotallyDisconnectedSpace Z] -@[to_additive] +@[to_additive (attr := simp)] lemma hom_ofHom (f : ContinuousMonoidHom X Y) : (ofHom f).hom = f := rfl @[to_additive (attr := simp)] @@ -175,20 +187,13 @@ lemma hom_inv_apply {A B : ProfiniteGrp.{u}} (e : A ≅ B) (x : B) : e.hom (e.in rw [← comp_apply] simp -@[to_additive] -instance : HasForget ProfiniteGrp where - forget := - { obj := fun G => G - map := fun f => f } - forget_faithful := ⟨fun h => by ext x; simpa using congrFun h x⟩ - @[to_additive (attr := simp)] -theorem coe_id (X : ProfiniteGrp) : (𝟙 ((forget ProfiniteGrp).obj X)) = id := +theorem coe_id (X : ProfiniteGrp) : (𝟙 X : X → X) = id := rfl @[to_additive (attr := simp)] theorem coe_comp {X Y Z : ProfiniteGrp} (f : X ⟶ Y) (g : Y ⟶ Z) : - ((forget ProfiniteGrp).map f ≫ (forget ProfiniteGrp).map g) = g ∘ f := + (f ≫ g : X → Z) = g ∘ f := rfl /-- Construct a term of `ProfiniteGrp` from a type endowed with the structure of a @@ -246,20 +251,20 @@ def ofContinuousMulEquiv {G : ProfiniteGrp.{u}} {H : Type v} [TopologicalSpace H /-- Build an isomorphism in the category `ProfiniteGrp` from a `ContinuousMulEquiv` between `ProfiniteGrp`s. -/ def ContinuousMulEquiv.toProfiniteGrpIso {X Y : ProfiniteGrp} (e : X ≃ₜ* Y) : X ≅ Y where - hom := ⟨e⟩ - inv := ⟨e.symm⟩ + hom := ofHom e + inv := ofHom e.symm /-- The functor mapping a profinite group to its underlying profinite space. -/ @[to_additive] instance : HasForget₂ ProfiniteGrp Profinite where forget₂ := { obj G := G.toProfinite - map f := ⟨f, by continuity⟩} + map f := CompHausLike.ofHom _ ⟨f, by continuity⟩} @[to_additive] instance : (forget₂ ProfiniteGrp Profinite).Faithful := { map_injective := fun {_ _} _ _ h => - ConcreteCategory.hom_ext_iff.mpr (congrFun (congrArg ContinuousMap.toFun h)) } + ConcreteCategory.hom_ext _ _ (CategoryTheory.congr_fun h) } instance : (forget₂ ProfiniteGrp Profinite).ReflectsIsomorphisms where reflects {X Y} f _ := by @@ -329,13 +334,13 @@ abbrev limitCone : Limits.Cone F where /-- `ProfiniteGrp.limitCone` is a limit cone. -/ def limitConeIsLimit : Limits.IsLimit (limitCone F) where - lift cone := ⟨{ - ((Profinite.limitConeIsLimit (F ⋙ (forget₂ ProfiniteGrp Profinite))).lift - ((forget₂ ProfiniteGrp Profinite).mapCone cone)) with - map_one' := Subtype.ext (funext fun j ↦ map_one (cone.π.app j).hom) - -- TODO: investigate whether it's possible to set up `ext` lemmas for the `TopCat`-related - -- categories so that `by ext j; exact map_one (cone.π.app j)` works here, similarly below. - map_mul' := fun _ _ ↦ Subtype.ext (funext fun j ↦ map_mul (cone.π.app j).hom _ _) }⟩ + lift cone := ofHom + { ((Profinite.limitConeIsLimit (F ⋙ (forget₂ ProfiniteGrp Profinite))).lift + ((forget₂ ProfiniteGrp Profinite).mapCone cone)).hom with + map_one' := Subtype.ext (funext fun j ↦ map_one (cone.π.app j).hom) + -- TODO: investigate whether it's possible to set up `ext` lemmas for the `TopCat`-related + -- categories so that `by ext j; exact map_one (cone.π.app j)` works here, similarly below. + map_mul' := fun _ _ ↦ Subtype.ext (funext fun j ↦ map_mul (cone.π.app j).hom _ _) } uniq cone m h := by apply (forget₂ ProfiniteGrp Profinite).map_injective simpa using (Profinite.limitConeIsLimit (F ⋙ (forget₂ ProfiniteGrp Profinite))).uniq diff --git a/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Limits.lean b/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Limits.lean index 47ceb0a6bf6bf..f9eccd2caf732 100644 --- a/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Limits.lean +++ b/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Limits.lean @@ -60,10 +60,9 @@ def toLimit_fun (P : ProfiniteGrp.{u}) : P →* lemma toLimit_fun_continuous (P : ProfiniteGrp.{u}) : Continuous (toLimit_fun P) := by apply continuous_induced_rng.mpr (continuous_pi _) intro H - dsimp only [Functor.comp_obj, CompHausLike.toCompHausLike_obj, CompHausLike.compHausLikeToTop_obj, - CompHausLike.coe_of, Functor.comp_map, CompHausLike.toCompHausLike_map, - CompHausLike.compHausLikeToTop_map, Set.mem_setOf_eq, toLimit_fun, - MonoidHom.coe_mk, OneHom.coe_mk, Function.comp_apply] + dsimp only [Functor.comp_obj, CompHausLike.coe_of, Functor.comp_map, + CompHausLike.toCompHausLike_map, CompHausLike.compHausLikeToTop_map, Set.mem_setOf_eq, + toLimit_fun, MonoidHom.coe_mk, OneHom.coe_mk, Function.comp_apply] apply Continuous.mk intro s _ rw [← (Set.biUnion_preimage_singleton QuotientGroup.mk s)] diff --git a/Mathlib/Topology/CWComplex.lean b/Mathlib/Topology/CWComplex.lean index 8dae230580f73..5223795380a0e 100644 --- a/Mathlib/Topology/CWComplex.lean +++ b/Mathlib/Topology/CWComplex.lean @@ -38,11 +38,12 @@ namespace RelativeCWComplex /-- The inclusion map from the `n`-sphere to the `(n + 1)`-disk. (For `n = -1`, this involves the empty space `𝕊 (-1)`. This is the reason why `sphere` takes `n : ℤ` as an input rather than `n : ℕ`.) -/ -def sphereInclusion (n : ℤ) : 𝕊 n ⟶ 𝔻 (n + 1) where - toFun := fun ⟨p, hp⟩ ↦ ⟨p, le_of_eq hp⟩ - continuous_toFun := ⟨fun t ⟨s, ⟨r, hro, hrs⟩, hst⟩ ↦ by - rw [isOpen_induced_iff, ← hst, ← hrs] - tauto⟩ +def sphereInclusion (n : ℤ) : 𝕊 n ⟶ 𝔻 (n + 1) := + TopCat.ofHom + { toFun := fun ⟨p, hp⟩ ↦ ⟨p, le_of_eq hp⟩ + continuous_toFun := ⟨fun t ⟨s, ⟨r, hro, hrs⟩, hst⟩ ↦ by + rw [isOpen_induced_iff, ← hst, ← hrs] + tauto⟩ } /-- A type witnessing that `X'` is obtained from `X` by attaching generalized cells `f : S ⟶ D` -/ structure AttachGeneralizedCells {S D : TopCat.{u}} (f : S ⟶ D) (X X' : TopCat.{u}) where diff --git a/Mathlib/Topology/Category/CompHaus/Basic.lean b/Mathlib/Topology/Category/CompHaus/Basic.lean index 705abf604355d..af6a4a5738214 100644 --- a/Mathlib/Topology/Category/CompHaus/Basic.lean +++ b/Mathlib/Topology/Category/CompHaus/Basic.lean @@ -34,9 +34,6 @@ The category `CompHaus` is defined using the structure `CompHausLike`. See the f universe v u --- This was a global instance prior to https://github.com/leanprover-community/mathlib4/pull/13170. We may experiment with removing it. -attribute [local instance] CategoryTheory.HasForget.instFunLike - open CategoryTheory CompHausLike /-- The category of compact Hausdorff spaces. -/ @@ -45,7 +42,7 @@ abbrev CompHaus := CompHausLike (fun _ ↦ True) namespace CompHaus instance : Inhabited CompHaus := - ⟨{ toTop := { α := PEmpty }, prop := trivial}⟩ + ⟨{ toTop := TopCat.of PEmpty, prop := trivial}⟩ instance : CoeSort CompHaus Type* := ⟨fun X => X.toTop⟩ @@ -85,17 +82,15 @@ Hausdorff spaces in topological spaces. -/ noncomputable def stoneCechEquivalence (X : TopCat.{u}) (Y : CompHaus.{u}) : (stoneCechObj X ⟶ Y) ≃ (X ⟶ compHausToTop.obj Y) where - toFun f := + toFun f := TopCat.ofHom { toFun := f ∘ stoneCechUnit - continuous_toFun := f.2.comp (@continuous_stoneCechUnit X _) } - invFun f := - { toFun := stoneCechExtend f.2 - continuous_toFun := continuous_stoneCechExtend f.2 } + continuous_toFun := f.hom.2.comp (@continuous_stoneCechUnit X _) } + invFun f := CompHausLike.ofHom _ + { toFun := stoneCechExtend f.hom.2 + continuous_toFun := continuous_stoneCechExtend f.hom.2 } left_inv := by rintro ⟨f : StoneCech X ⟶ Y, hf : Continuous f⟩ - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11041): `ext` fails. - apply ContinuousMap.ext - intro (x : StoneCech X) + ext x refine congr_fun ?_ x apply Continuous.ext_on denseRange_stoneCechUnit (continuous_stoneCechExtend _) hf · rintro _ ⟨y, rfl⟩ @@ -103,9 +98,7 @@ noncomputable def stoneCechEquivalence (X : TopCat.{u}) (Y : CompHaus.{u}) : apply continuous_stoneCechUnit right_inv := by rintro ⟨f : (X : Type _) ⟶ Y, hf : Continuous f⟩ - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11041): `ext` fails. - apply ContinuousMap.ext - intro + ext exact congr_fun (stoneCechExtend_extends hf) _ /-- The Stone-Cech compactification functor from topological spaces to compact Hausdorff spaces, @@ -157,7 +150,7 @@ def limitCone {J : Type v} [SmallCategory J] (F : J ⥤ CompHaus.{max v u}) : Li apply isClosed_iInter intro f apply isClosed_eq - · exact (ContinuousMap.continuous (F.map f)).comp (continuous_apply i) + · exact ((F.map f).hom.continuous).comp (continuous_apply i) · exact continuous_apply j is_hausdorff := show T2Space { u : ∀ j, F.obj j | ∀ {i j : J} (f : i ⟶ j), (F.map f) (u i) = u j } from @@ -185,7 +178,7 @@ theorem epi_iff_surjective {X Y : CompHaus.{u}} (f : X ⟶ Y) : Epi f ↔ Functi contrapose! rintro ⟨y, hy⟩ hf let C := Set.range f - have hC : IsClosed C := (isCompact_range f.continuous).isClosed + have hC : IsClosed C := (isCompact_range f.hom.continuous).isClosed let D := ({y} : Set Y) have hD : IsClosed D := isClosed_singleton have hCD : Disjoint C D := by @@ -196,27 +189,17 @@ theorem epi_iff_surjective {X Y : CompHaus.{u}} (f : X ⟶ Y) : Epi f ↔ Functi haveI : CompactSpace (ULift.{u} <| Set.Icc (0 : ℝ) 1) := Homeomorph.ulift.symm.compactSpace haveI : T2Space (ULift.{u} <| Set.Icc (0 : ℝ) 1) := Homeomorph.ulift.symm.t2Space let Z := of (ULift.{u} <| Set.Icc (0 : ℝ) 1) - let g : Y ⟶ Z := + let g : Y ⟶ Z := ofHom _ ⟨fun y' => ⟨⟨φ y', hφ01 y'⟩⟩, continuous_uLift_up.comp (φ.continuous.subtype_mk fun y' => hφ01 y')⟩ - let h : Y ⟶ Z := ⟨fun _ => ⟨⟨0, Set.left_mem_Icc.mpr zero_le_one⟩⟩, continuous_const⟩ + let h : Y ⟶ Z := ofHom _ + ⟨fun _ => ⟨⟨0, Set.left_mem_Icc.mpr zero_le_one⟩⟩, continuous_const⟩ have H : h = g := by rw [← cancel_epi f] - ext x - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11041): `ext` doesn't apply these two lemmas. - apply ULift.ext - apply Subtype.ext - dsimp - -- Porting note: This `change` is not ideal. - -- I think lean is having issues understanding when a `ContinuousMap` should be considered - -- as a morphism. - -- TODO(?): Make morphisms in `CompHaus` (and other topological categories) - -- into a one-field-structure. - change 0 = φ (f x) - simp only [hφ0 (Set.mem_range_self x), Pi.zero_apply] + ext x : 4 + simp [g, h, Z, hφ0 (Set.mem_range_self x)] apply_fun fun e => (e y).down.1 at H - dsimp [Z] at H - change 0 = φ y at H + dsimp [g, h, Z] at H simp only [hφ1 (Set.mem_singleton y), Pi.one_apply] at H exact zero_ne_one H · rw [← CategoryTheory.epi_iff_surjective] diff --git a/Mathlib/Topology/Category/CompHaus/EffectiveEpi.lean b/Mathlib/Topology/Category/CompHaus/EffectiveEpi.lean index 0c6a81f860057..ae813659bce41 100644 --- a/Mathlib/Topology/Category/CompHaus/EffectiveEpi.lean +++ b/Mathlib/Topology/Category/CompHaus/EffectiveEpi.lean @@ -29,8 +29,6 @@ universe u open CategoryTheory Limits CompHausLike -attribute [local instance] HasForget.instFunLike - namespace CompHaus open List in diff --git a/Mathlib/Topology/Category/CompHaus/Frm.lean b/Mathlib/Topology/Category/CompHaus/Frm.lean index 3e04891277900..b1cc66b4ec488 100644 --- a/Mathlib/Topology/Category/CompHaus/Frm.lean +++ b/Mathlib/Topology/Category/CompHaus/Frm.lean @@ -18,9 +18,10 @@ open TopologicalSpace Opposite CategoryTheory @[simps] def topCatOpToFrm : TopCatᵒᵖ ⥤ Frm where obj X := Frm.of (Opens (unop X : TopCat)) - map f := Opens.comap <| Quiver.Hom.unop f + map f := Opens.comap <| (Quiver.Hom.unop f).hom map_id _ := Opens.comap_id -- Note, `CompHaus` is too strong. We only need `T0Space`. instance CompHausOpToFrame.faithful : (compHausToTop.op ⋙ topCatOpToFrm.{u}).Faithful := - ⟨fun h => Quiver.Hom.unop_inj <| Opens.comap_injective h⟩ + ⟨fun {X _ _ _} h => Quiver.Hom.unop_inj <| ConcreteCategory.ext <| + Opens.comap_injective (β := (unop X).toTop) h⟩ diff --git a/Mathlib/Topology/Category/CompHaus/Projective.lean b/Mathlib/Topology/Category/CompHaus/Projective.lean index 94949dbecb705..e891c0742ab6c 100644 --- a/Mathlib/Topology/Category/CompHaus/Projective.lean +++ b/Mathlib/Topology/Category/CompHaus/Projective.lean @@ -34,8 +34,6 @@ open CategoryTheory Function namespace CompHaus -attribute [local instance] HasForget.instFunLike - instance projective_ultrafilter (X : Type*) : Projective (of <| Ultrafilter X) where factors {Y Z} f g hg := by rw [epi_iff_surjective] at hg @@ -43,14 +41,10 @@ instance projective_ultrafilter (X : Type*) : Projective (of <| Ultrafilter X) w let t : X → Y := g' ∘ f ∘ (pure : X → Ultrafilter X) let h : Ultrafilter X → Y := Ultrafilter.extend t have hh : Continuous h := continuous_ultrafilter_extend _ - use ⟨h, hh⟩ - apply (forget CompHaus).map_injective - simp only [Functor.map_comp, ContinuousMap.coe_mk, coe_comp] - convert denseRange_pure.equalizer (g.continuous.comp hh) f.continuous _ - -- Porting note: We need to get the coercions to functions under control. - -- The next two lines should not be needed. - let g'' : ContinuousMap Y Z := g - have : g'' ∘ g' = id := hg'.comp_eq_id + use CompHausLike.ofHom _ ⟨h, hh⟩ + apply ConcreteCategory.coe_ext + have : g.hom ∘ g' = id := hg'.comp_eq_id + convert denseRange_pure.equalizer (g.hom.continuous.comp hh) f.hom.continuous _ -- This used to be `rw`, but we need `rw; rfl` after https://github.com/leanprover/lean4/pull/2644 rw [comp_assoc, ultrafilter_extend_extends, ← comp_assoc, this, id_comp] rfl @@ -59,7 +53,7 @@ instance projective_ultrafilter (X : Type*) : Projective (of <| Ultrafilter X) w the natural map `Ultrafilter X → X` is a projective presentation. -/ def projectivePresentation (X : CompHaus) : ProjectivePresentation X where p := of <| Ultrafilter X - f := ⟨_, continuous_ultrafilter_extend id⟩ + f := CompHausLike.ofHom _ ⟨_, continuous_ultrafilter_extend id⟩ projective := CompHaus.projective_ultrafilter X epi := ConcreteCategory.epi_of_surjective _ fun x => diff --git a/Mathlib/Topology/Category/CompHausLike/Basic.lean b/Mathlib/Topology/Category/CompHausLike/Basic.lean index 7dd9915be9c18..d4bb77dfb91d8 100644 --- a/Mathlib/Topology/Category/CompHausLike/Basic.lean +++ b/Mathlib/Topology/Category/CompHausLike/Basic.lean @@ -64,8 +64,6 @@ universe u open CategoryTheory -attribute [local instance] HasForget.instFunLike - variable (P : TopCat.{u} → Prop) /-- The type of Compact Hausdorff topological spaces satisfying an additional property `P`. -/ @@ -89,8 +87,8 @@ instance : CoeSort (CompHausLike P) (Type u) := instance category : Category (CompHausLike P) := InducedCategory.category toTop -instance hasForget : HasForget (CompHausLike P) := - InducedCategory.hasForget _ +instance concreteCategory : ConcreteCategory (CompHausLike P) (C(·, ·)) := + InducedCategory.concreteCategory toTop instance hasForget₂ : HasForget₂ (CompHausLike P) TopCat := InducedCategory.hasForget₂ _ @@ -101,30 +99,47 @@ variable (X : Type u) [TopologicalSpace X] [CompactSpace X] [T2Space X] class HasProp : Prop where hasProp : P (TopCat.of X) +instance (X : CompHausLike P) : HasProp P X := ⟨X.4⟩ + variable [HasProp P X] /-- A constructor for objects of the category `CompHausLike P`, taking a type, and bundling the compact Hausdorff topology found by typeclass inference. -/ -def of : CompHausLike P where +abbrev of : CompHausLike P where toTop := TopCat.of X is_compact := ‹_› is_hausdorff := ‹_› prop := HasProp.hasProp -@[simp] -theorem coe_of : (CompHausLike.of P X : Type _) = X := - rfl +theorem coe_of : (CompHausLike.of P X : Type _) = X := rfl @[simp] -theorem coe_id (X : CompHausLike P) : (𝟙 ((forget (CompHausLike P)).obj X)) = id := +theorem coe_id (X : CompHausLike P) : (𝟙 X : X → X) = id := rfl @[simp] theorem coe_comp {X Y Z : CompHausLike P} (f : X ⟶ Y) (g : Y ⟶ Z) : - ((forget (CompHausLike P)).map f ≫ (forget (CompHausLike P)).map g) = g ∘ f := + (f ≫ g : X → Z) = g ∘ f := rfl +section + +variable {X} {Y : Type u} [TopologicalSpace Y] [CompactSpace Y] [T2Space Y] [HasProp P Y] +variable {Z : Type u} [TopologicalSpace Z] [CompactSpace Z] [T2Space Z] [HasProp P Z] + +/-- Typecheck a continous map as a morphism in the category `CompHausLike P`. -/ +abbrev ofHom (f : C(X, Y)) : of P X ⟶ of P Y := ConcreteCategory.ofHom f + +@[simp] lemma hom_ofHom (f : C(X, Y)) : ConcreteCategory.hom (ofHom P f) = f := rfl + +@[simp] lemma ofHom_id : ofHom P (ContinuousMap.id X) = 𝟙 (of _ X) := rfl + +@[simp] lemma ofHom_comp (f : C(X, Y)) (g : C(Y, Z)) : + ofHom P (g.comp f) = ofHom _ f ≫ ofHom _ g := rfl + +end + -- Note (https://github.com/leanprover-community/mathlib4/issues/10754): Lean does not see through the forgetful functor here instance (X : CompHausLike.{u} P) : TopologicalSpace ((forget (CompHausLike P)).obj X) := inferInstanceAs (TopologicalSpace X.toTop) @@ -140,7 +155,7 @@ instance (X : CompHausLike.{u} P) : T2Space ((forget (CompHausLike P)).obj X) := variable {P} /-- If `P` imples `P'`, then there is a functor from `CompHausLike P` to `CompHausLike P'`. -/ -@[simps] +@[simps map] def toCompHausLike {P P' : TopCat → Prop} (h : ∀ (X : CompHausLike P), P X.toTop → P' X.toTop) : CompHausLike P ⥤ CompHausLike P' where obj X := @@ -166,7 +181,7 @@ end variable (P) /-- The fully faithful embedding of `CompHausLike P` in `TopCat`. -/ -@[simps!] +@[simps! map] def compHausLikeToTop : CompHausLike.{u} P ⥤ TopCat.{u} := inducedFunctor _ -- deriving Full, Faithful -- Porting note: deriving fails, adding manually. @@ -200,16 +215,16 @@ theorem mono_iff_injective {X Y : CompHausLike.{u} P} (f : X ⟶ Y) : Mono f ↔ Function.Injective f := by constructor · intro hf x₁ x₂ h - let g₁ : X ⟶ X := ⟨fun _ => x₁, continuous_const⟩ - let g₂ : X ⟶ X := ⟨fun _ => x₂, continuous_const⟩ + let g₁ : X ⟶ X := ofHom _ ⟨fun _ => x₁, continuous_const⟩ + let g₂ : X ⟶ X := ofHom _ ⟨fun _ => x₂, continuous_const⟩ have : g₁ ≫ f = g₂ ≫ f := by ext; exact h - exact ContinuousMap.congr_fun ((cancel_mono _).mp this) x₁ + exact CategoryTheory.congr_fun ((cancel_mono _).mp this) x₁ · rw [← CategoryTheory.mono_iff_injective] apply (forget (CompHausLike P)).mono_of_mono_map /-- Any continuous function on compact Hausdorff spaces is a closed map. -/ theorem isClosedMap {X Y : CompHausLike.{u} P} (f : X ⟶ Y) : IsClosedMap f := fun _ hC => - (hC.isCompact.image f.continuous).isClosed + (hC.isCompact.image f.hom.continuous).isClosed /-- Any continuous bijection of compact Hausdorff spaces is an isomorphism. -/ theorem isIso_of_bijective {X Y : CompHausLike.{u} P} (f : X ⟶ Y) (bij : Function.Bijective f) : @@ -220,7 +235,7 @@ theorem isIso_of_bijective {X Y : CompHausLike.{u} P} (f : X ⟶ Y) (bij : Funct intro S hS rw [← E.image_eq_preimage] exact isClosedMap f S hS - refine ⟨⟨⟨E.symm, hE⟩, ?_, ?_⟩⟩ + refine ⟨⟨ofHom _ ⟨E.symm, hE⟩, ?_, ?_⟩⟩ · ext x apply E.symm_apply_apply · ext x @@ -258,7 +273,7 @@ def isoEquivHomeo {X Y : CompHausLike.{u} P} : (X ≅ Y) ≃ (X ≃ₜ Y) where /-- A constant map as a morphism in `CompHausLike` -/ def const {P : TopCat.{u} → Prop} (T : CompHausLike.{u} P) {S : CompHausLike.{u} P} (s : S) : T ⟶ S := - ContinuousMap.const _ s + ofHom _ (ContinuousMap.const _ s) lemma const_comp {P : TopCat.{u} → Prop} {S T U : CompHausLike.{u} P} (s : S) (g : S ⟶ U) : T.const s ≫ g = T.const (g s) := diff --git a/Mathlib/Topology/Category/CompHausLike/EffectiveEpi.lean b/Mathlib/Topology/Category/CompHausLike/EffectiveEpi.lean index 967d8531b8e53..91a9ffc3bf187 100644 --- a/Mathlib/Topology/Category/CompHausLike/EffectiveEpi.lean +++ b/Mathlib/Topology/Category/CompHausLike/EffectiveEpi.lean @@ -21,8 +21,6 @@ universe u open CategoryTheory Limits Topology -attribute [local instance] HasForget.instFunLike - namespace CompHausLike variable {P : TopCat.{u} → Prop} @@ -33,18 +31,30 @@ If `π` is a surjective morphism in `CompHausLike P`, then it is an effective ep noncomputable def effectiveEpiStruct {B X : CompHausLike P} (π : X ⟶ B) (hπ : Function.Surjective π) : EffectiveEpiStruct π where - desc e h := (IsQuotientMap.of_surjective_continuous hπ π.continuous).lift e fun a b hab ↦ - DFunLike.congr_fun (h ⟨fun _ ↦ a, continuous_const⟩ ⟨fun _ ↦ b, continuous_const⟩ - (by ext; exact hab)) a - fac e h := ((IsQuotientMap.of_surjective_continuous hπ π.continuous).lift_comp e - fun a b hab ↦ DFunLike.congr_fun (h ⟨fun _ ↦ a, continuous_const⟩ ⟨fun _ ↦ b, continuous_const⟩ + desc e h := ofHom _ ((IsQuotientMap.of_surjective_continuous hπ π.hom.continuous).lift e.hom + fun a b hab ↦ + CategoryTheory.congr_fun (h + (ofHom _ ⟨fun _ ↦ a, continuous_const⟩) + (ofHom _ ⟨fun _ ↦ b, continuous_const⟩) + (by ext; exact hab)) a) + fac e h := TopCat.hom_ext ((IsQuotientMap.of_surjective_continuous hπ π.hom.continuous).lift_comp + e.hom + fun a b hab ↦ CategoryTheory.congr_fun (h + (ofHom _ ⟨fun _ ↦ a, continuous_const⟩) + (ofHom _ ⟨fun _ ↦ b, continuous_const⟩) (by ext; exact hab)) a) uniq e h g hm := by - suffices g = (IsQuotientMap.of_surjective_continuous hπ π.continuous).liftEquiv ⟨e, - fun a b hab ↦ DFunLike.congr_fun - (h ⟨fun _ ↦ a, continuous_const⟩ ⟨fun _ ↦ b, continuous_const⟩ (by ext; exact hab)) - a⟩ by assumption - rw [← Equiv.symm_apply_eq (IsQuotientMap.of_surjective_continuous hπ π.continuous).liftEquiv] + suffices g = ofHom _ ((IsQuotientMap.of_surjective_continuous hπ π.hom.continuous).liftEquiv + ⟨e.hom, + fun a b hab ↦ CategoryTheory.congr_fun + (h + (ofHom _ ⟨fun _ ↦ a, continuous_const⟩) + (ofHom _ ⟨fun _ ↦ b, continuous_const⟩) + (by ext; exact hab)) + a⟩) by assumption + apply ConcreteCategory.ext + rw [hom_ofHom, + ← Equiv.symm_apply_eq (IsQuotientMap.of_surjective_continuous hπ π.hom.continuous).liftEquiv] ext simp only [IsQuotientMap.liftEquiv_symm_apply_coe, ContinuousMap.comp_apply, ← hm] rfl diff --git a/Mathlib/Topology/Category/CompHausLike/Limits.lean b/Mathlib/Topology/Category/CompHausLike/Limits.lean index a818fb4571e8b..92c8d6db22fc3 100644 --- a/Mathlib/Topology/Category/CompHausLike/Limits.lean +++ b/Mathlib/Topology/Category/CompHausLike/Limits.lean @@ -40,8 +40,6 @@ namespace CompHausLike universe w u -attribute [local instance] HasForget.instFunLike - section FiniteCoproducts variable {P : TopCat.{max u w} → Prop} {α : Type w} [Finite α] (X : α → CompHausLike P) @@ -63,9 +61,10 @@ def finiteCoproduct : CompHausLike P := CompHausLike.of P (Σ (a : α), X a) /-- The inclusion of one of the factors into the explicit finite coproduct. -/ -def finiteCoproduct.ι (a : α) : X a ⟶ finiteCoproduct X where - toFun := fun x ↦ ⟨a, x⟩ - continuous_toFun := continuous_sigmaMk (σ := fun a ↦ X a) +def finiteCoproduct.ι (a : α) : X a ⟶ finiteCoproduct X := + ofHom _ + { toFun := fun x ↦ ⟨a, x⟩ + continuous_toFun := continuous_sigmaMk (σ := fun a ↦ X a) } /-- To construct a morphism from the explicit finite coproduct, it suffices to @@ -73,11 +72,12 @@ specify a morphism from each of its factors. This is essentially the universal property of the coproduct. -/ def finiteCoproduct.desc {B : CompHausLike P} (e : (a : α) → (X a ⟶ B)) : - finiteCoproduct X ⟶ B where - toFun := fun ⟨a, x⟩ ↦ e a x - continuous_toFun := by - apply continuous_sigma - intro a; exact (e a).continuous + finiteCoproduct X ⟶ B := + ofHom _ + { toFun := fun ⟨a, x⟩ ↦ e a x + continuous_toFun := by + apply continuous_sigma + intro a; exact (e a).hom.continuous } @[reassoc (attr := simp)] lemma finiteCoproduct.ι_desc {B : CompHausLike P} (e : (a : α) → (X a ⟶ B)) (a : α) : @@ -100,7 +100,7 @@ def finiteCoproduct.isColimit : Limits.IsColimit (finiteCoproduct.cofan X) := (fun s ↦ desc _ fun a ↦ s.inj a) (fun _ _ ↦ ι_desc _ _ _) fun _ _ hm ↦ finiteCoproduct.hom_ext _ _ _ fun a ↦ - (DFunLike.ext _ _ fun t ↦ congrFun (congrArg DFunLike.coe (hm a)) t) + (ConcreteCategory.hom_ext _ _ fun t ↦ congrFun (congrArg _ (hm a)) t) lemma finiteCoproduct.ι_injective (a : α) : Function.Injective (finiteCoproduct.ι X a) := by intro x y hxy @@ -207,23 +207,25 @@ pairs `(x,y)` such that `f x = g y`, with the topology induced by the product. def pullback : CompHausLike P := letI set := { xy : X × Y | f xy.fst = g xy.snd } haveI : CompactSpace set := - isCompact_iff_compactSpace.mp (isClosed_eq (f.continuous.comp continuous_fst) - (g.continuous.comp continuous_snd)).isCompact + isCompact_iff_compactSpace.mp (isClosed_eq (f.hom.continuous.comp continuous_fst) + (g.hom.continuous.comp continuous_snd)).isCompact CompHausLike.of P set /-- The projection from the pullback to the first component. -/ -def pullback.fst : pullback f g ⟶ X where - toFun := fun ⟨⟨x, _⟩, _⟩ ↦ x - continuous_toFun := Continuous.comp continuous_fst continuous_subtype_val +def pullback.fst : pullback f g ⟶ X := + TopCat.ofHom + { toFun := fun ⟨⟨x, _⟩, _⟩ ↦ x + continuous_toFun := Continuous.comp continuous_fst continuous_subtype_val } /-- The projection from the pullback to the second component. -/ -def pullback.snd : pullback f g ⟶ Y where - toFun := fun ⟨⟨_,y⟩,_⟩ ↦ y - continuous_toFun := Continuous.comp continuous_snd continuous_subtype_val +def pullback.snd : pullback f g ⟶ Y := + TopCat.ofHom + { toFun := fun ⟨⟨_,y⟩,_⟩ ↦ y + continuous_toFun := Continuous.comp continuous_snd continuous_subtype_val } @[reassoc] lemma pullback.condition : pullback.fst f g ≫ f = pullback.snd f g ≫ g := by @@ -235,12 +237,13 @@ which are compatible with the maps to the base. This is essentially the universal property of the pullback. -/ def pullback.lift {Z : CompHausLike P} (a : Z ⟶ X) (b : Z ⟶ Y) (w : a ≫ f = b ≫ g) : - Z ⟶ pullback f g where - toFun := fun z ↦ ⟨⟨a z, b z⟩, by apply_fun (fun q ↦ q z) at w; exact w⟩ - continuous_toFun := by - apply Continuous.subtype_mk - rw [continuous_prod_mk] - exact ⟨a.continuous, b.continuous⟩ + Z ⟶ pullback f g := + TopCat.ofHom + { toFun := fun z ↦ ⟨⟨a z, b z⟩, by apply_fun (fun q ↦ q z) at w; exact w⟩ + continuous_toFun := by + apply Continuous.subtype_mk + rw [continuous_prod_mk] + exact ⟨a.hom.continuous, b.hom.continuous⟩ } @[reassoc (attr := simp)] lemma pullback.lift_fst {Z : CompHausLike P} (a : Z ⟶ X) (b : Z ⟶ Y) (w : a ≫ f = b ≫ g) : @@ -371,7 +374,7 @@ variable {P : TopCat.{u} → Prop} def isTerminalPUnit [HasProp P PUnit.{u+1}] : IsTerminal (CompHausLike.of P PUnit.{u + 1}) := haveI : ∀ X, Unique (X ⟶ CompHausLike.of P PUnit.{u + 1}) := fun _ ↦ - ⟨⟨⟨fun _ ↦ PUnit.unit, continuous_const⟩⟩, fun _ ↦ rfl⟩ + ⟨⟨ofHom _ ⟨fun _ ↦ PUnit.unit, continuous_const⟩⟩, fun _ ↦ rfl⟩ Limits.IsTerminal.ofUnique _ end Terminal diff --git a/Mathlib/Topology/Category/CompHausLike/SigmaComparison.lean b/Mathlib/Topology/Category/CompHausLike/SigmaComparison.lean index fc574ef66ea35..85db117945a69 100644 --- a/Mathlib/Topology/Category/CompHausLike/SigmaComparison.lean +++ b/Mathlib/Topology/Category/CompHausLike/SigmaComparison.lean @@ -36,7 +36,7 @@ The comparison map from the value of a condensed set on a finite coproduct to th values on the components. -/ def sigmaComparison : X.obj ⟨(of P ((a : α) × σ a))⟩ ⟶ ((a : α) → X.obj ⟨of P (σ a)⟩) := - fun x a ↦ X.map ⟨Sigma.mk a, continuous_sigmaMk⟩ x + fun x a ↦ X.map (ofHom _ ⟨Sigma.mk a, continuous_sigmaMk⟩).op x theorem sigmaComparison_eq_comp_isos : sigmaComparison X σ = (X.mapIso (opCoproductIsoProduct' diff --git a/Mathlib/Topology/Category/CompactlyGenerated.lean b/Mathlib/Topology/Category/CompactlyGenerated.lean index 3defff92c5ca0..b98907c3e182e 100644 --- a/Mathlib/Topology/Category/CompactlyGenerated.lean +++ b/Mathlib/Topology/Category/CompactlyGenerated.lean @@ -37,7 +37,7 @@ structure CompactlyGenerated where namespace CompactlyGenerated instance : Inhabited CompactlyGenerated.{u, w} := - ⟨{ toTop := { α := ULift (Fin 37) } }⟩ + ⟨{ toTop := TopCat.of (ULift (Fin 37)) }⟩ instance : CoeSort CompactlyGenerated Type* := ⟨fun X => X.toTop⟩ @@ -47,16 +47,25 @@ attribute [instance] is_compactly_generated instance : Category.{w, w+1} CompactlyGenerated.{u, w} := InducedCategory.category toTop -instance : HasForget.{w} CompactlyGenerated.{u, w} := - InducedCategory.hasForget _ +instance : ConcreteCategory.{w} CompactlyGenerated.{u, w} (C(·, ·)) := + InducedCategory.concreteCategory toTop variable (X : Type w) [TopologicalSpace X] [UCompactlyGeneratedSpace.{u} X] /-- Constructor for objects of the category `CompactlyGenerated`. -/ -def of : CompactlyGenerated.{u, w} where +abbrev of : CompactlyGenerated.{u, w} where toTop := TopCat.of X is_compactly_generated := ‹_› +section + +variable {X} {Y : Type w} [TopologicalSpace Y] [UCompactlyGeneratedSpace.{u} Y] + +/-- Typecheck a `ContinuousMap` as a morphism in `CompactlyGenerated`. -/ +abbrev ofHom (f : C(X, Y)) : of X ⟶ of Y := ConcreteCategory.ofHom f + +end + /-- The fully faithful embedding of `CompactlyGenerated` in `TopCat`. -/ @[simps!] def compactlyGeneratedToTop : CompactlyGenerated.{u, w} ⥤ TopCat.{w} := @@ -73,8 +82,8 @@ instance : compactlyGeneratedToTop.{u, w}.Faithful := fullyFaithfulCompactlyGene /-- Construct an isomorphism from a homeomorphism. -/ @[simps hom inv] def isoOfHomeo {X Y : CompactlyGenerated.{u, w}} (f : X ≃ₜ Y) : X ≅ Y where - hom := ⟨f, f.continuous⟩ - inv := ⟨f.symm, f.symm.continuous⟩ + hom := ofHom ⟨f, f.continuous⟩ + inv := ofHom ⟨f.symm, f.symm.continuous⟩ hom_inv_id := by ext x exact f.symm_apply_apply x @@ -87,10 +96,10 @@ def isoOfHomeo {X Y : CompactlyGenerated.{u, w}} (f : X ≃ₜ Y) : X ≅ Y wher def homeoOfIso {X Y : CompactlyGenerated.{u, w}} (f : X ≅ Y) : X ≃ₜ Y where toFun := f.hom invFun := f.inv - left_inv x := by simp - right_inv x := by simp - continuous_toFun := f.hom.continuous - continuous_invFun := f.inv.continuous + left_inv := f.hom_inv_id_apply + right_inv := f.inv_hom_id_apply + continuous_toFun := f.hom.hom.continuous + continuous_invFun := f.inv.hom.continuous /-- The equivalence between isomorphisms in `CompactlyGenerated` and homeomorphisms of topological spaces. -/ diff --git a/Mathlib/Topology/Category/Compactum.lean b/Mathlib/Topology/Category/Compactum.lean index 32dbfd00182a5..e336d80b202f0 100644 --- a/Mathlib/Topology/Category/Compactum.lean +++ b/Mathlib/Topology/Category/Compactum.lean @@ -407,8 +407,8 @@ end Compactum /-- The functor functor from Compactum to CompHaus. -/ def compactumToCompHaus : Compactum ⥤ CompHaus where - obj X := { toTop := { α := X }, prop := trivial } - map := fun f => + obj X := { toTop := TopCat.of X, prop := trivial } + map := fun f => CompHausLike.ofHom _ { toFun := f continuous_toFun := Compactum.continuous_of_hom _ } @@ -416,7 +416,7 @@ namespace compactumToCompHaus /-- The functor `compactumToCompHaus` is full. -/ instance full : compactumToCompHaus.{u}.Full where - map_surjective f := ⟨Compactum.homOfContinuous f.1 f.2, rfl⟩ + map_surjective f := ⟨Compactum.homOfContinuous f.1 f.hom.2, rfl⟩ /-- The functor `compactumToCompHaus` is faithful. -/ instance faithful : compactumToCompHaus.Faithful where @@ -425,18 +425,18 @@ instance faithful : compactumToCompHaus.Faithful where intro _ _ _ _ h -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11041): `ext` gets confused by coercion using forget. apply Monad.Algebra.Hom.ext - apply congrArg (fun f => f.toFun) h + apply congrArg (fun f => f.hom.toFun) h /-- This definition is used to prove essential surjectivity of `compactumToCompHaus`. -/ def isoOfTopologicalSpace {D : CompHaus} : compactumToCompHaus.obj (Compactum.ofTopologicalSpace D) ≅ D where - hom := + hom := CompHausLike.ofHom _ { toFun := id continuous_toFun := continuous_def.2 fun _ h => by rw [isOpen_iff_ultrafilter'] at h exact h } - inv := + inv := CompHausLike.ofHom _ { toFun := id continuous_toFun := continuous_def.2 fun _ h1 => by diff --git a/Mathlib/Topology/Category/DeltaGenerated.lean b/Mathlib/Topology/Category/DeltaGenerated.lean index 7024dfe3ba5b2..42cdecc4815f8 100644 --- a/Mathlib/Topology/Category/DeltaGenerated.lean +++ b/Mathlib/Topology/Category/DeltaGenerated.lean @@ -41,11 +41,11 @@ attribute [instance] deltaGenerated instance : LargeCategory.{u} DeltaGenerated.{u} := InducedCategory.category toTop -instance : HasForget.{u} DeltaGenerated.{u} := - InducedCategory.hasForget _ +instance : ConcreteCategory.{u} DeltaGenerated.{u} (C(·, ·)) := + InducedCategory.concreteCategory toTop /-- Constructor for objects of the category `DeltaGenerated` -/ -def of (X : Type u) [TopologicalSpace X] [DeltaGeneratedSpace X] : DeltaGenerated.{u} where +abbrev of (X : Type u) [TopologicalSpace X] [DeltaGeneratedSpace X] : DeltaGenerated.{u} where toTop := TopCat.of X deltaGenerated := ‹_› @@ -67,19 +67,19 @@ instance : deltaGeneratedToTop.{u}.Faithful := fullyFaithfulDeltaGeneratedToTop. @[simps!] def topToDeltaGenerated : TopCat.{u} ⥤ DeltaGenerated.{u} where obj X := of (DeltaGeneratedSpace.of X) - map {_ Y} f := ⟨f, (continuous_to_deltaGenerated (Y := Y)).mpr <| - continuous_le_dom deltaGenerated_le f.continuous⟩ + map {_ Y} f := TopCat.ofHom ⟨f, (continuous_to_deltaGenerated (Y := Y)).mpr <| + continuous_le_dom deltaGenerated_le f.hom.continuous⟩ instance : topToDeltaGenerated.{u}.Faithful := - ⟨fun h ↦ by ext x; exact congrFun (congrArg ContinuousMap.toFun h) x⟩ + ⟨fun h ↦ by ext x; exact CategoryTheory.congr_fun h x⟩ /-- The adjunction between the forgetful functor `DeltaGenerated ⥤ TopCat` and its coreflector. -/ def coreflectorAdjunction : deltaGeneratedToTop ⊣ topToDeltaGenerated := Adjunction.mkOfUnitCounit { unit := { - app X := ⟨id, continuous_iff_coinduced_le.mpr (eq_deltaGenerated (X := X)).le⟩ } + app X := TopCat.ofHom ⟨id, continuous_iff_coinduced_le.mpr (eq_deltaGenerated (X := X)).le⟩ } counit := { - app X := ⟨DeltaGeneratedSpace.counit, DeltaGeneratedSpace.continuous_counit⟩ }} + app X := TopCat.ofHom ⟨DeltaGeneratedSpace.counit, DeltaGeneratedSpace.continuous_counit⟩ }} /-- The category of delta-generated spaces is coreflective in the category of topological spaces. -/ instance deltaGeneratedToTop.coreflective : Coreflective deltaGeneratedToTop where diff --git a/Mathlib/Topology/Category/FinTopCat.lean b/Mathlib/Topology/Category/FinTopCat.lean index ff492e48cdfcf..34fca348c9e7f 100644 --- a/Mathlib/Topology/Category/FinTopCat.lean +++ b/Mathlib/Topology/Category/FinTopCat.lean @@ -22,13 +22,13 @@ open CategoryTheory /-- A bundled finite topological space. -/ structure FinTopCat where /-- carrier of a finite topological space. -/ - toTop : TopCat.{u} + toTop : TopCat.{u} -- TODO: turn this into an `extends`? [fintype : Fintype toTop] namespace FinTopCat instance : Inhabited FinTopCat := - ⟨{ toTop := { α := PEmpty } }⟩ + ⟨{ toTop := TopCat.of PEmpty }⟩ instance : CoeSort FinTopCat (Type u) := ⟨fun X => X.toTop⟩ @@ -38,14 +38,8 @@ attribute [instance] fintype instance : Category FinTopCat := InducedCategory.category toTop -instance : HasForget FinTopCat := - InducedCategory.hasForget _ - -instance (X : FinTopCat) : TopologicalSpace ((forget FinTopCat).obj X) := - inferInstanceAs <| TopologicalSpace X - -instance (X : FinTopCat) : Fintype ((forget FinTopCat).obj X) := - X.fintype +instance : ConcreteCategory FinTopCat (C(·, ·)) := + InducedCategory.concreteCategory toTop /-- Construct a bundled `FinTopCat` from the underlying type and the appropriate typeclasses. -/ def of (X : Type u) [Fintype X] [TopologicalSpace X] : FinTopCat where @@ -59,7 +53,7 @@ theorem coe_of (X : Type u) [Fintype X] [TopologicalSpace X] : /-- The forgetful functor to `FintypeCat`. -/ instance : HasForget₂ FinTopCat FintypeCat := - HasForget₂.mk' (fun X ↦ FintypeCat.of X) (fun _ ↦ rfl) (fun f ↦ f.toFun) HEq.rfl + HasForget₂.mk' (fun X ↦ FintypeCat.of X) (fun _ ↦ rfl) (fun f ↦ f.hom.toFun) HEq.rfl instance (X : FinTopCat) : TopologicalSpace ((forget₂ FinTopCat FintypeCat).obj X) := inferInstanceAs <| TopologicalSpace X diff --git a/Mathlib/Topology/Category/LightProfinite/AsLimit.lean b/Mathlib/Topology/Category/LightProfinite/AsLimit.lean index a7680b1ad8bb9..a7201f66bea5d 100644 --- a/Mathlib/Topology/Category/LightProfinite/AsLimit.lean +++ b/Mathlib/Topology/Category/LightProfinite/AsLimit.lean @@ -20,8 +20,6 @@ noncomputable section open CategoryTheory Limits CompHausLike -attribute [local instance] HasForget.instFunLike - namespace LightProfinite universe u @@ -79,7 +77,7 @@ abbrev proj (n : ℕ) : S ⟶ S.diagram.obj ⟨n⟩ := S.asLimitCone.π.app ⟨n lemma lightToProfinite_map_proj_eq (n : ℕ) : lightToProfinite.map (S.proj n) = (lightToProfinite.obj S).asLimitCone.π.app _ := by - simp only [toCompHausLike_obj, Functor.comp_obj, toCompHausLike_map, coe_of] + simp only [Functor.comp_obj, toCompHausLike_map, coe_of] let c : Cone (S.diagram ⋙ lightToProfinite) := S.toLightDiagram.cone let hc : IsLimit c := S.toLightDiagram.isLimit exact liftedLimitMapsToOriginal_inv_map_π hc _ diff --git a/Mathlib/Topology/Category/LightProfinite/Basic.lean b/Mathlib/Topology/Category/LightProfinite/Basic.lean index 7644318842d13..02867f3283bab 100644 --- a/Mathlib/Topology/Category/LightProfinite/Basic.lean +++ b/Mathlib/Topology/Category/LightProfinite/Basic.lean @@ -32,12 +32,6 @@ where possible, try to keep them in sync -/ universe v u -/- -Previously, this had accidentally been made a global instance, -and we now turn it on locally when convenient. --/ -attribute [local instance] CategoryTheory.HasForget.instFunLike - open CategoryTheory Limits Opposite FintypeCat Topology TopologicalSpace CompHausLike /-- `LightProfinite` is the category of second countable profinite spaces. -/ @@ -100,10 +94,10 @@ attribute [local instance] FintypeCat.discreteTopology /-- The natural functor from `Fintype` to `LightProfinite`, endowing a finite type with the discrete topology. -/ -@[simps! -isSimp map_apply] +@[simps! -isSimp map_hom_apply] def FintypeCat.toLightProfinite : FintypeCat ⥤ LightProfinite where obj A := LightProfinite.of A - map f := ⟨f, by continuity⟩ + map f := CompHausLike.ofHom _ ⟨f, by continuity⟩ /-- `FintypeCat.toLightProfinite` is fully faithful. -/ def FintypeCat.toLightProfiniteFullyFaithful : toLightProfinite.FullyFaithful where @@ -205,7 +199,7 @@ theorem epi_iff_surjective {X Y : LightProfinite.{u}} (f : X ⟶ Y) : contrapose! rintro ⟨y, hy⟩ hf let C := Set.range f - have hC : IsClosed C := (isCompact_range f.continuous).isClosed + have hC : IsClosed C := (isCompact_range f.hom.continuous).isClosed let U := Cᶜ have hyU : y ∈ U := by refine Set.mem_compl ?_ @@ -215,22 +209,20 @@ theorem epi_iff_surjective {X Y : LightProfinite.{u}} (f : X ⟶ Y) : obtain ⟨V, hV, hyV, hVU⟩ := isTopologicalBasis_isClopen.mem_nhds_iff.mp hUy classical let Z := of (ULift.{u} <| Fin 2) - let g : Y ⟶ Z := ⟨(LocallyConstant.ofIsClopen hV).map ULift.up, LocallyConstant.continuous _⟩ - let h : Y ⟶ Z := ⟨fun _ => ⟨1⟩, continuous_const⟩ + let g : Y ⟶ Z := CompHausLike.ofHom _ + ⟨(LocallyConstant.ofIsClopen hV).map ULift.up, LocallyConstant.continuous _⟩ + let h : Y ⟶ Z := CompHausLike.ofHom _ ⟨fun _ => ⟨1⟩, continuous_const⟩ have H : h = g := by rw [← cancel_epi f] ext x - apply ULift.ext dsimp [g, LocallyConstant.ofIsClopen] - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [CategoryTheory.comp_apply, ContinuousMap.coe_mk, - CategoryTheory.comp_apply, ContinuousMap.coe_mk, Function.comp_apply, if_neg] + rw [ContinuousMap.coe_mk, ContinuousMap.coe_mk, hom_ofHom, ContinuousMap.coe_mk, + Function.comp_apply, if_neg] refine mt (fun α => hVU α) ?_ - simp only [U, C, Set.mem_range_self, not_true, not_false_iff, Set.mem_compl_iff] + simp [U, C] apply_fun fun e => (e y).down at H dsimp [g, LocallyConstant.ofIsClopen] at H - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [ContinuousMap.coe_mk, ContinuousMap.coe_mk, Function.comp_apply, if_pos hyV] at H + rw [ContinuousMap.coe_mk, ContinuousMap.coe_mk, Function.comp_apply, if_pos hyV] at H exact top_ne_bot H · rw [← CategoryTheory.epi_iff_surjective] apply (forget LightProfinite).epi_of_epi_map @@ -257,7 +249,8 @@ def toProfinite (S : LightDiagram) : Profinite := S.cone.pt @[simps!] instance : Category LightDiagram := InducedCategory.category toProfinite -instance hasForget : HasForget LightDiagram := InducedCategory.hasForget _ +instance hasForget : ConcreteCategory LightDiagram (fun X Y => C(X.toProfinite, Y.toProfinite)) := + InducedCategory.concreteCategory toProfinite end LightDiagram @@ -321,13 +314,13 @@ instance (S : LightDiagram.{u}) : SecondCountableTopology S.cone.pt := by refine @Pi.finite _ _ ?_ _ simp only [Functor.comp_obj] exact show (Finite (S.diagram.obj _)) from inferInstance - · exact fun a ↦ a.snd.comap (S.cone.π.app ⟨a.fst⟩) + · exact fun a ↦ a.snd.comap (S.cone.π.app ⟨a.fst⟩).hom · intro a obtain ⟨n, g, h⟩ := Profinite.exists_locallyConstant S.cone S.isLimit a exact ⟨⟨unop n, g⟩, h.symm⟩ /-- The inverse part of the equivalence `LightProfinite ≌ LightDiagram` -/ -@[simps] +@[simps obj map] def lightDiagramToLightProfinite : LightDiagram.{u} ⥤ LightProfinite.{u} where obj X := LightProfinite.of X.cone.pt map f := f diff --git a/Mathlib/Topology/Category/LightProfinite/EffectiveEpi.lean b/Mathlib/Topology/Category/LightProfinite/EffectiveEpi.lean index 156e8287d0dc7..fac00ec92aca8 100644 --- a/Mathlib/Topology/Category/LightProfinite/EffectiveEpi.lean +++ b/Mathlib/Topology/Category/LightProfinite/EffectiveEpi.lean @@ -19,8 +19,6 @@ universe u open CategoryTheory Limits CompHausLike -attribute [local instance] HasForget.instFunLike - namespace LightProfinite theorem effectiveEpi_iff_surjective {X Y : LightProfinite.{u}} (f : X ⟶ Y) : diff --git a/Mathlib/Topology/Category/Locale.lean b/Mathlib/Topology/Category/Locale.lean index 208b21c604fbc..9991b17f693f1 100644 --- a/Mathlib/Topology/Category/Locale.lean +++ b/Mathlib/Topology/Category/Locale.lean @@ -53,4 +53,4 @@ def topToLocale : TopCat ⥤ Locale := instance CompHausToLocale.faithful : (compHausToTop ⋙ topToLocale.{u}).Faithful := ⟨fun h => by dsimp at h - exact Opens.comap_injective (Quiver.Hom.op_inj h)⟩ + exact ConcreteCategory.ext (Opens.comap_injective (Quiver.Hom.op_inj h))⟩ diff --git a/Mathlib/Topology/Category/Profinite/AsLimit.lean b/Mathlib/Topology/Category/Profinite/AsLimit.lean index a417cb6fdd284..c8ea63847dd6b 100644 --- a/Mathlib/Topology/Category/Profinite/AsLimit.lean +++ b/Mathlib/Topology/Category/Profinite/AsLimit.lean @@ -54,7 +54,8 @@ abbrev diagram : DiscreteQuotient X ⥤ Profinite := /-- A cone over `X.diagram` whose cone point is `X`. -/ def asLimitCone : CategoryTheory.Limits.Cone X.diagram := { pt := X - π := { app := fun S => ⟨S.proj, IsLocallyConstant.continuous (S.proj_isLocallyConstant)⟩ } } + π := { app := fun S => CompHausLike.ofHom (Y := X.diagram.obj S) _ + ⟨S.proj, IsLocallyConstant.continuous (S.proj_isLocallyConstant)⟩ } } instance isIso_asLimitCone_lift : IsIso ((limitConeIsLimit.{u, u} X.diagram).lift X.asLimitCone) := CompHausLike.isIso_of_bijective _ diff --git a/Mathlib/Topology/Category/Profinite/Basic.lean b/Mathlib/Topology/Category/Profinite/Basic.lean index 30959b584c678..3e4dfad34be93 100644 --- a/Mathlib/Topology/Category/Profinite/Basic.lean +++ b/Mathlib/Topology/Category/Profinite/Basic.lean @@ -109,12 +109,12 @@ spaces in compact Hausdorff spaces. -/ def Profinite.toCompHausEquivalence (X : CompHaus.{u}) (Y : Profinite.{u}) : (CompHaus.toProfiniteObj X ⟶ Y) ≃ (X ⟶ profiniteToCompHaus.obj Y) where - toFun f := f.comp ⟨Quotient.mk'', continuous_quotient_mk'⟩ - invFun g := - { toFun := Continuous.connectedComponentsLift g.2 - continuous_toFun := Continuous.connectedComponentsLift_continuous g.2 } - left_inv _ := ContinuousMap.ext <| ConnectedComponents.surjective_coe.forall.2 fun _ => rfl - right_inv _ := ContinuousMap.ext fun _ => rfl + toFun f := ofHom _ (f.hom.comp ⟨Quotient.mk'', continuous_quotient_mk'⟩) + invFun g := TopCat.ofHom + { toFun := Continuous.connectedComponentsLift g.hom.2 + continuous_toFun := Continuous.connectedComponentsLift_continuous g.hom.2 } + left_inv _ := TopCat.ext <| ConnectedComponents.surjective_coe.forall.2 fun _ => rfl + right_inv _ := TopCat.ext fun _ => rfl /-- The connected_components functor from compact Hausdorff spaces to profinite spaces, left adjoint to the inclusion functor. @@ -140,10 +140,10 @@ attribute [local instance] FintypeCat.discreteTopology /-- The natural functor from `Fintype` to `Profinite`, endowing a finite type with the discrete topology. -/ -@[simps -isSimp map_apply] +@[simps! -isSimp map_hom_apply] def FintypeCat.toProfinite : FintypeCat ⥤ Profinite where obj A := Profinite.of A - map f := ⟨f, by continuity⟩ + map f := ofHom _ ⟨f, by continuity⟩ /-- `FintypeCat.toLightProfinite` is fully faithful. -/ def FintypeCat.toProfiniteFullyFaithful : toProfinite.FullyFaithful where @@ -222,7 +222,7 @@ theorem epi_iff_surjective {X Y : Profinite.{u}} (f : X ⟶ Y) : Epi f ↔ Funct contrapose! rintro ⟨y, hy⟩ hf let C := Set.range f - have hC : IsClosed C := (isCompact_range f.continuous).isClosed + have hC : IsClosed C := (isCompact_range f.hom.continuous).isClosed let U := Cᶜ have hyU : y ∈ U := by refine Set.mem_compl ?_ @@ -232,22 +232,20 @@ theorem epi_iff_surjective {X Y : Profinite.{u}} (f : X ⟶ Y) : Epi f ↔ Funct obtain ⟨V, hV, hyV, hVU⟩ := isTopologicalBasis_isClopen.mem_nhds_iff.mp hUy classical let Z := of (ULift.{u} <| Fin 2) - let g : Y ⟶ Z := ⟨(LocallyConstant.ofIsClopen hV).map ULift.up, LocallyConstant.continuous _⟩ - let h : Y ⟶ Z := ⟨fun _ => ⟨1⟩, continuous_const⟩ + let g : Y ⟶ Z := ofHom _ + ⟨(LocallyConstant.ofIsClopen hV).map ULift.up, LocallyConstant.continuous _⟩ + let h : Y ⟶ Z := ofHom _ ⟨fun _ => ⟨1⟩, continuous_const⟩ have H : h = g := by rw [← cancel_epi f] ext x - apply ULift.ext dsimp [g, LocallyConstant.ofIsClopen] - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [CategoryTheory.comp_apply, ContinuousMap.coe_mk, CategoryTheory.comp_apply, + rw [ContinuousMap.coe_mk, ContinuousMap.coe_mk, ConcreteCategory.hom_ofHom, ContinuousMap.coe_mk, Function.comp_apply, if_neg] refine mt (fun α => hVU α) ?_ - simp only [U, C, Set.mem_range_self, not_true, not_false_iff, Set.mem_compl_iff] + simp [U, C] apply_fun fun e => (e y).down at H dsimp [g, LocallyConstant.ofIsClopen] at H - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [ContinuousMap.coe_mk, ContinuousMap.coe_mk, Function.comp_apply, if_pos hyV] at H + rw [ContinuousMap.coe_mk, ContinuousMap.coe_mk, Function.comp_apply, if_pos hyV] at H exact top_ne_bot H · rw [← CategoryTheory.epi_iff_surjective] apply (forget Profinite).epi_of_epi_map diff --git a/Mathlib/Topology/Category/Profinite/CofilteredLimit.lean b/Mathlib/Topology/Category/Profinite/CofilteredLimit.lean index 35974372c30e3..2aea64f2cf832 100644 --- a/Mathlib/Topology/Category/Profinite/CofilteredLimit.lean +++ b/Mathlib/Topology/Category/Profinite/CofilteredLimit.lean @@ -26,9 +26,6 @@ namespace Profinite open CategoryTheory Limits --- This was a global instance prior to https://github.com/leanprover-community/mathlib4/pull/13170. We may experiment with removing it. -attribute [local instance] HasForget.instFunLike - universe u v variable {J : Type v} [SmallCategory J] [IsCofiltered J] {F : J ⥤ Profinite.{max u v}} (C : Cone F) @@ -48,8 +45,8 @@ theorem exists_isClopen_of_cofiltered {U : Set C.pt} (hC : IsLimit C) (hU : IsCl change TopologicalSpace.IsTopologicalBasis {W : Set (F.obj i) | IsClopen W} apply isTopologicalBasis_isClopen · rintro i j f V (hV : IsClopen _) - exact ⟨hV.1.preimage ((F ⋙ toTopCat).map f).continuous, - hV.2.preimage ((F ⋙ toTopCat).map f).continuous⟩ + exact ⟨hV.1.preimage ((F ⋙ toTopCat).map f).hom.continuous, + hV.2.preimage ((F ⋙ toTopCat).map f).hom.continuous⟩ -- Porting note: `<;> continuity` fails -- Using this, since `U` is open, we can write `U` as a union of clopen sets all of which -- are preimages of clopens from the factors in the limit. @@ -64,13 +61,13 @@ theorem exists_isClopen_of_cofiltered {U : Set C.pt} (hC : IsLimit C) (hU : IsCl -- clopens constructed in the previous step. have hUo : ∀ (i : ↑S), IsOpen ((fun s ↦ (forget Profinite).map (C.π.app (j s)) ⁻¹' V s) i) := by intro s - exact (hV s).1.2.preimage (C.π.app (j s)).continuous + exact (hV s).1.2.preimage (C.π.app (j s)).hom.continuous have hsU : U ⊆ ⋃ (i : ↑S), (fun s ↦ (forget Profinite).map (C.π.app (j s)) ⁻¹' V s) i := by dsimp only rw [h] rintro x ⟨T, hT, hx⟩ refine ⟨_, ⟨⟨T, hT⟩, rfl⟩, ?_⟩ - dsimp only [forget_map_eq_coe] + dsimp only [ConcreteCategory.forget_map_eq_coe] rwa [← (hV ⟨T, hT⟩).2] have := hU.1.isCompact.elim_finite_subcover (fun s : S => C.π.app (j s) ⁻¹' V s) hUo hsU -- Porting note: same remark as after `hB` @@ -90,24 +87,25 @@ theorem exists_isClopen_of_cofiltered {U : Set C.pt} (hC : IsLimit C) (hU : IsCl intro s hs dsimp [W] rw [dif_pos hs] - exact ⟨(hV s).1.1.preimage (F.map _).continuous, (hV s).1.2.preimage (F.map _).continuous⟩ + exact ⟨(hV s).1.1.preimage (F.map _).hom.continuous, + (hV s).1.2.preimage (F.map _).hom.continuous⟩ · ext x constructor · intro hx simp_rw [W, Set.preimage_iUnion, Set.mem_iUnion] obtain ⟨_, ⟨s, rfl⟩, _, ⟨hs, rfl⟩, hh⟩ := hG hx refine ⟨s, hs, ?_⟩ - rwa [dif_pos hs, ← Set.preimage_comp, ← CompHausLike.coe_comp, ← Functor.map_comp, C.w] + rwa [dif_pos hs, ← Set.preimage_comp, ← CompHausLike.coe_comp, C.w] · intro hx simp_rw [W, Set.preimage_iUnion, Set.mem_iUnion] at hx obtain ⟨s, hs, hx⟩ := hx rw [h] refine ⟨s.1, s.2, ?_⟩ rw [(hV s).2] - rwa [dif_pos hs, ← Set.preimage_comp, ← CompHausLike.coe_comp, ← Functor.map_comp, C.w] at hx + rwa [dif_pos hs, ← Set.preimage_comp, ← CompHausLike.coe_comp, C.w] at hx theorem exists_locallyConstant_fin_two (hC : IsLimit C) (f : LocallyConstant C.pt (Fin 2)) : - ∃ (j : J) (g : LocallyConstant (F.obj j) (Fin 2)), f = g.comap (C.π.app _) := by + ∃ (j : J) (g : LocallyConstant (F.obj j) (Fin 2)), f = g.comap (C.π.app _).hom := by let U := f ⁻¹' {0} have hU : IsClopen U := f.isLocallyConstant.isClopen_fiber _ obtain ⟨j, V, hV, h⟩ := exists_isClopen_of_cofiltered C hC hU @@ -122,7 +120,7 @@ theorem exists_locallyConstant_fin_two (hC : IsLimit C) (f : LocallyConstant C.p open Classical in theorem exists_locallyConstant_finite_aux {α : Type*} [Finite α] (hC : IsLimit C) (f : LocallyConstant C.pt α) : ∃ (j : J) (g : LocallyConstant (F.obj j) (α → Fin 2)), - (f.map fun a b => if a = b then (0 : Fin 2) else 1) = g.comap (C.π.app _) := by + (f.map fun a b => if a = b then (0 : Fin 2) else 1) = g.comap (C.π.app _).hom := by cases nonempty_fintype α let ι : α → α → Fin 2 := fun x y => if x = y then 0 else 1 let ff := (f.map ι).flip @@ -134,14 +132,14 @@ theorem exists_locallyConstant_finite_aux {α : Type*} [Finite α] (hC : IsLimit intro a simp only [Finset.mem_image, Finset.mem_univ, true_and, exists_apply_eq_apply] let fs : ∀ a : α, j0 ⟶ j a := fun a => (hj0 (hj a)).some - let gg : α → LocallyConstant (F.obj j0) (Fin 2) := fun a => (g a).comap (F.map (fs _)) + let gg : α → LocallyConstant (F.obj j0) (Fin 2) := fun a => (g a).comap (F.map (fs _)).hom let ggg := LocallyConstant.unflip gg refine ⟨j0, ggg, ?_⟩ have : f.map ι = LocallyConstant.unflip (f.map ι).flip := by simp rw [this]; clear this have : - LocallyConstant.comap (C.π.app j0) ggg = - LocallyConstant.unflip (LocallyConstant.comap (C.π.app j0) ggg).flip := by + LocallyConstant.comap (C.π.app j0).hom ggg = + LocallyConstant.unflip (LocallyConstant.comap (C.π.app j0).hom ggg).flip := by simp rw [this]; clear this congr 1 @@ -155,7 +153,7 @@ theorem exists_locallyConstant_finite_aux {α : Type*} [Finite α] (hC : IsLimit theorem exists_locallyConstant_finite_nonempty {α : Type*} [Finite α] [Nonempty α] (hC : IsLimit C) (f : LocallyConstant C.pt α) : - ∃ (j : J) (g : LocallyConstant (F.obj j) α), f = g.comap (C.π.app _) := by + ∃ (j : J) (g : LocallyConstant (F.obj j) α), f = g.comap (C.π.app _).hom := by inhabit α obtain ⟨j, gg, h⟩ := exists_locallyConstant_finite_aux _ hC f classical @@ -187,7 +185,7 @@ theorem exists_locallyConstant_finite_nonempty {α : Type*} [Finite α] [Nonempt /-- Any locally constant function from a cofiltered limit of profinite sets factors through one of the components. -/ theorem exists_locallyConstant {α : Type*} (hC : IsLimit C) (f : LocallyConstant C.pt α) : - ∃ (j : J) (g : LocallyConstant (F.obj j) α), f = g.comap (C.π.app _) := by + ∃ (j : J) (g : LocallyConstant (F.obj j) α), f = g.comap (C.π.app _).hom := by let S := f.discreteQuotient let ff : S → α := f.lift cases isEmpty_or_nonempty S diff --git a/Mathlib/Topology/Category/Profinite/EffectiveEpi.lean b/Mathlib/Topology/Category/Profinite/EffectiveEpi.lean index ecdeb71c73112..c96bf1481284c 100644 --- a/Mathlib/Topology/Category/Profinite/EffectiveEpi.lean +++ b/Mathlib/Topology/Category/Profinite/EffectiveEpi.lean @@ -25,8 +25,6 @@ universe u open CategoryTheory Limits -attribute [local instance] HasForget.instFunLike - namespace Profinite open List in diff --git a/Mathlib/Topology/Category/Profinite/Extend.lean b/Mathlib/Topology/Category/Profinite/Extend.lean index cfb6aa9416fa0..1f88e04d2474f 100644 --- a/Mathlib/Topology/Category/Profinite/Extend.lean +++ b/Mathlib/Topology/Category/Profinite/Extend.lean @@ -27,8 +27,6 @@ universe u w open CategoryTheory Limits FintypeCat Functor -attribute [local instance] HasForget.instFunLike - namespace Profinite variable {I : Type u} [SmallCategory I] [IsCofiltered I] @@ -43,7 +41,7 @@ lemma exists_hom (hc : IsLimit c) {X : FintypeCat} (f : c.pt ⟶ toProfinite.obj let _ : TopologicalSpace X := ⊥ have : DiscreteTopology (toProfinite.obj X) := ⟨rfl⟩ let f' : LocallyConstant c.pt (toProfinite.obj X) := - ⟨f, (IsLocallyConstant.iff_continuous _).mpr f.continuous⟩ + ⟨f, (IsLocallyConstant.iff_continuous _).mpr f.hom.continuous⟩ obtain ⟨i, g, h⟩ := exists_locallyConstant.{_, u} c hc f' refine ⟨i, (g : _ → _), ?_⟩ ext x diff --git a/Mathlib/Topology/Category/Profinite/Nobeling.lean b/Mathlib/Topology/Category/Profinite/Nobeling.lean index fc08069c2269f..361f9b2704c8f 100644 --- a/Mathlib/Topology/Category/Profinite/Nobeling.lean +++ b/Mathlib/Topology/Category/Profinite/Nobeling.lean @@ -209,9 +209,10 @@ def spanFunctor [∀ (s : Finset I) (i : I), Decidable (i ∈ s)] (hC : IsCompac (Finset I)ᵒᵖ ⥤ Profinite.{u} where obj s := @Profinite.of (π C (· ∈ (unop s))) _ (by rw [← isCompact_iff_compactSpace]; exact hC.image (continuous_proj _)) _ _ - map h := ⟨(ProjRestricts C (leOfHom h.unop)), continuous_projRestricts _ _⟩ + map h := @CompHausLike.ofHom _ _ _ (_) (_) (_) (_) (_) (_) (_) (_) + ⟨(ProjRestricts C (leOfHom h.unop)), continuous_projRestricts _ _⟩ map_id J := by simp only [projRestricts_eq_id C (· ∈ (unop J))]; rfl - map_comp _ _ := by dsimp; congr; dsimp; rw [projRestricts_eq_comp] + map_comp _ _ := by dsimp; rw [← CompHausLike.ofHom_comp]; congr; dsimp; rw [projRestricts_eq_comp] /-- The limit cone on `spanFunctor` with point `C`. -/ noncomputable @@ -219,7 +220,7 @@ def spanCone [∀ (s : Finset I) (i : I), Decidable (i ∈ s)] (hC : IsCompact C Cone (spanFunctor hC) where pt := @Profinite.of C _ (by rwa [← isCompact_iff_compactSpace]) _ _ π := - { app := fun s ↦ ⟨ProjRestrict C (· ∈ unop s), continuous_projRestrict _ _⟩ + { app := fun s ↦ TopCat.ofHom ⟨ProjRestrict C (· ∈ unop s), continuous_projRestrict _ _⟩ naturality := by intro X Y h simp only [Functor.const_obj_obj, Homeomorph.setCongr, Homeomorph.homeomorph_mk_coe, diff --git a/Mathlib/Topology/Category/Profinite/Product.lean b/Mathlib/Topology/Category/Profinite/Product.lean index 0224264e33b98..f46ed3c188431 100644 --- a/Mathlib/Topology/Category/Profinite/Product.lean +++ b/Mathlib/Topology/Category/Profinite/Product.lean @@ -86,13 +86,13 @@ noncomputable def indexFunctor (hC : IsCompact C) : (Finset ι)ᵒᵖ ⥤ Profinite.{u} where obj J := @Profinite.of (obj C (· ∈ (unop J))) _ (by rw [← isCompact_iff_compactSpace]; exact hC.image (Pi.continuous_precomp' _)) _ _ - map h := map C (leOfHom h.unop) + map h := TopCat.ofHom (map C (leOfHom h.unop)) /-- The limit cone on `indexFunctor` -/ noncomputable def indexCone (hC : IsCompact C) : Cone (indexFunctor hC) where pt := @Profinite.of C _ (by rwa [← isCompact_iff_compactSpace]) _ _ - π := { app := fun J ↦ π_app C (· ∈ unop J) } + π := { app := fun J ↦ TopCat.ofHom (π_app C (· ∈ unop J)) } variable (hC : IsCompact C) diff --git a/Mathlib/Topology/Category/Profinite/Projective.lean b/Mathlib/Topology/Category/Profinite/Projective.lean index 4a53a7e275187..c15935e8aa672 100644 --- a/Mathlib/Topology/Category/Profinite/Projective.lean +++ b/Mathlib/Topology/Category/Profinite/Projective.lean @@ -30,12 +30,8 @@ universe u v w open CategoryTheory Function --- This was a global instance prior to https://github.com/leanprover-community/mathlib4/pull/13170. We may experiment with removing it. -attribute [local instance] HasForget.instFunLike - namespace Profinite - instance projective_ultrafilter (X : Type u) : Projective (of <| Ultrafilter X) where factors {Y Z} f g hg := by rw [epi_iff_surjective] at hg @@ -43,21 +39,18 @@ instance projective_ultrafilter (X : Type u) : Projective (of <| Ultrafilter X) let t : X → Y := g' ∘ f ∘ (pure : X → Ultrafilter X) let h : Ultrafilter X → Y := Ultrafilter.extend t have hh : Continuous h := continuous_ultrafilter_extend _ - use ⟨h, hh⟩ - apply (forget Profinite).map_injective + use CompHausLike.ofHom _ ⟨h, hh⟩ + apply ConcreteCategory.coe_ext simp only [h, ContinuousMap.coe_mk, coe_comp] - convert denseRange_pure.equalizer (g.continuous.comp hh) f.continuous _ - -- Porting note: same fix as in `Topology.Category.CompHaus.Projective` - let g'' : ContinuousMap Y Z := g - have : g'' ∘ g' = id := hg'.comp_eq_id - -- This used to be `rw`, but we need `rw; rfl` after https://github.com/leanprover/lean4/pull/2644 + convert denseRange_pure.equalizer (g.hom.continuous.comp hh) f.hom.continuous _ + have : g.hom ∘ g' = id := hg'.comp_eq_id rw [comp_assoc, ultrafilter_extend_extends, ← comp_assoc, this, id_comp] rfl /-- For any profinite `X`, the natural map `Ultrafilter X → X` is a projective presentation. -/ def projectivePresentation (X : Profinite.{u}) : ProjectivePresentation X where p := of <| Ultrafilter X - f := ⟨_, continuous_ultrafilter_extend id⟩ + f := CompHausLike.ofHom _ ⟨_, continuous_ultrafilter_extend id⟩ projective := Profinite.projective_ultrafilter X epi := ConcreteCategory.epi_of_surjective _ fun x => ⟨(pure x : Ultrafilter X), congr_fun (ultrafilter_extend_extends (𝟙 X)) x⟩ diff --git a/Mathlib/Topology/Category/Sequential.lean b/Mathlib/Topology/Category/Sequential.lean index 0d0d338a0a45d..c9cacc180776b 100644 --- a/Mathlib/Topology/Category/Sequential.lean +++ b/Mathlib/Topology/Category/Sequential.lean @@ -18,21 +18,19 @@ for defining categories of topological spaces, by giving it the induced category open CategoryTheory -attribute [local instance] HasForget.instFunLike - universe u /-- The type sequential topological spaces. -/ structure Sequential where /-- The underlying topological space of an object of `Sequential`. -/ - toTop : TopCat.{u} + toTop : TopCat.{u} -- TODO: turn this into `extends` /-- The underlying topological space is sequential. -/ [is_sequential : SequentialSpace toTop] namespace Sequential instance : Inhabited Sequential.{u} := - ⟨{ toTop := { α := ULift (Fin 37) } }⟩ + ⟨{ toTop := TopCat.of (ULift (Fin 37)) }⟩ instance : CoeSort Sequential Type* := ⟨fun X => X.toTop⟩ @@ -42,13 +40,13 @@ attribute [instance] is_sequential instance : Category.{u, u+1} Sequential.{u} := InducedCategory.category toTop -instance : HasForget.{u} Sequential.{u} := - InducedCategory.hasForget _ +instance : ConcreteCategory.{u} Sequential.{u} (C(·, ·)) := + InducedCategory.concreteCategory toTop variable (X : Type u) [TopologicalSpace X] [SequentialSpace X] /-- Constructor for objects of the category `Sequential`. -/ -def of : Sequential.{u} where +abbrev of : Sequential.{u} where toTop := TopCat.of X is_sequential := ‹_› @@ -70,8 +68,8 @@ instance : sequentialToTop.{u}.Faithful := /-- Construct an isomorphism from a homeomorphism. -/ @[simps hom inv] def isoOfHomeo {X Y : Sequential.{u}} (f : X ≃ₜ Y) : X ≅ Y where - hom := ⟨f, f.continuous⟩ - inv := ⟨f.symm, f.symm.continuous⟩ + hom := TopCat.ofHom ⟨f, f.continuous⟩ + inv := TopCat.ofHom ⟨f.symm, f.symm.continuous⟩ hom_inv_id := by ext x exact f.symm_apply_apply x @@ -84,10 +82,10 @@ def isoOfHomeo {X Y : Sequential.{u}} (f : X ≃ₜ Y) : X ≅ Y where def homeoOfIso {X Y : Sequential.{u}} (f : X ≅ Y) : X ≃ₜ Y where toFun := f.hom invFun := f.inv - left_inv x := by simp - right_inv x := by simp - continuous_toFun := f.hom.continuous - continuous_invFun := f.inv.continuous + left_inv := f.hom_inv_id_apply + right_inv := f.inv_hom_id_apply + continuous_toFun := f.hom.hom.continuous + continuous_invFun := f.inv.hom.continuous /-- The equivalence between isomorphisms in `Sequential` and homeomorphisms of topological spaces. -/ diff --git a/Mathlib/Topology/Category/Stonean/Basic.lean b/Mathlib/Topology/Category/Stonean/Basic.lean index 421a0327cf878..bf7f0aa66a44b 100644 --- a/Mathlib/Topology/Category/Stonean/Basic.lean +++ b/Mathlib/Topology/Category/Stonean/Basic.lean @@ -42,9 +42,6 @@ universe u open CategoryTheory open scoped Topology --- This was a global instance prior to https://github.com/leanprover-community/mathlib4/pull/13170. We may experiment with removing it. -attribute [local instance] HasForget.instFunLike - /-- `Stonean` is the category of extremally disconnected compact Hausdorff spaces. -/ abbrev Stonean := CompHausLike (fun X ↦ ExtremallyDisconnected X) @@ -56,13 +53,13 @@ instance (X : CompHaus.{u}) [Projective X] : ExtremallyDisconnected X := by intro A B _ _ _ _ _ _ f g hf hg hsurj let A' : CompHaus := CompHaus.of A let B' : CompHaus := CompHaus.of B - let f' : X ⟶ B' := ⟨f, hf⟩ - let g' : A' ⟶ B' := ⟨g,hg⟩ + let f' : X ⟶ B' := CompHausLike.ofHom _ ⟨f, hf⟩ + let g' : A' ⟶ B' := CompHausLike.ofHom _ ⟨g,hg⟩ have : Epi g' := by rw [CompHaus.epi_iff_surjective] assumption obtain ⟨h, hh⟩ := Projective.factors f' g' - refine ⟨h, h.2, ?_⟩ + refine ⟨h, h.hom.2, ?_⟩ ext t apply_fun (fun e => e t) at hh exact hh @@ -125,20 +122,20 @@ A morphism in `Stonean` is an epi iff it is surjective. -/ lemma epi_iff_surjective {X Y : Stonean} (f : X ⟶ Y) : Epi f ↔ Function.Surjective f := by - refine ⟨?_, ConcreteCategory.epi_of_surjective _⟩ + refine ⟨?_, fun h => ConcreteCategory.epi_of_surjective f h⟩ dsimp [Function.Surjective] intro h y by_contra! hy let C := Set.range f - have hC : IsClosed C := (isCompact_range f.continuous).isClosed + have hC : IsClosed C := (isCompact_range f.hom.continuous).isClosed let U := Cᶜ have hUy : U ∈ 𝓝 y := by simp only [U, C, Set.mem_range, hy, exists_false, not_false_eq_true, hC.compl_mem_nhds] obtain ⟨V, hV, hyV, hVU⟩ := isTopologicalBasis_isClopen.mem_nhds_iff.mp hUy classical - let g : Y ⟶ mkFinite (ULift (Fin 2)) := + let g : Y ⟶ mkFinite (ULift (Fin 2)) := TopCat.ofHom ⟨(LocallyConstant.ofIsClopen hV).map ULift.up, LocallyConstant.continuous _⟩ - let h : Y ⟶ mkFinite (ULift (Fin 2)) := ⟨fun _ => ⟨1⟩, continuous_const⟩ + let h : Y ⟶ mkFinite (ULift (Fin 2)) := TopCat.ofHom ⟨fun _ => ⟨1⟩, continuous_const⟩ have H : h = g := by rw [← cancel_epi f] ext x @@ -159,8 +156,9 @@ instance instProjectiveCompHausCompHaus (X : Stonean) : Projective (toCompHaus.o intro B C φ f _ haveI : ExtremallyDisconnected (toCompHaus.obj X).toTop := X.prop have hf : Function.Surjective f := by rwa [← CompHaus.epi_iff_surjective] - obtain ⟨f', h⟩ := CompactT2.ExtremallyDisconnected.projective φ.continuous f.continuous hf - use ⟨f', h.left⟩ + obtain ⟨f', h⟩ := CompactT2.ExtremallyDisconnected.projective φ.hom.continuous f.hom.continuous + hf + use ofHom _ ⟨f', h.left⟩ ext exact congr_fun h.right _ @@ -170,8 +168,9 @@ instance (X : Stonean) : Projective (toProfinite.obj X) where intro B C φ f _ haveI : ExtremallyDisconnected (toProfinite.obj X) := X.prop have hf : Function.Surjective f := by rwa [← Profinite.epi_iff_surjective] - obtain ⟨f', h⟩ := CompactT2.ExtremallyDisconnected.projective φ.continuous f.continuous hf - use ⟨f', h.left⟩ + obtain ⟨f', h⟩ := CompactT2.ExtremallyDisconnected.projective φ.hom.continuous f.hom.continuous + hf + use ofHom _ ⟨f', h.left⟩ ext exact congr_fun h.right _ @@ -181,8 +180,9 @@ instance (X : Stonean) : Projective X where intro B C φ f _ haveI : ExtremallyDisconnected X.toTop := X.prop have hf : Function.Surjective f := by rwa [← Stonean.epi_iff_surjective] - obtain ⟨f', h⟩ := CompactT2.ExtremallyDisconnected.projective φ.continuous f.continuous hf - use ⟨f', h.left⟩ + obtain ⟨f', h⟩ := CompactT2.ExtremallyDisconnected.projective φ.hom.continuous f.hom.continuous + hf + use ofHom _ ⟨f', h.left⟩ ext exact congr_fun h.right _ @@ -199,10 +199,10 @@ def presentation (X : CompHaus) : Stonean where prop := by refine CompactT2.Projective.extremallyDisconnected (@fun Y Z _ _ _ _ _ _ f g hfcont hgcont hgsurj => ?_) - let g₁ : (CompHaus.of Y) ⟶ (CompHaus.of Z) := ⟨g, hgcont⟩ - let f₁ : (projectivePresentation X).p ⟶ (CompHaus.of Z) := ⟨f, hfcont⟩ + let g₁ : (CompHaus.of Y) ⟶ (CompHaus.of Z) := CompHausLike.ofHom _ ⟨g, hgcont⟩ + let f₁ : (projectivePresentation X).p ⟶ (CompHaus.of Z) := CompHausLike.ofHom _ ⟨f, hfcont⟩ have hg₁ : Epi g₁ := (epi_iff_surjective _).2 hgsurj - refine ⟨Projective.factorThru f₁ g₁, (Projective.factorThru f₁ g₁).2, funext (fun _ => ?_)⟩ + refine ⟨Projective.factorThru f₁ g₁, (Projective.factorThru f₁ g₁).hom.2, funext (fun _ => ?_)⟩ change (Projective.factorThru f₁ g₁ ≫ g₁) _ = f _ rw [Projective.factorThru_comp] rfl diff --git a/Mathlib/Topology/Category/Stonean/EffectiveEpi.lean b/Mathlib/Topology/Category/Stonean/EffectiveEpi.lean index 9d1ef396385b6..5b16f02450c68 100644 --- a/Mathlib/Topology/Category/Stonean/EffectiveEpi.lean +++ b/Mathlib/Topology/Category/Stonean/EffectiveEpi.lean @@ -24,8 +24,6 @@ universe u open CategoryTheory Limits CompHausLike -attribute [local instance] HasForget.instFunLike - namespace Stonean open List in diff --git a/Mathlib/Topology/Category/Stonean/Limits.lean b/Mathlib/Topology/Category/Stonean/Limits.lean index 6e9904e8c16da..f3b4f280e534c 100644 --- a/Mathlib/Topology/Category/Stonean/Limits.lean +++ b/Mathlib/Topology/Category/Stonean/Limits.lean @@ -17,8 +17,6 @@ universe w u open CategoryTheory Limits CompHausLike Topology -attribute [local instance] HasForget.instFunLike - namespace Stonean instance : HasExplicitFiniteCoproducts.{w, u} (fun Y ↦ ExtremallyDisconnected Y) where @@ -30,8 +28,8 @@ include hi lemma extremallyDisconnected_preimage : ExtremallyDisconnected (i ⁻¹' (Set.range f)) where open_closure U hU := by have h : IsClopen (i ⁻¹' (Set.range f)) := - ⟨IsClosed.preimage i.continuous (isCompact_range f.continuous).isClosed, - IsOpen.preimage i.continuous hi.isOpen_range⟩ + ⟨IsClosed.preimage i.hom.continuous (isCompact_range f.hom.continuous).isClosed, + IsOpen.preimage i.hom.continuous hi.isOpen_range⟩ rw [← (closure U).preimage_image_eq Subtype.coe_injective, ← h.1.isClosedEmbedding_subtypeVal.closure_image_eq U] exact isOpen_induced (ExtremallyDisconnected.open_closure _ @@ -39,7 +37,7 @@ lemma extremallyDisconnected_preimage : ExtremallyDisconnected (i ⁻¹' (Set.ra lemma extremallyDisconnected_pullback : ExtremallyDisconnected {xy : X × Y | f xy.1 = i xy.2} := have := extremallyDisconnected_preimage i hi - let e := (TopCat.pullbackHomeoPreimage i i.2 f hi.isEmbedding).symm + let e := (TopCat.pullbackHomeoPreimage i i.hom.2 f hi.isEmbedding).symm let e' : {xy : X × Y | f xy.1 = i xy.2} ≃ₜ {xy : Y × X | i xy.1 = f xy.2} := by exact TopCat.homeoOfIso ((TopCat.pullbackIsoProdSubtype f i).symm ≪≫ pullbackSymmetry _ _ ≪≫ diff --git a/Mathlib/Topology/Category/TopCat/Adjunctions.lean b/Mathlib/Topology/Category/TopCat/Adjunctions.lean index 52f1591638bd4..1ca62757df9a9 100644 --- a/Mathlib/Topology/Category/TopCat/Adjunctions.lean +++ b/Mathlib/Topology/Category/TopCat/Adjunctions.lean @@ -28,13 +28,13 @@ namespace TopCat @[simps! unit counit] def adj₁ : discrete ⊣ forget TopCat.{u} where unit := { app := fun _ => id } - counit := { app := fun _ => ⟨id, continuous_bot⟩ } + counit := { app := fun X => TopCat.ofHom (X := discrete.obj X) ⟨id, continuous_bot⟩ } /-- Equipping a type with the trivial topology is right adjoint to the forgetful functor `Top ⥤ Type`. -/ @[simps! unit counit] def adj₂ : forget TopCat.{u} ⊣ trivial where - unit := { app := fun _ => ⟨id, continuous_top⟩ } + unit := { app := fun X => TopCat.ofHom (Y := trivial.obj X) ⟨id, continuous_top⟩ } counit := { app := fun _ => id } instance : (forget TopCat.{u}).IsRightAdjoint := diff --git a/Mathlib/Topology/Category/TopCat/Basic.lean b/Mathlib/Topology/Category/TopCat/Basic.lean index 31d2fe85ecda8..42c84fbb1dd72 100644 --- a/Mathlib/Topology/Category/TopCat/Basic.lean +++ b/Mathlib/Topology/Category/TopCat/Basic.lean @@ -3,7 +3,7 @@ Copyright (c) 2017 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Patrick Massot, Kim Morrison, Mario Carneiro -/ -import Mathlib.CategoryTheory.ConcreteCategory.BundledHom +import Mathlib.CategoryTheory.ConcreteCategory.Basic import Mathlib.Topology.ContinuousMap.Basic /-! @@ -20,72 +20,123 @@ open CategoryTheory TopologicalSpace Topology universe u -/-- The category of topological spaces and continuous maps. -/ -@[to_additive existing TopCat] -def TopCat : Type (u + 1) := - Bundled TopologicalSpace +/-- The category of semirings. -/ +structure TopCat where + private mk :: + /-- The underlying type. -/ + carrier : Type u + [str : TopologicalSpace carrier] + +attribute [instance] TopCat.str + +initialize_simps_projections TopCat (-str) namespace TopCat -instance bundledHom : BundledHom @ContinuousMap where - toFun := @ContinuousMap.toFun - id := @ContinuousMap.id - comp := @ContinuousMap.comp +instance : CoeSort (TopCat) (Type u) := + ⟨TopCat.carrier⟩ + +attribute [coe] TopCat.carrier + +/-- The object in `TopCat` associated to a type equipped with the appropriate +typeclasses. This is the preferred way to construct a term of `TopCat`. -/ +abbrev of (X : Type u) [TopologicalSpace X] : TopCat := + ⟨X⟩ + +lemma coe_of (X : Type u) [TopologicalSpace X] : (of X : Type u) = X := + rfl + +lemma of_carrier (X : TopCat.{u}) : of X = X := rfl + +variable {X} in +/-- The type of morphisms in `TopCat`. -/ +@[ext] +structure Hom (X Y : TopCat.{u}) where + private mk :: + /-- The underlying `ContinuousMap`. -/ + hom' : C(X, Y) -deriving instance LargeCategory for TopCat +instance : Category TopCat where + Hom X Y := Hom X Y + id X := ⟨ContinuousMap.id X⟩ + comp f g := ⟨g.hom'.comp f.hom'⟩ --- Porting note: currently no derive handler for HasForget --- see https://github.com/leanprover-community/mathlib4/issues/5020 -instance hasForget : HasForget TopCat := - inferInstanceAs <| HasForget (Bundled TopologicalSpace) +instance : ConcreteCategory.{u} TopCat (fun X Y => C(X, Y)) where + hom := Hom.hom' + ofHom f := ⟨f⟩ -instance : CoeSort TopCat Type* where - coe X := X.α +/-- Turn a morphism in `TopCat` back into a `ContinuousMap`. -/ +abbrev Hom.hom {X Y : TopCat.{u}} (f : Hom X Y) := + ConcreteCategory.hom (C := TopCat) f -instance topologicalSpaceUnbundled (X : TopCat) : TopologicalSpace X := - X.str +/-- Typecheck a `ContinuousMap` as a morphism in `TopCat`. -/ +abbrev ofHom {X Y : Type u} [TopologicalSpace X] [TopologicalSpace Y] (f : C(X, Y)) : of X ⟶ of Y := + ConcreteCategory.ofHom (C := TopCat) f -instance instFunLike (X Y : TopCat) : FunLike (X ⟶ Y) X Y := - inferInstanceAs <| FunLike C(X, Y) X Y +/-- Use the `ConcreteCategory.hom` projection for `@[simps]` lemmas. -/ +def Hom.Simps.hom (X Y : TopCat) (f : Hom X Y) := + f.hom -instance instContinuousMapClass (X Y : TopCat) : ContinuousMapClass (X ⟶ Y) X Y := - inferInstanceAs <| ContinuousMapClass C(X, Y) X Y +initialize_simps_projections Hom (hom' → hom) + +/-! +The results below duplicate the `ConcreteCategory` simp lemmas, but we can keep them for `dsimp`. +-/ + +@[simp] +lemma hom_id {X : TopCat.{u}} : (𝟙 X : X ⟶ X).hom = ContinuousMap.id X := rfl @[simp] theorem id_app (X : TopCat.{u}) (x : ↑X) : (𝟙 X : X ⟶ X) x = x := rfl +@[simp] theorem coe_id (X : TopCat.{u}) : (𝟙 X : X → X) = id := rfl + +@[simp] +lemma hom_comp {X Y Z : TopCat.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) : + (f ≫ g).hom = g.hom.comp f.hom := rfl + @[simp] theorem comp_app {X Y Z : TopCat.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) (x : X) : (f ≫ g : X → Z) x = g (f x) := rfl -@[simp] theorem coe_id (X : TopCat.{u}) : (𝟙 X : X → X) = id := rfl - @[simp] theorem coe_comp {X Y Z : TopCat.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) : (f ≫ g : X → Z) = g ∘ f := rfl +@[ext] +lemma hom_ext {X Y : TopCat} {f g : X ⟶ Y} (hf : f.hom = g.hom) : f = g := + Hom.ext hf + +@[ext] +lemma ext {X Y : TopCat} {f g : X ⟶ Y} (w : ∀ x : X, f x = g x) : f = g := + ConcreteCategory.hom_ext _ _ w + @[simp] -lemma hom_inv_id_apply {X Y : TopCat} (f : X ≅ Y) (x : X) : f.inv (f.hom x) = x := - DFunLike.congr_fun f.hom_inv_id x +lemma hom_ofHom {X Y : Type u} [TopologicalSpace X] [TopologicalSpace Y] (f : C(X, Y)) : + (ofHom f).hom = f := rfl @[simp] -lemma inv_hom_id_apply {X Y : TopCat} (f : X ≅ Y) (y : Y) : f.hom (f.inv y) = y := - DFunLike.congr_fun f.inv_hom_id y +lemma ofHom_hom {X Y : TopCat} (f : X ⟶ Y) : + ofHom (Hom.hom f) = f := rfl -/-- Construct a bundled `Top` from the underlying type and the typeclass. -/ -def of (X : Type u) [TopologicalSpace X] : TopCat := - -- Porting note: needed to call inferInstance - ⟨X, inferInstance⟩ +@[simp] +lemma ofHom_id {X : Type u} [TopologicalSpace X] : ofHom (ContinuousMap.id X) = 𝟙 (of X) := rfl -instance topologicalSpace_coe (X : TopCat) : TopologicalSpace X := - X.str +@[simp] +lemma ofHom_comp {X Y Z : Type u} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] + (f : C(X, Y)) (g : C(Y, Z)) : + ofHom (g.comp f) = ofHom f ≫ ofHom g := + rfl --- Porting note: cannot see through forget; made reducible to get closer to Lean 3 behavior -@[instance] abbrev topologicalSpace_forget - (X : TopCat) : TopologicalSpace <| (forget TopCat).obj X := - X.str +lemma ofHom_apply {X Y : Type u} [TopologicalSpace X] [TopologicalSpace Y] (f : C(X, Y)) (x : X) : + (ofHom f) x = f x := rfl @[simp] -theorem coe_of (X : Type u) [TopologicalSpace X] : (of X : Type u) = X := rfl +lemma hom_inv_id_apply {X Y : TopCat} (f : X ≅ Y) (x : X) : f.inv (f.hom x) = x := + CategoryTheory.congr_fun f.hom_inv_id x + +@[simp] +lemma inv_hom_id_apply {X Y : TopCat} (f : X ≅ Y) (y : Y) : f.hom (f.inv y) = y := + CategoryTheory.congr_fun f.inv_hom_id y /-- Replace a function coercion for a morphism `TopCat.of X ⟶ TopCat.of Y` with the definitionally @@ -95,7 +146,7 @@ equal function coercion for a continuous map `C(X, Y)`. {f : C(X, Y)} {x} : @DFunLike.coe (TopCat.of X ⟶ TopCat.of Y) ((CategoryTheory.forget TopCat).obj (TopCat.of X)) (fun _ ↦ (CategoryTheory.forget TopCat).obj (TopCat.of Y)) HasForget.instFunLike - f x = + (ofHom f) x = @DFunLike.coe C(X, Y) X (fun _ ↦ Y) _ f x := @@ -104,30 +155,29 @@ equal function coercion for a continuous map `C(X, Y)`. instance inhabited : Inhabited TopCat := ⟨TopCat.of Empty⟩ --- Porting note: added to ease the port of `AlgebraicTopology.TopologicalSimplex` -lemma hom_apply {X Y : TopCat} (f : X ⟶ Y) (x : X) : f x = ContinuousMap.toFun f x := rfl +@[deprecated + "Simply remove this from the `simp`/`rw` set: the LHS and RHS are now identical." + (since := "2025-01-30")] +lemma hom_apply {X Y : TopCat} (f : X ⟶ Y) (x : X) : f x = ContinuousMap.toFun f.hom x := rfl /-- The discrete topology on any type. -/ def discrete : Type u ⥤ TopCat.{u} where - obj X := ⟨X , ⊥⟩ - map f := @ContinuousMap.mk _ _ ⊥ ⊥ f continuous_bot + obj X := @of X ⊥ + map f := @ofHom _ _ ⊥ ⊥ <| @ContinuousMap.mk _ _ ⊥ ⊥ f continuous_bot instance {X : Type u} : DiscreteTopology (discrete.obj X) := ⟨rfl⟩ /-- The trivial topology on any type. -/ def trivial : Type u ⥤ TopCat.{u} where - obj X := ⟨X, ⊤⟩ - map f := @ContinuousMap.mk _ _ ⊤ ⊤ f continuous_top + obj X := @of X ⊤ + map f := @ofHom _ _ ⊤ ⊤ <| @ContinuousMap.mk _ _ ⊤ ⊤ f continuous_top /-- Any homeomorphisms induces an isomorphism in `Top`. -/ @[simps] def isoOfHomeo {X Y : TopCat.{u}} (f : X ≃ₜ Y) : X ≅ Y where - -- Porting note: previously ⟨f⟩ for hom (inv) and tidy closed proofs - hom := (f : C(X, Y)) - inv := (f.symm : C(Y, X)) - hom_inv_id := by ext; exact f.symm_apply_apply _ - inv_hom_id := by ext; exact f.apply_symm_apply _ + hom := ofHom f + inv := ofHom f.symm /-- Any isomorphism in `Top` induces a homeomorphism. -/ @[simps] @@ -136,33 +186,29 @@ def homeoOfIso {X Y : TopCat.{u}} (f : X ≅ Y) : X ≃ₜ Y where invFun := f.inv left_inv x := by simp right_inv x := by simp - continuous_toFun := f.hom.continuous - continuous_invFun := f.inv.continuous + continuous_toFun := f.hom.hom.continuous + continuous_invFun := f.inv.hom.continuous @[simp] theorem of_isoOfHomeo {X Y : TopCat.{u}} (f : X ≃ₜ Y) : homeoOfIso (isoOfHomeo f) = f := by - -- Porting note: unfold some defs now - dsimp [homeoOfIso, isoOfHomeo] ext rfl @[simp] theorem of_homeoOfIso {X Y : TopCat.{u}} (f : X ≅ Y) : isoOfHomeo (homeoOfIso f) = f := by - -- Porting note: unfold some defs now - dsimp [homeoOfIso, isoOfHomeo] ext rfl lemma isIso_of_bijective_of_isOpenMap {X Y : TopCat.{u}} (f : X ⟶ Y) (hfbij : Function.Bijective f) (hfcl : IsOpenMap f) : IsIso f := let e : X ≃ₜ Y := Homeomorph.homeomorphOfContinuousOpen - (Equiv.ofBijective f hfbij) f.continuous hfcl + (Equiv.ofBijective f hfbij) f.hom.continuous hfcl inferInstanceAs <| IsIso (TopCat.isoOfHomeo e).hom lemma isIso_of_bijective_of_isClosedMap {X Y : TopCat.{u}} (f : X ⟶ Y) (hfbij : Function.Bijective f) (hfcl : IsClosedMap f) : IsIso f := let e : X ≃ₜ Y := Homeomorph.homeomorphOfContinuousClosed - (Equiv.ofBijective f hfbij) f.continuous hfcl + (Equiv.ofBijective f hfbij) f.hom.continuous hfcl inferInstanceAs <| IsIso (TopCat.isoOfHomeo e).hom theorem isOpenEmbedding_iff_comp_isIso {X Y Z : TopCat} (f : X ⟶ Y) (g : Y ⟶ Z) [IsIso g] : @@ -174,7 +220,7 @@ alias openEmbedding_iff_comp_isIso := isOpenEmbedding_iff_comp_isIso @[simp] theorem isOpenEmbedding_iff_comp_isIso' {X Y Z : TopCat} (f : X ⟶ Y) (g : Y ⟶ Z) [IsIso g] : - IsOpenEmbedding ((forget TopCat).map f ≫ (forget TopCat).map g) ↔ IsOpenEmbedding f := by + IsOpenEmbedding (g ∘ f) ↔ IsOpenEmbedding f := by simp only [← Functor.map_comp] exact isOpenEmbedding_iff_comp_isIso f g @@ -186,7 +232,7 @@ theorem isOpenEmbedding_iff_isIso_comp {X Y Z : TopCat} (f : X ⟶ Y) (g : Y ⟶ constructor · intro h convert h.comp (TopCat.homeoOfIso (asIso f).symm).isOpenEmbedding - exact congrArg _ (IsIso.inv_hom_id_assoc f g).symm + exact congr_arg (DFunLike.coe ∘ ConcreteCategory.hom) (IsIso.inv_hom_id_assoc f g).symm · exact fun h => h.comp (TopCat.homeoOfIso (asIso f)).isOpenEmbedding @[deprecated (since := "2024-10-18")] @@ -194,7 +240,7 @@ alias openEmbedding_iff_isIso_comp := isOpenEmbedding_iff_isIso_comp @[simp] theorem isOpenEmbedding_iff_isIso_comp' {X Y Z : TopCat} (f : X ⟶ Y) (g : Y ⟶ Z) [IsIso f] : - IsOpenEmbedding ((forget TopCat).map f ≫ (forget TopCat).map g) ↔ IsOpenEmbedding g := by + IsOpenEmbedding (g ∘ f) ↔ IsOpenEmbedding g := by simp only [← Functor.map_comp] exact isOpenEmbedding_iff_isIso_comp f g diff --git a/Mathlib/Topology/Category/TopCat/EffectiveEpi.lean b/Mathlib/Topology/Category/TopCat/EffectiveEpi.lean index a42db3835f71f..057fcab0da98c 100644 --- a/Mathlib/Topology/Category/TopCat/EffectiveEpi.lean +++ b/Mathlib/Topology/Category/TopCat/EffectiveEpi.lean @@ -29,21 +29,28 @@ noncomputable def effectiveEpiStructOfQuotientMap {B X : TopCat.{u}} (π : X ⟶ B) (hπ : IsQuotientMap π) : EffectiveEpiStruct π where /- `IsQuotientMap.lift` gives the required morphism -/ - desc e h := hπ.lift e fun a b hab ↦ - DFunLike.congr_fun (h ⟨fun _ ↦ a, continuous_const⟩ ⟨fun _ ↦ b, continuous_const⟩ + desc e h := ofHom <| hπ.lift e.hom fun a b hab ↦ + CategoryTheory.congr_fun (h + (ofHom ⟨fun _ ↦ a, continuous_const⟩) + (ofHom ⟨fun _ ↦ b, continuous_const⟩) (by ext; exact hab)) a /- `IsQuotientMap.lift_comp` gives the factorisation -/ - fac e h := (hπ.lift_comp e - fun a b hab ↦ DFunLike.congr_fun (h ⟨fun _ ↦ a, continuous_const⟩ ⟨fun _ ↦ b, continuous_const⟩ + fac e h := hom_ext (hπ.lift_comp e.hom + fun a b hab ↦ CategoryTheory.congr_fun (h + (ofHom ⟨fun _ ↦ a, continuous_const⟩) + (ofHom ⟨fun _ ↦ b, continuous_const⟩) (by ext; exact hab)) a) /- Uniqueness follows from the fact that `IsQuotientMap.lift` is an equivalence (given by `IsQuotientMap.liftEquiv`). -/ uniq e h g hm := by - suffices g = hπ.liftEquiv ⟨e, - fun a b hab ↦ DFunLike.congr_fun - (h ⟨fun _ ↦ a, continuous_const⟩ ⟨fun _ ↦ b, continuous_const⟩ (by ext; exact hab)) - a⟩ by assumption - rw [← Equiv.symm_apply_eq hπ.liftEquiv] + suffices g = ofHom (hπ.liftEquiv ⟨e.hom, + fun a b hab ↦ CategoryTheory.congr_fun (h + (ofHom ⟨fun _ ↦ a, continuous_const⟩) + (ofHom ⟨fun _ ↦ b, continuous_const⟩) + (by ext; exact hab)) + a⟩) by assumption + apply hom_ext + rw [hom_ofHom, ← Equiv.symm_apply_eq hπ.liftEquiv] ext simp only [IsQuotientMap.liftEquiv_symm_apply_coe, ContinuousMap.comp_apply, ← hm] rfl diff --git a/Mathlib/Topology/Category/TopCat/Limits/Basic.lean b/Mathlib/Topology/Category/TopCat/Limits/Basic.lean index 99c6519501cba..445b8f3488846 100644 --- a/Mathlib/Topology/Category/TopCat/Limits/Basic.lean +++ b/Mathlib/Topology/Category/TopCat/Limits/Basic.lean @@ -34,16 +34,12 @@ Generally you should just use `limit.cone F`, unless you need the actual definit def limitCone (F : J ⥤ TopCat.{max v u}) : Cone F where pt := TopCat.of { u : ∀ j : J, F.obj j | ∀ {i j : J} (f : i ⟶ j), F.map f (u i) = u j } π := - { app := fun j => + { app := fun j => ofHom { toFun := fun u => u.val j -- Porting note: `continuity` from the original mathlib3 proof failed here. continuous_toFun := Continuous.comp (continuous_apply _) (continuous_subtype_val) } naturality := fun X Y f => by - -- Automation fails in various ways in this proof. Why?! - dsimp - rw [Category.id_comp] - apply ContinuousMap.ext - intro a + ext a exact (a.2 f).symm } /-- A choice of limit cone for a functor `F : J ⥤ TopCat` whose topology is defined as an @@ -52,35 +48,35 @@ Generally you should just use `limit.cone F`, unless you need the actual definit (which is in terms of `Types.limitCone`). -/ def limitConeInfi (F : J ⥤ TopCat.{max v u}) : Cone F where - pt := - ⟨(Types.limitCone.{v,u} (F ⋙ forget)).pt, - ⨅ j, (F.obj j).str.induced ((Types.limitCone.{v,u} (F ⋙ forget)).π.app j)⟩ + pt := @of + ((Types.limitCone.{v,u} (F ⋙ forget)).pt) + (⨅ j, (F.obj j).str.induced ((Types.limitCone.{v,u} (F ⋙ forget)).π.app j)) π := - { app := fun j => - ⟨(Types.limitCone.{v,u} (F ⋙ forget)).π.app j, continuous_iff_le_induced.mpr (iInf_le _ _)⟩ + { app := fun j => @ofHom _ _ (_) (_) <| @ContinuousMap.mk _ _ (_) (_) + ((Types.limitCone.{v,u} (F ⋙ forget)).π.app j) + (continuous_iff_le_induced.mpr (iInf_le _ _)) naturality := fun _ _ f => - ContinuousMap.coe_injective ((Types.limitCone.{v,u} (F ⋙ forget)).π.naturality f) } + ConcreteCategory.coe_ext ((Types.limitCone.{v,u} (F ⋙ forget)).π.naturality f) } /-- The chosen cone `TopCat.limitCone F` for a functor `F : J ⥤ TopCat` is a limit cone. Generally you should just use `limit.isLimit F`, unless you need the actual definition (which is in terms of `Types.limitConeIsLimit`). -/ def limitConeIsLimit (F : J ⥤ TopCat.{max v u}) : IsLimit (limitCone.{v,u} F) where - lift S := + lift S := ofHom { toFun := fun x => ⟨fun _ => S.π.app _ x, fun f => by dsimp rw [← S.w f] rfl⟩ continuous_toFun := - Continuous.subtype_mk (continuous_pi fun j => (S.π.app j).2) fun x i j f => by + Continuous.subtype_mk (continuous_pi fun j => (S.π.app j).hom.2) fun x i j f => by dsimp rw [← S.w f] rfl } uniq S m h := by - apply ContinuousMap.ext; intros a; apply Subtype.ext; funext j - dsimp - rw [← h] + ext a + simp [← h] rfl /-- The chosen cone `TopCat.limitConeInfi F` for a functor `F : J ⥤ TopCat` is a limit cone. @@ -90,17 +86,18 @@ Generally you should just use `limit.isLimit F`, unless you need the actual defi def limitConeInfiIsLimit (F : J ⥤ TopCat.{max v u}) : IsLimit (limitConeInfi.{v,u} F) := by refine IsLimit.ofFaithful forget (Types.limitConeIsLimit.{v,u} (F ⋙ forget)) -- Porting note: previously could infer all ?_ except continuity - (fun s => ⟨fun v => ⟨fun j => (Functor.mapCone forget s).π.app j v, ?_⟩, ?_⟩) fun s => ?_ + (fun s => @ofHom _ _ (_) (_) (@ContinuousMap.mk _ _ (_) (_) + (fun v => ⟨fun j => (Functor.mapCone forget s).π.app j v, ?_⟩) + ?_)) fun s => ?_ · dsimp [Functor.sections] intro _ _ _ - rw [← comp_apply', forget_map_eq_coe, ← s.π.naturality, forget_map_eq_coe] + rw [← ConcreteCategory.comp_apply, ← s.π.naturality] dsimp - rw [Category.id_comp] · exact continuous_iff_coinduced_le.mpr (le_iInf fun j => coinduced_le_iff_le_induced.mp <| - (continuous_iff_coinduced_le.mp (s.π.app j).continuous :)) + (continuous_iff_coinduced_le.mp (s.π.app j).hom.continuous :)) · rfl instance topCat_hasLimitsOfSize : HasLimitsOfSize.{w, v} TopCat.{max v u} where @@ -128,17 +125,18 @@ Generally you should just use `colimit.cocone F`, unless you need the actual def (which is in terms of `Types.colimitCocone`). -/ def colimitCocone (F : J ⥤ TopCat.{max v u}) : Cocone F where - pt := - ⟨(Types.TypeMax.colimitCocone.{v,u} (F ⋙ forget)).pt, - ⨆ j, (F.obj j).str.coinduced ((Types.TypeMax.colimitCocone (F ⋙ forget)).ι.app j)⟩ + pt := @of + ((Types.TypeMax.colimitCocone.{v,u} (F ⋙ forget)).pt) + (⨆ j, (F.obj j).str.coinduced ((Types.TypeMax.colimitCocone (F ⋙ forget)).ι.app j)) ι := - { app := fun j => - ⟨(Types.TypeMax.colimitCocone (F ⋙ forget)).ι.app j, continuous_iff_coinduced_le.mpr <| + { app := fun j => @ofHom _ _ (_) (_) <| @ContinuousMap.mk _ _ (_) (_) + ((Types.TypeMax.colimitCocone (F ⋙ forget)).ι.app j) + (continuous_iff_coinduced_le.mpr <| -- Porting note: didn't need function before le_iSup (fun j => - coinduced ((Types.TypeMax.colimitCocone (F ⋙ forget)).ι.app j) (F.obj j).str) j⟩ + coinduced ((Types.TypeMax.colimitCocone (F ⋙ forget)).ι.app j) (F.obj j).str) j) naturality := fun _ _ f => - ContinuousMap.coe_injective ((Types.TypeMax.colimitCocone (F ⋙ forget)).ι.naturality f) } + ConcreteCategory.coe_ext ((Types.TypeMax.colimitCocone (F ⋙ forget)).ι.naturality f) } /-- The chosen cocone `TopCat.colimitCocone F` for a functor `F : J ⥤ TopCat` is a colimit cocone. Generally you should just use `colimit.isColimit F`, unless you need the actual definition @@ -149,17 +147,16 @@ def colimitCoconeIsColimit (F : J ⥤ TopCat.{max v u}) : IsColimit (colimitCoco IsColimit.ofFaithful forget (Types.TypeMax.colimitCoconeIsColimit.{v, u} _) (fun s => -- Porting note: it appears notation for forget breaks dot notation (also above) -- Porting note: previously function was inferred - ⟨Quot.lift (fun p => (Functor.mapCocone forget s).ι.app p.fst p.snd) ?_, ?_⟩) fun s => ?_ + @ofHom _ _ (_) (_) <| @ContinuousMap.mk _ _ (_) (_) + (Quot.lift (fun p => (Functor.mapCocone forget s).ι.app p.fst p.snd) ?_) + ?_) fun s => ?_ · intro _ _ ⟨_, h⟩ - dsimp - rw [h, Functor.comp_map, ← comp_apply', s.ι.naturality] - dsimp - rw [Category.comp_id] + simp [h, ← ConcreteCategory.comp_apply, s.ι.naturality] · exact continuous_iff_le_induced.mpr (iSup_le fun j => coinduced_le_iff_le_induced.mp <| - (continuous_iff_coinduced_le.mp (s.ι.app j).continuous :)) + (continuous_iff_coinduced_le.mp (s.ι.app j).hom.continuous :)) · rfl instance topCat_hasColimitsOfSize : HasColimitsOfSize.{w,v} TopCat.{max v u} where @@ -185,7 +182,7 @@ instance forget_preservesColimits : PreservesColimits (forget : TopCat.{u} ⥤ T /-- The terminal object of `Top` is `PUnit`. -/ def isTerminalPUnit : IsTerminal (TopCat.of PUnit.{u + 1}) := haveI : ∀ X, Unique (X ⟶ TopCat.of PUnit.{u + 1}) := fun X => - ⟨⟨⟨fun _ => PUnit.unit, continuous_const⟩⟩, fun f => by ext; aesop⟩ + ⟨⟨ofHom ⟨fun _ => PUnit.unit, continuous_const⟩⟩, fun f => by ext⟩ Limits.IsTerminal.ofUnique _ /-- The terminal object of `Top` is `PUnit`. -/ @@ -195,7 +192,7 @@ def terminalIsoPUnit : ⊤_ TopCat.{u} ≅ TopCat.of PUnit := /-- The initial object of `Top` is `PEmpty`. -/ def isInitialPEmpty : IsInitial (TopCat.of PEmpty.{u + 1}) := haveI : ∀ X, Unique (TopCat.of PEmpty.{u + 1} ⟶ X) := fun X => - ⟨⟨⟨fun x => x.elim, by continuity⟩⟩, fun f => by ext ⟨⟩⟩ + ⟨⟨ofHom ⟨fun x => x.elim, by continuity⟩⟩, fun f => by ext ⟨⟩⟩ Limits.IsInitial.ofUnique _ /-- The initial object of `Top` is `PEmpty`. -/ diff --git a/Mathlib/Topology/Category/TopCat/Limits/Konig.lean b/Mathlib/Topology/Category/TopCat/Limits/Konig.lean index 0d6f7501547f2..a1d9385502d9a 100644 --- a/Mathlib/Topology/Category/TopCat/Limits/Konig.lean +++ b/Mathlib/Topology/Category/TopCat/Limits/Konig.lean @@ -29,7 +29,6 @@ discrete topology) in lemmas `nonempty_sections_of_finite_cofiltered_system` and (See for the Set version.) -/ - open CategoryTheory open CategoryTheory.Limits @@ -108,13 +107,7 @@ theorem partialSections.closed [∀ j : J, T2Space (F.obj j)] {G : Finset J} rw [this] apply isClosed_biInter intro f _ - -- Porting note: can't see through forget - have : T2Space ((forget TopCat).obj (F.obj f.snd.fst)) := - inferInstanceAs (T2Space (F.obj f.snd.fst)) - apply isClosed_eq - -- Porting note: used to be a single `continuity` that closed both goals - · exact (F.map f.snd.snd.snd.snd).continuous.comp (continuous_apply f.fst) - · continuity + apply isClosed_eq <;> fun_prop /-- Cofiltered limits of nonempty compact Hausdorff spaces are nonempty topological spaces. -/ diff --git a/Mathlib/Topology/Category/TopCat/Limits/Products.lean b/Mathlib/Topology/Category/TopCat/Limits/Products.lean index e9caaf169d458..a1177ebe29171 100644 --- a/Mathlib/Topology/Category/TopCat/Limits/Products.lean +++ b/Mathlib/Topology/Category/TopCat/Limits/Products.lean @@ -26,7 +26,7 @@ variable {J : Type v} [Category.{w} J] /-- The projection from the product as a bundled continuous map. -/ abbrev piπ {ι : Type v} (α : ι → TopCat.{max v u}) (i : ι) : TopCat.of (∀ i, α i) ⟶ α i := - ⟨fun f => f i, continuous_apply i⟩ + ofHom ⟨fun f => f i, continuous_apply i⟩ /-- The explicit fan of a family of topological spaces given by the pi type. -/ @[simps! pt π_app] @@ -35,15 +35,14 @@ def piFan {ι : Type v} (α : ι → TopCat.{max v u}) : Fan α := /-- The constructed fan is indeed a limit -/ def piFanIsLimit {ι : Type v} (α : ι → TopCat.{max v u}) : IsLimit (piFan α) where - lift S := + lift S := ofHom { toFun := fun s i => S.π.app ⟨i⟩ s - continuous_toFun := continuous_pi (fun i => (S.π.app ⟨i⟩).2) } + continuous_toFun := continuous_pi (fun i => (S.π.app ⟨i⟩).hom.2) } uniq := by intro S m h - apply ContinuousMap.ext; intro x + ext x funext i simp [ContinuousMap.coe_mk, ← h ⟨i⟩] - rfl fac _ _ := rfl /-- The product is homeomorphic to the product of the underlying spaces, @@ -68,10 +67,9 @@ theorem piIsoPi_hom_apply {ι : Type v} (α : ι → TopCat.{max v u}) (i : ι) rw [Iso.inv_comp_eq] at this exact ConcreteCategory.congr_hom this x --- Porting note: Lean doesn't automatically reduce TopCat.of X|>.α to X now /-- The inclusion to the coproduct as a bundled continuous map. -/ abbrev sigmaι {ι : Type v} (α : ι → TopCat.{max v u}) (i : ι) : α i ⟶ TopCat.of (Σi, α i) := by - refine ContinuousMap.mk ?_ ?_ + refine ofHom (ContinuousMap.mk ?_ ?_) · dsimp apply Sigma.mk i · dsimp; continuity @@ -83,13 +81,13 @@ def sigmaCofan {ι : Type v} (α : ι → TopCat.{max v u}) : Cofan α := /-- The constructed cofan is indeed a colimit -/ def sigmaCofanIsColimit {ι : Type v} (β : ι → TopCat.{max v u}) : IsColimit (sigmaCofan β) where - desc S := + desc S := ofHom { toFun := fun (s : of (Σ i, β i)) => S.ι.app ⟨s.1⟩ s.2 - continuous_toFun := continuous_sigma fun i => (S.ι.app ⟨i⟩).continuous_toFun } + continuous_toFun := by continuity } uniq := by intro S m h ext ⟨i, x⟩ - simp only [hom_apply, ← h] + simp only [← h] congr fac s j := by cases j @@ -114,7 +112,6 @@ theorem sigmaIsoSigma_inv_apply {ι : Type v} (α : ι → TopCat.{max v u}) (i rw [← sigmaIsoSigma_hom_ι_apply, ← comp_app, ← comp_app, Iso.hom_inv_id, Category.comp_id] --- Porting note: cannot use .topologicalSpace in place .str theorem induced_of_isLimit {F : J ⥤ TopCat.{max v u}} (C : Cone F) (hC : IsLimit C) : C.pt.str = ⨅ j, (F.obj j).str.induced (C.π.app j) := by let homeo := homeoOfIso (hC.conePointUniqueUpToIso (limitConeInfiIsLimit F)) @@ -132,11 +129,11 @@ section Prod -- Porting note: why is autoParam not firing? /-- The first projection from the product. -/ abbrev prodFst {X Y : TopCat.{u}} : TopCat.of (X × Y) ⟶ X := - ⟨Prod.fst, by continuity⟩ + ofHom ⟨Prod.fst, by continuity⟩ /-- The second projection from the product. -/ abbrev prodSnd {X Y : TopCat.{u}} : TopCat.of (X × Y) ⟶ Y := - ⟨Prod.snd, by continuity⟩ + ofHom ⟨Prod.snd, by continuity⟩ /-- The explicit binary cofan of `X, Y` given by `X × Y`. -/ def prodBinaryFan (X Y : TopCat.{u}) : BinaryFan X Y := @@ -144,18 +141,16 @@ def prodBinaryFan (X Y : TopCat.{u}) : BinaryFan X Y := /-- The constructed binary fan is indeed a limit -/ def prodBinaryFanIsLimit (X Y : TopCat.{u}) : IsLimit (prodBinaryFan X Y) where - lift := fun S : BinaryFan X Y => { + lift := fun S : BinaryFan X Y => ofHom { toFun := fun s => (S.fst s, S.snd s) - -- Porting note: continuity failed again here. Lean cannot infer - -- ContinuousMapClass (X ⟶ Y) X Y for X Y : TopCat which may be one of the problems - continuous_toFun := Continuous.prod_mk - (BinaryFan.fst S).continuous_toFun (BinaryFan.snd S).continuous_toFun } + continuous_toFun := by continuity } fac := by rintro S (_ | _) <;> {dsimp; ext; rfl} uniq := by intro S m h - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11041): used to be `ext x` - refine ContinuousMap.ext (fun (x : ↥(S.pt)) => Prod.ext ?_ ?_) + ext x + -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11041): used to be part of `ext x` + refine Prod.ext ?_ ?_ · specialize h ⟨WalkingPair.left⟩ apply_fun fun e => e x at h exact h @@ -181,12 +176,11 @@ theorem prodIsoProd_hom_snd (X Y : TopCat.{u}) : simp [← Iso.eq_inv_comp, prodIsoProd] rfl --- Porting note: need to force Lean to coerce X × Y to a type -theorem prodIsoProd_hom_apply {X Y : TopCat.{u}} (x : ↑ (X ⨯ Y)) : +-- Note that `(x : X ⨯ Y)` would mean `(x : ↑X × ↑Y)` below: +theorem prodIsoProd_hom_apply {X Y : TopCat.{u}} (x : ↑(X ⨯ Y)) : (prodIsoProd X Y).hom x = ((Limits.prod.fst : X ⨯ Y ⟶ _) x, (Limits.prod.snd : X ⨯ Y ⟶ _) x) := by - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11041): `ext` didn't pick this up. - apply Prod.ext + ext · exact ConcreteCategory.congr_hom (prodIsoProd_hom_fst X Y) x · exact ConcreteCategory.congr_hom (prodIsoProd_hom_snd X Y) x @@ -215,24 +209,21 @@ theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) : ext x constructor · rintro ⟨y, rfl⟩ - simp_rw [Set.mem_inter_iff, Set.mem_preimage, Set.mem_range] - -- sizable changes in this proof after https://github.com/leanprover-community/mathlib4/pull/13170 - rw [← CategoryTheory.comp_apply, ← CategoryTheory.comp_apply] - simp_rw [Limits.prod.map_fst, - Limits.prod.map_snd, CategoryTheory.comp_apply] - exact ⟨exists_apply_eq_apply _ _, exists_apply_eq_apply _ _⟩ + simp_rw [Set.mem_inter_iff, Set.mem_preimage, Set.mem_range, ← ConcreteCategory.comp_apply, + Limits.prod.map_fst, Limits.prod.map_snd, ConcreteCategory.comp_apply, exists_apply_eq_apply, + and_self_iff] · rintro ⟨⟨x₁, hx₁⟩, ⟨x₂, hx₂⟩⟩ use (prodIsoProd W X).inv (x₁, x₂) change (forget TopCat).map _ _ = _ apply Concrete.limit_ext rintro ⟨⟨⟩⟩ · change limit.π (pair Y Z) _ ((prod.map f g) _) = _ - erw [← CategoryTheory.comp_apply, Limits.prod.map_fst] + erw [← ConcreteCategory.comp_apply, Limits.prod.map_fst] change (_ ≫ _ ≫ f) _ = _ rw [TopCat.prodIsoProd_inv_fst_assoc,TopCat.comp_app] exact hx₁ · change limit.π (pair Y Z) _ ((prod.map f g) _) = _ - erw [← CategoryTheory.comp_apply, Limits.prod.map_snd] + erw [← ConcreteCategory.comp_apply, Limits.prod.map_snd] change (_ ≫ _ ≫ g) _ = _ rw [TopCat.prodIsoProd_inv_snd_assoc,TopCat.comp_app] exact hx₂ @@ -240,10 +231,9 @@ theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) : theorem isInducing_prodMap {W X Y Z : TopCat.{u}} {f : W ⟶ X} {g : Y ⟶ Z} (hf : IsInducing f) (hg : IsInducing g) : IsInducing (Limits.prod.map f g) := by constructor - simp_rw [topologicalSpace_coe, prod_topology, induced_inf, induced_compose, ← coe_comp, + simp_rw [prod_topology, induced_inf, induced_compose, ← coe_comp, prod.map_fst, prod.map_snd, coe_comp, ← induced_compose (g := f), ← induced_compose (g := g)] - erw [← hf.eq_induced, ← hg.eq_induced] -- now `erw` after https://github.com/leanprover-community/mathlib4/pull/13170 - rfl -- `rfl` was not needed before https://github.com/leanprover-community/mathlib4/pull/13170 + rw [← hf.eq_induced, ← hg.eq_induced] @[deprecated (since := "2024-10-28")] alias inducing_prod_map := isInducing_prodMap @@ -261,14 +251,13 @@ end Prod /-- The binary coproduct cofan in `TopCat`. -/ protected def binaryCofan (X Y : TopCat.{u}) : BinaryCofan X Y := - BinaryCofan.mk (⟨Sum.inl, by continuity⟩ : X ⟶ TopCat.of (X ⊕ Y)) ⟨Sum.inr, by continuity⟩ + BinaryCofan.mk (ofHom ⟨Sum.inl, by continuity⟩) (ofHom ⟨Sum.inr, by continuity⟩) /-- The constructed binary coproduct cofan in `TopCat` is the coproduct. -/ def binaryCofanIsColimit (X Y : TopCat.{u}) : IsColimit (TopCat.binaryCofan X Y) := by - refine Limits.BinaryCofan.isColimitMk (fun s => - {toFun := Sum.elim s.inl s.inr, continuous_toFun := ?_ }) ?_ ?_ ?_ - · apply - Continuous.sum_elim (BinaryCofan.inl s).continuous_toFun (BinaryCofan.inr s).continuous_toFun + refine Limits.BinaryCofan.isColimitMk (fun s => ofHom + { toFun := Sum.elim s.inl s.inr, continuous_toFun := ?_ }) ?_ ?_ ?_ + · continuity · intro s ext rfl @@ -277,7 +266,7 @@ def binaryCofanIsColimit (X Y : TopCat.{u}) : IsColimit (TopCat.binaryCofan X Y) rfl · intro s m h₁ h₂ ext (x | x) - exacts [(ConcreteCategory.congr_hom h₁ x :), (ConcreteCategory.congr_hom h₂ x :)] + exacts [ConcreteCategory.congr_hom h₁ x, ConcreteCategory.congr_hom h₂ x] theorem binaryCofan_isColimit_iff {X Y : TopCat} (c : BinaryCofan X Y) : Nonempty (IsColimit c) ↔ @@ -303,7 +292,7 @@ theorem binaryCofan_isColimit_iff {X Y : TopCat} (c : BinaryCofan X Y) : exact fun _ => or_not refine ⟨BinaryCofan.IsColimit.mk _ ?_ ?_ ?_ ?_⟩ · intro T f g - refine ContinuousMap.mk ?_ ?_ + refine ofHom (ContinuousMap.mk ?_ ?_) · exact fun x => if h : x ∈ Set.range c.inl then f ((Equiv.ofInjective _ h₁.injective).symm ⟨x, h⟩) else g ((Equiv.ofInjective _ h₂.injective).symm ⟨x, (this x).resolve_left h⟩) @@ -316,9 +305,7 @@ theorem binaryCofan_isColimit_iff {X Y : TopCat} (c : BinaryCofan X Y) : convert_to Continuous (f ∘ (Homeomorph.ofIsEmbedding _ h₁.isEmbedding).symm) · ext ⟨x, hx⟩ exact dif_pos hx - apply Continuous.comp - · exact f.continuous_toFun - · continuity + continuity · exact h₁.isOpen_range · revert h x apply (IsOpen.continuousOn_iff _).mp @@ -331,7 +318,7 @@ theorem binaryCofan_isColimit_iff {X Y : TopCat} (c : BinaryCofan X Y) : · ext ⟨x, hx⟩ exact dif_neg hx apply Continuous.comp - · exact g.continuous_toFun + · exact g.hom.continuous_toFun · apply Continuous.comp · continuity · rw [IsEmbedding.subtypeVal.isInducing.continuous_iff] @@ -341,17 +328,17 @@ theorem binaryCofan_isColimit_iff {X Y : TopCat} (c : BinaryCofan X Y) : exact h₂.isOpen_range · intro T f g ext x - refine (dif_pos ?_).trans ?_ - · exact ⟨x, rfl⟩ - · dsimp - conv_lhs => rw [Equiv.ofInjective_symm_apply] + dsimp + rw [dif_pos] + conv_lhs => rw [Equiv.ofInjective_symm_apply] · intro T f g ext x - refine (dif_neg ?_).trans ?_ + dsimp + rw [dif_neg] + · exact congr_arg g (Equiv.ofInjective_symm_apply _ _) · rintro ⟨y, e⟩ have : c.inr x ∈ Set.range c.inl ⊓ Set.range c.inr := ⟨⟨_, e⟩, ⟨_, rfl⟩⟩ rwa [disjoint_iff.mp h₃.1] at this - · exact congr_arg g (Equiv.ofInjective_symm_apply _ _) · rintro T _ _ m rfl rfl ext x change m x = dite _ _ _ diff --git a/Mathlib/Topology/Category/TopCat/Limits/Pullbacks.lean b/Mathlib/Topology/Category/TopCat/Limits/Pullbacks.lean index 910c964c28b26..9f15b3544fecb 100644 --- a/Mathlib/Topology/Category/TopCat/Limits/Pullbacks.lean +++ b/Mathlib/Topology/Category/TopCat/Limits/Pullbacks.lean @@ -29,13 +29,13 @@ variable {X Y Z : TopCat.{u}} /-- The first projection from the pullback. -/ abbrev pullbackFst (f : X ⟶ Z) (g : Y ⟶ Z) : TopCat.of { p : X × Y // f p.1 = g p.2 } ⟶ X := - ⟨Prod.fst ∘ Subtype.val, by fun_prop⟩ + ofHom ⟨Prod.fst ∘ Subtype.val, by fun_prop⟩ lemma pullbackFst_apply (f : X ⟶ Z) (g : Y ⟶ Z) (x) : pullbackFst f g x = x.1.1 := rfl /-- The second projection from the pullback. -/ abbrev pullbackSnd (f : X ⟶ Z) (g : Y ⟶ Z) : TopCat.of { p : X × Y // f p.1 = g p.2 } ⟶ Y := - ⟨Prod.snd ∘ Subtype.val, by fun_prop⟩ + ofHom ⟨Prod.snd ∘ Subtype.val, by fun_prop⟩ lemma pullbackSnd_apply (f : X ⟶ Z) (g : Y ⟶ Z) (x) : pullbackSnd f g x = x.1.2 := rfl @@ -45,11 +45,7 @@ def pullbackCone (f : X ⟶ Z) (g : Y ⟶ Z) : PullbackCone f g := (by dsimp [pullbackFst, pullbackSnd, Function.comp_def] ext ⟨x, h⟩ - -- Next 2 lines were - -- `rw [comp_apply, ContinuousMap.coe_mk, comp_apply, ContinuousMap.coe_mk]` - -- `exact h` before https://github.com/leanprover/lean4/pull/2644 - rw [CategoryTheory.comp_apply, CategoryTheory.comp_apply] - congr!) + simpa) /-- The constructed cone is a limit. -/ def pullbackConeIsLimit (f : X ⟶ Z) (g : Y ⟶ Z) : IsLimit (pullbackCone f g) := @@ -57,28 +53,24 @@ def pullbackConeIsLimit (f : X ⟶ Z) (g : Y ⟶ Z) : IsLimit (pullbackCone f g) (by intro S constructor; swap - · exact + · exact ofHom { toFun := fun x => ⟨⟨S.fst x, S.snd x⟩, by simpa using ConcreteCategory.congr_hom S.condition x⟩ continuous_toFun := by apply Continuous.subtype_mk <| Continuous.prod_mk ?_ ?_ - · exact (PullbackCone.fst S)|>.continuous_toFun - · exact (PullbackCone.snd S)|>.continuous_toFun + · exact (PullbackCone.fst S).hom.continuous_toFun + · exact (PullbackCone.snd S).hom.continuous_toFun } refine ⟨?_, ?_, ?_⟩ · delta pullbackCone ext a - -- This used to be `rw`, but we need `rw; rfl` after https://github.com/leanprover/lean4/pull/2644 - rw [CategoryTheory.comp_apply, ContinuousMap.coe_mk] - rfl + dsimp · delta pullbackCone ext a - -- This used to be `rw`, but we need `rw; rfl` after https://github.com/leanprover/lean4/pull/2644 - rw [CategoryTheory.comp_apply, ContinuousMap.coe_mk] - rfl + dsimp · intro m h₁ h₂ + ext x -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11041): used to be `ext x`. - apply ContinuousMap.ext; intro x apply Subtype.ext apply Prod.ext · simpa using ConcreteCategory.congr_hom h₁ x @@ -117,12 +109,11 @@ theorem pullbackIsoProdSubtype_hom_snd (f : X ⟶ Z) (g : Y ⟶ Z) : (pullbackIsoProdSubtype f g).hom ≫ pullbackSnd f g = pullback.snd _ _ := by rw [← Iso.eq_inv_comp, pullbackIsoProdSubtype_inv_snd] --- Porting note: why do I need to tell Lean to coerce pullback to a type theorem pullbackIsoProdSubtype_hom_apply {f : X ⟶ Z} {g : Y ⟶ Z} - (x : HasForget.forget.obj (pullback f g)) : + (x : ↑(pullback f g)) : (pullbackIsoProdSubtype f g).hom x = ⟨⟨pullback.fst f g x, pullback.snd f g x⟩, by - simpa using ConcreteCategory.congr_hom pullback.condition x⟩ := by + simpa using CategoryTheory.congr_fun pullback.condition x⟩ := by apply Subtype.ext; apply Prod.ext exacts [ConcreteCategory.congr_hom (pullbackIsoProdSubtype_hom_fst f g) x, ConcreteCategory.congr_hom (pullbackIsoProdSubtype_hom_snd f g) x] @@ -143,11 +134,13 @@ theorem range_pullback_to_prod {X Y Z : TopCat} (f : X ⟶ Z) (g : Y ⟶ Z) : ext x constructor · rintro ⟨y, rfl⟩ - change (_ ≫ _ ≫ f) _ = (_ ≫ _ ≫ g) _ -- new `change` after https://github.com/leanprover-community/mathlib4/pull/13170 + simp only [← ConcreteCategory.comp_apply, Set.mem_setOf_eq] simp [pullback.condition] · rintro (h : f (_, _).1 = g (_, _).2) use (pullbackIsoProdSubtype f g).inv ⟨⟨_, _⟩, h⟩ - change (forget TopCat).map _ _ = _ -- new `change` after https://github.com/leanprover-community/mathlib4/pull/13170 + -- new `change` after https://github.com/leanprover-community/mathlib4/pull/13170 + -- should be removed when we redo limits for `ConcreteCategory` instead of `HasForget` + change (forget TopCat).map _ _ = _ apply Concrete.limit_ext rintro ⟨⟨⟩⟩ <;> erw [← CategoryTheory.comp_apply, ← CategoryTheory.comp_apply, limit.lift_π] <;> -- now `erw` after https://github.com/leanprover-community/mathlib4/pull/13170 @@ -181,7 +174,7 @@ def pullbackHomeoPreimage theorem isInducing_pullback_to_prod {X Y Z : TopCat.{u}} (f : X ⟶ Z) (g : Y ⟶ Z) : IsInducing <| ⇑(prod.lift (pullback.fst f g) (pullback.snd f g)) := - ⟨by simp [topologicalSpace_coe, prod_topology, pullback_topology, induced_compose, ← coe_comp]⟩ + ⟨by simp [prod_topology, pullback_topology, induced_compose, ← coe_comp]⟩ @[deprecated (since := "2024-10-28")] alias inducing_pullback_to_prod := isInducing_pullback_to_prod @@ -202,39 +195,46 @@ theorem range_pullback_map {W X Y Z S T : TopCat} (f₁ : W ⟶ S) (f₂ : X ⟶ constructor · rintro ⟨y, rfl⟩ simp only [Set.mem_inter_iff, Set.mem_preimage, Set.mem_range] - rw [← CategoryTheory.comp_apply, ← CategoryTheory.comp_apply] + rw [← ConcreteCategory.comp_apply, ← ConcreteCategory.comp_apply] simp only [limit.lift_π, PullbackCone.mk_pt, PullbackCone.mk_π_app, CategoryTheory.comp_apply] exact ⟨exists_apply_eq_apply _ _, exists_apply_eq_apply _ _⟩ rintro ⟨⟨x₁, hx₁⟩, ⟨x₂, hx₂⟩⟩ have : f₁ x₁ = f₂ x₂ := by apply (TopCat.mono_iff_injective _).mp H₃ - rw [← CategoryTheory.comp_apply, eq₁, ← CategoryTheory.comp_apply, eq₂, - CategoryTheory.comp_apply, CategoryTheory.comp_apply, hx₁, hx₂, ← CategoryTheory.comp_apply, - pullback.condition] - rfl -- `rfl` was not needed before https://github.com/leanprover-community/mathlib4/pull/13170 + rw [← ConcreteCategory.comp_apply, eq₁, ← ConcreteCategory.comp_apply, eq₂, + ConcreteCategory.comp_apply, ConcreteCategory.comp_apply, hx₁, hx₂, + ← ConcreteCategory.comp_apply, pullback.condition, ConcreteCategory.comp_apply] use (pullbackIsoProdSubtype f₁ f₂).inv ⟨⟨x₁, x₂⟩, this⟩ + -- `change` should be removed when we redo limits for `ConcreteCategory` instead of `HasForget` change (forget TopCat).map _ _ = _ apply Concrete.limit_ext rintro (_ | _ | _) <;> erw [← CategoryTheory.comp_apply, ← CategoryTheory.comp_apply] -- now `erw` after https://github.com/leanprover-community/mathlib4/pull/13170 · simp only [Category.assoc, limit.lift_π, PullbackCone.mk_π_app_one] - simp only [cospan_one, pullbackIsoProdSubtype_inv_fst_assoc, CategoryTheory.comp_apply] - rw [pullbackFst_apply, hx₁, ← limit.w _ WalkingCospan.Hom.inl, cospan_map_inl, - CategoryTheory.comp_apply (g := g₁)] + simp only [cospan_one, pullbackIsoProdSubtype_inv_fst_assoc, ConcreteCategory.comp_apply, + CategoryTheory.comp_apply] + -- Work around the `ConcreteCategory`/`HasForget` mismatch: + change g₁ (i₁ ((pullbackFst f₁ f₂) ⟨(x₁, x₂), this⟩)) = (limit.π (cospan g₁ g₂) none) _ + simp [pullbackFst_apply, hx₁, ← limit.w _ WalkingCospan.Hom.inl, cospan_map_inl] · simp only [cospan_left, limit.lift_π, PullbackCone.mk_pt, PullbackCone.mk_π_app, pullbackIsoProdSubtype_inv_fst_assoc, CategoryTheory.comp_apply] - erw [hx₁] -- now `erw` after https://github.com/leanprover-community/mathlib4/pull/13170 + -- Work around the `ConcreteCategory`/`HasForget` mismatch: + change i₁ ((pullbackFst f₁ f₂) ⟨(x₁, x₂), this⟩) = + limit.π (cospan g₁ g₂) (some WalkingPair.left) _ + simp [hx₁] · simp only [cospan_right, limit.lift_π, PullbackCone.mk_pt, PullbackCone.mk_π_app, pullbackIsoProdSubtype_inv_snd_assoc, CategoryTheory.comp_apply] - erw [hx₂] -- now `erw` after https://github.com/leanprover-community/mathlib4/pull/13170 + change i₂ (pullbackSnd f₁ f₂ ⟨(x₁, x₂), this⟩) = + limit.π (cospan g₁ g₂) (some WalkingPair.right) _ + simp [hx₂] theorem pullback_fst_range {X Y S : TopCat} (f : X ⟶ S) (g : Y ⟶ S) : Set.range (pullback.fst f g) = { x : X | ∃ y : Y, f x = g y } := by ext x constructor - · rintro ⟨(y : (forget TopCat).obj _), rfl⟩ - use (pullback.snd f g) y - exact ConcreteCategory.congr_hom pullback.condition y + · rintro ⟨y, rfl⟩ + use pullback.snd f g y + exact CategoryTheory.congr_fun pullback.condition y · rintro ⟨y, eq⟩ use (TopCat.pullbackIsoProdSubtype f g).inv ⟨⟨x, y⟩, eq⟩ rw [pullbackIsoProdSubtype_inv_fst_apply] @@ -243,9 +243,9 @@ theorem pullback_snd_range {X Y S : TopCat} (f : X ⟶ S) (g : Y ⟶ S) : Set.range (pullback.snd f g) = { y : Y | ∃ x : X, f x = g y } := by ext y constructor - · rintro ⟨(x : (forget TopCat).obj _), rfl⟩ - use (pullback.fst f g) x - exact ConcreteCategory.congr_hom pullback.condition x + · rintro ⟨x, rfl⟩ + use pullback.fst f g x + exact CategoryTheory.congr_fun pullback.condition x · rintro ⟨x, eq⟩ use (TopCat.pullbackIsoProdSubtype f g).inv ⟨⟨x, y⟩, eq⟩ rw [pullbackIsoProdSubtype_inv_snd_apply] @@ -406,9 +406,9 @@ theorem pullback_snd_image_fst_preimage (f : X ⟶ Z) (g : Y ⟶ Z) (U : Set X) g ⁻¹' (f '' U) := by ext x constructor - · rintro ⟨(y : (forget TopCat).obj _), hy, rfl⟩ + · rintro ⟨y, hy, rfl⟩ exact - ⟨(pullback.fst f g) y, hy, ConcreteCategory.congr_hom pullback.condition y⟩ + ⟨(pullback.fst f g) y, hy, CategoryTheory.congr_fun pullback.condition y⟩ · rintro ⟨y, hy, eq⟩ -- next 5 lines were -- `exact ⟨(TopCat.pullbackIsoProdSubtype f g).inv ⟨⟨_, _⟩, eq⟩, by simpa, by simp⟩` before https://github.com/leanprover-community/mathlib4/pull/13170 @@ -423,10 +423,10 @@ theorem pullback_fst_image_snd_preimage (f : X ⟶ Z) (g : Y ⟶ Z) (U : Set Y) f ⁻¹' (g '' U) := by ext x constructor - · rintro ⟨(y : (forget TopCat).obj _), hy, rfl⟩ + · rintro ⟨y, hy, rfl⟩ exact ⟨(pullback.snd f g) y, hy, - (ConcreteCategory.congr_hom pullback.condition y).symm⟩ + (CategoryTheory.congr_fun pullback.condition y).symm⟩ · rintro ⟨y, hy, eq⟩ -- next 5 lines were -- `exact ⟨(TopCat.pullbackIsoProdSubtype f g).inv ⟨⟨_, _⟩, eq.symm⟩, by simpa, by simp⟩` @@ -434,7 +434,7 @@ theorem pullback_fst_image_snd_preimage (f : X ⟶ Z) (g : Y ⟶ Z) (U : Set Y) refine ⟨(TopCat.pullbackIsoProdSubtype f g).inv ⟨⟨_, _⟩, eq.symm⟩, ?_, ?_⟩ · simp only [coe_of, Set.mem_preimage] convert hy - erw [pullbackIsoProdSubtype_inv_snd_apply] + rw [pullbackIsoProdSubtype_inv_snd_apply] · rw [pullbackIsoProdSubtype_inv_fst_apply] end Pullback @@ -453,7 +453,6 @@ theorem colimit_topology (F : J ⥤ TopCat.{max v u}) : theorem colimit_isOpen_iff (F : J ⥤ TopCat.{max v u}) (U : Set ((colimit F :) : Type max v u)) : IsOpen U ↔ ∀ j, IsOpen (colimit.ι F j ⁻¹' U) := by - dsimp [topologicalSpace_coe] conv_lhs => rw [colimit_topology F] exact isOpen_iSup_iff @@ -467,7 +466,7 @@ theorem coequalizer_isOpen_iff (F : WalkingParallelPair ⥤ TopCat.{u}) · intro H j cases j · rw [← colimit.w F WalkingParallelPairHom.left] - exact (F.map WalkingParallelPairHom.left).continuous_toFun.isOpen_preimage _ H + exact (F.map WalkingParallelPairHom.left).hom.continuous_toFun.isOpen_preimage _ H · exact H end TopCat diff --git a/Mathlib/Topology/Category/TopCat/Opens.lean b/Mathlib/Topology/Category/TopCat/Opens.lean index cd24b21e34cb9..f7ded3baca850 100644 --- a/Mathlib/Topology/Category/TopCat/Opens.lean +++ b/Mathlib/Topology/Category/TopCat/Opens.lean @@ -98,8 +98,9 @@ theorem leSupr_apply_mk {ι : Type*} (U : ι → Opens X) (i : ι) (x) (m) : realising each open set as a topological space itself. -/ def toTopCat (X : TopCat.{u}) : Opens X ⥤ TopCat where - obj U := ⟨U, inferInstance⟩ - map i := ⟨fun x ↦ ⟨x.1, i.le x.2⟩, IsEmbedding.subtypeVal.continuous_iff.2 continuous_induced_dom⟩ + obj U := TopCat.of U + map i := TopCat.ofHom ⟨fun x ↦ ⟨x.1, i.le x.2⟩, + IsEmbedding.subtypeVal.continuous_iff.2 continuous_induced_dom⟩ @[simp] theorem toTopCat_map (X : TopCat.{u}) {U V : Opens X} {f : U ⟶ V} {x} {h} : @@ -108,10 +109,11 @@ theorem toTopCat_map (X : TopCat.{u}) {U V : Opens X} {f : U ⟶ V} {x} {h} : /-- The inclusion map from an open subset to the whole space, as a morphism in `TopCat`. -/ -@[simps (config := .asFn)] -def inclusion' {X : TopCat.{u}} (U : Opens X) : (toTopCat X).obj U ⟶ X where - toFun := _ - continuous_toFun := continuous_subtype_val +@[simps! (config := .asFn)] +def inclusion' {X : TopCat.{u}} (U : Opens X) : (toTopCat X).obj U ⟶ X := + TopCat.ofHom + { toFun := _ + continuous_toFun := continuous_subtype_val } @[simp] theorem coe_inclusion' {X : TopCat} {U : Opens X} : @@ -127,12 +129,12 @@ alias openEmbedding := isOpenEmbedding -/ def inclusionTopIso (X : TopCat.{u}) : (toTopCat X).obj ⊤ ≅ X where hom := inclusion' ⊤ - inv := ⟨fun x => ⟨x, trivial⟩, continuous_def.2 fun _ ⟨_, hS, hSU⟩ => hSU ▸ hS⟩ + inv := TopCat.ofHom ⟨fun x => ⟨x, trivial⟩, continuous_def.2 fun _ ⟨_, hS, hSU⟩ => hSU ▸ hS⟩ /-- `Opens.map f` gives the functor from open sets in Y to open set in X, given by taking preimages under f. -/ def map (f : X ⟶ Y) : Opens Y ⥤ Opens X where - obj U := ⟨f ⁻¹' (U : Set Y), U.isOpen.preimage f.continuous⟩ + obj U := ⟨f ⁻¹' (U : Set Y), U.isOpen.preimage f.hom.continuous⟩ map i := ⟨⟨fun _ h => i.le h⟩⟩ @[simp] @@ -140,7 +142,7 @@ theorem map_coe (f : X ⟶ Y) (U : Opens Y) : ((map f).obj U : Set X) = f ⁻¹' rfl @[simp] -theorem map_obj (f : X ⟶ Y) (U) (p) : (map f).obj ⟨U, p⟩ = ⟨f ⁻¹' U, p.preimage f.continuous⟩ := +theorem map_obj (f : X ⟶ Y) (U) (p) : (map f).obj ⟨U, p⟩ = ⟨f ⁻¹' U, p.preimage f.hom.continuous⟩ := rfl @[simp] diff --git a/Mathlib/Topology/Category/TopCat/Yoneda.lean b/Mathlib/Topology/Category/TopCat/Yoneda.lean index f724695c46e33..5542ec352bdf8 100644 --- a/Mathlib/Topology/Category/TopCat/Yoneda.lean +++ b/Mathlib/Topology/Category/TopCat/Yoneda.lean @@ -32,7 +32,7 @@ A universe polymorphic "Yoneda presheaf" on `C` given by continuous maps into a @[simps] def yonedaPresheaf : Cᵒᵖ ⥤ Type (max w w') where obj X := C(F.obj (unop X), Y) - map f g := ContinuousMap.comp g (F.map f.unop) + map f g := ContinuousMap.comp g (F.map f.unop).hom /-- A universe polymorphic Yoneda presheaf on `TopCat` given by continuous maps into a topoological @@ -41,7 +41,7 @@ space `Y`. @[simps] def yonedaPresheaf' : TopCat.{w}ᵒᵖ ⥤ Type (max w w') where obj X := C((unop X).1, Y) - map f g := ContinuousMap.comp g f.unop + map f g := ContinuousMap.comp g f.unop.hom theorem comp_yonedaPresheaf' : yonedaPresheaf F Y = F.op ⋙ yonedaPresheaf' Y := rfl diff --git a/Mathlib/Topology/Category/TopCommRingCat.lean b/Mathlib/Topology/Category/TopCommRingCat.lean index eedae4582314d..6544499fdfee3 100644 --- a/Mathlib/Topology/Category/TopCommRingCat.lean +++ b/Mathlib/Topology/Category/TopCommRingCat.lean @@ -86,7 +86,7 @@ instance forgetToCommRingCatTopologicalSpace (R : TopCommRingCat) : /-- The forgetful functor to `TopCat`. -/ instance hasForgetToTopCat : HasForget₂ TopCommRingCat TopCat := - HasForget₂.mk' (fun R => TopCat.of R) (fun _ => rfl) (fun f => ⟨⇑f.1, f.2⟩) HEq.rfl + HasForget₂.mk' (fun R => TopCat.of R) (fun _ => rfl) (fun f => TopCat.ofHom ⟨⇑f.1, f.2⟩) HEq.rfl instance forgetToTopCatCommRing (R : TopCommRingCat) : CommRing ((forget₂ TopCommRingCat TopCat).obj R) := @@ -107,7 +107,7 @@ instance : (forget₂ TopCommRingCat.{u} TopCat.{u}).ReflectsIsomorphisms where let e_Ring : X ≃+* Y := { f.1, ((forget TopCat).mapIso i_Top).toEquiv with } -- Putting these together we obtain the isomorphism we're after: exact - ⟨⟨⟨e_Ring.symm, i_Top.inv.2⟩, + ⟨⟨⟨e_Ring.symm, i_Top.inv.hom.2⟩, ⟨by ext x exact e_Ring.left_inv x, by diff --git a/Mathlib/Topology/Category/UniformSpace.lean b/Mathlib/Topology/Category/UniformSpace.lean index 37b17fb3b293d..e2e2b390df7a8 100644 --- a/Mathlib/Topology/Category/UniformSpace.lean +++ b/Mathlib/Topology/Category/UniformSpace.lean @@ -78,7 +78,7 @@ theorem hom_ext {X Y : UniformSpaceCat} {f g : X ⟶ Y} : (f : X → Y) = g → instance hasForgetToTop : HasForget₂ UniformSpaceCat.{u} TopCat.{u} where forget₂ := { obj := fun X => TopCat.of X - map := fun f => + map := fun f => TopCat.ofHom { toFun := f continuous_toFun := f.property.continuous } } diff --git a/Mathlib/Topology/Gluing.lean b/Mathlib/Topology/Gluing.lean index 1e3280f06bdbe..804c803d834ff 100644 --- a/Mathlib/Topology/Gluing.lean +++ b/Mathlib/Topology/Gluing.lean @@ -112,16 +112,20 @@ def Rel (a b : Σ i, ((D.U i : TopCat) : Type _)) : Prop := ∃ x : D.V (a.1, b.1), D.f _ _ x = a.2 ∧ D.f _ _ (D.t _ _ x) = b.2 theorem rel_equiv : Equivalence D.Rel := - ⟨fun x => ⟨inv (D.f _ _) x.2, IsIso.inv_hom_id_apply _ _, - by simp [IsIso.inv_hom_id_apply _ _]⟩, by + ⟨fun x => ⟨inv (D.f _ _) x.2, IsIso.inv_hom_id_apply (D.f x.fst x.fst) _, + -- Use `elementwise_of%` elaborator instead of `IsIso.inv_hom_id_apply` to work around + -- `ConcreteCategory`/`HasForget` mismatch: + by simp [elementwise_of% IsIso.inv_hom_id (D.f x.fst x.fst)]⟩, by rintro a b ⟨x, e₁, e₂⟩ - exact ⟨D.t _ _ x, e₂, by rw [← e₁, D.t_inv_apply]⟩, by + -- `erw` works around the `ConcreteCategory`/`HasForget` mismatch: + exact ⟨D.t _ _ x, e₂, by erw [← e₁, D.t_inv_apply]⟩, by rintro ⟨i, a⟩ ⟨j, b⟩ ⟨k, c⟩ ⟨x, e₁, e₂⟩ rintro ⟨y, e₃, e₄⟩ let z := (pullbackIsoProdSubtype (D.f j i) (D.f j k)).inv ⟨⟨_, _⟩, e₂.trans e₃.symm⟩ have eq₁ : (D.t j i) ((pullback.fst _ _ : _ /-(D.f j k)-/ ⟶ D.V (j, i)) z) = x := by dsimp only [coe_of, z] - erw [pullbackIsoProdSubtype_inv_fst_apply, D.t_inv_apply]-- now `erw` after https://github.com/leanprover-community/mathlib4/pull/13170 + -- `erw` works around the `ConcreteCategory`/`HasForget` mismatch: + erw [pullbackIsoProdSubtype_inv_fst_apply, D.t_inv_apply] have eq₂ : (pullback.snd _ _ : _ ⟶ D.V _) z = y := pullbackIsoProdSubtype_inv_snd_apply _ _ _ clear_value z use (pullback.fst _ _ : _ ⟶ D.V (i, k)) (D.t' _ _ _ z) @@ -135,7 +139,7 @@ theorem rel_equiv : Equivalence D.Rel := apply @Epi.left_cancellation _ _ _ _ (D.t' k j i) rw [𝖣.cocycle_assoc, 𝖣.t_fac_assoc, 𝖣.t_inv_assoc] exact pullback.condition.symm - exact ⟨ContinuousMap.congr_fun h₁ z, ContinuousMap.congr_fun h₂ z⟩⟩ + exact ⟨CategoryTheory.congr_fun h₁ z, CategoryTheory.congr_fun h₂ z⟩⟩ open CategoryTheory.Limits.WalkingParallelPair @@ -152,12 +156,15 @@ theorem eqvGen_of_π_eq x y := by delta GlueData.π Multicoequalizer.sigmaπ at h -- Porting note: inlined `inferInstance` instead of leaving as a side goal. - replace h := (TopCat.mono_iff_injective (Multicoequalizer.isoCoequalizer 𝖣.diagram).inv).mp + replace h : coequalizer.π D.diagram.fstSigmaMap D.diagram.sndSigmaMap x = + coequalizer.π D.diagram.fstSigmaMap D.diagram.sndSigmaMap y := + (TopCat.mono_iff_injective (Multicoequalizer.isoCoequalizer 𝖣.diagram).inv).mp inferInstance h let diagram := parallelPair 𝖣.diagram.fstSigmaMap 𝖣.diagram.sndSigmaMap ⋙ forget _ have : colimit.ι diagram one x = colimit.ι diagram one y := by - dsimp only [coequalizer.π, ContinuousMap.toFun_eq_coe] at h - rw [← ι_preservesColimitIso_hom, forget_map_eq_coe, types_comp_apply, h] + dsimp only [coequalizer.π] at h + rw [← ι_preservesColimitIso_hom, ConcreteCategory.forget_map_eq_coe, types_comp_apply] + erw [h] simp have : (colimit.ι diagram _ ≫ colim.map _ ≫ (colimit.isoColimitCocone _).hom) _ = @@ -194,9 +201,9 @@ theorem ι_eq_iff_rel (i j : D.J) (x : D.U i) (y : D.U j) : (ConcreteCategory.bijective_of_isIso (sigmaIsoSigma.{u, u} _).inv).2 x unfold InvImage MultispanIndex.fstSigmaMap MultispanIndex.sndSigmaMap simp only [forget_map_eq_coe] - erw [TopCat.comp_app, sigmaIsoSigma_inv_apply, ← CategoryTheory.comp_apply, - ← CategoryTheory.comp_apply, colimit.ι_desc_assoc, ← CategoryTheory.comp_apply, - ← CategoryTheory.comp_apply, colimit.ι_desc_assoc] + erw [TopCat.comp_app, sigmaIsoSigma_inv_apply, ← ConcreteCategory.comp_apply, + ← ConcreteCategory.comp_apply, colimit.ι_desc_assoc, ← ConcreteCategory.comp_apply, + ← ConcreteCategory.comp_apply, colimit.ι_desc_assoc] -- previous line now `erw` after https://github.com/leanprover-community/mathlib4/pull/13170 erw [sigmaIsoSigma_hom_ι_apply, sigmaIsoSigma_hom_ι_apply] exact ⟨y, ⟨rfl, rfl⟩⟩ @@ -204,7 +211,9 @@ theorem ι_eq_iff_rel (i j : D.J) (x : D.U i) (y : D.U j) : dsimp only at * -- Porting note: there were `subst e₁` and `subst e₂`, instead of the `rw` rw [← e₁, ← e₂] at * - rw [D.glue_condition_apply] + -- `erw; rfl` works around the `ConcreteCategory`/`HasForget` mismatch: + erw [D.glue_condition_apply] + rfl theorem ι_injective (i : D.J) : Function.Injective (𝖣.ι i) := by intro x y h @@ -227,7 +236,8 @@ theorem image_inter (i j : D.J) : exact ⟨y, by simp [e₁]⟩ · rintro ⟨x, hx⟩ refine ⟨⟨D.f i j x, hx⟩, ⟨D.f j i (D.t _ _ x), ?_⟩⟩ - rw [D.glue_condition_apply] + -- `erw` works around the `ConcreteCategory`/`HasForget` mismatch: + erw [D.glue_condition_apply] exact hx theorem preimage_range (i j : D.J) : 𝖣.ι j ⁻¹' Set.range (𝖣.ι i) = Set.range (D.f j i) := by @@ -243,7 +253,9 @@ theorem preimage_image_eq_image (i j : D.J) (U : Set (𝖣.U i)) : generalize 𝖣.ι i '' U = U' -- next 4 lines were `simp` before https://github.com/leanprover-community/mathlib4/pull/13170 simp only [GlueData.diagram_l, GlueData.diagram_r, Set.mem_preimage, coe_comp, Function.comp_apply] - rw [D.glue_condition_apply] + -- `erw; rfl` works around the `ConcreteCategory`/`HasForget` mismatch: + erw [D.glue_condition_apply] + rfl rw [← this, Set.image_preimage_eq_inter_range] symm apply Set.inter_eq_self_of_subset_left @@ -269,11 +281,11 @@ theorem open_image_open (i : D.J) (U : Opens (𝖣.U i)) : IsOpen (𝖣.ι i '' intro j rw [preimage_image_eq_image] apply (D.f_open _ _).isOpenMap - apply (D.t j i ≫ D.f i j).continuous_toFun.isOpen_preimage + apply (D.t j i ≫ D.f i j).hom.continuous_toFun.isOpen_preimage exact U.isOpen theorem ι_isOpenEmbedding (i : D.J) : IsOpenEmbedding (𝖣.ι i) := - .of_continuous_injective_isOpenMap (𝖣.ι i).continuous_toFun (D.ι_injective i) fun U h => + .of_continuous_injective_isOpenMap (𝖣.ι i).hom.continuous_toFun (D.ι_injective i) fun U h => D.open_image_open i ⟨U, h⟩ @[deprecated (since := "2024-10-18")] @@ -319,7 +331,7 @@ instance (h : MkCore.{u}) (i j : h.J) : IsIso (h.t i j) := by def MkCore.t' (h : MkCore.{u}) (i j k : h.J) : pullback (h.V i j).inclusion' (h.V i k).inclusion' ⟶ pullback (h.V j k).inclusion' (h.V j i).inclusion' := by - refine (pullbackIsoProdSubtype _ _).hom ≫ ⟨?_, ?_⟩ ≫ (pullbackIsoProdSubtype _ _).inv + refine (pullbackIsoProdSubtype _ _).hom ≫ ofHom ⟨?_, ?_⟩ ≫ (pullbackIsoProdSubtype _ _).inv · intro x refine ⟨⟨⟨(h.t i j x.1.1).1, ?_⟩, h.t i j x.1.1⟩, rfl⟩ rcases x with ⟨⟨⟨x, hx⟩, ⟨x', hx'⟩⟩, rfl : x = x'⟩ @@ -355,8 +367,9 @@ def mk' (h : MkCore.{u}) : TopCat.GlueData where simp only [Iso.inv_hom_id_assoc, Category.assoc, Category.id_comp] rw [← Iso.eq_inv_comp, Iso.inv_hom_id] ext1 ⟨⟨⟨x, hx⟩, ⟨x', hx'⟩⟩, rfl : x = x'⟩ - rw [comp_app, ContinuousMap.coe_mk, comp_app, id_app, ContinuousMap.coe_mk, Subtype.mk_eq_mk, - Prod.mk.inj_iff, Subtype.mk_eq_mk, Subtype.ext_iff, and_self_iff] + dsimp only [Opens.coe_inclusion', hom_comp, hom_ofHom, ContinuousMap.comp_assoc, + ContinuousMap.comp_apply, ContinuousMap.coe_mk, hom_id, ContinuousMap.id_apply] + rw [Subtype.mk_eq_mk, Prod.mk.inj_iff, Subtype.mk_eq_mk, Subtype.ext_iff, and_self_iff] convert congr_arg Subtype.val (h.t_inv k i ⟨x, hx'⟩) using 3 refine Subtype.ext ?_ exact h.cocycle i j k ⟨x, hx⟩ hx' @@ -372,7 +385,7 @@ def ofOpenSubsets : TopCat.GlueData.{u} := { J U := fun i => (Opens.toTopCat <| TopCat.of α).obj (U i) V := fun _ j => (Opens.map <| Opens.inclusion' _).obj (U j) - t := fun i j => ⟨fun x => ⟨⟨x.1.1, x.2⟩, x.1.2⟩, by fun_prop⟩ + t := fun i j => ofHom ⟨fun x => ⟨⟨x.1.1, x.2⟩, x.1.2⟩, by fun_prop⟩ V_id := fun i => by ext; simp t_id := fun i => by ext; rfl t_inter := fun _ _ _ _ hx => hx @@ -420,7 +433,7 @@ theorem fromOpenSubsetsGlue_isOpenMap : IsOpenMap (fromOpenSubsetsGlue U) := by exact Set.preimage_image_eq _ (fromOpenSubsetsGlue_injective U) · refine ⟨Set.mem_image_of_mem _ hx, ?_⟩ rw [ι_fromOpenSubsetsGlue_apply] - exact Set.mem_range_self _ + exact Set.mem_range_self (f := (Opens.inclusion' _).hom) ⟨x, hx'⟩ theorem fromOpenSubsetsGlue_isOpenEmbedding : IsOpenEmbedding (fromOpenSubsetsGlue U) := .of_continuous_injective_isOpenMap (ContinuousMap.continuous_toFun _) @@ -447,7 +460,7 @@ def openCoverGlueHomeo (h : ⋃ i, (U i : Set α) = Set.univ) : (Equiv.ofBijective (fromOpenSubsetsGlue U) ⟨fromOpenSubsetsGlue_injective U, Set.range_eq_univ.mp ((range_fromOpenSubsetsGlue U).symm ▸ h)⟩) - (fromOpenSubsetsGlue U).2 (fromOpenSubsetsGlue_isOpenMap U) + (fromOpenSubsetsGlue U).hom.2 (fromOpenSubsetsGlue_isOpenMap U) end GlueData diff --git a/Mathlib/Topology/Order/Category/AlexDisc.lean b/Mathlib/Topology/Order/Category/AlexDisc.lean index fd44e293d4337..da80cb58877d5 100644 --- a/Mathlib/Topology/Order/Category/AlexDisc.lean +++ b/Mathlib/Topology/Order/Category/AlexDisc.lean @@ -14,45 +14,50 @@ maps, and proves it's equivalent to the category of preorders. open CategoryTheory Topology -/-- Auxiliary typeclass to define the category of Alexandrov-discrete spaces. Do not use this -directly. Use `AlexandrovDiscrete` instead. -/ -class AlexandrovDiscreteSpace (α : Type*) extends TopologicalSpace α, AlexandrovDiscrete α - /-- The category of Alexandrov-discrete spaces. -/ -def AlexDisc := Bundled AlexandrovDiscreteSpace +structure AlexDisc extends TopCat where + [is_alexandrovDiscrete : AlexandrovDiscrete carrier] namespace AlexDisc -instance instCoeSort : CoeSort AlexDisc Type* := Bundled.coeSort -instance instTopologicalSpace (α : AlexDisc) : TopologicalSpace α := α.2.1 -instance instAlexandrovDiscrete (α : AlexDisc) : AlexandrovDiscrete α := α.2.2 +attribute [instance] is_alexandrovDiscrete -instance : BundledHom.ParentProjection @AlexandrovDiscreteSpace.toTopologicalSpace := ⟨⟩ +instance : CoeSort AlexDisc (Type _) := + ⟨fun X => X.toTopCat⟩ -deriving instance LargeCategory for AlexDisc +instance category : Category AlexDisc := + InducedCategory.category toTopCat -instance instHasForget : HasForget AlexDisc := BundledHom.hasForget _ -instance instHasForgetToTop : HasForget₂ AlexDisc TopCat := BundledHom.forget₂ _ _ -instance forgetToTop_full : (forget₂ AlexDisc TopCat).Full := BundledHom.forget₂_full _ _ -instance forgetToTop_faithful : (forget₂ AlexDisc TopCat).Faithful where +instance concreteCategory : ConcreteCategory AlexDisc (C(·, ·)) := + InducedCategory.concreteCategory toTopCat -@[simp] lemma coe_forgetToTop (X : AlexDisc) : ↥((forget₂ _ TopCat).obj X) = X := rfl +instance instHasForgetToTop : HasForget₂ AlexDisc TopCat := InducedCategory.hasForget₂ toTopCat + +-- TODO: generalize to `InducedCategory.forget₂_full`? +instance forgetToTop_full : (forget₂ AlexDisc TopCat).Full where + map_surjective f := ⟨f, rfl⟩ + +instance forgetToTop_faithful : (forget₂ AlexDisc TopCat).Faithful where /-- Construct a bundled `AlexDisc` from the underlying topological space. -/ -def of (α : Type*) [TopologicalSpace α] [AlexandrovDiscrete α] : AlexDisc := ⟨α, ⟨⟩⟩ +abbrev of (X : Type*) [TopologicalSpace X] [AlexandrovDiscrete X] : AlexDisc where + toTopCat := TopCat.of X + +lemma coe_of (α : Type*) [TopologicalSpace α] [AlexandrovDiscrete α] : ↥(of α) = α := rfl -@[simp] lemma coe_of (α : Type*) [TopologicalSpace α] [AlexandrovDiscrete α] : ↥(of α) = α := rfl @[simp] lemma forgetToTop_of (α : Type*) [TopologicalSpace α] [AlexandrovDiscrete α] : (forget₂ AlexDisc TopCat).obj (of α) = TopCat.of α := rfl +@[simp] lemma coe_forgetToTop (X : AlexDisc) : ↥((forget₂ _ TopCat).obj X) = X := rfl + -- This was a global instance prior to https://github.com/leanprover-community/mathlib4/pull/13170. We may experiment with removing it. attribute [local instance] CategoryTheory.HasForget.instFunLike /-- Constructs an equivalence between preorders from an order isomorphism between them. -/ @[simps] def Iso.mk {α β : AlexDisc} (e : α ≃ₜ β) : α ≅ β where - hom := (e : ContinuousMap α β) - inv := (e.symm : ContinuousMap β α) + hom := TopCat.ofHom (e : ContinuousMap α β) + inv := TopCat.ofHom (e.symm : ContinuousMap β α) hom_inv_id := DFunLike.ext _ _ e.symm_apply_apply inv_hom_id := DFunLike.ext _ _ e.apply_symm_apply @@ -62,7 +67,8 @@ end AlexDisc @[simps] def alexDiscEquivPreord : AlexDisc ≌ Preord where functor := forget₂ _ _ ⋙ topToPreord - inverse := { obj := fun X ↦ AlexDisc.of (WithUpperSet X), map := WithUpperSet.map } + inverse.obj X := AlexDisc.of (WithUpperSet X) + inverse.map f := TopCat.ofHom (WithUpperSet.map f) unitIso := NatIso.ofComponents fun X ↦ AlexDisc.Iso.mk <| by dsimp; exact homeoWithUpperSetTopologyorderIso X counitIso := NatIso.ofComponents fun X ↦ Preord.Iso.mk <| by diff --git a/Mathlib/Topology/Order/Category/FrameAdjunction.lean b/Mathlib/Topology/Order/Category/FrameAdjunction.lean index 2501e640cac85..192dfc9fe540f 100644 --- a/Mathlib/Topology/Order/Category/FrameAdjunction.lean +++ b/Mathlib/Topology/Order/Category/FrameAdjunction.lean @@ -84,8 +84,9 @@ topological spaces, which sends a locale `L` to the topological space `PT L` of from `L` to `Prop` and a locale homomorphism `f` to a continuous function between the spaces of points. -/ def pt : Locale ⥤ TopCat where - obj L := ⟨PT L.unop, inferInstance⟩ - map f := ⟨fun p ↦ p.comp f.unop, continuous_def.2 <| by rintro s ⟨u, rfl⟩; use f.unop u; rfl⟩ + obj L := TopCat.of (PT L.unop) + map f := TopCat.ofHom ⟨fun p ↦ p.comp f.unop, + continuous_def.2 <| by rintro s ⟨u, rfl⟩; use f.unop u; rfl⟩ end pt_definition section locale_top_adjunction @@ -110,7 +111,7 @@ def counitAppCont : FrameHom L (Opens <| PT L) where /-- The forgetful functor `topToLocale` is left adjoint to the functor `pt`. -/ def adjunctionTopToLocalePT : topToLocale ⊣ pt where - unit := { app := fun X ↦ ⟨localePointOfSpacePoint X, continuous_def.2 <| + unit := { app := fun X ↦ TopCat.ofHom ⟨localePointOfSpacePoint X, continuous_def.2 <| by rintro _ ⟨u, rfl⟩; simpa using u.2⟩ } counit := { app := fun L ↦ ⟨counitAppCont L⟩ } diff --git a/Mathlib/Topology/Sheaves/CommRingCat.lean b/Mathlib/Topology/Sheaves/CommRingCat.lean index 2bdba51313e3d..9ee14ac28953d 100644 --- a/Mathlib/Topology/Sheaves/CommRingCat.lean +++ b/Mathlib/Topology/Sheaves/CommRingCat.lean @@ -196,23 +196,54 @@ section ContinuousFunctions namespace TopCat -variable (X : TopCat.{v}) +variable (X : TopCat.{v}) (R : TopCommRingCat.{v}) + +instance : NatCast (X ⟶ (forget₂ TopCommRingCat TopCat).obj R) where + natCast n := ofHom n + +instance : IntCast (X ⟶ (forget₂ TopCommRingCat TopCat).obj R) where + intCast n := ofHom n + +instance : Zero (X ⟶ (forget₂ TopCommRingCat TopCat).obj R) where + zero := ofHom 0 + +instance : One (X ⟶ (forget₂ TopCommRingCat TopCat).obj R) where + one := ofHom 1 + +instance : Neg (X ⟶ (forget₂ TopCommRingCat TopCat).obj R) where + neg f := ofHom (-f.hom) + +instance : Sub (X ⟶ (forget₂ TopCommRingCat TopCat).obj R) where + sub f g := ofHom (f.hom - g.hom) + +instance : Add (X ⟶ (forget₂ TopCommRingCat TopCat).obj R) where + add f g := ofHom (f.hom + g.hom) + +instance : Mul (X ⟶ (forget₂ TopCommRingCat TopCat).obj R) where + mul f g := ofHom (f.hom * g.hom) + +instance : SMul ℕ (X ⟶ (forget₂ TopCommRingCat TopCat).obj R) where + smul n f := ofHom (n • f.hom) + +instance : SMul ℤ (X ⟶ (forget₂ TopCommRingCat TopCat).obj R) where + smul n f := ofHom (n • f.hom) + +instance : Pow (X ⟶ (forget₂ TopCommRingCat TopCat).obj R) ℕ where + pow f n := ofHom (f.hom ^ n) + +instance : CommRing (X ⟶ (forget₂ TopCommRingCat TopCat).obj R) := + Function.Injective.commRing _ ConcreteCategory.hom_injective + rfl rfl (fun _ _ => rfl) (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) + (fun _ _ => rfl) (fun _ _ => rfl) (fun _ => rfl) (fun _ => rfl) -- TODO upgrade the result to TopCommRing? /-- The (bundled) commutative ring of continuous functions from a topological space to a topological commutative ring, with pointwise multiplication. -/ def continuousFunctions (X : TopCat.{v}ᵒᵖ) (R : TopCommRingCat.{v}) : CommRingCat.{v} := - -- Porting note: Lean did not see through that `X.unop ⟶ R` is just continuous functions - -- hence forms a ring - @CommRingCat.of (X.unop ⟶ (forget₂ TopCommRingCat TopCat).obj R) <| - inferInstanceAs (CommRing (ContinuousMap _ _)) + CommRingCat.of (X.unop ⟶ (forget₂ TopCommRingCat TopCat).obj R) namespace continuousFunctions -instance (X : TopCat.{v}ᵒᵖ) (R : TopCommRingCat.{v}) : - CommRing (unop X ⟶ (forget₂ TopCommRingCat TopCat).obj R) := - inferInstanceAs (CommRing (ContinuousMap _ _)) - /-- Pulling back functions into a topological ring along a continuous map is a ring homomorphism. -/ def pullback {X Y : TopCatᵒᵖ} (f : X ⟶ Y) (R : TopCommRingCat) : continuousFunctions X R ⟶ continuousFunctions Y R := CommRingCat.ofHom @@ -227,12 +258,10 @@ this is a ring homomorphism (with respect to the pointwise ring operations on fu def map (X : TopCat.{u}ᵒᵖ) {R S : TopCommRingCat.{u}} (φ : R ⟶ S) : continuousFunctions X R ⟶ continuousFunctions X S := CommRingCat.ofHom { toFun g := g ≫ (forget₂ TopCommRingCat TopCat).map φ - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11041): `ext` tactic does not work, since Lean can't see through `R ⟶ S` is just - -- continuous ring homomorphism - map_one' := ContinuousMap.ext fun _ => φ.1.map_one - map_zero' := ContinuousMap.ext fun _ => φ.1.map_zero - map_add' := fun _ _ => ContinuousMap.ext fun _ => φ.1.map_add _ _ - map_mul' := fun _ _ => ContinuousMap.ext fun _ => φ.1.map_mul _ _ } + map_one' := by ext; exact φ.1.map_one + map_zero' := by ext; exact φ.1.map_zero + map_add' _ _ := by ext; exact φ.1.map_add _ _ + map_mul' _ _ := by ext; exact φ.1.map_mul _ _ } end continuousFunctions @@ -353,9 +382,8 @@ theorem objSupIsoProdEqLocus_inv_eq_iff {X : TopCat.{u}} (F : X.Sheaf CommRingCa constructor · rintro rfl rw [← TopCat.Sheaf.objSupIsoProdEqLocus_inv_fst, ← TopCat.Sheaf.objSupIsoProdEqLocus_inv_snd] - -- `simp` doesn't see through the type equality of objects in `CommRingCat`, so use `rw` https://github.com/leanprover-community/mathlib4/pull/8386 - repeat rw [← CommRingCat.comp_apply] - simp only [← Functor.map_comp, ← op_comp, Category.assoc, homOfLE_comp, and_self] + simp only [← CommRingCat.comp_apply, ← Functor.map_comp, ← op_comp, Category.assoc, + homOfLE_comp, and_self] · rintro ⟨e₁, e₂⟩ refine F.eq_of_locally_eq₂ (homOfLE (inf_le_right : U ⊓ W ≤ W)) (homOfLE (inf_le_right : V ⊓ W ≤ W)) ?_ _ _ ?_ ?_ @@ -364,15 +392,13 @@ theorem objSupIsoProdEqLocus_inv_eq_iff {X : TopCat.{u}} (F : X.Sheaf CommRingCa · change (F.val.map _) ((F.val.map (homOfLE e).op).hom ((F.objSupIsoProdEqLocus U V).inv.hom x)) = (F.val.map _) y rw [← e₁, ← TopCat.Sheaf.objSupIsoProdEqLocus_inv_fst] - -- `simp` doesn't see through the type equality of objects in `CommRingCat`, so use `rw` https://github.com/leanprover-community/mathlib4/pull/8386 - repeat rw [← CommRingCat.comp_apply] - simp only [← Functor.map_comp, ← op_comp, Category.assoc, homOfLE_comp] + simp only [← CommRingCat.comp_apply, ← Functor.map_comp, ← op_comp, Category.assoc, + homOfLE_comp] · show (F.val.map _) ((F.val.map (homOfLE e).op).hom ((F.objSupIsoProdEqLocus U V).inv.hom x)) = (F.val.map _) y rw [← e₂, ← TopCat.Sheaf.objSupIsoProdEqLocus_inv_snd] - -- `simp` doesn't see through the type equality of objects in `CommRingCat`, so use `rw` https://github.com/leanprover-community/mathlib4/pull/8386 - repeat rw [← CommRingCat.comp_apply] - simp only [← Functor.map_comp, ← op_comp, Category.assoc, homOfLE_comp] + simp only [← CommRingCat.comp_apply, ← Functor.map_comp, ← op_comp, Category.assoc, + homOfLE_comp] end TopCat.Sheaf diff --git a/Mathlib/Topology/Sheaves/LocalPredicate.lean b/Mathlib/Topology/Sheaves/LocalPredicate.lean index f212a015ac7f6..b23ec369670d9 100644 --- a/Mathlib/Topology/Sheaves/LocalPredicate.lean +++ b/Mathlib/Topology/Sheaves/LocalPredicate.lean @@ -269,7 +269,7 @@ the presheaf of continuous functions. def subpresheafContinuousPrelocalIsoPresheafToTop (T : TopCat.{v}) : subpresheafToTypes (continuousPrelocal X T) ≅ presheafToTop X T := NatIso.ofComponents fun X => - { hom := by rintro ⟨f, c⟩; exact ⟨f, c⟩ + { hom := by rintro ⟨f, c⟩; exact ofHom ⟨f, c⟩ inv := by rintro ⟨f, c⟩; exact ⟨f, c⟩ } /-- The sheaf of continuous functions on `X` with values in a space `T`. diff --git a/Mathlib/Topology/Sheaves/SheafCondition/UniqueGluing.lean b/Mathlib/Topology/Sheaves/SheafCondition/UniqueGluing.lean index 3ff71a0720c23..bca89d92fce46 100644 --- a/Mathlib/Topology/Sheaves/SheafCondition/UniqueGluing.lean +++ b/Mathlib/Topology/Sheaves/SheafCondition/UniqueGluing.lean @@ -135,8 +135,6 @@ end TypeValued section -attribute [local instance] HasForget.hasCoeToSort HasForget.instFunLike - variable [HasLimits C] [(forget C).ReflectsIsomorphisms] [PreservesLimits (forget C)] variable {X : TopCat.{v}} (F : Presheaf C X) diff --git a/Mathlib/Topology/Sheaves/Skyscraper.lean b/Mathlib/Topology/Sheaves/Skyscraper.lean index 259b736775448..64f9541a6587a 100644 --- a/Mathlib/Topology/Sheaves/Skyscraper.lean +++ b/Mathlib/Topology/Sheaves/Skyscraper.lean @@ -66,9 +66,10 @@ def skyscraperPresheaf : Presheaf C X where theorem skyscraperPresheaf_eq_pushforward [hd : ∀ U : Opens (TopCat.of PUnit.{u + 1}), Decidable (PUnit.unit ∈ U)] : skyscraperPresheaf p₀ A = - ContinuousMap.const (TopCat.of PUnit) p₀ _* + (ofHom (ContinuousMap.const (TopCat.of PUnit) p₀)) _* skyscraperPresheaf (X := TopCat.of PUnit) PUnit.unit A := by - convert_to @skyscraperPresheaf X p₀ (fun U => hd <| (Opens.map <| ContinuousMap.const _ p₀).obj U) + convert_to @skyscraperPresheaf X p₀ (fun U => hd <| (Opens.map <| ofHom <| + ContinuousMap.const _ p₀).obj U) C _ _ A = _ <;> congr /-- Taking skyscraper presheaf at a point is functorial: `c ↦ skyscraper p₀ c` defines a functor by diff --git a/Mathlib/Topology/Sheaves/Stalks.lean b/Mathlib/Topology/Sheaves/Stalks.lean index c977d29a84f28..a6f2e68ef6c47 100644 --- a/Mathlib/Topology/Sheaves/Stalks.lean +++ b/Mathlib/Topology/Sheaves/Stalks.lean @@ -374,7 +374,7 @@ theorem stalkSpecializes_stalkFunctor_map {F G : X.Presheaf C} (f : F ⟶ G) {x -- See https://github.com/leanprover-community/batteries/issues/365 for the simpNF issue. @[reassoc, elementwise, simp, nolint simpNF] theorem stalkSpecializes_stalkPushforward (f : X ⟶ Y) (F : X.Presheaf C) {x y : X} (h : x ⤳ y) : - (f _* F).stalkSpecializes (f.map_specializes h) ≫ F.stalkPushforward _ f x = + (f _* F).stalkSpecializes (f.hom.map_specializes h) ≫ F.stalkPushforward _ f x = F.stalkPushforward _ f y ≫ F.stalkSpecializes h := by change (_ : colimit _ ⟶ _) = (_ : colimit _ ⟶ _) ext; delta stalkPushforward diff --git a/Mathlib/Topology/Specialization.lean b/Mathlib/Topology/Specialization.lean index bd57a351804bd..1ffdefb59b68c 100644 --- a/Mathlib/Topology/Specialization.lean +++ b/Mathlib/Topology/Specialization.lean @@ -87,4 +87,4 @@ def homeoWithUpperSetTopologyorderIso (α : Type*) [TopologicalSpace α] [Alexan @[simps] def topToPreord : TopCat ⥤ Preord where obj X := Preord.of <| Specialization X - map := Specialization.map + map {X Y} f := Specialization.map (α := X) (β := Y) f.hom diff --git a/MathlibTest/slow_simp.lean b/MathlibTest/slow_simp.lean index 124ec08fb86dc..587f98f81ac99 100644 --- a/MathlibTest/slow_simp.lean +++ b/MathlibTest/slow_simp.lean @@ -51,16 +51,16 @@ instance : Category PointedSpace where end PointedSpace -set_option maxHeartbeats 40000 in +set_option maxHeartbeats 20000 in def PointedSpaceEquiv_inverse : Under (TopCat.of Unit) ⥤ PointedSpace where obj := fun X => { carrier := X.right base := X.hom () } map := fun f => - { map := f.right + { map := f.right.hom base := by have := f.w - replace this := DFunLike.congr_fun this () + replace this := CategoryTheory.congr_fun this () simp [-Under.w] at this simp exact this.symm } From 89c8ee9c08f18fff82ca7a7d5ae2caef95d0e905 Mon Sep 17 00:00:00 2001 From: Yakov Pechersky Date: Mon, 3 Feb 2025 16:47:38 +0000 Subject: [PATCH 042/103] chore(InfiniteSum/NatInt): put `Multipliable.tendsto_prod_tprod_nat` in the right namespace (#21337) Before, it was: ``` HasProd.Multipliable.tendsto_prod_tprod_nat ``` which made the additive version ``` HasSum.Multipliable.tendsto_sum_tsum_nat ``` By lifting into the root namespace, Multipliable properly additivizes Co-authored-by: Yakov Pechersky --- Mathlib/Topology/Algebra/InfiniteSum/NatInt.lean | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Mathlib/Topology/Algebra/InfiniteSum/NatInt.lean b/Mathlib/Topology/Algebra/InfiniteSum/NatInt.lean index 83fcac52c0419..31ac4d376124e 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/NatInt.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/NatInt.lean @@ -35,13 +35,11 @@ section Nat section Monoid -namespace HasProd - /-- If `f : ℕ → M` has product `m`, then the partial products `∏ i ∈ range n, f i` converge to `m`. -/ @[to_additive "If `f : ℕ → M` has sum `m`, then the partial sums `∑ i ∈ range n, f i` converge to `m`."] -theorem tendsto_prod_nat {f : ℕ → M} (h : HasProd f m) : +theorem HasProd.tendsto_prod_nat {f : ℕ → M} (h : HasProd f m) : Tendsto (fun n ↦ ∏ i ∈ range n, f i) atTop (𝓝 m) := h.comp tendsto_finset_range @@ -51,7 +49,15 @@ to `∏' i, f i`. -/ to `∑' i, f i`."] theorem Multipliable.tendsto_prod_tprod_nat {f : ℕ → M} (h : Multipliable f) : Tendsto (fun n ↦ ∏ i ∈ range n, f i) atTop (𝓝 (∏' i, f i)) := - tendsto_prod_nat h.hasProd + h.hasProd.tendsto_prod_nat + +@[deprecated (since := "2025-02-02")] +alias HasProd.Multipliable.tendsto_prod_tprod_nat := Multipliable.tendsto_prod_tprod_nat + +@[deprecated (since := "2025-02-02")] +alias HasSum.Multipliable.tendsto_sum_tsum_nat := Summable.tendsto_sum_tsum_nat + +namespace HasProd section ContinuousMul From 7bb9660499e451d2f1346888702596b9fed41723 Mon Sep 17 00:00:00 2001 From: Alex Meiburg Date: Mon, 3 Feb 2025 16:47:39 +0000 Subject: [PATCH 043/103] feat(Analysis/RCLike/Basic): PosMulReflectLE (#21351) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds ``` @[simp] theorem RCLike.inv_nonneg {x : 𝕜} : 0 ≤ x⁻¹ ↔ 0 ≤ x ``` to match [inv_nonneg](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/Order/GroupWithZero/Unbundled.html#inv_nonneg) and [Rat.inv_nonneg](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Algebra/Field/Rat.html#Rat.inv_nonneg). Upstreamed from [QuantumInfo](https://github.com/Timeroot/Lean-QuantumInfo) Co-authored-by: Alex Meiburg --- Mathlib/Analysis/RCLike/Basic.lean | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Mathlib/Analysis/RCLike/Basic.lean b/Mathlib/Analysis/RCLike/Basic.lean index efaf322fb9c49..a96b068f2f45a 100644 --- a/Mathlib/Analysis/RCLike/Basic.lean +++ b/Mathlib/Analysis/RCLike/Basic.lean @@ -879,6 +879,19 @@ theorem ofReal_mul_neg_iff (x : ℝ) (z : K) : x * z < 0 ↔ (x < 0 ∧ 0 < z) ∨ (0 < x ∧ z < 0) := by simpa only [mul_neg, neg_pos, neg_neg_iff_pos] using ofReal_mul_pos_iff x (-z) +lemma instPosMulReflectLE : PosMulReflectLE K := by + constructor + intro a b c (h : _ * _ ≤ _ * _) + obtain ⟨a', ha1, ha2⟩ := pos_iff_exists_ofReal.mp a.2 + rw [← sub_nonneg] + rw [← ha2, ← sub_nonneg, ← mul_sub, le_iff_lt_or_eq] at h + rcases h with h | h + · rw [ofReal_mul_pos_iff] at h + exact le_of_lt <| h.rec (False.elim <| not_lt_of_gt ·.1 ha1) (·.2) + · exact ((mul_eq_zero_iff_left <| ofReal_ne_zero.mpr ha1.ne').mp h.symm).ge + +scoped[ComplexOrder] attribute [instance] RCLike.instPosMulReflectLE + end Order section CleanupLemmas From fc39d3b84083d7355ac85f75b7305939ae4b31e8 Mon Sep 17 00:00:00 2001 From: Anne Baanen Date: Mon, 3 Feb 2025 16:47:41 +0000 Subject: [PATCH 044/103] feat(Algebra/Category): `ConcreteCategory` instance for `Semigrp` (#21368) Very straightforward, essentially copypasting the design of `MonCat` back onto `MagmaCat` and `Semigrp`. We can probably do without this amount of `dsimp` lemmas, they should all be pretty easy to prove from generic `ConcreteCategory` results, but it doesn't hurt to have them in any case. --- .../Algebra/Category/MonCat/Adjunctions.lean | 8 +- Mathlib/Algebra/Category/Semigrp/Basic.lean | 371 +++++++++++++----- .../ConcreteCategory/Semigrp.lean | 47 +++ 3 files changed, 322 insertions(+), 104 deletions(-) create mode 100644 MathlibTest/CategoryTheory/ConcreteCategory/Semigrp.lean diff --git a/Mathlib/Algebra/Category/MonCat/Adjunctions.lean b/Mathlib/Algebra/Category/MonCat/Adjunctions.lean index d4219c84e035f..e1d6ad2dd4607 100644 --- a/Mathlib/Algebra/Category/MonCat/Adjunctions.lean +++ b/Mathlib/Algebra/Category/MonCat/Adjunctions.lean @@ -32,7 +32,7 @@ namespace MonCat @[to_additive (attr := simps) "The functor of adjoining a neutral element `zero` to a semigroup"] def adjoinOne : Semigrp.{u} ⥤ MonCat.{u} where obj S := MonCat.of (WithOne S) - map f := ofHom (WithOne.map f) + map f := ofHom (WithOne.map f.hom) map_id _ := MonCat.hom_ext WithOne.map_id map_comp _ _ := MonCat.hom_ext (WithOne.map_comp _ _) @@ -40,13 +40,15 @@ def adjoinOne : Semigrp.{u} ⥤ MonCat.{u} where instance hasForgetToSemigroup : HasForget₂ MonCat Semigrp where forget₂ := { obj := fun M => Semigrp.of M - map f := f.hom.toMulHom } + map f := Semigrp.ofHom f.hom.toMulHom } /-- The `adjoinOne`-forgetful adjunction from `Semigrp` to `MonCat`. -/ @[to_additive "The `adjoinZero`-forgetful adjunction from `AddSemigrp` to `AddMonCat`"] def adjoinOneAdj : adjoinOne ⊣ forget₂ MonCat.{u} Semigrp.{u} := Adjunction.mkOfHomEquiv - { homEquiv := fun _ _ => ConcreteCategory.homEquiv.trans WithOne.lift.symm + { homEquiv X Y := + ConcreteCategory.homEquiv.trans (WithOne.lift.symm.trans + (ConcreteCategory.homEquiv (X := X) (Y := (forget₂ _ _).obj Y)).symm) homEquiv_naturality_left_symm := by intros ext ⟨_|_⟩ <;> simp <;> rfl } diff --git a/Mathlib/Algebra/Category/Semigrp/Basic.lean b/Mathlib/Algebra/Category/Semigrp/Basic.lean index f587fda266623..4032f9def4d0c 100644 --- a/Mathlib/Algebra/Category/Semigrp/Basic.lean +++ b/Mathlib/Algebra/Category/Semigrp/Basic.lean @@ -5,7 +5,7 @@ Authors: Julian Kuelshammer -/ import Mathlib.Algebra.PEmptyInstances import Mathlib.Algebra.Group.Equiv.Defs -import Mathlib.CategoryTheory.ConcreteCategory.BundledHom +import Mathlib.CategoryTheory.ConcreteCategory.Basic import Mathlib.CategoryTheory.Functor.ReflectsIso /-! @@ -31,77 +31,163 @@ universe u v open CategoryTheory +/-- The category of additive magmas and additive magma morphisms. -/ +structure AddMagmaCat : Type (u + 1) where + /-- The underlying additive magma. -/ + (carrier : Type u) + [str : Add carrier] + /-- The category of magmas and magma morphisms. -/ @[to_additive] -def MagmaCat : Type (u + 1) := - Bundled Mul +structure MagmaCat : Type (u + 1) where + /-- The underlying magma. -/ + (carrier : Type u) + [str : Mul carrier] -/-- The category of additive magmas and additive magma morphisms. -/ -add_decl_doc AddMagmaCat +attribute [instance] AddMagmaCat.str MagmaCat.str +attribute [to_additive existing] MagmaCat.carrier MagmaCat.str + +initialize_simps_projections AddMagmaCat (carrier → coe, -str) +initialize_simps_projections MagmaCat (carrier → coe, -str) namespace MagmaCat @[to_additive] -instance bundledHom : BundledHom @MulHom := - ⟨@MulHom.toFun, @MulHom.id, @MulHom.comp, - by intros; apply @DFunLike.coe_injective, by aesop_cat, by simp⟩ +instance : CoeSort MagmaCat (Type u) := + ⟨MagmaCat.carrier⟩ --- Porting note: deriving failed for `HasForget`, --- "default handlers have not been implemented yet" --- https://github.com/leanprover-community/mathlib4/issues/5020 -deriving instance LargeCategory for MagmaCat -instance instHasForget : HasForget MagmaCat := BundledHom.hasForget MulHom +attribute [coe] AddMagmaCat.carrier MagmaCat.carrier -attribute [to_additive] instMagmaCatLargeCategory instHasForget +/-- Construct a bundled `MagmaCat` from the underlying type and typeclass. -/ +@[to_additive "Construct a bundled `AddMagmaCat` from the underlying type and typeclass."] +abbrev of (M : Type u) [Mul M] : MagmaCat := ⟨M⟩ -@[to_additive] -instance : CoeSort MagmaCat Type* where - coe X := X.α +end MagmaCat + +/-- The type of morphisms in `AddMagmaCat R`. -/ +@[ext] +structure AddMagmaCat.Hom (A B : AddMagmaCat.{u}) where + private mk :: + /-- The underlying `AddHom`. -/ + hom' : A →ₙ+ B + +/-- The type of morphisms in `MagmaCat R`. -/ +@[to_additive, ext] +structure MagmaCat.Hom (A B : MagmaCat.{u}) where + private mk :: + /-- The underlying `MulHom`. -/ + hom' : A →ₙ* B --- Porting note: Hinting to Lean that `forget R` and `R` are the same -unif_hint forget_obj_eq_coe (R : MagmaCat) where ⊢ - (forget MagmaCat).obj R ≟ R -unif_hint _root_.AddMagmaCat.forget_obj_eq_coe (R : AddMagmaCat) where ⊢ - (forget AddMagmaCat).obj R ≟ R +attribute [to_additive existing AddMagmaCat.Hom.mk] MagmaCat.Hom.mk + +namespace MagmaCat @[to_additive] -instance (X : MagmaCat) : Mul X := X.str +instance : Category MagmaCat.{u} where + Hom X Y := Hom X Y + id X := ⟨MulHom.id X⟩ + comp f g := ⟨g.hom'.comp f.hom'⟩ + +@[to_additive] +instance : ConcreteCategory MagmaCat (· →ₙ* ·) where + hom := Hom.hom' + ofHom := Hom.mk + +/-- Turn a morphism in `MagmaCat` back into a `MulHom`. -/ +@[to_additive "Turn a morphism in `AddMagmaCat` back into an `AddHom`."] +abbrev Hom.hom {X Y : MagmaCat.{u}} (f : Hom X Y) := + ConcreteCategory.hom (C := MagmaCat) f + +/-- Typecheck a `MulHom` as a morphism in `MagmaCat`. -/ +@[to_additive "Typecheck an `AddHom` as a morphism in `AddMagmaCat`. "] +abbrev ofHom {X Y : Type u} [Mul X] [Mul Y] (f : X →ₙ* Y) : of X ⟶ of Y := + ConcreteCategory.ofHom (C := MagmaCat) f + +variable {R} in +/-- Use the `ConcreteCategory.hom` projection for `@[simps]` lemmas. -/ +def Hom.Simps.hom (X Y : MagmaCat.{u}) (f : Hom X Y) := + f.hom + +initialize_simps_projections Hom (hom' → hom) +initialize_simps_projections AddMagmaCat.Hom (hom' → hom) + +/-! +The results below duplicate the `ConcreteCategory` simp lemmas, but we can keep them for `dsimp`. +-/ + +@[to_additive (attr := simp)] +lemma coe_id {X : MagmaCat} : (𝟙 X : X → X) = id := rfl + +@[to_additive (attr := simp)] +lemma coe_comp {X Y Z : MagmaCat} {f : X ⟶ Y} {g : Y ⟶ Z} : (f ≫ g : X → Z) = g ∘ f := rfl + +@[to_additive (attr := simp)] +lemma forget_map {X Y : MagmaCat} (f : X ⟶ Y) : + (forget MagmaCat).map f = f := rfl + +@[to_additive (attr := ext)] +lemma ext {X Y : MagmaCat} {f g : X ⟶ Y} (w : ∀ x : X, f x = g x) : f = g := + ConcreteCategory.hom_ext _ _ w @[to_additive] -instance instFunLike (X Y : MagmaCat) : FunLike (X ⟶ Y) X Y := - inferInstanceAs <| FunLike (X →ₙ* Y) X Y +-- This is not `simp` to avoid rewriting in types of terms. +theorem coe_of (M : Type u) [Mul M] : (MagmaCat.of M : Type u) = M := rfl + +@[to_additive (attr := simp)] +lemma hom_id {M : MagmaCat} : (𝟙 M : M ⟶ M).hom = MulHom.id M := rfl +/- Provided for rewriting. -/ @[to_additive] -instance instMulHomClass (X Y : MagmaCat) : MulHomClass (X ⟶ Y) X Y := - inferInstanceAs <| MulHomClass (X →ₙ* Y) X Y +lemma id_apply (M : MagmaCat) (x : M) : + (𝟙 M : M ⟶ M) x = x := by simp -/-- Construct a bundled `MagmaCat` from the underlying type and typeclass. -/ +@[to_additive (attr := simp)] +lemma hom_comp {M N T : MagmaCat} (f : M ⟶ N) (g : N ⟶ T) : + (f ≫ g).hom = g.hom.comp f.hom := rfl + +/- Provided for rewriting. -/ @[to_additive] -def of (M : Type u) [Mul M] : MagmaCat := - Bundled.of M +lemma comp_apply {M N T : MagmaCat} (f : M ⟶ N) (g : N ⟶ T) (x : M) : + (f ≫ g) x = g (f x) := by simp -/-- Construct a bundled `AddMagmaCat` from the underlying type and typeclass. -/ -add_decl_doc AddMagmaCat.of +@[to_additive (attr := ext)] +lemma hom_ext {M N : MagmaCat} {f g : M ⟶ N} (hf : f.hom = g.hom) : f = g := + Hom.ext hf @[to_additive (attr := simp)] -theorem coe_of (R : Type u) [Mul R] : (MagmaCat.of R : Type u) = R := - rfl +lemma hom_ofHom {M N : Type u} [Mul M] [Mul N] (f : M →ₙ* N) : + (ofHom f).hom = f := rfl @[to_additive (attr := simp)] -lemma mulEquiv_coe_eq {X Y : Type _} [Mul X] [Mul Y] (e : X ≃* Y) : - (@DFunLike.coe (MagmaCat.of X ⟶ MagmaCat.of Y) _ (fun _ => (forget MagmaCat).obj _) - HasForget.instFunLike (e : X →ₙ* Y) : X → Y) = ↑e := +lemma ofHom_hom {M N : MagmaCat} (f : M ⟶ N) : + ofHom (Hom.hom f) = f := rfl + +@[to_additive (attr := simp)] +lemma ofHom_id {M : Type u} [Mul M] : ofHom (MulHom.id M) = 𝟙 (of M) := rfl + +@[to_additive (attr := simp)] +lemma ofHom_comp {M N P : Type u} [Mul M] [Mul N] [Mul P] + (f : M →ₙ* N) (g : N →ₙ* P) : + ofHom (g.comp f) = ofHom f ≫ ofHom g := rfl -/-- Typecheck a `MulHom` as a morphism in `MagmaCat`. -/ @[to_additive] -def ofHom {X Y : Type u} [Mul X] [Mul Y] (f : X →ₙ* Y) : of X ⟶ of Y := f +lemma ofHom_apply {X Y : Type u} [Mul X] [Mul Y] (f : X →ₙ* Y) (x : X) : + (ofHom f) x = f x := rfl -/-- Typecheck an `AddHom` as a morphism in `AddMagmaCat`. -/ -add_decl_doc AddMagmaCat.ofHom +@[to_additive (attr := simp)] +lemma inv_hom_apply {M N : MagmaCat} (e : M ≅ N) (x : M) : e.inv (e.hom x) = x := by + rw [← comp_apply] + simp -@[to_additive] -theorem ofHom_apply {X Y : Type u} [Mul X] [Mul Y] (f : X →ₙ* Y) (x : X) : ofHom f x = f x := +@[to_additive (attr := simp)] +lemma hom_inv_apply {M N : MagmaCat} (e : M ≅ N) (s : N) : e.hom (e.inv s) = s := by + rw [← comp_apply] + simp + +@[to_additive (attr := simp)] +lemma mulEquiv_coe_eq {X Y : Type _} [Mul X] [Mul Y] (e : X ≃* Y) : + (ofHom (e : X →ₙ* Y)).hom = ↑e := rfl @[to_additive] @@ -110,79 +196,164 @@ instance : Inhabited MagmaCat := end MagmaCat +/-- The category of additive semigroups and semigroup morphisms. -/ +structure AddSemigrp : Type (u + 1) where + /-- The underlying type. -/ + (carrier : Type u) + [str : AddSemigroup carrier] + /-- The category of semigroups and semigroup morphisms. -/ @[to_additive] -def Semigrp : Type (u + 1) := - Bundled Semigroup +structure Semigrp : Type (u + 1) where + /-- The underlying type. -/ + (carrier : Type u) + [str : Semigroup carrier] -/-- The category of additive semigroups and semigroup morphisms. -/ -add_decl_doc AddSemigrp +attribute [instance] AddSemigrp.str Semigrp.str +attribute [to_additive existing] Semigrp.carrier Semigrp.str + +initialize_simps_projections AddSemigrp (carrier → coe, -str) +initialize_simps_projections Semigrp (carrier → coe, -str) namespace Semigrp @[to_additive] -instance : BundledHom.ParentProjection @Semigroup.toMul := ⟨⟩ +instance : CoeSort Semigrp (Type u) := + ⟨Semigrp.carrier⟩ + +attribute [coe] AddSemigrp.carrier Semigrp.carrier + +/-- Construct a bundled `Semigrp` from the underlying type and typeclass. -/ +@[to_additive "Construct a bundled `AddSemigrp` from the underlying type and typeclass."] +abbrev of (M : Type u) [Semigroup M] : Semigrp := ⟨M⟩ -deriving instance LargeCategory for Semigrp +end Semigrp --- Porting note: deriving failed for `HasForget`, --- "default handlers have not been implemented yet" --- https://github.com/leanprover-community/mathlib4/issues/5020 -instance instHasForget : HasForget Semigrp := - BundledHom.hasForget (fun _ _ => _) +/-- The type of morphisms in `AddSemigrp R`. -/ +@[ext] +structure AddSemigrp.Hom (A B : AddSemigrp.{u}) where + private mk :: + /-- The underlying `AddHom`. -/ + hom' : A →ₙ+ B -attribute [to_additive] instSemigrpLargeCategory Semigrp.instHasForget +/-- The type of morphisms in `Semigrp R`. -/ +@[to_additive, ext] +structure Semigrp.Hom (A B : Semigrp.{u}) where + private mk :: + /-- The underlying `MulHom`. -/ + hom' : A →ₙ* B -@[to_additive] -instance : CoeSort Semigrp Type* where - coe X := X.α +attribute [to_additive existing AddSemigrp.Hom.mk] Semigrp.Hom.mk --- Porting note: Hinting to Lean that `forget R` and `R` are the same -unif_hint forget_obj_eq_coe (R : Semigrp) where ⊢ - (forget Semigrp).obj R ≟ R -unif_hint _root_.AddSemigrp.forget_obj_eq_coe (R : AddSemigrp) where ⊢ - (forget AddSemigrp).obj R ≟ R +namespace Semigrp + +@[to_additive] +instance : Category Semigrp.{u} where + Hom X Y := Hom X Y + id X := ⟨MulHom.id X⟩ + comp f g := ⟨g.hom'.comp f.hom'⟩ @[to_additive] -instance (X : Semigrp) : Semigroup X := X.str +instance : ConcreteCategory Semigrp (· →ₙ* ·) where + hom := Hom.hom' + ofHom := Hom.mk + +/-- Turn a morphism in `Semigrp` back into a `MulHom`. -/ +@[to_additive "Turn a morphism in `AddSemigrp` back into an `AddHom`."] +abbrev Hom.hom {X Y : Semigrp.{u}} (f : Hom X Y) := + ConcreteCategory.hom (C := Semigrp) f + +/-- Typecheck a `MulHom` as a morphism in `Semigrp`. -/ +@[to_additive "Typecheck an `AddHom` as a morphism in `AddSemigrp`. "] +abbrev ofHom {X Y : Type u} [Semigroup X] [Semigroup Y] (f : X →ₙ* Y) : of X ⟶ of Y := + ConcreteCategory.ofHom (C := Semigrp) f + +variable {R} in +/-- Use the `ConcreteCategory.hom` projection for `@[simps]` lemmas. -/ +def Hom.Simps.hom (X Y : Semigrp.{u}) (f : Hom X Y) := + f.hom + +initialize_simps_projections Hom (hom' → hom) +initialize_simps_projections AddSemigrp.Hom (hom' → hom) + +/-! +The results below duplicate the `ConcreteCategory` simp lemmas, but we can keep them for `dsimp`. +-/ + +@[to_additive (attr := simp)] +lemma coe_id {X : Semigrp} : (𝟙 X : X → X) = id := rfl + +@[to_additive (attr := simp)] +lemma coe_comp {X Y Z : Semigrp} {f : X ⟶ Y} {g : Y ⟶ Z} : (f ≫ g : X → Z) = g ∘ f := rfl + +@[to_additive (attr := deprecated "Use hom_comp instead" (since := "2025-01-28"))] +lemma comp_def {X Y Z : Semigrp} {f : X ⟶ Y} {g : Y ⟶ Z} : (f ≫ g).hom = g.hom.comp f.hom := rfl + +@[simp] lemma forget_map {X Y : Semigrp} (f : X ⟶ Y) : (forget Semigrp).map f = (f : X → Y) := rfl + +@[to_additive (attr := ext)] +lemma ext {X Y : Semigrp} {f g : X ⟶ Y} (w : ∀ x : X, f x = g x) : f = g := + ConcreteCategory.hom_ext _ _ w @[to_additive] -instance instFunLike (X Y : Semigrp) : FunLike (X ⟶ Y) X Y := - inferInstanceAs <| FunLike (X →ₙ* Y) X Y +-- This is not `simp` to avoid rewriting in types of terms. +theorem coe_of (R : Type u) [Semigroup R] : ↑(Semigrp.of R) = R := + rfl + +@[to_additive (attr := simp)] +lemma hom_id {X : Semigrp} : (𝟙 X : X ⟶ X).hom = MulHom.id X := rfl +/- Provided for rewriting. -/ @[to_additive] -instance instMulHomClass (X Y : Semigrp) : MulHomClass (X ⟶ Y) X Y := - inferInstanceAs <| MulHomClass (X →ₙ* Y) X Y +lemma id_apply (X : Semigrp) (x : X) : + (𝟙 X : X ⟶ X) x = x := by simp -/-- Construct a bundled `Semigrp` from the underlying type and typeclass. -/ +@[to_additive (attr := simp)] +lemma hom_comp {X Y T : Semigrp} (f : X ⟶ Y) (g : Y ⟶ T) : + (f ≫ g).hom = g.hom.comp f.hom := rfl + +/- Provided for rewriting. -/ @[to_additive] -def of (M : Type u) [Semigroup M] : Semigrp := - Bundled.of M +lemma comp_apply {X Y T : Semigrp} (f : X ⟶ Y) (g : Y ⟶ T) (x : X) : + (f ≫ g) x = g (f x) := by simp -/-- Construct a bundled `AddSemigrp` from the underlying type and typeclass. -/ -add_decl_doc AddSemigrp.of +@[to_additive (attr := ext)] +lemma hom_ext {X Y : Semigrp} {f g : X ⟶ Y} (hf : f.hom = g.hom) : f = g := + Hom.ext hf @[to_additive (attr := simp)] -theorem coe_of (R : Type u) [Semigroup R] : (Semigrp.of R : Type u) = R := - rfl +lemma hom_ofHom {X Y : Type u} [Semigroup X] [Semigroup Y] (f : X →ₙ* Y) : (ofHom f).hom = f := rfl @[to_additive (attr := simp)] -lemma mulEquiv_coe_eq {X Y : Type _} [Semigroup X] [Semigroup Y] (e : X ≃* Y) : - (@DFunLike.coe (Semigrp.of X ⟶ Semigrp.of Y) _ (fun _ => (forget Semigrp).obj _) - HasForget.instFunLike (e : X →ₙ* Y) : X → Y) = ↑e := +lemma ofHom_hom {X Y : Semigrp} (f : X ⟶ Y) : + ofHom (Hom.hom f) = f := rfl + +@[to_additive (attr := simp)] +lemma ofHom_id {X : Type u} [Semigroup X] : ofHom (MulHom.id X) = 𝟙 (of X) := rfl + +@[to_additive (attr := simp)] +lemma ofHom_comp {X Y Z : Type u} [Semigroup X] [Semigroup Y] [Semigroup Z] + (f : X →ₙ* Y) (g : Y →ₙ* Z) : + ofHom (g.comp f) = ofHom f ≫ ofHom g := rfl -/-- Typecheck a `MulHom` as a morphism in `Semigrp`. -/ @[to_additive] -def ofHom {X Y : Type u} [Semigroup X] [Semigroup Y] (f : X →ₙ* Y) : of X ⟶ of Y := - f +lemma ofHom_apply {X Y : Type u} [Semigroup X] [Semigroup Y] (f : X →ₙ* Y) (x : X) : + (ofHom f) x = f x := rfl -/-- Typecheck an `AddHom` as a morphism in `AddSemigrp`. -/ -add_decl_doc AddSemigrp.ofHom +@[to_additive (attr := simp)] +lemma inv_hom_apply {X Y : Semigrp} (e : X ≅ Y) (x : X) : e.inv (e.hom x) = x := by + rw [← comp_apply] + simp -@[to_additive] -theorem ofHom_apply {X Y : Type u} [Semigroup X] [Semigroup Y] (f : X →ₙ* Y) (x : X) : - ofHom f x = f x := +@[to_additive (attr := simp)] +lemma hom_inv_apply {X Y : Semigrp} (e : X ≅ Y) (s : Y) : e.hom (e.inv s) = s := by + rw [← comp_apply] + simp + +@[to_additive (attr := simp)] +lemma mulEquiv_coe_eq {X Y : Type _} [Semigroup X] [Semigroup Y] (e : X ≃* Y) : + (ofHom (e : X →ₙ* Y)).hom = ↑e := rfl @[to_additive] @@ -190,8 +361,10 @@ instance : Inhabited Semigrp := ⟨Semigrp.of PEmpty⟩ @[to_additive] -instance hasForgetToMagmaCat : HasForget₂ Semigrp MagmaCat := - BundledHom.forget₂ _ _ +instance hasForgetToMagmaCat : HasForget₂ Semigrp MagmaCat where + forget₂ := + { obj R := MagmaCat.of R + map f := MagmaCat.ofHom f.hom } end Semigrp @@ -205,12 +378,8 @@ variable [Mul X] [Mul Y] @[to_additive (attr := simps) "Build an isomorphism in the category `AddMagmaCat` from an `AddEquiv` between `Add`s."] def MulEquiv.toMagmaCatIso (e : X ≃* Y) : MagmaCat.of X ≅ MagmaCat.of Y where - hom := e.toMulHom - inv := e.symm.toMulHom - hom_inv_id := by - ext - simp_rw [CategoryTheory.comp_apply, toMulHom_eq_coe, MagmaCat.mulEquiv_coe_eq, symm_apply_apply, - CategoryTheory.id_apply] + hom := MagmaCat.ofHom e.toMulHom + inv := MagmaCat.ofHom e.symm.toMulHom end @@ -223,8 +392,8 @@ variable [Semigroup X] [Semigroup Y] "Build an isomorphism in the category `AddSemigroup` from an `AddEquiv` between `AddSemigroup`s."] def MulEquiv.toSemigrpIso (e : X ≃* Y) : Semigrp.of X ≅ Semigrp.of Y where - hom := e.toMulHom - inv := e.symm.toMulHom + hom := Semigrp.ofHom e.toMulHom + inv := Semigrp.ofHom e.symm.toMulHom end @@ -234,13 +403,13 @@ namespace CategoryTheory.Iso @[to_additive "Build an `AddEquiv` from an isomorphism in the category `AddMagmaCat`."] def magmaCatIsoToMulEquiv {X Y : MagmaCat} (i : X ≅ Y) : X ≃* Y := - MulHom.toMulEquiv i.hom i.inv i.hom_inv_id i.inv_hom_id + MulHom.toMulEquiv i.hom.hom i.inv.hom (by ext; simp) (by ext; simp) /-- Build a `MulEquiv` from an isomorphism in the category `Semigroup`. -/ @[to_additive "Build an `AddEquiv` from an isomorphism in the category `AddSemigroup`."] def semigrpIsoToMulEquiv {X Y : Semigrp} (i : X ≅ Y) : X ≃* Y := - MulHom.toMulEquiv i.hom i.inv i.hom_inv_id i.inv_hom_id + MulHom.toMulEquiv i.hom.hom i.inv.hom (by ext; simp) (by ext; simp) end CategoryTheory.Iso @@ -268,14 +437,14 @@ def mulEquivIsoSemigrpIso {X Y : Type u} [Semigroup X] [Semigroup Y] : instance MagmaCat.forgetReflectsIsos : (forget MagmaCat.{u}).ReflectsIsomorphisms where reflects {X Y} f _ := by let i := asIso ((forget MagmaCat).map f) - let e : X ≃* Y := { f, i.toEquiv with } + let e : X ≃* Y := { f.hom, i.toEquiv with } exact e.toMagmaCatIso.isIso_hom @[to_additive] instance Semigrp.forgetReflectsIsos : (forget Semigrp.{u}).ReflectsIsomorphisms where reflects {X Y} f _ := by let i := asIso ((forget Semigrp).map f) - let e : X ≃* Y := { f, i.toEquiv with } + let e : X ≃* Y := { f.hom, i.toEquiv with } exact e.toSemigrpIso.isIso_hom -- Porting note: this was added in order to ensure that `forget₂ CommMonCat MonCat` @@ -283,7 +452,7 @@ instance Semigrp.forgetReflectsIsos : (forget Semigrp.{u}).ReflectsIsomorphisms -- we could have used `CategoryTheory.HasForget.ReflectsIso` alternatively @[to_additive] instance Semigrp.forget₂_full : (forget₂ Semigrp MagmaCat).Full where - map_surjective f := ⟨f, rfl⟩ + map_surjective f := ⟨ofHom f.hom, rfl⟩ /-! Once we've shown that the forgetful functors to type reflect isomorphisms, diff --git a/MathlibTest/CategoryTheory/ConcreteCategory/Semigrp.lean b/MathlibTest/CategoryTheory/ConcreteCategory/Semigrp.lean new file mode 100644 index 0000000000000..2707c28a35888 --- /dev/null +++ b/MathlibTest/CategoryTheory/ConcreteCategory/Semigrp.lean @@ -0,0 +1,47 @@ +import Mathlib.Algebra.Category.Semigrp.Basic + +universe v u + +open CategoryTheory Semigrp + +set_option maxHeartbeats 10000 +set_option synthInstance.maxHeartbeats 2000 + +/- We test if all the coercions and `map_mul` lemmas trigger correctly. -/ + +example (X : Type u) [Semigroup X] : ⇑(𝟙 (of X)) = id := by simp + +example {X Y : Type u} [Semigroup X] [Semigroup Y] (f : X →ₙ* Y) : + ⇑(ofHom f) = ⇑f := by simp + +example {X Y : Type u} [Semigroup X] [Semigroup Y] (f : X →ₙ* Y) + (x : X) : (ofHom f) x = f x := by simp + +example {X Y Z : Semigrp} (f : X ⟶ Y) (g : Y ⟶ Z) : ⇑(f ≫ g) = ⇑g ∘ ⇑f := by simp + +example {X Y Z : Type u} [Semigroup X] [Semigroup Y] [Semigroup Z] + (f : X →ₙ* Y) (g : Y →ₙ* Z) : + ⇑(ofHom f ≫ ofHom g) = g ∘ f := by simp + +example {X Y : Type u} [Semigroup X] [Semigroup Y] {Z : Semigrp} + (f : X →ₙ* Y) (g : of Y ⟶ Z) : + ⇑(ofHom f ≫ g) = g ∘ f := by simp + +example {X Y : Semigrp} {Z : Type u} [Semigroup Z] (f : X ⟶ Y) (g : Y ⟶ of Z) : + ⇑(f ≫ g) = g ∘ f := by simp + +example {Y Z : Semigrp} {X : Type u} [Semigroup X] (f : of X ⟶ Y) (g : Y ⟶ Z) : + ⇑(f ≫ g) = g ∘ f := by simp + +example {X Y Z : Semigrp} (f : X ⟶ Y) (g : Y ⟶ Z) (x : X) : (f ≫ g) x = g (f x) := by simp + +example {X Y : Semigrp} (e : X ≅ Y) (x : X) : e.inv (e.hom x) = x := by simp + +example {X Y : Semigrp} (e : X ≅ Y) (y : Y) : e.hom (e.inv y) = y := by simp + +example (X : Semigrp) : ⇑(𝟙 X) = id := by simp + +example {X : Type*} [Semigroup X] : ⇑(MulHom.id X) = id := by simp + +example {M N : Semigrp} (f : M ⟶ N) (x y : M) : f (x * y) = f x * f y := by + simp From 254905746828d4a2e11391886f9fa498a3f82ef9 Mon Sep 17 00:00:00 2001 From: Yoh Tanimoto Date: Mon, 3 Feb 2025 17:10:55 +0000 Subject: [PATCH 045/103] feat(Topology/ContinuousMap/CompactlySupported): turn a positive `Real`-linear functional into a `NNReal`-linear functional (#20257) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define `toNNRealLinear` that maps positive `Real`-linear functionals to `NNReal`-linear functionals and prove that it is injective. Co-authored-by: Yoh Tanimoto <57562556+yoh-tanimoto@users.noreply.github.com> Co-authored-by: Yaël Dillies --- .../ContinuousMap/CompactlySupported.lean | 52 +++++++++++++++++++ Mathlib/Topology/Instances/NNReal/Defs.lean | 3 ++ 2 files changed, 55 insertions(+) diff --git a/Mathlib/Topology/ContinuousMap/CompactlySupported.lean b/Mathlib/Topology/ContinuousMap/CompactlySupported.lean index 1708d589decf1..b7975118f44fa 100644 --- a/Mathlib/Topology/ContinuousMap/CompactlySupported.lean +++ b/Mathlib/Topology/ContinuousMap/CompactlySupported.lean @@ -641,6 +641,58 @@ noncomputable def nnrealPart (f : C_c(α, ℝ)) : C_c(α, ℝ≥0) where lemma nnrealPart_apply (f : C_c(α, ℝ)) (x : α) : f.nnrealPart x = Real.toNNReal (f x) := rfl +/-- The compactly supported continuous `ℝ≥0`-valued function as a compactly supported `ℝ`-valued +function. -/ +noncomputable def toReal (f : C_c(α, ℝ≥0)) : C_c(α, ℝ) := + f.compLeft ContinuousMap.coeNNRealReal + +@[simp] +lemma toReal_apply (f : C_c(α, ℝ≥0)) (x : α) : f.toReal x = f x := compLeft_apply rfl _ _ + +@[simp] lemma toReal_nonneg {f : C_c(α, ℝ≥0)} : 0 ≤ f.toReal := fun _ ↦ by simp + +@[simp] lemma toReal_add (f g : C_c(α, ℝ≥0)) : (f + g).toReal = f.toReal + g.toReal := by ext; simp +@[simp] lemma toReal_smul (r : ℝ≥0) (f : C_c(α, ℝ≥0)) : (r • f).toReal = r • f.toReal := by + ext; simp [NNReal.smul_def] + +lemma nnrealPart_sub_nnrealPart_neg (f : C_c(α, ℝ)) : + (nnrealPart f).toReal - (nnrealPart (-f)).toReal = f := by + ext x + simp + +/-- The compactly supported continuous `ℝ≥0`-valued function as a compactly supported `ℝ`-valued +function. -/ +noncomputable def toRealLinearMap : C_c(α, ℝ≥0) →ₗ[ℝ≥0] C_c(α, ℝ) where + toFun := toReal + map_add' f g := by ext x; simp + map_smul' a f := by ext x; simp [NNReal.smul_def] + +@[simp, norm_cast] +lemma coe_toRealLinearMap : (toRealLinearMap : C_c(α, ℝ≥0) → C_c(α, ℝ)) = toReal := rfl + +lemma toRealLinearMap_apply (f : C_c(α, ℝ≥0)) : toRealLinearMap f = f.toReal := rfl + +lemma toRealLinearMap_apply_apply (f : C_c(α, ℝ≥0)) (x : α) : + toRealLinearMap f x = (f x).toReal := by simp + +/-- For a positive linear functional `Λ : C_c(α, ℝ) → ℝ`, define a `ℝ≥0`-linear map. -/ +noncomputable def toNNRealLinear (Λ : C_c(α, ℝ) →ₗ[ℝ] ℝ) (hΛ : ∀ f, 0 ≤ f → 0 ≤ Λ f) : + C_c(α, ℝ≥0) →ₗ[ℝ≥0] ℝ≥0 where + toFun f := ⟨Λ (toRealLinearMap f), hΛ _ <| by simp⟩ + map_add' f g := by ext; simp + map_smul' a f := by ext; simp [NNReal.smul_def] + +@[simp] +lemma toNNRealLinear_apply (Λ : C_c(α, ℝ) →ₗ[ℝ] ℝ) (hΛ) (f : C_c(α, ℝ≥0)) : + toNNRealLinear Λ hΛ f = Λ (toReal f) := rfl + +@[simp] lemma toNNRealLinear_inj (Λ₁ Λ₂ : C_c(α, ℝ) →ₗ[ℝ] ℝ) (hΛ₁ hΛ₂) : + toNNRealLinear Λ₁ hΛ₁ = toNNRealLinear Λ₂ hΛ₂ ↔ Λ₁ = Λ₂ := by + simp only [LinearMap.ext_iff, NNReal.eq_iff, toNNRealLinear_apply] + refine ⟨fun h f ↦ ?_, fun h f ↦ by rw [LinearMap.ext h]⟩ + rw [← nnrealPart_sub_nnrealPart_neg f] + simp_rw [map_sub, h] + end CompactlySupportedContinuousMap end NonnegativePart diff --git a/Mathlib/Topology/Instances/NNReal/Defs.lean b/Mathlib/Topology/Instances/NNReal/Defs.lean index 4ab30b14fb4b0..5f3144de0b9ed 100644 --- a/Mathlib/Topology/Instances/NNReal/Defs.lean +++ b/Mathlib/Topology/Instances/NNReal/Defs.lean @@ -85,6 +85,9 @@ instance [TopologicalSpace α] [MulAction ℝ α] [ContinuousSMul ℝ α] : def _root_.ContinuousMap.coeNNRealReal : C(ℝ≥0, ℝ) := ⟨(↑), continuous_coe⟩ +@[simp] +lemma coeNNRealReal_zero : ContinuousMap.coeNNRealReal 0 = 0 := rfl + instance ContinuousMap.canLift {X : Type*} [TopologicalSpace X] : CanLift C(X, ℝ) C(X, ℝ≥0) ContinuousMap.coeNNRealReal.comp fun f => ∀ x, 0 ≤ f x where prf f hf := ⟨⟨fun x => ⟨f x, hf x⟩, f.2.subtype_mk _⟩, DFunLike.ext' rfl⟩ From d9a9fc0f2f3444ca45bef39e3a5bf33ba1469c94 Mon Sep 17 00:00:00 2001 From: Christian Merten <136261474+chrisflav@users.noreply.github.com> Date: Mon, 3 Feb 2025 17:32:51 +0000 Subject: [PATCH 046/103] docs(AlgebraicGeometry): fix local at the source vs. at the target (#21373) --- Mathlib/AlgebraicGeometry/Morphisms/Basic.lean | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean b/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean index 5b5e0f2bcc6d8..24705327fb315 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean @@ -195,10 +195,10 @@ namespace IsLocalAtSource attribute [instance] respectsIso /-- -`P` is local at the target if +`P` is local at the source if 1. `P` respects isomorphisms. -2. If `P` holds for `f : X ⟶ Y`, then `P` holds for `f ∣_ U` for any `U`. -3. If `P` holds for `f ∣_ U` for an open cover `U` of `Y`, then `P` holds for `f`. +2. If `P` holds for `f : X ⟶ Y`, then `P` holds for `U.ι ≫ f` for any `U`. +3. If `P` holds for `U.ι ≫ f` for an open cover `U` of `X`, then `P` holds for `f`. -/ protected lemma mk' {P : MorphismProperty Scheme} [P.RespectsIso] (restrict : ∀ {X Y : Scheme} (f : X ⟶ Y) (U : X.Opens), P f → P (U.ι ≫ f)) From 3685941cee510d07c956201c23a77c6a89b7857b Mon Sep 17 00:00:00 2001 From: Johan Commelin Date: Mon, 3 Feb 2025 17:43:24 +0000 Subject: [PATCH 047/103] chore: bump toolchain to v4.17.0-rc1 (#21377) Co-authored-by: Kim Morrison --- Mathlib/Algebra/Free.lean | 19 +--- Mathlib/Algebra/LinearRecurrence.lean | 3 +- Mathlib/Algebra/TrivSqZeroExt.lean | 6 +- Mathlib/Analysis/Analytic/Composition.lean | 2 +- .../Enumerative/Composition.lean | 2 +- Mathlib/Computability/Primrec.lean | 12 +- Mathlib/Computability/RegularExpressions.lean | 37 ++---- Mathlib/Data/Fin/Basic.lean | 4 - Mathlib/Data/FinEnum.lean | 4 +- Mathlib/Data/Finset/Sort.lean | 2 +- Mathlib/Data/List/Basic.lean | 105 ++++++++++-------- Mathlib/Data/List/Count.lean | 1 + Mathlib/Data/List/Enum.lean | 79 +++++-------- Mathlib/Data/List/FinRange.lean | 8 +- Mathlib/Data/List/Forall2.lean | 3 +- Mathlib/Data/List/Indexes.lean | 9 +- Mathlib/Data/List/Intervals.lean | 2 +- Mathlib/Data/List/MinMax.lean | 16 +-- Mathlib/Data/List/Nodup.lean | 20 ++-- Mathlib/Data/List/NodupEquivFin.lean | 10 +- Mathlib/Data/List/OfFn.lean | 9 +- Mathlib/Data/List/ProdSigma.lean | 1 - Mathlib/Data/List/Sigma.lean | 5 +- Mathlib/Data/List/Sublists.lean | 4 +- Mathlib/Data/List/ToFinsupp.lean | 9 +- Mathlib/Data/Nat/Defs.lean | 6 +- Mathlib/Data/Nat/Digits.lean | 16 +-- Mathlib/Data/Option/Basic.lean | 10 -- Mathlib/Data/Sigma/Basic.lean | 11 +- Mathlib/Data/ULift.lean | 8 +- Mathlib/GroupTheory/Perm/Cycle/Basic.lean | 6 +- Mathlib/Lean/Meta/KAbstractPositions.lean | 2 +- Mathlib/LinearAlgebra/Multilinear/Basic.lean | 8 +- Mathlib/Logic/Equiv/List.lean | 2 +- .../LegendreSymbol/JacobiSymbol.lean | 3 +- Mathlib/NumberTheory/Ostrowski.lean | 23 ++-- Mathlib/Order/RelSeries.lean | 2 +- Mathlib/Tactic/DeriveTraversable.lean | 2 +- .../Linarith/Oracle/FourierMotzkin.lean | 2 +- .../Linarith/Oracle/SimplexAlgorithm.lean | 3 +- .../Oracle/SimplexAlgorithm/Datatypes.lean | 8 +- Mathlib/Tactic/Linarith/Verification.lean | 4 +- Mathlib/Tactic/Linter/TextBased.lean | 7 +- Mathlib/Tactic/Linter/UnusedTactic.lean | 1 + Mathlib/Tactic/MinImports.lean | 4 +- Mathlib/Tactic/MkIffOfInductiveProp.lean | 2 +- Mathlib/Tactic/MoveAdd.lean | 4 +- Mathlib/Tactic/Widget/StringDiagram.lean | 6 +- MathlibTest/fun_prop_dev.lean | 2 +- lake-manifest.json | 12 +- lean-toolchain | 2 +- scripts/noshake.json | 3 +- 52 files changed, 238 insertions(+), 293 deletions(-) diff --git a/Mathlib/Algebra/Free.lean b/Mathlib/Algebra/Free.lean index 0fbfaa9678903..50106b3d672c7 100644 --- a/Mathlib/Algebra/Free.lean +++ b/Mathlib/Algebra/Free.lean @@ -61,9 +61,6 @@ instance [Inhabited α] : Inhabited (FreeMagma α) := ⟨of default⟩ @[to_additive] instance : Mul (FreeMagma α) := ⟨FreeMagma.mul⟩ --- Porting note: invalid attribute 'match_pattern', declaration is in an imported module --- attribute [match_pattern] Mul.mul - @[to_additive (attr := simp)] theorem mul_eq (x y : FreeMagma α) : mul x y = x * y := rfl @@ -80,12 +77,10 @@ theorem hom_ext {β : Type v} [Mul β] {f g : FreeMagma α →ₙ* β} (h : f end FreeMagma -#adaptation_note /-- nightly-2024-02-25 -we need to write `mul x y` in the second pattern, instead of `x * y`. --/ /-- Lifts a function `α → β` to a magma homomorphism `FreeMagma α → β` given a magma `β`. -/ def FreeMagma.liftAux {α : Type u} {β : Type v} [Mul β] (f : α → β) : FreeMagma α → β | FreeMagma.of x => f x - | mul x y => liftAux f x * liftAux f y + | x * y => liftAux f x * liftAux f y /-- Lifts a function `α → β` to an additive magma homomorphism `FreeAddMagma α → β` given an additive magma `β`. -/ @@ -185,13 +180,11 @@ end Category end FreeMagma -#adaptation_note /-- nightly-2024-02-25 -we need to write `mul x y` in the second pattern, instead of `x * y`. -/ /-- `FreeMagma` is traversable. -/ protected def FreeMagma.traverse {m : Type u → Type u} [Applicative m] {α β : Type u} (F : α → m β) : FreeMagma α → m (FreeMagma β) | FreeMagma.of x => FreeMagma.of <$> F x - | mul x y => (· * ·) <$> x.traverse F <*> y.traverse F + | x * y => (· * ·) <$> x.traverse F <*> y.traverse F /-- `FreeAddMagma` is traversable. -/ protected def FreeAddMagma.traverse {m : Type u → Type u} [Applicative m] {α β : Type u} @@ -262,12 +255,10 @@ end Category end FreeMagma -#adaptation_note /-- nightly-2024-02-25 -we need to write `mul x y` in the second pattern, instead of `x * y`. -/ /-- Representation of an element of a free magma. -/ protected def FreeMagma.repr {α : Type u} [Repr α] : FreeMagma α → Lean.Format | FreeMagma.of x => repr x - | mul x y => "( " ++ x.repr ++ " * " ++ y.repr ++ " )" + | x * y => "( " ++ x.repr ++ " * " ++ y.repr ++ " )" /-- Representation of an element of a free additive magma. -/ protected def FreeAddMagma.repr {α : Type u} [Repr α] : FreeAddMagma α → Lean.Format @@ -279,12 +270,10 @@ attribute [to_additive existing] FreeMagma.repr @[to_additive] instance {α : Type u} [Repr α] : Repr (FreeMagma α) := ⟨fun o _ => FreeMagma.repr o⟩ -#adaptation_note /-- nightly-2024-02-25 -we need to write `mul x y` in the second pattern, instead of `x * y`. -/ /-- Length of an element of a free magma. -/ def FreeMagma.length {α : Type u} : FreeMagma α → ℕ | FreeMagma.of _x => 1 - | mul x y => x.length + y.length + | x * y => x.length + y.length /-- Length of an element of a free additive magma. -/ def FreeAddMagma.length {α : Type u} : FreeAddMagma α → ℕ diff --git a/Mathlib/Algebra/LinearRecurrence.lean b/Mathlib/Algebra/LinearRecurrence.lean index b9fe57a324105..cec0da0476a21 100644 --- a/Mathlib/Algebra/LinearRecurrence.lean +++ b/Mathlib/Algebra/LinearRecurrence.lean @@ -92,7 +92,8 @@ theorem eq_mk_of_is_sol_of_eq_init {u : ℕ → α} {init : Fin E.order → α} rw [mkSol] split_ifs with h' · exact mod_cast heq ⟨n, h'⟩ - · rw [← tsub_add_cancel_of_le (le_of_not_lt h'), h (n - E.order)] + · dsimp only + rw [← tsub_add_cancel_of_le (le_of_not_lt h'), h (n - E.order)] congr with k have : n - E.order + k < n := by omega rw [eq_mk_of_is_sol_of_eq_init h heq (n - E.order + k)] diff --git a/Mathlib/Algebra/TrivSqZeroExt.lean b/Mathlib/Algebra/TrivSqZeroExt.lean index 310e881988587..cf3a609ed5730 100644 --- a/Mathlib/Algebra/TrivSqZeroExt.lean +++ b/Mathlib/Algebra/TrivSqZeroExt.lean @@ -640,12 +640,12 @@ $r_0\cdots r_{i-1}m_ir_{i+1}\cdots r_n$. -/ theorem snd_list_prod [Semiring R] [AddCommMonoid M] [Module R M] [Module Rᵐᵒᵖ M] [SMulCommClass R Rᵐᵒᵖ M] (l : List (tsze R M)) : l.prod.snd = - (l.enum.map fun x : ℕ × tsze R M => - ((l.map fst).take x.1).prod •> x.snd.snd <• ((l.map fst).drop x.1.succ).prod).sum := by + (l.zipIdx.map fun x : tsze R M × ℕ => + ((l.map fst).take x.2).prod •> x.fst.snd <• ((l.map fst).drop x.2.succ).prod).sum := by induction l with | nil => simp | cons x xs ih => - rw [List.enum_cons, ← List.map_fst_add_enum_eq_enumFrom] + rw [List.zipIdx_cons'] simp_rw [List.map_cons, List.map_map, Function.comp_def, Prod.map_snd, Prod.map_fst, id, List.take_zero, List.take_succ_cons, List.prod_nil, List.prod_cons, snd_mul, one_smul, List.drop, mul_smul, List.sum_cons, fst_list_prod, ih, List.smul_sum, List.map_map, diff --git a/Mathlib/Analysis/Analytic/Composition.lean b/Mathlib/Analysis/Analytic/Composition.lean index dea028ad9f747..ba83a3ede5f6d 100644 --- a/Mathlib/Analysis/Analytic/Composition.lean +++ b/Mathlib/Analysis/Analytic/Composition.lean @@ -550,7 +550,7 @@ def compChangeOfVariables (m M N : ℕ) (i : Σ n, Fin n → ℕ) (hi : i ∈ co rw [mem_compPartialSumSource_iff] at hi refine ⟨∑ j, f j, ofFn fun a => f a, fun hi' => ?_, by simp [sum_ofFn]⟩ rename_i i - obtain ⟨j, rfl⟩ : ∃ j : Fin n, f j = i := by rwa [mem_ofFn, Set.mem_range] at hi' + obtain ⟨j, rfl⟩ : ∃ j : Fin n, f j = i := by rwa [mem_ofFn', Set.mem_range] at hi' exact (hi.2 j).1 @[simp] diff --git a/Mathlib/Combinatorics/Enumerative/Composition.lean b/Mathlib/Combinatorics/Enumerative/Composition.lean index fcf38ce535510..1583aa24ea055 100644 --- a/Mathlib/Combinatorics/Enumerative/Composition.lean +++ b/Mathlib/Combinatorics/Enumerative/Composition.lean @@ -478,7 +478,7 @@ theorem eq_ones_iff_length {c : Composition n} : c = ones n ↔ c.length = n := _ < ∑ i : Fin c.length, c.blocksFun i := by { obtain ⟨i, hi, i_blocks⟩ : ∃ i ∈ c.blocks, 1 < i := ne_ones_iff.1 H - rw [← ofFn_blocksFun, mem_ofFn c.blocksFun, Set.mem_range] at hi + rw [← ofFn_blocksFun, mem_ofFn' c.blocksFun, Set.mem_range] at hi obtain ⟨j : Fin c.length, hj : c.blocksFun j = i⟩ := hi rw [← hj] at i_blocks exact Finset.sum_lt_sum (fun i _ => one_le_blocksFun c i) ⟨j, Finset.mem_univ _, i_blocks⟩ diff --git a/Mathlib/Computability/Primrec.lean b/Mathlib/Computability/Primrec.lean index a4c9369593bb2..5c47e48f3f4da 100644 --- a/Mathlib/Computability/Primrec.lean +++ b/Mathlib/Computability/Primrec.lean @@ -619,15 +619,17 @@ theorem list_findIdx₁ {p : α → β → Bool} (hp : Primrec₂ p) : | a :: l => (cond (hp.comp .id (const a)) (const 0) (succ.comp (list_findIdx₁ hp l))).of_eq fun n => by simp [List.findIdx_cons] -theorem list_indexOf₁ [DecidableEq α] (l : List α) : Primrec fun a => l.indexOf a := +theorem list_idxOf₁ [DecidableEq α] (l : List α) : Primrec fun a => l.idxOf a := list_findIdx₁ (.swap .beq) l +@[deprecated (since := "2025-01-30")] alias list_indexOf₁ := list_idxOf₁ + theorem dom_fintype [Finite α] (f : α → σ) : Primrec f := let ⟨l, _, m⟩ := Finite.exists_univ_list α option_some_iff.1 <| by haveI := decidableEqOfEncodable α - refine ((list_get?₁ (l.map f)).comp (list_indexOf₁ l)).of_eq fun a => ?_ - rw [List.get?_eq_getElem?, List.getElem?_map, List.getElem?_indexOf (m a), Option.map_some'] + refine ((list_get?₁ (l.map f)).comp (list_idxOf₁ l)).of_eq fun a => ?_ + rw [List.get?_eq_getElem?, List.getElem?_map, List.getElem?_idxOf (m a), Option.map_some'] -- Porting note: These are new lemmas -- I added it because it actually simplified the proofs @@ -952,9 +954,11 @@ theorem list_findIdx {f : α → List β} {p : α → β → Bool} to₂ <| cond (hp.comp fst <| fst.comp snd) (const 0) (succ.comp <| snd.comp snd)).of_eq fun a => by dsimp; induction f a <;> simp [List.findIdx_cons, *] -theorem list_indexOf [DecidableEq α] : Primrec₂ (@List.indexOf α _) := +theorem list_idxOf [DecidableEq α] : Primrec₂ (@List.idxOf α _) := to₂ <| list_findIdx snd <| Primrec.beq.comp₂ snd.to₂ (fst.comp fst).to₂ +@[deprecated (since := "2025-01-30")] alias list_indexOf := list_idxOf + theorem nat_strong_rec (f : α → ℕ → σ) {g : α → List σ → Option σ} (hg : Primrec₂ g) (H : ∀ a n, g a ((List.range n).map (f a)) = some (f a n)) : Primrec₂ f := suffices Primrec₂ fun a n => (List.range n).map (f a) from diff --git a/Mathlib/Computability/RegularExpressions.lean b/Mathlib/Computability/RegularExpressions.lean index a1922965cec30..ebc30c4312724 100644 --- a/Mathlib/Computability/RegularExpressions.lean +++ b/Mathlib/Computability/RegularExpressions.lean @@ -17,11 +17,6 @@ computer science such as the POSIX standard. * Show that this regular expressions and DFA/NFA's are equivalent. -/ --- Porting note: this has been commented out --- * `attribute [pattern] has_mul.mul` has been added into this file, it could be moved. - - - open List Set open Computability @@ -72,9 +67,6 @@ instance : Zero (RegularExpression α) := instance : Pow (RegularExpression α) ℕ := ⟨fun n r => npowRec r n⟩ --- Porting note: declaration in an imported module --- attribute [match_pattern] Mul.mul - @[simp] theorem zero_def : (zero : RegularExpression α) = 0 := rfl @@ -92,8 +84,6 @@ theorem comp_def (P Q : RegularExpression α) : comp P Q = P * Q := rfl -- This was renamed to `matches'` during the port of Lean 4 as `matches` is a reserved word. -#adaptation_note /-- nightly-2024-02-25 - we need to write `comp x y` in the pattern `comp P Q`, instead of `x * y`. -/ /-- `matches' P` provides a language which contains all strings that `P` matches -/ -- Porting note: was '@[simp] but removed based on -- https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/simpNF.20issues.20in.20Computability.2ERegularExpressions.20!4.232306/near/328355362 @@ -102,7 +92,7 @@ def matches' : RegularExpression α → Language α | 1 => 1 | char a => {[a]} | P + Q => P.matches' + Q.matches' - | comp P Q => P.matches' * Q.matches' + | P * Q => P.matches' * Q.matches' | star P => P.matches'∗ @[simp] @@ -136,22 +126,18 @@ theorem matches'_pow (P : RegularExpression α) : ∀ n : ℕ, (P ^ n).matches' theorem matches'_star (P : RegularExpression α) : P.star.matches' = P.matches'∗ := rfl -#adaptation_note /-- nightly-2024-02-25 - we need to write `comp x y` in the pattern `comp P Q`, instead of `x * y`. -/ /-- `matchEpsilon P` is true if and only if `P` matches the empty string -/ def matchEpsilon : RegularExpression α → Bool | 0 => false | 1 => true | char _ => false | P + Q => P.matchEpsilon || Q.matchEpsilon - | comp P Q => P.matchEpsilon && Q.matchEpsilon + | P * Q => P.matchEpsilon && Q.matchEpsilon | star _P => true section DecidableEq variable [DecidableEq α] -#adaptation_note /-- nightly-2024-02-25 - we need to write `comp x y` in the pattern `comp P Q`, instead of `x * y`. -/ /-- `P.deriv a` matches `x` if `P` matches `a :: x`, the Brzozowski derivative of `P` with respect to `a` -/ def deriv : RegularExpression α → α → RegularExpression α @@ -159,7 +145,7 @@ def deriv : RegularExpression α → α → RegularExpression α | 1, _ => 0 | char a₁, a₂ => if a₁ = a₂ then 1 else 0 | P + Q, a => deriv P a + deriv Q a - | comp P Q, a => if P.matchEpsilon then deriv P a * Q + deriv Q a else deriv P a * Q + | P * Q, a => if P.matchEpsilon then deriv P a * Q + deriv Q a else deriv P a * Q | star P, a => deriv P a * star P @[simp] @@ -343,8 +329,6 @@ instance (P : RegularExpression α) : DecidablePred (· ∈ P.matches') := fun _ end DecidableEq -#adaptation_note /-- nightly-2024-02-25 - we need to write `comp x y` in the pattern `comp P Q`, instead of `x * y`. -/ /-- Map the alphabet of a regular expression. -/ @[simp] def map (f : α → β) : RegularExpression α → RegularExpression β @@ -352,7 +336,7 @@ def map (f : α → β) : RegularExpression α → RegularExpression β | 1 => 1 | char a => char (f a) | R + S => map f R + map f S - | comp R S => map f R * map f S + | R * S => map f R * map f S | star R => star (map f R) @[simp] @@ -361,31 +345,24 @@ protected theorem map_pow (f : α → β) (P : RegularExpression α) : | 0 => by unfold map; rfl | n + 1 => (congr_arg (· * map f P) (RegularExpression.map_pow f P n) :) -#adaptation_note /-- nightly-2024-02-25 - we need to write `comp x y` in the pattern `comp P Q`, instead of `x * y`. -/ @[simp] theorem map_id : ∀ P : RegularExpression α, P.map id = P | 0 => rfl | 1 => rfl | char _ => rfl | R + S => by simp_rw [map, map_id] - | comp R S => by simp_rw [map, map_id]; rfl + | R * S => by simp_rw [map, map_id] | star R => by simp_rw [map, map_id] -#adaptation_note /-- nightly-2024-02-25 - we need to write `comp x y` in the pattern `comp P Q`, instead of `x * y`. -/ @[simp] theorem map_map (g : β → γ) (f : α → β) : ∀ P : RegularExpression α, (P.map f).map g = P.map (g ∘ f) | 0 => rfl | 1 => rfl | char _ => rfl | R + S => by simp only [map, Function.comp_apply, map_map] - | comp R S => by simp only [map, Function.comp_apply, map_map] + | R * S => by simp only [map, Function.comp_apply, map_map] | star R => by simp only [map, Function.comp_apply, map_map] -#adaptation_note /-- nightly-2024-02-25 - we need to write `comp x y` in the pattern `comp R S`, - instead of `x * y` (and the `erw` was just `rw`). -/ /-- The language of the map is the map of the language. -/ @[simp] theorem matches'_map (f : α → β) : @@ -396,7 +373,7 @@ theorem matches'_map (f : α → β) : rw [eq_comm] exact image_singleton | R + S => by simp only [matches'_map, map, matches'_add, map_add] - | comp R S => by simp [matches'_map] + | R * S => by simp [matches'_map] | star R => by simp [matches'_map] end RegularExpression diff --git a/Mathlib/Data/Fin/Basic.lean b/Mathlib/Data/Fin/Basic.lean index 41d00bd289761..016b08669bf2b 100644 --- a/Mathlib/Data/Fin/Basic.lean +++ b/Mathlib/Data/Fin/Basic.lean @@ -596,10 +596,6 @@ lemma _root_.finCongr_symm_apply_coe (h : m = n) (k : Fin n) : ((finCongr h).sym a generic theorem about `cast`. -/ lemma _root_.finCongr_eq_equivCast (h : n = m) : finCongr h = .cast (h ▸ rfl) := by subst h; simp -@[simp] -theorem cast_zero {n' : ℕ} [NeZero n] {h : n = n'} : (0 : Fin n).cast h = - by { haveI : NeZero n' := by {rw [← h]; infer_instance}; exact 0} := rfl - /-- While in many cases `Fin.cast` is better than `Equiv.cast`/`cast`, sometimes we want to apply a generic theorem about `cast`. -/ theorem cast_eq_cast (h : n = m) : (Fin.cast h : Fin n → Fin m) = _root_.cast (h ▸ rfl) := by diff --git a/Mathlib/Data/FinEnum.lean b/Mathlib/Data/FinEnum.lean index d928b5d459a79..3743426362fb7 100644 --- a/Mathlib/Data/FinEnum.lean +++ b/Mathlib/Data/FinEnum.lean @@ -46,8 +46,8 @@ def ofNodupList [DecidableEq α] (xs : List α) (h : ∀ x : α, x ∈ xs) (h' : FinEnum α where card := xs.length equiv := - ⟨fun x => ⟨xs.indexOf x, by rw [List.indexOf_lt_length_iff]; apply h⟩, xs.get, fun x => by simp, - fun i => by ext; simp [List.indexOf_getElem h']⟩ + ⟨fun x => ⟨xs.idxOf x, by rw [List.idxOf_lt_length_iff]; apply h⟩, xs.get, fun x => by simp, + fun i => by ext; simp [List.idxOf_getElem h']⟩ /-- create a `FinEnum` instance from an exhaustive list; duplicates are removed -/ def ofList [DecidableEq α] (xs : List α) (h : ∀ x : α, x ∈ xs) : FinEnum α := diff --git a/Mathlib/Data/Finset/Sort.lean b/Mathlib/Data/Finset/Sort.lean index d4354b5039a5b..4b49c0b4443dd 100644 --- a/Mathlib/Data/Finset/Sort.lean +++ b/Mathlib/Data/Finset/Sort.lean @@ -170,7 +170,7 @@ theorem coe_orderIsoOfFin_apply (s : Finset α) {k : ℕ} (h : s.card = k) (i : rfl theorem orderIsoOfFin_symm_apply (s : Finset α) {k : ℕ} (h : s.card = k) (x : s) : - ↑((s.orderIsoOfFin h).symm x) = (s.sort (· ≤ ·)).indexOf ↑x := + ↑((s.orderIsoOfFin h).symm x) = (s.sort (· ≤ ·)).idxOf ↑x := rfl theorem orderEmbOfFin_apply (s : Finset α) {k : ℕ} (h : s.card = k) (i : Fin k) : diff --git a/Mathlib/Data/List/Basic.lean b/Mathlib/Data/List/Basic.lean index 569361c5a5b42..55bb99dc01ffa 100644 --- a/Mathlib/Data/List/Basic.lean +++ b/Mathlib/Data/List/Basic.lean @@ -29,10 +29,6 @@ open Nat hiding one_pos namespace List --- Renamed in lean core; to be removed with the version bump. -alias replicate_append_replicate := append_replicate_replicate -alias append_eq_nil_iff := append_eq_nil - universe u v w variable {ι : Type*} {α : Type u} {β : Type v} {γ : Type w} {l₁ l₂ : List α} @@ -662,24 +658,24 @@ variable [DecidableEq α] The ported versions of the earlier proofs are given in comments. -/ --- indexOf_cons_eq _ rfl -@[simp] -theorem indexOf_cons_self {a : α} {l : List α} : indexOf a (a :: l) = 0 := by - rw [indexOf, findIdx_cons, beq_self_eq_true, cond] -- fun e => if_pos e -theorem indexOf_cons_eq {a b : α} (l : List α) : b = a → indexOf a (b :: l) = 0 - | e => by rw [← e]; exact indexOf_cons_self +theorem idxOf_cons_eq {a b : α} (l : List α) : b = a → idxOf a (b :: l) = 0 + | e => by rw [← e]; exact idxOf_cons_self + +@[deprecated (since := "2025-01-30")] alias indexOf_cons_eq := idxOf_cons_eq -- fun n => if_neg n @[simp] -theorem indexOf_cons_ne {a b : α} (l : List α) : b ≠ a → indexOf a (b :: l) = succ (indexOf a l) - | h => by simp only [indexOf, findIdx_cons, Bool.cond_eq_ite, beq_iff_eq, h, ite_false] +theorem idxOf_cons_ne {a b : α} (l : List α) : b ≠ a → idxOf a (b :: l) = succ (idxOf a l) + | h => by simp only [idxOf, findIdx_cons, Bool.cond_eq_ite, beq_iff_eq, h, ite_false] + +@[deprecated (since := "2025-01-30")] alias indexOf_cons_ne := idxOf_cons_ne -theorem indexOf_eq_length_iff {a : α} {l : List α} : indexOf a l = length l ↔ a ∉ l := by +theorem idxOf_eq_length_iff {a : α} {l : List α} : idxOf a l = length l ↔ a ∉ l := by induction' l with b l ih · exact iff_of_true rfl (not_mem_nil _) - simp only [length, mem_cons, indexOf_cons, eq_comm] + simp only [length, mem_cons, idxOf_cons, eq_comm] rw [cond_eq_if] split_ifs with h <;> simp at h · exact iff_of_false (by rintro ⟨⟩) fun H => H <| Or.inl h.symm @@ -687,42 +683,47 @@ theorem indexOf_eq_length_iff {a : α} {l : List α} : indexOf a l = length l rw [← ih] exact succ_inj' -@[deprecated (since := "2025-01-28")] -alias indexOf_eq_length := indexOf_eq_length_iff - @[simp] -theorem indexOf_of_not_mem {l : List α} {a : α} : a ∉ l → indexOf a l = length l := - indexOf_eq_length_iff.2 +theorem idxOf_of_not_mem {l : List α} {a : α} : a ∉ l → idxOf a l = length l := + idxOf_eq_length_iff.2 + +@[deprecated (since := "2025-01-30")] alias indexOf_of_not_mem := idxOf_of_not_mem -theorem indexOf_le_length {a : α} {l : List α} : indexOf a l ≤ length l := by +theorem idxOf_le_length {a : α} {l : List α} : idxOf a l ≤ length l := by induction' l with b l ih; · rfl - simp only [length, indexOf_cons, cond_eq_if, beq_iff_eq] + simp only [length, idxOf_cons, cond_eq_if, beq_iff_eq] by_cases h : b = a · rw [if_pos h]; exact Nat.zero_le _ · rw [if_neg h]; exact succ_le_succ ih -theorem indexOf_lt_length_iff {a} {l : List α} : indexOf a l < length l ↔ a ∈ l := - ⟨fun h => Decidable.byContradiction fun al => Nat.ne_of_lt h <| indexOf_eq_length_iff.2 al, - fun al => (lt_of_le_of_ne indexOf_le_length) fun h => indexOf_eq_length_iff.1 h al⟩ +@[deprecated (since := "2025-01-30")] alias indexOf_le_length := idxOf_le_length + +theorem idxOf_lt_length_iff {a} {l : List α} : idxOf a l < length l ↔ a ∈ l := + ⟨fun h => Decidable.byContradiction fun al => Nat.ne_of_lt h <| idxOf_eq_length_iff.2 al, + fun al => (lt_of_le_of_ne idxOf_le_length) fun h => idxOf_eq_length_iff.1 h al⟩ -@[deprecated (since := "2025-01-22")] alias indexOf_lt_length := indexOf_lt_length_iff +@[deprecated (since := "2025-01-30")] alias indexOf_lt_length_iff := idxOf_lt_length_iff -theorem indexOf_append_of_mem {a : α} (h : a ∈ l₁) : indexOf a (l₁ ++ l₂) = indexOf a l₁ := by +theorem idxOf_append_of_mem {a : α} (h : a ∈ l₁) : idxOf a (l₁ ++ l₂) = idxOf a l₁ := by induction' l₁ with d₁ t₁ ih · exfalso exact not_mem_nil a h rw [List.cons_append] by_cases hh : d₁ = a - · iterate 2 rw [indexOf_cons_eq _ hh] - rw [indexOf_cons_ne _ hh, indexOf_cons_ne _ hh, ih (mem_of_ne_of_mem (Ne.symm hh) h)] + · iterate 2 rw [idxOf_cons_eq _ hh] + rw [idxOf_cons_ne _ hh, idxOf_cons_ne _ hh, ih (mem_of_ne_of_mem (Ne.symm hh) h)] -theorem indexOf_append_of_not_mem {a : α} (h : a ∉ l₁) : - indexOf a (l₁ ++ l₂) = l₁.length + indexOf a l₂ := by +@[deprecated (since := "2025-01-30")] alias indexOf_append_of_mem := idxOf_append_of_mem + +theorem idxOf_append_of_not_mem {a : α} (h : a ∉ l₁) : + idxOf a (l₁ ++ l₂) = l₁.length + idxOf a l₂ := by induction' l₁ with d₁ t₁ ih · rw [List.nil_append, List.length, Nat.zero_add] - rw [List.cons_append, indexOf_cons_ne _ (ne_of_not_mem_cons h).symm, List.length, + rw [List.cons_append, idxOf_cons_ne _ (ne_of_not_mem_cons h).symm, List.length, ih (not_mem_of_not_mem_cons h), Nat.succ_add] +@[deprecated (since := "2025-01-30")] alias indexOf_append_of_not_mem := idxOf_append_of_not_mem + end IndexOf /-! ### nth element -/ @@ -775,35 +776,45 @@ theorem ext_getElem! [Inhabited α] (hl : length l₁ = length l₂) (h : ∀ n ext_getElem hl fun n h₁ h₂ ↦ by simpa only [← getElem!_pos] using h n @[simp] -theorem getElem_indexOf [DecidableEq α] {a : α} : ∀ {l : List α} (h : indexOf a l < l.length), - l[indexOf a l] = a +theorem getElem_idxOf [DecidableEq α] {a : α} : ∀ {l : List α} (h : idxOf a l < l.length), + l[idxOf a l] = a | b :: l, h => by by_cases h' : b = a <;> - simp [h', if_pos, if_false, getElem_indexOf] + simp [h', if_pos, if_false, getElem_idxOf] --- This is incorrectly named and should be `get_indexOf`; +@[deprecated (since := "2025-01-30")] alias getElem_indexOf := getElem_idxOf + +-- This is incorrectly named and should be `get_idxOf`; -- this already exists, so will require a deprecation dance. -theorem indexOf_get [DecidableEq α] {a : α} {l : List α} (h) : get l ⟨indexOf a l, h⟩ = a := by +theorem idxOf_get [DecidableEq α] {a : α} {l : List α} (h) : get l ⟨idxOf a l, h⟩ = a := by simp +@[deprecated (since := "2025-01-30")] alias indexOf_get := idxOf_get + @[simp] -theorem getElem?_indexOf [DecidableEq α] {a : α} {l : List α} (h : a ∈ l) : - l[indexOf a l]? = some a := by - rw [getElem?_eq_getElem, getElem_indexOf (indexOf_lt_length_iff.2 h)] +theorem getElem?_idxOf [DecidableEq α] {a : α} {l : List α} (h : a ∈ l) : + l[idxOf a l]? = some a := by + rw [getElem?_eq_getElem, getElem_idxOf (idxOf_lt_length_iff.2 h)] --- This is incorrectly named and should be `get?_indexOf`; +@[deprecated (since := "2025-01-30")] alias getElem?_indexOf := getElem?_idxOf + +-- This is incorrectly named and should be `get?_idxOf`; -- this already exists, so will require a deprecation dance. -theorem indexOf_get? [DecidableEq α] {a : α} {l : List α} (h : a ∈ l) : - get? l (indexOf a l) = some a := by simp [h] +theorem idxOf_get? [DecidableEq α] {a : α} {l : List α} (h : a ∈ l) : + get? l (idxOf a l) = some a := by simp [h] + +@[deprecated (since := "2025-01-30")] alias indexOf_get? := idxOf_get? -theorem indexOf_inj [DecidableEq α] {l : List α} {x y : α} (hx : x ∈ l) (hy : y ∈ l) : - indexOf x l = indexOf y l ↔ x = y := +theorem idxOf_inj [DecidableEq α] {l : List α} {x y : α} (hx : x ∈ l) (hy : y ∈ l) : + idxOf x l = idxOf y l ↔ x = y := ⟨fun h => by have x_eq_y : - get l ⟨indexOf x l, indexOf_lt_length_iff.2 hx⟩ = - get l ⟨indexOf y l, indexOf_lt_length_iff.2 hy⟩ := by + get l ⟨idxOf x l, idxOf_lt_length_iff.2 hx⟩ = + get l ⟨idxOf y l, idxOf_lt_length_iff.2 hy⟩ := by simp only [h] - simp only [indexOf_get] at x_eq_y; exact x_eq_y, fun h => by subst h; rfl⟩ + simp only [idxOf_get] at x_eq_y; exact x_eq_y, fun h => by subst h; rfl⟩ + +@[deprecated (since := "2025-01-30")] alias indexOf_inj := idxOf_inj theorem get_reverse' (l : List α) (n) (hn') : l.reverse.get n = l.get ⟨l.length - 1 - n, hn'⟩ := by diff --git a/Mathlib/Data/List/Count.lean b/Mathlib/Data/List/Count.lean index ff77b8257b8d5..e8305bd7e081b 100644 --- a/Mathlib/Data/List/Count.lean +++ b/Mathlib/Data/List/Count.lean @@ -3,6 +3,7 @@ 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 Batteries.Data.List.Perm import Mathlib.Logic.Function.Basic import Mathlib.Tactic.Common diff --git a/Mathlib/Data/List/Enum.lean b/Mathlib/Data/List/Enum.lean index 38f58ee6b8223..1bc5b003288be 100644 --- a/Mathlib/Data/List/Enum.lean +++ b/Mathlib/Data/List/Enum.lean @@ -21,58 +21,31 @@ namespace List variable {α : Type*} -@[deprecated getElem?_enumFrom (since := "2024-08-15")] -theorem get?_enumFrom (n) (l : List α) (m) : - get? (enumFrom n l) m = (get? l m).map fun a => (n + m, a) := by - simp - -@[deprecated getElem?_enum (since := "2024-08-15")] -theorem get?_enum (l : List α) (n) : get? (enum l) n = (get? l n).map fun a => (n, a) := by - simp - -@[deprecated getElem_enumFrom (since := "2024-08-15")] -theorem get_enumFrom (l : List α) (n) (i : Fin (l.enumFrom n).length) : - (l.enumFrom n).get i = (n + i, l.get (i.cast enumFrom_length)) := by - simp - -@[deprecated getElem_enum (since := "2024-08-15")] -theorem get_enum (l : List α) (i : Fin l.enum.length) : - l.enum.get i = (i.1, l.get (i.cast enum_length)) := by - simp - -@[deprecated mk_add_mem_enumFrom_iff_getElem? (since := "2024-08-12")] -theorem mk_add_mem_enumFrom_iff_get? {n i : ℕ} {x : α} {l : List α} : - (n + i, x) ∈ enumFrom n l ↔ l.get? i = x := by - simp [mem_iff_get?] - -@[deprecated mk_mem_enumFrom_iff_le_and_getElem?_sub (since := "2024-08-12")] -theorem mk_mem_enumFrom_iff_le_and_get?_sub {n i : ℕ} {x : α} {l : List α} : - (i, x) ∈ enumFrom n l ↔ n ≤ i ∧ l.get? (i - n) = x := by - simp [mk_mem_enumFrom_iff_le_and_getElem?_sub] - -@[deprecated mk_mem_enum_iff_getElem? (since := "2024-08-15")] -theorem mk_mem_enum_iff_get? {i : ℕ} {x : α} {l : List α} : (i, x) ∈ enum l ↔ l.get? i = x := by - simp [enum, mk_mem_enumFrom_iff_le_and_getElem?_sub] - -set_option linter.deprecated false in -@[deprecated mem_enum_iff_getElem? (since := "2024-08-15")] -theorem mem_enum_iff_get? {x : ℕ × α} {l : List α} : x ∈ enum l ↔ l.get? x.1 = x.2 := - mk_mem_enum_iff_get? - -theorem forall_mem_enumFrom {l : List α} {n : ℕ} {p : ℕ × α → Prop} : - (∀ x ∈ l.enumFrom n, p x) ↔ ∀ (i : ℕ) (_ : i < length l), p (n + i, l[i]) := by - simp only [forall_mem_iff_getElem, getElem_enumFrom, enumFrom_length] - -theorem forall_mem_enum {l : List α} {p : ℕ × α → Prop} : - (∀ x ∈ l.enum, p x) ↔ ∀ (i : ℕ) (_ : i < length l), p (i, l[i]) := - forall_mem_enumFrom.trans <| by simp - -theorem exists_mem_enumFrom {l : List α} {n : ℕ} {p : ℕ × α → Prop} : - (∃ x ∈ l.enumFrom n, p x) ↔ ∃ (i : ℕ) (_ : i < length l), p (n + i, l[i]) := by - simp only [exists_mem_iff_getElem, getElem_enumFrom, enumFrom_length] - -theorem exists_mem_enum {l : List α} {p : ℕ × α → Prop} : - (∃ x ∈ l.enum, p x) ↔ ∃ (i : ℕ) (_ : i < length l), p (i, l[i]) := - exists_mem_enumFrom.trans <| by simp +theorem forall_mem_zipIdx {l : List α} {n : ℕ} {p : α × ℕ → Prop} : + (∀ x ∈ l.zipIdx n, p x) ↔ ∀ (i : ℕ) (_ : i < length l), p (l[i], n + i) := by + simp only [forall_mem_iff_getElem, getElem_zipIdx, length_zipIdx] + +/-- Variant of `forall_mem_zipIdx` with the `zipIdx` argument specialized to `0`. -/ +theorem forall_mem_zipIdx' {l : List α} {p : α × ℕ → Prop} : + (∀ x ∈ l.zipIdx, p x) ↔ ∀ (i : ℕ) (_ : i < length l), p (l[i], i) := + forall_mem_zipIdx.trans <| by simp + +theorem exists_mem_zipIdx {l : List α} {n : ℕ} {p : α × ℕ → Prop} : + (∃ x ∈ l.zipIdx n, p x) ↔ ∃ (i : ℕ) (_ : i < length l), p (l[i], n + i) := by + simp only [exists_mem_iff_getElem, getElem_zipIdx, length_zipIdx] + +/-- Variant of `exists_mem_zipIdx` with the `zipIdx` argument specialized to `0`. -/ +theorem exists_mem_zipIdx' {l : List α} {p : α × ℕ → Prop} : + (∃ x ∈ l.zipIdx, p x) ↔ ∃ (i : ℕ) (_ : i < length l), p (l[i], i) := + exists_mem_zipIdx.trans <| by simp + +@[deprecated (since := "2025-01-28")] +alias forall_mem_enumFrom := forall_mem_zipIdx +@[deprecated (since := "2025-01-28")] +alias forall_mem_enum := forall_mem_zipIdx' +@[deprecated (since := "2025-01-28")] +alias exists_mem_enumFrom := exists_mem_zipIdx +@[deprecated (since := "2025-01-28")] +alias exists_mem_enum := exists_mem_zipIdx' end List diff --git a/Mathlib/Data/List/FinRange.lean b/Mathlib/Data/List/FinRange.lean index de54055232145..4931507ccde7a 100644 --- a/Mathlib/Data/List/FinRange.lean +++ b/Mathlib/Data/List/FinRange.lean @@ -60,12 +60,14 @@ theorem get_finRange {n : ℕ} {i : ℕ} (h) : theorem finRange_map_get (l : List α) : (finRange l.length).map l.get = l := List.ext_get (by simp) (by simp) -@[simp] theorem indexOf_finRange {k : ℕ} (i : Fin k) : (finRange k).indexOf i = i := by - have : (finRange k).indexOf i < (finRange k).length := indexOf_lt_length_iff.mpr (by simp) - have h₁ : (finRange k).get ⟨(finRange k).indexOf i, this⟩ = i := indexOf_get this +@[simp] theorem idxOf_finRange {k : ℕ} (i : Fin k) : (finRange k).idxOf i = i := by + have : (finRange k).idxOf i < (finRange k).length := idxOf_lt_length_iff.mpr (by simp) + have h₁ : (finRange k).get ⟨(finRange k).idxOf i, this⟩ = i := idxOf_get this have h₂ : (finRange k).get ⟨i, by simp⟩ = i := get_finRange _ simpa using (Nodup.get_inj_iff (nodup_finRange k)).mp (Eq.trans h₁ h₂.symm) +@[deprecated (since := "2025-01-30")] alias indexOf_finRange := idxOf_get + @[simp] theorem map_coe_finRange (n : ℕ) : ((finRange n) : List (Fin n)).map (Fin.val) = List.range n := by apply List.ext_getElem <;> simp diff --git a/Mathlib/Data/List/Forall2.lean b/Mathlib/Data/List/Forall2.lean index 0cb3064f00ac4..cb0a1e713998c 100644 --- a/Mathlib/Data/List/Forall2.lean +++ b/Mathlib/Data/List/Forall2.lean @@ -226,7 +226,8 @@ theorem rel_flatten : (Forall₂ (Forall₂ R) ⇒ Forall₂ R) flatten flatten @[deprecated (since := "2025-10-15")] alias rel_join := rel_flatten -theorem rel_flatMap : (Forall₂ R ⇒ (R ⇒ Forall₂ P) ⇒ Forall₂ P) List.flatMap List.flatMap := +theorem rel_flatMap : (Forall₂ R ⇒ (R ⇒ Forall₂ P) ⇒ Forall₂ P) + (Function.swap List.flatMap) (Function.swap List.flatMap) := fun _ _ h₁ _ _ h₂ => rel_flatten (rel_map (@h₂) h₁) @[deprecated (since := "2025-10-16")] alias rel_bind := rel_flatMap diff --git a/Mathlib/Data/List/Indexes.lean b/Mathlib/Data/List/Indexes.lean index e307495cd9f2c..21c03a33508e0 100644 --- a/Mathlib/Data/List/Indexes.lean +++ b/Mathlib/Data/List/Indexes.lean @@ -42,6 +42,7 @@ theorem mapIdx_append_one : ∀ {f : ℕ → α → β} {l : List α} {e : α}, mapIdx f (l ++ [e]) = mapIdx f l ++ [f l.length e] := mapIdx_concat +set_option linter.deprecated false in @[deprecated "Deprecated without replacement." (since := "2025-01-29"), local simp] theorem map_enumFrom_eq_zipWith : ∀ (l : List α) (n : ℕ) (f : ℕ → α → β), map (uncurry f) (enumFrom n l) = zipWith (fun i ↦ f (i + n)) (range (length l)) l := by @@ -68,11 +69,12 @@ theorem map_enumFrom_eq_zipWith : ∀ (l : List α) (n : ℕ) (f : ℕ → α @[deprecated (since := "2024-10-15")] alias mapIdx_eq_nil := mapIdx_eq_nil_iff +set_option linter.deprecated false in @[deprecated "Deprecated without replacement." (since := "2025-01-29")] theorem get_mapIdx (l : List α) (f : ℕ → α → β) (i : ℕ) (h : i < l.length) (h' : i < (l.mapIdx f).length := h.trans_le length_mapIdx.ge) : (l.mapIdx f).get ⟨i, h'⟩ = f i (l.get ⟨i, h⟩) := by - simp [mapIdx_eq_enum_map, enum_eq_zip_range] + simp [mapIdx_eq_zipIdx_map, enum_eq_zip_range] @[deprecated (since := "2024-08-19")] alias nthLe_mapIdx := get_mapIdx @@ -160,6 +162,7 @@ end MapIdx section FoldrIdx -- Porting note: Changed argument order of `foldrIdxSpec` to align better with `foldrIdx`. +set_option linter.deprecated false in /-- Specification of `foldrIdx`. -/ @[deprecated "Deprecated without replacement." (since := "2025-01-29")] def foldrIdxSpec (f : ℕ → α → β → β) (b : β) (as : List α) (start : ℕ) : β := @@ -205,6 +208,7 @@ theorem findIdxs_eq_map_indexesValues (p : α → Prop) [DecidablePred p] (as : section FoldlIdx -- Porting note: Changed argument order of `foldlIdxSpec` to align better with `foldlIdx`. +set_option linter.deprecated false in /-- Specification of `foldlIdx`. -/ @[deprecated "Deprecated without replacement." (since := "2025-01-29")] def foldlIdxSpec (f : ℕ → α → β → α) (a : α) (bs : List β) (start : ℕ) : α := @@ -257,6 +261,7 @@ section MapIdxM -- Porting note: `[Applicative m]` replaced by `[Monad m] [LawfulMonad m]` variable {m : Type u → Type v} [Monad m] +set_option linter.deprecated false in /-- Specification of `mapIdxMAux`. -/ @[deprecated "Deprecated without replacement." (since := "2025-01-29")] def mapIdxMAuxSpec {β} (f : ℕ → α → m β) (start : ℕ) (as : List α) : m (List β) := @@ -322,7 +327,7 @@ theorem mapIdxMAux'_eq_mapIdxMGo {α} (f : ℕ → α → m PUnit) (as : List α simp only [seqRight_eq, map_eq_pure_bind, seq_pure, LawfulMonad.bind_assoc, pure_bind] theorem mapIdxM'_eq_mapIdxM {α} (f : ℕ → α → m PUnit) (as : List α) : - mapIdxM' f as = mapIdxM as f *> pure PUnit.unit := + mapIdxM' f as = mapIdxM f as *> pure PUnit.unit := mapIdxMAux'_eq_mapIdxMGo f as #[] end MapIdxM' diff --git a/Mathlib/Data/List/Intervals.lean b/Mathlib/Data/List/Intervals.lean index 0ea92237b0822..bc6af1bfc374a 100644 --- a/Mathlib/Data/List/Intervals.lean +++ b/Mathlib/Data/List/Intervals.lean @@ -81,7 +81,7 @@ theorem append_consecutive {n m l : ℕ} (hnm : n ≤ m) (hml : m ≤ l) : dsimp only [Ico] convert range'_append n (m-n) (l-m) 1 using 2 · rw [Nat.one_mul, Nat.add_sub_cancel' hnm] - · rw [Nat.sub_add_sub_cancel hml hnm] + · omega @[simp] theorem inter_consecutive (n m l : ℕ) : Ico n m ∩ Ico m l = [] := by diff --git a/Mathlib/Data/List/MinMax.lean b/Mathlib/Data/List/MinMax.lean index 1adc6b35b85fc..e069728cff22f 100644 --- a/Mathlib/Data/List/MinMax.lean +++ b/Mathlib/Data/List/MinMax.lean @@ -185,10 +185,10 @@ theorem argmin_cons (f : α → β) (a : α) (l : List α) : variable [DecidableEq α] theorem index_of_argmax : - ∀ {l : List α} {m : α}, m ∈ argmax f l → ∀ {a}, a ∈ l → f m ≤ f a → l.indexOf m ≤ l.indexOf a + ∀ {l : List α} {m : α}, m ∈ argmax f l → ∀ {a}, a ∈ l → f m ≤ f a → l.idxOf m ≤ l.idxOf a | [], m, _, _, _, _ => by simp | hd :: tl, m, hm, a, ha, ham => by - simp only [indexOf_cons, argmax_cons, Option.mem_def] at hm ⊢ + simp only [idxOf_cons, argmax_cons, Option.mem_def] at hm ⊢ cases h : argmax f tl · rw [h] at hm simp_all @@ -206,12 +206,12 @@ theorem index_of_argmax : exact Nat.zero_le _ theorem index_of_argmin : - ∀ {l : List α} {m : α}, m ∈ argmin f l → ∀ {a}, a ∈ l → f a ≤ f m → l.indexOf m ≤ l.indexOf a := + ∀ {l : List α} {m : α}, m ∈ argmin f l → ∀ {a}, a ∈ l → f a ≤ f m → l.idxOf m ≤ l.idxOf a := @index_of_argmax _ βᵒᵈ _ _ _ theorem mem_argmax_iff : m ∈ argmax f l ↔ - m ∈ l ∧ (∀ a ∈ l, f a ≤ f m) ∧ ∀ a ∈ l, f m ≤ f a → l.indexOf m ≤ l.indexOf a := + m ∈ l ∧ (∀ a ∈ l, f a ≤ f m) ∧ ∀ a ∈ l, f m ≤ f a → l.idxOf m ≤ l.idxOf a := ⟨fun hm => ⟨argmax_mem hm, fun _ ha => le_of_mem_argmax ha hm, fun _ => index_of_argmax hm⟩, by rintro ⟨hml, ham, hma⟩ @@ -220,21 +220,21 @@ theorem mem_argmax_iff : · have := _root_.le_antisymm (hma n (argmax_mem harg) (le_of_mem_argmax hml harg)) (index_of_argmax harg hml (ham _ (argmax_mem harg))) - rw [(indexOf_inj hml (argmax_mem harg)).1 this, Option.mem_def]⟩ + rw [(idxOf_inj hml (argmax_mem harg)).1 this, Option.mem_def]⟩ theorem argmax_eq_some_iff : argmax f l = some m ↔ - m ∈ l ∧ (∀ a ∈ l, f a ≤ f m) ∧ ∀ a ∈ l, f m ≤ f a → l.indexOf m ≤ l.indexOf a := + m ∈ l ∧ (∀ a ∈ l, f a ≤ f m) ∧ ∀ a ∈ l, f m ≤ f a → l.idxOf m ≤ l.idxOf a := mem_argmax_iff theorem mem_argmin_iff : m ∈ argmin f l ↔ - m ∈ l ∧ (∀ a ∈ l, f m ≤ f a) ∧ ∀ a ∈ l, f a ≤ f m → l.indexOf m ≤ l.indexOf a := + m ∈ l ∧ (∀ a ∈ l, f m ≤ f a) ∧ ∀ a ∈ l, f a ≤ f m → l.idxOf m ≤ l.idxOf a := @mem_argmax_iff _ βᵒᵈ _ _ _ _ _ theorem argmin_eq_some_iff : argmin f l = some m ↔ - m ∈ l ∧ (∀ a ∈ l, f m ≤ f a) ∧ ∀ a ∈ l, f a ≤ f m → l.indexOf m ≤ l.indexOf a := + m ∈ l ∧ (∀ a ∈ l, f m ≤ f a) ∧ ∀ a ∈ l, f a ≤ f m → l.idxOf m ≤ l.idxOf a := mem_argmin_iff end LinearOrder diff --git a/Mathlib/Data/List/Nodup.lean b/Mathlib/Data/List/Nodup.lean index 084e0e51bba63..858af6ecd2ebd 100644 --- a/Mathlib/Data/List/Nodup.lean +++ b/Mathlib/Data/List/Nodup.lean @@ -120,17 +120,21 @@ theorem not_nodup_of_get_eq_of_ne (xs : List α) (n m : Fin xs.length) rw [nodup_iff_injective_get] exact fun hinj => hne (hinj h) -theorem indexOf_getElem [DecidableEq α] {l : List α} (H : Nodup l) (i : Nat) (h : i < l.length) : - indexOf l[i] l = i := - suffices (⟨indexOf l[i] l, indexOf_lt_length_iff.2 (getElem_mem _)⟩ : Fin l.length) = ⟨i, h⟩ +theorem idxOf_getElem [DecidableEq α] {l : List α} (H : Nodup l) (i : Nat) (h : i < l.length) : + idxOf l[i] l = i := + suffices (⟨idxOf l[i] l, idxOf_lt_length_iff.2 (getElem_mem _)⟩ : Fin l.length) = ⟨i, h⟩ from Fin.val_eq_of_eq this nodup_iff_injective_get.1 H (by simp) --- This is incorrectly named and should be `indexOf_get`; +@[deprecated (since := "2025-01-30")] alias indexOf_getElem := idxOf_getElem + +-- This is incorrectly named and should be `idxOf_get`; -- this already exists, so will require a deprecation dance. -theorem get_indexOf [DecidableEq α] {l : List α} (H : Nodup l) (i : Fin l.length) : - indexOf (get l i) l = i := by - simp [indexOf_getElem, H] +theorem get_idxOf [DecidableEq α] {l : List α} (H : Nodup l) (i : Fin l.length) : + idxOf (get l i) l = i := by + simp [idxOf_getElem, H] + +@[deprecated (since := "2025-01-30")] alias get_indexOf := get_idxOf theorem nodup_iff_count_le_one [DecidableEq α] {l : List α} : Nodup l ↔ ∀ a, count a l ≤ 1 := nodup_iff_sublist.trans <| @@ -343,7 +347,7 @@ protected theorem Nodup.set : theorem Nodup.map_update [DecidableEq α] {l : List α} (hl : l.Nodup) (f : α → β) (x : α) (y : β) : l.map (Function.update f x y) = - if x ∈ l then (l.map f).set (l.indexOf x) y else l.map f := by + if x ∈ l then (l.map f).set (l.idxOf x) y else l.map f := by induction' l with hd tl ihl; · simp rw [nodup_cons] at hl simp only [mem_cons, map, ihl hl.2] diff --git a/Mathlib/Data/List/NodupEquivFin.lean b/Mathlib/Data/List/NodupEquivFin.lean index 0edcc7b2aba6c..5673bb3adebe1 100644 --- a/Mathlib/Data/List/NodupEquivFin.lean +++ b/Mathlib/Data/List/NodupEquivFin.lean @@ -50,8 +50,8 @@ the set of elements of `l`. -/ @[simps] def getEquiv (l : List α) (H : Nodup l) : Fin (length l) ≃ { x // x ∈ l } where toFun i := ⟨get l i, get_mem _ _⟩ - invFun x := ⟨indexOf (↑x) l, indexOf_lt_length_iff.2 x.2⟩ - left_inv i := by simp only [List.get_indexOf, eq_self_iff_true, Fin.eta, Subtype.coe_mk, H] + invFun x := ⟨idxOf (↑x) l, idxOf_lt_length_iff.2 x.2⟩ + left_inv i := by simp only [List.get_idxOf, eq_self_iff_true, Fin.eta, Subtype.coe_mk, H] right_inv x := by simp /-- If `l` lists all the elements of `α` without duplicates, then `List.get` defines @@ -63,8 +63,8 @@ decidable equality. -/ def getEquivOfForallMemList (l : List α) (nd : l.Nodup) (h : ∀ x : α, x ∈ l) : Fin l.length ≃ α where toFun i := l.get i - invFun a := ⟨_, indexOf_lt_length_iff.2 (h a)⟩ - left_inv i := by simp [List.indexOf_getElem, nd] + invFun a := ⟨_, idxOf_lt_length_iff.2 (h a)⟩ + left_inv i := by simp [List.idxOf_getElem, nd] right_inv a := by simp end Nodup @@ -92,7 +92,7 @@ theorem coe_getIso_apply : (H.getIso l i : α) = get l i := rfl @[simp] -theorem coe_getIso_symm_apply : ((H.getIso l).symm x : ℕ) = indexOf (↑x) l := +theorem coe_getIso_symm_apply : ((H.getIso l).symm x : ℕ) = idxOf (↑x) l := rfl end Sorted diff --git a/Mathlib/Data/List/OfFn.lean b/Mathlib/Data/List/OfFn.lean index 0e77e65fdc740..b51e2171232bb 100644 --- a/Mathlib/Data/List/OfFn.lean +++ b/Mathlib/Data/List/OfFn.lean @@ -123,15 +123,14 @@ theorem ofFn_getElem_eq_map {β : Type*} (l : List α) (f : α → β) : ofFn (fun i : Fin l.length => f <| l[(i : Nat)]) = l.map f := by rw [← Function.comp_def, ← map_ofFn, ofFn_getElem] --- not registered as a simp lemma, as otherwise it fires before `forall_mem_ofFn_iff` which --- is much more useful -theorem mem_ofFn {n} (f : Fin n → α) (a : α) : a ∈ ofFn f ↔ a ∈ Set.range f := by +-- Note there is a now another `mem_ofFn` defined in Lean, with an existential on the RHS, +-- which is marked as a simp lemma. +theorem mem_ofFn' {n} (f : Fin n → α) (a : α) : a ∈ ofFn f ↔ a ∈ Set.range f := by simp only [mem_iff_get, Set.mem_range, get_ofFn] exact ⟨fun ⟨i, hi⟩ => ⟨Fin.cast (by simp) i, hi⟩, fun ⟨i, hi⟩ => ⟨Fin.cast (by simp) i, hi⟩⟩ -@[simp] theorem forall_mem_ofFn_iff {n : ℕ} {f : Fin n → α} {P : α → Prop} : - (∀ i ∈ ofFn f, P i) ↔ ∀ j : Fin n, P (f j) := by simp only [mem_ofFn, Set.forall_mem_range] + (∀ i ∈ ofFn f, P i) ↔ ∀ j : Fin n, P (f j) := by simp @[simp] theorem ofFn_const : ∀ (n : ℕ) (c : α), (ofFn fun _ : Fin n => c) = replicate n c diff --git a/Mathlib/Data/List/ProdSigma.lean b/Mathlib/Data/List/ProdSigma.lean index 6e1aec6c08ded..e18598bb29ea0 100644 --- a/Mathlib/Data/List/ProdSigma.lean +++ b/Mathlib/Data/List/ProdSigma.lean @@ -5,7 +5,6 @@ Authors: Leonardo de Moura, Mario Carneiro -/ import Mathlib.Data.List.Basic import Mathlib.Data.Prod.Basic -import Mathlib.Data.Sigma.Basic /-! # Lists in product and sigma types diff --git a/Mathlib/Data/List/Sigma.lean b/Mathlib/Data/List/Sigma.lean index 5b5e7fba9dd66..f449bb6695315 100644 --- a/Mathlib/Data/List/Sigma.lean +++ b/Mathlib/Data/List/Sigma.lean @@ -128,7 +128,10 @@ theorem nodupKeys_flatten {L : List (List (Sigma β))} : @[deprecated (since := "2024-10-15")] alias nodupKeys_join := nodupKeys_flatten -theorem nodup_enum_map_fst (l : List α) : (l.enum.map Prod.fst).Nodup := by simp [List.nodup_range] +theorem nodup_zipIdx_map_snd (l : List α) : (l.zipIdx.map Prod.snd).Nodup := by + simp [List.nodup_range'] + +@[deprecated (since := "2025-01-28")] alias nodup_enum_map_fst := nodup_zipIdx_map_snd theorem mem_ext {l₀ l₁ : List (Sigma β)} (nd₀ : l₀.Nodup) (nd₁ : l₁.Nodup) (h : ∀ x, x ∈ l₀ ↔ x ∈ l₁) : l₀ ~ l₁ := diff --git a/Mathlib/Data/List/Sublists.lean b/Mathlib/Data/List/Sublists.lean index cf9436cf68118..c403e3538cf54 100644 --- a/Mathlib/Data/List/Sublists.lean +++ b/Mathlib/Data/List/Sublists.lean @@ -367,9 +367,9 @@ theorem revzip_sublists (l : List α) : ∀ l₁ l₂, (l₁, l₂) ∈ revzip l rw [revzip] induction' l using List.reverseRecOn with l' a ih · intro l₁ l₂ h - simp? at h says + simp? at h says simp only [sublists_nil, reverse_cons, reverse_nil, nil_append, zip_cons_cons, zip_nil_right, - mem_singleton, Prod.mk.injEq] at h + mem_cons, Prod.mk.injEq, not_mem_nil, or_false] at h simp [h] · intro l₁ l₂ h rw [sublists_concat, reverse_append, zip_append (by simp), ← map_reverse, zip_map_right, diff --git a/Mathlib/Data/List/ToFinsupp.lean b/Mathlib/Data/List/ToFinsupp.lean index 3af2f3ea04c13..48590950ee13b 100644 --- a/Mathlib/Data/List/ToFinsupp.lean +++ b/Mathlib/Data/List/ToFinsupp.lean @@ -114,15 +114,18 @@ theorem toFinsupp_concat_eq_toFinsupp_add_single {R : Type*} [AddZeroClass R] (x addLeftEmbedding_apply, add_zero] -theorem toFinsupp_eq_sum_map_enum_single {R : Type*} [AddMonoid R] (l : List R) +theorem toFinsupp_eq_sum_mapIdx_single {R : Type*} [AddMonoid R] (l : List R) [DecidablePred (getD l · 0 ≠ 0)] : - toFinsupp l = (l.enum.map fun nr : ℕ × R => Finsupp.single nr.1 nr.2).sum := by + toFinsupp l = (l.mapIdx fun n r => Finsupp.single n r).sum := by /- Porting note (https://github.com/leanprover-community/mathlib4/issues/11215): TODO: `induction` fails to substitute `l = []` in `[DecidablePred (getD l · 0 ≠ 0)]`, so we manually do some `revert`/`intro` as a workaround -/ revert l; intro l induction l using List.reverseRecOn with | nil => exact toFinsupp_nil | append_singleton x xs ih => - classical simp [toFinsupp_concat_eq_toFinsupp_add_single, enum_append, ih] + classical simp [toFinsupp_concat_eq_toFinsupp_add_single, ih] + +@[deprecated (since := "2025-01-28")] +alias toFinsupp_eq_sum_map_enum_single := toFinsupp_eq_sum_mapIdx_single end List diff --git a/Mathlib/Data/Nat/Defs.lean b/Mathlib/Data/Nat/Defs.lean index 1ba1022898043..6954d22b81538 100644 --- a/Mathlib/Data/Nat/Defs.lean +++ b/Mathlib/Data/Nat/Defs.lean @@ -436,8 +436,6 @@ protected lemma div_ne_zero_iff : a / b ≠ 0 ↔ b ≠ 0 ∧ b ≤ a := by simp @[simp] protected lemma div_pos_iff : 0 < a / b ↔ 0 < b ∧ b ≤ a := by simp [Nat.pos_iff_ne_zero] -protected lemma div_pos (hba : b ≤ a) (hb : 0 < b) : 0 < a / b := Nat.div_pos_iff.2 ⟨hb, hba⟩ - lemma lt_mul_of_div_lt (h : a / c < b) (hc : 0 < c) : a < b * c := Nat.lt_of_not_ge <| Nat.not_le_of_gt h ∘ (Nat.le_div_iff_mul_le hc).2 @@ -518,9 +516,7 @@ protected lemma div_le_self' (m n : ℕ) : m / n ≤ m := by lemma two_mul_odd_div_two (hn : n % 2 = 1) : 2 * (n / 2) = n - 1 := by conv => rhs; rw [← Nat.mod_add_div n 2, hn, Nat.add_sub_cancel_left] -@[gcongr] -lemma div_le_div_left (hcb : c ≤ b) (hc : 0 < c) : a / b ≤ a / c := - (Nat.le_div_iff_mul_le hc).2 <| Nat.le_trans (Nat.mul_le_mul_left _ hcb) (div_mul_le_self _ _) +attribute [gcongr] div_le_div_left lemma div_eq_self : m / n = m ↔ m = 0 ∨ n = 1 := by constructor diff --git a/Mathlib/Data/Nat/Digits.lean b/Mathlib/Data/Nat/Digits.lean index bde0bf0b51b40..7b3dfcc978157 100644 --- a/Mathlib/Data/Nat/Digits.lean +++ b/Mathlib/Data/Nat/Digits.lean @@ -150,22 +150,22 @@ theorem ofDigits_eq_foldr {α : Type*} [Semiring α] (b : α) (L : List ℕ) : · dsimp [ofDigits] rw [ih] -theorem ofDigits_eq_sum_map_with_index_aux (b : ℕ) (l : List ℕ) : - ((List.range l.length).zipWith ((fun i a : ℕ => a * b ^ (i + 1))) l).sum = - b * ((List.range l.length).zipWith (fun i a => a * b ^ i) l).sum := by +theorem ofDigits_eq_sum_mapIdx_aux (b : ℕ) (l : List ℕ) : + (l.zipWith ((fun a i : ℕ => a * b ^ (i + 1))) (List.range l.length)).sum = + b * (l.zipWith (fun a i => a * b ^ i) (List.range l.length)).sum := by suffices - (List.range l.length).zipWith (fun i a : ℕ => a * b ^ (i + 1)) l = - (List.range l.length).zipWith (fun i a => b * (a * b ^ i)) l + l.zipWith (fun a i : ℕ => a * b ^ (i + 1)) (List.range l.length) = + l.zipWith (fun a i=> b * (a * b ^ i)) (List.range l.length) by simp [this] congr; ext; simp [pow_succ]; ring theorem ofDigits_eq_sum_mapIdx (b : ℕ) (L : List ℕ) : ofDigits b L = (L.mapIdx fun i a => a * b ^ i).sum := by - rw [List.mapIdx_eq_enum_map, List.enum_eq_zip_range, List.map_uncurry_zip_eq_zipWith, - ofDigits_eq_foldr] + rw [List.mapIdx_eq_zipIdx_map, List.zipIdx_eq_zip_range', List.map_zip_eq_zipWith, + ofDigits_eq_foldr, ← List.range_eq_range'] induction' L with hd tl hl · simp - · simpa [List.range_succ_eq_map, List.zipWith_map_left, ofDigits_eq_sum_map_with_index_aux] using + · simpa [List.range_succ_eq_map, List.zipWith_map_right, ofDigits_eq_sum_mapIdx_aux] using Or.inl hl @[simp] diff --git a/Mathlib/Data/Option/Basic.lean b/Mathlib/Data/Option/Basic.lean index d6f5815d92c9e..a12db6bd272f9 100644 --- a/Mathlib/Data/Option/Basic.lean +++ b/Mathlib/Data/Option/Basic.lean @@ -152,16 +152,6 @@ theorem pmap_map (g : γ → α) (x : Option γ) (H) : pmap f (x.map g) H = pmap (fun a h ↦ f (g a) h) x fun _ h ↦ H _ (mem_map_of_mem _ h) := by cases x <;> simp only [map_none', map_some', pmap] -theorem map_pmap (g : β → γ) (f : ∀ a, p a → β) (x H) : - Option.map g (pmap f x H) = pmap (fun a h ↦ g (f a h)) x H := by - cases x <;> simp only [map_none', map_some', pmap] - --- Porting note: Can't simp tag this anymore because `pmap` simplifies --- @[simp] -theorem pmap_eq_map (p : α → Prop) (f : α → β) (x H) : - @pmap _ _ p (fun a _ ↦ f a) x H = Option.map f x := by - cases x <;> simp only [map_none', map_some', pmap] - theorem pmap_bind {α β γ} {x : Option α} {g : α → Option β} {p : β → Prop} {f : ∀ b, p b → γ} (H) (H' : ∀ (a : α), ∀ b ∈ g a, b ∈ x >>= g) : pmap f (x >>= g) H = x >>= fun a ↦ pmap f (g a) fun _ h ↦ H _ (H' a _ h) := by diff --git a/Mathlib/Data/Sigma/Basic.lean b/Mathlib/Data/Sigma/Basic.lean index 85bb264783fc7..50310134cc974 100644 --- a/Mathlib/Data/Sigma/Basic.lean +++ b/Mathlib/Data/Sigma/Basic.lean @@ -50,12 +50,8 @@ instance instDecidableEqSigma [h₁ : DecidableEq α] [h₂ : ∀ a, DecidableEq | _, _, isFalse n => isFalse fun h ↦ Sigma.noConfusion h fun _ e₂ ↦ n <| eq_of_heq e₂ | _, _, _, _, isFalse n => isFalse fun h ↦ Sigma.noConfusion h fun e₁ _ ↦ n e₁ --- sometimes the built-in injectivity support does not work -@[simp] theorem mk.inj_iff {a₁ a₂ : α} {b₁ : β a₁} {b₂ : β a₂} : - Sigma.mk a₁ b₁ = ⟨a₂, b₂⟩ ↔ a₁ = a₂ ∧ HEq b₁ b₂ := - ⟨fun h ↦ by cases h; simp, - fun ⟨h₁, h₂⟩ ↦ by subst h₁; rw [eq_of_heq h₂]⟩ + Sigma.mk a₁ b₁ = ⟨a₂, b₂⟩ ↔ a₁ = a₂ ∧ HEq b₁ b₂ := by simp @[simp] theorem eta : ∀ x : Σa, β a, Sigma.mk x.1 x.2 = x @@ -225,11 +221,6 @@ instance decidableEq [h₁ : DecidableEq α] [h₂ : ∀ a, DecidableEq (β a)] | _, _, isFalse n => isFalse fun h ↦ PSigma.noConfusion h fun _ e₂ ↦ n <| eq_of_heq e₂ | _, _, _, _, isFalse n => isFalse fun h ↦ PSigma.noConfusion h fun e₁ _ ↦ n e₁ --- See https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/porting.20data.2Esigma.2Ebasic/near/304855864 --- for an explanation of why this is currently needed. It generates `PSigma.mk.inj`. --- This could be done elsewhere. -gen_injective_theorems% PSigma - theorem mk.inj_iff {a₁ a₂ : α} {b₁ : β a₁} {b₂ : β a₂} : @PSigma.mk α β a₁ b₁ = @PSigma.mk α β a₂ b₂ ↔ a₁ = a₂ ∧ HEq b₁ b₂ := (Iff.intro PSigma.mk.inj) fun ⟨h₁, h₂⟩ ↦ diff --git a/Mathlib/Data/ULift.lean b/Mathlib/Data/ULift.lean index 29aed3723b5e7..4fb68daa44d18 100644 --- a/Mathlib/Data/ULift.lean +++ b/Mathlib/Data/ULift.lean @@ -46,9 +46,7 @@ theorem up_surjective : Surjective (@up α) := theorem up_bijective : Bijective (@up α) := Equiv.plift.symm.bijective -@[simp] -theorem up_inj {x y : α} : up x = up y ↔ x = y := - up_injective.eq_iff +theorem up_inj {x y : α} : up x = up y ↔ x = y := by simp theorem down_surjective : Surjective (@down α) := Equiv.plift.surjective @@ -103,9 +101,7 @@ theorem up_surjective : Surjective (@up α) := theorem up_bijective : Bijective (@up α) := Equiv.ulift.symm.bijective -@[simp] -theorem up_inj {x y : α} : up x = up y ↔ x = y := - up_injective.eq_iff +theorem up_inj {x y : α} : up x = up y ↔ x = y := by simp theorem down_surjective : Surjective (@down α) := Equiv.ulift.surjective diff --git a/Mathlib/GroupTheory/Perm/Cycle/Basic.lean b/Mathlib/GroupTheory/Perm/Cycle/Basic.lean index 05e5a64c67a95..32bc8a0b17285 100644 --- a/Mathlib/GroupTheory/Perm/Cycle/Basic.lean +++ b/Mathlib/GroupTheory/Perm/Cycle/Basic.lean @@ -858,9 +858,9 @@ variable [DecidableEq α] {l : List α} theorem Nodup.isCycleOn_formPerm (h : l.Nodup) : l.formPerm.IsCycleOn { a | a ∈ l } := by refine ⟨l.formPerm.bijOn fun _ => List.formPerm_mem_iff_mem, fun a ha b hb => ?_⟩ - rw [Set.mem_setOf, ← List.indexOf_lt_length_iff] at ha hb - rw [← List.getElem_indexOf ha, ← List.getElem_indexOf hb] - refine ⟨l.indexOf b - l.indexOf a, ?_⟩ + rw [Set.mem_setOf, ← List.idxOf_lt_length_iff] at ha hb + rw [← List.getElem_idxOf ha, ← List.getElem_idxOf hb] + refine ⟨l.idxOf b - l.idxOf a, ?_⟩ simp only [sub_eq_neg_add, zpow_add, zpow_neg, Equiv.Perm.inv_eq_iff_eq, zpow_natCast, Equiv.Perm.coe_mul, List.formPerm_pow_apply_getElem _ h, Function.comp] rw [add_comm] diff --git a/Mathlib/Lean/Meta/KAbstractPositions.lean b/Mathlib/Lean/Meta/KAbstractPositions.lean index ffb5899f96568..d8b18350513d2 100644 --- a/Mathlib/Lean/Meta/KAbstractPositions.lean +++ b/Mathlib/Lean/Meta/KAbstractPositions.lean @@ -71,7 +71,7 @@ def viewKAbstractSubExpr (e : Expr) (pos : SubExpr.Pos) : MetaM (Option (Expr × if subExpr.hasLooseBVars then return none let positions ← kabstractPositions subExpr e - let some n := positions.indexOf? pos | unreachable! + let some n := positions.idxOf? pos | unreachable! return some (subExpr, if positions.size == 1 then none else some (n + 1)) /-- Determine whether the result of abstracting `subExpr` from `e` at position `pos` results diff --git a/Mathlib/LinearAlgebra/Multilinear/Basic.lean b/Mathlib/LinearAlgebra/Multilinear/Basic.lean index 91124505b00ab..a593265e814c4 100644 --- a/Mathlib/LinearAlgebra/Multilinear/Basic.lean +++ b/Mathlib/LinearAlgebra/Multilinear/Basic.lean @@ -1154,14 +1154,14 @@ protected def mkPiAlgebraFin : MultilinearMap R (fun _ : Fin n => A) A where toFun m := (List.ofFn m).prod map_update_add' {dec} m i x y := by rw [Subsingleton.elim dec (by infer_instance)] - have : (List.finRange n).indexOf i < n := by - simpa using List.indexOf_lt_length_iff.2 (List.mem_finRange i) + have : (List.finRange n).idxOf i < n := by + simpa using List.idxOf_lt_length_iff.2 (List.mem_finRange i) simp [List.ofFn_eq_map, (List.nodup_finRange n).map_update, List.prod_set, add_mul, this, mul_add, add_mul] map_update_smul' {dec} m i c x := by rw [Subsingleton.elim dec (by infer_instance)] - have : (List.finRange n).indexOf i < n := by - simpa using List.indexOf_lt_length_iff.2 (List.mem_finRange i) + have : (List.finRange n).idxOf i < n := by + simpa using List.idxOf_lt_length_iff.2 (List.mem_finRange i) simp [List.ofFn_eq_map, (List.nodup_finRange n).map_update, List.prod_set, this] variable {R A n} diff --git a/Mathlib/Logic/Equiv/List.lean b/Mathlib/Logic/Equiv/List.lean index 7c84c312dfc46..37b796a38066b 100644 --- a/Mathlib/Logic/Equiv/List.lean +++ b/Mathlib/Logic/Equiv/List.lean @@ -112,7 +112,7 @@ end Finset /-- A listable type with decidable equality is encodable. -/ def encodableOfList [DecidableEq α] (l : List α) (H : ∀ x, x ∈ l) : Encodable α := - ⟨fun a => indexOf a l, l.get?, fun _ => indexOf_get? (H _)⟩ + ⟨fun a => idxOf a l, l.get?, fun _ => idxOf_get? (H _)⟩ /-- A finite type is encodable. Because the encoding is not unique, we wrap it in `Trunc` to preserve computability. -/ diff --git a/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean b/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean index d609a2dcc3395..50d947b4ff816 100644 --- a/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean +++ b/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean @@ -575,7 +575,8 @@ private def fastJacobiSym (a : ℤ) (b : ℕ) : ℤ := refine Nat.le_of_dvd (Int.gcd_pos_iff.mpr (mod_cast .inr hb0)) ?_ refine Nat.dvd_gcd (Int.ofNat_dvd_left.mp (Int.dvd_of_emod_eq_zero ha2)) ?_ exact Int.ofNat_dvd_left.mp (Int.dvd_of_emod_eq_zero (mod_cast hb2)) - · rw [← IH (b / 2) (b.div_lt_self (Nat.pos_of_ne_zero hb0) one_lt_two)] + · dsimp only + rw [← IH (b / 2) (b.div_lt_self (Nat.pos_of_ne_zero hb0) one_lt_two)] obtain ⟨b, rfl⟩ := Nat.dvd_of_mod_eq_zero hb2 rw [mul_right' a (by decide) fun h ↦ hb0 (mul_eq_zero_of_right 2 h), b.mul_div_cancel_left (by decide), mod_left a 2, Nat.cast_ofNat, diff --git a/Mathlib/NumberTheory/Ostrowski.lean b/Mathlib/NumberTheory/Ostrowski.lean index 292717210cee3..024a8093ad42f 100644 --- a/Mathlib/NumberTheory/Ostrowski.lean +++ b/Mathlib/NumberTheory/Ostrowski.lean @@ -55,17 +55,17 @@ private lemma tendsto_nat_rpow_inv : -- Multiplication by a constant moves in a List.sum private lemma list_mul_sum {R : Type*} [CommSemiring R] {T : Type*} (l : List T) (y : R) (x : R) : (l.mapIdx fun i _ => x * y ^ i).sum = x * (l.mapIdx fun i _ => y ^ i).sum := by - simp_rw [← smul_eq_mul, List.smul_sum, List.mapIdx_eq_enum_map] + simp_rw [← smul_eq_mul, List.smul_sum, List.mapIdx_eq_zipIdx_map] congr 1 simp -- Geometric sum for lists private lemma list_geom {T : Type*} {F : Type*} [Field F] (l : List T) {y : F} (hy : y ≠ 1) : (l.mapIdx fun i _ => y ^ i).sum = (y ^ l.length - 1) / (y - 1) := by - rw [← geom_sum_eq hy l.length, List.mapIdx_eq_enum_map, Finset.sum_range, ← Fin.sum_univ_get'] - simp only [List.getElem_enum, Function.uncurry_apply_pair] - let e : Fin l.enum.length ≃ Fin l.length := finCongr List.enum_length - exact Fintype.sum_bijective e e.bijective _ _ fun _ ↦ rfl + rw [← geom_sum_eq hy l.length, List.mapIdx_eq_zipIdx_map, Finset.sum_range, ← Fin.sum_univ_get'] + simp only [List.getElem_zipIdx, Function.uncurry_apply_pair] + let e : Fin l.zipIdx.length ≃ Fin l.length := finCongr List.length_zipIdx + exact Fintype.sum_bijective e e.bijective _ _ fun _ ↦ by simp [e] open AbsoluteValue -- does not work as intended after `namespace Rat.AbsoluteValue` @@ -294,10 +294,10 @@ lemma apply_le_sum_digits (n : ℕ) {m : ℕ} (hm : 1 < m) : _ = f L'.sum := by rw [Nat.ofDigits_eq_sum_mapIdx]; norm_cast _ ≤ (L'.map f).sum := listSum_le f L' _ ≤ (L.mapIdx fun i _ ↦ m * (f m) ^ i).sum := ?_ - simp only [hL', List.mapIdx_eq_enum_map, List.map_map] - refine List.sum_le_sum fun ⟨i, a⟩ hia ↦ ?_ + simp only [hL', List.mapIdx_eq_zipIdx_map, List.map_map] + refine List.sum_le_sum fun ⟨a, i⟩ hia ↦ ?_ dsimp only [Function.comp_apply, Function.uncurry_apply_pair] - replace hia := List.mem_enumFrom hia + replace hia := List.mem_zipIdx hia push_cast rw [map_mul, map_pow] refine mul_le_mul_of_nonneg_right ?_ <| pow_nonneg (f.nonneg _) i @@ -316,15 +316,14 @@ lemma one_lt_of_not_bounded (notbdd : ¬ ∀ n : ℕ, f n ≤ 1) {n₀ : ℕ} (h calc f m ≤ (L.mapIdx fun i _ ↦ n₀ * f n₀ ^ i).sum := apply_le_sum_digits m hn₀ _ ≤ (L.mapIdx fun _ _ ↦ (n₀ : ℝ)).sum := by - simp only [List.mapIdx_eq_enum_map, List.map_map] + simp only [List.mapIdx_eq_zipIdx_map, List.map_map] refine List.sum_le_sum fun ⟨i, a⟩ _ ↦ ?_ simp only [Function.comp_apply, Function.uncurry_apply_pair] exact mul_le_of_le_of_le_one' (mod_cast le_refl n₀) (pow_le_one₀ (by positivity) h) (by positivity) (by positivity) _ = n₀ * (Nat.log n₀ m + 1) := by - rw [List.mapIdx_eq_enum_map, List.eq_replicate_of_mem (a := (n₀ : ℝ)) - (l := List.map (Function.uncurry fun _ _ ↦ n₀) (List.enum L)), - List.sum_replicate, List.length_map, List.enum_length, nsmul_eq_mul, mul_comm, + rw [List.mapIdx_eq_zipIdx_map, List.eq_replicate_of_mem (a := (n₀ : ℝ)) (l := L.zipIdx.map _), + List.sum_replicate, List.length_map, List.length_zipIdx, nsmul_eq_mul, mul_comm, Nat.digits_len n₀ m hn₀ (not_eq_zero_of_lt hm), Nat.cast_add_one] simp +contextual _ ≤ n₀ * (logb n₀ m + 1) := by gcongr; exact natLog_le_logb .. diff --git a/Mathlib/Order/RelSeries.lean b/Mathlib/Order/RelSeries.lean index 81867c483651c..d8d45c2b14c06 100644 --- a/Mathlib/Order/RelSeries.lean +++ b/Mathlib/Order/RelSeries.lean @@ -177,7 +177,7 @@ instance membership : Membership α (RelSeries r) := theorem mem_def : x ∈ s ↔ x ∈ Set.range s := Iff.rfl @[simp] theorem mem_toList : x ∈ s.toList ↔ x ∈ s := by - rw [RelSeries.toList, List.mem_ofFn, RelSeries.mem_def] + rw [RelSeries.toList, List.mem_ofFn', RelSeries.mem_def] theorem subsingleton_of_length_eq_zero (hs : s.length = 0) : {x | x ∈ s}.Subsingleton := by rintro - ⟨i, rfl⟩ - ⟨j, rfl⟩ diff --git a/Mathlib/Tactic/DeriveTraversable.lean b/Mathlib/Tactic/DeriveTraversable.lean index 54a52f0b432bf..1844b160ba5ef 100644 --- a/Mathlib/Tactic/DeriveTraversable.lean +++ b/Mathlib/Tactic/DeriveTraversable.lean @@ -217,7 +217,7 @@ def mkOneInstance (n cls : Name) (tac : MVarId → TermElabM Unit) let params := params.pop let tgt := mkAppN tgt params let tgt ← mkInst cls tgt - params.zipWithIndex.foldrM (fun (param, i) tgt => do + params.zipIdx.foldrM (fun (param, i) tgt => do -- add typeclass hypothesis for each inductive parameter let tgt ← (do guard (i < decl.numParams) diff --git a/Mathlib/Tactic/Linarith/Oracle/FourierMotzkin.lean b/Mathlib/Tactic/Linarith/Oracle/FourierMotzkin.lean index 160faf10c2854..188e872f4dc19 100644 --- a/Mathlib/Tactic/Linarith/Oracle/FourierMotzkin.lean +++ b/Mathlib/Tactic/Linarith/Oracle/FourierMotzkin.lean @@ -327,7 +327,7 @@ def elimAllVarsM : LinarithM Unit := do those hypotheses. It produces an initial state for the elimination monad. -/ def mkLinarithData (hyps : List Comp) (maxVar : ℕ) : LinarithData := - ⟨maxVar, .ofList (hyps.enum.map fun ⟨n, cmp⟩ => PComp.assump cmp n) _⟩ + ⟨maxVar, .ofList (hyps.mapIdx fun n cmp => PComp.assump cmp n) _⟩ /-- An oracle that uses Fourier-Motzkin elimination. -/ def CertificateOracle.fourierMotzkin : CertificateOracle where diff --git a/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm.lean b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm.lean index a96634597705a..87d71a0c573f5 100644 --- a/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm.lean +++ b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm.lean @@ -32,7 +32,8 @@ Extract the certificate from the `vec` found by `Linarith.SimplexAlgorithm.findP def postprocess (vec : Array ℚ) : Std.HashMap ℕ ℕ := let common_den : ℕ := vec.foldl (fun acc item => acc.lcm item.den) 1 let vecNat : Array ℕ := vec.map (fun x : ℚ => (x * common_den).floor.toNat) - Std.HashMap.empty.insertMany <| vecNat.toList.enum.filter (fun ⟨_, item⟩ => item != 0) + Std.HashMap.empty.insertMany <| vecNat.zipIdx.filterMap + fun ⟨item, idx⟩ => if item != 0 then some (idx, item) else none end SimplexAlgorithm diff --git a/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/Datatypes.lean b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/Datatypes.lean index 2f6eb09ce7de1..177ec7e8b2a32 100644 --- a/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/Datatypes.lean +++ b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/Datatypes.lean @@ -57,8 +57,8 @@ instance : UsableInSimplexAlgorithm DenseMatrix where getElem mat i j := mat.data[i]![j]! setElem mat i j v := ⟨mat.data.modify i fun row => row.set! j v⟩ getValues mat := - mat.data.zipWithIndex.foldl (init := []) fun acc (row, i) => - let rowVals := Array.toList <| row.zipWithIndex.filterMap fun (v, j) => + mat.data.zipIdx.foldl (init := []) fun acc (row, i) => + let rowVals := Array.toList <| row.zipIdx.filterMap fun (v, j) => if v != 0 then .some (i, j, v) else @@ -72,7 +72,7 @@ instance : UsableInSimplexAlgorithm DenseMatrix where swapRows mat i j := ⟨mat.data.swapIfInBounds i j⟩ subtractRow mat i j coef := let newData : Array (Array Rat) := mat.data.modify j fun row => - row.zipWith mat.data[i]! fun x y => x - coef * y + Array.zipWith (fun x y => x - coef * y) row mat.data[i]! ⟨newData⟩ divideRow mat i coef := ⟨mat.data.modify i (·.map (· / coef))⟩ @@ -92,7 +92,7 @@ instance : UsableInSimplexAlgorithm SparseMatrix where else ⟨mat.data.modify i fun row => row.insert j v⟩ getValues mat := - mat.data.zipWithIndex.foldl (init := []) fun acc (row, i) => + mat.data.zipIdx.foldl (init := []) fun acc (row, i) => let rowVals := row.toList.map fun (j, v) => (i, j, v) rowVals ++ acc ofValues {n _ : Nat} vals := Id.run do diff --git a/Mathlib/Tactic/Linarith/Verification.lean b/Mathlib/Tactic/Linarith/Verification.lean index 2a5e07a579937..9fe7e89217e92 100644 --- a/Mathlib/Tactic/Linarith/Verification.lean +++ b/Mathlib/Tactic/Linarith/Verification.lean @@ -214,10 +214,10 @@ def proveFalseByLinarith (transparency : TransparencyMode) (oracle : Certificate return certificate let (sm, zip) ← withTraceNode `linarith (return m!"{exceptEmoji ·} Building final expression") do - let enum_inputs := inputs.enum + let enum_inputs := inputs.zipIdx -- construct a list pairing nonzero coeffs with the proof of their corresponding -- comparison - let zip := enum_inputs.filterMap fun ⟨n, e⟩ => (certificate[n]?).map (e, ·) + let zip := enum_inputs.filterMap fun ⟨e, n⟩ => (certificate[n]?).map (e, ·) let mls ← zip.mapM fun ⟨e, n⟩ => do mulExpr n (← leftOfIneqProof e) -- `sm` is the sum of input terms, scaled to cancel out all variables. let sm ← addExprs mls diff --git a/Mathlib/Tactic/Linter/TextBased.lean b/Mathlib/Tactic/Linter/TextBased.lean index 5786f3360de33..babc21254285c 100644 --- a/Mathlib/Tactic/Linter/TextBased.lean +++ b/Mathlib/Tactic/Linter/TextBased.lean @@ -201,9 +201,9 @@ section /-- Lint on any occurrences of the string "Adaptation note:" or variants thereof. -/ def adaptationNoteLinter : TextbasedLinter := fun lines ↦ Id.run do let mut errors := Array.mkEmpty 0 - for (line, idx) in lines.zipWithIndex do + for h : idx in [:lines.size] do -- We make this shorter to catch "Adaptation note", "adaptation note" and a missing colon. - if line.containsSubstr "daptation note" then + if lines[idx].containsSubstr "daptation note" then errors := errors.push (StyleError.adaptationNote, idx + 1) return (errors, none) @@ -212,7 +212,8 @@ def adaptationNoteLinter : TextbasedLinter := fun lines ↦ Id.run do def trailingWhitespaceLinter : TextbasedLinter := fun lines ↦ Id.run do let mut errors := Array.mkEmpty 0 let mut fixedLines := lines - for (line, idx) in lines.zipWithIndex do + for h : idx in [:lines.size] do + let line := lines[idx] if line.back == ' ' then errors := errors.push (StyleError.trailingWhitespace, idx + 1) fixedLines := fixedLines.set! idx line.trimRight diff --git a/Mathlib/Tactic/Linter/UnusedTactic.lean b/Mathlib/Tactic/Linter/UnusedTactic.lean index 807699e1024c3..379ef18d2ff6a 100644 --- a/Mathlib/Tactic/Linter/UnusedTactic.lean +++ b/Mathlib/Tactic/Linter/UnusedTactic.lean @@ -5,6 +5,7 @@ Authors: Damiano Testa -/ import Lean.Elab.Command +import Lean.Parser.Syntax import Batteries.Tactic.Unreachable -- Import this linter explicitly to ensure that -- this file has a valid copyright header and module docstring. diff --git a/Mathlib/Tactic/MinImports.lean b/Mathlib/Tactic/MinImports.lean index b841e9bad9942..57ad4068615bf 100644 --- a/Mathlib/Tactic/MinImports.lean +++ b/Mathlib/Tactic/MinImports.lean @@ -3,10 +3,10 @@ Copyright (c) 2024 Damiano Testa. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa -/ -import Mathlib.Init -import ImportGraph.Imports import Lean.Elab.DefView import Lean.Util.CollectAxioms +import Mathlib.Init +import ImportGraph.Imports /-! # `#min_imports in` a command to find minimal imports diff --git a/Mathlib/Tactic/MkIffOfInductiveProp.lean b/Mathlib/Tactic/MkIffOfInductiveProp.lean index 2c97c99dd86ae..bc24422910a3c 100644 --- a/Mathlib/Tactic/MkIffOfInductiveProp.lean +++ b/Mathlib/Tactic/MkIffOfInductiveProp.lean @@ -191,7 +191,7 @@ def toCases (mvar : MVarId) (shape : List Shape) : MetaM Unit := do let ⟨h, mvar'⟩ ← mvar.intro1 let subgoals ← mvar'.cases h - let _ ← (shape.zip subgoals.toList).enum.mapM fun ⟨p, ⟨⟨shape, t⟩, subgoal⟩⟩ ↦ do + let _ ← (shape.zip subgoals.toList).zipIdx.mapM fun ⟨⟨⟨shape, t⟩, subgoal⟩, p⟩ ↦ do let vars := subgoal.fields let si := (shape.zip vars.toList).filterMap (fun ⟨c,v⟩ ↦ if c then some v else none) let mvar'' ← select p (subgoals.size - 1) subgoal.mvarId diff --git a/Mathlib/Tactic/MoveAdd.lean b/Mathlib/Tactic/MoveAdd.lean index 5c0f00d0efe32..8ed7a04de0339 100644 --- a/Mathlib/Tactic/MoveAdd.lean +++ b/Mathlib/Tactic/MoveAdd.lean @@ -169,7 +169,7 @@ similarly for the pairs with second coordinate equal to `false`. def weight (L : List (α × Bool)) (a : α) : ℤ := let l := L.length match L.find? (Prod.fst · == a) with - | some (_, b) => if b then - l + (L.indexOf (a, b) : ℤ) else (L.indexOf (a, b) + 1 : ℤ) + | some (_, b) => if b then - l + (L.idxOf (a, b) : ℤ) else (L.idxOf (a, b) + 1 : ℤ) | none => 0 /-- `reorderUsing toReorder instructions` produces a reordering of `toReorder : List α`, @@ -196,7 +196,7 @@ def reorderUsing (toReorder : List α) (instructions : List (α × Bool)) : List let reorder := uToReorder.qsort fun x y => match uInstructions.find? (Prod.fst · == x), uInstructions.find? (Prod.fst · == y) with | none, none => - ((uToReorder.indexOf? x).map Fin.val).get! ≤ ((uToReorder.indexOf? y).map Fin.val).get! + (uToReorder.idxOf? x).get! ≤ (uToReorder.idxOf? y).get! | _, _ => weight uInstructions x ≤ weight uInstructions y (reorder.map Prod.fst).toList diff --git a/Mathlib/Tactic/Widget/StringDiagram.lean b/Mathlib/Tactic/Widget/StringDiagram.lean index 0a6871ad89cdc..f72bf44ff6397 100644 --- a/Mathlib/Tactic/Widget/StringDiagram.lean +++ b/Mathlib/Tactic/Widget/StringDiagram.lean @@ -186,12 +186,12 @@ variable {ρ : Type} [MonadMor₁ (CoherenceM ρ)] /-- The list of nodes at the top of a string diagram. -/ def topNodes (η : WhiskerLeft) : CoherenceM ρ (List Node) := do - return (← η.srcM).toList.enum.map (fun (i, f) => .id ⟨0, i, i, f⟩) + return (← η.srcM).toList.mapIdx fun i f => .id ⟨0, i, i, f⟩ /-- The list of nodes at the top of a string diagram. The position is counted from the specified natural number. -/ def NormalExpr.nodesAux (v : ℕ) : NormalExpr → CoherenceM ρ (List (List Node)) - | NormalExpr.nil _ α => return [(← α.srcM).toList.enum.map (fun (i, f) => .id ⟨v, i, i, f⟩)] + | NormalExpr.nil _ α => return [(← α.srcM).toList.mapIdx fun i f => .id ⟨v, i, i, f⟩] | NormalExpr.cons _ _ η ηs => do let s₁ := η.nodes v 0 0 let s₂ ← ηs.nodesAux (v + 1) @@ -216,7 +216,7 @@ def NormalExpr.strands (e : NormalExpr) : CoherenceM ρ (List (List Strand)) := -- sanity check if xs.length ≠ ys.length then throwError "The number of the start and end points of a string does not match." - (xs.zip ys).enum.mapM fun (k, (n₁, f₁), (n₂, _)) => do + (xs.zip ys).mapIdxM fun k ((n₁, f₁), (n₂, _)) => do return ⟨n₁.hPosTar + k, n₁, n₂, f₁⟩ end BicategoryLike diff --git a/MathlibTest/fun_prop_dev.lean b/MathlibTest/fun_prop_dev.lean index 866e3b6aebefa..8128212a89b5f 100644 --- a/MathlibTest/fun_prop_dev.lean +++ b/MathlibTest/fun_prop_dev.lean @@ -393,7 +393,7 @@ example (f : β → γ) (g : α → β) (h : B) : Con (fun x => f (g x)) := by f end MultipleLambdaTheorems -/-- warning: `?m` is not a `fun_prop` goal! -/ +/-- info: `?m` is not a `fun_prop` goal! -/ #guard_msgs in #check_failure ((by fun_prop) : ?m) diff --git a/lake-manifest.json b/lake-manifest.json index 029c55215aa62..33e37d07b8f18 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -5,7 +5,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "e104724db91693a3a088c5fdd76cff4fac331739", + "rev": "59a8514bb0ee5bae2689d8be717b5272c9b3dc1c", "name": "plausible", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -25,7 +25,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "1a6613663c3eb08c401ce0fd1a408412f2c2321e", + "rev": "5013810061a18ca1f5510106172b94c6fbd0a2fc", "name": "importGraph", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -35,7 +35,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "dafff53912eac07a1a983080df61df10f622fe25", + "rev": "8fff3f074da9237cd4e179fd6dd89be6c4022d41", "name": "proofwidgets", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -45,7 +45,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "44dab9f36aa73d5f789629b55528c5a1501877a6", + "rev": "ba9a63be53f16b3b6e4043641c6bad4883e650b4", "name": "aesop", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -65,7 +65,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "01006c9e86bf9e397c026fef4190478dd1fd897e", + "rev": "512d7fa38234139a34c04e3b3438fc142b51bbee", "name": "batteries", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -75,7 +75,7 @@ "type": "git", "subDir": null, "scope": "leanprover", - "rev": "0c8ea32a15a4f74143e4e1e107ba2c412adb90fd", + "rev": "a2eb24a3dbf681f2b655f82ba5ee5b139d4a5abc", "name": "Cli", "manifestFile": "lake-manifest.json", "inputRev": "main", diff --git a/lean-toolchain b/lean-toolchain index 8b4f470c73e01..3ca992cf968f8 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.16.0 \ No newline at end of file +leanprover/lean4:v4.17.0-rc1 diff --git a/scripts/noshake.json b/scripts/noshake.json index c41910752e88b..c8aeb867d26d7 100644 --- a/scripts/noshake.json +++ b/scripts/noshake.json @@ -247,7 +247,8 @@ ["Mathlib.Algebra.Group.Basic", "Mathlib.Init.Order.LinearOrder"], "Mathlib.Tactic.Measurability": ["Mathlib.Algebra.Group.Defs", "Mathlib.Tactic.Measurability.Init"], - "Mathlib.Tactic.Linter.UnusedTactic": ["Batteries.Tactic.Unreachable"], + "Mathlib.Tactic.Linter.UnusedTactic": + ["Batteries.Tactic.Unreachable", "Lean.Parser.Syntax"], "Mathlib.Tactic.LinearCombination": ["Mathlib.Tactic.LinearCombination.Lemmas"], "Mathlib.Tactic.Lemma": ["Lean.Parser.Command"], From 740a8370e3f2f7f8df97edf5b31a09c368466a88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Mon, 3 Feb 2025 19:15:25 +0000 Subject: [PATCH 048/103] feat(CategoryTheory/SmallObject): promote a construction from `Over` to `Arrow` (#20260) With this change, in the proof of the small object arguments (#20245), we shall get a functorial factorization instance `HasFunctorialFactorization` instead of `HasFactorization`. --- .../SmallObject/Construction.lean | 149 ++++++++++-------- 1 file changed, 84 insertions(+), 65 deletions(-) diff --git a/Mathlib/CategoryTheory/SmallObject/Construction.lean b/Mathlib/CategoryTheory/SmallObject/Construction.lean index 4a30175a01a6c..333e74170d002 100644 --- a/Mathlib/CategoryTheory/SmallObject/Construction.lean +++ b/Mathlib/CategoryTheory/SmallObject/Construction.lean @@ -9,10 +9,10 @@ import Mathlib.CategoryTheory.Limits.Shapes.Pullback.HasPullback /-! # Construction for the small object argument -Given a family of morphisms `f i : A i ⟶ B i` in a category `C` -and an object `S : C`, we define a functor -`SmallObject.functor f S : Over S ⥤ Over S` which sends -an object given by `πX : X ⟶ S` to the pushout `functorObj f πX`: +Given a family of morphisms `f i : A i ⟶ B i` in a category `C`, +we define a functor +`SmallObject.functor f : Arrow S ⥤ Arrow S` which sends +an object given by arrow `πX : X ⟶ S` to the pushout `functorObj f πX`: ``` ∐ functorObjSrcFamily f πX ⟶ X @@ -20,7 +20,7 @@ an object given by `πX : X ⟶ S` to the pushout `functorObj f πX`: | | v v -∐ functorObjTgtFamily f πX ⟶ functorObj f S πX +∐ functorObjTgtFamily f πX ⟶ functorObj f πX ``` where the morphism on the left is a coproduct (of copies of maps `f i`) indexed by a type `FunctorObjIndex f πX` which parametrizes the @@ -33,8 +33,8 @@ A i ⟶ X B i ⟶ S ``` -The morphism `ιFunctorObj f S πX : X ⟶ functorObj f πX` is part of -a natural transformation `SmallObject.ε f S : 𝟭 (Over S) ⟶ functor f S`. +The morphism `ιFunctorObj f πX : X ⟶ functorObj f πX` is part of +a natural transformation `SmallObject.ε f : 𝟭 (Arrow C) ⟶ functor f S`. The main idea in this construction is that for any commutative square as above, there may not exist a lifting `B i ⟶ X`, but the construction provides a tautological morphism `B i ⟶ functorObj f πX` @@ -62,7 +62,7 @@ variable {C : Type u} [Category.{v} C] {I : Type w} {A B : I → C} (f : ∀ i, section -variable {S : C} {X Y : C} (πX : X ⟶ S) (πY : Y ⟶ S) (φ : X ⟶ Y) +variable {S X : C} (πX : X ⟶ S) /-- Given a family of morphisms `f i : A i ⟶ B i` and a morphism `πX : X ⟶ S`, this type parametrizes the commutative squares with a morphism `f i` on the left @@ -79,7 +79,6 @@ structure FunctorObjIndex where attribute [reassoc (attr := simp)] FunctorObjIndex.w variable [HasColimitsOfShape (Discrete (FunctorObjIndex f πX)) C] - [HasColimitsOfShape (Discrete (FunctorObjIndex f πY)) C] /-- The family of objects `A x.i` parametrized by `x : FunctorObjIndex f πX`. -/ abbrev functorObjSrcFamily (x : FunctorObjIndex f πX) : C := A x.i @@ -101,10 +100,9 @@ noncomputable abbrev functorObjLeft : ∐ functorObjSrcFamily f πX ⟶ ∐ functorObjTgtFamily f πX := Limits.Sigma.map (functorObjLeftFamily f πX) -section variable [HasPushout (functorObjTop f πX) (functorObjLeft f πX)] -/-- The functor `SmallObject.functor f S : Over S ⥤ Over S` that is part of +/-- The functor `SmallObject.functor f : Arrow C ⥤ Arrow C` that is part of the small object argument for a family of morphisms `f`, on an object given as a morphism `πX : X ⟶ S`. -/ noncomputable abbrev functorObj : C := @@ -141,79 +139,92 @@ lemma ρFunctorObj_π : ρFunctorObj f πX ≫ πFunctorObj f πX = π'FunctorOb lemma ιFunctorObj_πFunctorObj : ιFunctorObj f πX ≫ πFunctorObj f πX = πX := by simp [ιFunctorObj, πFunctorObj] -/-- The canonical morphism `∐ (functorObjSrcFamily f πX) ⟶ ∐ (functorObjSrcFamily f πY)` -induced by a morphism in `φ : X ⟶ Y` such that `φ ≫ πX = πY`. -/ -noncomputable def functorMapSrc (hφ : φ ≫ πY = πX) : - ∐ (functorObjSrcFamily f πX) ⟶ ∐ functorObjSrcFamily f πY := - Sigma.map' (fun x => FunctorObjIndex.mk x.i (x.t ≫ φ) x.b (by simp [hφ])) (fun _ => 𝟙 _) +section -end +variable {S T X Y : C} {πX : X ⟶ S} {πY : Y ⟶ T} (τ : Arrow.mk πX ⟶ Arrow.mk πY) + [HasColimitsOfShape (Discrete (FunctorObjIndex f πX)) C] + [HasColimitsOfShape (Discrete (FunctorObjIndex f πY)) C] -variable (hφ : φ ≫ πY = πX) +/-- The canonical morphism `∐ (functorObjSrcFamily f πX) ⟶ ∐ (functorObjSrcFamily f πY)` +induced by a morphism `Arrow.mk πX ⟶ Arrow.mk πY`. -/ +noncomputable def functorMapSrc : + ∐ (functorObjSrcFamily f πX) ⟶ ∐ functorObjSrcFamily f πY := + Sigma.map' (fun x => FunctorObjIndex.mk x.i (x.t ≫ τ.left) (x.b ≫ τ.right) (by simp)) + (fun _ => 𝟙 _) @[reassoc] lemma ι_functorMapSrc (i : I) (t : A i ⟶ X) (b : B i ⟶ S) (w : t ≫ πX = f i ≫ b) - (t' : A i ⟶ Y) (fac : t ≫ φ = t') : - Sigma.ι _ (FunctorObjIndex.mk i t b w) ≫ functorMapSrc f πX πY φ hφ = + (b' : B i ⟶ T) (hb' : b ≫ τ.right = b') + (t' : A i ⟶ Y) (ht' : t ≫ τ.left = t') : + Sigma.ι _ (FunctorObjIndex.mk i t b w) ≫ functorMapSrc f τ = Sigma.ι (functorObjSrcFamily f πY) - (FunctorObjIndex.mk i t' b (by rw [← w, ← fac, assoc, hφ])) := by - subst fac + (FunctorObjIndex.mk i t' b' (by + have := τ.w + dsimp at this + rw [← hb', ← reassoc_of% w, ← ht', assoc, this])) := by + subst hb' ht' simp [functorMapSrc] @[reassoc (attr := simp)] lemma functorMapSrc_functorObjTop : - functorMapSrc f πX πY φ hφ ≫ functorObjTop f πY = functorObjTop f πX ≫ φ := by + functorMapSrc f τ ≫ functorObjTop f πY = functorObjTop f πX ≫ τ.left := by ext ⟨i, t, b, w⟩ - simp [ι_functorMapSrc_assoc f πX πY φ hφ i t b w _ rfl] + simp [ι_functorMapSrc_assoc f τ i t b w _ rfl] /-- The canonical morphism `∐ functorObjTgtFamily f πX ⟶ ∐ functorObjTgtFamily f πY` -induced by a morphism in `φ : X ⟶ Y` such that `φ ≫ πX = πY`. -/ -noncomputable def functorMapTgt (hφ : φ ≫ πY = πX) : +induced by a morphism `Arrow.mk πX ⟶ Arrow.mk πY`. -/ +noncomputable def functorMapTgt : ∐ functorObjTgtFamily f πX ⟶ ∐ functorObjTgtFamily f πY := - Sigma.map' (fun x => FunctorObjIndex.mk x.i (x.t ≫ φ) x.b (by simp [hφ])) (fun _ => 𝟙 _) + Sigma.map' (fun x => FunctorObjIndex.mk x.i (x.t ≫ τ.left) (x.b ≫ τ.right) (by simp)) + (fun _ => 𝟙 _) @[reassoc] lemma ι_functorMapTgt (i : I) (t : A i ⟶ X) (b : B i ⟶ S) (w : t ≫ πX = f i ≫ b) - (t' : A i ⟶ Y) (fac : t ≫ φ = t') : - Sigma.ι _ (FunctorObjIndex.mk i t b w) ≫ functorMapTgt f πX πY φ hφ = + (b' : B i ⟶ T) (hb' : b ≫ τ.right = b') + (t' : A i ⟶ Y) (ht' : t ≫ τ.left = t') : + Sigma.ι _ (FunctorObjIndex.mk i t b w) ≫ functorMapTgt f τ = Sigma.ι (functorObjTgtFamily f πY) - (FunctorObjIndex.mk i t' b (by rw [← w, ← fac, assoc, hφ])) := by - subst fac + (FunctorObjIndex.mk i t' b' (by + have := τ.w + dsimp at this + rw [← hb', ← reassoc_of% w, ← ht', assoc, this])) := by + subst hb' ht' simp [functorMapTgt] lemma functorMap_comm : - functorObjLeft f πX ≫ functorMapTgt f πX πY φ hφ = - functorMapSrc f πX πY φ hφ ≫ functorObjLeft f πY := by + functorObjLeft f πX ≫ functorMapTgt f τ = + functorMapSrc f τ ≫ functorObjLeft f πY := by ext ⟨i, t, b, w⟩ simp only [ι_colimMap_assoc, Discrete.natTrans_app, ι_colimMap, - ι_functorMapTgt f πX πY φ hφ i t b w _ rfl, - ι_functorMapSrc_assoc f πX πY φ hφ i t b w _ rfl] + ι_functorMapTgt f τ i t b w _ rfl, + ι_functorMapSrc_assoc f τ i t b w _ rfl] variable [HasPushout (functorObjTop f πX) (functorObjLeft f πX)] [HasPushout (functorObjTop f πY) (functorObjLeft f πY)] -/-- The functor `SmallObject.functor f S : Over S ⥤ Over S` that is part of +/-- The functor `SmallObject.functor f S : Arrow S ⥤ Arrow S` that is part of the small object argument for a family of morphisms `f`, on morphisms. -/ noncomputable def functorMap : functorObj f πX ⟶ functorObj f πY := - pushout.map _ _ _ _ φ (functorMapTgt f πX πY φ hφ) (functorMapSrc f πX πY φ hφ) (by simp) - (functorMap_comm f πX πY φ hφ) + pushout.map _ _ _ _ τ.left (functorMapTgt f τ) (functorMapSrc f τ) (by simp) + (functorMap_comm f τ) @[reassoc (attr := simp)] -lemma functorMap_π : functorMap f πX πY φ hφ ≫ πFunctorObj f πY = πFunctorObj f πX := by +lemma functorMap_π : functorMap f τ ≫ πFunctorObj f πY = πFunctorObj f πX ≫ τ.right := by ext ⟨i, t, b, w⟩ - · simp [functorMap, hφ] - · simp [functorMap, ι_functorMapTgt_assoc f πX πY φ hφ i t b w _ rfl] + · simp [functorMap] + · simp [functorMap, ι_functorMapTgt_assoc f τ i t b w _ rfl] variable (X) in @[simp] -lemma functorMap_id : functorMap f πX πX (𝟙 X) (by simp) = 𝟙 _ := by +lemma functorMap_id : functorMap f (𝟙 (Arrow.mk πX)) = 𝟙 _ := by ext ⟨i, t, b, w⟩ · simp [functorMap] - · simp [functorMap, ι_functorMapTgt_assoc f πX πX (𝟙 X) (by simp) i t b w t (by simp)] + · simp [functorMap, + ι_functorMapTgt_assoc f (𝟙 (Arrow.mk πX)) i t b w b (by simp) t (by simp)] @[reassoc (attr := simp)] lemma ιFunctorObj_naturality : - ιFunctorObj f πX ≫ functorMap f πX πY φ hφ = φ ≫ ιFunctorObj f πY := by + ιFunctorObj f πX ≫ functorMap f τ = τ.left ≫ ιFunctorObj f πY := by simp [ιFunctorObj, functorMap] lemma ιFunctorObj_extension {i : I} (t : A i ⟶ X) (b : B i ⟶ S) @@ -225,31 +236,39 @@ lemma ιFunctorObj_extension {i : I} (t : A i ⟶ X) (b : B i ⟶ S) end -variable (S : C) [HasPushouts C] - [∀ {X : C} (πX : X ⟶ S), HasColimitsOfShape (Discrete (FunctorObjIndex f πX)) C] +variable [HasPushouts C] + [∀ {X S : C} (πX : X ⟶ S), HasColimitsOfShape (Discrete (FunctorObjIndex f πX)) C] -/-- The functor `Over S ⥤ Over S` that is constructed in order to apply the small +/-- The functor `Arrow C ⥤ Arrow C` that is constructed in order to apply the small object argument to a family of morphisms `f i : A i ⟶ B i`, see the introduction of the file `Mathlib.CategoryTheory.SmallObject.Construction` -/ @[simps! obj map] -noncomputable def functor : Over S ⥤ Over S where - obj π := Over.mk (πFunctorObj f π.hom) - map {π₁ π₂} φ := Over.homMk (functorMap f π₁.hom π₂.hom φ.left (Over.w φ)) - map_id _ := by ext; dsimp; simp - map_comp {π₁ π₂ π₃} φ φ' := by - ext1 - dsimp - ext ⟨i, t, b, w⟩ - · simp - · simp [functorMap, ι_functorMapTgt_assoc f π₁.hom π₂.hom φ.left (Over.w φ) i t b w _ rfl, - ι_functorMapTgt_assoc f π₁.hom π₃.hom (φ.left ≫ φ'.left) (Over.w (φ ≫ φ')) i t b w _ rfl, - ι_functorMapTgt_assoc f π₂.hom π₃.hom (φ'.left) (Over.w φ') i (t ≫ φ.left) b - (by simp [w]) (t ≫ φ.left ≫ φ'.left) (by simp)] - -/-- The canonical natural transformation `𝟭 (Over S) ⟶ functor f S`. -/ -@[simps! app] -noncomputable def ε : 𝟭 (Over S) ⟶ functor f S where - app w := Over.homMk (ιFunctorObj f w.hom) +noncomputable def functor : Arrow C ⥤ Arrow C where + obj π := Arrow.mk (πFunctorObj f π.hom) + map {π₁ π₂} τ := Arrow.homMk (functorMap f τ) τ.right + map_id g := by + ext + · apply functorMap_id + · dsimp + map_comp {π₁ π₂ π₃} τ τ' := by + ext + · dsimp + simp [functorMap] + ext ⟨i, t, b, w⟩ + · simp + · simp [ι_functorMapTgt_assoc f τ i t b w _ rfl _ rfl, + ι_functorMapTgt_assoc f (τ ≫ τ') i t b w _ rfl _ rfl, + ι_functorMapTgt_assoc f τ' i (t ≫ τ.left) (b ≫ τ.right) + (by simp [reassoc_of% w]) (b ≫ τ.right ≫ τ'.right) (by simp) + (t ≫ (τ ≫ τ').left) (by simp)] + · dsimp + +/-- The canonical natural transformation `𝟭 (Arrow C) ⟶ functor f`. -/ +@[simps app] +noncomputable def ε : 𝟭 (Arrow C) ⟶ functor f where + app π := Arrow.homMk (ιFunctorObj f π.hom) (𝟙 _) + +end end SmallObject From 96a5ba5ce504f8b8e6acd659015e46e641d7af10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= <37772949+joelriou@users.noreply.github.com> Date: Mon, 3 Feb 2025 20:04:14 +0000 Subject: [PATCH 049/103] refactor(CategoryTheory/SmallObject): generalization of the definitions (#20256) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ongoing definition of the iteration of a natural transformation `ε : 𝟭 C ⟶ F` (with `F : C ⥤ C`) is generalized to "successor structures" (which shall become a mathlibism), i.e. in a category `D`, this consists of a zeroth object `X₀`, a successor application `succ : D → D` and, for all `X : D`, a map `toSucc X : X → succ X` (which does not have to be natural: it is not always so in some applications). For such a `Φ : SuccStruct D`, if `J` is a well-ordered type, we define the `J`-th iteration of `Φ`. (In the case `J := ℕ`, this is the colimit of `succ (succ (succ (succ ... X₀)))`.) The iteration of a functor is a particular case of this constructor with `D := C ⥤ C`. As `toSucc` does not have to be natural in `X`, the caveat is that the proofs make extensive use of equalities of objects in `C` and `Arrow C`, while my previous construction used comparison isomorphisms. Nevertheless, the proofs look much more clean now. One of the reasons is that in the inductive construction (file `Iteration.Nonempty`), in the terms of data, we only need to provide a functor, and then all the fields are in `Prop`. (In the downstream API, we shall obviously use isomorphisms instead of equalities...) This PR supersedes #19264. The results are used in #20245 in order to get functorial factorizations in the small object argument. After refactoring my code, I found that this approach had already been used in 2018 by Reid Barton in his pioneering formalization work in Lean 3 towards the model category structure on topological spaces. Co-authored-by: Joël Riou --- Mathlib.lean | 1 - .../SmallObject/Iteration/Basic.lean | 548 ++++++++++++------ .../SmallObject/Iteration/ExtendToSucc.lean | 72 ++- .../Iteration/FunctorOfCocone.lean | 38 +- .../SmallObject/Iteration/Nonempty.lean | 198 ++++--- .../SmallObject/Iteration/UniqueHom.lean | 249 -------- Mathlib/Order/Monotone/Basic.lean | 12 - 7 files changed, 569 insertions(+), 549 deletions(-) delete mode 100644 Mathlib/CategoryTheory/SmallObject/Iteration/UniqueHom.lean diff --git a/Mathlib.lean b/Mathlib.lean index 60a6904ec63fe..4d002f3a687f9 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2268,7 +2268,6 @@ import Mathlib.CategoryTheory.SmallObject.Iteration.Basic import Mathlib.CategoryTheory.SmallObject.Iteration.ExtendToSucc import Mathlib.CategoryTheory.SmallObject.Iteration.FunctorOfCocone import Mathlib.CategoryTheory.SmallObject.Iteration.Nonempty -import Mathlib.CategoryTheory.SmallObject.Iteration.UniqueHom import Mathlib.CategoryTheory.SmallObject.TransfiniteCompositionLifting import Mathlib.CategoryTheory.SmallObject.WellOrderInductionData import Mathlib.CategoryTheory.Square diff --git a/Mathlib/CategoryTheory/SmallObject/Iteration/Basic.lean b/Mathlib/CategoryTheory/SmallObject/Iteration/Basic.lean index d739917e114af..af7544acc81f5 100644 --- a/Mathlib/CategoryTheory/SmallObject/Iteration/Basic.lean +++ b/Mathlib/CategoryTheory/SmallObject/Iteration/Basic.lean @@ -4,59 +4,84 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Joël Riou -/ import Mathlib.CategoryTheory.Category.Preorder -import Mathlib.CategoryTheory.Limits.IsLimit +import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic +import Mathlib.CategoryTheory.Limits.Shapes.Preorder.HasIterationOfShape +import Mathlib.CategoryTheory.Limits.Shapes.Preorder.PrincipalSeg +import Mathlib.CategoryTheory.Limits.Comma import Mathlib.Order.ConditionallyCompleteLattice.Basic import Mathlib.Order.SuccPred.Limit - -/-! # Transfinite iterations of a functor - -In this file, given a functor `Φ : C ⥤ C` and a natural transformation -`ε : 𝟭 C ⟶ Φ`, we shall define the transfinite iterations of `Φ` (TODO). - -Given `j : J` where `J` is a well ordered set, we first introduce -a category `Iteration ε j`. An object in this category consists of -a functor `F : Set.Iic j ⥤ C ⥤ C` equipped with the data -which makes it the `i`th-iteration of `Φ` for all `i` such that `i ≤ j`. -Under suitable assumptions on `C`, we shall show that this category -`Iteration ε j` is equivalent to the punctual category (TODO). -In this file, we show that the there is at most one morphism between -two objects. In `SmallObject.Iteration.UniqueHom`, we shall show -that there does always exist a unique morphism between -two objects (TODO). Then, we shall show the existence of -an object (TODO). In these proofs, which are all done using -transfinite induction, we have to treat three cases separately: -* the case `j = ⊥`; -* the case `j` is a successor; -* the case `j` is a limit element. +import Mathlib.Order.Interval.Set.InitialSeg + +/-! # Transfinite iterations of a successor structure + +In this file, we introduce the structure `SuccStruct` on a category `C`. +It consists of the data of an object `X₀ : C`, a successor map `succ : C → C` +and a morphism `toSucc : X ⟶ succ X` for any `X : C`. The map `toSucc` +does not have to be natural in `X`. For any element `j : J` in a +well-ordered type `J`, we would like to define +the iteration of `Φ : SuccStruct C`, as a functor `F : J ⥤ C` +such that `F.obj ⊥ = X₀`, `F.obj j ⟶ F.obj (Order.succ j)` is `toSucc (F.obj j)` +when `j` is not maximal, and when `j` is limit, `F.obj j` should be the +colimit of the `F.obj k` for `k < j`. + +In the small object argument, we shall apply this to the iteration of +a functor `F : C ⥤ C` equipped with a natural transformation `ε : 𝟭 C ⟶ F`: +this will correspond to the case of +`SuccStruct.ofNatTrans ε : SuccStruct (C ⥤ C)`, for which `X₀ := 𝟭 C`, +`succ G := G ⋙ F` and `toSucc G : G ⟶ G ⋙ F` is given by `whiskerLeft G ε`. + +The construction of the iteration of `Φ : SuccStruct C` is done +by transfinite induction, under an assumption `HasIterationOfShape C J`. +However, for a limit element `j : J`, the definition of `F.obj j` +does not involve only the objects `F.obj i` for `i < j`, but it also +involves the maps `F.obj i₁ ⟶ F.obj i₂` for `i₁ ≤ i₂ < j`. +Then, this is not a straightforward application of definitions by +transfinite induction. In order to solve this technical difficulty, +we introduce a structure `Φ.Iteration j` for any `j : J`. This +structure contains all the expected data and properties for +all the indices that are `≤ j`. In this file, we show that +`Φ.Iteration j` is a subsingleton. The existence shall be +obtained in the file `SmallObject.Iteration.Nonempty`, and +the construction of the functor `Φ.iterationFunctor J : J ⥤ C` +and of its colimit `Φ.iteration J : C` will done in the +file `SmallObject.TransfiniteIteration`. + +The map `Φ.toSucc X : X ⟶ Φ.succ X` does not have to be natural +(and it is not in certain applications). Then, two isomorphic +objects `X` and `Y` may have non isomorphic successors. This is +the reason why we make an extensive use of equalities in +`C` and in `Arrow C` in the definitions. + +## Note + +The iteration was first introduced in mathlib by Joël Riou, using +a different approach as the one described above. After refactoring +his code, he found that the approach described above had already +been used in the pioneering formalization work in Lean 3 by +Reid Barton in 2018 towards the model category structure on +topological spaces. -/ -universe u +universe w v v' u u' namespace CategoryTheory open Category Limits -variable {C : Type*} [Category C] {Φ : C ⥤ C} (ε : 𝟭 C ⟶ Φ) {J : Type u} - -namespace Functor - -namespace Iteration +namespace SmallObject -variable [Preorder J] {j : J} (F : Set.Iic j ⥤ C) +variable {C : Type u} [Category.{v} C] {J : Type w} -/-- The map `F.obj ⟨i, _⟩ ⟶ F.obj ⟨Order.succ i, _⟩` when `F : Set.Iic j ⥤ C` -and `i : J` is such that `i < j`. -/ -noncomputable abbrev mapSucc' [SuccOrder J] (i : J) (hi : i < j) : - F.obj ⟨i, hi.le⟩ ⟶ F.obj ⟨Order.succ i, Order.succ_le_of_lt hi⟩ := - F.map <| homOfLE <| Subtype.mk_le_mk.2 <| Order.le_succ i +section -variable {i : J} (hi : i ≤ j) +variable [PartialOrder J] {j : J} (F : Set.Iic j ⥤ C) {i : J} (hi : i ≤ j) /-- The functor `Set.Iio i ⥤ C` obtained by "restriction" of `F : Set.Iic j ⥤ C` when `i ≤ j`. -/ def restrictionLT : Set.Iio i ⥤ C := - (monotone_inclusion_lt_le_of_le hi).functor ⋙ F + (Set.principalSegIioIicOfLE hi).monotone.functor ⋙ F + @[simp] lemma restrictionLT_obj (k : J) (hk : k < i) : @@ -68,18 +93,14 @@ lemma restrictionLT_map {k₁ k₂ : Set.Iio i} (φ : k₁ ⟶ k₂) : /-- Given `F : Set.Iic j ⥤ C`, `i : J` such that `hi : i ≤ j`, this is the cocone consisting of all maps `F.obj ⟨k, hk⟩ ⟶ F.obj ⟨i, hi⟩` for `k : J` such that `k < i`. -/ -@[simps] -def coconeOfLE : Cocone (restrictionLT F hi) where - pt := F.obj ⟨i, hi⟩ - ι := - { app := fun ⟨k, hk⟩ => F.map (homOfLE (by simpa using hk.le)) - naturality := fun ⟨k₁, hk₁⟩ ⟨k₂, hk₂⟩ _ => by - simp [comp_id, ← Functor.map_comp, homOfLE_comp] } +@[simps!] +def coconeOfLE : Cocone (restrictionLT F hi) := + (Set.principalSegIioIicOfLE hi).cocone F /-- The functor `Set.Iic i ⥤ C` obtained by "restriction" of `F : Set.Iic j ⥤ C` when `i ≤ j`. -/ def restrictionLE : Set.Iic i ⥤ C := - (monotone_inclusion_le_le_of_le hi).functor ⋙ F + (Set.initialSegIicIicOfLE hi).monotone.functor ⋙ F @[simp] lemma restrictionLE_obj (k : J) (hk : k ≤ i) : @@ -89,187 +110,334 @@ lemma restrictionLE_obj (k : J) (hk : k ≤ i) : lemma restrictionLE_map {k₁ k₂ : Set.Iic i} (φ : k₁ ⟶ k₂) : (restrictionLE F hi).map φ = F.map (homOfLE (by simpa using leOfHom φ)) := rfl -end Iteration +end -/-- The category of `j`th iterations of a functor `Φ` equipped with a natural -transformation `ε : 𝟭 C ⟶ Φ`. An object consists of the data of all iterations -of `Φ` for `i : J` such that `i ≤ j` (this is the field `F`). Such objects are -equipped with data and properties which characterizes the iterations up to a unique -isomorphism for the three types of elements: `⊥`, successors, limit elements. -/ -structure Iteration [Preorder J] [OrderBot J] [SuccOrder J] (j : J) where - /-- The data of all `i`th iterations for `i : J` such that `i ≤ j`. -/ - F : Set.Iic j ⥤ C ⥤ C - /-- The zeroth iteration is the identity functor. -/ - isoZero : F.obj ⟨⊥, bot_le⟩ ≅ 𝟭 C - /-- The iteration on a successor element is obtained by composition of - the previous iteration with `Φ`. -/ - isoSucc (i : J) (hi : i < j) : F.obj ⟨Order.succ i, Order.succ_le_of_lt hi⟩ ≅ F.obj ⟨i, hi.le⟩ ⋙ Φ - /-- The natural map from an iteration to its successor is induced by `ε`. -/ - mapSucc'_eq (i : J) (hi : i < j) : - Iteration.mapSucc' F i hi = whiskerLeft _ ε ≫ (isoSucc i hi).inv - /-- If `i` is a limit element, the `i`th iteration is the colimit - of `k`th iterations for `k < i`. -/ - isColimit (i : J) (hi : Order.IsSuccLimit i) (hij : i ≤ j) : - IsColimit (Iteration.coconeOfLE F hij) +variable (C) in +/-- A successor structure on a category consists of the +data of an object `succ X` for any `X : C`, a map `toSucc X : X ⟶ toSucc X` +(which does not need to be natural), and a zeroth object `X₀`. +-/ +structure SuccStruct where + /-- the zeroth object -/ + X₀ : C + /-- the successor of an object -/ + succ (X : C) : C + /-- the map to the successor -/ + toSucc (X : C) : X ⟶ succ X + +namespace SuccStruct + +/-- Given a functor `Φ : C ⥤ C`, a natural transformation of the form `𝟭 C ⟶ Φ` +induces a successor structure on `C ⥤ C`. -/ +@[simps] +def ofNatTrans {F : C ⥤ C} (ε : 𝟭 C ⟶ F) : SuccStruct (C ⥤ C) where + succ G := G ⋙ F + toSucc G := whiskerLeft G ε + X₀ := 𝟭 C -namespace Iteration +variable (Φ : SuccStruct C) -variable {ε} -variable {j : J} +/-- The class of morphisms that are of the form `toSucc X : X ⟶ succ X`. -/ +def prop : MorphismProperty C := .ofHoms (fun (X : C) ↦ Φ.toSucc X) + +lemma prop_toSucc (X : C) : Φ.prop (Φ.toSucc X) := ⟨_⟩ + +/-- The map `Φ.toSucc X : X ⟶ Φ.Succ X`, as an element in `Arrow C`. -/ +def toSuccArrow (X : C) : Arrow C := Arrow.mk (Φ.toSucc X) + +lemma prop_iff {X Y : C} (f : X ⟶ Y) : + Φ.prop f ↔ Arrow.mk f = Φ.toSuccArrow X := by + constructor + · rintro ⟨_⟩ + rfl + · intro h + rw [← Φ.prop.arrow_mk_mem_toSet_iff, h] + apply prop_toSucc + +variable [LinearOrder J] + +/-- Given a functor `F : Set.Iic ⥤ C`, this is the morphism in `C`, as an element +in `Arrow C`, that is obtained by applying `F.map` to an inequality. -/ +def arrowMap {j : J} (F : Set.Iic j ⥤ C) (i₁ i₂ : J) (h₁₂ : i₁ ≤ i₂) (h₂ : i₂ ≤ j) : + Arrow C := + Arrow.mk (F.map (homOfLE h₁₂ : ⟨i₁, h₁₂.trans h₂⟩ ⟶ ⟨i₂, h₂⟩)) + +@[simp] +lemma arrowMap_refl {j : J} (F : Set.Iic j ⥤ C) (i : J) (hi : i ≤ j) : + arrowMap F i i (by simp) hi = Arrow.mk (𝟙 (F.obj ⟨i, hi⟩)) := by + simp [arrowMap] + +lemma arrowMap_restrictionLE {j : J} (F : Set.Iic j ⥤ C) {j' : J} (hj' : j' ≤ j) + (i₁ i₂ : J) (h₁₂ : i₁ ≤ i₂) (h₂ : i₂ ≤ j') : + arrowMap (restrictionLE F hj') i₁ i₂ h₁₂ h₂ = + arrowMap F i₁ i₂ h₁₂ (h₂.trans hj') := rfl section -variable [Preorder J] [OrderBot J] [SuccOrder J] (iter : Φ.Iteration ε j) +variable [SuccOrder J] {j : J} (F : Set.Iic j ⥤ C) (i : J) (hi : i < j) -/-- For `iter : Φ.Iteration.ε j`, this is the map -`iter.F.obj ⟨i, _⟩ ⟶ iter.F.obj ⟨Order.succ i, _⟩` if `i : J` is such that `i < j`. -/ -noncomputable abbrev mapSucc (i : J) (hi : i < j) : - iter.F.obj ⟨i, hi.le⟩ ⟶ iter.F.obj ⟨Order.succ i, Order.succ_le_of_lt hi⟩ := - mapSucc' iter.F i hi +/-- Given a functor `F : Set.Iic j ⥤ C` and `i : J` such that `i < j`, +this is the arrow `F.obj ⟨i, _⟩ ⟶ F.obj ⟨Order.succ i, _⟩`. -/ +def arrowSucc : Arrow C := + arrowMap F i (Order.succ i) (Order.le_succ i) (Order.succ_le_of_lt hi) -lemma mapSucc_eq (i : J) (hi : i < j) : - iter.mapSucc i hi = whiskerLeft _ ε ≫ (iter.isoSucc i hi).inv := - iter.mapSucc'_eq _ hi +lemma arrowSucc_def : + arrowSucc F i hi = arrowMap F i (Order.succ i) (Order.le_succ i) (Order.succ_le_of_lt hi) := + rfl end section -variable [Preorder J] [OrderBot J] [SuccOrder J] (iter₁ iter₂ : Φ.Iteration ε j) +variable [HasIterationOfShape J C] + {i : J} (F : Set.Iio i ⥤ C) (hi : Order.IsSuccLimit i) (k : J) (hk : k < i) -/-- A morphism between two objects `iter₁` and `iter₂` in the -category `Φ.Iteration ε j` of `j`th iterations of a functor `Φ` -equipped with a natural transformation `ε : 𝟭 C ⟶ Φ` consists of a natural -transformation `natTrans : iter₁.F ⟶ iter₂.F` which is compatible with the -isomorphisms `isoZero` and `isoSucc`. -/ -structure Hom where - /-- A natural transformation `iter₁.F ⟶ iter₂.F` -/ - natTrans : iter₁.F ⟶ iter₂.F - natTrans_app_zero : - natTrans.app ⟨⊥, bot_le⟩ = iter₁.isoZero.hom ≫ iter₂.isoZero.inv := by aesop_cat - natTrans_app_succ (i : J) (hi : i < j) : - natTrans.app ⟨Order.succ i, Order.succ_le_of_lt hi⟩ = (iter₁.isoSucc i hi).hom ≫ - whiskerRight (natTrans.app ⟨i, hi.le⟩) _ ≫ (iter₂.isoSucc i hi).inv := by aesop_cat +/-- Given `F : Set.Iio i ⥤ C`, with `i` a limit element, and `k` such that `hk : k < i`, +this is the map `colimit.ι F ⟨k, hk⟩`, as an element in `Arrow C`. -/ +noncomputable def arrowι : Arrow C := + letI := hasColimitsOfShape_of_isSuccLimit C i hi + Arrow.mk (colimit.ι F ⟨k, hk⟩) -namespace Hom +lemma arrowι_def : + letI := hasColimitsOfShape_of_isSuccLimit C i hi + arrowι F hi k hk = Arrow.mk (colimit.ι F ⟨k, hk⟩) := rfl -attribute [simp, reassoc] natTrans_app_zero +end -/-- The identity morphism in the category `Φ.Iteration ε j`. -/ -@[simps] -def id : Hom iter₁ iter₁ where - natTrans := 𝟙 _ +variable [SuccOrder J] [OrderBot J] [HasIterationOfShape J C] -variable {iter₁ iter₂} +/-- The category of `j`th iterations of a succesor structure `Φ : SuccStruct C`. +An object consists of the data of all iterations of `Φ` for `i : J` such +that `i ≤ j` (this is the field `F`). Such objects are +equipped with data and properties which characterizes uniquely the iterations +on three types of elements: `⊥`, successors, limit elements. -/ +@[ext] +structure Iteration [WellFoundedLT J] (j : J) where + /-- The data of all `i`th iterations for `i : J` such that `i ≤ j`. -/ + F : Set.Iic j ⥤ C + /-- The zeroth iteration is the zeroth object . -/ + obj_bot : F.obj ⟨⊥, bot_le⟩ = Φ.X₀ + /-- The iteration on a successor element is the successor. -/ + arrowSucc_eq (i : J) (hi : i < j) : arrowSucc F i hi = Φ.toSuccArrow (F.obj ⟨i, hi.le⟩) + /-- The iteration on a limit element identifies to the colimit of the + value on smaller elements, see `Iteration.isColimit`. -/ + arrowMap_limit (i : J) (hi : Order.IsSuccLimit i) (hij : i ≤ j) (k : J) (hk : k < i) : + arrowMap F k i hk.le hij = arrowι (restrictionLT F hij) hi k hk + +variable [WellFoundedLT J] --- Note: this is not made a global ext lemma because it is shown below --- that the type of morphisms is a subsingleton. -lemma ext' {f g : Hom iter₁ iter₂} (h : f.natTrans = g.natTrans) : f = g := by - cases f - cases g - subst h - rfl +namespace Iteration -attribute [local ext] ext' +variable {Φ} +variable {j : J} -/-- The composition of morphisms in the category `Iteration ε j`. -/ -@[simps] -def comp {iter₃ : Iteration ε j} (f : Hom iter₁ iter₂) (g : Hom iter₂ iter₃) : - Hom iter₁ iter₃ where - natTrans := f.natTrans ≫ g.natTrans - natTrans_app_succ i hi := by simp [natTrans_app_succ _ _ hi] - -instance : Category (Iteration ε j) where - Hom := Hom - id := id - comp := comp - -instance {J} {j : J} [PartialOrder J] [OrderBot J] [WellFoundedLT J] [SuccOrder J] - {iter₁ iter₂ : Iteration ε j} : - Subsingleton (iter₁ ⟶ iter₂) where - allEq f g := by - apply ext' - suffices ∀ i hi, f.natTrans.app ⟨i, hi⟩ = g.natTrans.app ⟨i, hi⟩ by - ext ⟨i, hi⟩ : 2 - apply this - intro i - induction i using SuccOrder.limitRecOn with - | hm j H => - obtain rfl := H.eq_bot - simp [natTrans_app_zero] - | hs j H IH => - intro hj - simp [Hom.natTrans_app_succ, IH, (Order.lt_succ_of_not_isMax H).trans_le hj] - | hl j H IH => - refine fun hj ↦ (iter₁.isColimit j H hj).hom_ext ?_ - rintro ⟨k, hk⟩ - simp [IH k hk] - -end Hom +section -@[simp] -lemma natTrans_id : Hom.natTrans (𝟙 iter₁) = 𝟙 _ := rfl +variable (iter : Φ.Iteration j) + +lemma obj_succ (i : J) (hi : i < j) : + iter.F.obj ⟨Order.succ i, Order.succ_le_of_lt hi⟩ = Φ.succ (iter.F.obj ⟨i, hi.le⟩) := + congr_arg Comma.right (iter.arrowSucc_eq i hi) + +lemma prop_map_succ (i : J) (hi : i < j) : + Φ.prop (iter.F.map (homOfLE (Order.le_succ i) : + ⟨i, hi.le⟩ ⟶ ⟨Order.succ i, Order.succ_le_of_lt hi⟩)) := by + rw [prop_iff, ← arrowMap, ← arrowSucc_def _ _ hi, iter.arrowSucc_eq] + +lemma obj_limit (i : J) (hi : Order.IsSuccLimit i) (hij : i ≤ j) : + letI := hasColimitsOfShape_of_isSuccLimit C i hi + iter.F.obj ⟨i, hij⟩ = colimit (restrictionLT iter.F hij) := + congr_arg Comma.right (iter.arrowMap_limit i hi hij ⊥ (Order.IsSuccLimit.bot_lt hi)) + +/-- The iteration on a limit element identifies to the colimit of the +value on smaller elements. -/ +noncomputable def isColimit (i : J) (hi : Order.IsSuccLimit i) (hij : i ≤ j) : + IsColimit (coconeOfLE iter.F hij) := by + letI := hasColimitsOfShape_of_isSuccLimit C i hi + refine IsColimit.ofIsoColimit (colimit.isColimit (restrictionLT iter.F hij)) + (Cocones.ext (eqToIso (iter.obj_limit i hi hij).symm) ?_) + rintro ⟨k, hk⟩ + apply Arrow.mk_injective + dsimp + rw [← arrowMap] + simp [iter.arrowMap_limit i hi hij k hk, arrowι_def] + +/-- The element in `Φ.Iteration i` that is deduced from an element +in `Φ.Iteration j` when `i ≤ j`. -/ +@[simps F] +def trunc (iter : Φ.Iteration j) {j' : J} (hj' : j' ≤ j) : Φ.Iteration j' where + F := restrictionLE iter.F hj' + obj_bot := iter.obj_bot + arrowSucc_eq i hi := iter.arrowSucc_eq i (lt_of_lt_of_le hi hj') + arrowMap_limit i hi hij k hk := iter.arrowMap_limit i hi (hij.trans hj') k hk -variable {iter₁ iter₂} +end -@[simp, reassoc] -lemma natTrans_comp {iter₃ : Iteration ε j} (φ : iter₁ ⟶ iter₂) (ψ : iter₂ ⟶ iter₃) : - (φ ≫ ψ).natTrans = φ.natTrans ≫ ψ.natTrans := rfl +namespace subsingleton -@[reassoc] -lemma natTrans_naturality (φ : iter₁ ⟶ iter₂) (i₁ i₂ : J) (h : i₁ ≤ i₂) (h' : i₂ ≤ j) : - iter₁.F.map (by exact homOfLE h) ≫ φ.natTrans.app ⟨i₂, h'⟩ = - φ.natTrans.app ⟨i₁, h.trans h'⟩ ≫ iter₂.F.map (by exact homOfLE h) := by - apply φ.natTrans.naturality +variable {K : Type w} [LinearOrder K] {x : K} (F G : Set.Iic x ⥤ C) -variable (ε) in -/-- The evaluation functor `Iteration ε j ⥤ C ⥤ C` at `i : J` when `i ≤ j`. -/ -@[simps] -def eval {i : J} (hi : i ≤ j) : Iteration ε j ⥤ C ⥤ C where - obj iter := iter.F.obj ⟨i, hi⟩ - map φ := φ.natTrans.app _ - -/-- Given `iter : Iteration ε j` and `i : J` such that `i ≤ j`, this is the -induced element in `Iteration ε i`. -/ -@[simps F isoZero isoSucc] -def trunc (iter : Iteration ε j) {i : J} (hi : i ≤ j) : Iteration ε i where - F := restrictionLE iter.F hi - isoZero := iter.isoZero - isoSucc k hk := iter.isoSucc k (lt_of_lt_of_le hk hi) - mapSucc'_eq k hk := iter.mapSucc'_eq k (lt_of_lt_of_le hk hi) - isColimit k hk' hk := iter.isColimit k hk' (hk.trans hi) - -variable (ε) in -/-- The truncation functor `Iteration ε j ⥤ Iteration ε i` when `i ≤ j`. -/ -@[simps obj] -def truncFunctor {i : J} (hi : i ≤ j) : Iteration ε j ⥤ Iteration ε i where - obj iter := iter.trunc hi - map {iter₁ iter₂} φ := - { natTrans := whiskerLeft _ φ.natTrans - natTrans_app_succ := fun k hk => φ.natTrans_app_succ k (lt_of_lt_of_le hk hi) } +section -@[simp] -lemma truncFunctor_map_natTrans_app - (φ : iter₁ ⟶ iter₂) {i : J} (hi : i ≤ j) (k : J) (hk : k ≤ i) : - ((truncFunctor ε hi).map φ).natTrans.app ⟨k, hk⟩ = - φ.natTrans.app ⟨k, hk.trans hi⟩ := rfl +variable (k₁ k₂ : K) (h₁₂ : k₁ ≤ k₂) (h₂ : k₂ ≤ x) -end +/-- Auxiliary definition for the proof of `Subsingleton (Φ.Iteration j)`. -/ +def MapEq : Prop := arrowMap F k₁ k₂ h₁₂ h₂ = arrowMap G k₁ k₂ h₁₂ h₂ + +namespace MapEq + +variable {k₁ k₂ h₁₂ h₂} (h : MapEq F G k₁ k₂ h₁₂ h₂) + +include h + +lemma src : F.obj ⟨k₁, h₁₂.trans h₂⟩ = G.obj ⟨k₁, h₁₂.trans h₂⟩ := + congr_arg Comma.left h + +lemma tgt : F.obj ⟨k₂, h₂⟩ = G.obj ⟨k₂, h₂⟩ := + congr_arg Comma.right h -namespace Hom +lemma w : + F.map (homOfLE h₁₂ : ⟨k₁, h₁₂.trans h₂⟩ ⟶ ⟨k₂, h₂⟩) = + eqToHom (by rw [h.src]) ≫ G.map (homOfLE h₁₂ : ⟨k₁, h₁₂.trans h₂⟩ ⟶ ⟨k₂, h₂⟩) ≫ + eqToHom (by rw [h.tgt]) := by + have := (Arrow.mk_eq_mk_iff _ _).1 h + tauto -variable [PartialOrder J] [OrderBot J] [SuccOrder J] [WellFoundedLT J] - {iter₁ iter₂ : Φ.Iteration ε j} +end MapEq -lemma congr_app (φ φ' : iter₁ ⟶ iter₂) (i : J) (hi : i ≤ j) : - φ.natTrans.app ⟨i, hi⟩ = φ'.natTrans.app ⟨i, hi⟩ := by - obtain rfl := Subsingleton.elim φ φ' +end + +variable {F G} + +lemma mapEq_refl (k : K) (hk : k ≤ x) (h : F.obj ⟨k, hk⟩ = G.obj ⟨k, hk⟩) : + MapEq F G k k (by simp) hk := by + rw [MapEq, arrowMap_refl, arrowMap_refl, h] + +lemma mapEq_trans {i₁ i₂ i₃ : K} (h₁₂ : i₁ ≤ i₂) (h₂₃ : i₂ ≤ i₃) {h₃ : i₃ ≤ x} + (m₁₂ : MapEq F G i₁ i₂ h₁₂ (h₂₃.trans h₃)) (m₂₃ : MapEq F G i₂ i₃ h₂₃ h₃) : + MapEq F G i₁ i₃ (h₁₂.trans h₂₃) h₃ := by + simp only [MapEq, arrowMap, Arrow.mk_eq_mk_iff] + refine ⟨m₁₂.src, m₂₃.tgt, ?_⟩ + rw [← homOfLE_comp (y := ⟨i₂, h₂₃.trans h₃⟩) h₁₂ h₂₃] + simp [-homOfLE_comp, m₁₂.w, m₂₃.w] + +lemma ext (h : ∀ (k₁ k₂ : K) (h₁₂ : k₁ ≤ k₂) (h₂ : k₂ ≤ x), + MapEq F G k₁ k₂ h₁₂ h₂) : + F = G := by + apply Arrow.functor_ext + rintro ⟨k₁, _⟩ ⟨k₂, h₂⟩ f + apply h + +end subsingleton + +open subsingleton in +instance subsingleton : Subsingleton (Φ.Iteration j) where + allEq iter₁ iter₂ := by + suffices iter₁.F = iter₂.F by aesop + revert iter₁ iter₂ + induction j using SuccOrder.limitRecOn with + | hm j h => + obtain rfl := h.eq_bot + intro iter₁ iter₂ + refine ext (fun k₁ k₂ h₁₂ h₂ ↦ ?_) + obtain rfl : k₂ = ⊥ := by simpa using h₂ + obtain rfl : k₁ = ⊥ := by simpa using h₁₂ + apply mapEq_refl _ _ (by simp only [obj_bot]) + | hs j hj₁ hj₂ => + intro iter₁ iter₂ + refine ext (fun k₁ k₂ h₁₂ h₂ ↦ ?_) + have h₀ := Order.le_succ j + replace hj₂ := hj₂ (iter₁.trunc h₀) (iter₂.trunc h₀) + have hsucc := Functor.congr_obj hj₂ ⟨j, by simp⟩ + dsimp at hj₂ hsucc + wlog h : k₂ ≤ j generalizing k₁ k₂ + · obtain h₂ | rfl := h₂.lt_or_eq + · exact this _ _ _ _ ((Order.lt_succ_iff_of_not_isMax hj₁).1 h₂) + · by_cases h' : k₁ ≤ j + · apply mapEq_trans _ h₀ (this k₁ j h' h₀ (by simp)) + simp only [MapEq, ← arrowSucc_def _ _ (Order.lt_succ_of_not_isMax hj₁), + arrowSucc_eq, hsucc] + · simp only [not_le] at h' + obtain rfl : k₁ = Order.succ j := le_antisymm h₁₂ + ((Order.succ_le_iff_of_not_isMax hj₁).2 h') + rw [MapEq, arrowMap_refl, arrowMap_refl, + obj_succ _ _ h', obj_succ _ _ h', hsucc] + simp only [MapEq, ← arrowMap_restrictionLE _ (Order.le_succ j) _ _ _ h, hj₂] + | hl j h₁ h₂ => + intro iter₁ iter₂ + refine ext (fun k₁ k₂ h₁₂ h₃ ↦ ?_) + wlog h₄ : k₂ < j generalizing k₁ k₂; swap + · have := h₂ k₂ h₄ (iter₁.trunc h₄.le) (iter₂.trunc h₄.le) + simp at this + simp only [MapEq, ← arrowMap_restrictionLE _ h₄.le _ _ _ (by rfl), this] + · obtain rfl : j = k₂ := le_antisymm (by simpa using h₄) h₃ + have : restrictionLT iter₁.F le_rfl = restrictionLT iter₂.F le_rfl := + Arrow.functor_ext (fun _ l _ ↦ this _ _ _ _ l.2) + by_cases h₅ : k₁ < j + · dsimp [MapEq] + simp_rw [arrowMap_limit _ _ h₁ _ _ h₅, this] + · obtain rfl : k₁ = j := le_antisymm h₁₂ (by simpa using h₅) + apply mapEq_refl + simp only [obj_limit _ _ h₁, this] + +lemma congr_obj {j₁ j₂ : J} (iter₁ : Φ.Iteration j₁) (iter₂ : Φ.Iteration j₂) + (k : J) (h₁ : k ≤ j₁) (h₂ : k ≤ j₂) : + iter₁.F.obj ⟨k, h₁⟩ = iter₂.F.obj ⟨k, h₂⟩ := by + wlog h : j₁ ≤ j₂ generalizing j₁ j₂ + · exact (this iter₂ iter₁ h₂ h₁ (le_of_lt (by simpa using h))).symm + rw [Subsingleton.elim iter₁ (iter₂.trunc h)] + dsimp + +lemma congr_arrowMap {j₁ j₂ : J} (iter₁ : Φ.Iteration j₁) (iter₂ : Φ.Iteration j₂) + {k₁ k₂ : J} (h : k₁ ≤ k₂) (h₁ : k₂ ≤ j₁) (h₂ : k₂ ≤ j₂) : + arrowMap iter₁.F k₁ k₂ h h₁ = arrowMap iter₂.F k₁ k₂ h h₂ := by + wlog hj : j₁ ≤ j₂ generalizing j₁ j₂ + · simp [this iter₂ iter₁ h₂ h₁ ((not_le.1 hj).le)] + rw [Subsingleton.elim iter₁ (iter₂.trunc hj)] rfl -end Hom +lemma congr_map {j₁ j₂ : J} (iter₁ : Φ.Iteration j₁) (iter₂ : Φ.Iteration j₂) + {k₁ k₂ : J} (h : k₁ ≤ k₂) (h₁ : k₂ ≤ j₁) (h₂ : k₂ ≤ j₂) : + iter₁.F.map (homOfLE h : ⟨k₁, h.trans h₁⟩ ⟶ ⟨k₂, h₁⟩) = + eqToHom (congr_obj iter₁ iter₂ k₁ (h.trans h₁) (h.trans h₂)) ≫ + iter₂.F.map (homOfLE h) ≫ + eqToHom (congr_obj iter₁ iter₂ k₂ h₁ h₂).symm := by + have := (Arrow.mk_eq_mk_iff _ _).1 (congr_arrowMap iter₁ iter₂ h h₁ h₂) + tauto + +/-- Given `iter₁ : Φ.Iteration j₁` and `iter₂ : Φ.Iteration j₂`, with `j₁ ≤ j₂`, +if `k₁ ≤ k₂` are elements such that `k₁ ≤ j₁` and `k₂ ≤ k₂`, then this +is the canonical map `iter₁.F.obj ⟨k₁, h₁⟩ ⟶ iter₂.F.obj ⟨k₂, h₂⟩`. -/ +def mapObj {j₁ j₂ : J} (iter₁ : Φ.Iteration j₁) (iter₂ : Φ.Iteration j₂) + {k₁ k₂ : J} (h₁₂ : k₁ ≤ k₂) (h₁ : k₁ ≤ j₁) (h₂ : k₂ ≤ j₂) (hj : j₁ ≤ j₂) : + iter₁.F.obj ⟨k₁, h₁⟩ ⟶ iter₂.F.obj ⟨k₂, h₂⟩ := + eqToHom (congr_obj iter₁ iter₂ k₁ h₁ (h₁.trans hj)) ≫ + iter₂.F.map (homOfLE h₁₂) + +lemma arrow_mk_mapObj {j₁ j₂ : J} (iter₁ : Φ.Iteration j₁) (iter₂ : Φ.Iteration j₂) + {k₁ k₂ : J} (h₁₂ : k₁ ≤ k₂) (h₁ : k₁ ≤ j₁) (h₂ : k₂ ≤ j₂) (hj : j₁ ≤ j₂) : + Arrow.mk (mapObj iter₁ iter₂ h₁₂ h₁ h₂ hj) = + arrowMap iter₂.F k₁ k₂ h₁₂ h₂ := by + simp [mapObj, arrowMap] + +@[simp] +lemma mapObj_refl {j : J} (iter : Φ.Iteration j) + {k l : J} (h : k ≤ l) (h' : l ≤ j) : + mapObj iter iter h (h.trans h') h' (by rfl) = iter.F.map (homOfLE h) := by + simp [mapObj] + +@[reassoc (attr := simp)] +lemma mapObj_trans {j₁ j₂ j₃ : J} (iter₁ : Φ.Iteration j₁) (iter₂ : Φ.Iteration j₂) + (iter₃ : Φ.Iteration j₃) {k₁ k₂ k₃ : J} (h₁₂ : k₁ ≤ k₂) (h₂₃ : k₂ ≤ k₃) + (h₁ : k₁ ≤ j₁) (h₂ : k₂ ≤ j₂) (h₃ : k₃ ≤ j₃) (h₁₂' : j₁ ≤ j₂) (h₂₃' : j₂ ≤ j₃) : + mapObj iter₁ iter₂ h₁₂ h₁ h₂ h₁₂' ≫ mapObj iter₂ iter₃ h₂₃ h₂ h₃ h₂₃' = + mapObj iter₁ iter₃ (h₁₂.trans h₂₃) h₁ h₃ (h₁₂'.trans h₂₃') := by + simp [mapObj, congr_map iter₂ iter₃ h₁₂ h₂ (h₂.trans h₂₃'), ← Functor.map_comp] end Iteration -end Functor +end SuccStruct + +end SmallObject end CategoryTheory diff --git a/Mathlib/CategoryTheory/SmallObject/Iteration/ExtendToSucc.lean b/Mathlib/CategoryTheory/SmallObject/Iteration/ExtendToSucc.lean index 166469022df52..730a42b41c679 100644 --- a/Mathlib/CategoryTheory/SmallObject/Iteration/ExtendToSucc.lean +++ b/Mathlib/CategoryTheory/SmallObject/Iteration/ExtendToSucc.lean @@ -22,12 +22,14 @@ namespace CategoryTheory open Category -namespace Functor +namespace SmallObject variable {C : Type*} [Category C] {J : Type u} [LinearOrder J] [SuccOrder J] {j : J} (hj : ¬IsMax j) (F : Set.Iic j ⥤ C) {X : C} (τ : F.obj ⟨j, by simp⟩ ⟶ X) +namespace SuccStruct + namespace extendToSucc variable (X) @@ -37,14 +39,22 @@ it sends `Order.succ j` to the given object `X`. -/ def obj (i : Set.Iic (Order.succ j)) : C := if hij : i.1 ≤ j then F.obj ⟨i.1, hij⟩ else X +lemma obj_eq (i : Set.Iic j) : + obj F X ⟨i, i.2.trans (Order.le_succ j)⟩ = F.obj i := dif_pos i.2 + /-- The isomorphism `obj F X ⟨i, _⟩ ≅ F.obj i` when `i : Set.Iic j`. -/ def objIso (i : Set.Iic j) : - obj F X ⟨i, i.2.trans (Order.le_succ j)⟩ ≅ F.obj i := eqToIso (dif_pos i.2) + obj F X ⟨i, i.2.trans (Order.le_succ j)⟩ ≅ F.obj i := + eqToIso (obj_eq _ _ _) + +include hj in +lemma obj_succ_eq : obj F X ⟨Order.succ j, by simp⟩ = X := + dif_neg (by simpa only [Order.succ_le_iff_isMax] using hj) /-- The isomorphism `obj F X ⟨Order.succ j, _⟩ ≅ X`. -/ def objSuccIso : obj F X ⟨Order.succ j, by simp⟩ ≅ X := - eqToIso (dif_neg (by simpa only [Order.succ_le_iff_isMax] using hj)) + eqToIso (obj_succ_eq hj _ _) variable {X} @@ -76,7 +86,7 @@ lemma map_self_succ : (objIso F X ⟨j, by simp⟩).hom ≫ τ ≫ (objSuccIso hj F X).inv := by dsimp [map] rw [dif_neg (by simpa only [Order.succ_le_iff_isMax] using hj), - dif_pos (by rfl), map_id, comp_id, id_comp] + dif_pos (by rfl), Functor.map_id, comp_id, id_comp] @[simp] lemma map_id (i : J) (hi : i ≤ Order.succ j) : @@ -93,15 +103,15 @@ lemma map_comp (i₁ i₂ i₃ : J) (h₁₂ : i₁ ≤ i₂) (h₂₃ : i₂ map hj F τ i₁ i₂ h₁₂ (h₂₃.trans h) ≫ map hj F τ i₂ i₃ h₂₃ h := by by_cases h₁ : i₃ ≤ j · rw [map_eq hj F τ i₁ i₂ _ (h₂₃.trans h₁), map_eq hj F τ i₂ i₃ _ h₁, - map_eq hj F τ i₁ i₃ _ h₁, assoc, assoc, Iso.inv_hom_id_assoc, ← map_comp_assoc, + map_eq hj F τ i₁ i₃ _ h₁, assoc, assoc, Iso.inv_hom_id_assoc, ← Functor.map_comp_assoc, homOfLE_comp] · obtain rfl : i₃ = Order.succ j := le_antisymm h (Order.succ_le_of_lt (not_le.1 h₁)) obtain h₂ | rfl := h₂₃.lt_or_eq · rw [Order.lt_succ_iff_of_not_isMax hj] at h₂ rw [map_eq hj F τ i₁ i₂ _ h₂] dsimp [map] - rw [dif_neg h₁, dif_pos (h₁₂.trans h₂), dif_neg h₁, dif_pos h₂, - assoc, assoc, Iso.inv_hom_id_assoc,comp_id, ← map_comp_assoc, homOfLE_comp] + rw [dif_neg h₁, dif_pos (h₁₂.trans h₂), dif_neg h₁, dif_pos h₂, assoc, assoc, + Iso.inv_hom_id_assoc,comp_id, ← Functor.map_comp_assoc, homOfLE_comp] · rw [map_id, comp_id] end extendToSucc @@ -116,10 +126,18 @@ def extendToSucc : Set.Iic (Order.succ j) ⥤ C where map_id _ := extendToSucc.map_id _ F τ _ _ map_comp {i₁ i₂ i₃} f g := extendToSucc.map_comp hj F τ i₁ i₂ i₃ (leOfHom f) (leOfHom g) i₃.2 -/-- The isomorphism `(extendToSucc hj F τ).obj ⟨i, _⟩ ≅ F.obj i` when `i : Set.Iic j` -/ -def extendToSuccObjIso (i : Set.Iic j) : - (extendToSucc hj F τ).obj ⟨i, i.2.trans (Order.le_succ j)⟩ ≅ F.obj i := - extendToSucc.objIso F X i +lemma extendToSucc_obj_eq (i : J) (hi : i ≤ j) : + (extendToSucc hj F τ).obj ⟨i, hi.trans (Order.le_succ j)⟩ = F.obj ⟨i, hi⟩ := + extendToSucc.obj_eq F X ⟨i, hi⟩ + +/-- The isomorphism `(extendToSucc hj F τ).obj ⟨i, _⟩ ≅ F.obj i` when `i ≤ j` -/ +def extendToSuccObjIso (i : J) (hi : i ≤ j) : + (extendToSucc hj F τ).obj ⟨i, hi.trans (Order.le_succ j)⟩ ≅ F.obj ⟨i, hi⟩ := + extendToSucc.objIso F X ⟨i, hi⟩ + +lemma extendToSucc_obj_succ_eq : + (extendToSucc hj F τ).obj ⟨Order.succ j, by simp⟩ = X := + extendToSucc.obj_succ_eq hj F X /-- The isomorphism `(extendToSucc hj F τ).obj ⟨Order.succ j, _⟩ ≅ X`. -/ def extendToSuccObjSuccIso : @@ -130,32 +148,46 @@ def extendToSuccObjSuccIso : lemma extendToSuccObjIso_hom_naturality (i₁ i₂ : J) (hi : i₁ ≤ i₂) (hi₂ : i₂ ≤ j) : (extendToSucc hj F τ).map (homOfLE hi : ⟨i₁, hi.trans (hi₂.trans (Order.le_succ j))⟩ ⟶ ⟨i₂, hi₂.trans (Order.le_succ j)⟩) ≫ - (extendToSuccObjIso hj F τ ⟨i₂, hi₂⟩).hom = - (extendToSuccObjIso hj F τ ⟨i₁, hi.trans hi₂⟩).hom ≫ F.map (homOfLE hi) := by + (extendToSuccObjIso hj F τ i₂ hi₂).hom = + (extendToSuccObjIso hj F τ i₁ (hi.trans hi₂)).hom ≫ F.map (homOfLE hi) := by dsimp [extendToSucc, extendToSuccObjIso] rw [extendToSucc.map_eq _ _ _ _ _ _ hi₂, assoc, assoc, Iso.inv_hom_id, comp_id] /-- The isomorphism expressing that `extendToSucc hj F τ` extends `F`. -/ @[simps!] def extendToSuccRestrictionLEIso : - Iteration.restrictionLE (extendToSucc hj F τ) (Order.le_succ j) ≅ F := - NatIso.ofComponents (extendToSuccObjIso hj F τ) (by + SmallObject.restrictionLE (extendToSucc hj F τ) (Order.le_succ j) ≅ F := + NatIso.ofComponents (fun i ↦ extendToSuccObjIso hj F τ i.1 i.2) (by rintro ⟨i₁, h₁⟩ ⟨i₂, h₂⟩ f apply extendToSuccObjIso_hom_naturality) -lemma extentToSucc_map (i₁ i₂ : J) (hi : i₁ ≤ i₂) (hi₂ : i₂ ≤ j) : +lemma extendToSucc_map (i₁ i₂ : J) (hi : i₁ ≤ i₂) (hi₂ : i₂ ≤ j) : (extendToSucc hj F τ).map (homOfLE hi : ⟨i₁, hi.trans (hi₂.trans (Order.le_succ j))⟩ ⟶ ⟨i₂, hi₂.trans (Order.le_succ j)⟩) = - (extendToSuccObjIso hj F τ ⟨i₁, hi.trans hi₂⟩).hom ≫ F.map (homOfLE hi) ≫ - (extendToSuccObjIso hj F τ ⟨i₂, hi₂⟩).inv := by + (extendToSuccObjIso hj F τ i₁ (hi.trans hi₂)).hom ≫ F.map (homOfLE hi) ≫ + (extendToSuccObjIso hj F τ i₂ hi₂).inv := by rw [← extendToSuccObjIso_hom_naturality_assoc, Iso.hom_inv_id, comp_id] lemma extendToSucc_map_le_succ : (extendToSucc hj F τ).map (homOfLE (Order.le_succ j)) = - (extendToSuccObjIso hj F τ ⟨j, by simp⟩).hom ≫ τ ≫ + (extendToSuccObjIso hj F τ j (by simp)).hom ≫ τ ≫ (extendToSuccObjSuccIso hj F τ).inv := extendToSucc.map_self_succ _ _ _ -end Functor +lemma arrowMap_extendToSucc (i₁ i₂ : J) (hi : i₁ ≤ i₂) (hi₂ : i₂ ≤ j) : + arrowMap (extendToSucc hj F τ) i₁ i₂ hi (hi₂.trans (Order.le_succ j)) = + arrowMap F i₁ i₂ hi hi₂ := by + simp [arrowMap, extendToSucc_map hj F τ i₁ i₂ hi hi₂, + extendToSuccObjIso, extendToSucc.objIso] + +lemma arrowSucc_extendToSucc : + arrowSucc (extendToSucc hj F τ) j (Order.lt_succ_of_not_isMax hj) = + Arrow.mk τ := by + simp [arrowSucc, arrowMap, extendToSucc_map_le_succ, extendToSuccObjIso, + extendToSucc.objIso, extendToSuccObjSuccIso, extendToSucc.objSuccIso] + +end SuccStruct + +end SmallObject end CategoryTheory diff --git a/Mathlib/CategoryTheory/SmallObject/Iteration/FunctorOfCocone.lean b/Mathlib/CategoryTheory/SmallObject/Iteration/FunctorOfCocone.lean index 35b3bf90ea04c..c75826a22944f 100644 --- a/Mathlib/CategoryTheory/SmallObject/Iteration/FunctorOfCocone.lean +++ b/Mathlib/CategoryTheory/SmallObject/Iteration/FunctorOfCocone.lean @@ -21,7 +21,9 @@ namespace CategoryTheory open Category Limits -namespace Functor +namespace SmallObject + +namespace SuccStruct variable {C : Type*} [Category C] {J : Type u} [LinearOrder J] @@ -29,23 +31,23 @@ variable {C : Type*} [Category C] namespace ofCocone -/-- Auxiliary definition for `Functor.ofCocone`. -/ +/-- Auxiliary definition for `ofCocone`. -/ def obj (i : J) : C := if hi : i < j then F.obj ⟨i, hi⟩ else c.pt -/-- Auxiliary definition for `Functor.ofCocone`. -/ +/-- Auxiliary definition for `ofCocone`. -/ def objIso (i : J) (hi : i < j) : obj c i ≅ F.obj ⟨i, hi⟩ := eqToIso (dif_pos hi) -/-- Auxiliary definition for `Functor.ofCocone`. -/ +/-- Auxiliary definition for `ofCocone`. -/ def objIsoPt : obj c j ≅ c.pt := eqToIso (dif_neg (by simp)) -/-- Auxiliary definition for `Functor.ofCocone`. -/ +/-- Auxiliary definition for `ofCocone`. -/ def map (i₁ i₂ : J) (hi : i₁ ≤ i₂) (hi₂ : i₂ ≤ j) : obj c i₁ ⟶ obj c i₂ := if h₂ : i₂ < j then @@ -92,11 +94,19 @@ def ofCocone : Set.Iic j ⥤ C where map_id i := ofCocone.map_id _ _ i.2 map_comp {_ _ i₃} _ _ := ofCocone.map_comp _ _ _ _ _ _ i₃.2 +lemma ofCocone_obj_eq (i : J) (hi : i < j) : + (ofCocone c).obj ⟨i, hi.le⟩ = F.obj ⟨i, hi⟩ := + dif_pos hi + /-- The isomorphism `(ofCocone c).obj ⟨i, _⟩ ≅ F.obj ⟨i, _⟩` when `i < j`. -/ def ofCoconeObjIso (i : J) (hi : i < j) : (ofCocone c).obj ⟨i, hi.le⟩ ≅ F.obj ⟨i, hi⟩ := ofCocone.objIso c _ _ +lemma ofCocone_obj_eq_pt : + (ofCocone c).obj ⟨j, by simp⟩ = c.pt := + dif_neg (by simp) + /-- The isomorphism `(ofCocone c).obj ⟨j, _⟩ ≅ c.pt`. -/ def ofCoconeObjIsoPt : (ofCocone c).obj ⟨j, by simp⟩ ≅ c.pt := @@ -127,20 +137,32 @@ lemma ofCoconeObjIso_hom_naturality (i₁ i₂ : J) (hi : i₁ ≤ i₂) (hi₂ when `c : Cocone F`. -/ @[simps!] def restrictionLTOfCoconeIso : - Iteration.restrictionLT (ofCocone c) (Preorder.le_refl j) ≅ F := + SmallObject.restrictionLT (ofCocone c) (Preorder.le_refl j) ≅ F := NatIso.ofComponents (fun ⟨i, hi⟩ ↦ ofCoconeObjIso c i hi) (by intros; apply ofCoconeObjIso_hom_naturality) variable {c} in /-- If `c` is a colimit cocone, then so is `coconeOfLE (ofCocone c) (Preorder.le_refl j)`. -/ def isColimitCoconeOfLEOfCocone (hc : IsColimit c) : - IsColimit (Iteration.coconeOfLE (ofCocone c) (Preorder.le_refl j)) := + IsColimit (coconeOfLE (ofCocone c) (Preorder.le_refl j)) := (IsColimit.precomposeInvEquiv (restrictionLTOfCoconeIso c) _).1 (IsColimit.ofIsoColimit hc (Cocones.ext (ofCoconeObjIsoPt c).symm (fun ⟨i, hi⟩ ↦ by dsimp rw [ofCocone_map_to_top _ _ hi, Iso.inv_hom_id_assoc]))) -end Functor +lemma arrowMap_ofCocone (i₁ i₂ : J) (h₁₂ : i₁ ≤ i₂) (h₂ : i₂ < j) : + arrowMap (ofCocone c) i₁ i₂ h₁₂ h₂.le = + Arrow.mk (F.map (homOfLE h₁₂ : ⟨i₁, lt_of_le_of_lt h₁₂ h₂⟩ ⟶ ⟨i₂, h₂⟩)) := + Arrow.ext (ofCocone_obj_eq _ _ _) (ofCocone_obj_eq _ _ _) (ofCocone_map _ _ _ _ _) + +lemma arrowMap_ofCocone_to_top (i : J) (hi : i < j) : + arrowMap (ofCocone c) i j hi.le (by simp) = Arrow.mk (c.ι.app ⟨i, hi⟩) := by + rw [arrowMap, ofCocone_map_to_top _ _ hi] + exact Arrow.ext (ofCocone_obj_eq _ _ _) (ofCocone_obj_eq_pt _) rfl + +end SuccStruct + +end SmallObject end CategoryTheory diff --git a/Mathlib/CategoryTheory/SmallObject/Iteration/Nonempty.lean b/Mathlib/CategoryTheory/SmallObject/Iteration/Nonempty.lean index 80bdbaec34cea..69f13db5160b7 100644 --- a/Mathlib/CategoryTheory/SmallObject/Iteration/Nonempty.lean +++ b/Mathlib/CategoryTheory/SmallObject/Iteration/Nonempty.lean @@ -3,18 +3,16 @@ Copyright (c) 2024 Joël Riou. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Joël Riou -/ +import Mathlib.CategoryTheory.SmallObject.Iteration.Basic import Mathlib.CategoryTheory.SmallObject.Iteration.ExtendToSucc +import Mathlib.CategoryTheory.SmallObject.Iteration.FunctorOfCocone /-! -# Existence of objects in the category of iterations of functors +# Existence of the iteration of a successor structure -Given a functor `Φ : C ⥤ C` and a natural transformation `ε : 𝟭 C ⟶ Φ`, -we shall show in this file that for any well ordered set `J`, -and `j : J`, the category `Functor.Iteration ε j` is nonempty. -As we already know from the main result in `SmallObject.Iteration.UniqueHom` -that such objects, if they exist, are unique up to a unique isomorphism, -we shall show the existence of a term in `Functor.Iteration ε j` by -transfinite induction. +Given `Φ : SuccStruct C`, we show by transfinite induction +that for any element `j` in a well ordered set `J`, +the type `Φ.Iteration j` is nonempty. -/ @@ -22,76 +20,138 @@ universe u namespace CategoryTheory -open Category Limits +namespace SmallObject + +namespace SuccStruct -variable {C : Type*} [Category C] {Φ : C ⥤ C} {ε : 𝟭 C ⟶ Φ} - {J : Type u} [LinearOrder J] [OrderBot J] [SuccOrder J] +open Category Limits -namespace Functor +variable {C : Type*} [Category C] (Φ : SuccStruct C) + {J : Type u} [LinearOrder J] [OrderBot J] [SuccOrder J] [WellFoundedLT J] + [HasIterationOfShape J C] namespace Iteration -variable (ε J) in -/-- The obvious term in `Iteration ε ⊥`: it is given by the identity functor. -/ -def mkOfBot : Iteration ε (⊥ : J) where - F := (Functor.const _).obj (𝟭 C) - isoZero := Iso.refl _ - isoSucc _ h := by simp at h - mapSucc'_eq _ h := by simp at h - isColimit x hx h := by - exfalso - refine hx.not_isMin (by simpa using h) - -/-- When `j : J` is not maximal, this is the extension as `Iteration ε (Order.succ j)` -of any `iter : Iteration ε j`. -/ -noncomputable def mkOfSucc {j : J} (hj : ¬IsMax j) (iter : Iteration ε j) : - Iteration ε (Order.succ j) where - F := extendToSucc hj iter.F (whiskerLeft _ ε) - isoZero := (extendToSuccObjIso hj iter.F (whiskerLeft _ ε) ⟨⊥, by simp⟩).trans iter.isoZero - isoSucc i hi := - if hij : i < j then - extendToSuccObjIso _ _ _ ⟨Order.succ i, Order.succ_le_of_lt hij⟩ ≪≫ - iter.isoSucc i hij ≪≫ (isoWhiskerRight (extendToSuccObjIso _ _ _ ⟨i, hij.le⟩).symm _) - else - have hij' : i = j := le_antisymm - (by simpa only [Order.lt_succ_iff_of_not_isMax hj] using hi) (by simpa using hij) - eqToIso (by subst hij'; rfl) ≪≫ extendToSuccObjSuccIso hj iter.F (whiskerLeft _ ε) ≪≫ - isoWhiskerRight ((extendToSuccObjIso hj iter.F (whiskerLeft _ ε) ⟨j, by simp⟩).symm.trans - (eqToIso (by subst hij'; rfl))) _ - mapSucc'_eq i hi := by - obtain hi' | rfl := ((Order.lt_succ_iff_of_not_isMax hj).mp hi).lt_or_eq - · ext X - have := iter.mapSucc_eq i hi' - dsimp [mapSucc, mapSucc'] at this ⊢ - rw [extentToSucc_map _ _ _ _ _ _ (Order.succ_le_of_lt hi'), this, dif_pos hi'] +variable (J) in +/-- The obvious term in `Φ.Iteration ε ⊥` that is given by `Φ.X₀`. -/ +def mkOfBot : Φ.Iteration (⊥ : J) where + F := (Functor.const _).obj Φ.X₀ + obj_bot := rfl + arrowSucc_eq _ h := by simp at h + arrowMap_limit _ h₁ h₂ := (h₁.not_isMin (by simpa using h₂)).elim + +variable {Φ} + +open Functor in +/-- When `j : J` is not maximal, this is the extension in `Φ.Iteration (Order.succ j)` +of any `iter : Φ.Iteration j`. -/ +noncomputable def mkOfSucc {j : J} (hj : ¬IsMax j) (iter : Φ.Iteration j) : + Φ.Iteration (Order.succ j) where + F := extendToSucc hj iter.F (Φ.toSucc _) + obj_bot := by rw [extendToSucc_obj_eq _ _ _ _ bot_le, obj_bot] + arrowSucc_eq i hi₁ := by + rw [Order.lt_succ_iff_of_not_isMax hj] at hi₁ + obtain hi₁ | rfl := hi₁.lt_or_eq + · rw [arrowSucc_def, arrowMap_extendToSucc _ _ _ _ _ _ (Order.succ_le_of_lt hi₁), + ← arrowSucc_def _ _ hi₁, iter.arrowSucc_eq i hi₁, + extendToSucc_obj_eq hj iter.F (Φ.toSucc _) i hi₁.le] + · rw [arrowSucc_extendToSucc, toSuccArrow, + extendToSucc_obj_eq hj iter.F (Φ.toSucc _) i] + arrowMap_limit i hi hij k hk := by + have hij' := (Order.IsSuccLimit.le_succ_iff hi).1 hij + rw [arrowMap_extendToSucc _ _ _ _ _ _ hij', arrowMap_limit _ _ hi _ _ hk] + congr 1 + apply Arrow.functor_ext + rintro ⟨k₁, h₁⟩ ⟨k₂, h₂⟩ f + dsimp + rw [← arrowMap, ← arrowMap, arrowMap_extendToSucc] + +namespace mkOfLimit + +open Functor + +variable {j : J} (hj : Order.IsSuccLimit j) (iter : ∀ (i : J), i < j → Φ.Iteration i) + +/-- Assuming `j : J` is a limit element and that we have `∀ (i : J), i < j → Φ.Iteration i`, +this is the inductive system `Set.Iio j ⥤ C` which sends `⟨i, _⟩` to +`(iter i _).F.obj ⟨i, _⟩`. -/ +@[simps] +noncomputable def inductiveSystem : Set.Iio j ⥤ C where + obj i := (iter i.1 i.2).F.obj ⟨i.1, by simp⟩ + map {i₁ i₂} f := mapObj (iter i₁.1 i₁.2) (iter i₂.1 i₂.2) (leOfHom f) + (by simp) (by simp) (leOfHom f) + +/-- The extension of `inductiveSystem iter` to a functor `Set.Iic j ⥤ C` which +sends the top element to the colimit of `inductiveSystem iter`. -/ +noncomputable def functor : Set.Iic j ⥤ C := + letI := hasColimitsOfShape_of_isSuccLimit C j hj + ofCocone (colimit.cocone (inductiveSystem iter)) + +lemma functor_obj (i : J) (hi : i < j) {k : J} (iter' : Φ.Iteration k) (hk : i ≤ k) : + (functor hj iter).obj ⟨i, hi.le⟩ = iter'.F.obj ⟨i, hk⟩ := by + dsimp only [functor] + rw [ofCocone_obj_eq _ _ hi] + apply congr_obj + +lemma arrowMap_functor (i₁ i₂ : J) (h₁₂ : i₁ ≤ i₂) (h₂ : i₂ < j) : + arrowMap (functor hj iter) i₁ i₂ h₁₂ h₂.le = + Arrow.mk (mapObj (iter i₁ (lt_of_le_of_lt h₁₂ h₂)) (iter i₂ h₂) h₁₂ + (by simp) (by simp) h₁₂) := + arrowMap_ofCocone _ _ _ _ h₂ + +lemma arrowMap_functor_to_top (i : J) (hi : i < j) : + letI := hasColimitsOfShape_of_isSuccLimit C j hj + arrowMap (functor hj iter) i j hi.le (by simp) = + Arrow.mk (colimit.ι (inductiveSystem iter) ⟨i, hi⟩) := + arrowMap_ofCocone_to_top _ _ _ + +end mkOfLimit + +open mkOfLimit in +/-- When `j` is a limit element, this is the element in `Φ.Iteration j` +that is constructed from elements in `Φ.Iteration i` for all `i < j`. -/ +noncomputable def mkOfLimit {j : J} (hj : Order.IsSuccLimit j) + (iter : ∀ (i : J), i < j → Φ.Iteration i) : + Φ.Iteration j where + F := functor hj iter + obj_bot := functor_obj hj iter ⊥ (Order.IsSuccLimit.bot_lt hj) (mkOfBot Φ J) (by rfl) + arrowSucc_eq i hi := by + rw [arrowSucc_def, arrowMap_functor _ _ _ _ (Order.le_succ i) + ((Order.IsSuccLimit.succ_lt_iff hj).2 hi), arrow_mk_mapObj, + ← arrowSucc_def _ _ ((Order.lt_succ_of_le_of_not_isMax (by rfl) (not_isMax_of_lt hi))), + arrowSucc_eq, functor_obj _ _ _ hi] + arrowMap_limit i hi hij k hk := by + obtain hij | rfl := hij.lt_or_eq + · rw [arrowMap_functor _ _ _ _ _ hij, arrow_mk_mapObj, + arrowMap_limit _ _ hi _ _ hk] + congr 1 + apply Arrow.functor_ext + rintro ⟨l₁, hl₁⟩ ⟨l₂, hl₂⟩ f dsimp - rw [assoc, assoc] - erw [ε.naturality_assoc] - · ext X - dsimp [mapSucc'] - rw [dif_neg (gt_irrefl i), extendToSucc_map_le_succ] + rw [← arrowMap, ← arrowMap, arrowMap_functor hj iter l₁ l₂ _ (hl₂.trans hij), + arrow_mk_mapObj] + apply congr_arrowMap + · rw [arrowMap_functor_to_top _ _ _ hk, ← arrowι_def _ hi] + congr 1 + apply Arrow.functor_ext + rintro ⟨l₁, hl₁⟩ ⟨l₂, hl₂⟩ f dsimp - rw [id_comp, comp_id] - erw [ε.naturality_assoc] - isColimit i hi hij := by - have hij' : i ≤ j := by - obtain hij | rfl := hij.lt_or_eq - · exact (Order.lt_succ_iff_of_not_isMax hj).1 hij - · exfalso - exact Order.not_isSuccLimit_succ_of_not_isMax hj hi - refine (IsColimit.precomposeHomEquiv - (isoWhiskerLeft (monotone_inclusion_lt_le_of_le hij').functor - (extendToSuccRestrictionLEIso hj iter.F (whiskerLeft _ ε))).symm _).1 - (IsColimit.ofIsoColimit (iter.isColimit i hi hij') - (Iso.symm (Cocones.ext (extendToSuccObjIso hj iter.F (whiskerLeft _ ε) ⟨i, hij'⟩) - (fun ⟨k, hk⟩ ↦ ?_)))) - dsimp - rw [assoc, extendToSuccObjIso_hom_naturality hj iter.F (whiskerLeft _ ε)] - dsimp - rw [Iso.inv_hom_id_assoc] + rw [← arrowMap, arrow_mk_mapObj, arrowMap_functor _ _ _ _ _ hl₂, arrow_mk_mapObj] + +variable (Φ) + +instance nonempty (j : J) : Nonempty (Φ.Iteration j) := by + induction j using SuccOrder.limitRecOn with + | hm i hi => + obtain rfl : i = ⊥ := by simpa using hi + exact ⟨mkOfBot Φ J⟩ + | hs i hi hi' => exact ⟨mkOfSucc hi hi'.some⟩ + | hl i hi hi' => exact ⟨mkOfLimit hi (fun a ha ↦ (hi' a ha).some)⟩ end Iteration -end Functor +end SuccStruct + +end SmallObject end CategoryTheory diff --git a/Mathlib/CategoryTheory/SmallObject/Iteration/UniqueHom.lean b/Mathlib/CategoryTheory/SmallObject/Iteration/UniqueHom.lean deleted file mode 100644 index 5e804f4b55103..0000000000000 --- a/Mathlib/CategoryTheory/SmallObject/Iteration/UniqueHom.lean +++ /dev/null @@ -1,249 +0,0 @@ -/- -Copyright (c) 2024 Joël Riou. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Joël Riou --/ -import Mathlib.CategoryTheory.SmallObject.Iteration.Basic - -/-! -# Uniqueness of morphisms in the category of iterations of functors - -Given a functor `Φ : C ⥤ C` and a natural transformation `ε : 𝟭 C ⟶ Φ`, -we show in this file that there exists a unique morphism -between two arbitrary objects in the category `Functor.Iteration ε j` -when `j : J` and `J` is a well orderered set. - --/ - -universe u - -namespace CategoryTheory - -open Category Limits - -variable {C : Type*} [Category C] {Φ : C ⥤ C} {ε : 𝟭 C ⟶ Φ} - {J : Type u} [LinearOrder J] [OrderBot J] [SuccOrder J] - -namespace Functor - -namespace Iteration - -namespace Hom - -/-- The (unique) morphism between two objects in `Iteration ε ⊥` -/ -def mkOfBot (iter₁ iter₂ : Iteration ε (⊥ : J)) : iter₁ ⟶ iter₂ where - natTrans := - { app := fun ⟨i, hi⟩ => eqToHom (by congr; simpa using hi) ≫ iter₁.isoZero.hom ≫ - iter₂.isoZero.inv ≫ eqToHom (by congr; symm; simpa using hi) - naturality := fun ⟨i, hi⟩ ⟨k, hk⟩ φ => by - obtain rfl : i = ⊥ := by simpa using hi - obtain rfl : k = ⊥ := by simpa using hk - obtain rfl : φ = 𝟙 _ := rfl - simp } - natTrans_app_succ i hi := by simp at hi - -section - -variable {i : J} {iter₁ iter₂ : Iteration ε (Order.succ i)} - (hi : ¬IsMax i) (φ : iter₁.trunc (SuccOrder.le_succ i) ⟶ iter₂.trunc (SuccOrder.le_succ i)) - -/-- Auxiliary definition for `mkOfSucc`. -/ -noncomputable def mkOfSuccNatTransApp (k : J) (hk : k ≤ Order.succ i) : - iter₁.F.obj ⟨k, hk⟩ ⟶ iter₂.F.obj ⟨k, hk⟩ := - if hk' : k = Order.succ i then - eqToHom (by subst hk'; rfl) ≫ (iter₁.isoSucc i (Order.lt_succ_of_not_isMax hi)).hom ≫ - whiskerRight (φ.natTrans.app ⟨i, by simp⟩) _ ≫ - (iter₂.isoSucc i (Order.lt_succ_of_not_isMax hi)).inv ≫ - eqToHom (by subst hk'; rfl) - else - φ.natTrans.app ⟨k, Order.le_of_lt_succ (by - obtain hk | rfl := hk.lt_or_eq - · exact hk - · tauto)⟩ - -lemma mkOfSuccNatTransApp_eq_of_le (k : J) (hk : k ≤ i) : - mkOfSuccNatTransApp hi φ k (hk.trans (Order.le_succ i)) = - φ.natTrans.app ⟨k, hk⟩ := - dif_neg (by rintro rfl; simpa using lt_of_le_of_lt hk (Order.lt_succ_of_not_isMax hi)) - -@[simp] -lemma mkOfSuccNatTransApp_succ_eq : - mkOfSuccNatTransApp hi φ (Order.succ i) (by rfl) = - (iter₁.isoSucc i (Order.lt_succ_of_not_isMax hi)).hom ≫ - whiskerRight (φ.natTrans.app ⟨i, by simp⟩) _ ≫ - (iter₂.isoSucc i (Order.lt_succ_of_not_isMax hi)).inv := by - dsimp [mkOfSuccNatTransApp] - rw [dif_pos rfl, comp_id, id_comp] - -/-- Auxiliary definition for `mkOfSucc`. -/ -@[simps] -noncomputable def mkOfSuccNatTrans : - iter₁.F ⟶ iter₂.F where - app := fun ⟨k, hk⟩ => mkOfSuccNatTransApp hi φ k hk - naturality := fun ⟨k₁, hk₁⟩ ⟨k₂, hk₂⟩ f => by - dsimp - have hk : k₁ ≤ k₂ := leOfHom f - obtain h₂ | rfl := hk₂.lt_or_eq - · replace h₂ : k₂ ≤ i := Order.le_of_lt_succ h₂ - rw [mkOfSuccNatTransApp_eq_of_le hi φ k₂ h₂, - mkOfSuccNatTransApp_eq_of_le hi φ k₁ (hk.trans h₂)] - exact natTrans_naturality φ k₁ k₂ hk h₂ - · obtain h₁ | rfl := hk.lt_or_eq - · have h₂ : k₁ ≤ i := Order.le_of_lt_succ h₁ - let f₁ : (⟨k₁, hk⟩ : { l | l ≤ Order.succ i}) ⟶ - ⟨i, Order.le_succ i⟩ := homOfLE h₂ - let f₂ : (⟨i, Order.le_succ i⟩ : Set.Iic (Order.succ i)) ⟶ - ⟨Order.succ i, by simp⟩ := homOfLE (Order.le_succ i) - obtain rfl : f = f₁ ≫ f₂ := rfl - rw [Functor.map_comp, Functor.map_comp, assoc, - mkOfSuccNatTransApp_eq_of_le hi φ k₁ h₂] - erw [← natTrans_naturality_assoc φ k₁ i h₂ (by rfl)] - rw [mkOfSuccNatTransApp_succ_eq] - dsimp - have ha : iter₁.F.map f₂ = iter₁.mapSucc i (Order.lt_succ_of_not_isMax hi) := rfl - have hb : iter₂.F.map f₂ = iter₂.mapSucc i (Order.lt_succ_of_not_isMax hi) := rfl - rw [ha, hb] - rw [iter₁.mapSucc_eq i, iter₂.mapSucc_eq i, assoc, - Iso.inv_hom_id_assoc] - ext X - dsimp - rw [← ε.naturality_assoc] - rfl - · obtain rfl : f = 𝟙 _ := rfl - rw [Functor.map_id, Functor.map_id, id_comp, comp_id] - -end - -/-- The (unique) morphism between two objects in `Iteration ε (Order.succ i)`, -assuming we have a morphism between the truncations to `Iteration ε i`. -/ -noncomputable def mkOfSucc - {i : J} (iter₁ iter₂ : Iteration ε (Order.succ i)) (hi : ¬IsMax i) - (φ : iter₁.trunc (SuccOrder.le_succ i) ⟶ iter₂.trunc (SuccOrder.le_succ i)) : - iter₁ ⟶ iter₂ where - natTrans := mkOfSuccNatTrans hi φ - natTrans_app_zero := by - dsimp - rw [mkOfSuccNatTransApp_eq_of_le _ _ _ bot_le, φ.natTrans_app_zero] - rfl - natTrans_app_succ k hk := by - obtain hk' | rfl := (Order.le_of_lt_succ hk).lt_or_eq - · dsimp - rw [mkOfSuccNatTransApp_eq_of_le hi φ k hk'.le, - mkOfSuccNatTransApp_eq_of_le hi φ (Order.succ k) (Order.succ_le_of_lt hk'), - φ.natTrans_app_succ _ hk'] - rfl - · simp [mkOfSuccNatTransApp_eq_of_le hi φ k (by rfl)] - -variable {j : J} {iter₁ iter₂ : Iteration ε j} - -section - -variable (φ : ∀ (i : J) (hi : i < j), iter₁.trunc hi.le ⟶ iter₂.trunc hi.le) - [WellFoundedLT J] (hj : Order.IsSuccLimit j) - -/-- Auxiliary definition for `mkOfLimit`. -/ -def mkOfLimitNatTransApp (i : J) (hi : i ≤ j) : - iter₁.F.obj ⟨i, hi⟩ ⟶ iter₂.F.obj ⟨i, hi⟩ := - if h : i < j - then - (φ i h).natTrans.app ⟨i, by simp⟩ - else by - obtain rfl : i = j := by - obtain h' | rfl := hi.lt_or_eq - · exfalso - exact h h' - · rfl - exact (iter₁.isColimit i hj (by simp)).desc (Cocone.mk _ - { app := fun ⟨k, hk⟩ => (φ k hk).natTrans.app ⟨k, by simp⟩ ≫ - iter₂.F.map (homOfLE (by exact hk.le)) - naturality := fun ⟨k₁, hk₁⟩ ⟨k₂, hk₂⟩ f => by - have hf : k₁ ≤ k₂ := by simpa using leOfHom f - dsimp - rw [comp_id, congr_app (φ k₁ hk₁) ((truncFunctor ε hf).map (φ k₂ hk₂))] - erw [natTrans_naturality_assoc (φ k₂ hk₂) k₁ k₂ hf (by rfl)] - dsimp - rw [← Functor.map_comp, homOfLE_comp] }) - -lemma mkOfLimitNatTransApp_eq_of_lt (i : J) (hi : i < j) : - mkOfLimitNatTransApp φ hj i hi.le = (φ i hi).natTrans.app ⟨i, by simp⟩ := - dif_pos hi - -lemma mkOfLimitNatTransApp_naturality_top (i : J) (hi : i < j) : - iter₁.F.map (homOfLE (by simpa using hi.le) : ⟨i, hi.le⟩ ⟶ ⟨j, by simp⟩) ≫ - mkOfLimitNatTransApp φ hj j (by rfl) = - mkOfLimitNatTransApp φ hj i hi.le ≫ iter₂.F.map (homOfLE (by simpa using hi.le)) := by - rw [mkOfLimitNatTransApp_eq_of_lt φ hj i hi, mkOfLimitNatTransApp, dif_neg (by simp)] - exact (iter₁.isColimit j hj (by rfl)).fac _ ⟨i, hi⟩ - -/-- Auxiliary definition for `mkOfLimit`. -/ -@[simps] -def mkOfLimitNatTrans : iter₁.F ⟶ iter₂.F where - app := fun ⟨k, hk⟩ => mkOfLimitNatTransApp φ hj k hk - naturality := fun ⟨k₁, hk₁⟩ ⟨k₂, hk₂⟩ f => by - have hk : k₁ ≤ k₂ := leOfHom f - obtain h₂ | rfl := hk₂.lt_or_eq - · dsimp - rw [mkOfLimitNatTransApp_eq_of_lt _ hj k₂ h₂, - mkOfLimitNatTransApp_eq_of_lt _ hj k₁ (lt_of_le_of_lt hk h₂), - congr_app (φ k₁ (lt_of_le_of_lt hk h₂)) ((truncFunctor ε hk).map (φ k₂ h₂))] - exact natTrans_naturality (φ k₂ h₂) k₁ k₂ hk (by rfl) - · obtain h₁ | rfl := hk₁.lt_or_eq - · exact mkOfLimitNatTransApp_naturality_top _ hj _ h₁ - · obtain rfl : f = 𝟙 _ := rfl - simp only [map_id, id_comp, comp_id] - -/-- The (unique) morphism between two objects in `Iteration ε j` when `j` is a limit element, -assuming we have a morphism between the truncations to `Iteration ε i` for all `i < j`. -/ -def mkOfLimit : iter₁ ⟶ iter₂ where - natTrans := mkOfLimitNatTrans φ hj - natTrans_app_zero := by - simp [mkOfLimitNatTransApp_eq_of_lt φ _ ⊥ (by simpa only [bot_lt_iff_ne_bot] using hj.ne_bot)] - natTrans_app_succ i h := by - dsimp - have h' := hj.succ_lt h - rw [mkOfLimitNatTransApp_eq_of_lt φ hj _ h', - (φ _ h').natTrans_app_succ i (Order.lt_succ_of_not_isMax (not_isMax_of_lt h)), - mkOfLimitNatTransApp_eq_of_lt φ _ _ h, - congr_app (φ i h) ((truncFunctor ε (Order.le_succ i)).map (φ (Order.succ i) h'))] - dsimp - -end - -variable [WellFoundedLT J] - -instance : Nonempty (iter₁ ⟶ iter₂) := by - let P := fun (i : J) => ∀ (hi : i ≤ j), - Nonempty ((truncFunctor ε hi).obj iter₁ ⟶ (truncFunctor ε hi).obj iter₂) - suffices ∀ i, P i from this j (by rfl) - intro i - induction i using SuccOrder.limitRecOn with - | hm i hi => - obtain rfl : i = ⊥ := by simpa using hi - exact fun hi' ↦ ⟨Hom.mkOfBot _ _⟩ - | hs i hi hi' => - exact fun hi'' ↦ ⟨Hom.mkOfSucc _ _ hi (hi' ((Order.le_succ i).trans hi'')).some⟩ - | hl i hi hi' => - exact fun hi'' ↦ ⟨Hom.mkOfLimit (fun k hk ↦ (hi' k hk (hk.le.trans hi'')).some) hi⟩ - -noncomputable instance : Unique (iter₁ ⟶ iter₂) := - uniqueOfSubsingleton (Nonempty.some inferInstance) - -end Hom - -variable [WellFoundedLT J] {j : J} (iter₁ iter₂ iter₃ : Iteration ε j) - -/-- The canonical isomorphism between two objects in the category `Iteration ε j`. -/ -noncomputable def iso : iter₁ ≅ iter₂ where - hom := default - inv := default - -@[simp] -lemma iso_refl : iso iter₁ iter₁ = Iso.refl _ := by aesop_cat - -lemma iso_trans : iso iter₁ iter₂ ≪≫ iso iter₂ iter₃ = iso iter₁ iter₃ := by aesop_cat - -end Iteration - -end Functor - -end CategoryTheory diff --git a/Mathlib/Order/Monotone/Basic.lean b/Mathlib/Order/Monotone/Basic.lean index 0adce71cb1c93..0e42cdb9f044f 100644 --- a/Mathlib/Order/Monotone/Basic.lean +++ b/Mathlib/Order/Monotone/Basic.lean @@ -133,18 +133,6 @@ instance [i : Decidable (∀ a ∈ s, ∀ b ∈ s, a < b → f b < f a)] : end Decidable -lemma monotone_inclusion_le_le_of_le [Preorder α] {k j : α} (hkj : k ≤ j) : - Monotone (fun ⟨i, hi⟩ => ⟨i, hi.trans hkj⟩ : { i // i ≤ k } → { i // i ≤ j}) := - fun _ _ h => h - -lemma monotone_inclusion_lt_le_of_le [Preorder α] {k j : α} (hkj : k ≤ j) : - Monotone (fun ⟨i, hi⟩ => ⟨i, hi.le.trans hkj⟩ : { i // i < k } → { i // i ≤ j}) := - fun _ _ h => h - -lemma monotone_inclusion_lt_lt_of_le [Preorder α] {k j : α} (hkj : k ≤ j) : - Monotone (fun ⟨i, hi⟩ => ⟨i, lt_of_lt_of_le hi hkj⟩ : { i // i < k } → { i // i < j}) := - fun _ _ h => h - /-! ### Monotonicity on the dual order Strictly, many of the `*On.dual` lemmas in this section should use `ofDual ⁻¹' s` instead of `s`, From ea8848aa5d5bca273da97859e882382c58ddb273 Mon Sep 17 00:00:00 2001 From: mathlib4-update-dependencies-bot <150093616+mathlib-bors@users.noreply.github.com> Date: Tue, 4 Feb 2025 05:49:50 +0000 Subject: [PATCH 050/103] chore: update Mathlib dependencies 2025-02-04 (#21400) This PR updates the Mathlib dependencies. --- lake-manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lake-manifest.json b/lake-manifest.json index 33e37d07b8f18..8d5bbad6a913b 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -55,7 +55,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "b1311119f5f7c79c818d3e06621cc81f4bb8973f", + "rev": "7b3b0c8327b3c0214ac49ca6d6922edbb81ab8c9", "name": "Qq", "manifestFile": "lake-manifest.json", "inputRev": "master", From d3675333a598dc352b8b342d29db9af745316dd1 Mon Sep 17 00:00:00 2001 From: Andrew Yang Date: Tue, 4 Feb 2025 06:00:23 +0000 Subject: [PATCH 051/103] feat(AlgebraicGeometry): integral = universally closed + affine (#19419) as a corollary, finite = proper + affine Co-authored-by: Andrew Yang <36414270+erdOne@users.noreply.github.com> --- .../Algebra/Category/Ring/Constructions.lean | 10 +++ Mathlib/Algebra/Polynomial/Eval/Defs.lean | 2 +- .../AlgebraicGeometry/Morphisms/Integral.lean | 66 ++++++++++++++- .../AlgebraicGeometry/Morphisms/Proper.lean | 19 ++++- Mathlib/RingTheory/IsTensorProduct.lean | 83 ++++++++----------- Mathlib/RingTheory/PolynomialAlgebra.lean | 19 +++++ 6 files changed, 142 insertions(+), 57 deletions(-) diff --git a/Mathlib/Algebra/Category/Ring/Constructions.lean b/Mathlib/Algebra/Category/Ring/Constructions.lean index 19a99274584c3..b714a7255c877 100644 --- a/Mathlib/Algebra/Category/Ring/Constructions.lean +++ b/Mathlib/Algebra/Category/Ring/Constructions.lean @@ -8,6 +8,7 @@ import Mathlib.Algebra.Category.Ring.Limits import Mathlib.CategoryTheory.Limits.Shapes.Pullback.CommSq import Mathlib.CategoryTheory.Limits.Shapes.StrictInitial import Mathlib.RingTheory.TensorProduct.Basic +import Mathlib.RingTheory.IsTensorProduct /-! # Constructions of (co)limits in `CommRingCat` @@ -115,6 +116,15 @@ lemma isPushout_tensorProduct (R A B : Type u) [CommRing R] [CommRing A] [CommRi simp isColimit' := ⟨pushoutCoconeIsColimit R A B⟩ +lemma isPushout_of_isPushout (R S A B : Type u) [CommRing R] [CommRing S] + [CommRing A] [CommRing B] [Algebra R S] [Algebra S B] [Algebra R A] [Algebra A B] [Algebra R B] + [IsScalarTower R A B] [IsScalarTower R S B] [Algebra.IsPushout R S A B] : + IsPushout (ofHom (algebraMap R S)) (ofHom (algebraMap R A)) + (ofHom (algebraMap S B)) (ofHom (algebraMap A B)) := + (isPushout_tensorProduct R S A).of_iso (Iso.refl _) (Iso.refl _) (Iso.refl _) + (Algebra.IsPushout.equiv R S A B).toCommRingCatIso (by simp) (by simp) + (by ext; simp [Algebra.IsPushout.equiv_tmul]) (by ext; simp [Algebra.IsPushout.equiv_tmul]) + end Pushout section BinaryCoproduct diff --git a/Mathlib/Algebra/Polynomial/Eval/Defs.lean b/Mathlib/Algebra/Polynomial/Eval/Defs.lean index 4a88165f66aed..9e49062ca629b 100644 --- a/Mathlib/Algebra/Polynomial/Eval/Defs.lean +++ b/Mathlib/Algebra/Polynomial/Eval/Defs.lean @@ -533,7 +533,7 @@ protected theorem map_ofNat (n : ℕ) [n.AtLeastTwo] : theorem map_dvd (f : R →+* S) {x y : R[X]} : x ∣ y → x.map f ∣ y.map f := (mapRingHom f).map_dvd -lemma mapRingHom_comp_C {R S} [CommRing R] [CommRing S] (f : R →+* S) : +lemma mapRingHom_comp_C {R S : Type*} [Semiring R] [Semiring S] (f : R →+* S) : (mapRingHom f).comp C = C.comp f := by ext; simp theorem eval₂_eq_eval_map {x : S} : p.eval₂ f x = (p.map f).eval x := by diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Integral.lean b/Mathlib/AlgebraicGeometry/Morphisms/Integral.lean index 72aed7577ed99..cf5b4bab36ac3 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Integral.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Integral.lean @@ -5,7 +5,9 @@ Authors: Andrew Yang -/ import Mathlib.AlgebraicGeometry.Morphisms.AffineAnd import Mathlib.AlgebraicGeometry.Morphisms.ClosedImmersion +import Mathlib.AlgebraicGeometry.Morphisms.UniversallyClosed import Mathlib.RingTheory.RingHom.Integral +import Mathlib.RingTheory.PolynomialAlgebra /-! @@ -17,10 +19,6 @@ of an arbitrary affine open subset of `Y` is affine and the induced ring map is It is equivalent to ask only that `Y` is covered by affine opens whose preimage is affine and the induced ring map is integral. -## TODO - -- Show integral = universally closed + affine - -/ universe v u @@ -57,8 +55,68 @@ instance : IsStableUnderBaseChange @IsIntegralHom := instance : ContainsIdentities @IsIntegralHom := ⟨fun X ↦ ⟨fun _ _ ↦ by simpa using RingHom.isIntegral_of_surjective _ (Equiv.refl _).surjective⟩⟩ +lemma SpecMap_iff {R S : CommRingCat} {φ : R ⟶ S} : + IsIntegralHom (Spec.map φ) ↔ φ.hom.IsIntegral := by + have := RingHom.toMorphismProperty_respectsIso_iff.mp RingHom.isIntegral_respectsIso + rw [HasAffineProperty.iff_of_isAffine (P := @IsIntegralHom), and_iff_right] + exacts [MorphismProperty.arrow_mk_iso_iff (RingHom.toMorphismProperty RingHom.IsIntegral) + (arrowIsoΓSpecOfIsAffine φ).symm, inferInstance] + instance : IsMultiplicative @IsIntegralHom where +instance (priority := 100) {X Y : Scheme.{u}} (f : X ⟶ Y) [IsIntegralHom f] : + UniversallyClosed f := by + revert X Y f ‹IsIntegralHom f› + rw [universallyClosed_eq, ← IsStableUnderBaseChange.universally_eq (P := @IsIntegralHom)] + apply universally_mono + intro X Y f + wlog hY : ∃ R, Y = Spec R + · rw [IsLocalAtTarget.iff_of_openCover (P := @IsIntegralHom) Y.affineCover, + IsLocalAtTarget.iff_of_openCover (P := topologically _) Y.affineCover] + exact fun a i ↦ this _ ⟨_, rfl⟩ (a i) + obtain ⟨R, rfl⟩ := hY + wlog hX : ∃ S, X = Spec S + · intro H + have inst : IsAffine X := isAffine_of_isAffineHom f + rw [← cancel_left_of_respectsIso (P := topologically _) X.isoSpec.inv] + rw [← cancel_left_of_respectsIso (P := @IsIntegralHom) X.isoSpec.inv] at H + exact this _ _ ⟨_, rfl⟩ H + obtain ⟨S, rfl⟩ := hX + obtain ⟨φ, rfl⟩ := Spec.map_surjective f + rw [SpecMap_iff] + exact PrimeSpectrum.isClosedMap_comap_of_isIntegral _ + +lemma iff_universallyClosed_and_isAffineHom {X Y : Scheme.{u}} {f : X ⟶ Y} : + IsIntegralHom f ↔ UniversallyClosed f ∧ IsAffineHom f := by + refine ⟨fun _ ↦ ⟨inferInstance, inferInstance⟩, fun ⟨H₁, H₂⟩ ↦ ?_⟩ + clear * - + wlog hY : ∃ R, Y = Spec R + · rw [IsLocalAtTarget.iff_of_openCover (P := @IsIntegralHom) Y.affineCover] + rw [IsLocalAtTarget.iff_of_openCover (P := @UniversallyClosed) Y.affineCover] at H₁ + rw [IsLocalAtTarget.iff_of_openCover (P := @IsAffineHom) Y.affineCover] at H₂ + exact fun _ ↦ this inferInstance inferInstance ⟨_, rfl⟩ + obtain ⟨R, rfl⟩ := hY + wlog hX : ∃ S, X = Spec S + · have inst : IsAffine X := isAffine_of_isAffineHom f + rw [← cancel_left_of_respectsIso (P := @IsIntegralHom) X.isoSpec.inv] + exact this _ inferInstance inferInstance ⟨_, rfl⟩ + obtain ⟨S, rfl⟩ := hX + obtain ⟨φ, rfl⟩ : ∃ φ, Spec.map φ = f := ⟨_, Spec.map_preimage _⟩ + rw [SpecMap_iff] + apply PrimeSpectrum.isIntegral_of_isClosedMap_comap_mapRingHom + algebraize [φ.1, Polynomial.mapRingHom φ.1] + haveI : IsScalarTower R (Polynomial R) (Polynomial S) := + .of_algebraMap_eq' (Polynomial.mapRingHom_comp_C _).symm + refine H₁.out (Spec.map (CommRingCat.ofHom Polynomial.C)) + (Spec.map (CommRingCat.ofHom Polynomial.C)) (Spec.map _) + (isPullback_Spec_map_isPushout _ _ _ _ + (CommRingCat.isPushout_of_isPushout R S (Polynomial R) (Polynomial S))).flip + +lemma eq_universallyClosed_inf_isAffineHom : + @IsIntegralHom = (@UniversallyClosed ⊓ @IsAffineHom : MorphismProperty Scheme) := by + ext + exact iff_universallyClosed_and_isAffineHom + end IsIntegralHom end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Proper.lean b/Mathlib/AlgebraicGeometry/Morphisms/Proper.lean index dc14fbd74406d..a6e4afb4f19da 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Proper.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Proper.lean @@ -4,15 +4,14 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Christian Merten, Andrew Yang -/ import Mathlib.AlgebraicGeometry.Morphisms.Separated -import Mathlib.AlgebraicGeometry.Morphisms.UniversallyClosed -import Mathlib.AlgebraicGeometry.Morphisms.FiniteType +import Mathlib.AlgebraicGeometry.Morphisms.Finite /-! # Proper morphisms A morphism of schemes is proper if it is separated, universally closed and (locally) of finite type. -Note that we don't require quasi-compact, since this is implied by universally closed (TODO). +Note that we don't require quasi-compact, since this is implied by universally closed. -/ @@ -51,7 +50,7 @@ instance : MorphismProperty.IsMultiplicative @IsProper := by rw [isProper_eq] infer_instance -instance (priority := 900) [IsClosedImmersion f] : IsProper f where +instance (priority := 900) [IsFinite f] : IsProper f where instance isStableUnderBaseChange : MorphismProperty.IsStableUnderBaseChange @IsProper := by rw [isProper_eq] @@ -63,4 +62,16 @@ instance : IsLocalAtTarget @IsProper := by end IsProper +lemma IsFinite.eq_isProper_inf_isAffineHom : + @IsFinite = (@IsProper ⊓ @IsAffineHom : MorphismProperty _) := by + have : (@IsAffineHom ⊓ @IsSeparated : MorphismProperty _) = @IsAffineHom := + inf_eq_left.mpr fun _ _ _ _ ↦ inferInstance + rw [inf_comm, isProper_eq, inf_assoc, ← inf_assoc, this, eq_inf, + IsIntegralHom.eq_universallyClosed_inf_isAffineHom, inf_assoc, inf_left_comm] + +lemma IsFinite.iff_isProper_and_isAffineHom : + IsFinite f ↔ IsProper f ∧ IsAffineHom f := by + rw [eq_isProper_inf_isAffineHom] + rfl + end AlgebraicGeometry diff --git a/Mathlib/RingTheory/IsTensorProduct.lean b/Mathlib/RingTheory/IsTensorProduct.lean index addd18bf5d59f..b0664eeeb4d21 100644 --- a/Mathlib/RingTheory/IsTensorProduct.lean +++ b/Mathlib/RingTheory/IsTensorProduct.lean @@ -447,59 +447,50 @@ instance TensorProduct.isPushout' {R S T : Type*} [CommRing R] [CommRing S] [Com [Algebra R S] [Algebra R T] : Algebra.IsPushout R T S (TensorProduct R S T) := Algebra.IsPushout.symm inferInstance +variable (R S R') in +/-- The isomorphism `S' ≃ S ⊗[R] R` given `Algebra.IsPushout R S R' S'`. -/ +noncomputable +def Algebra.IsPushout.equiv [h : Algebra.IsPushout R S R' S'] : S ⊗[R] R' ≃ₐ[S] S' where + __ := h.out.equiv + map_mul' x y := by + dsimp + induction x with + | zero => simp + | add x y _ _ => simp [*, add_mul] + | tmul a b => + induction y with + | zero => simp + | add x y _ _ => simp [*, mul_add] + | tmul x y => simp [IsBaseChange.equiv_tmul, Algebra.smul_def, mul_mul_mul_comm] + commutes' := by simp [IsBaseChange.equiv_tmul, Algebra.smul_def] + +lemma Algebra.IsPushout.equiv_tmul [h : Algebra.IsPushout R S R' S'] (a : S) (b : R') : + equiv R S R' S' (a ⊗ₜ b) = algebraMap _ _ a * algebraMap _ _ b := + (h.out.equiv_tmul _ _).trans (Algebra.smul_def _ _) + +lemma Algebra.IsPushout.equiv_symm_algebraMap_left [Algebra.IsPushout R S R' S'] (a : S) : + (equiv R S R' S').symm (algebraMap S S' a) = a ⊗ₜ 1 := by + rw [(equiv R S R' S').symm_apply_eq, equiv_tmul, map_one, mul_one] + +lemma Algebra.IsPushout.equiv_symm_algebraMap_right [Algebra.IsPushout R S R' S'] (a : R') : + (equiv R S R' S').symm (algebraMap R' S' a) = 1 ⊗ₜ a := by + rw [(equiv R S R' S').symm_apply_eq, equiv_tmul, map_one, one_mul] + /-- If `S' = S ⊗[R] R'`, then any pair of `R`-algebra homomorphisms `f : S → A` and `g : R' → A` such that `f x` and `g y` commutes for all `x, y` descends to a (unique) homomorphism `S' → A`. -/ @[simps! (config := .lemmasOnly) apply] noncomputable def Algebra.pushoutDesc [H : Algebra.IsPushout R S R' S'] {A : Type*} [Semiring A] [Algebra R A] (f : S →ₐ[R] A) (g : R' →ₐ[R] A) (hf : ∀ x y, f x * g y = g y * f x) : - S' →ₐ[R] A := by - letI := Module.compHom A f.toRingHom - haveI : IsScalarTower R S A := - { smul_assoc := fun r s a => - show f (r • s) * a = r • (f s * a) by rw [map_smul, smul_mul_assoc] } - haveI : IsScalarTower S A A := { smul_assoc := fun r a b => mul_assoc _ _ _ } - have : ∀ x, H.out.lift g.toLinearMap (algebraMap R' S' x) = g x := H.out.lift_eq _ - refine AlgHom.ofLinearMap ((H.out.lift g.toLinearMap).restrictScalars R) ?_ ?_ - · dsimp only [LinearMap.restrictScalars_apply] - rw [← (algebraMap R' S').map_one, this, map_one] - · intro x y - refine H.out.inductionOn x _ ?_ ?_ ?_ ?_ - · rw [zero_mul, map_zero, zero_mul] - rotate_left - · intro s s' e - dsimp only [LinearMap.restrictScalars_apply] at e ⊢ - rw [LinearMap.map_smul, smul_mul_assoc, LinearMap.map_smul, e, smul_mul_assoc] - · intro s s' e₁ e₂ - dsimp only [LinearMap.restrictScalars_apply] at e₁ e₂ ⊢ - rw [add_mul, map_add, map_add, add_mul, e₁, e₂] - intro x - dsimp - rw [this] - refine H.out.inductionOn y _ ?_ ?_ ?_ ?_ - · rw [mul_zero, map_zero, mul_zero] - · intro y - dsimp - rw [← map_mul, this, this, map_mul] - · intro s s' e - rw [mul_comm, smul_mul_assoc, LinearMap.map_smul, LinearMap.map_smul, mul_comm, e] - change f s * (g x * _) = g x * (f s * _) - rw [← mul_assoc, ← mul_assoc, hf] - · intro s s' e₁ e₂ - rw [mul_add, map_add, map_add, mul_add, e₁, e₂] + S' →ₐ[R] A := + (Algebra.TensorProduct.lift f g hf).comp + ((Algebra.IsPushout.equiv R S R' S').symm.toAlgHom.restrictScalars R) @[simp] theorem Algebra.pushoutDesc_left [Algebra.IsPushout R S R' S'] {A : Type*} [Semiring A] [Algebra R A] (f : S →ₐ[R] A) (g : R' →ₐ[R] A) (H) (x : S) : Algebra.pushoutDesc S' f g H (algebraMap S S' x) = f x := by - letI := Module.compHom A f.toRingHom - haveI : IsScalarTower R S A := - { smul_assoc := fun r s a => - show f (r • s) * a = r • (f s * a) by rw [map_smul, smul_mul_assoc] } - haveI : IsScalarTower S A A := { smul_assoc := fun r a b => mul_assoc _ _ _ } - rw [Algebra.algebraMap_eq_smul_one, pushoutDesc_apply, map_smul, ← - Algebra.pushoutDesc_apply S' f g H, map_one] - exact mul_one (f x) + simp [Algebra.pushoutDesc_apply] theorem Algebra.lift_algHom_comp_left [Algebra.IsPushout R S R' S'] {A : Type*} [Semiring A] [Algebra R A] (f : S →ₐ[R] A) (g : R' →ₐ[R] A) (H) : @@ -509,12 +500,8 @@ theorem Algebra.lift_algHom_comp_left [Algebra.IsPushout R S R' S'] {A : Type*} @[simp] theorem Algebra.pushoutDesc_right [Algebra.IsPushout R S R' S'] {A : Type*} [Semiring A] [Algebra R A] (f : S →ₐ[R] A) (g : R' →ₐ[R] A) (H) (x : R') : - Algebra.pushoutDesc S' f g H (algebraMap R' S' x) = g x := - letI := Module.compHom A f.toRingHom - haveI : IsScalarTower R S A := - { smul_assoc := fun r s a => - show f (r • s) * a = r • (f s * a) by rw [map_smul, smul_mul_assoc] } - IsBaseChange.lift_eq _ _ _ + Algebra.pushoutDesc S' f g H (algebraMap R' S' x) = g x := by + simp [Algebra.pushoutDesc_apply, Algebra.IsPushout.equiv_symm_algebraMap_right] theorem Algebra.lift_algHom_comp_right [Algebra.IsPushout R S R' S'] {A : Type*} [Semiring A] [Algebra R A] (f : S →ₐ[R] A) (g : R' →ₐ[R] A) (H) : diff --git a/Mathlib/RingTheory/PolynomialAlgebra.lean b/Mathlib/RingTheory/PolynomialAlgebra.lean index 12ebc739f51b9..e904cb1e4aa13 100644 --- a/Mathlib/RingTheory/PolynomialAlgebra.lean +++ b/Mathlib/RingTheory/PolynomialAlgebra.lean @@ -8,6 +8,7 @@ import Mathlib.Data.Matrix.Basis import Mathlib.Data.Matrix.Composition import Mathlib.Data.Matrix.DMatrix import Mathlib.RingTheory.MatrixAlgebra +import Mathlib.RingTheory.IsTensorProduct /-! # Algebra isomorphism between matrices of polynomials and polynomials of matrices @@ -318,3 +319,21 @@ lemma evalRingHom_mapMatrix_comp_compRingEquiv {m} [Fintype m] [DecidableEq m] : (evalRingHom 0).mapMatrix.comp (compRingEquiv m n R[X]) = (compRingEquiv m n R).toRingHom.comp (evalRingHom 0).mapMatrix.mapMatrix := by ext; simp + +/-- If `S` is an `R`-algebra, then `S[X]` is an `R[X]` algebra. +This gives a diamond for `Algebra R[X] R[X][X]`, so this is not a global instance. -/ +@[reducible] def Polynomial.algebra [Algebra R S] : + Algebra R[X] S[X] := (mapRingHom (algebraMap R S)).toAlgebra + +attribute [local instance] Polynomial.algebra + +instance [Algebra R S] : IsScalarTower R R[X] S[X] := .of_algebraMap_eq' (mapRingHom_comp_C _).symm + +instance {R S : Type*} [CommRing R] [CommRing S] [Algebra R S] : + Algebra.IsPushout R S R[X] S[X] := by + constructor + let e : S[X] ≃ₐ[S] TensorProduct R S R[X] := { __ := polyEquivTensor R S, commutes' := by simp } + convert (TensorProduct.isBaseChange R R[X] S).comp (.ofEquiv e.symm.toLinearEquiv) using 1 + ext : 2 + refine Eq.trans ?_ (polyEquivTensor_symm_apply_tmul R S _ _).symm + simp [RingHom.algebraMap_toAlgebra] From 7e37e86171054745f9bbc26ae2d178ffdd677478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Tue, 4 Feb 2025 06:23:53 +0000 Subject: [PATCH 052/103] feat(CategoryTheory/Enriched): enrichement of functor categories over a functor category (#18976) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let `C` be a category that is enriched over a monoidal category `V` in such a way that the category structure and the enriched category structure are compatible. If `J` is a category and that `V` has certain limits, then the functor category `J ⥤ C` is enriched over `J ⥤ V`. Co-authored-by: Joël Riou <37772949+joelriou@users.noreply.github.com> --- .../Enriched/FunctorCategory.lean | 205 ++++++++++++++---- Mathlib/CategoryTheory/Limits/IsLimit.lean | 17 +- 2 files changed, 178 insertions(+), 44 deletions(-) diff --git a/Mathlib/CategoryTheory/Enriched/FunctorCategory.lean b/Mathlib/CategoryTheory/Enriched/FunctorCategory.lean index 4636b05731fa4..e93aa41a745ae 100644 --- a/Mathlib/CategoryTheory/Enriched/FunctorCategory.lean +++ b/Mathlib/CategoryTheory/Enriched/FunctorCategory.lean @@ -3,6 +3,7 @@ Copyright (c) 2024 Joël Riou. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Joël Riou -/ +import Mathlib.CategoryTheory.Monoidal.FunctorCategory import Mathlib.CategoryTheory.Enriched.Ordinary.Basic import Mathlib.CategoryTheory.Functor.Category import Mathlib.CategoryTheory.Limits.Shapes.End @@ -11,7 +12,17 @@ import Mathlib.CategoryTheory.Limits.Shapes.End # Functor categories are enriched If `C` is a `V`-enriched ordinary category, then `J ⥤ C` is also -a `V`-enriched ordinary category, provided `C` has suitable limits. +both a `V`-enriched ordinary category and a `J ⥤ V`-enriched +ordinary category, provided `C` has suitable limits. + +We first define the `V`-enriched structure on `J ⥤ C` by saying +that if `F₁` and `F₂` are in `J ⥤ C`, then `enrichedHom V F₁ F₂ : V` +is a suitable limit involving `F₁.obj j ⟶[V] F₂.obj j` for all `j : C`. +The `J ⥤ V` object of morphisms `functorEnrichedHom V F₁ F₂ : J ⥤ V` +is defined by sending `j : J` to the previously defined `enrichedHom` +for the "restriction" of `F₁` and `F₂` to the category `Under j`. +The definition `isLimitConeFunctorEnrichedHom` shows that +`enriched V F₁ F₂` is the limit of the functor `functorEnrichedHom V F₁ F₂`. -/ @@ -51,6 +62,12 @@ noncomputable abbrev enrichedHomπ (j : J) : enrichedHom V F₁ F₂ ⟶ F₁.ob @[reassoc] lemma enrichedHom_condition {i j : J} (f : i ⟶ j) : + enrichedHomπ V F₁ F₂ i ≫ eHomWhiskerLeft V (F₁.obj i) (F₂.map f) = + enrichedHomπ V F₁ F₂ j ≫ eHomWhiskerRight V (F₁.map f) (F₂.obj j) := + end_.condition (diagram V F₁ F₂) f + +@[reassoc] +lemma enrichedHom_condition' {i j : J} (f : i ⟶ j) : enrichedHomπ V F₁ F₂ i ≫ (ρ_ _).inv ≫ _ ◁ (eHomEquiv V) (F₂.map f) ≫ eComp V _ _ _ = enrichedHomπ V F₁ F₂ j ≫ (λ_ _).inv ≫ @@ -60,7 +77,7 @@ lemma enrichedHom_condition {i j : J} (f : i ⟶ j) : variable {F₁ F₂} /-- Given functors `F₁` and `F₂` in `J ⥤ C`, where `C` is a `V`-enriched ordinary category, -this is the isomorphism `(F₁ ⟶ F₂) ≃ (𝟙_ V ⟶ enrichedHom V F₁ F₂)` in the category `V`. -/ +this is the bijection `(F₁ ⟶ F₂) ≃ (𝟙_ V ⟶ enrichedHom V F₁ F₂)`. -/ noncomputable def homEquiv : (F₁ ⟶ F₂) ≃ (𝟙_ V ⟶ enrichedHom V F₁ F₂) where toFun τ := end_.lift (fun j ↦ eHomEquiv V (τ.app j)) (fun i j f ↦ by trans eHomEquiv V (τ.app i ≫ F₂.map f) @@ -77,7 +94,7 @@ noncomputable def homEquiv : (F₁ ⟶ F₂) ≃ (𝟙_ V ⟶ enrichedHom V F₁ simp only [eHomEquiv_comp, Equiv.apply_symm_apply, Iso.cancel_iso_inv_left] conv_rhs => rw [tensorHom_def_assoc, MonoidalCategory.whiskerRight_id_assoc, assoc, - enrichedHom_condition V F₁ F₂ f] + enrichedHom_condition' V F₁ F₂ f] conv_lhs => rw [tensorHom_def'_assoc, MonoidalCategory.whiskerLeft_comp_assoc, id_whiskerLeft_assoc, id_whiskerLeft_assoc, Iso.inv_hom_id_assoc, unitors_equal]) } @@ -95,7 +112,7 @@ section variable [HasEnrichedHom V F₁ F₁] -/-- The identity for the `V`-enrichment of the category `J ⥤ C` over `V`. -/ +/-- The identity for the `V`-enrichment of the category `J ⥤ C`. -/ noncomputable def enrichedId : 𝟙_ V ⟶ enrichedHom V F₁ F₁ := homEquiv _ (𝟙 F₁) @[reassoc (attr := simp)] @@ -111,7 +128,7 @@ section variable [HasEnrichedHom V F₁ F₂] [HasEnrichedHom V F₂ F₃] [HasEnrichedHom V F₁ F₃] -/-- The composition for the `V`-enrichment of the category `J ⥤ C` over `V`. -/ +/-- The composition for the `V`-enrichment of the category `J ⥤ C`. -/ noncomputable def enrichedComp : enrichedHom V F₁ F₂ ⊗ enrichedHom V F₂ F₃ ⟶ enrichedHom V F₁ F₃ := end_.lift (fun j ↦ (end_.π _ j ⊗ end_.π _ j) ≫ eComp V _ _ _) (fun i j f ↦ by dsimp @@ -221,19 +238,41 @@ variable {J C} section variable (G : K ⥤ J) [HasEnrichedHom V F₁ F₂] - [HasEnrichedHom V (G ⋙ F₁) (G ⋙ F₂)] + +variable {F₁ F₂} in +/-- If `F₁` and `F₂` are functors `J ⥤ C`, `G : K ⥤ J`, and +`F₁'` and `F₂'` are functors `K ⥤ C` that are respectively +isomorphic to `G ⋙ F₁` and `G ⋙ F₂`, then this is the +induced morphism `enrichedHom V F₁ F₂ ⟶ enrichedHom V F₁' F₂'` in `V` +when `C` is a category enriched in `V`. -/ +noncomputable abbrev precompEnrichedHom' {F₁' F₂' : K ⥤ C} + [HasEnrichedHom V F₁' F₂'] (e₁ : G ⋙ F₁ ≅ F₁') (e₂ : G ⋙ F₂ ≅ F₂') : + enrichedHom V F₁ F₂ ⟶ enrichedHom V F₁' F₂' := + end_.lift (fun x ↦ enrichedHomπ V F₁ F₂ (G.obj x) ≫ + (eHomWhiskerRight _ (e₁.inv.app x) _ ≫ eHomWhiskerLeft _ _ (e₂.hom.app x))) + (fun i j f ↦ by + dsimp + rw [assoc, assoc, assoc, assoc, ← eHomWhiskerLeft_comp, + ← eHom_whisker_exchange, ← e₂.hom.naturality f, + eHomWhiskerLeft_comp_assoc] + dsimp + rw [enrichedHom_condition_assoc, eHom_whisker_exchange, + eHom_whisker_exchange, ← eHomWhiskerRight_comp_assoc, + ← eHomWhiskerRight_comp_assoc, NatTrans.naturality] + dsimp ) /-- If `F₁` and `F₂` are functors `J ⥤ C`, and `G : K ⥤ J`, then this is the induced morphism `enrichedHom V F₁ F₂ ⟶ enrichedHom V (G ⋙ F₁) (G ⋙ F₂)` in `V` when `C` is a category enriched in `V`. -/ -noncomputable abbrev precompEnrichedHom : +noncomputable abbrev precompEnrichedHom + [HasEnrichedHom V (G ⋙ F₁) (G ⋙ F₂)] : enrichedHom V F₁ F₂ ⟶ enrichedHom V (G ⋙ F₁) (G ⋙ F₂) := - end_.lift (fun x ↦ enrichedHomπ V F₁ F₂ (G.obj x)) - (fun _ _ f ↦ enrichedHom_condition V F₁ F₂ (G.map f)) + precompEnrichedHom' V G (Iso.refl _) (Iso.refl _) end + section /-- Given functors `F₁` and `F₂` in `J ⥤ C`, where `C` is a category enriched in `V`, @@ -253,20 +292,24 @@ this is the enriched hom functor from `F₁` to `F₂` in `J ⥤ V`. -/ @[simps!] noncomputable def functorEnrichedHom : J ⥤ V where obj j := enrichedHom V (Under.forget j ⋙ F₁) (Under.forget j ⋙ F₂) - map f := precompEnrichedHom V (Under.forget _ ⋙ F₁) (Under.forget _ ⋙ F₂) (Under.map f) + map f := precompEnrichedHom' V (Under.map f) (Iso.refl _) (Iso.refl _) map_id X := by dsimp ext j - dsimp - simp only [end_.lift_π, id_comp] + -- this was produced by `simp?` + simp only [diagram_obj_obj, Functor.comp_obj, Under.forget_obj, end_.lift_π, + Under.map_obj_right, Iso.refl_inv, NatTrans.id_app, eHomWhiskerRight_id, Iso.refl_hom, + eHomWhiskerLeft_id, comp_id, id_comp] congr 1 simp [Under.map, Comma.mapLeft] rfl map_comp f g := by dsimp ext j - rw [end_.lift_π, assoc] - erw [end_.lift_π, end_.lift_π] + -- this was produced by `simp?` + simp only [diagram_obj_obj, Functor.comp_obj, Under.forget_obj, end_.lift_π, + Under.map_obj_right, Iso.refl_inv, NatTrans.id_app, eHomWhiskerRight_id, Iso.refl_hom, + eHomWhiskerLeft_id, comp_id, assoc] congr 1 simp [Under.map, Comma.mapLeft] @@ -274,19 +317,10 @@ variable [HasEnrichedHom V F₁ F₂] /-- The (limit) cone expressing that the limit of `functorEnrichedHom V F₁ F₂` is `enrichedHom V F₁ F₂`. -/ -@[simps pt] +@[simps] noncomputable def coneFunctorEnrichedHom : Cone (functorEnrichedHom V F₁ F₂) where pt := enrichedHom V F₁ F₂ - π := - { app := fun j ↦ precompEnrichedHom V F₁ F₂ (Under.forget j) - naturality := fun j j' f ↦ by - dsimp - rw [id_comp] - ext k - rw [assoc, end_.lift_π] - erw [end_.lift_π] - rw [end_.lift_π] - rfl } + π := { app := fun j ↦ precompEnrichedHom V F₁ F₂ (Under.forget j) } namespace isLimitConeFunctorEnrichedHom @@ -297,10 +331,14 @@ noncomputable def lift : s.pt ⟶ enrichedHom V F₁ F₂ := end_.lift (fun j ↦ s.π.app j ≫ enrichedHomπ V _ _ (Under.mk (𝟙 j))) (fun j j' f ↦ by dsimp rw [← s.w f, assoc, assoc, assoc] - dsimp [functorEnrichedHom] - erw [end_.lift_π_assoc, - enrichedHom_condition V (Under.forget j ⋙ F₁) (Under.forget j ⋙ F₂) - (Under.homMk f : Under.mk (𝟙 j) ⟶ Under.mk f)] + -- this was produced by `simp?` + simp only [functorEnrichedHom_obj, functorEnrichedHom_map, end_.lift_π_assoc, diagram_obj_obj, + Functor.comp_obj, Under.forget_obj, Under.mk_right, Under.map_obj_right, Iso.refl_inv, + NatTrans.id_app, eHomWhiskerRight_id, Iso.refl_hom, eHomWhiskerLeft_id, comp_id] + have := enrichedHom_condition V (Under.forget j ⋙ F₁) (Under.forget j ⋙ F₂) + (Under.homMk f : Under.mk (𝟙 j) ⟶ Under.mk f) + dsimp at this + rw [this] congr 3 simp [Under.map, Comma.mapLeft] rfl) @@ -308,11 +346,12 @@ noncomputable def lift : s.pt ⟶ enrichedHom V F₁ F₂ := lemma fac (j : J) : lift s ≫ (coneFunctorEnrichedHom V F₁ F₂).π.app j = s.π.app j := by dsimp [coneFunctorEnrichedHom] ext k - rw [assoc] - erw [end_.lift_π, end_.lift_π, ← s.w k.hom] - rw [assoc] - dsimp - erw [end_.lift_π] + have := s.w k.hom + dsimp at this + -- this was produced by `simp? [lift, ← this]` + simp only [diagram_obj_obj, Functor.comp_obj, Under.forget_obj, lift, functorEnrichedHom_obj, + assoc, end_.lift_π, Iso.refl_inv, NatTrans.id_app, eHomWhiskerRight_id, Iso.refl_hom, + eHomWhiskerLeft_id, comp_id, ← this, Under.map_obj_right, Under.mk_right] congr simp [Under.map, Comma.mapLeft] rfl @@ -328,11 +367,101 @@ noncomputable def isLimitConeFunctorEnrichedHom : uniq s m hm := by dsimp ext j - have := ((hm j).trans (fac s j).symm) =≫ enrichedHomπ V _ _ (Under.mk (𝟙 j)) - dsimp [coneFunctorEnrichedHom] at this - rw [assoc, assoc, end_.lift_π] at this - exact this + simpa using ((hm j).trans (fac s j).symm) =≫ enrichedHomπ V _ _ (Under.mk (𝟙 j)) end +/-- The identity for the `J ⥤ V`-enrichment of the category `J ⥤ C`. -/ +@[simps] +noncomputable def functorEnrichedId [HasFunctorEnrichedHom V F₁ F₁] : + 𝟙_ (J ⥤ V) ⟶ functorEnrichedHom V F₁ F₁ where + app j := enrichedId V _ + +/-- The composition for the `J ⥤ V`-enrichment of the category `J ⥤ C`. -/ +@[simps] +noncomputable def functorEnrichedComp [HasFunctorEnrichedHom V F₁ F₂] + [HasFunctorEnrichedHom V F₂ F₃] [HasFunctorEnrichedHom V F₁ F₃] : + functorEnrichedHom V F₁ F₂ ⊗ functorEnrichedHom V F₂ F₃ ⟶ functorEnrichedHom V F₁ F₃ where + app j := enrichedComp V _ _ _ + naturality j j' f := by + dsimp + ext k + dsimp + rw [assoc, assoc, enrichedComp_π] + dsimp + rw [← tensor_comp_assoc] + simp + +@[reassoc (attr := simp)] +lemma functorEnriched_id_comp [HasFunctorEnrichedHom V F₁ F₂] [HasFunctorEnrichedHom V F₁ F₁] : + (λ_ (functorEnrichedHom V F₁ F₂)).inv ≫ + functorEnrichedId V F₁ ▷ functorEnrichedHom V F₁ F₂ ≫ + functorEnrichedComp V F₁ F₁ F₂ = 𝟙 (functorEnrichedHom V F₁ F₂) := by aesop_cat + +@[reassoc (attr := simp)] +lemma functorEnriched_comp_id [HasFunctorEnrichedHom V F₁ F₂] [HasFunctorEnrichedHom V F₂ F₂] : + (ρ_ (functorEnrichedHom V F₁ F₂)).inv ≫ + functorEnrichedHom V F₁ F₂ ◁ functorEnrichedId V F₂ ≫ + functorEnrichedComp V F₁ F₂ F₂ = 𝟙 (functorEnrichedHom V F₁ F₂) := by aesop_cat + +@[reassoc] +lemma functorEnriched_assoc [HasFunctorEnrichedHom V F₁ F₂] [HasFunctorEnrichedHom V F₂ F₃] + [HasFunctorEnrichedHom V F₃ F₄] [HasFunctorEnrichedHom V F₁ F₃] + [HasFunctorEnrichedHom V F₂ F₄] [HasFunctorEnrichedHom V F₁ F₄] : + (α_ _ _ _).inv ≫ functorEnrichedComp V F₁ F₂ F₃ ▷ functorEnrichedHom V F₃ F₄ ≫ + functorEnrichedComp V F₁ F₃ F₄ = + functorEnrichedHom V F₁ F₂ ◁ functorEnrichedComp V F₂ F₃ F₄ ≫ + functorEnrichedComp V F₁ F₂ F₄ := by + ext j + dsimp + rw [enriched_assoc] + +variable (J C) in +/-- If `C` is a `V`-enriched ordinary category, and `C` has suitable limits, +then `J ⥤ C` is also a `J ⥤ V`-enriched ordinary category. -/ +noncomputable def functorEnrichedCategory + [∀ (F₁ F₂ : J ⥤ C), HasFunctorEnrichedHom V F₁ F₂] : + EnrichedCategory (J ⥤ V) (J ⥤ C) where + Hom F₁ F₂ := functorEnrichedHom V F₁ F₂ + id F := functorEnrichedId V F + comp F₁ F₂ F₃ := functorEnrichedComp V F₁ F₂ F₃ + assoc F₁ F₂ F₃ F₄ := functorEnriched_assoc V F₁ F₂ F₃ F₄ + +variable {F₁ F₂} in +/-- Given functors `F₁` and `F₂` in `J ⥤ C`, where `C` is a `V`-enriched ordinary category, +this is the bijection `(F₁ ⟶ F₂) ≃ (𝟙_ (J ⥤ V) ⟶ functorEnrichedHom V F₁ F₂)`. -/ +@[simps! apply_app] +noncomputable def functorHomEquiv [HasFunctorEnrichedHom V F₁ F₂] [HasEnrichedHom V F₁ F₂] : + (F₁ ⟶ F₂) ≃ (𝟙_ (J ⥤ V) ⟶ functorEnrichedHom V F₁ F₂) := + (homEquiv V).trans (isLimitConeFunctorEnrichedHom V F₁ F₂).homEquiv + +lemma functorHomEquiv_id [HasFunctorEnrichedHom V F₁ F₁] [HasEnrichedHom V F₁ F₁] : + (functorHomEquiv V) (𝟙 F₁) = functorEnrichedId V F₁ := by aesop_cat + +variable {F₁ F₂ F₃} in +lemma functorHomEquiv_comp [HasFunctorEnrichedHom V F₁ F₂] [HasEnrichedHom V F₁ F₂] + [HasFunctorEnrichedHom V F₂ F₃] [HasEnrichedHom V F₂ F₃] + [HasFunctorEnrichedHom V F₁ F₃] [HasEnrichedHom V F₁ F₃] + (f : F₁ ⟶ F₂) (g : F₂ ⟶ F₃) : + (functorHomEquiv V) (f ≫ g) = (λ_ (𝟙_ (J ⥤ V))).inv ≫ + ((functorHomEquiv V) f ⊗ (functorHomEquiv V) g) ≫ functorEnrichedComp V F₁ F₂ F₃ := by + ext j + dsimp + ext k + rw [homEquiv_comp, assoc, assoc, assoc, assoc, assoc, end_.lift_π, enrichedComp_π] + simp [← tensor_comp_assoc] + +attribute [local instance] functorEnrichedCategory + +variable (J C) in +/-- If `C` is a `V`-enriched ordinary category, and `C` has suitable limits, +then `J ⥤ C` is also a `J ⥤ V`-enriched ordinary category. -/ +noncomputable def functorEnrichedOrdinaryCategory + [∀ (F₁ F₂ : J ⥤ C), HasFunctorEnrichedHom V F₁ F₂] + [∀ (F₁ F₂ : J ⥤ C), HasEnrichedHom V F₁ F₂] : + EnrichedOrdinaryCategory (J ⥤ V) (J ⥤ C) where + homEquiv := functorHomEquiv V + homEquiv_id F := functorHomEquiv_id V F + homEquiv_comp f g := functorHomEquiv_comp V f g + end CategoryTheory.Enriched.FunctorCategory diff --git a/Mathlib/CategoryTheory/Limits/IsLimit.lean b/Mathlib/CategoryTheory/Limits/IsLimit.lean index aead84cff4f8a..8c4e88bc3b3cc 100644 --- a/Mathlib/CategoryTheory/Limits/IsLimit.lean +++ b/Mathlib/CategoryTheory/Limits/IsLimit.lean @@ -351,14 +351,19 @@ def conePointsIsoOfEquivalence {F : J ⥤ C} {s : Cone F} {G : K ⥤ C} {t : Con end Equivalence +/-- The universal property of a limit cone: a wap `W ⟶ t.pt` is the same as + a cone on `F` with cone point `W`. -/ +@[simps apply] +def homEquiv (h : IsLimit t) {W : C} : (W ⟶ t.pt) ≃ ((Functor.const J).obj W ⟶ F) where + toFun f := (t.extend f).π + invFun π := h.lift (Cone.mk _ π) + left_inv f := h.hom_ext (by simp) + right_inv π := by aesop_cat + /-- The universal property of a limit cone: a map `W ⟶ X` is the same as a cone on `F` with cone point `W`. -/ -def homIso (h : IsLimit t) (W : C) : ULift.{u₁} (W ⟶ t.pt : Type v₃) ≅ (const J).obj W ⟶ F where - hom f := (t.extend f.down).π - inv π := ⟨h.lift { pt := W, π }⟩ - hom_inv_id := by - funext f; apply ULift.ext - apply h.hom_ext; intro j; simp +def homIso (h : IsLimit t) (W : C) : ULift.{u₁} (W ⟶ t.pt : Type v₃) ≅ (const J).obj W ⟶ F := + Equiv.toIso (Equiv.ulift.trans h.homEquiv) @[simp] theorem homIso_hom (h : IsLimit t) {W : C} (f : ULift.{u₁} (W ⟶ t.pt)) : From 62d4aefeb87eeb08a5030b8da7069f4a1ce87783 Mon Sep 17 00:00:00 2001 From: Andrew Yang Date: Tue, 4 Feb 2025 06:23:54 +0000 Subject: [PATCH 053/103] feat(AlgebraicGeometry): ideal sheaf data on a scheme (#21052) Co-authored-by: Andrew Yang <36414270+erdOne@users.noreply.github.com> --- Mathlib.lean | 1 + Mathlib/AlgebraicGeometry/AffineScheme.lean | 34 +++ Mathlib/AlgebraicGeometry/IdealSheaf.lean | 300 ++++++++++++++++++++ Mathlib/RingTheory/Localization/Ideal.lean | 11 + 4 files changed, 346 insertions(+) create mode 100644 Mathlib/AlgebraicGeometry/IdealSheaf.lean diff --git a/Mathlib.lean b/Mathlib.lean index 4d002f3a687f9..67712d2f7132c 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -1027,6 +1027,7 @@ import Mathlib.AlgebraicGeometry.FunctionField import Mathlib.AlgebraicGeometry.GammaSpecAdjunction import Mathlib.AlgebraicGeometry.Gluing import Mathlib.AlgebraicGeometry.GluingOneHypercover +import Mathlib.AlgebraicGeometry.IdealSheaf import Mathlib.AlgebraicGeometry.Limits import Mathlib.AlgebraicGeometry.Modules.Presheaf import Mathlib.AlgebraicGeometry.Modules.Sheaf diff --git a/Mathlib/AlgebraicGeometry/AffineScheme.lean b/Mathlib/AlgebraicGeometry/AffineScheme.lean index b4abde67aa374..af4d698aa28b0 100644 --- a/Mathlib/AlgebraicGeometry/AffineScheme.lean +++ b/Mathlib/AlgebraicGeometry/AffineScheme.lean @@ -758,12 +758,46 @@ lemma stalkMap_injective (f : X ⟶ Y) {U : Opens Y} (hU : IsAffineOpen U) (x : apply (hU.isLocalization_stalk ⟨f.base x, hx⟩).injective_of_map_algebraMap_zero exact h +include hU in +lemma mem_ideal_iff {s : Γ(X, U)} {I : Ideal Γ(X, U)} : + s ∈ I ↔ ∀ (x : X) (h : x ∈ U), X.presheaf.germ U x h s ∈ I.map (X.presheaf.germ U x h).hom := by + refine ⟨fun hs x hxU ↦ Ideal.mem_map_of_mem _ hs, fun H ↦ ?_⟩ + letI (x) : Algebra Γ(X, U) (X.presheaf.stalk (hU.fromSpec.base x)) := + TopCat.Presheaf.algebra_section_stalk X.presheaf _ + have (P : Ideal Γ(X, U)) [hP : P.IsPrime] : IsLocalization.AtPrime _ P := + hU.isLocalization_stalk' ⟨P, hP⟩ (hU.isoSpec.inv.base _).2 + have (P : Ideal Γ(X, U)) [hP : P.IsPrime] : IsLocalizedModule P.primeCompl _ := + (@isLocalizedModule_iff_isLocalization' ..).mpr (this P) + refine Submodule.mem_of_localization_maximal + (fun P hP ↦ X.presheaf.stalk (hU.fromSpec.base ⟨P, hP.isPrime⟩)) + (fun P hP ↦ Algebra.linearMap _ _) _ _ ?_ + intro P hP + rw [Ideal.localized₀_eq_restrictScalars_map] + exact H _ _ + +include hU in +lemma ideal_le_iff {I J : Ideal Γ(X, U)} : + I ≤ J ↔ ∀ (x : X) (h : x ∈ U), + I.map (X.presheaf.germ U x h).hom ≤ J.map (X.presheaf.germ U x h).hom := + ⟨fun h _ _ ↦ Ideal.map_mono h, + fun H _ hs ↦ hU.mem_ideal_iff.mpr fun x hx ↦ H x hx (Ideal.mem_map_of_mem _ hs)⟩ + +include hU in +lemma ideal_ext_iff {I J : Ideal Γ(X, U)} : + I = J ↔ ∀ (x : X) (h : x ∈ U), + I.map (X.presheaf.germ U x h).hom = J.map (X.presheaf.germ U x h).hom := by + simp_rw [le_antisymm_iff, hU.ideal_le_iff, forall_and] + /-- The basic open set of a section `f` on an affine open as an `X.affineOpens`. -/ @[simps] def _root_.AlgebraicGeometry.Scheme.affineBasicOpen (X : Scheme) {U : X.affineOpens} (f : Γ(X, U)) : X.affineOpens := ⟨X.basicOpen f, U.prop.basicOpen f⟩ +lemma _root_.AlgebraicGeometry.Scheme.affineBasicOpen_le + (X : Scheme) {V : X.affineOpens} (f : Γ(X, V.1)) : X.affineBasicOpen f ≤ V := + X.basicOpen_le f + include hU in /-- In an affine open set `U`, a family of basic open covers `U` iff the sections span `Γ(X, U)`. diff --git a/Mathlib/AlgebraicGeometry/IdealSheaf.lean b/Mathlib/AlgebraicGeometry/IdealSheaf.lean new file mode 100644 index 0000000000000..d43dde1affebf --- /dev/null +++ b/Mathlib/AlgebraicGeometry/IdealSheaf.lean @@ -0,0 +1,300 @@ +/- +Copyright (c) 2025 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.AlgebraicGeometry.AffineScheme +import Mathlib.Topology.LocalAtTarget + +/-! +# Ideal sheaves on schemes + +We define ideal sheaves of schemes and provide various constructors for it. + +## Main definition +* `AlgebraicGeometry.Scheme.IdealSheafData`: A structure that contains the data to uniquely define + an ideal sheaf, consisting of + 1. an ideal `I(U) ≤ Γ(X, U)` for every affine open `U` + 2. a proof that `I(D(f)) = I(U)_f` for every affine open `U` and every section `f : Γ(X, U)`. +* `AlgebraicGeometry.Scheme.IdealSheafData.ofIdeals`: + The largest ideal sheaf contained in a family of ideals. +* `AlgebraicGeometry.Scheme.IdealSheafData.equivOfIsAffine`: + Over affine schemes, ideal sheaves are in bijection with ideals of the global sections. +* `AlgebraicGeometry.Scheme.IdealSheafData.support`: + The support of an ideal sheaf. + +## Implementation detail + +Ideal sheaves are not yet defined in this file as actual subsheaves of `𝒪ₓ`. +Instead, for the ease of development and application, +we define the structure `IdealSheafData` containing all necessary data to uniquely define an +ideal sheaf. This should be refectored as a constructor for ideal sheaves once they are introduced +into mathlib. + +-/ + +open CategoryTheory + +universe u + +namespace AlgebraicGeometry.Scheme + +variable {X : Scheme.{u}} + +/-- +A structure that contains the data to uniquely define an ideal sheaf, consisting of +1. an ideal `I(U) ≤ Γ(X, U)` for every affine open `U` +2. a proof that `I(D(f)) = I(U)_f` for every affine open `U` and every section `f : Γ(X, U)`. +-/ +@[ext] +structure IdealSheafData (X : Scheme.{u}) : Type u where + /-- The component of an ideal sheaf at an affine open. -/ + ideal : ∀ U : X.affineOpens, Ideal Γ(X, U) + /-- Also see `AlgebraicGeometry.Scheme.IdealSheafData.map_ideal` -/ + map_ideal_basicOpen : ∀ (U : X.affineOpens) (f : Γ(X, U)), + (ideal U).map (X.presheaf.map (homOfLE <| X.basicOpen_le f).op).hom = + ideal (X.affineBasicOpen f) + +namespace IdealSheafData + +section Order + +instance : PartialOrder (IdealSheafData X) := PartialOrder.lift ideal fun _ _ ↦ IdealSheafData.ext + +lemma le_def {I J : IdealSheafData X} : I ≤ J ↔ ∀ U, I.ideal U ≤ J.ideal U := .rfl + +instance : CompleteSemilatticeSup (IdealSheafData X) where + sSup s := ⟨sSup (ideal '' s), by + have : sSup (ideal '' s) = ⨆ i : s, ideal i.1 := by + conv_lhs => rw [← Subtype.range_val (s := s), ← Set.range_comp] + rfl + simp only [this, iSup_apply, Ideal.map_iSup, map_ideal_basicOpen, implies_true]⟩ + le_sSup s x hxs := le_sSup (s := ideal '' s) ⟨_, hxs, rfl⟩ + sSup_le s i hi := sSup_le (s := ideal '' s) (Set.forall_mem_image.mpr hi) + +/-- The largest ideal sheaf contained in a family of ideals. -/ +def ofIdeals (I : ∀ U : X.affineOpens, Ideal Γ(X, U)) : IdealSheafData X := + sSup { J : IdealSheafData X | J.ideal ≤ I } + +lemma ideal_ofIdeals_le (I : ∀ U : X.affineOpens, Ideal Γ(X, U)) : + (ofIdeals I).ideal ≤ I := + sSup_le (Set.forall_mem_image.mpr fun _ ↦ id) + +/-- The galois coinsertion between ideal sheaves and arbitrary families of ideals. -/ +protected def gci : GaloisCoinsertion ideal (ofIdeals (X := X)) where + choice I hI := ⟨I, fun U f ↦ + (ideal_ofIdeals_le I).antisymm hI ▸ (ofIdeals I).map_ideal_basicOpen U f⟩ + gc _ _ := ⟨(le_sSup ·), (le_trans · (ideal_ofIdeals_le _))⟩ + u_l_le _ := sSup_le fun _ ↦ id + choice_eq I hI := IdealSheafData.ext (hI.antisymm (ideal_ofIdeals_le I)) + +lemma strictMono_ideal : StrictMono (ideal (X := X)) := IdealSheafData.gci.strictMono_l +lemma ideal_mono : Monotone (ideal (X := X)) := strictMono_ideal.monotone +lemma ofIdeals_mono : Monotone (ofIdeals (X := X)) := IdealSheafData.gci.gc.monotone_u +lemma ofIdeals_ideal (I : IdealSheafData X) : ofIdeals I.ideal = I := IdealSheafData.gci.u_l_eq _ +lemma le_ofIdeals_iff {I : IdealSheafData X} {J} : I ≤ ofIdeals J ↔ I.ideal ≤ J := + IdealSheafData.gci.gc.le_iff_le.symm + +instance : CompleteLattice (IdealSheafData X) where + __ := inferInstanceAs (CompleteSemilatticeSup (IdealSheafData X)) + __ := IdealSheafData.gci.liftCompleteLattice + +@[simp] +lemma ideal_top : ideal (X := X) ⊤ = ⊤ := + top_le_iff.mp (ideal_mono (le_top (a := ⟨⊤, by simp [Ideal.map_top]⟩))) + +@[simp] +lemma ideal_bot : ideal (X := X) ⊥ = ⊥ := rfl + +@[simp] +lemma ideal_sup {I J : IdealSheafData X} : (I ⊔ J).ideal = I.ideal ⊔ J.ideal := rfl + +@[simp] +lemma ideal_sSup {I : Set (IdealSheafData X)} : (sSup I).ideal = sSup (ideal '' I) := rfl + +@[simp] +lemma ideal_iSup {ι : Type*} {I : ι → IdealSheafData X} : (iSup I).ideal = ⨆ i, (I i).ideal := by + show sSup _ = sSup _ + rw [← Set.range_comp] + rfl + +@[simp] +lemma ideal_inf {I J : IdealSheafData X} : (I ⊓ J).ideal = I.ideal ⊓ J.ideal := by + let K : IdealSheafData X := ⟨I.ideal ⊓ J.ideal, by + intro U f + dsimp + have : (X.presheaf.map (homOfLE (X.basicOpen_le f)).op).hom = algebraMap _ _ := rfl + have inst := U.2.isLocalization_basicOpen f + rw [← I.map_ideal_basicOpen U f, ← J.map_ideal_basicOpen U f, this] + ext x + obtain ⟨x, s, rfl⟩ := IsLocalization.mk'_surjective (.powers f) x + simp only [IsLocalization.mk'_mem_map_algebraMap_iff, Submonoid.mem_powers_iff, Ideal.mem_inf, + exists_exists_eq_and] + refine ⟨fun ⟨n, h₁, h₂⟩ ↦ ⟨⟨n, h₁⟩, ⟨n, h₂⟩⟩, ?_⟩ + rintro ⟨⟨n₁, h₁⟩, ⟨n₂, h₂⟩⟩ + refine ⟨n₁ + n₂, ?_, ?_⟩ + · rw [add_comm, pow_add, mul_assoc]; exact Ideal.mul_mem_left _ _ h₁ + · rw [pow_add, mul_assoc]; exact Ideal.mul_mem_left _ _ h₂⟩ + exact (le_inf (ideal_mono inf_le_left) (ideal_mono inf_le_right)).antisymm + ((le_ofIdeals_iff (I := K)).mpr le_rfl) + +@[simp] +lemma ideal_biInf {ι : Type*} (I : ι → IdealSheafData X) {s : Set ι} (hs : s.Finite) : + (⨅ i ∈ s, I i).ideal = ⨅ i ∈ s, (I i).ideal := by + refine hs.induction_on _ (by simp) fun {i s} his hs e ↦ ?_ + simp only [iInf_insert, e, ideal_inf] + +@[simp] +lemma ideal_iInf {ι : Type*} (I : ι → IdealSheafData X) [Finite ι] : + (⨅ i, I i).ideal = ⨅ i, (I i).ideal := by + simpa using ideal_biInf I Set.finite_univ + +end Order + +variable (I : IdealSheafData X) + +section map_ideal + +/-- subsumed by `IdealSheafData.map_ideal` below. -/ +private lemma map_ideal_basicOpen_of_eq + {U V : X.affineOpens} (f : Γ(X, U)) (hV : V = X.affineBasicOpen f) : + (I.ideal U).map (X.presheaf.map + (homOfLE (X := X.Opens) (hV.trans_le (X.affineBasicOpen_le f))).op).hom = + I.ideal V := by + subst hV; exact I.map_ideal_basicOpen _ _ + +lemma map_ideal {U V : X.affineOpens} (h : U ≤ V) : + (I.ideal V).map (X.presheaf.map (homOfLE h).op).hom = I.ideal U := by + rw [U.2.ideal_ext_iff] + intro x hxU + obtain ⟨f, g, hfg, hxf⟩ := exists_basicOpen_le_affine_inter U.2 V.2 x ⟨hxU, h hxU⟩ + have := I.map_ideal_basicOpen_of_eq (V := X.affineBasicOpen g) f (Subtype.ext hfg.symm) + rw [← I.map_ideal_basicOpen] at this + apply_fun Ideal.map (X.presheaf.germ (X.basicOpen g) x (hfg ▸ hxf)).hom at this + simp only [Ideal.map_map, ← RingHom.comp_apply, ← CommRingCat.hom_comp, + affineBasicOpen_coe, X.presheaf.germ_res] at this ⊢ + simp only [homOfLE_leOfHom, TopCat.Presheaf.germ_res', this] + +/-- A form of `map_ideal` that is easier to rewrite with. -/ +lemma map_ideal' {U V : X.affineOpens} (h : Opposite.op V.1 ⟶ .op U.1) : + (I.ideal V).map (X.presheaf.map h).hom = I.ideal U := + map_ideal _ _ + +lemma ideal_le_comap_ideal {U V : X.affineOpens} (h : U ≤ V) : + I.ideal V ≤ (I.ideal U).comap (X.presheaf.map (homOfLE h).op).hom := by + rw [← Ideal.map_le_iff_le_comap, ← I.map_ideal h] + +end map_ideal + +section IsAffine + +/-- The ideal sheaf induced by an ideal of the global sections. -/ +@[simps] +def ofIdealTop (I : Ideal Γ(X, ⊤)) : IdealSheafData X where + ideal U := I.map (X.presheaf.map (homOfLE le_top).op).hom + map_ideal_basicOpen U f := by rw [Ideal.map_map, ← CommRingCat.hom_comp, ← Functor.map_comp]; rfl + +lemma le_of_isAffine [IsAffine X] {I J : IdealSheafData X} + (H : I.ideal ⟨⊤, isAffineOpen_top X⟩ ≤ J.ideal ⟨⊤, isAffineOpen_top X⟩) : I ≤ J := by + intro U + rw [← map_ideal (U := U) (V := ⟨⊤, isAffineOpen_top X⟩) I (le_top (a := U.1)), + ← map_ideal (U := U) (V := ⟨⊤, isAffineOpen_top X⟩) J (le_top (a := U.1))] + exact Ideal.map_mono H + +lemma ext_of_isAffine [IsAffine X] {I J : IdealSheafData X} + (H : I.ideal ⟨⊤, isAffineOpen_top X⟩ = J.ideal ⟨⊤, isAffineOpen_top X⟩) : I = J := + (le_of_isAffine H.le).antisymm (le_of_isAffine H.ge) + +/-- Over affine schemes, ideal sheaves are in bijection with ideals of the global sections. -/ +@[simps] +def equivOfIsAffine [IsAffine X] : IdealSheafData X ≃ Ideal Γ(X, ⊤) where + toFun := (ideal · ⟨⊤, isAffineOpen_top X⟩) + invFun := ofIdealTop + left_inv I := ext_of_isAffine (by simp) + right_inv I := by simp + +end IsAffine + +section support + +/-- The support of an ideal sheaf. Also see `IdealSheafData.mem_support_iff_of_mem`. -/ +def support (I : IdealSheafData X) : Set X := ⋂ U, X.zeroLocus (U := U.1) (I.ideal U) + +lemma mem_support_iff {I : IdealSheafData X} {x} : + x ∈ I.support ↔ ∀ U, x ∈ X.zeroLocus (U := U.1) (I.ideal U) := Set.mem_iInter + +lemma support_subset_zeroLocus (I : IdealSheafData X) (U : X.affineOpens) : + I.support ⊆ X.zeroLocus (U := U.1) (I.ideal U) := Set.iInter_subset _ _ + +lemma zeroLocus_inter_subset_support (I : IdealSheafData X) (U : X.affineOpens) : + X.zeroLocus (U := U.1) (I.ideal U) ∩ U ⊆ I.support := by + refine Set.subset_iInter fun V ↦ ?_ + apply (X.codisjoint_zeroLocus (U := V) (I.ideal V)).symm.left_le_of_le_inf_right + rintro x ⟨⟨hx, hxU⟩, hxV⟩ + simp only [Scheme.mem_zeroLocus_iff, SetLike.mem_coe] at hx ⊢ + intro s hfU hxs + obtain ⟨f, g, hfg, hxf⟩ := exists_basicOpen_le_affine_inter U.2 V.2 x ⟨hxU, hxV⟩ + have inst := U.2.isLocalization_basicOpen f + have := (I.map_ideal (U := X.affineBasicOpen f) (hfg.trans_le (X.basicOpen_le g))).le + (Ideal.mem_map_of_mem _ hfU) + rw [← I.map_ideal_basicOpen] at this + obtain ⟨⟨s', ⟨_, n, rfl⟩⟩, hs'⟩ := + (IsLocalization.mem_map_algebraMap_iff (.powers f) Γ(X, X.basicOpen f)).mp this + apply_fun (x ∈ X.basicOpen ·) at hs' + refine hx s' s'.2 ?_ + cases n <;> + simpa [RingHom.algebraMap_toAlgebra, ← hfg, hxf, hxs, Scheme.basicOpen_pow] using hs' + +lemma mem_support_iff_of_mem {I : IdealSheafData X} {x} {U : X.affineOpens} (hxU : x ∈ U.1) : + x ∈ I.support ↔ x ∈ X.zeroLocus (U := U.1) (I.ideal U) := + ⟨fun h ↦ Set.iInter_subset _ U h, fun h ↦ I.zeroLocus_inter_subset_support U ⟨h, hxU⟩⟩ + +lemma support_inter (I : IdealSheafData X) (U : X.affineOpens) : + I.support ∩ U = X.zeroLocus (U := U.1) (I.ideal U) ∩ U := by + ext x + by_cases hxU : x ∈ U.1 + · simp [hxU, mem_support_iff_of_mem hxU] + · simp [hxU] + +lemma isClosed_support (I : IdealSheafData X) : IsClosed I.support := by + rw [isClosed_iff_coe_preimage_of_iSup_eq_top (iSup_affineOpens_eq_top X)] + intro U + refine ⟨(X.zeroLocus (U := U.1) (I.ideal U))ᶜ, (X.zeroLocus_isClosed _).isOpen_compl, ?_⟩ + simp only [Set.preimage_compl, compl_inj_iff] + apply Subtype.val_injective.image_injective + simp [Set.image_preimage_eq_inter_range, I.support_inter] + +@[simp] +lemma support_top : support (X := X) ⊤ = ∅ := by + ext x + obtain ⟨_, ⟨U, hU, rfl⟩, hxU, -⟩ := + (isBasis_affine_open X).exists_subset_of_mem_open (Set.mem_univ x) isOpen_univ + simpa [support] using ⟨U, hU, hxU⟩ + +@[simp] +lemma support_bot : support (X := X) ⊥ = Set.univ := by ext; simp [support] + +lemma support_antitone : Antitone (support (X := X)) := + fun _ _ h ↦ Set.iInter_mono fun U ↦ X.zeroLocus_mono (h U) + +lemma support_ofIdealTop (I : Ideal Γ(X, ⊤)) : (ofIdealTop I).support = X.zeroLocus (U := ⊤) I := by + suffices ∀ U : X.affineOpens, (ofIdealTop I).support ∩ U = X.zeroLocus (U := ⊤) I ∩ U by + ext x + obtain ⟨_, ⟨U, hU, rfl⟩, hxU, -⟩ := + (isBasis_affine_open X).exists_subset_of_mem_open (Set.mem_univ x) isOpen_univ + simpa [hxU] using congr(x ∈ $(this ⟨U, hU⟩)) + intro U + rw [support_inter, ofIdealTop_ideal, Ideal.map, zeroLocus_span, zeroLocus_map, + Set.union_inter_distrib_right, Set.compl_inter_self, Set.union_empty] + +@[simp] +lemma support_eq_empty_iff : support I = ∅ ↔ I = ⊤ := by + refine ⟨fun H ↦ top_le_iff.mp fun U ↦ ?_, by simp +contextual⟩ + have := (U.2.fromSpec_image_zeroLocus _).trans_subset + ((zeroLocus_inter_subset_support I U).trans_eq H) + simp only [Set.subset_empty_iff, Set.image_eq_empty] at this + simp [PrimeSpectrum.zeroLocus_empty_iff_eq_top.mp this] + +end support + +end AlgebraicGeometry.Scheme.IdealSheafData diff --git a/Mathlib/RingTheory/Localization/Ideal.lean b/Mathlib/RingTheory/Localization/Ideal.lean index 17ab0c536c1ad..6242a91b11488 100644 --- a/Mathlib/RingTheory/Localization/Ideal.lean +++ b/Mathlib/RingTheory/Localization/Ideal.lean @@ -182,6 +182,17 @@ def orderIsoOfPrime : map_comap M S I'.val ▸ Ideal.map_mono h) exact fun h x hx => h hx +include M in +lemma map_radical (I : Ideal R) : + I.radical.map (algebraMap R S) = (I.map (algebraMap R S)).radical := by + refine (I.map_radical_le (algebraMap R S)).antisymm ?_ + rintro x ⟨n, hn⟩ + obtain ⟨x, s, rfl⟩ := IsLocalization.mk'_surjective M x + simp only [← IsLocalization.mk'_pow, IsLocalization.mk'_mem_map_algebraMap_iff M, + Submonoid.mem_powers_iff, exists_exists_eq_and] at hn ⊢ + obtain ⟨s, hs, h⟩ := hn + refine ⟨s, hs, n + 1, by convert I.mul_mem_left (s ^ n * x) h; ring⟩ + end CommSemiring section CommRing From cfa0cb250ae159392afa692b4580c6b4faddd964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 4 Feb 2025 06:23:56 +0000 Subject: [PATCH 054/103] feat: the prime spectrum is quasi-separated (#21362) Also golf the `QuasiSeparatedSpace` instance for affine schemes (the common proof was abstracted out in #21325) and prove that open sets are retrocompact iff they are compact (this should eventually become a lemma about spectral spaces). --- .../Morphisms/QuasiSeparated.lean | 17 ++--------------- Mathlib/RingTheory/Spectrum/Prime/Topology.lean | 12 ++++++++++++ Mathlib/Topology/QuasiSeparated.lean | 4 ++++ 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean b/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean index cc98f5e3fe6c5..8d74ee3cec8c0 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean @@ -150,21 +150,8 @@ theorem quasiSeparatedSpace_of_quasiSeparated {X Y : Scheme} (f : X ⟶ Y) rw [← terminalIsTerminal.hom_ext (f ≫ terminal.from Y) (terminal.from X)] infer_instance -instance quasiSeparatedSpace_of_isAffine (X : Scheme) [IsAffine X] : - QuasiSeparatedSpace X := by - constructor - intro U V hU hU' hV hV' - obtain ⟨s, hs, e⟩ := (isCompactOpen_iff_eq_basicOpen_union _).mp ⟨hU', hU⟩ - obtain ⟨s', hs', e'⟩ := (isCompactOpen_iff_eq_basicOpen_union _).mp ⟨hV', hV⟩ - rw [e, e', Set.iUnion₂_inter] - simp_rw [Set.inter_iUnion₂] - apply hs.isCompact_biUnion - intro i _ - apply hs'.isCompact_biUnion - intro i' _ - change IsCompact (X.basicOpen i ⊓ X.basicOpen i').1 - rw [← Scheme.basicOpen_mul] - exact ((isAffineOpen_top _).basicOpen _).isCompact +instance quasiSeparatedSpace_of_isAffine (X : Scheme) [IsAffine X] : QuasiSeparatedSpace X := + (quasiSeparatedSpace_congr X.isoSpec.hom.homeomorph).2 PrimeSpectrum.instQuasiSeparatedSpace theorem IsAffineOpen.isQuasiSeparated {X : Scheme} {U : X.Opens} (hU : IsAffineOpen U) : IsQuasiSeparated (U : Set X) := by diff --git a/Mathlib/RingTheory/Spectrum/Prime/Topology.lean b/Mathlib/RingTheory/Spectrum/Prime/Topology.lean index c846ca364238f..352cd2a76b48a 100644 --- a/Mathlib/RingTheory/Spectrum/Prime/Topology.lean +++ b/Mathlib/RingTheory/Spectrum/Prime/Topology.lean @@ -14,7 +14,9 @@ import Mathlib.RingTheory.Localization.Away.Basic import Mathlib.RingTheory.Localization.Ideal import Mathlib.RingTheory.Spectrum.Maximal.Localization import Mathlib.Tactic.StacksAttribute +import Mathlib.Topology.Constructible import Mathlib.Topology.KrullDimension +import Mathlib.Topology.QuasiSeparated import Mathlib.Topology.Sober /-! @@ -589,6 +591,16 @@ lemma range_comap_algebraMap_localization_compl_eq_range_comap_quotientMk rw [range_comap_of_surjective _ _ surj, localization_away_comap_range _ (C c)] simp [Polynomial.ker_mapRingHom, Ideal.map_span] +instance : QuasiSeparatedSpace (PrimeSpectrum R) := + .of_isTopologicalBasis isTopologicalBasis_basic_opens fun i j ↦ by + simpa [← TopologicalSpace.Opens.coe_inf, ← basicOpen_mul, -basicOpen_eq_zeroLocus_compl] + using isCompact_basicOpen _ + +-- TODO: Abstract out this lemma to spectral spaces +lemma isRetrocompact_iff {U : Set (PrimeSpectrum R)} (hU : IsOpen U) : + IsRetrocompact U ↔ IsCompact U := + isTopologicalBasis_basic_opens.isRetrocompact_iff_isCompact isCompact_basicOpen hU + end BasicOpen section DiscreteTopology diff --git a/Mathlib/Topology/QuasiSeparated.lean b/Mathlib/Topology/QuasiSeparated.lean index 154b7fe4c1901..13fa80c3a6c6b 100644 --- a/Mathlib/Topology/QuasiSeparated.lean +++ b/Mathlib/Topology/QuasiSeparated.lean @@ -139,3 +139,7 @@ lemma IsCompact.inter_of_isOpen (hUcomp : IsCompact U) (hVcomp : IsCompact V) (h QuasiSeparatedSpace.inter_isCompact _ _ hUopen hUcomp hVopen hVcomp end QuasiSeparatedSpace + +lemma quasiSeparatedSpace_congr (e : α ≃ₜ β) : QuasiSeparatedSpace α ↔ QuasiSeparatedSpace β where + mp _ := .of_isOpenEmbedding e.symm.isOpenEmbedding + mpr _ := .of_isOpenEmbedding e.isOpenEmbedding From 02696de6520e08c2b842963910eee19622a03f76 Mon Sep 17 00:00:00 2001 From: Anne Baanen Date: Tue, 4 Feb 2025 06:23:57 +0000 Subject: [PATCH 055/103] feat(Tactic/Linter): options to in/exclude definitions and private decls (#21374) Zulip thread: https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/late.20imports Two new options: * `linter.upstreamableDecl.defs` (default: `false`): warn if a definition can be upstreamed * `linter.upstreamableDecl.private` (default: `false`): warn if a private declaration can be upstreamed --- Mathlib/Tactic/Linter/UpstreamableDecl.lean | 34 ++++++++++++++- MathlibTest/MinImports.lean | 46 +++++++++++++++++++-- 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/Mathlib/Tactic/Linter/UpstreamableDecl.lean b/Mathlib/Tactic/Linter/UpstreamableDecl.lean index 59beda016bc47..6d0352a0692f7 100644 --- a/Mathlib/Tactic/Linter/UpstreamableDecl.lean +++ b/Mathlib/Tactic/Linter/UpstreamableDecl.lean @@ -56,15 +56,34 @@ namespace Mathlib.Linter The `upstreamableDecl` linter detects declarations that could be moved to a file higher up in the import hierarchy. If this is the case, it emits a warning. +By default, this linter will not fire on definitions, nor private declarations: +see options `linter.upstreamableDecl.defs` and `linter.upstreamableDecl.private`. + This is intended to assist with splitting files. +-/ +register_option linter.upstreamableDecl : Bool := { + defValue := false + descr := "enable the upstreamableDecl linter" +} + +/-- +If set to `true`, the `upstreamableDecl` linter will add warnings on definitions. The linter does not place a warning on any declaration depending on a definition in the current file (while it does place a warning on the definition itself), since we often create a new file for a definition on purpose. -/ -register_option linter.upstreamableDecl : Bool := { +register_option linter.upstreamableDecl.defs : Bool := { defValue := false - descr := "enable the upstreamableDecl linter" + descr := "upstreamableDecl warns on definitions" +} + +/-- +If set to `true`, the `upstreamableDecl` linter will add warnings on private declarations. +-/ +register_option linter.upstreamableDecl.private : Bool := { + defValue := false + descr := "upstreamableDecl warns on private declarations" } namespace DoubleImports @@ -75,10 +94,21 @@ def upstreamableDeclLinter : Linter where run := withSetOptionIn fun stx ↦ do return if (← get).messages.hasErrors then return + let skipDef := !Linter.getLinterValue linter.upstreamableDecl.defs (← getOptions) + let skipPrivate := !Linter.getLinterValue linter.upstreamableDecl.private (← getOptions) if stx == (← `(command| set_option $(mkIdent `linter.upstreamableDecl) true)) then return let env ← getEnv let id ← getId stx if id != .missing then + -- Skip defs and private decls by default. + let names ← resolveGlobalConst id + if (skipDef && names.any fun name => + if let some constInfo := env.find? name + then !(constInfo.isTheorem || constInfo.isCtor) + else true) || + (skipPrivate && names.any isPrivateName) then + return + let minImports := getIrredundantImports env (← getAllImports stx id) match minImports with | ⟨(RBNode.node _ .leaf upstream _ .leaf), _⟩ => do diff --git a/MathlibTest/MinImports.lean b/MathlibTest/MinImports.lean index ad749a05da97f..86837c0d3123e 100644 --- a/MathlibTest/MinImports.lean +++ b/MathlibTest/MinImports.lean @@ -152,6 +152,10 @@ note: this linter can be disabled with `set_option linter.upstreamableDecl false #guard_msgs in theorem propose_to_move_this_theorem : (0 : ℕ) = 0 := rfl +-- By default, the linter does not warn on definitions. +def dont_propose_to_move_this_def : ℕ := 0 + +set_option linter.upstreamableDecl.defs true in /-- warning: Consider moving this declaration to the module Mathlib.Data.Nat.Notation. note: this linter can be disabled with `set_option linter.upstreamableDecl false` @@ -165,12 +169,48 @@ theorem theorem_with_local_def : propose_to_move_this_def = 0 := rfl -- This definition depends on definitions in two different files, so should not be moved. #guard_msgs in -def def_with_multiple_dependencies := +theorem theorem_with_multiple_dependencies : True := let _ := Mathlib.Meta.FunProp.funPropAttr let _ := Mathlib.Meta.NormNum.evalNatDvd - false + trivial + +-- Private declarations shouldn't get a warning by default. +private theorem private_theorem : (0 : ℕ) = 0 := rfl + +-- But we can enable the option. +set_option linter.upstreamableDecl.private true in +/-- +warning: Consider moving this declaration to the module Mathlib.Data.Nat.Notation. +note: this linter can be disabled with `set_option linter.upstreamableDecl false` +-/ +#guard_msgs in +private theorem propose_to_move_this_private_theorem : (0 : ℕ) = 0 := rfl + +-- Private declarations shouldn't get a warning by default, even if definitions get a warning. +set_option linter.upstreamableDecl.defs true in +private def private_def : ℕ := 0 + +-- But if we enable both options, they should. +set_option linter.upstreamableDecl.defs true in +set_option linter.upstreamableDecl.private true in +/-- +warning: Consider moving this declaration to the module Mathlib.Data.Nat.Notation. +note: this linter can be disabled with `set_option linter.upstreamableDecl false` +-/ +#guard_msgs in +private def propose_to_move_this_private_def : ℕ := 0 + +/-! Structures and inductives should be treated just like definitions: +no warnings by default, unless we enable the option. -/ + +structure DontProposeToMoveThisStructure where + foo : ℕ + +inductive DontProposeToMoveThisInductive where +| foo : ℕ → DontProposeToMoveThisInductive +| bar : ℕ → DontProposeToMoveThisInductive → DontProposeToMoveThisInductive -/-! Structures and inductives should be treated just like definitions. -/ +set_option linter.upstreamableDecl.defs true /-- From 517102f6cc68000008731b6480dbb24fa7d43203 Mon Sep 17 00:00:00 2001 From: Bhavik Mehta Date: Tue, 4 Feb 2025 06:23:58 +0000 Subject: [PATCH 056/103] feat(RingTheory/PowerSeries): describe when power series map is zero (#21379) Add two simple lemmas to describe when the `map` of a (mv) power series is zero. --- Mathlib/RingTheory/MvPowerSeries/Basic.lean | 7 +++++++ Mathlib/RingTheory/PowerSeries/Basic.lean | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/Mathlib/RingTheory/MvPowerSeries/Basic.lean b/Mathlib/RingTheory/MvPowerSeries/Basic.lean index 442bce30a6a45..f346658a9210f 100644 --- a/Mathlib/RingTheory/MvPowerSeries/Basic.lean +++ b/Mathlib/RingTheory/MvPowerSeries/Basic.lean @@ -549,6 +549,13 @@ theorem map_X (s : σ) : map σ f (X s) = X s := by simp [MvPowerSeries.X] end Map +@[simp] +theorem map_eq_zero {S : Type*} [DivisionSemiring R] [Semiring S] [Nontrivial S] + (φ : MvPowerSeries σ R) (f : R →+* S) : φ.map σ f = 0 ↔ φ = 0 := by + simp only [MvPowerSeries.ext_iff] + congr! with n + simp + section Semiring variable [Semiring R] diff --git a/Mathlib/RingTheory/PowerSeries/Basic.lean b/Mathlib/RingTheory/PowerSeries/Basic.lean index 798c473721bd8..8531b7e90a4e7 100644 --- a/Mathlib/RingTheory/PowerSeries/Basic.lean +++ b/Mathlib/RingTheory/PowerSeries/Basic.lean @@ -465,6 +465,11 @@ theorem map_X : map f X = X := by end Map +@[simp] +theorem map_eq_zero {R S : Type*} [DivisionSemiring R] [Semiring S] [Nontrivial S] (φ : R⟦X⟧) + (f : R →+* S) : φ.map f = 0 ↔ φ = 0 := + MvPowerSeries.map_eq_zero _ _ + theorem X_pow_dvd_iff {n : ℕ} {φ : R⟦X⟧} : (X : R⟦X⟧) ^ n ∣ φ ↔ ∀ m, m < n → coeff R m φ = 0 := by convert@MvPowerSeries.X_pow_dvd_iff Unit R _ () n φ From e8a5fb3ec892aa1fcbc28cfa4f843bfe268ae89e Mon Sep 17 00:00:00 2001 From: Bhavik Mehta Date: Tue, 4 Feb 2025 06:23:59 +0000 Subject: [PATCH 057/103] chore(Algebra/PUnitInstances): generalise universes (#21381) Generalise these shortcut instances to arbitrary universes rather than restricting them to `PUnit.{1}`. As a consequence, the following 8 lemmas are also universe generalised. --- Mathlib/Algebra/PUnitInstances/Algebra.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mathlib/Algebra/PUnitInstances/Algebra.lean b/Mathlib/Algebra/PUnitInstances/Algebra.lean index 8a9c98a4aebdc..77dfa188192ec 100644 --- a/Mathlib/Algebra/PUnitInstances/Algebra.lean +++ b/Mathlib/Algebra/PUnitInstances/Algebra.lean @@ -29,10 +29,10 @@ instance commGroup : CommGroup PUnit where mul_comm := by intros; rfl -- shortcut instances -@[to_additive] instance : One PUnit where one := () -@[to_additive] instance : Mul PUnit where mul _ _ := () -@[to_additive] instance : Div PUnit where div _ _ := () -@[to_additive] instance : Inv PUnit where inv _ := () +@[to_additive] instance : One PUnit where one := unit +@[to_additive] instance : Mul PUnit where mul _ _ := unit +@[to_additive] instance : Div PUnit where div _ _ := unit +@[to_additive] instance : Inv PUnit where inv _ := unit -- dsimp loops when applying this lemma to its LHS, -- probably https://github.com/leanprover/lean4/pull/2867 From 7fb58b4058cb43344868bffb1d603315dbffef75 Mon Sep 17 00:00:00 2001 From: JovanGerb Date: Tue, 4 Feb 2025 06:24:00 +0000 Subject: [PATCH 058/103] chore: remove `@[simp]` from `CategoryTheory.Discrete.functor_map` (#21392) the simpNF complained about this in my other PR. indeed, the same simplification can be done with ``` simp only [Discrete.functor_obj_eq_as, Discrete.functor_map_id] ``` --- Mathlib/CategoryTheory/DiscreteCategory.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/CategoryTheory/DiscreteCategory.lean b/Mathlib/CategoryTheory/DiscreteCategory.lean index d30dc736344e6..5fbcff43bd047 100644 --- a/Mathlib/CategoryTheory/DiscreteCategory.lean +++ b/Mathlib/CategoryTheory/DiscreteCategory.lean @@ -167,9 +167,9 @@ theorem functor_obj {I : Type u₁} (F : I → C) (i : I) : (Discrete.functor F).obj (Discrete.mk i) = F i := rfl -@[simp] theorem functor_map {I : Type u₁} (F : I → C) {i : Discrete I} (f : i ⟶ i) : (Discrete.functor F).map f = 𝟙 (F i.as) := by aesop_cat + @[simp] theorem functor_obj_eq_as {I : Type u₁} (F : I → C) (X : Discrete I) : (Discrete.functor F).obj X = F X.as := From a42d40c0557e574eef833c60cb0a35edef417803 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 4 Feb 2025 06:24:02 +0000 Subject: [PATCH 059/103] fix: bug in daily.yml (#21401) The daily.yml workflow, which is responsible for running `lean4checker` on nightly and master, was broken. --- .github/workflows/daily.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml index f1f7dbe840941..8a85d069eb14e 100644 --- a/.github/workflows/daily.yml +++ b/.github/workflows/daily.yml @@ -37,6 +37,10 @@ jobs: ./elan-init -y --default-toolchain none echo "$HOME/.elan/bin" >> "${GITHUB_PATH}" + # Checkout repository, so that we can fetch tags to decide which branch we want. + - name: Checkout branch or tag + uses: actions/checkout@v4 + - name: Fetch latest tags (if nightly) if: matrix.branch_type == 'nightly' run: | @@ -52,6 +56,7 @@ jobs: echo "BRANCH_REF=${{ env.LATEST_TAG }}" >> "$GITHUB_ENV" fi + # Checkout the branch or tag we want to test. - name: Checkout branch or tag uses: actions/checkout@v4 with: From e13a712b1a981526ce626085abf1dad8832a4dec Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Tue, 4 Feb 2025 07:19:26 +0000 Subject: [PATCH 060/103] chore: rename AnalyticAt.order_neq_top_iff (#21388) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per the naming convention, the symbol `≠` should be transcribed as "ne", not "neq". --- Mathlib/Analysis/Analytic/IsolatedZeros.lean | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Mathlib/Analysis/Analytic/IsolatedZeros.lean b/Mathlib/Analysis/Analytic/IsolatedZeros.lean index 477f764d36f0e..d976c6b046c7f 100644 --- a/Mathlib/Analysis/Analytic/IsolatedZeros.lean +++ b/Mathlib/Analysis/Analytic/IsolatedZeros.lean @@ -218,15 +218,18 @@ lemma order_eq_nat_iff (hf : AnalyticAt 𝕜 f z₀) (n : ℕ) : hf.order = ↑n refine ⟨fun hn ↦ (WithTop.coe_inj.mp hn : h.choose = n) ▸ h.choose_spec, fun h' ↦ ?_⟩ rw [unique_eventuallyEq_pow_smul_nonzero h.choose_spec h'] -/- An analytic function `f` has finite order at a point `z₀` iff it locally looks +/-- An analytic function `f` has finite order at a point `z₀` iff it locally looks like `(z - z₀) ^ order • g`, where `g` is analytic and does not vanish at `z₀`. -/ -lemma order_neq_top_iff (hf : AnalyticAt 𝕜 f z₀) : +lemma order_ne_top_iff (hf : AnalyticAt 𝕜 f z₀) : hf.order ≠ ⊤ ↔ ∃ (g : 𝕜 → E), AnalyticAt 𝕜 g z₀ ∧ g z₀ ≠ 0 ∧ f =ᶠ[𝓝 z₀] fun z ↦ (z - z₀) ^ (hf.order.toNat) • g z := by simp only [← ENat.coe_toNat_eq_self, Eq.comm, EventuallyEq, ← hf.order_eq_nat_iff] -/- An analytic function has order zero at a point iff it does not vanish there. -/ +@[deprecated (since := "2025-02-03")] +alias order_neq_top_iff := order_ne_top_iff + +/-- An analytic function has order zero at a point iff it does not vanish there. -/ lemma order_eq_zero_iff (hf : AnalyticAt 𝕜 f z₀) : hf.order = 0 ↔ f z₀ ≠ 0 := by rw [← ENat.coe_zero, order_eq_nat_iff hf 0] @@ -235,7 +238,7 @@ lemma order_eq_zero_iff (hf : AnalyticAt 𝕜 f z₀) : simpa [hg.self_of_nhds] · exact fun hz ↦ ⟨f, hf, hz, by simp⟩ -/- An analytic function vanishes at a point if its order is nonzero when converted to ℕ. -/ +/-- An analytic function vanishes at a point if its order is nonzero when converted to ℕ. -/ lemma apply_eq_zero_of_order_toNat_ne_zero (hf : AnalyticAt 𝕜 f z₀) : hf.order.toNat ≠ 0 → f z₀ = 0 := by simp [hf.order_eq_zero_iff] @@ -258,8 +261,8 @@ theorem order_mul {f g : 𝕜 → 𝕜} (hf : AnalyticAt 𝕜 f z₀) (hg : Anal by_cases h₂g : hg.order = ⊤ · simp [mul_comm f g, hg.order_mul_of_order_eq_top hf h₂g, h₂g] -- Non-trivial case: both functions do not vanish around z₀ - obtain ⟨g₁, h₁g₁, h₂g₁, h₃g₁⟩ := hf.order_neq_top_iff.1 h₂f - obtain ⟨g₂, h₁g₂, h₂g₂, h₃g₂⟩ := hg.order_neq_top_iff.1 h₂g + obtain ⟨g₁, h₁g₁, h₂g₁, h₃g₁⟩ := hf.order_ne_top_iff.1 h₂f + obtain ⟨g₂, h₁g₂, h₂g₂, h₃g₂⟩ := hg.order_ne_top_iff.1 h₂g rw [← ENat.coe_toNat h₂f, ← ENat.coe_toNat h₂g, ← ENat.coe_add, (hf.mul hg).order_eq_nat_iff] use g₁ * g₂, by exact h₁g₁.mul h₁g₂ constructor From b08254cec963f6d2b039f8eb6f5768f363b811f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Renison?= <85908989+IvanRenison@users.noreply.github.com> Date: Tue, 4 Feb 2025 08:24:45 +0000 Subject: [PATCH 061/103] chore(Combinatorics/SimpleGraph): Fix `hadj` naming (#21389) --- .../Combinatorics/SimpleGraph/Circulant.lean | 8 +++--- .../SimpleGraph/ConcreteColorings.lean | 26 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Circulant.lean b/Mathlib/Combinatorics/SimpleGraph/Circulant.lean index d4c83ed115ba7..338c80d929778 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Circulant.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Circulant.lean @@ -137,15 +137,15 @@ private def cycleGraph_EulerianCircuit_cons (n : ℕ) : ∀ m : Fin (n + 3), (cycleGraph (n + 3)).Walk m 0 | ⟨0, h⟩ => Walk.nil | ⟨m + 1, h⟩ => - have hAdj : (cycleGraph (n + 3)).Adj ⟨m + 1, h⟩ ⟨m, Nat.lt_of_succ_lt h⟩ := by + have hadj : (cycleGraph (n + 3)).Adj ⟨m + 1, h⟩ ⟨m, Nat.lt_of_succ_lt h⟩ := by simp [cycleGraph_adj, Fin.ext_iff, Fin.sub_val_of_le] - Walk.cons hAdj (cycleGraph_EulerianCircuit_cons n ⟨m, Nat.lt_of_succ_lt h⟩) + Walk.cons hadj (cycleGraph_EulerianCircuit_cons n ⟨m, Nat.lt_of_succ_lt h⟩) /-- Eulerian trail of `cycleGraph (n + 3)` -/ def cycleGraph_EulerianCircuit (n : ℕ) : (cycleGraph (n + 3)).Walk 0 0 := - have hAdj : (cycleGraph (n + 3)).Adj 0 (Fin.last (n + 2)) := by + have hadj : (cycleGraph (n + 3)).Adj 0 (Fin.last (n + 2)) := by simp [cycleGraph_adj] - Walk.cons hAdj (cycleGraph_EulerianCircuit_cons n (Fin.last (n + 2))) + Walk.cons hadj (cycleGraph_EulerianCircuit_cons n (Fin.last (n + 2))) private theorem cycleGraph_EulerianCircuit_cons_length (n : ℕ) : ∀ m : Fin (n + 3), (cycleGraph_EulerianCircuit_cons n m).length = m.val diff --git a/Mathlib/Combinatorics/SimpleGraph/ConcreteColorings.lean b/Mathlib/Combinatorics/SimpleGraph/ConcreteColorings.lean index b6c01c361ac73..750a74bc99fd8 100644 --- a/Mathlib/Combinatorics/SimpleGraph/ConcreteColorings.lean +++ b/Mathlib/Combinatorics/SimpleGraph/ConcreteColorings.lean @@ -23,13 +23,13 @@ assert_not_exists Field namespace SimpleGraph -theorem two_le_chromaticNumber_of_adj {α} {G : SimpleGraph α} {u v : α} (hAdj : G.Adj u v) : +theorem two_le_chromaticNumber_of_adj {α} {G : SimpleGraph α} {u v : α} (hadj : G.Adj u v) : 2 ≤ G.chromaticNumber := by refine le_of_not_lt ?_ intro h have hc : G.Colorable 1 := chromaticNumber_le_iff_colorable.mp (Order.le_of_lt_add_one h) let c : G.Coloring (Fin 1) := hc.some - exact c.valid hAdj (Subsingleton.elim (c u) (c v)) + exact c.valid hadj (Subsingleton.elim (c u) (c v)) /-- Bicoloring of a path graph -/ def pathGraph.bicoloring (n : ℕ) : @@ -55,8 +55,8 @@ theorem chromaticNumber_pathGraph (n : ℕ) (h : 2 ≤ n) : have hc := (pathGraph.bicoloring n).colorable apply le_antisymm · exact hc.chromaticNumber_le - · have hAdj : (pathGraph n).Adj ⟨0, Nat.zero_lt_of_lt h⟩ ⟨1, h⟩ := by simp [pathGraph_adj] - exact two_le_chromaticNumber_of_adj hAdj + · have hadj : (pathGraph n).Adj ⟨0, Nat.zero_lt_of_lt h⟩ ⟨1, h⟩ := by simp [pathGraph_adj] + exact two_le_chromaticNumber_of_adj hadj theorem Coloring.even_length_iff_congr {α} {G : SimpleGraph α} (c : G.Coloring Bool) {u v : α} (p : G.Walk u v) : @@ -88,14 +88,14 @@ theorem Walk.three_le_chromaticNumber_of_odd_loop {α} {G : SimpleGraph α} {u : /-- Bicoloring of a cycle graph of even size -/ def cycleGraph.bicoloring_of_even (n : ℕ) (h : Even n) : Coloring (cycleGraph n) Bool := Coloring.mk (fun u ↦ u.val % 2 = 0) <| by - intro u v hAdj + intro u v hadj match n with | 0 => exact u.elim0 | 1 => simp at h | n + 2 => simp only [ne_eq, decide_eq_decide] - simp only [cycleGraph_adj] at hAdj - cases hAdj with + simp only [cycleGraph_adj] at hadj + cases hadj with | inl huv | inr huv => rw [← add_eq_of_eq_sub' huv.symm, ← Fin.even_iff_mod_of_even h, ← Fin.even_iff_mod_of_even h, Fin.even_add_one_iff_odd] @@ -107,22 +107,22 @@ theorem chromaticNumber_cycleGraph_of_even (n : ℕ) (h : 2 ≤ n) (hEven : Even have hc := (cycleGraph.bicoloring_of_even n hEven).colorable apply le_antisymm · apply hc.chromaticNumber_le - · have hAdj : (cycleGraph n).Adj ⟨0, Nat.zero_lt_of_lt h⟩ ⟨1, h⟩ := by + · have hadj : (cycleGraph n).Adj ⟨0, Nat.zero_lt_of_lt h⟩ ⟨1, h⟩ := by simp [cycleGraph_adj', Fin.sub_val_of_le] - exact two_le_chromaticNumber_of_adj hAdj + exact two_le_chromaticNumber_of_adj hadj /-- Tricoloring of a cycle graph -/ def cycleGraph.tricoloring (n : ℕ) (h : 2 ≤ n) : Coloring (cycleGraph n) (Fin 3) := Coloring.mk (fun u ↦ if u.val = n - 1 then 2 else ⟨u.val % 2, by fin_omega⟩) <| by - intro u v hAdj + intro u v hadj match n with | 0 => exact u.elim0 | 1 => simp at h | n + 2 => simp only - simp [cycleGraph_adj] at hAdj + simp [cycleGraph_adj] at hadj split_ifs with hu hv - · simp [Fin.eq_mk_iff_val_eq.mpr hu, Fin.eq_mk_iff_val_eq.mpr hv] at hAdj + · simp [Fin.eq_mk_iff_val_eq.mpr hu, Fin.eq_mk_iff_val_eq.mpr hv] at hadj · refine (Fin.ne_of_lt (Fin.mk_lt_of_lt_val (?_))).symm exact v.val.mod_lt Nat.zero_lt_two · refine (Fin.ne_of_lt (Fin.mk_lt_of_lt_val ?_)) @@ -130,7 +130,7 @@ def cycleGraph.tricoloring (n : ℕ) (h : 2 ≤ n) : Coloring (cycleGraph n) · simp [Fin.ext_iff] have hu' : u.val + (1 : Fin (n + 2)) < n + 2 := by fin_omega have hv' : v.val + (1 : Fin (n + 2)) < n + 2 := by fin_omega - cases hAdj with + cases hadj with | inl huv | inr huv => rw [← add_eq_of_eq_sub' huv.symm] simp only [Fin.val_add_eq_of_add_lt hv', Fin.val_add_eq_of_add_lt hu', Fin.val_one] From 644048a602f71c0157d72660af5fc00c09d7112a Mon Sep 17 00:00:00 2001 From: Peter Nelson <71660771+apnelson1@users.noreply.github.com> Date: Tue, 4 Feb 2025 08:33:47 +0000 Subject: [PATCH 062/103] feat(Data/LinearIndependent): iff versions of smul action on independent sets (#21383) We add iff versions of `LinearIndependent.group_smul` and `LinearIndependent.units_smul`, which can be simp. --- Mathlib/LinearAlgebra/LinearIndependent.lean | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Mathlib/LinearAlgebra/LinearIndependent.lean b/Mathlib/LinearAlgebra/LinearIndependent.lean index cf92c3c6fe93a..2406baba71b70 100644 --- a/Mathlib/LinearAlgebra/LinearIndependent.lean +++ b/Mathlib/LinearAlgebra/LinearIndependent.lean @@ -398,6 +398,14 @@ theorem LinearIndependent.group_smul {G : Type*} [hG : Group G] [DistribMulActio · simp_rw [hgs i hi] · simpa only [smul_assoc, smul_comm] using hsum +@[simp] +theorem LinearIndependent.group_smul_iff {G : Type*} [hG : Group G] [DistribMulAction G R] + [DistribMulAction G M] [IsScalarTower G R M] [SMulCommClass G R M] (v : ι → M) (w : ι → G) : + LinearIndependent R (w • v) ↔ LinearIndependent R v := by + refine ⟨fun h ↦ ?_, fun h ↦ h.group_smul w⟩ + convert h.group_smul (fun i ↦ (w i)⁻¹) + simp [funext_iff] + -- This lemma cannot be proved with `LinearIndependent.group_smul` since the action of -- `Rˣ` on `R` is not commutative. theorem LinearIndependent.units_smul {v : ι → M} (hv : LinearIndependent R v) (w : ι → Rˣ) : @@ -409,6 +417,13 @@ theorem LinearIndependent.units_smul {v : ι → M} (hv : LinearIndependent R v) · simp_rw [hgs i hi] · simpa only [smul_eq_mul, mul_smul, Pi.smul_apply'] using hsum +@[simp] +theorem LinearIndependent.units_smul_iff (v : ι → M) (w : ι → Rˣ) : + LinearIndependent R (w • v) ↔ LinearIndependent R v := by + refine ⟨fun h ↦ ?_, fun h ↦ h.units_smul w⟩ + convert h.units_smul (fun i ↦ (w i)⁻¹) + simp [funext_iff] + theorem linearIndependent_image {ι} {s : Set ι} {f : ι → M} (hf : Set.InjOn f s) : (LinearIndependent R fun x : s ↦ f x) ↔ LinearIndependent R fun x : f '' s => (x : M) := linearIndependent_equiv' (Equiv.Set.imageOfInjOn _ _ hf) rfl From 2dd5bb2d33e82377b2cc4e347e2317a4ec0603bc Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Tue, 4 Feb 2025 09:16:25 +0000 Subject: [PATCH 063/103] feat(AlgebraicGeometry): the diagonal of an unramified morphism is an open immersion (#21386) --- .../AlgebraicGeometry/Morphisms/Basic.lean | 20 +++++++++ .../Morphisms/FormallyUnramified.lean | 43 ++++++++++++++++++- Mathlib/AlgebraicGeometry/Restrict.lean | 20 +++++++++ 3 files changed, 81 insertions(+), 2 deletions(-) diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean b/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean index 24705327fb315..0079bbcb1d206 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean @@ -174,6 +174,26 @@ theorem iff_of_openCover (𝒰 : Y.OpenCover) : P f ↔ ∀ i, P (𝒰.pullbackHom f i) := ⟨fun H _ ↦ of_isPullback (.of_hasPullback _ _) H, of_openCover _⟩ +lemma of_range_subset_iSup [P.RespectsRight @IsOpenImmersion] {ι : Type*} (U : ι → Y.Opens) + (H : Set.range f.base ⊆ (⨆ i, U i : Y.Opens)) (hf : ∀ i, P (f ∣_ U i)) : P f := by + let g : X ⟶ (⨆ i, U i : Y.Opens) := IsOpenImmersion.lift (Scheme.Opens.ι _) f (by simpa using H) + rw [← IsOpenImmersion.lift_fac (⨆ i, U i).ι f (by simpa using H)] + apply MorphismProperty.RespectsRight.postcomp (Q := @IsOpenImmersion) _ inferInstance + rw [IsLocalAtTarget.iff_of_iSup_eq_top (P := P) (U := fun i : ι ↦ (⨆ i, U i).ι ⁻¹ᵁ U i)] + · intro i + have heq : g ⁻¹ᵁ (⨆ i, U i).ι ⁻¹ᵁ U i = f ⁻¹ᵁ U i := by + show (g ≫ (⨆ i, U i).ι) ⁻¹ᵁ U i = _ + simp [g] + let e : Arrow.mk (g ∣_ (⨆ i, U i).ι ⁻¹ᵁ U i) ≅ Arrow.mk (f ∣_ U i) := + Arrow.isoMk (X.isoOfEq heq) (Scheme.Opens.isoOfLE (le_iSup U i)) <| by + simp [← CategoryTheory.cancel_mono (U i).ι, g] + rw [P.arrow_mk_iso_iff e] + exact hf i + apply (⨆ i, U i).ι.image_injective + dsimp + rw [Scheme.Hom.image_iSup, Scheme.Hom.image_top_eq_opensRange, Scheme.Opens.opensRange_ι] + simp [Scheme.Hom.image_preimage_eq_opensRange_inter, le_iSup U] + end IsLocalAtTarget /-- diff --git a/Mathlib/AlgebraicGeometry/Morphisms/FormallyUnramified.lean b/Mathlib/AlgebraicGeometry/Morphisms/FormallyUnramified.lean index 4182443309f6f..282f08c60d7c6 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/FormallyUnramified.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/FormallyUnramified.lean @@ -3,8 +3,8 @@ Copyright (c) 2025 Andrew Yang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ -import Mathlib.AlgebraicGeometry.Morphisms.RingHomProperties -import Mathlib.AlgebraicGeometry.Morphisms.OpenImmersion +import Mathlib.AlgebraicGeometry.Morphisms.Separated +import Mathlib.RingTheory.Ideal.IdempotentFG import Mathlib.RingTheory.RingHom.Unramified /-! @@ -24,6 +24,18 @@ open CategoryTheory CategoryTheory.Limits Opposite TopologicalSpace universe v u +open AlgebraicGeometry + +/-- If `S` is a formally unramified `R`-algebra, essentially of finite type, the diagonal is an +open immersion. -/ +instance Algebra.FormallyUnramified.isOpenImmersion_SpecMap_lmul {R S : Type u} [CommRing R] + [CommRing S] [Algebra R S] [Algebra.FormallyUnramified R S] [Algebra.EssFiniteType R S] : + IsOpenImmersion (Spec.map (CommRingCat.ofHom (TensorProduct.lmul' R (S := S)).toRingHom)) := by + rw [isOpenImmersion_SpecMap_iff_of_surjective _ (fun x ↦ ⟨1 ⊗ₜ x, by simp⟩)] + apply (Ideal.isIdempotentElem_iff_of_fg _ (KaehlerDifferential.ideal_fg R S)).mp + apply (Ideal.cotangent_subsingleton_iff _).mp + exact inferInstanceAs <| Subsingleton (Ω[S⁄R]) + namespace AlgebraicGeometry variable {X Y : Scheme.{u}} (f : X ⟶ Y) @@ -94,6 +106,33 @@ instance : MorphismProperty.IsMultiplicative @FormallyUnramified where instance : MorphismProperty.IsStableUnderBaseChange @FormallyUnramified := HasRingHomProperty.isStableUnderBaseChange RingHom.FormallyUnramified.isStableUnderBaseChange +open MorphismProperty in +/-- The diagonal of a formally unramified morphism of finite type is an open immersion. -/ +lemma AlgebraicGeometry.FormallyUnramified.isOpenImmersion_diagonal {X Y : Scheme.{u}} (f : X ⟶ Y) + [FormallyUnramified f] [LocallyOfFiniteType f] : IsOpenImmersion (pullback.diagonal f) := by + wlog hX : (∃ S, X = Spec S) ∧ ∃ R, Y = Spec R + · let 𝒰Y := Y.affineCover + let 𝒰X (j : (Y.affineCover.pullbackCover f).J) : + ((Y.affineCover.pullbackCover f).obj j).OpenCover := Scheme.affineCover _ + apply IsLocalAtTarget.of_range_subset_iSup _ + (Scheme.Pullback.range_diagonal_subset_diagonalCoverDiagonalRange f 𝒰Y 𝒰X) + intro ⟨i, j⟩ + rw [arrow_mk_iso_iff (P := @IsOpenImmersion) + (Scheme.Pullback.diagonalRestrictIsoDiagonal f 𝒰Y 𝒰X i j)] + have hu : FormallyUnramified ((𝒰X i).map j ≫ pullback.snd f (𝒰Y.map i)) := + comp_mem _ _ _ inferInstance (pullback_snd _ _ inferInstance) + have hfin : LocallyOfFiniteType ((𝒰X i).map j ≫ pullback.snd f (𝒰Y.map i)) := + comp_mem _ _ _ inferInstance (pullback_snd _ _ inferInstance) + exact this _ ⟨⟨_, rfl⟩, ⟨_, rfl⟩⟩ + obtain ⟨⟨S, rfl⟩, R, rfl⟩ := hX + obtain ⟨f, rfl⟩ := Spec.map_surjective f + rw [HasRingHomProperty.Spec_iff (P := @FormallyUnramified), + HasRingHomProperty.Spec_iff (P := @LocallyOfFiniteType)] at * + algebraize [f.hom] + rw [show f = CommRingCat.ofHom (algebraMap R S) from rfl, diagonal_Spec_map R S, + cancel_right_of_respectsIso (P := @IsOpenImmersion)] + infer_instance + end FormallyUnramified end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Restrict.lean b/Mathlib/AlgebraicGeometry/Restrict.lean index ad0701e07ad58..c933e69c7913f 100644 --- a/Mathlib/AlgebraicGeometry/Restrict.lean +++ b/Mathlib/AlgebraicGeometry/Restrict.lean @@ -406,6 +406,26 @@ lemma Scheme.Hom.preimageIso_inv_ι {X Y : Scheme.{u}} (f : X.Hom Y) [IsIso (C : @[deprecated (since := "2024-10-20")] alias Scheme.restrictMapIso := Scheme.Hom.preimageIso +/-- If `U ≤ V` are opens of `X`, the restriction of `U` to `V` is isomorphic to `U`. -/ +noncomputable def Scheme.Opens.isoOfLE {X : Scheme.{u}} {U V : X.Opens} + (hUV : U ≤ V) : (V.ι ⁻¹ᵁ U).toScheme ≅ U := + IsOpenImmersion.isoOfRangeEq ((V.ι ⁻¹ᵁ U).ι ≫ V.ι) U.ι <| by + have : V.ι ''ᵁ (V.ι ⁻¹ᵁ U) = U := by simpa [Scheme.Hom.image_preimage_eq_opensRange_inter] + rw [Scheme.comp_coeBase, TopCat.coe_comp, Scheme.Opens.range_ι, Set.range_comp, ← this] + simp + +@[reassoc (attr := simp)] +lemma Scheme.Opens.isoOfLE_hom_ι {X : Scheme.{u}} {U V : X.Opens} + (hUV : U ≤ V) : + (Scheme.Opens.isoOfLE hUV).hom ≫ U.ι = (V.ι ⁻¹ᵁ U).ι ≫ V.ι := by + simp [isoOfLE] + +@[reassoc (attr := simp)] +lemma Scheme.Opens.isoOfLE_inv_ι {X : Scheme.{u}} {U V : X.Opens} + (hUV : U ≤ V) : + (Scheme.Opens.isoOfLE hUV).inv ≫ (V.ι ⁻¹ᵁ U).ι ≫ V.ι = U.ι := by + simp [isoOfLE] + section MorphismRestrict /-- Given a morphism `f : X ⟶ Y` and an open set `U ⊆ Y`, we have `X ×[Y] U ≅ X |_{f ⁻¹ U}` -/ From 79ad6ef36345d2b2b3f7c340017c0738e69d6dd3 Mon Sep 17 00:00:00 2001 From: Oliver Nash Date: Tue, 4 Feb 2025 09:36:11 +0000 Subject: [PATCH 064/103] feat: drop ordering assumption in `RootPairing.coxeterWeight_mem_set_of_isCrystallographic` (#21122) Some of the required changes also allow us to unify (and generalise) the `RootPairing.IsAnisotropic` instances. The means of obtaining these generalisations is to work with a root pairing with coefficients in `R` taking values in an ordered subring `S` (in the sense of `RootPairing.IsValuedIn`). This allows us to avoid assuming `R` is ordered, and includes the important case of a crystallographic pairing in characteristic zero. The cost of this is that various definitions and lemmas need to be generalised to allow room for the subring `S` (implemented using an injective `algebra S R` structure). In particular the definition `RootPairing.IsRootPositive` becomes `RootPairing.RootPositiveForm` and has its API substantially reworked. An alternative approach to the headline result (taken in the informal literature) is to invoke `RootPairing.restrictScalarsRat` but this only works with field coefficients and does not provide the same unifications. We also repair some doc strings (which did not have fully-qualified names, or had names which had drifted from the code). --- Mathlib/LinearAlgebra/BilinearMap.lean | 5 + .../RootSystem/CartanMatrix.lean | 2 +- Mathlib/LinearAlgebra/RootSystem/Defs.lean | 29 ++- .../RootSystem/Finite/CanonicalBilinear.lean | 139 ++++++++----- .../RootSystem/Finite/Nondegenerate.lean | 43 ++-- .../RootSystem/RootPositive.lean | 187 +++++++++++++----- 6 files changed, 272 insertions(+), 133 deletions(-) diff --git a/Mathlib/LinearAlgebra/BilinearMap.lean b/Mathlib/LinearAlgebra/BilinearMap.lean index e1b2be24a3275..146dc3a125bc7 100644 --- a/Mathlib/LinearAlgebra/BilinearMap.lean +++ b/Mathlib/LinearAlgebra/BilinearMap.lean @@ -429,6 +429,11 @@ noncomputable def restrictScalarsRange : k (restrictScalarsRange i j k hk B hB m n) = B (i m) (j n) := by simp [restrictScalarsRange] +@[simp] +lemma eq_restrictScalarsRange_iff (m : M') (n : N') (p : P') : + p = restrictScalarsRange i j k hk B hB m n ↔ k p = B (i m) (j n) := by + rw [← restrictScalarsRange_apply i j k hk B hB m n, hk.eq_iff] + @[simp] lemma restrictScalarsRange_apply_eq_zero_iff (m : M') (n : N') : restrictScalarsRange i j k hk B hB m n = 0 ↔ B (i m) (j n) = 0 := by diff --git a/Mathlib/LinearAlgebra/RootSystem/CartanMatrix.lean b/Mathlib/LinearAlgebra/RootSystem/CartanMatrix.lean index 863271814fe03..ad38f6d9be0e1 100644 --- a/Mathlib/LinearAlgebra/RootSystem/CartanMatrix.lean +++ b/Mathlib/LinearAlgebra/RootSystem/CartanMatrix.lean @@ -43,7 +43,7 @@ lemma cartanMatrixIn_def (i j : b.support) : b.cartanMatrixIn S i j = P.pairingIn S i j := rfl -variable [Nontrivial R] [NoZeroSMulDivisors S R] +variable [FaithfulSMul S R] @[simp] lemma cartanMatrixIn_apply_same (i : b.support) : diff --git a/Mathlib/LinearAlgebra/RootSystem/Defs.lean b/Mathlib/LinearAlgebra/RootSystem/Defs.lean index 7ca876bc7654e..cb69a08031d57 100644 --- a/Mathlib/LinearAlgebra/RootSystem/Defs.lean +++ b/Mathlib/LinearAlgebra/RootSystem/Defs.lean @@ -406,9 +406,6 @@ lemma isValuedIn_iff_mem_range : P.IsValuedIn S ↔ ∀ i j, P.pairing i j ∈ range (algebraMap S R) := by simp only [isValuedIn_iff, mem_range] -instance : P.IsValuedIn R where - exists_value := by simp - instance [P.IsValuedIn S] : P.flip.IsValuedIn S := by rw [isValuedIn_iff, forall_comm] exact P.exists_value @@ -417,7 +414,7 @@ instance [P.IsValuedIn S] : P.flip.IsValuedIn S := by coefficients. Note that it is uniquely-defined only when the map `S → R` is injective, i.e., when we have -`[NoZeroSMulDivisors S R]`. -/ +`[FaithfulSMul S R]`. -/ def pairingIn [P.IsValuedIn S] (i j : ι) : S := (P.exists_value i j).choose @@ -426,6 +423,11 @@ lemma algebraMap_pairingIn [P.IsValuedIn S] (i j : ι) : algebraMap S R (P.pairingIn S i j) = P.pairing i j := (P.exists_value i j).choose_spec +@[simp] +lemma pairingIn_same [FaithfulSMul S R] [P.IsValuedIn S] (i : ι) : + P.pairingIn S i i = 2 := + FaithfulSMul.algebraMap_injective S R <| by simp [map_ofNat] + lemma IsValuedIn.trans (T : Type*) [CommRing T] [Algebra T S] [Algebra T R] [IsScalarTower T S R] [P.IsValuedIn T] : P.IsValuedIn S where @@ -433,6 +435,23 @@ lemma IsValuedIn.trans (T : Type*) [CommRing T] [Algebra T S] [Algebra T R] [IsS use algebraMap T S (P.pairingIn T i j) simp [← RingHom.comp_apply, ← IsScalarTower.algebraMap_eq T S R] +lemma coroot'_apply_apply_mem_of_mem_span [Module S M] [IsScalarTower S R M] [P.IsValuedIn S] + {x : M} (hx : x ∈ span S (range P.root)) (i : ι) : + P.coroot' i x ∈ range (algebraMap S R) := by + rw [show range (algebraMap S R) = LinearMap.range (Algebra.linearMap S R) from rfl] + induction hx using Submodule.span_induction with + | mem x hx => + obtain ⟨k, rfl⟩ := hx + simpa using RootPairing.exists_value k i + | zero => simp + | add x y _ _ hx hy => simpa only [map_add] using add_mem hx hy + | smul t x _ hx => simpa only [LinearMap.map_smul_of_tower] using Submodule.smul_mem _ t hx + +lemma root'_apply_apply_mem_of_mem_span [Module S N] [IsScalarTower S R N] [P.IsValuedIn S] + {x : N} (hx : x ∈ span S (range P.coroot)) (i : ι) : + P.root' i x ∈ LinearMap.range (Algebra.linearMap S R) := + P.flip.coroot'_apply_apply_mem_of_mem_span S hx i + end IsValuedIn /-- A root pairing is said to be reduced if any linearly dependent pair of roots is related by a @@ -582,7 +601,7 @@ lemma coxeterWeight_swap : coxeterWeight P i j = coxeterWeight P j i := by coefficients. Note that it is uniquely-defined only when the map `S → R` is injective, i.e., when we have -`[NoZeroSMulDivisors S R]`. -/ +`[FaithfulSMul S R]`. -/ def coxeterWeightIn (S : Type*) [CommRing S] [Algebra S R] [P.IsValuedIn S] (i j : ι) : S := P.pairingIn S i j * P.pairingIn S j i diff --git a/Mathlib/LinearAlgebra/RootSystem/Finite/CanonicalBilinear.lean b/Mathlib/LinearAlgebra/RootSystem/Finite/CanonicalBilinear.lean index e2e30db0f2b7c..0132dea94b520 100644 --- a/Mathlib/LinearAlgebra/RootSystem/Finite/CanonicalBilinear.lean +++ b/Mathlib/LinearAlgebra/RootSystem/Finite/CanonicalBilinear.lean @@ -19,16 +19,20 @@ Another application is to the faithfulness of the Weyl group action on roots, an Weyl group. ## Main definitions: - * `Polarization`: A distinguished linear map from the weight space to the coweight space. - * `RootForm` : The bilinear form on weight space corresponding to `Polarization`. + * `RootPairing.Polarization`: A distinguished linear map from the weight space to the coweight + space. + * `RootPairing.RootForm` : The bilinear form on weight space corresponding to `Polarization`. ## Main results: - * `polarization_self_sum_of_squares` : The inner product of any weight vector is a sum of squares. - * `rootForm_reflection_reflection_apply` : `RootForm` is invariant with respect + * `RootPairing.rootForm_self_sum_of_squares` : The inner product of any + weight vector is a sum of squares. + * `RootPairing.rootForm_reflection_reflection_apply` : `RootForm` is invariant with respect to reflections. - * `rootForm_self_smul_coroot`: The inner product of a root with itself times the - corresponding coroot is equal to two times Polarization applied to the root. - * `rootForm_self_non_neg`: `RootForm` is positive semidefinite. + * `RootPairing.rootForm_self_smul_coroot`: The inner product of a root with itself + times the corresponding coroot is equal to two times Polarization applied to the root. + * `RootPairing.exists_ge_zero_eq_rootForm`: `RootForm` is positive semidefinite. + * `RootPairing.coxeterWeight_mem_set_of_isCrystallographic`: the Coxeter weights belongs to the + set `{0, 1, 2, 3, 4}`. ## References: * [N. Bourbaki, *Lie groups and Lie algebras. Chapters 4--6*][bourbaki1968] @@ -37,8 +41,6 @@ Weyl group. ## TODO (possibly in other files) * Weyl-invariance * Faithfulness of Weyl group action, and finiteness of Weyl group, for finite root systems. - * Relation to Coxeter weight. In particular, positivity constraints for finite root pairings mean - we restrict to weights between 0 and 4. -/ open Set Function @@ -51,11 +53,13 @@ variable {ι R M N : Type*} namespace RootPairing -section CommRing - -variable [Fintype ι] [CommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] +variable [CommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] (P : RootPairing ι R M N) +section Fintype + +variable [Fintype ι] + instance : Module.Finite R P.rootSpan := Finite.span_of_finite R <| finite_range P.root instance : Module.Finite R P.corootSpan := Finite.span_of_finite R <| finite_range P.coroot @@ -166,6 +170,16 @@ lemma rootForm_self_smul_coroot (i : ι) : rw [Finset.sum_smul, add_neg_eq_zero.mpr rfl] exact sub_eq_zero_of_eq rfl +lemma corootForm_self_smul_root (i : ι) : + (P.CorootForm (P.coroot i) (P.coroot i)) • P.root i = 2 • P.CoPolarization (P.coroot i) := + rootForm_self_smul_coroot (P.flip) i + +lemma four_nsmul_coPolarization_compl_polarization_apply_root (i : ι) : + (4 • P.CoPolarization ∘ₗ P.Polarization) (P.root i) = + (P.RootForm (P.root i) (P.root i) * P.CorootForm (P.coroot i) (P.coroot i)) • P.root i := by + rw [LinearMap.smul_apply, LinearMap.comp_apply, show 4 = 2 * 2 from rfl, mul_smul, ← map_nsmul, + ← rootForm_self_smul_coroot, map_smul, smul_comm, ← corootForm_self_smul_root, smul_smul] + lemma four_smul_rootForm_sq_eq_coxeterWeight_smul (i j : ι) : 4 • (P.RootForm (P.root i) (P.root j)) ^ 2 = P.coxeterWeight i j • (P.RootForm (P.root i) (P.root i) * P.RootForm (P.root j) (P.root j)) := by @@ -183,10 +197,6 @@ lemma four_smul_rootForm_sq_eq_coxeterWeight_smul (i j : ι) : map_smul, ← pairing, smul_eq_mul, smul_eq_mul, smul_eq_mul, coxeterWeight] ring -lemma corootForm_self_smul_root (i : ι) : - (P.CorootForm (P.coroot i) (P.coroot i)) • P.root i = 2 • P.CoPolarization (P.coroot i) := - rootForm_self_smul_coroot (P.flip) i - lemma rootForm_self_sum_of_squares (x : M) : IsSumSq (P.RootForm x x) := P.rootForm_apply_apply x x ▸ IsSumSq.sum_mul_self Finset.univ _ @@ -226,57 +236,86 @@ lemma prod_rootForm_smul_coroot_mem_range_domRestrict (i : ι) : use ⟨(c • 2 • P.root i), by aesop⟩ simp -end CommRing - -section LinearOrderedCommRing +end Fintype -variable [Fintype ι] [LinearOrderedCommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] - [Module R N] (P : RootPairing ι R M N) +section IsValuedInOrdered -theorem rootForm_self_non_neg (x : M) : 0 ≤ P.RootForm x x := - IsSumSq.nonneg (P.rootForm_self_sum_of_squares x) +variable (S : Type*) [LinearOrderedCommRing S] [Algebra S R] [FaithfulSMul S R] + [Module S M] [IsScalarTower S R M] [P.IsValuedIn S] -lemma rootForm_self_eq_zero_iff {x : M} : - P.RootForm x x = 0 ↔ x ∈ LinearMap.ker P.RootForm := - P.RootForm.apply_apply_same_eq_zero_iff P.rootForm_self_non_neg P.rootForm_symmetric - -lemma rootForm_root_self_pos (i : ι) : - 0 < P.RootForm (P.root i) (P.root i) := by - simp only [rootForm_apply_apply] - exact Finset.sum_pos' (fun j _ ↦ mul_self_nonneg _) ⟨i, by simp⟩ +/-- The bilinear form of a finite root pairing taking values in a linearly-ordered ring, as a +root-positive form. -/ +def posRootForm [Fintype ι] : P.RootPositiveForm S where + form := P.RootForm + symm := P.rootForm_symmetric + isOrthogonal_reflection := P.rootForm_reflection_reflection_apply + exists_eq i j := ⟨∑ k, P.pairingIn S i k * P.pairingIn S j k, by simp [rootForm_apply_apply]⟩ + exists_pos_eq i := by + refine ⟨∑ k, P.pairingIn S i k ^ 2, ?_, by simp [sq, rootForm_apply_apply]⟩ + exact Finset.sum_pos' (fun j _ ↦ sq_nonneg _) ⟨i, by simp⟩ + +theorem exists_ge_zero_eq_rootForm [Fintype ι] (x : M) (hx : x ∈ span S (range P.root)) : + ∃ s ≥ 0, algebraMap S R s = P.RootForm x x := by + refine ⟨(P.posRootForm S).posForm ⟨x, hx⟩ ⟨x, hx⟩, IsSumSq.nonneg ?_, by simp [posRootForm]⟩ + choose s hs using P.coroot'_apply_apply_mem_of_mem_span S hx + suffices (P.posRootForm S).posForm ⟨x, hx⟩ ⟨x, hx⟩ = ∑ i, s i * s i from + this ▸ IsSumSq.sum_mul_self Finset.univ s + apply FaithfulSMul.algebraMap_injective S R + simp only [posRootForm, RootPositiveForm.algebraMap_posForm, map_sum, map_mul] + simp [← Algebra.linearMap_apply, hs, rootForm_apply_apply] /-- SGA3 XXI Prop. 2.3.1 -/ -lemma coxeterWeight_le_four (i j : ι) : P.coxeterWeight i j ≤ 4 := by - set li := P.RootForm (P.root i) (P.root i) - set lj := P.RootForm (P.root j) (P.root j) - set lij := P.RootForm (P.root i) (P.root j) - have hi := P.rootForm_root_self_pos i - have hj := P.rootForm_root_self_pos j +lemma coxeterWeightIn_le_four [Finite ι] (i j : ι) : + P.coxeterWeightIn S i j ≤ 4 := by + have : Fintype ι := Fintype.ofFinite ι + let ri : span S (range P.root) := ⟨P.root i, Submodule.subset_span (mem_range_self _)⟩ + let rj : span S (range P.root) := ⟨P.root j, Submodule.subset_span (mem_range_self _)⟩ + set li := (P.posRootForm S).posForm ri ri + set lj := (P.posRootForm S).posForm rj rj + set lij := (P.posRootForm S).posForm ri rj + obtain ⟨si, hsi, hsi'⟩ := (P.posRootForm S).exists_pos_eq i + obtain ⟨sj, hsj, hsj'⟩ := (P.posRootForm S).exists_pos_eq j + replace hsi' : si = li := FaithfulSMul.algebraMap_injective S R <| by simpa [li] using hsi' + replace hsj' : sj = lj := FaithfulSMul.algebraMap_injective S R <| by simpa [lj] using hsj' + rw [hsi'] at hsi + rw [hsj'] at hsj have cs : 4 * lij ^ 2 ≤ 4 * (li * lj) := by rw [mul_le_mul_left four_pos] - exact LinearMap.BilinForm.apply_sq_le_of_symm P.RootForm P.rootForm_self_non_neg - P.rootForm_symmetric (P.root i) (P.root j) - have key : 4 • lij ^ 2 = _ • (li * lj) := P.four_smul_rootForm_sq_eq_coxeterWeight_smul i j + refine (P.posRootForm S).posForm.apply_sq_le_of_symm ?_ (P.posRootForm S).isSymm_posForm ri rj + intro x + obtain ⟨s, hs, hs'⟩ := P.exists_ge_zero_eq_rootForm S x x.property + change _ = (P.posRootForm S).form x x at hs' + rw [(P.posRootForm S).algebraMap_apply_eq_form_iff] at hs' + rwa [← hs'] + have key : 4 • lij ^ 2 = P.coxeterWeightIn S i j • (li * lj) := by + apply FaithfulSMul.algebraMap_injective S R + simpa [map_ofNat, lij, posRootForm, ri, rj, li, lj] using + P.four_smul_rootForm_sq_eq_coxeterWeight_smul i j simp only [nsmul_eq_mul, smul_eq_mul, Nat.cast_ofNat] at key rwa [key, mul_le_mul_right (by positivity)] at cs -instance instIsRootPositiveRootForm : IsRootPositive P P.RootForm where - zero_lt_apply_root i := P.rootForm_root_self_pos i - symm := P.rootForm_symmetric - apply_reflection_eq := P.rootForm_reflection_reflection_apply +variable [Finite ι] [P.IsCrystallographic] [CharZero R] (i j : ι) -lemma coxeterWeight_mem_set_of_isCrystallographic (i j : ι) [P.IsCrystallographic] : - P.coxeterWeight i j ∈ ({0, 1, 2, 3, 4} : Set R) := by - obtain ⟨n, hcn⟩ : ∃ n : ℕ, P.coxeterWeight i j = n := by +lemma coxeterWeightIn_mem_set_of_isCrystallographic : + P.coxeterWeightIn ℤ i j ∈ ({0, 1, 2, 3, 4} : Set ℤ) := by + have : Fintype ι := Fintype.ofFinite ι + obtain ⟨n, hcn⟩ : ∃ n : ℕ, P.coxeterWeightIn ℤ i j = n := by have : 0 ≤ P.coxeterWeightIn ℤ i j := by - simpa [← P.algebraMap_coxeterWeightIn ℤ] using P.coxeterWeight_non_neg P.RootForm i j + simpa only [P.algebraMap_coxeterWeightIn] using P.coxeterWeight_nonneg (P.posRootForm ℤ) i j obtain ⟨n, hn⟩ := Int.eq_ofNat_of_zero_le this exact ⟨n, by simp [← P.algebraMap_coxeterWeightIn ℤ, hn]⟩ - have : P.coxeterWeight i j ≤ 4 := P.coxeterWeight_le_four i j + have : P.coxeterWeightIn ℤ i j ≤ 4 := P.coxeterWeightIn_le_four ℤ i j simp only [hcn, mem_insert_iff, mem_singleton_iff] at this ⊢ norm_cast at this ⊢ omega -end LinearOrderedCommRing +lemma coxeterWeight_mem_set_of_isCrystallographic : + P.coxeterWeight i j ∈ ({0, 1, 2, 3, 4} : Set R) := by + have := (FaithfulSMul.algebraMap_injective ℤ R).mem_set_image.mpr <| + P.coxeterWeightIn_mem_set_of_isCrystallographic i j + rw [algebraMap_coxeterWeightIn] at this + simpa [eq_comm] using this + +end IsValuedInOrdered end RootPairing diff --git a/Mathlib/LinearAlgebra/RootSystem/Finite/Nondegenerate.lean b/Mathlib/LinearAlgebra/RootSystem/Finite/Nondegenerate.lean index aa86853fa0777..d36a94f286c84 100644 --- a/Mathlib/LinearAlgebra/RootSystem/Finite/Nondegenerate.lean +++ b/Mathlib/LinearAlgebra/RootSystem/Finite/Nondegenerate.lean @@ -42,8 +42,7 @@ Weyl group. ## Todo * Weyl-invariance of `RootForm` and `CorootForm` * Faithfulness of Weyl group perm action, and finiteness of Weyl group, over ordered rings. - * Relation to Coxeter weight. In particular, positivity constraints for finite root pairings mean - we restrict to weights between 0 and 4. + * Relation to Coxeter weight. -/ noncomputable section @@ -74,24 +73,15 @@ instance [P.IsAnisotropic] : P.flip.IsAnisotropic where rootForm_root_ne_zero := IsAnisotropic.corootForm_coroot_ne_zero corootForm_coroot_ne_zero := IsAnisotropic.rootForm_root_ne_zero -/-- An auxiliary lemma en route to `RootPairing.instIsAnisotropicOfIsCrystallographic`. -/ -private lemma rootForm_root_ne_zero_aux [CharZero R] [P.IsCrystallographic] (i : ι) : - P.RootForm (P.root i) (P.root i) ≠ 0 := by - choose z hz using P.exists_value (S := ℤ) i - simp_rw [algebraMap_int_eq, Int.coe_castRingHom] at hz - simp only [rootForm_apply_apply, PerfectPairing.flip_apply_apply, root_coroot_eq_pairing, ← hz] - suffices 0 < ∑ i, z i * z i by norm_cast; exact this.ne' - refine Finset.sum_pos' (fun i _ ↦ mul_self_nonneg (z i)) ⟨i, Finset.mem_univ i, ?_⟩ - have hzi : z i = 2 := by - specialize hz i - rw [pairing_same] at hz - norm_cast at hz - simp [hzi] +lemma isAnisotropic_of_isValuedIn (S : Type*) + [LinearOrderedCommRing S] [Algebra S R] [FaithfulSMul S R] [P.IsValuedIn S] : + IsAnisotropic P where + rootForm_root_ne_zero i := (P.posRootForm S).form_apply_root_ne_zero i + corootForm_coroot_ne_zero i := (P.flip.posRootForm S).form_apply_root_ne_zero i instance instIsAnisotropicOfIsCrystallographic [CharZero R] [P.IsCrystallographic] : - IsAnisotropic P where - rootForm_root_ne_zero := P.rootForm_root_ne_zero_aux - corootForm_coroot_ne_zero := P.flip.rootForm_root_ne_zero_aux + IsAnisotropic P := + P.isAnisotropic_of_isValuedIn ℤ end CommRing @@ -224,16 +214,23 @@ section LinearOrderedCommRing variable [LinearOrderedCommRing R] [Module R M] [Module R N] (P : RootPairing ι R M N) -instance instIsAnisotropicOfLinearOrderedCommRing : IsAnisotropic P where - rootForm_root_ne_zero i := (P.rootForm_root_self_pos i).ne' - corootForm_coroot_ne_zero i := (P.flip.rootForm_root_self_pos i).ne' +instance instIsAnisotropicOfLinearOrderedCommRing : IsAnisotropic P := + P.isAnisotropic_of_isValuedIn R + +lemma zero_le_rootForm (x : M) : + 0 ≤ P.RootForm x x := + (P.rootForm_self_sum_of_squares x).nonneg /-- See also `RootPairing.rootForm_restrict_nondegenerate_of_isAnisotropic`. -/ lemma rootForm_restrict_nondegenerate_of_ordered : LinearMap.Nondegenerate (P.RootForm.restrict P.rootSpan) := - (P.RootForm.nondegenerate_restrict_iff_disjoint_ker (rootForm_self_non_neg P) + (P.RootForm.nondegenerate_restrict_iff_disjoint_ker P.zero_le_rootForm P.rootForm_symmetric).mpr P.disjoint_rootSpan_ker_rootForm +lemma rootForm_self_eq_zero_iff {x : M} : + P.RootForm x x = 0 ↔ x ∈ LinearMap.ker P.RootForm := + P.RootForm.apply_apply_same_eq_zero_iff P.zero_le_rootForm P.rootForm_symmetric + lemma eq_zero_of_mem_rootSpan_of_rootForm_self_eq_zero {x : M} (hx : x ∈ P.rootSpan) (hx' : P.RootForm x x = 0) : x = 0 := by @@ -242,7 +239,7 @@ lemma eq_zero_of_mem_rootSpan_of_rootForm_self_eq_zero {x : M} lemma rootForm_pos_of_ne_zero {x : M} (hx : x ∈ P.rootSpan) (h : x ≠ 0) : 0 < P.RootForm x x := by - apply (P.rootForm_self_non_neg x).lt_of_ne + apply (P.zero_le_rootForm x).lt_of_ne contrapose! h exact P.eq_zero_of_mem_rootSpan_of_rootForm_self_eq_zero hx h.symm diff --git a/Mathlib/LinearAlgebra/RootSystem/RootPositive.lean b/Mathlib/LinearAlgebra/RootSystem/RootPositive.lean index e9d55f92f8209..ac82c39e0ac23 100644 --- a/Mathlib/LinearAlgebra/RootSystem/RootPositive.lean +++ b/Mathlib/LinearAlgebra/RootSystem/RootPositive.lean @@ -9,7 +9,7 @@ import Mathlib.LinearAlgebra.RootSystem.Defs # Root-positive bilinear forms on root pairings This file contains basic results on Weyl-invariant inner products for root systems and root data. -We introduce a Prop-valued mixin class for a root pairing and bilinear form, specifying +Given a root pairing we define a structure which contains a bilinear form together with axioms for reflection-invariance, symmetry, and strict positivity on all roots. We show that root-positive forms display the same sign behavior as the canonical pairing between roots and coroots. @@ -17,16 +17,17 @@ Root-positive forms show up naturally as the invariant forms for symmetrizable K algebras. In the finite case, the canonical polarization yields a root-positive form that is positive semi-definite on weight space and positive-definite on the span of roots. -## Main definitions: +## Main definitions / results: - * `IsRootPositive`: A prop-valued mixin class for root pairings with bilinear forms, specifying - the form is symmetric, reflection-invariant, and all roots have strictly positive norm. - -## Main results: - -* `pairing_pos_iff` and `pairing_zero_iff` : sign relations between `P.pairing` and the form `B`. -* `coxeter_weight_non_neg` : All pairs of roots have non-negative Coxeter weight. -* `orthogonal_of_coxeter_weight_zero` : If Coxeter weight vanishes, then the roots are orthogonal. + * `RootPairing.RootPositiveForm`: Given a root pairing this is a structure which contains a + bilinear form together with axioms for reflection-invariance, symmetry, and strict positivity on + all roots. + * `RootPairing.zero_lt_pairingIn_iff`: sign relations between `RootPairing.pairingIn` and a + root-positive form. + * `RootPairing.pairing_zero_iff`: symmetric vanishing condition for `RootPairing.pairing` + * `RootPairing.coxeterWeight_nonneg`: All pairs of roots have non-negative Coxeter weight. + * `RootPairing.coxeterWeight_zero_iff_isOrthogonal` : A Coxeter weight vanishes iff the roots are + orthogonal. ## TODO @@ -36,62 +37,140 @@ positive semi-definite on weight space and positive-definite on the span of root noncomputable section -variable {ι R M N : Type*} - -namespace RootPairing +open Function Set Submodule -variable [LinearOrderedCommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] +variable {ι R S M N : Type*} [LinearOrderedCommRing S] [CommRing R] [Algebra S R] + [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] -/-- A Prop-valued class for a bilinear form to be compatible with a root pairing. -/ -class IsRootPositive (P : RootPairing ι R M N) (B : M →ₗ[R] M →ₗ[R] R) : Prop where - zero_lt_apply_root : ∀ i, 0 < B (P.root i) (P.root i) - symm : ∀ x y, B x y = B y x - apply_reflection_eq : ∀ i x y, B (P.reflection i x) (P.reflection i y) = B x y - -variable {P : RootPairing ι R M N} (B : M →ₗ[R] M →ₗ[R] R) [IsRootPositive P B] (i j : ι) -include B +namespace RootPairing -lemma two_mul_apply_root_root : +lemma two_mul_apply_root_root_of_isOrthogonal (P : RootPairing ι R M N) + (B : LinearMap.BilinForm R M) (i j : ι) (h : B.IsOrthogonal (P.reflection j)) : 2 * B (P.root i) (P.root j) = P.pairing i j * B (P.root j) (P.root j) := by rw [two_mul, ← eq_sub_iff_add_eq] - nth_rw 1 [← IsRootPositive.apply_reflection_eq (P := P) (B := B) j (P.root i) (P.root j)] + nth_rw 1 [← h] rw [reflection_apply, reflection_apply_self, root_coroot'_eq_pairing, LinearMap.map_sub₂, LinearMap.map_smul₂, smul_eq_mul, LinearMap.map_neg, LinearMap.map_neg, mul_neg, neg_sub_neg] +variable (S) in +/-- Given a root pairing, this is an invariant symmetric bilinear form satisfying a positivity +condition. -/ +structure RootPositiveForm (P : RootPairing ι R M N) [P.IsValuedIn S] where + /-- The bilinear form bundled inside a `RootPositiveForm`. -/ + form : LinearMap.BilinForm R M + symm : form.IsSymm + isOrthogonal_reflection (i : ι) : form.IsOrthogonal (P.reflection i) + exists_eq (i j : ι) : ∃ s, algebraMap S R s = form (P.root i) (P.root j) + exists_pos_eq (i : ι) : ∃ s > 0, algebraMap S R s = form (P.root i) (P.root i) + +variable {P : RootPairing ι R M N} [P.IsValuedIn S] (B : P.RootPositiveForm S) (i j : ι) + +lemma RootPositiveForm.two_mul_apply_root_root : + 2 * B.form (P.root i) (P.root j) = P.pairing i j * B.form (P.root j) (P.root j) := + P.two_mul_apply_root_root_of_isOrthogonal B.form i j (B.isOrthogonal_reflection j) + +variable [FaithfulSMul S R] + +lemma RootPositiveForm.form_apply_root_ne_zero (i : ι) : + B.form (P.root i) (P.root i) ≠ 0 := by + obtain ⟨s, hs, hs'⟩ := B.exists_pos_eq i + simpa [← hs'] using hs.ne' + +variable [Module S M] [IsScalarTower S R M] + +namespace RootPositiveForm + +/-- Given a root-positive form associated to a root pairing with coefficients in `R` but taking +values in `S`, this is the associated `S`-bilinear form on the `S`-span of the roots. -/ +def posForm : + LinearMap.BilinForm S (span S (range P.root)) := + LinearMap.restrictScalarsRange (span S (range P.root)).subtype (span S (range P.root)).subtype + (Algebra.linearMap S R) (FaithfulSMul.algebraMap_injective S R) B.form + (fun ⟨x, hx⟩ ⟨y, hy⟩ ↦ by + apply LinearMap.BilinMap.apply_apply_mem_of_mem_span + (s := range P.root) (t := range P.root) + (B := (LinearMap.restrictScalarsₗ S R _ _ _).comp (B.form.restrictScalars S)) + · rintro - ⟨i, rfl⟩ - ⟨j, rfl⟩ + simpa using B.exists_eq i j + · simpa + · simpa) + +@[simp] lemma algebraMap_posForm {x y : span S (range P.root)} : + algebraMap S R (B.posForm x y) = B.form x y := by + change Algebra.linearMap S R _ = _ + simp [posForm] + +lemma algebraMap_apply_eq_form_iff {x y : span S (range P.root)} {s : S} : + algebraMap S R s = B.form x y ↔ s = B.posForm x y := by + simp [RootPositiveForm.posForm] + +lemma zero_lt_posForm_iff {x y : span S (range P.root)} : + 0 < B.posForm x y ↔ ∃ s > 0, algebraMap S R s = B.form x y := by + refine ⟨fun h ↦ ⟨B.posForm x y, h, by simp⟩, fun ⟨s, h, h'⟩ ↦ ?_⟩ + rw [← B.algebraMap_posForm] at h' + rwa [← FaithfulSMul.algebraMap_injective S R h'] + +lemma zero_lt_posForm_apply_root (i : ι) + (hi : P.root i ∈ span S (range P.root) := subset_span (mem_range_self i)) : + 0 < B.posForm ⟨P.root i, hi⟩ ⟨P.root i, hi⟩ := by + simpa only [zero_lt_posForm_iff] using B.exists_pos_eq i + +lemma isSymm_posForm : + B.posForm.IsSymm := by + intro x y + apply FaithfulSMul.algebraMap_injective S R + simpa using B.symm.eq x y + @[simp] -lemma zero_lt_apply_root_root_iff : 0 < B (P.root i) (P.root j) ↔ 0 < P.pairing i j := by - refine ⟨fun h ↦ (mul_pos_iff_of_pos_right - (IsRootPositive.zero_lt_apply_root (P := P) (B := B) j)).mp ?_, - fun h ↦ (mul_pos_iff_of_pos_left zero_lt_two).mp ?_⟩ - · rw [← two_mul_apply_root_root] - exact mul_pos zero_lt_two h - · rw [two_mul_apply_root_root] - exact mul_pos h (IsRootPositive.zero_lt_apply_root (P := P) (B := B) j) - -lemma zero_lt_pairing_iff : 0 < P.pairing i j ↔ 0 < P.pairing j i := by - rw [← zero_lt_apply_root_root_iff B, IsRootPositive.symm P, zero_lt_apply_root_root_iff] - -lemma coxeterWeight_non_neg : 0 ≤ P.coxeterWeight i j := by - dsimp [coxeterWeight] - by_cases h : 0 < P.pairing i j - · exact le_of_lt <| mul_pos h ((zero_lt_pairing_iff B i j).mp h) - · have hn : ¬ 0 < P.pairing j i := fun hc ↦ h ((zero_lt_pairing_iff B i j).mpr hc) - simp_all only [not_lt, ge_iff_le] +lemma zero_lt_apply_root_root_iff + (hi : P.root i ∈ span S (range P.root) := subset_span (mem_range_self i)) + (hj : P.root j ∈ span S (range P.root) := subset_span (mem_range_self j)) : + 0 < B.posForm ⟨P.root i, hi⟩ ⟨P.root j, hj⟩ ↔ 0 < P.pairingIn S i j := by + let ri : span S (range P.root) := ⟨P.root i, hi⟩ + let rj : span S (range P.root) := ⟨P.root j, hj⟩ + have : 2 * B.posForm ri rj = P.pairingIn S i j * B.posForm rj rj := by + apply FaithfulSMul.algebraMap_injective S R + simpa [map_ofNat] using two_mul_apply_root_root B i j + calc 0 < B.posForm ri rj + ↔ 0 < 2 * B.posForm ri rj := by rw [mul_pos_iff_of_pos_left zero_lt_two] + _ ↔ 0 < P.pairingIn S i j * B.posForm rj rj := by rw [this] + _ ↔ 0 < P.pairingIn S i j := by rw [mul_pos_iff_of_pos_right (B.zero_lt_posForm_apply_root j)] + +end RootPositiveForm + +include B + +lemma zero_lt_pairingIn_iff : + 0 < P.pairingIn S i j ↔ 0 < P.pairingIn S j i := by + rw [← B.zero_lt_apply_root_root_iff, ← B.isSymm_posForm.eq, RingHom.id_apply, + B.zero_lt_apply_root_root_iff] + +lemma coxeterWeight_nonneg : 0 ≤ P.coxeterWeightIn S i j := by + dsimp [coxeterWeightIn] + rcases lt_or_le 0 (P.pairingIn S i j) with h | h + · exact le_of_lt <| mul_pos h ((zero_lt_pairingIn_iff B i j).mp h) + · have hn : P.pairingIn S j i ≤ 0 := by rwa [← not_lt, ← zero_lt_pairingIn_iff B i j, not_lt] exact mul_nonneg_of_nonpos_of_nonpos h hn +variable [NoZeroDivisors R] + +omit [Module S M] [IsScalarTower S R M] + @[simp] -lemma apply_root_root_zero_iff : B (P.root i) (P.root j) = 0 ↔ P.pairing i j = 0 := by - refine ⟨fun hB => ?_, fun hP => ?_⟩ - · have h2 : 2 * (B (P.root i)) (P.root j) = 0 := mul_eq_zero_of_right 2 hB - rw [two_mul_apply_root_root] at h2 - exact eq_zero_of_ne_zero_of_mul_right_eq_zero (IsRootPositive.zero_lt_apply_root j).ne' h2 - · have h2 : 2 * B (P.root i) (P.root j) = 0 := by rw [two_mul_apply_root_root, hP, zero_mul] - exact (mul_eq_zero.mp h2).resolve_left two_ne_zero - -lemma pairing_zero_iff : P.pairing i j = 0 ↔ P.pairing j i = 0 := by - rw [← apply_root_root_zero_iff B, IsRootPositive.symm P, apply_root_root_zero_iff B] - -lemma coxeterWeight_zero_iff_isOrthogonal : P.coxeterWeight i j = 0 ↔ P.IsOrthogonal i j := by +lemma apply_root_root_zero_iff : + B.form (P.root i) (P.root j) = 0 ↔ P.pairing i j = 0 := by + have _i := Algebra.charZero_of_charZero S R + calc B.form (P.root i) (P.root j) = 0 + ↔ 2 * B.form (P.root i) (P.root j) = 0 := by simp + _ ↔ P.pairing i j * B.form (P.root j) (P.root j) = 0 := by rw [B.two_mul_apply_root_root i j] + _ ↔ P.pairing i j = 0 := by simp [B.form_apply_root_ne_zero j] + +lemma pairing_zero_iff : + P.pairing i j = 0 ↔ P.pairing j i = 0 := by + rw [← apply_root_root_zero_iff B, ← B.symm.eq, RingHom.id_apply, apply_root_root_zero_iff] + +lemma coxeterWeight_zero_iff_isOrthogonal : + P.coxeterWeight i j = 0 ↔ P.IsOrthogonal i j := by rw [coxeterWeight, mul_eq_zero] refine ⟨fun h => ?_, fun h => Or.inl h.1⟩ rcases h with h | h From 415af18dac1c4cb944eded206575c5b3422a9f2e Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Tue, 4 Feb 2025 10:52:01 +0000 Subject: [PATCH 065/103] chore: rename mem_nonZeroDivisor_of_injective and comap_nonZeroDivisor_le_of_injective (#21408) --- Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean | 12 +++++++++--- Mathlib/RingTheory/Artinian/Algebra.lean | 2 +- Mathlib/RingTheory/LocalRing/Subring.lean | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean b/Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean index 0ff54a5cbf495..cb06b9531ce00 100644 --- a/Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean +++ b/Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean @@ -211,13 +211,19 @@ theorem nonZeroDivisors_le_comap_nonZeroDivisors_of_injective [NoZeroDivisors M' /-- If an element maps to a non-zero-divisor via injective homomorphism, then it is non-zero-divisor. -/ -theorem mem_nonZeroDivisor_of_injective [MonoidWithZeroHomClass F M M'] {f : F} +theorem mem_nonZeroDivisors_of_injective [MonoidWithZeroHomClass F M M'] {f : F} (hf : Function.Injective f) {a : M} (ha : f a ∈ M'⁰) : a ∈ M⁰ := fun x hx ↦ hf <| map_zero f ▸ ha (f x) (map_mul f x a ▸ map_zero f ▸ congrArg f hx) -theorem comap_nonZeroDivisor_le_of_injective [MonoidWithZeroHomClass F M M'] {f : F} +@[deprecated (since := "2025-02-03")] +alias mem_nonZeroDivisor_of_injective := mem_nonZeroDivisors_of_injective + +theorem comap_nonZeroDivisors_le_of_injective [MonoidWithZeroHomClass F M M'] {f : F} (hf : Function.Injective f) : M'⁰.comap f ≤ M⁰ := - fun _ ha ↦ mem_nonZeroDivisor_of_injective hf (Submonoid.mem_comap.mp ha) + fun _ ha ↦ mem_nonZeroDivisors_of_injective hf (Submonoid.mem_comap.mp ha) + +@[deprecated (since := "2025-02-03")] +alias comap_nonZeroDivisor_le_of_injective := comap_nonZeroDivisors_le_of_injective end MonoidWithZero diff --git a/Mathlib/RingTheory/Artinian/Algebra.lean b/Mathlib/RingTheory/Artinian/Algebra.lean index aabaf78742221..9933a7eec0933 100644 --- a/Mathlib/RingTheory/Artinian/Algebra.lean +++ b/Mathlib/RingTheory/Artinian/Algebra.lean @@ -29,7 +29,7 @@ theorem isUnit_of_isIntegral_of_nonZeroDivisor {a : A} haveI : Module.Finite R B := Algebra.finite_adjoin_simple_of_isIntegral hi haveI : IsArtinianRing B := isArtinian_of_tower R inferInstance have hinj : Function.Injective (B.subtype) := Subtype.val_injective - have hb : b ∈ B⁰ := comap_nonZeroDivisor_le_of_injective hinj ha + have hb : b ∈ B⁰ := comap_nonZeroDivisors_le_of_injective hinj ha (isUnit_of_mem_nonZeroDivisors hb).map B.subtype /-- Integral element of an algebra over artinian ring `R` is either a zero divisor or a unit. -/ diff --git a/Mathlib/RingTheory/LocalRing/Subring.lean b/Mathlib/RingTheory/LocalRing/Subring.lean index e8b5746196ff6..61bbcfe8a5c61 100644 --- a/Mathlib/RingTheory/LocalRing/Subring.lean +++ b/Mathlib/RingTheory/LocalRing/Subring.lean @@ -26,7 +26,7 @@ theorem of_injective [IsLocalRing S] {f : R →+* S} (hf : Function.Injective f) haveI : Nontrivial R := f.domain_nontrivial refine .of_is_unit_or_is_unit_of_add_one fun {a b} hab ↦ (IsLocalRing.isUnit_or_isUnit_of_add_one (map_add f .. ▸ map_one f ▸ congrArg f hab)).imp ?_ ?_ - <;> exact h _ ∘ mem_nonZeroDivisor_of_injective hf ∘ IsUnit.mem_nonZeroDivisors + <;> exact h _ ∘ mem_nonZeroDivisors_of_injective hf ∘ IsUnit.mem_nonZeroDivisors /-- If in a sub(semi)ring `R` of a local (semi)ring `S` every element is either invertible or a zero divisor, then `R` is local. -/ From 759db60c436a1912d237b3494c247df19e122f37 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 4 Feb 2025 12:18:33 +0000 Subject: [PATCH 066/103] chore: move ProofWidgets to v0.0.51 (#21416) If ProofWidgets is not pinned to a release tag, we will probably get `npm` errors when its `main` branch moves on. --- lakefile.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lakefile.lean b/lakefile.lean index d465b3738a9bd..f546b6fc4c919 100644 --- a/lakefile.lean +++ b/lakefile.lean @@ -10,7 +10,7 @@ open Lake DSL require "leanprover-community" / "batteries" @ git "main" require "leanprover-community" / "Qq" @ git "master" require "leanprover-community" / "aesop" @ git "master" -require "leanprover-community" / "proofwidgets" @ git "main" +require "leanprover-community" / "proofwidgets" @ git "v0.0.51" -- ProofWidgets should always be pinned to a specific version require "leanprover-community" / "importGraph" @ git "main" require "leanprover-community" / "LeanSearchClient" @ git "main" require "leanprover-community" / "plausible" @ git "main" From fc5672026c5fd963ad581efb1671f98a24c4d136 Mon Sep 17 00:00:00 2001 From: Bergschaf Date: Tue, 4 Feb 2025 13:07:49 +0000 Subject: [PATCH 067/103] doc(Order/Heyting/Basic): Coheyting difference is not right adjoint but left adjoint (#21418) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The difference operation of a coheyting algebra is left adjoint to `(· ⊔ a)` (not right adjoint). Source: [nlab](https://ncatlab.org/nlab/show/co-Heyting+algebra) in section 5. --- Mathlib/Order/Heyting/Basic.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Order/Heyting/Basic.lean b/Mathlib/Order/Heyting/Basic.lean index 1252f8884377c..ac82b721c02fd 100644 --- a/Mathlib/Order/Heyting/Basic.lean +++ b/Mathlib/Order/Heyting/Basic.lean @@ -132,7 +132,7 @@ class GeneralizedHeytingAlgebra (α : Type*) extends Lattice α, OrderTop α, HI le_himp_iff (a b c : α) : a ≤ b ⇨ c ↔ a ⊓ b ≤ c /-- A generalized co-Heyting algebra is a lattice with an additional binary -difference operation `\` such that `(· \ a)` is right adjoint to `(· ⊔ a)`. +difference operation `\` such that `(· \ a)` is left adjoint to `(· ⊔ a)`. This generalizes `CoheytingAlgebra` by not requiring a top element. -/ class GeneralizedCoheytingAlgebra (α : Type*) extends Lattice α, OrderBot α, SDiff α where @@ -146,7 +146,7 @@ class HeytingAlgebra (α : Type*) extends GeneralizedHeytingAlgebra α, OrderBot himp_bot (a : α) : a ⇨ ⊥ = aᶜ /-- A co-Heyting algebra is a bounded lattice with an additional binary difference operation `\` -such that `(· \ a)` is right adjoint to `(· ⊔ a)`. -/ +such that `(· \ a)` is left adjoint to `(· ⊔ a)`. -/ class CoheytingAlgebra (α : Type*) extends GeneralizedCoheytingAlgebra α, OrderTop α, HNot α where /-- `⊤ \ a` is `¬a` -/ top_sdiff (a : α) : ⊤ \ a = ¬a From cf27f6e9ab76895c6029a287c24e89ca8056ef01 Mon Sep 17 00:00:00 2001 From: Andrew Yang Date: Tue, 4 Feb 2025 14:13:48 +0000 Subject: [PATCH 068/103] =?UTF-8?q?feat(RingTheory):=20unramified=20iff=20?= =?UTF-8?q?`=CE=BA(q)/=CE=BA(p)`=20is=20separable=20and=20`pS=5Fq=20=3D=20?= =?UTF-8?q?qS=5Fq`=20(#20690)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Andrew Yang <36414270+erdOne@users.noreply.github.com> --- Mathlib.lean | 1 + Mathlib/RingTheory/Artinian/Ring.lean | 7 + Mathlib/RingTheory/EssentialFiniteness.lean | 7 + .../LocalRing/ResidueField/Basic.lean | 20 ++- Mathlib/RingTheory/Unramified/Basic.lean | 4 + Mathlib/RingTheory/Unramified/Field.lean | 2 +- Mathlib/RingTheory/Unramified/LocalRing.lean | 145 ++++++++++++++++++ Mathlib/RingTheory/Unramified/Locus.lean | 15 +- 8 files changed, 189 insertions(+), 12 deletions(-) create mode 100644 Mathlib/RingTheory/Unramified/LocalRing.lean diff --git a/Mathlib.lean b/Mathlib.lean index 67712d2f7132c..338fabb0ba3dc 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -4851,6 +4851,7 @@ import Mathlib.RingTheory.UniqueFactorizationDomain.NormalizedFactors import Mathlib.RingTheory.Unramified.Basic import Mathlib.RingTheory.Unramified.Field import Mathlib.RingTheory.Unramified.Finite +import Mathlib.RingTheory.Unramified.LocalRing import Mathlib.RingTheory.Unramified.Locus import Mathlib.RingTheory.Unramified.Pi import Mathlib.RingTheory.Valuation.AlgebraInstances diff --git a/Mathlib/RingTheory/Artinian/Ring.lean b/Mathlib/RingTheory/Artinian/Ring.lean index 455b601e23f61..fb3c9704b135e 100644 --- a/Mathlib/RingTheory/Artinian/Ring.lean +++ b/Mathlib/RingTheory/Artinian/Ring.lean @@ -85,6 +85,13 @@ theorem isNilpotent_jacobson_bot : IsNilpotent (Ideal.jacobson (⊥ : Ideal R)) refine this (mul_mem_mul (mem_span_singleton_self x) ?_) rwa [← hn (n + 1) (Nat.le_succ _)] +lemma jacobson_eq_radical (I : Ideal R) : I.jacobson = I.radical := by + simp_rw [Ideal.jacobson, Ideal.radical_eq_sInf, IsArtinianRing.isPrime_iff_isMaximal] + +theorem isNilpotent_nilradical : IsNilpotent (nilradical R) := by + rw [nilradical, ← jacobson_eq_radical] + exact isNilpotent_jacobson_bot + variable (R) in /-- Commutative artinian reduced local ring is a field. -/ theorem isField_of_isReduced_of_isLocalRing [IsReduced R] [IsLocalRing R] : IsField R := diff --git a/Mathlib/RingTheory/EssentialFiniteness.lean b/Mathlib/RingTheory/EssentialFiniteness.lean index 251fa9f3fc321..28b75f4d9f358 100644 --- a/Mathlib/RingTheory/EssentialFiniteness.lean +++ b/Mathlib/RingTheory/EssentialFiniteness.lean @@ -202,6 +202,13 @@ lemma EssFiniteType.comp_iff [EssFiniteType R S] : EssFiniteType R T ↔ EssFiniteType S T := ⟨fun _ ↦ of_comp R S T, fun _ ↦ comp R S T⟩ +instance [EssFiniteType R S] (I : Ideal S) : EssFiniteType R (S ⧸ I) := + .comp R S _ + +instance [EssFiniteType R S] (M : Submonoid S) : EssFiniteType R (Localization M) := + have : EssFiniteType S (Localization M) := .of_isLocalization _ M + .comp R S _ + end variable {R S} in diff --git a/Mathlib/RingTheory/LocalRing/ResidueField/Basic.lean b/Mathlib/RingTheory/LocalRing/ResidueField/Basic.lean index cf35586f78472..f30ff11f3f7d0 100644 --- a/Mathlib/RingTheory/LocalRing/ResidueField/Basic.lean +++ b/Mathlib/RingTheory/LocalRing/ResidueField/Basic.lean @@ -3,7 +3,7 @@ Copyright (c) 2018 Kenny Lau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, Chris Hughes, Mario Carneiro -/ -import Mathlib.LinearAlgebra.FiniteDimensional.Defs +import Mathlib.RingTheory.Finiteness.Cardinality import Mathlib.RingTheory.LocalRing.ResidueField.Defs import Mathlib.RingTheory.LocalRing.RingHom.Basic @@ -56,6 +56,10 @@ instance : IsLocalHom (IsLocalRing.residue R) := ⟨fun _ ha => Classical.not_not.mp (Ideal.Quotient.eq_zero_iff_mem.not.mp (isUnit_iff_ne_zero.mp ha))⟩ +instance {R₀} [CommRing R₀] [Algebra R₀ R] [Module.Finite R₀ R] : + Module.Finite R₀ (ResidueField R) := + .of_surjective (IsScalarTower.toAlgHom R₀ R _).toLinearMap Ideal.Quotient.mk_surjective + variable {R} namespace ResidueField @@ -167,16 +171,16 @@ noncomputable instance : Algebra (ResidueField R) (ResidueField S) := instance : IsScalarTower R (ResidueField R) (ResidueField S) := IsScalarTower.of_algebraMap_eq (congrFun rfl) -instance finiteDimensional_of_noetherian [IsNoetherian R S] : - FiniteDimensional (ResidueField R) (ResidueField S) := by - apply IsNoetherian.iff_fg.mp <| - isNoetherian_of_tower R (S := ResidueField R) (M := ResidueField S) _ - convert isNoetherian_of_surjective S (Ideal.Quotient.mkₐ R (maximalIdeal S)).toLinearMap - (LinearMap.range_eq_top.mpr Ideal.Quotient.mk_surjective) +instance finite_of_module_finite [Module.Finite R S] : + Module.Finite (ResidueField R) (ResidueField S) := + .of_restrictScalars_finite R _ _ + +@[deprecated (since := "2025-01-12")] +alias finiteDimensional_of_noetherian := finite_of_module_finite -- We want to be able to refer to `hfin` set_option linter.unusedVariables false in -lemma finite_of_finite [IsNoetherian R S] (hfin : Finite (ResidueField R)) : +lemma finite_of_finite [Module.Finite R S] (hfin : Finite (ResidueField R)) : Finite (ResidueField S) := Module.finite_of_finite (ResidueField R) end FiniteDimensional diff --git a/Mathlib/RingTheory/Unramified/Basic.lean b/Mathlib/RingTheory/Unramified/Basic.lean index 8d6c532010819..eaaa4c9bbc31e 100644 --- a/Mathlib/RingTheory/Unramified/Basic.lean +++ b/Mathlib/RingTheory/Unramified/Basic.lean @@ -255,6 +255,10 @@ theorem of_isLocalization [IsLocalization M Rₘ] : FormallyUnramified R Rₘ := ext simp +instance [FormallyUnramified R S] (M : Submonoid S) : FormallyUnramified R (Localization M) := + have := of_isLocalization (Rₘ := Localization M) M + .comp _ S _ + /-- This actually does not need the localization instance, and is stated here again for consistency. See `Algebra.FormallyUnramified.of_comp` instead. diff --git a/Mathlib/RingTheory/Unramified/Field.lean b/Mathlib/RingTheory/Unramified/Field.lean index 35b6536cfcb58..21503e28b8811 100644 --- a/Mathlib/RingTheory/Unramified/Field.lean +++ b/Mathlib/RingTheory/Unramified/Field.lean @@ -31,7 +31,7 @@ Let `K` be a field, `A` be a `K`-algebra and `L` be a field extension of `K`. universe u -variable (K A L : Type u) [Field K] [Field L] [CommRing A] [Algebra K A] [Algebra K L] +variable (K A L : Type*) [Field K] [Field L] [CommRing A] [Algebra K A] [Algebra K L] open Algebra Polynomial diff --git a/Mathlib/RingTheory/Unramified/LocalRing.lean b/Mathlib/RingTheory/Unramified/LocalRing.lean new file mode 100644 index 0000000000000..bdf51b22fd1df --- /dev/null +++ b/Mathlib/RingTheory/Unramified/LocalRing.lean @@ -0,0 +1,145 @@ +/- +Copyright (c) 2025 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.RingTheory.LocalRing.Module +import Mathlib.RingTheory.LocalRing.ResidueField.Ideal +import Mathlib.RingTheory.Unramified.Field +import Mathlib.RingTheory.Unramified.Locus + +/-! +# Unramified algebras over local rings + +## Main results +- `Algebra.FormallyUnramified.iff_map_maximalIdeal_eq`: + Let `R` be a local ring, `A` be a local `R`-algebra essentially of finite type. + Then `A/R` is unramified if and only if `κA/κR` is separable, and `m_R S = m_S`. +- `Algebra.isUnramifiedAt_iff_map_eq`: + Let `A` be an essentially of finite type `R`-algebra, `q` be a prime over `p`. + Then `A` is unramified at `p` if and only if `κ(q)/κ(p)` is separable, and `pS_q = qS_q`. +-/ + +open IsLocalRing + +namespace Algebra + +section IsLocalRing + +variable {R S : Type*} [CommRing R] [CommRing S] [Algebra R S] +variable [IsLocalRing R] [IsLocalRing S] [IsLocalHom (algebraMap R S)] + +instance : FormallyUnramified S (ResidueField S) := .quotient _ + +instance [FormallyUnramified R S] : + FormallyUnramified (ResidueField R) (ResidueField S) := + have : FormallyUnramified R (ResidueField S) := .comp _ S _ + .of_comp R _ _ + +variable [EssFiniteType R S] + +@[stacks 00UW "(2)"] +instance [FormallyUnramified R S] : + Module.Finite (ResidueField R) (ResidueField S) := + have : EssFiniteType R (ResidueField S) := .comp _ S _ + have : EssFiniteType (ResidueField R) (ResidueField S) := .of_comp R _ _ + FormallyUnramified.finite_of_free _ _ + +@[stacks 00UW "(2)"] +instance [FormallyUnramified R S] : + Algebra.IsSeparable (ResidueField R) (ResidueField S) := + FormallyUnramified.isSeparable _ _ + +lemma FormallyUnramified.isField_quotient_map_maximalIdeal [FormallyUnramified R S] : + IsField (S ⧸ (maximalIdeal R).map (algebraMap R S)) := by + let mR := (maximalIdeal R).map (algebraMap R S) + have hmR : mR ≤ maximalIdeal S := ((local_hom_TFAE (algebraMap R S)).out 0 2 rfl rfl).mp ‹_› + letI : Algebra (ResidueField R) (S ⧸ mR) := inferInstanceAs (Algebra (R ⧸ _) _) + have : IsScalarTower R (ResidueField R) (S ⧸ mR) := inferInstanceAs (IsScalarTower R (R ⧸ _) _) + have : FormallyUnramified (ResidueField R) (S ⧸ mR) := .of_comp R _ _ + have : EssFiniteType (ResidueField R) (S ⧸ mR) := .of_comp R _ _ + have : Module.Finite (ResidueField R) (S ⧸ mR) := FormallyUnramified.finite_of_free _ _ + have : IsReduced (S ⧸ mR) := FormallyUnramified.isReduced_of_field (ResidueField R) (S ⧸ mR) + have : IsArtinianRing (S ⧸ mR) := isArtinian_of_tower (ResidueField R) inferInstance + have : Nontrivial (S ⧸ mR) := Ideal.Quotient.nontrivial fun e ↦ + (maximalIdeal.isMaximal S).ne_top (top_le_iff.mp <| e.symm.trans_le hmR) + have : IsLocalRing (S ⧸ mR) := .of_surjective' _ Ideal.Quotient.mk_surjective + have : maximalIdeal (S ⧸ mR) = ⊥ := by + rw [← jacobson_eq_maximalIdeal _ bot_ne_top, IsArtinianRing.jacobson_eq_radical, + ← Ideal.zero_eq_bot, ← nilradical, nilradical_eq_zero] + rwa [← isField_iff_maximalIdeal_eq] at this + +@[stacks 00UW "(1)"] +lemma FormallyUnramified.map_maximalIdeal [FormallyUnramified R S] : + (maximalIdeal R).map (algebraMap R S) = maximalIdeal S := by + apply eq_maximalIdeal + rw [Ideal.Quotient.maximal_ideal_iff_isField_quotient] + exact isField_quotient_map_maximalIdeal + +@[stacks 02FM] +lemma FormallyUnramified.of_map_maximalIdeal + [Algebra.IsSeparable (ResidueField R) (ResidueField S)] + (H : (maximalIdeal R).map (algebraMap R S) = maximalIdeal S) : + Algebra.FormallyUnramified R S := by + constructor + have : FormallyUnramified (ResidueField R) (ResidueField S) := .of_isSeparable _ _ + have : FormallyUnramified R (ResidueField S) := .comp _ (ResidueField R) _ + rw [← subsingleton_tensorProduct (R := S)] + refine subsingleton_of_forall_eq 0 fun x ↦ ?_ + obtain ⟨x, rfl⟩ := (KaehlerDifferential.exact_kerCotangentToTensor_mapBaseChange R S + (ResidueField S) Ideal.Quotient.mk_surjective x).mp (Subsingleton.elim _ _) + obtain ⟨⟨x, hx⟩, rfl⟩ := Ideal.toCotangent_surjective _ x + simp only [KaehlerDifferential.kerCotangentToTensor_toCotangent] + replace hx : x ∈ Ideal.map (algebraMap R S) (maximalIdeal R) := by simpa [H] using hx + induction hx using Submodule.span_induction with + | zero => simp + | mem x h => obtain ⟨x, hx, rfl⟩ := h; simp + | add x y hx hy _ _ => simp [*, TensorProduct.tmul_add] + | smul a x hx _ => + have : residue S x = 0 := by rwa [residue_eq_zero_iff, ← H] + simp [*, TensorProduct.tmul_add, TensorProduct.smul_tmul', ← Algebra.algebraMap_eq_smul_one] + +lemma FormallyUnramified.iff_map_maximalIdeal_eq : + Algebra.FormallyUnramified R S ↔ + Algebra.IsSeparable (ResidueField R) (ResidueField S) ∧ + (maximalIdeal R).map (algebraMap R S) = maximalIdeal S := + ⟨fun _ ↦ ⟨inferInstance, map_maximalIdeal⟩, fun ⟨_, e⟩ ↦ of_map_maximalIdeal e⟩ + +end IsLocalRing + +section IsUnramifiedAt + +universe u + +variable (R : Type u) {S : Type u} [CommRing R] [CommRing S] [Algebra R S] + +noncomputable +instance (p : Ideal R) [p.IsPrime] (q : Ideal S) [q.IsPrime] [q.LiesOver p] : + Algebra p.ResidueField q.ResidueField := + (Ideal.ResidueField.mapₐ p q Ideal.LiesOver.over).toAlgebra + +/-- Let `A` be an essentially of finite type `R`-algebra, `q` be a prime over `p`. +Then `A` is unramified at `p` if and only if `κ(q)/κ(p)` is separable, and `pS_q = qS_q`. -/ +lemma isUnramifiedAt_iff_map_eq [EssFiniteType R S] + (p : Ideal R) [p.IsPrime] (q : Ideal S) [q.IsPrime] [q.LiesOver p] : + Algebra.IsUnramifiedAt R q ↔ + Algebra.IsSeparable p.ResidueField q.ResidueField ∧ + p.map (algebraMap R (Localization.AtPrime q)) = maximalIdeal _ := by + letI : Algebra (Localization.AtPrime p) (Localization.AtPrime q) := + (Localization.localRingHom p q (algebraMap R S) Ideal.LiesOver.over).toAlgebra + have : IsScalarTower R (Localization.AtPrime p) (Localization.AtPrime q) := .of_algebraMap_eq + fun x ↦ (Localization.localRingHom_to_map p q (algebraMap R S) Ideal.LiesOver.over x).symm + letI : IsLocalHom (algebraMap (Localization.AtPrime p) (Localization.AtPrime q)) := + Localization.isLocalHom_localRingHom _ _ _ Ideal.LiesOver.over + have : EssFiniteType (Localization.AtPrime p) (Localization.AtPrime q) := .of_comp R _ _ + trans Algebra.FormallyUnramified (Localization.AtPrime p) (Localization.AtPrime q) + · exact ⟨fun _ ↦ .of_comp R _ _, fun _ ↦ .comp _ (Localization.AtPrime p) _⟩ + rw [FormallyUnramified.iff_map_maximalIdeal_eq] + congr! + rw [RingHom.algebraMap_toAlgebra, ← Localization.AtPrime.map_eq_maximalIdeal, + Ideal.map_map, Localization.localRingHom, + IsLocalization.map_comp, ← IsScalarTower.algebraMap_eq] + +end IsUnramifiedAt + +end Algebra diff --git a/Mathlib/RingTheory/Unramified/Locus.lean b/Mathlib/RingTheory/Unramified/Locus.lean index 44a5e740a4e0b..caf354a401e6d 100644 --- a/Mathlib/RingTheory/Unramified/Locus.lean +++ b/Mathlib/RingTheory/Unramified/Locus.lean @@ -26,10 +26,19 @@ variable (R A : Type u) [CommRing R] [CommRing A] [Algebra R A] namespace Algebra -/-- `Algebra.unramifiedLocus R A` is the set of primes `p` of `A` -such that `Aₚ` is formally unramified over `R`. -/ +variable {A} in +/-- We say that an `R`-algebra `A` is unramified at a prime `q` of `A` +if `A_q` is formally unramified over `R`. + +If `A` is of finite type over `R` and `q` is lying over `p`, then this is equivalent to +`κ(q)/κ(p)` being separable and `pA_q = qA_q`. +See `Algebra.isUnramifiedAt_iff_map_eq` in `RingTheory.Unramified.LocalRing` -/ +abbrev IsUnramifiedAt (q : Ideal A) [q.IsPrime] : Prop := + FormallyUnramified R (Localization.AtPrime q) + +/-- `Algebra.unramifiedLocus R A` is the set of primes `p` of `A` that are unramified. -/ def unramifiedLocus : Set (PrimeSpectrum A) := - { p | Algebra.FormallyUnramified R (Localization.AtPrime p.asIdeal) } + { p | IsUnramifiedAt R p.asIdeal } variable {R A} From 86986e5d50e5ce2e00b5c56b12dfbf14b5c2c96b Mon Sep 17 00:00:00 2001 From: Anne Baanen Date: Tue, 4 Feb 2025 15:00:04 +0000 Subject: [PATCH 069/103] chore(Algebra/Category/ModuleCat): delete `ModuleCat.hasForgetModuleCat` (#21425) I was looking through the remaining `HasForget` instances and noticed we forgot to delete this one when switching to `ConcreteCategory`. We can simply delete it. --- Mathlib/Algebra/Category/ModuleCat/Basic.lean | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Mathlib/Algebra/Category/ModuleCat/Basic.lean b/Mathlib/Algebra/Category/ModuleCat/Basic.lean index cf31eaa4d1665..0e4f8d3a91ed0 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Basic.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Basic.lean @@ -202,12 +202,6 @@ end instance : Inhabited (ModuleCat R) := ⟨of R R⟩ -instance moduleHasForget : HasForget.{v} (ModuleCat.{v} R) where - forget := - { obj := fun R => R - map := fun f => f.hom } - forget_faithful := ⟨fun h => by ext x; simpa using congrFun h x⟩ - /- Not a `@[simp]` lemma since it will rewrite the (co)domain of maps and cause definitional equality issues. -/ lemma forget_obj {M : ModuleCat.{v} R} : (forget (ModuleCat.{v} R)).obj M = M := rfl From 1cca6b8e67f4d0cf8380a38f2262b36d17676f87 Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Tue, 4 Feb 2025 15:13:04 +0000 Subject: [PATCH 070/103] refactor: introduce `Ideal.IsTwoSided` class for quotients of noncommutative rings (#17930) --- Mathlib/Algebra/Algebra/Operations.lean | 7 + Mathlib/Algebra/GroupWithZero/Basic.lean | 9 + Mathlib/Algebra/Module/LinearMap/Defs.lean | 2 + Mathlib/Algebra/Module/Torsion.lean | 119 +++++++--- Mathlib/Algebra/RingQuot.lean | 5 +- Mathlib/AlgebraicGeometry/PointsPi.lean | 2 +- Mathlib/FieldTheory/LinearDisjoint.lean | 3 +- Mathlib/LinearAlgebra/Quotient/Defs.lean | 4 + Mathlib/NumberTheory/Padics/RingHoms.lean | 6 +- .../RingTheory/AdicCompletion/Algebra.lean | 2 +- Mathlib/RingTheory/Ideal/Basic.lean | 3 + Mathlib/RingTheory/Ideal/Colon.lean | 44 ++-- Mathlib/RingTheory/Ideal/Defs.lean | 34 ++- Mathlib/RingTheory/Ideal/Lattice.lean | 8 + Mathlib/RingTheory/Ideal/Maps.lean | 17 ++ Mathlib/RingTheory/Ideal/Maximal.lean | 5 +- Mathlib/RingTheory/Ideal/Operations.lean | 72 ++++-- Mathlib/RingTheory/Ideal/Quotient/Basic.lean | 109 +++++---- Mathlib/RingTheory/Ideal/Quotient/Defs.lean | 81 ++++--- .../RingTheory/Ideal/Quotient/Nilpotent.lean | 2 +- .../RingTheory/Ideal/Quotient/Operations.lean | 218 ++++++++++-------- Mathlib/RingTheory/Jacobson/Ring.lean | 3 +- Mathlib/RingTheory/Polynomial/Quotient.lean | 2 +- docs/overview.yaml | 2 +- docs/undergrad.yaml | 2 +- 25 files changed, 465 insertions(+), 296 deletions(-) diff --git a/Mathlib/Algebra/Algebra/Operations.lean b/Mathlib/Algebra/Algebra/Operations.lean index e5fb04b5435a7..95a0f2a818196 100644 --- a/Mathlib/Algebra/Algebra/Operations.lean +++ b/Mathlib/Algebra/Algebra/Operations.lean @@ -300,9 +300,16 @@ protected theorem pow_zero : M ^ 0 = 1 := rfl protected theorem pow_succ {n : ℕ} : M ^ (n + 1) = M ^ n * M := rfl +protected theorem pow_add {m n : ℕ} (h : n ≠ 0) : M ^ (m + n) = M ^ m * M ^ n := + npowRec_add m n h _ M.one_mul + protected theorem pow_one : M ^ 1 = M := by rw [Submodule.pow_succ, Submodule.pow_zero, Submodule.one_mul] +/-- `Submodule.pow_succ` with the right hand side commuted. -/ +protected theorem pow_succ' {n : ℕ} (h : n ≠ 0) : M ^ (n + 1) = M * M ^ n := by + rw [add_comm, M.pow_add h, Submodule.pow_one] + theorem pow_toAddSubmonoid {n : ℕ} (h : n ≠ 0) : (M ^ n).toAddSubmonoid = M.toAddSubmonoid ^ n := by induction n with | zero => exact (h rfl).elim diff --git a/Mathlib/Algebra/GroupWithZero/Basic.lean b/Mathlib/Algebra/GroupWithZero/Basic.lean index 936f7cd3c7d9e..f45f36352d396 100644 --- a/Mathlib/Algebra/GroupWithZero/Basic.lean +++ b/Mathlib/Algebra/GroupWithZero/Basic.lean @@ -185,6 +185,15 @@ lemma sq_eq_zero_iff : a ^ 2 = 0 ↔ a = 0 := pow_eq_zero_iff two_ne_zero @[simp] lemma pow_eq_zero_iff' [Nontrivial M₀] : a ^ n = 0 ↔ a = 0 ∧ n ≠ 0 := by obtain rfl | hn := eq_or_ne n 0 <;> simp [*] +theorem exists_right_inv_of_exists_left_inv {α} [MonoidWithZero α] + (h : ∀ a : α, a ≠ 0 → ∃ b : α, b * a = 1) {a : α} (ha : a ≠ 0) : ∃ b : α, a * b = 1 := by + obtain _ | _ := subsingleton_or_nontrivial α + · exact ⟨a, Subsingleton.elim _ _⟩ + obtain ⟨b, hb⟩ := h a ha + obtain ⟨c, hc⟩ := h b (left_ne_zero_of_mul <| hb.trans_ne one_ne_zero) + refine ⟨b, ?_⟩ + conv_lhs => rw [← one_mul (a * b), ← hc, mul_assoc, ← mul_assoc b, hb, one_mul, hc] + end MonoidWithZero section CancelMonoidWithZero diff --git a/Mathlib/Algebra/Module/LinearMap/Defs.lean b/Mathlib/Algebra/Module/LinearMap/Defs.lean index c99d8725f1947..dc728bfb3ed8c 100644 --- a/Mathlib/Algebra/Module/LinearMap/Defs.lean +++ b/Mathlib/Algebra/Module/LinearMap/Defs.lean @@ -449,6 +449,8 @@ def _root_.RingHom.toSemilinearMap (f : R →+* S) : R →ₛₗ[f] S := { f with map_smul' := f.map_mul } +@[simp] theorem _root_.RingHom.coe_toSemilinearMap (f : R →+* S) : ⇑f.toSemilinearMap = f := rfl + section variable [Semiring R₁] [Semiring R₂] [Semiring R₃] diff --git a/Mathlib/Algebra/Module/Torsion.lean b/Mathlib/Algebra/Module/Torsion.lean index 099a6f0601239..cd72dfd24e03b 100644 --- a/Mathlib/Algebra/Module/Torsion.lean +++ b/Mathlib/Algebra/Module/Torsion.lean @@ -144,10 +144,11 @@ open nonZeroDivisors section Defs -variable (R M : Type*) [CommSemiring R] [AddCommMonoid M] [Module R M] - namespace Submodule +variable (R M : Type*) [CommSemiring R] [AddCommMonoid M] [Module R M] + +-- TODO: generalize to `Submodule S M` with `SMulCommClass R S M`. /-- The `a`-torsion submodule for `a` in `R`, containing all elements `x` of `M` such that `a • x = 0`. -/ @[simps!] @@ -191,6 +192,8 @@ end Submodule namespace Module +variable (R M : Type*) [Semiring R] [AddCommMonoid M] [Module R M] + /-- An `a`-torsion module is a module where every element is `a`-torsion. -/ abbrev IsTorsionBy (a : R) := ∀ ⦃x : M⦄, a • x = 0 @@ -208,9 +211,18 @@ abbrev IsTorsion' (S : Type*) [SMul S M] := abbrev IsTorsion := ∀ ⦃x : M⦄, ∃ a : R⁰, a • x = 0 -theorem isTorsionBySet_annihilator : IsTorsionBySet R M (Module.annihilator R M) := +theorem isTorsionBySet_annihilator : IsTorsionBySet R M (annihilator R M) := fun _ r ↦ Module.mem_annihilator.mp r.2 _ +theorem isTorsionBy_iff_mem_annihilator {a : R} : + IsTorsionBy R M a ↔ a ∈ annihilator R M := by + rw [IsTorsionBy, mem_annihilator] + +theorem isTorsionBySet_iff_subset_annihilator {s : Set R} : + IsTorsionBySet R M s ↔ s ⊆ annihilator R M := by + simp_rw [IsTorsionBySet, Set.subset_def, SetLike.mem_coe, mem_annihilator] + rw [forall_comm, SetCoe.forall] + end Module end Defs @@ -224,10 +236,10 @@ variable {R M : Type*} section -variable [CommSemiring R] [AddCommMonoid M] [Module R M] (s : Set R) (a : R) - namespace Submodule +variable [CommSemiring R] [AddCommMonoid M] [Module R M] (s : Set R) (a : R) + @[simp] theorem smul_torsionBy (x : torsionBy R M a) : a • x = 0 := Subtype.ext x.prop @@ -292,13 +304,32 @@ open Submodule namespace Module +variable [Semiring R] [AddCommMonoid M] [Module R M] (s : Set R) (a : R) + +theorem isTorsionBySet_of_subset {s t : Set R} (h : s ⊆ t) + (ht : IsTorsionBySet R M t) : IsTorsionBySet R M s := + fun m r ↦ @ht m ⟨r, h r.2⟩ + @[simp] theorem isTorsionBySet_singleton_iff : IsTorsionBySet R M {a} ↔ IsTorsionBy R M a := by refine ⟨fun h x => @h _ ⟨_, Set.mem_singleton _⟩, fun h x => ?_⟩ rintro ⟨b, rfl : b = a⟩; exact @h _ +theorem isTorsionBySet_iff_is_torsion_by_span : + IsTorsionBySet R M s ↔ IsTorsionBySet R M (Ideal.span s) := by + simpa only [isTorsionBySet_iff_subset_annihilator] using Ideal.span_le.symm + +theorem isTorsionBySet_span_singleton_iff : IsTorsionBySet R M (R ∙ a) ↔ IsTorsionBy R M a := + (isTorsionBySet_iff_is_torsion_by_span _).symm.trans <| isTorsionBySet_singleton_iff _ + +end Module + +namespace Module + +variable [CommSemiring R] [AddCommMonoid M] [Module R M] (s : Set R) (a : R) + theorem isTorsionBySet_iff_torsionBySet_eq_top : - IsTorsionBySet R M s ↔ Submodule.torsionBySet R M s = ⊤ := + IsTorsionBySet R M s ↔ torsionBySet R M s = ⊤ := ⟨fun h => eq_top_iff.mpr fun _ _ => (mem_torsionBySet_iff _ _).mpr <| @h _, fun h x => by rw [← mem_torsionBySet_iff, h] trivial⟩ @@ -308,14 +339,6 @@ theorem isTorsionBy_iff_torsionBy_eq_top : IsTorsionBy R M a ↔ torsionBy R M a rw [← torsionBySet_singleton_eq, ← isTorsionBySet_singleton_iff, isTorsionBySet_iff_torsionBySet_eq_top] -theorem isTorsionBySet_iff_is_torsion_by_span : - IsTorsionBySet R M s ↔ IsTorsionBySet R M (Ideal.span s) := by - rw [isTorsionBySet_iff_torsionBySet_eq_top, isTorsionBySet_iff_torsionBySet_eq_top, - torsionBySet_eq_torsionBySet_span] - -theorem isTorsionBySet_span_singleton_iff : IsTorsionBySet R M (R ∙ a) ↔ IsTorsionBy R M a := - (isTorsionBySet_iff_is_torsion_by_span _).symm.trans <| isTorsionBySet_singleton_iff _ - theorem isTorsionBySet_iff_subseteq_ker_lsmul : IsTorsionBySet R M s ↔ s ⊆ LinearMap.ker (LinearMap.lsmul R M) where mp h r hr := LinearMap.mem_ker.mpr <| LinearMap.ext fun x => @h x ⟨r, hr⟩ @@ -331,6 +354,8 @@ namespace Submodule open Module +variable [CommSemiring R] [AddCommMonoid M] [Module R M] (s : Set R) (a : R) + theorem torsionBySet_isTorsionBySet : IsTorsionBySet R (torsionBySet R M s) s := fun ⟨_, hx⟩ a => Subtype.ext <| (mem_torsionBySet_iff _ _).mp hx a @@ -437,10 +462,9 @@ end section NeedsGroup -variable [CommRing R] [AddCommGroup M] [Module R M] - namespace Submodule +variable [CommRing R] [AddCommGroup M] [Module R M] variable {ι : Type*} [DecidableEq ι] {S : Finset ι} /-- If the `p i` are pairwise coprime, a `⨅ i, p i`-torsion module is the internal direct sum of @@ -473,43 +497,54 @@ end Submodule namespace Module +variable [Ring R] [AddCommGroup M] [Module R M] variable {I : Ideal R} {r : R} /-- can't be an instance because `hM` can't be inferred -/ def IsTorsionBySet.hasSMul (hM : IsTorsionBySet R M I) : SMul (R ⧸ I) M where - smul b x := I.liftQ (LinearMap.lsmul R M) - ((isTorsionBySet_iff_subseteq_ker_lsmul _).mp hM) b x + smul b := QuotientAddGroup.lift I.toAddSubgroup (smulAddHom R M) + (by rwa [isTorsionBySet_iff_subset_annihilator] at hM) b /-- can't be an instance because `hM` can't be inferred -/ abbrev IsTorsionBy.hasSMul (hM : IsTorsionBy R M r) : SMul (R ⧸ Ideal.span {r}) M := ((isTorsionBySet_span_singleton_iff r).mpr hM).hasSMul @[simp] -theorem IsTorsionBySet.mk_smul (hM : IsTorsionBySet R M I) (b : R) (x : M) : +theorem IsTorsionBySet.mk_smul [I.IsTwoSided] (hM : IsTorsionBySet R M I) (b : R) (x : M) : haveI := hM.hasSMul Ideal.Quotient.mk I b • x = b • x := rfl @[simp] -theorem IsTorsionBy.mk_smul (hM : IsTorsionBy R M r) (b : R) (x : M) : +theorem IsTorsionBy.mk_smul [(Ideal.span {r}).IsTwoSided] (hM : IsTorsionBy R M r) (b : R) (x : M) : haveI := hM.hasSMul Ideal.Quotient.mk (Ideal.span {r}) b • x = b • x := rfl /-- An `(R ⧸ I)`-module is an `R`-module which `IsTorsionBySet R M I`. -/ -def IsTorsionBySet.module (hM : IsTorsionBySet R M I) : Module (R ⧸ I) M := +def IsTorsionBySet.module [I.IsTwoSided] (hM : IsTorsionBySet R M I) : Module (R ⧸ I) M := letI := hM.hasSMul; I.mkQ_surjective.moduleLeft _ (IsTorsionBySet.mk_smul hM) -instance IsTorsionBySet.isScalarTower (hM : IsTorsionBySet R M I) +instance IsTorsionBySet.isScalarTower [I.IsTwoSided] (hM : IsTorsionBySet R M I) {S : Type*} [SMul S R] [SMul S M] [IsScalarTower S R M] [IsScalarTower S R R] : @IsScalarTower S (R ⧸ I) M _ (IsTorsionBySet.module hM).toSMul _ := -- Porting note: still needed to be fed the Module R / I M instance @IsScalarTower.mk S (R ⧸ I) M _ (IsTorsionBySet.module hM).toSMul _ (fun b d x => Quotient.inductionOn' d fun c => (smul_assoc b c x :)) +/-- If a `R`-module `M` is annihilated by a two-sided ideal `I`, then the identity is a semilinear +map from the `R`-module `M` to the `R ⧸ I`-module `M`. -/ +def IsTorsionBySet.semilinearMap [I.IsTwoSided] (hM : IsTorsionBySet R M I) : + let _ := hM.module; M →ₛₗ[Ideal.Quotient.mk I] M := + let _ := hM.module + { toFun := id + map_add' := fun _ _ ↦ rfl + map_smul' := fun _ _ ↦ rfl } + /-- An `(R ⧸ Ideal.span {r})`-module is an `R`-module for which `IsTorsionBy R M r`. -/ -abbrev IsTorsionBy.module (hM : IsTorsionBy R M r) : Module (R ⧸ Ideal.span {r}) M := - ((isTorsionBySet_span_singleton_iff r).mpr hM).module +abbrev IsTorsionBy.module [h : (Ideal.span {r}).IsTwoSided] (hM : IsTorsionBy R M r) : + Module (R ⧸ Ideal.span {r}) M := by + rw [Ideal.span] at h; exact ((isTorsionBySet_span_singleton_iff r).mpr hM).module /-- Any module is also a module over the quotient of the ring by the annihilator. Not an instance because it causes synthesis failures / timeouts. -/ @@ -544,25 +579,14 @@ lemma isTorsionBySet_quotient_set_smul : (isTorsionBySet_quotient_iff _ _).mpr fun _ _ h => mem_set_smul_of_mem_mem h mem_top -lemma isTorsionBy_quotient_element_smul : - IsTorsionBy R (M⧸r • (⊤ : Submodule R M)) r := - (isTorsionBy_quotient_iff _ _).mpr (smul_mem_pointwise_smul · r ⊤ ⟨⟩) - lemma isTorsionBySet_quotient_ideal_smul : IsTorsionBySet R (M⧸I • (⊤ : Submodule R M)) I := (isTorsionBySet_quotient_iff _ _).mpr fun _ _ h => smul_mem_smul h ⟨⟩ -instance : Module (R ⧸ Ideal.span s) (M ⧸ s • (⊤ : Submodule R M)) := - ((isTorsionBySet_iff_is_torsion_by_span s).mp - (isTorsionBySet_quotient_set_smul M s)).module - -instance : Module (R ⧸ I) (M ⧸ I • (⊤ : Submodule R M)) := +instance [I.IsTwoSided] : Module (R ⧸ I) (M ⧸ I • (⊤ : Submodule R M)) := (isTorsionBySet_quotient_ideal_smul M I).module -instance : Module (R ⧸ Ideal.span {r}) (M ⧸ r • (⊤ : Submodule R M)) := - (isTorsionBy_quotient_element_smul M r).module - -lemma Quotient.mk_smul_mk (r : R) (m : M) : +lemma Quotient.mk_smul_mk [I.IsTwoSided] (r : R) (m : M) : Ideal.Quotient.mk I r • Submodule.Quotient.mk (p := (I • ⊤ : Submodule R M)) m = Submodule.Quotient.mk (p := (I • ⊤ : Submodule R M)) (r • m) := @@ -570,8 +594,29 @@ lemma Quotient.mk_smul_mk (r : R) (m : M) : end Module +namespace Module + +variable (M) [CommRing R] [AddCommGroup M] [Module R M] (s : Set R) (r : R) + +open Pointwise + +lemma isTorsionBy_quotient_element_smul : + IsTorsionBy R (M⧸r • (⊤ : Submodule R M)) r := + (isTorsionBy_quotient_iff _ _).mpr (Submodule.smul_mem_pointwise_smul · r ⊤ ⟨⟩) + +instance : Module (R ⧸ Ideal.span s) (M ⧸ s • (⊤ : Submodule R M)) := + ((isTorsionBySet_iff_is_torsion_by_span s).mp + (isTorsionBySet_quotient_set_smul M s)).module + +instance : Module (R ⧸ Ideal.span {r}) (M ⧸ r • (⊤ : Submodule R M)) := + (isTorsionBy_quotient_element_smul M r).module + +end Module + namespace Submodule +variable [CommRing R] [AddCommGroup M] [Module R M] + instance (I : Ideal R) : Module (R ⧸ I) (torsionBySet R M I) := -- Porting note: times out without the (R := R) Module.IsTorsionBySet.module <| torsionBySet_isTorsionBySet (R := R) I diff --git a/Mathlib/Algebra/RingQuot.lean b/Mathlib/Algebra/RingQuot.lean index 1a801894c1ef2..19eff76956afa 100644 --- a/Mathlib/Algebra/RingQuot.lean +++ b/Mathlib/Algebra/RingQuot.lean @@ -9,10 +9,7 @@ import Mathlib.RingTheory.Ideal.Quotient.Defs import Mathlib.RingTheory.Ideal.Span /-! -# Quotients of non-commutative rings - -Unfortunately, ideals have only been developed in the commutative case as `Ideal`, -and it's not immediately clear how one should formalise ideals in the non-commutative case. +# Quotients of semirings In this file, we directly define the quotient of a semiring by any relation, by building a bigger relation that represents the ideal generated by that relation. diff --git a/Mathlib/AlgebraicGeometry/PointsPi.lean b/Mathlib/AlgebraicGeometry/PointsPi.lean index a9ebeba3e62e1..0e98f659ada52 100644 --- a/Mathlib/AlgebraicGeometry/PointsPi.lean +++ b/Mathlib/AlgebraicGeometry/PointsPi.lean @@ -83,7 +83,7 @@ lemma isIso_of_comp_eq_sigmaSpec {V : Scheme} infer_instance obtain ⟨I, e, rfl⟩ := IsClosedImmersion.Spec_iff.mp this obtain rfl := eq_bot_of_comp_quotientMk_eq_sigmaSpec R I (f ≫ e.hom) (by rwa [Category.assoc]) - show IsIso (e.hom ≫ Spec.map (RingEquiv.quotientBot _).toCommRingCatIso.inv) + convert_to IsIso (e.hom ≫ Spec.map (RingEquiv.quotientBot _).toCommRingCatIso.inv) infer_instance variable (X : Scheme) diff --git a/Mathlib/FieldTheory/LinearDisjoint.lean b/Mathlib/FieldTheory/LinearDisjoint.lean index 47fa1b206ee9b..b89a101d64350 100644 --- a/Mathlib/FieldTheory/LinearDisjoint.lean +++ b/Mathlib/FieldTheory/LinearDisjoint.lean @@ -445,7 +445,8 @@ theorem isField_of_forall (A : Type v) [Field A] (B : Type w) [Field B] have hi : i = (fa.range.mulMap fb.range).comp (Algebra.TensorProduct.congr (AlgEquiv.ofInjective fa fa.injective) (AlgEquiv.ofInjective fb fb.injective)) := by ext <;> simp [fa, fb] - replace H : Function.Injective i := by simpa [hi] + replace H : Function.Injective i := by simpa only + [hi, AlgHom.coe_comp, AlgHom.coe_coe, EquivLike.injective_comp, fa, this, K, fb] change Function.Injective (Ideal.Quotient.mk M) at H rwa [RingHom.injective_iff_ker_eq_bot, Ideal.mk_ker] at H diff --git a/Mathlib/LinearAlgebra/Quotient/Defs.lean b/Mathlib/LinearAlgebra/Quotient/Defs.lean index fc58414515648..1845a7f5de2e3 100644 --- a/Mathlib/LinearAlgebra/Quotient/Defs.lean +++ b/Mathlib/LinearAlgebra/Quotient/Defs.lean @@ -107,6 +107,10 @@ theorem mk_sub : (mk (x - y) : M ⧸ p) = mk x - mk y := protected nonrec lemma «forall» {P : M ⧸ p → Prop} : (∀ a, P a) ↔ ∀ a, P (mk a) := Quotient.forall +theorem subsingleton_iff : Subsingleton (M ⧸ p) ↔ ∀ x : M, x ∈ p := by + rw [subsingleton_iff_forall_eq 0, Submodule.Quotient.forall] + simp_rw [Submodule.Quotient.mk_eq_zero] + section SMul variable {S : Type*} [SMul S R] [SMul S M] [IsScalarTower S R M] (P : Submodule R M) diff --git a/Mathlib/NumberTheory/Padics/RingHoms.lean b/Mathlib/NumberTheory/Padics/RingHoms.lean index 7482f2835cb49..a4bc7e4bf2fd8 100644 --- a/Mathlib/NumberTheory/Padics/RingHoms.lean +++ b/Mathlib/NumberTheory/Padics/RingHoms.lean @@ -288,9 +288,9 @@ theorem ker_toZMod : RingHom.ker (toZMod : ℤ_[p] →+* ZMod p) = maximalIdeal · apply sub_zmodRepr_mem /-- The equivalence between the residue field of the `p`-adic integers and `ℤ/pℤ` -/ -def residueField : IsLocalRing.ResidueField ℤ_[p] ≃+* ZMod p := by - exact_mod_cast (@PadicInt.ker_toZMod p _) ▸ RingHom.quotientKerEquivOfSurjective - (ZMod.ringHom_surjective PadicInt.toZMod) +def residueField : IsLocalRing.ResidueField ℤ_[p] ≃+* ZMod p := + (Ideal.quotEquivOfEq PadicInt.ker_toZMod.symm).trans <| + RingHom.quotientKerEquivOfSurjective (ZMod.ringHom_surjective PadicInt.toZMod) open scoped Classical in /-- `appr n x` gives a value `v : ℕ` such that `x` and `↑v : ℤ_p` are congruent mod `p^n`. diff --git a/Mathlib/RingTheory/AdicCompletion/Algebra.lean b/Mathlib/RingTheory/AdicCompletion/Algebra.lean index 732a04c01ad0d..c7f7c8f5bf96f 100644 --- a/Mathlib/RingTheory/AdicCompletion/Algebra.lean +++ b/Mathlib/RingTheory/AdicCompletion/Algebra.lean @@ -187,7 +187,7 @@ theorem evalₐ_mkₐ (n : ℕ) (x : AdicCauchySequence I R) : theorem Ideal.mk_eq_mk {m n : ℕ} (hmn : m ≤ n) (r : AdicCauchySequence I R) : Ideal.Quotient.mk (I ^ m) (r.val n) = Ideal.Quotient.mk (I ^ m) (r.val m) := by have h : I ^ m = I ^ m • ⊤ := by simp - rw [h, ← Ideal.Quotient.mk_eq_mk, ← Ideal.Quotient.mk_eq_mk] + rw [← Ideal.Quotient.mk_eq_mk, ← Ideal.Quotient.mk_eq_mk, h] exact (r.property hmn).symm theorem smul_mk {m n : ℕ} (hmn : m ≤ n) (r : AdicCauchySequence I R) diff --git a/Mathlib/RingTheory/Ideal/Basic.lean b/Mathlib/RingTheory/Ideal/Basic.lean index bb6c5745b3faf..5b5ae53a65a30 100644 --- a/Mathlib/RingTheory/Ideal/Basic.lean +++ b/Mathlib/RingTheory/Ideal/Basic.lean @@ -51,6 +51,9 @@ def pi : Ideal (Π i, α i) where theorem mem_pi (x : Π i, α i) : x ∈ pi I ↔ ∀ i, x i ∈ I i := Iff.rfl +instance (priority := low) [∀ i, (I i).IsTwoSided] : (pi I).IsTwoSided := + ⟨fun _b hb i ↦ mul_mem_right _ _ (hb i)⟩ + end Pi section Commute diff --git a/Mathlib/RingTheory/Ideal/Colon.lean b/Mathlib/RingTheory/Ideal/Colon.lean index 37b90aaaf0c8f..552648c41e8b2 100644 --- a/Mathlib/RingTheory/Ideal/Colon.lean +++ b/Mathlib/RingTheory/Ideal/Colon.lean @@ -23,7 +23,7 @@ variable {R M M' F G : Type*} section Semiring variable [Semiring R] [AddCommMonoid M] [Module R M] -variable {N P : Submodule R M} +variable {N N₁ N₂ P P₁ P₂ : Submodule R M} /-- `N.colon P` is the ideal of all elements `r : R` such that `r • P ⊆ N`. -/ def colon (N P : Submodule R M) : Ideal R where @@ -38,18 +38,13 @@ def colon (N P : Submodule R M) : Ideal R where theorem mem_colon {r} : r ∈ N.colon P ↔ ∀ p ∈ P, r • p ∈ N := Set.smul_set_subset_iff -end Semiring - -section CommSemiring - -variable [CommSemiring R] [AddCommMonoid M] [Module R M] -variable {N N₁ N₂ P P₁ P₂ : Submodule R M} - -theorem mem_colon' {r} : r ∈ N.colon P ↔ P ≤ comap (r • (LinearMap.id : M →ₗ[R] M)) N := - mem_colon +instance (priority := low) : (N.colon P).IsTwoSided where + mul_mem_of_left {r} s hr p hp := by + obtain ⟨p, hp, rfl⟩ := hp + exact hr ⟨_, P.smul_mem _ hp, (mul_smul ..).symm⟩ @[simp] -theorem colon_top {I : Ideal R} : I.colon ⊤ = I := by +theorem colon_top {I : Ideal R} [I.IsTwoSided] : I.colon ⊤ = I := by simp_rw [SetLike.ext_iff, mem_colon, smul_eq_mul] exact fun x ↦ ⟨fun h ↦ mul_one x ▸ h 1 trivial, fun h _ _ ↦ I.mul_mem_right _ h⟩ @@ -60,6 +55,18 @@ theorem colon_bot : colon ⊥ N = N.annihilator := by theorem colon_mono (hn : N₁ ≤ N₂) (hp : P₁ ≤ P₂) : N₁.colon P₂ ≤ N₂.colon P₁ := fun _ hrnp => mem_colon.2 fun p₁ hp₁ => hn <| mem_colon.1 hrnp p₁ <| hp hp₁ +end Semiring + +section CommSemiring + +variable [CommSemiring R] [AddCommMonoid M] [Module R M] +variable {N N₁ N₂ P P₁ P₂ : Submodule R M} + +variable {R M : Type*} [CommRing R] [AddCommGroup M] [Module R M] {N P : Submodule R M} + +theorem mem_colon' {r} : r ∈ N.colon P ↔ P ≤ comap (r • (LinearMap.id : M →ₗ[R] M)) N := + mem_colon + theorem iInf_colon_iSup (ι₁ : Sort*) (f : ι₁ → Submodule R M) (ι₂ : Sort*) (g : ι₂ → Submodule R M) : (⨅ i, f i).colon (⨆ j, g j) = ⨅ (i) (j), (f i).colon (g j) := le_antisymm (le_iInf fun _ => le_iInf fun _ => colon_mono (iInf_le _ _) (le_iSup _ _)) fun _ H => @@ -88,9 +95,9 @@ theorem _root_.Ideal.mem_colon_singleton {I : Ideal R} {x r : R} : end CommSemiring -section CommRing +section Ring -variable [CommRing R] [AddCommGroup M] [Module R M] +variable [Ring R] [AddCommGroup M] [Module R M] variable {N N₁ N₂ P P₁ P₂ : Submodule R M} @[simp] @@ -102,13 +109,14 @@ lemma annihilator_map_mkQ_eq_colon : annihilator (P.map N.mkQ) = N.colon P := by theorem annihilator_quotient {N : Submodule R M} : Module.annihilator R (M ⧸ N) = N.colon ⊤ := by - simp_rw [SetLike.ext_iff, Module.mem_annihilator, ←annihilator_map_mkQ_eq_colon, mem_annihilator, - map_top, LinearMap.range_eq_top.mpr (mkQ_surjective N), mem_top, forall_true_left, - forall_const] + simp_rw [SetLike.ext_iff, Module.mem_annihilator, ← annihilator_map_mkQ_eq_colon, mem_annihilator, + map_top, LinearMap.range_eq_top.mpr (mkQ_surjective N), mem_top, forall_true_left, + forall_const] -theorem _root_.Ideal.annihilator_quotient {I : Ideal R} : Module.annihilator R (R ⧸ I) = I := by +theorem _root_.Ideal.annihilator_quotient {I : Ideal R} [I.IsTwoSided] : + Module.annihilator R (R ⧸ I) = I := by rw [Submodule.annihilator_quotient, colon_top] -end CommRing +end Ring end Submodule diff --git a/Mathlib/RingTheory/Ideal/Defs.lean b/Mathlib/RingTheory/Ideal/Defs.lean index ca2e6072c593a..18937053f74fd 100644 --- a/Mathlib/RingTheory/Ideal/Defs.lean +++ b/Mathlib/RingTheory/Ideal/Defs.lean @@ -42,6 +42,10 @@ namespace Ideal variable [Semiring α] (I : Ideal α) {a b : α} +/-- A left ideal `I : Ideal R` is two-sided if it is also a right ideal. -/ +class IsTwoSided : Prop where + mul_mem_of_left {a : α} (b : α) : a ∈ I → a * b ∈ I + protected theorem zero_mem : (0 : α) ∈ I := Submodule.zero_mem I @@ -53,6 +57,10 @@ variable (a) theorem mul_mem_left : b ∈ I → a * b ∈ I := Submodule.smul_mem I a +theorem mul_mem_right {α} {a : α} (b : α) [Semiring α] (I : Ideal α) [I.IsTwoSided] + (h : a ∈ I) : a * b ∈ I := + IsTwoSided.mul_mem_of_left b h + variable {a} @[ext] @@ -97,17 +105,13 @@ namespace Ideal variable [CommSemiring α] (I : Ideal α) +instance : I.IsTwoSided := ⟨fun b ha ↦ mul_comm b _ ▸ I.smul_mem _ ha⟩ +instance {α} [CommRing α] (I : Ideal α) : I.IsTwoSided := inferInstance + @[simp] theorem mul_unit_mem_iff_mem {x y : α} (hy : IsUnit y) : x * y ∈ I ↔ x ∈ I := mul_comm y x ▸ unit_mul_mem_iff_mem I hy -variable (b) - -theorem mul_mem_right (h : a ∈ I) : a * b ∈ I := - mul_comm b a ▸ I.mul_mem_left b h - -variable {b} - lemma mem_of_dvd (hab : a ∣ b) (ha : a ∈ I) : b ∈ I := by obtain ⟨c, rfl⟩ := hab; exact I.mul_mem_right _ ha @@ -119,7 +123,7 @@ section Ring namespace Ideal -variable [Ring α] (I : Ideal α) {a b : α} +variable [Ring α] (I : Ideal α) {a b c d : α} protected theorem neg_mem_iff : -a ∈ I ↔ a ∈ I := Submodule.neg_mem_iff I @@ -133,19 +137,11 @@ protected theorem add_mem_iff_right : a ∈ I → (a + b ∈ I ↔ b ∈ I) := protected theorem sub_mem : a ∈ I → b ∈ I → a - b ∈ I := Submodule.sub_mem I -end Ideal - -end Ring - -section CommRing - -namespace Ideal - -theorem mul_sub_mul_mem {R : Type*} [CommRing R] (I : Ideal R) {a b c d : R} (h1 : a - b ∈ I) - (h2 : c - d ∈ I) : a * c - b * d ∈ I := by +theorem mul_sub_mul_mem [I.IsTwoSided] + (h1 : a - b ∈ I) (h2 : c - d ∈ I) : a * c - b * d ∈ I := by rw [show a * c - b * d = (a - b) * c + b * (c - d) by rw [sub_mul, mul_sub]; abel] exact I.add_mem (I.mul_mem_right _ h1) (I.mul_mem_left _ h2) end Ideal -end CommRing +end Ring diff --git a/Mathlib/RingTheory/Ideal/Lattice.lean b/Mathlib/RingTheory/Ideal/Lattice.lean index 1be75b0570396..b3e38d382403f 100644 --- a/Mathlib/RingTheory/Ideal/Lattice.lean +++ b/Mathlib/RingTheory/Ideal/Lattice.lean @@ -32,6 +32,14 @@ namespace Ideal variable [Semiring α] (I : Ideal α) {a b : α} +instance (priority := low) : IsTwoSided (⊥ : Ideal α) := + ⟨fun _ h ↦ by rw [h, zero_mul]; exact zero_mem _⟩ + +instance (priority := low) : IsTwoSided (⊤ : Ideal α) := ⟨fun _ _ ↦ trivial⟩ + +instance (priority := low) {ι} (I : ι → Ideal α) [∀ i, (I i).IsTwoSided] : (⨅ i, I i).IsTwoSided := + ⟨fun _ h ↦ (Submodule.mem_iInf _).mpr (mul_mem_right _ _ <| (Submodule.mem_iInf _).mp h ·)⟩ + theorem eq_top_of_unit_mem (x y : α) (hx : x ∈ I) (h : y * x = 1) : I = ⊤ := eq_top_iff.2 fun z _ => calc diff --git a/Mathlib/RingTheory/Ideal/Maps.lean b/Mathlib/RingTheory/Ideal/Maps.lean index 4ef12677ebde3..33d2e42be5c8e 100644 --- a/Mathlib/RingTheory/Ideal/Maps.lean +++ b/Mathlib/RingTheory/Ideal/Maps.lean @@ -102,6 +102,9 @@ theorem map_le_comap_of_inverse [RingHomClass G S R] (g : G) (I : Ideal R) variable [RingHomClass F R S] +instance (priority := low) [K.IsTwoSided] : (comap f K).IsTwoSided := + ⟨fun b ha ↦ by rw [mem_comap, map_mul]; exact mul_mem_right _ _ ha⟩ + /-- The `Ideal` version of `Set.preimage_subset_image_of_inverse`. -/ theorem comap_le_map_of_inverse (g : G) (I : Ideal S) (h : Function.LeftInverse g f) : I.comap f ≤ I.map g := @@ -321,6 +324,15 @@ theorem map_eq_submodule_map (f : R →+* S) [h : RingHomSurjective f] (I : Idea I.map f = Submodule.map f.toSemilinearMap I := Submodule.ext fun _ => mem_map_iff_of_surjective f h.1 +instance (priority := low) (f : R →+* S) [RingHomSurjective f] (I : Ideal R) [I.IsTwoSided] : + (I.map f).IsTwoSided where + mul_mem_of_left b ha := by + rw [map_eq_submodule_map] at ha ⊢ + obtain ⟨a, ha, rfl⟩ := ha + obtain ⟨b, rfl⟩ := f.surjective b + rw [RingHom.coe_toSemilinearMap, ← map_mul] + exact ⟨_, I.mul_mem_right _ ha, rfl⟩ + open Function in theorem IsMaximal.comap_piEvalRingHom {ι : Type*} {R : ι → Type*} [∀ i, Semiring (R i)] {i : ι} {I : Ideal (R i)} (h : I.IsMaximal) : (I.comap <| Pi.evalRingHom R i).IsMaximal := by @@ -602,6 +614,8 @@ variable (f : F) (g : G) def ker : Ideal R := Ideal.comap f ⊥ +instance (priority := low) : (ker f).IsTwoSided := inferInstanceAs (Ideal.comap f ⊥).IsTwoSided + variable {f} in /-- An element is in the kernel if and only if it maps to zero. -/ @[simp] theorem mem_ker {r} : r ∈ ker f ↔ f r = 0 := by rw [ker, Ideal.mem_comap, Submodule.mem_bot] @@ -707,6 +721,9 @@ def Module.annihilator : Ideal R := RingHom.ker (Module.toAddMonoidEnd R M) theorem Module.mem_annihilator {r} : r ∈ Module.annihilator R M ↔ ∀ m : M, r • m = 0 := ⟨fun h ↦ (congr($h ·)), (AddMonoidHom.ext ·)⟩ +instance (priority := low) : (Module.annihilator R M).IsTwoSided := + inferInstanceAs (RingHom.ker _).IsTwoSided + theorem LinearMap.annihilator_le_of_injective (f : M →ₗ[R] M') (hf : Function.Injective f) : Module.annihilator R M' ≤ Module.annihilator R M := fun x h ↦ by rw [Module.mem_annihilator] at h ⊢; exact fun m ↦ hf (by rw [map_smul, h, f.map_zero]) diff --git a/Mathlib/RingTheory/Ideal/Maximal.lean b/Mathlib/RingTheory/Ideal/Maximal.lean index bb913acd39e29..fd31e404f0a5b 100644 --- a/Mathlib/RingTheory/Ideal/Maximal.lean +++ b/Mathlib/RingTheory/Ideal/Maximal.lean @@ -57,10 +57,7 @@ theorem isMaximal_iff {I : Ideal α} : theorem IsMaximal.eq_of_le {I J : Ideal α} (hI : I.IsMaximal) (hJ : J ≠ ⊤) (IJ : I ≤ J) : I = J := eq_iff_le_not_lt.2 ⟨IJ, fun h => hJ (hI.1.2 _ h)⟩ -instance : IsCoatomic (Ideal α) := by - apply CompleteLattice.coatomic_of_top_compact - rw [← span_singleton_one] - exact Submodule.singleton_span_isCompactElement 1 +instance : IsCoatomic (Ideal α) := CompleteLattice.coatomic_of_top_compact isCompactElement_top theorem IsMaximal.coprime_of_ne {M M' : Ideal α} (hM : M.IsMaximal) (hM' : M'.IsMaximal) (hne : M ≠ M') : M ⊔ M' = ⊤ := by diff --git a/Mathlib/RingTheory/Ideal/Operations.lean b/Mathlib/RingTheory/Ideal/Operations.lean index 24405d05da768..ff3c7b59f3257 100644 --- a/Mathlib/RingTheory/Ideal/Operations.lean +++ b/Mathlib/RingTheory/Ideal/Operations.lean @@ -61,7 +61,7 @@ apply. -/ protected theorem _root_.Ideal.smul_eq_mul (I J : Ideal R) : I • J = I * J := rfl -variable {I : Ideal R} {N : Submodule R M} +variable {I J : Ideal R} {N : Submodule R M} theorem smul_le_right : I • N ≤ N := smul_le.2 fun r _ _ ↦ N.smul_mem r @@ -72,12 +72,15 @@ theorem map_le_smul_top (I : Ideal R) (f : R →ₗ[R] M) : rw [← mul_one y, ← smul_eq_mul, f.map_smul] exact smul_mem_smul hy mem_top -variable (I N) +variable (I J N) @[simp] theorem top_smul : (⊤ : Ideal R) • N = N := le_antisymm smul_le_right fun r hri => one_smul R r ▸ smul_mem_smul mem_top hri +protected theorem mul_smul : (I * J) • N = I • J • N := + Submodule.smul_assoc _ _ _ + theorem mem_of_span_top_of_smul_mem (M' : Submodule R M) (s : Set R) (hs : Ideal.span s = ⊤) (x : M) (H : ∀ r : s, (r : R) • x ∈ M') : x ∈ M' := by suffices LinearMap.range (LinearMap.toSpanSingleton R M x) ≤ M' by @@ -252,15 +255,26 @@ theorem mul_le : I * J ≤ K ↔ ∀ r ∈ I, ∀ s ∈ J, r * s ∈ K := Submodule.smul_le theorem mul_le_left : I * J ≤ J := - Ideal.mul_le.2 fun _ _ _ => J.mul_mem_left _ + mul_le.2 fun _ _ _ => J.mul_mem_left _ @[simp] theorem sup_mul_left_self : I ⊔ J * I = I := - sup_eq_left.2 Ideal.mul_le_left + sup_eq_left.2 mul_le_left @[simp] theorem mul_left_self_sup : J * I ⊔ I = I := - sup_eq_right.2 Ideal.mul_le_left + sup_eq_right.2 mul_le_left + +theorem mul_le_right [I.IsTwoSided] : I * J ≤ I := + mul_le.2 fun _ hr _ _ ↦ I.mul_mem_right _ hr + +@[simp] +theorem sup_mul_right_self [I.IsTwoSided] : I ⊔ I * J = I := + sup_eq_left.2 mul_le_right + +@[simp] +theorem mul_right_self_sup [I.IsTwoSided] : I * J ⊔ I = I := + sup_eq_right.2 mul_le_right protected theorem mul_assoc : I * J * K = I * (J * K) := Submodule.smul_assoc I J K @@ -314,6 +328,33 @@ theorem pow_right_mono (e : I ≤ J) (n : ℕ) : I ^ n ≤ J ^ n := by · rw [Submodule.pow_succ, Submodule.pow_succ] exact Ideal.mul_mono hn e +namespace IsTwoSided + +instance (priority := low) [J.IsTwoSided] : (I * J).IsTwoSided := + ⟨fun b ha ↦ Submodule.mul_induction_on ha + (fun i hi j hj ↦ by rw [mul_assoc]; exact mul_mem_mul hi (mul_mem_right _ _ hj)) + fun x y hx hy ↦ by rw [right_distrib]; exact add_mem hx hy⟩ + +variable [I.IsTwoSided] (m n : ℕ) + +instance (priority := low) : (I ^ n).IsTwoSided := + n.rec + (by rw [Submodule.pow_zero, one_eq_top]; infer_instance) + (fun _ _ ↦ by rw [Submodule.pow_succ]; infer_instance) + +protected theorem mul_one : I * 1 = I := + mul_le_right.antisymm fun i hi ↦ mul_one i ▸ mul_mem_mul hi (one_eq_top (R := R) ▸ trivial) + +protected theorem pow_add : I ^ (m + n) = I ^ m * I ^ n := by + obtain rfl | h := eq_or_ne n 0 + · rw [add_zero, Submodule.pow_zero, IsTwoSided.mul_one] + · exact Submodule.pow_add _ h + +protected theorem pow_succ : I ^ (n + 1) = I * I ^ n := by + rw [add_comm, IsTwoSided.pow_add, Submodule.pow_one] + +end IsTwoSided + @[simp] theorem mul_eq_bot [NoZeroDivisors R] : I * J = ⊥ ↔ I = ⊥ ∨ J = ⊥ := ⟨fun hij => @@ -353,25 +394,6 @@ theorem prod_mem_prod {ι : Type*} {s : Finset ι} {I : ι → Ideal R} {x : ι mul_mem_mul (h a <| Finset.mem_insert_self a s) (IH fun i hi => h i <| Finset.mem_insert_of_mem hi) -theorem mul_le_right : I * J ≤ I := - Ideal.mul_le.2 fun _ hr _ _ => I.mul_mem_right _ hr - -#adaptation_note /-- nightly-2024-11-12 -we had to add `nolint simpNF` to the following lemma, -as otherwise we get a deterministic timeout in typeclass inference. -This should be investigated. -/ -@[simp, nolint simpNF] -theorem sup_mul_right_self : I ⊔ I * J = I := - sup_eq_left.2 Ideal.mul_le_right - -#adaptation_note /-- nightly-2024-11-12 -we had to add `nolint simpNF` to the following lemma, -as otherwise we get a deterministic timeout in typeclass inference. -This should be investigated. -/ -@[simp, nolint simpNF] -theorem mul_right_self_sup : I * J ⊔ I = I := - sup_eq_right.2 Ideal.mul_le_right - lemma sup_pow_add_le_pow_sup_pow {n m : ℕ} : (I ⊔ J) ^ (n + m) ≤ I ^ n ⊔ J ^ m := by rw [← Ideal.add_eq_sup, ← Ideal.add_eq_sup, add_pow, Ideal.sum_eq_sup] apply Finset.sup_le @@ -1189,7 +1211,7 @@ variable [CommSemiring R] [AddCommMonoid M] [Module R M] instance moduleSubmodule : Module (Ideal R) (Submodule R M) where smul_add := smul_sup add_smul := sup_smul - mul_smul := Submodule.smul_assoc + mul_smul := Submodule.mul_smul one_smul := by simp zero_smul := bot_smul smul_zero := smul_bot diff --git a/Mathlib/RingTheory/Ideal/Quotient/Basic.lean b/Mathlib/RingTheory/Ideal/Quotient/Basic.lean index dc04cdcc3ae36..ac88e2b91c590 100644 --- a/Mathlib/RingTheory/Ideal/Quotient/Basic.lean +++ b/Mathlib/RingTheory/Ideal/Quotient/Basic.lean @@ -16,11 +16,11 @@ import Mathlib.Tactic.FinCases This file defines ideal quotients as a special case of submodule quotients and proves some basic results about these quotients. -See `Algebra.RingQuot` for quotients of non-commutative rings. +See `Algebra.RingQuot` for quotients of semirings. ## Main definitions - - `Ideal.Quotient`: the quotient of a commutative ring `R` by an ideal `I : Ideal R` + - `Ideal.Quotient.Ring`: the quotient of a ring `R` by a two-sided ideal `I : Ideal R` -/ @@ -31,13 +31,31 @@ namespace Ideal open Set -variable {R : Type u} [CommRing R] (I : Ideal R) {a b : R} +variable {R : Type u} [Ring R] (I J : Ideal R) {a b : R} variable {S : Type v} namespace Quotient variable {I} {x y : R} +theorem zero_eq_one_iff : (0 : R ⧸ I) = 1 ↔ I = ⊤ := + eq_comm.trans <| (Submodule.Quotient.mk_eq_zero _).trans (eq_top_iff_one _).symm + +theorem zero_ne_one_iff : (0 : R ⧸ I) ≠ 1 ↔ I ≠ ⊤ := + not_congr zero_eq_one_iff + +protected theorem nontrivial (hI : I ≠ ⊤) : Nontrivial (R ⧸ I) := + ⟨⟨0, 1, zero_ne_one_iff.2 hI⟩⟩ + +theorem subsingleton_iff : Subsingleton (R ⧸ I) ↔ I = ⊤ := by + rw [Submodule.Quotient.subsingleton_iff, eq_top_iff, SetLike.le_def] + simp_rw [Submodule.mem_top, true_implies] + +instance : Unique (R ⧸ (⊤ : Ideal R)) := + ⟨⟨0⟩, by rintro ⟨x⟩; exact Quotient.eq_zero_iff_mem.mpr Submodule.mem_top⟩ + +variable [I.IsTwoSided] + -- this instance is harder to find than the one via `Algebra α (R ⧸ I)`, so use a lower priority instance (priority := 100) isScalarTower_right {α} [SMul α R] [IsScalarTower α R R] : IsScalarTower α (R ⧸ I) (R ⧸ I) := @@ -51,39 +69,26 @@ instance smulCommClass' {α} [SMul α R] [IsScalarTower α R R] [SMulCommClass R SMulCommClass (R ⧸ I) α (R ⧸ I) := (Quotient.ringCon I).smulCommClass' -theorem eq_zero_iff_dvd (x y : R) : Ideal.Quotient.mk (Ideal.span ({x} : Set R)) y = 0 ↔ x ∣ y := by +theorem eq_zero_iff_dvd {R} [CommRing R] (x y : R) : + Ideal.Quotient.mk (Ideal.span ({x} : Set R)) y = 0 ↔ x ∣ y := by rw [Ideal.Quotient.eq_zero_iff_mem, Ideal.mem_span_singleton] @[simp] -lemma mk_singleton_self (x : R) : mk (Ideal.span {x}) x = 0 := by - rw [eq_zero_iff_dvd] +lemma mk_singleton_self (x : R) [(Ideal.span {x}).IsTwoSided] : mk (Ideal.span {x}) x = 0 := + (Submodule.Quotient.mk_eq_zero _).mpr (mem_span_singleton_self _) -theorem zero_eq_one_iff {I : Ideal R} : (0 : R ⧸ I) = 1 ↔ I = ⊤ := - eq_comm.trans <| eq_zero_iff_mem.trans (eq_top_iff_one _).symm +variable (I) -theorem zero_ne_one_iff {I : Ideal R} : (0 : R ⧸ I) ≠ 1 ↔ I ≠ ⊤ := - not_congr zero_eq_one_iff - -protected theorem nontrivial {I : Ideal R} (hI : I ≠ ⊤) : Nontrivial (R ⧸ I) := - ⟨⟨0, 1, zero_ne_one_iff.2 hI⟩⟩ - -theorem subsingleton_iff {I : Ideal R} : Subsingleton (R ⧸ I) ↔ I = ⊤ := by - rw [eq_top_iff_one, ← subsingleton_iff_zero_eq_one, eq_comm, ← (mk I).map_one, - Quotient.eq_zero_iff_mem] - -instance : Unique (R ⧸ (⊤ : Ideal R)) := - ⟨⟨0⟩, by rintro ⟨x⟩; exact Quotient.eq_zero_iff_mem.mpr Submodule.mem_top⟩ - -instance noZeroDivisors (I : Ideal R) [hI : I.IsPrime] : NoZeroDivisors (R ⧸ I) where +instance noZeroDivisors [hI : I.IsPrime] : NoZeroDivisors (R ⧸ I) where eq_zero_or_eq_zero_of_mul_eq_zero {a b} := Quotient.inductionOn₂' a b fun {_ _} hab => (hI.mem_or_mem (eq_zero_iff_mem.1 hab)).elim (Or.inl ∘ eq_zero_iff_mem.2) (Or.inr ∘ eq_zero_iff_mem.2) -instance isDomain (I : Ideal R) [hI : I.IsPrime] : IsDomain (R ⧸ I) := +instance isDomain [hI : I.IsPrime] : IsDomain (R ⧸ I) := let _ := Quotient.nontrivial hI.1 NoZeroDivisors.to_isDomain _ -theorem isDomain_iff_prime (I : Ideal R) : IsDomain (R ⧸ I) ↔ I.IsPrime := by +theorem isDomain_iff_prime : IsDomain (R ⧸ I) ↔ I.IsPrime := by refine ⟨fun H => ⟨zero_ne_one_iff.1 ?_, fun {x y} h => ?_⟩, fun h => inferInstance⟩ · haveI : Nontrivial (R ⧸ I) := ⟨H.2.1⟩ exact zero_ne_one @@ -91,11 +96,12 @@ theorem isDomain_iff_prime (I : Ideal R) : IsDomain (R ⧸ I) ↔ I.IsPrime := b haveI := @IsDomain.to_noZeroDivisors (R ⧸ I) _ H exact eq_zero_or_eq_zero_of_mul_eq_zero h -theorem exists_inv {I : Ideal R} [hI : I.IsMaximal] : +variable {I} in +theorem exists_inv [hI : I.IsMaximal] : ∀ {a : R ⧸ I}, a ≠ 0 → ∃ b : R ⧸ I, a * b = 1 := by + apply exists_right_inv_of_exists_left_inv rintro ⟨a⟩ h rcases hI.exists_inv (mt eq_zero_iff_mem.2 h) with ⟨b, c, hc, abc⟩ - rw [mul_comm] at abc refine ⟨mk _ b, Quot.sound ?_⟩ simp only [Submodule.quotientRel_def] rw [← eq_sub_iff_add_eq'] at abc @@ -106,27 +112,38 @@ open Classical in since users will have computable inverses in some applications. See note [reducible non-instances]. -/ -protected noncomputable abbrev groupWithZero (I : Ideal R) [hI : I.IsMaximal] : - GroupWithZero (R ⧸ I) := +protected noncomputable abbrev groupWithZero [hI : I.IsMaximal] : + GroupWithZero (R ⧸ I) := fast_instance% { inv := fun a => if ha : a = 0 then 0 else Classical.choose (exists_inv ha) mul_inv_cancel := fun a (ha : a ≠ 0) => show a * dite _ _ _ = _ by rw [dif_neg ha]; exact Classical.choose_spec (exists_inv ha) - inv_zero := dif_pos rfl } + inv_zero := dif_pos rfl + __ := Quotient.nontrivial hI.out.1 } -/-- The quotient by a maximal ideal is a field. This is a `def` rather than `instance`, since users +/-- The quotient by a two-sided ideal that is maximal as a left ideal is a division ring. +This is a `def` rather than `instance`, since users +will have computable inverses (and `qsmul`, `ratCast`) in some applications. + +See note [reducible non-instances]. -/ +protected noncomputable abbrev divisionRing [I.IsMaximal] : DivisionRing (R ⧸ I) := fast_instance% + { __ := ring _ + __ := Quotient.groupWithZero _ + nnqsmul_def _ _ := rfl + qsmul_def _ _ := rfl } + +/-- The quotient of a commutative ring by a maximal ideal is a field. +This is a `def` rather than `instance`, since users will have computable inverses (and `qsmul`, `ratCast`) in some applications. See note [reducible non-instances]. -/ -protected noncomputable abbrev field (I : Ideal R) [I.IsMaximal] : Field (R ⧸ I) where - __ := commRing _ - __ := Quotient.groupWithZero _ - nnqsmul := _ - nnqsmul_def := fun _ _ => rfl - qsmul := _ - qsmul_def := fun _ _ => rfl +protected noncomputable abbrev field {R} [CommRing R] (I : Ideal R) [I.IsMaximal] : + Field (R ⧸ I) := fast_instance% + { __ := commRing _ + __ := Quotient.divisionRing I } /-- If the quotient by an ideal is a field, then the ideal is maximal. -/ -theorem maximal_of_isField (I : Ideal R) (hqf : IsField (R ⧸ I)) : I.IsMaximal := by +theorem maximal_of_isField {R} [CommRing R] (I : Ideal R) (hqf : IsField (R ⧸ I)) : + I.IsMaximal := by apply Ideal.isMaximal_iff.2 constructor · intro h @@ -138,7 +155,8 @@ theorem maximal_of_isField (I : Ideal R) (hqf : IsField (R ⧸ I)) : I.IsMaximal exact J.sub_mem (J.mul_mem_right _ hxJ) (hIJ (Ideal.Quotient.eq.1 hy)) /-- The quotient of a ring by an ideal is a field iff the ideal is maximal. -/ -theorem maximal_ideal_iff_isField_quotient (I : Ideal R) : I.IsMaximal ↔ IsField (R ⧸ I) := +theorem maximal_ideal_iff_isField_quotient {R} [CommRing R] (I : Ideal R) : + I.IsMaximal ↔ IsField (R ⧸ I) := ⟨fun h => let _i := @Quotient.field _ _ I h Field.toIsField _, @@ -151,7 +169,7 @@ section Pi variable (ι : Type v) /-- `R^n/I^n` is a `R/I`-module. -/ -instance modulePi : Module (R ⧸ I) ((ι → R) ⧸ pi fun _ ↦ I) where +instance modulePi [I.IsTwoSided] : Module (R ⧸ I) ((ι → R) ⧸ pi fun _ ↦ I) where smul c m := Quotient.liftOn₂' c m (fun r m ↦ Submodule.Quotient.mk <| r • m) <| by intro c₁ m₁ c₂ m₂ hc hm @@ -167,7 +185,7 @@ instance modulePi : Module (R ⧸ I) ((ι → R) ⧸ pi fun _ ↦ I) where zero_smul := by rintro ⟨a⟩; exact congr_arg _ (zero_smul _ _) /-- `R^n/I^n` is isomorphic to `(R/I)^n` as an `R/I`-module. -/ -noncomputable def piQuotEquiv : ((ι → R) ⧸ pi fun _ ↦ I) ≃ₗ[R ⧸ I] ι → (R ⧸ I) where +noncomputable def piQuotEquiv [I.IsTwoSided] : ((ι → R) ⧸ pi fun _ ↦ I) ≃ₗ[R ⧸ I] ι → (R ⧸ I) where toFun x := Quotient.liftOn' x (fun f i ↦ Ideal.Quotient.mk I (f i)) fun _ _ hab ↦ funext fun i ↦ (Submodule.Quotient.eq' _).2 (QuotientAddGroup.leftRel_apply.mp hab i) map_add' := by rintro ⟨_⟩ ⟨_⟩; rfl @@ -180,7 +198,7 @@ noncomputable def piQuotEquiv : ((ι → R) ⧸ pi fun _ ↦ I) ≃ₗ[R ⧸ I] /-- If `f : R^n → R^m` is an `R`-linear map and `I ⊆ R` is an ideal, then the image of `I^n` is contained in `I^m`. -/ -theorem map_pi {ι : Type*} [Finite ι] {ι' : Type w} (x : ι → R) (hi : ∀ i, x i ∈ I) +theorem map_pi [I.IsTwoSided] {ι : Type*} [Finite ι] {ι' : Type w} (x : ι → R) (hi : ∀ i, x i ∈ I) (f : (ι → R) →ₗ[R] ι' → R) (i : ι') : f x i ∈ I := by classical cases nonempty_fintype ι @@ -192,12 +210,11 @@ end Pi open scoped Pointwise in /-- A ring is made up of a disjoint union of cosets of an ideal. -/ -lemma univ_eq_iUnion_image_add {R : Type*} [Ring R] (I : Ideal R) : - (Set.univ (α := R)) = ⋃ x : R ⧸ I, x.out +ᵥ (I : Set R) := +lemma univ_eq_iUnion_image_add : (Set.univ (α := R)) = ⋃ x : R ⧸ I, x.out +ᵥ (I : Set R) := QuotientAddGroup.univ_eq_iUnion_vadd I.toAddSubgroup -lemma _root_.Finite.of_finite_quot_finite_ideal {R : Type*} [Ring R] {I : Ideal R} - [hI : Finite I] [h : Finite (R ⧸ I)] : Finite R := +variable {I} in +lemma _root_.Finite.of_finite_quot_finite_ideal [hI : Finite I] [h : Finite (R ⧸ I)] : Finite R := @Finite.of_finite_quot_finite_addSubgroup _ _ _ hI h end Ideal diff --git a/Mathlib/RingTheory/Ideal/Quotient/Defs.lean b/Mathlib/RingTheory/Ideal/Quotient/Defs.lean index d7af0ce89bff8..4d83df751721f 100644 --- a/Mathlib/RingTheory/Ideal/Quotient/Defs.lean +++ b/Mathlib/RingTheory/Ideal/Quotient/Defs.lean @@ -31,20 +31,15 @@ namespace Ideal open Set -variable {R : Type u} [CommRing R] (I : Ideal R) {a b : R} +variable {R : Type u} [Ring R] (I J : Ideal R) {a b : R} variable {S : Type v} --- Note that at present `Ideal` means a left-ideal, --- so this quotient is only useful in a commutative ring. --- We should develop quotients by two-sided ideals as well. -/-- The quotient `R/I` of a ring `R` by an ideal `I`. +/-- The quotient `R/I` of a ring `R` by an ideal `I`, +defined to equal the quotient of `I` as an `R`-submodule of `R`. -/ +instance instHasQuotient : HasQuotient R (Ideal R) := Submodule.hasQuotient -The ideal quotient of `I` is defined to equal the quotient of `I` as an `R`-submodule of `R`. -This definition uses `abbrev` so that typeclass instances can be shared between -`Ideal.Quotient I` and `Submodule.Quotient I`. --/ -@[instance] abbrev instHasQuotient : HasQuotient R (Ideal R) := - Submodule.hasQuotient +/-- Shortcut instance for commutative rings. -/ +instance {R} [CommRing R] : HasQuotient R (Ideal R) := inferInstance namespace Quotient @@ -54,29 +49,39 @@ instance one (I : Ideal R) : One (R ⧸ I) := ⟨Submodule.Quotient.mk 1⟩ /-- On `Ideal`s, `Submodule.quotientRel` is a ring congruence. -/ -protected def ringCon (I : Ideal R) : RingCon R := - { QuotientAddGroup.con I.toAddSubgroup with - mul' := fun {a₁ b₁ a₂ b₂} h₁ h₂ => by - rw [Submodule.quotientRel_def] at h₁ h₂ ⊢ - exact mul_sub_mul_mem I h₁ h₂ } +protected def ringCon (I : Ideal R) [I.IsTwoSided] : RingCon R where + __ := QuotientAddGroup.con I.toAddSubgroup + mul' {a₁ b₁ a₂ b₂} h₁ h₂ := by + rw [Submodule.quotientRel_def] at h₁ h₂ ⊢ + exact mul_sub_mul_mem I h₁ h₂ + +instance ring (I : Ideal R) [I.IsTwoSided] : Ring (R ⧸ I) := fast_instance% + { __ : AddCommGroup (R ⧸ I) := inferInstance + __ : Ring (Quotient.ringCon I).Quotient := inferInstance } + +instance commRing {R} [CommRing R] (I : Ideal R) : CommRing (R ⧸ I) := fast_instance% + { mul_comm := by rintro ⟨a⟩ ⟨b⟩; exact congr_arg _ (mul_comm a b) } --- This instance makes use of the existing AddCommGroup instance to boost performance. -instance commRing (I : Ideal R) : CommRing (R ⧸ I) where - __ : AddCommGroup (R ⧸ I) := inferInstance - __ : CommRing (Quotient.ringCon I).Quotient := inferInstance +instance {R} [CommRing R] (I : Ideal R) : Ring (R ⧸ I) := fast_instance% inferInstance +instance commSemiring {R} [CommRing R] (I : Ideal R) : CommSemiring (R ⧸ I) := fast_instance% + inferInstance +instance semiring {R} [CommRing R] (I : Ideal R) : Semiring (R ⧸ I) := fast_instance% inferInstance + +variable [I.IsTwoSided] -- Sanity test to make sure no diamonds have emerged in `commRing` -example : (commRing I).toAddCommGroup = Submodule.Quotient.addCommGroup I := rfl +example : (ring I).toAddCommGroup = Submodule.Quotient.addCommGroup I := rfl +variable (I) in /-- The ring homomorphism from a ring `R` to a quotient ring `R/I`. -/ -def mk (I : Ideal R) : R →+* R ⧸ I where +def mk : R →+* R ⧸ I where toFun a := Submodule.Quotient.mk a map_zero' := rfl map_one' := rfl map_mul' _ _ := rfl map_add' _ _ := rfl -instance {I : Ideal R} : Coe R (R ⧸ I) := +instance : Coe R (R ⧸ I) := ⟨Ideal.Quotient.mk I⟩ /-- Two `RingHom`s from the quotient by an ideal are equal if their @@ -88,7 +93,7 @@ theorem ringHom_ext [NonAssocSemiring S] ⦃f g : R ⧸ I →+* S⦄ (h : f.comp f = g := RingHom.ext fun x => Quotient.inductionOn' x <| (RingHom.congr_fun h :) -instance inhabited : Inhabited (R ⧸ I) := +instance : Nonempty (R ⧸ I) := ⟨mk I 37⟩ protected theorem eq : mk I x = mk I y ↔ x - y ∈ I := @@ -97,7 +102,7 @@ protected theorem eq : mk I x = mk I y ↔ x - y ∈ I := @[simp] theorem mk_eq_mk (x : R) : (Submodule.Quotient.mk x : R ⧸ I) = mk I x := rfl -theorem eq_zero_iff_mem {I : Ideal R} : mk I a = 0 ↔ a ∈ I := +theorem eq_zero_iff_mem : mk I a = 0 ↔ a ∈ I := Submodule.Quotient.mk_eq_zero _ theorem mk_eq_mk_iff_sub_mem (x y : R) : mk I x = mk I y ↔ x - y ∈ I := by @@ -111,7 +116,7 @@ instance : RingHomSurjective (mk I) := /-- If `I` is an ideal of a commutative ring `R`, if `q : R → R/I` is the quotient map, and if `s ⊆ R` is a subset, then `q⁻¹(q(s)) = ⋃ᵢ(i + s)`, the union running over all `i ∈ I`. -/ -theorem quotient_ring_saturate (I : Ideal R) (s : Set R) : +theorem quotient_ring_saturate (s : Set R) : mk I ⁻¹' (mk I '' s) = ⋃ x : I, (fun y => x.1 + y) '' s := by ext x simp only [mem_preimage, mem_image, mem_iUnion, Ideal.Quotient.eq] @@ -119,61 +124,65 @@ theorem quotient_ring_saturate (I : Ideal R) (s : Set R) : ⟨fun ⟨a, a_in, h⟩ => ⟨⟨_, I.neg_mem h⟩, a, a_in, by simp⟩, fun ⟨⟨i, hi⟩, a, ha, Eq⟩ => ⟨a, ha, by rw [← Eq, sub_add_eq_sub_sub_swap, sub_self, zero_sub]; exact I.neg_mem hi⟩⟩ -variable [Semiring S] +variable [Semiring S] (I) /-- Given a ring homomorphism `f : R →+* S` sending all elements of an ideal to zero, lift it to the quotient by this ideal. -/ -def lift (I : Ideal R) (f : R →+* S) (H : ∀ a : R, a ∈ I → f a = 0) : R ⧸ I →+* S := +def lift (f : R →+* S) (H : ∀ a : R, a ∈ I → f a = 0) : R ⧸ I →+* S := { QuotientAddGroup.lift I.toAddSubgroup f.toAddMonoidHom H with map_one' := f.map_one map_mul' := fun a₁ a₂ => Quotient.inductionOn₂' a₁ a₂ f.map_mul } @[simp] -theorem lift_mk (I : Ideal R) (f : R →+* S) (H : ∀ a : R, a ∈ I → f a = 0) : +theorem lift_mk (f : R →+* S) (H : ∀ a : R, a ∈ I → f a = 0) : lift I f H (mk I a) = f a := rfl -theorem lift_surjective_of_surjective (I : Ideal R) {f : R →+* S} (H : ∀ a : R, a ∈ I → f a = 0) +theorem lift_surjective_of_surjective {f : R →+* S} (H : ∀ a : R, a ∈ I → f a = 0) (hf : Function.Surjective f) : Function.Surjective (Ideal.Quotient.lift I f H) := by intro y obtain ⟨x, rfl⟩ := hf y use Ideal.Quotient.mk I x simp only [Ideal.Quotient.lift_mk] +variable (S T : Ideal R) [S.IsTwoSided] [T.IsTwoSided] + /-- The ring homomorphism from the quotient by a smaller ideal to the quotient by a larger ideal. This is the `Ideal.Quotient` version of `Quot.Factor` -/ -def factor (S T : Ideal R) (H : S ≤ T) : R ⧸ S →+* R ⧸ T := +def factor (H : S ≤ T) : R ⧸ S →+* R ⧸ T := Ideal.Quotient.lift S (mk T) fun _ hx => eq_zero_iff_mem.2 (H hx) @[simp] -theorem factor_mk (S T : Ideal R) (H : S ≤ T) (x : R) : factor S T H (mk S x) = mk T x := +theorem factor_mk (H : S ≤ T) (x : R) : factor S T H (mk S x) = mk T x := rfl @[simp] -theorem factor_comp_mk (S T : Ideal R) (H : S ≤ T) : (factor S T H).comp (mk S) = mk T := by +theorem factor_comp_mk (H : S ≤ T) : (factor S T H).comp (mk S) = mk T := by ext x rw [RingHom.comp_apply, factor_mk] end Quotient +variable {I J} [I.IsTwoSided] [J.IsTwoSided] + /-- Quotienting by equal ideals gives equivalent rings. See also `Submodule.quotEquivOfEq` and `Ideal.quotientEquivAlgOfEq`. -/ -def quotEquivOfEq {R : Type*} [CommRing R] {I J : Ideal R} (h : I = J) : R ⧸ I ≃+* R ⧸ J := +def quotEquivOfEq (h : I = J) : R ⧸ I ≃+* R ⧸ J := { Submodule.quotEquivOfEq I J h with map_mul' := by rintro ⟨x⟩ ⟨y⟩ rfl } @[simp] -theorem quotEquivOfEq_mk {R : Type*} [CommRing R] {I J : Ideal R} (h : I = J) (x : R) : +theorem quotEquivOfEq_mk (h : I = J) (x : R) : quotEquivOfEq h (Ideal.Quotient.mk I x) = Ideal.Quotient.mk J x := rfl @[simp] -theorem quotEquivOfEq_symm {R : Type*} [CommRing R] {I J : Ideal R} (h : I = J) : +theorem quotEquivOfEq_symm (h : I = J) : (Ideal.quotEquivOfEq h).symm = Ideal.quotEquivOfEq h.symm := by ext; rfl end Ideal diff --git a/Mathlib/RingTheory/Ideal/Quotient/Nilpotent.lean b/Mathlib/RingTheory/Ideal/Quotient/Nilpotent.lean index 7bfc95e2f5367..c6ee2781aac6a 100644 --- a/Mathlib/RingTheory/Ideal/Quotient/Nilpotent.lean +++ b/Mathlib/RingTheory/Ideal/Quotient/Nilpotent.lean @@ -13,7 +13,7 @@ import Mathlib.RingTheory.Nilpotent.Lemmas theorem Ideal.isRadical_iff_quotient_reduced {R : Type*} [CommRing R] (I : Ideal R) : I.IsRadical ↔ IsReduced (R ⧸ I) := by conv_lhs => rw [← @Ideal.mk_ker R _ I] - exact RingHom.ker_isRadical_iff_reduced_of_surjective (@Ideal.Quotient.mk_surjective R _ I) + exact RingHom.ker_isRadical_iff_reduced_of_surjective Quotient.mk_surjective variable {S : Type*} [CommRing S] (I : Ideal S) diff --git a/Mathlib/RingTheory/Ideal/Quotient/Operations.lean b/Mathlib/RingTheory/Ideal/Quotient/Operations.lean index 8b758cb2564b1..0f27e03ce60fc 100644 --- a/Mathlib/RingTheory/Ideal/Quotient/Operations.lean +++ b/Mathlib/RingTheory/Ideal/Quotient/Operations.lean @@ -29,7 +29,7 @@ universe u v w namespace RingHom -variable {R : Type u} {S : Type v} [CommRing R] [Semiring S] (f : R →+* S) +variable {R : Type u} {S : Type v} [Ring R] [Semiring S] (f : R →+* S) /-- The induced map from the quotient by the kernel to the codomain. @@ -43,7 +43,8 @@ def kerLift : R ⧸ ker f →+* S := theorem kerLift_mk (r : R) : kerLift f (Ideal.Quotient.mk (ker f) r) = f r := Ideal.Quotient.lift_mk _ _ _ -theorem lift_injective_of_ker_le_ideal (I : Ideal R) {f : R →+* S} (H : ∀ a : R, a ∈ I → f a = 0) +theorem lift_injective_of_ker_le_ideal (I : Ideal R) [I.IsTwoSided] + {f : R →+* S} (H : ∀ a : R, a ∈ I → f a = 0) (hI : ker f ≤ I) : Function.Injective (Ideal.Quotient.lift I f H) := by rw [RingHom.injective_iff_ker_eq_bot, RingHom.ker_eq_bot_iff_eq_zero] intro u hu @@ -109,24 +110,25 @@ end RingHom namespace Ideal open Function RingHom -variable {R : Type u} {S : Type v} {F : Type w} [CommRing R] [Semiring S] +variable {R : Type u} {S : Type v} {F : Type w} [Ring R] [Semiring S] @[simp] -theorem map_quotient_self (I : Ideal R) : map (Quotient.mk I) I = ⊥ := +theorem map_quotient_self (I : Ideal R) [I.IsTwoSided] : map (Quotient.mk I) I = ⊥ := eq_bot_iff.2 <| Ideal.map_le_iff_le_comap.2 fun _ hx => (Submodule.mem_bot (R ⧸ I)).2 <| Ideal.Quotient.eq_zero_iff_mem.2 hx @[simp] -theorem mk_ker {I : Ideal R} : ker (Quotient.mk I) = I := by +theorem mk_ker {I : Ideal R} [I.IsTwoSided] : ker (Quotient.mk I) = I := by ext rw [ker, mem_comap, Submodule.mem_bot, Quotient.eq_zero_iff_mem] -theorem map_mk_eq_bot_of_le {I J : Ideal R} (h : I ≤ J) : I.map (Quotient.mk J) = ⊥ := by +theorem map_mk_eq_bot_of_le {I J : Ideal R} [J.IsTwoSided] (h : I ≤ J) : + I.map (Quotient.mk J) = ⊥ := by rw [map_eq_bot_iff_le_ker, mk_ker] exact h -theorem ker_quotient_lift {I : Ideal R} (f : R →+* S) +theorem ker_quotient_lift {I : Ideal R} [I.IsTwoSided] (f : R →+* S) (H : I ≤ ker f) : ker (Ideal.Quotient.lift I f H) = f.ker.map (Quotient.mk I) := by apply Ideal.ext @@ -143,35 +145,37 @@ theorem ker_quotient_lift {I : Ideal R} (f : R →+* S) rw [mem_ker, ← hy.right, Ideal.Quotient.lift_mk] exact hy.left -lemma injective_lift_iff {I : Ideal R} {f : R →+* S} (H : ∀ (a : R), a ∈ I → f a = 0) : +lemma injective_lift_iff {I : Ideal R} [I.IsTwoSided] + {f : R →+* S} (H : ∀ (a : R), a ∈ I → f a = 0) : Injective (Quotient.lift I f H) ↔ ker f = I := by rw [injective_iff_ker_eq_bot, ker_quotient_lift, map_eq_bot_iff_le_ker, mk_ker] constructor · exact fun h ↦ le_antisymm h H · rintro rfl; rfl -lemma ker_Pi_Quotient_mk {ι : Type*} (I : ι → Ideal R) : +lemma ker_Pi_Quotient_mk {ι : Type*} (I : ι → Ideal R) [∀ i, (I i).IsTwoSided] : ker (Pi.ringHom fun i : ι ↦ Quotient.mk (I i)) = ⨅ i, I i := by simp [Pi.ker_ringHom, mk_ker] @[simp] -theorem bot_quotient_isMaximal_iff (I : Ideal R) : (⊥ : Ideal (R ⧸ I)).IsMaximal ↔ I.IsMaximal := +theorem bot_quotient_isMaximal_iff (I : Ideal R) [I.IsTwoSided] : + (⊥ : Ideal (R ⧸ I)).IsMaximal ↔ I.IsMaximal := ⟨fun hI => mk_ker (I := I) ▸ comap_isMaximal_of_surjective (Quotient.mk I) Quotient.mk_surjective (K := ⊥) (H := hI), fun hI => by - letI := Quotient.field I + letI := Quotient.divisionRing I exact bot_isMaximal⟩ /-- See also `Ideal.mem_quotient_iff_mem` in case `I ≤ J`. -/ @[simp] -theorem mem_quotient_iff_mem_sup {I J : Ideal R} {x : R} : +theorem mem_quotient_iff_mem_sup {I J : Ideal R} [I.IsTwoSided] {x : R} : Quotient.mk I x ∈ J.map (Quotient.mk I) ↔ x ∈ J ⊔ I := by rw [← mem_comap, comap_map_of_surjective (Quotient.mk I) Quotient.mk_surjective, ← ker_eq_comap_bot, mk_ker] /-- See also `Ideal.mem_quotient_iff_mem_sup` if the assumption `I ≤ J` is not available. -/ -theorem mem_quotient_iff_mem {I J : Ideal R} (hIJ : I ≤ J) {x : R} : +theorem mem_quotient_iff_mem {I J : Ideal R} [I.IsTwoSided] (hIJ : I ≤ J) {x : R} : Quotient.mk I x ∈ J.map (Quotient.mk I) ↔ x ∈ J := by rw [mem_quotient_iff_mem_sup, sup_eq_left.mpr hIJ] @@ -182,22 +186,26 @@ variable {ι : Type*} /-- The homomorphism from `R/(⋂ i, f i)` to `∏ i, (R / f i)` featured in the Chinese Remainder Theorem. It is bijective if the ideals `f i` are coprime. -/ -def quotientInfToPiQuotient (I : ι → Ideal R) : (R ⧸ ⨅ i, I i) →+* ∀ i, R ⧸ I i := +def quotientInfToPiQuotient (I : ι → Ideal R) [∀ i, (I i).IsTwoSided] : + (R ⧸ ⨅ i, I i) →+* ∀ i, R ⧸ I i := Quotient.lift (⨅ i, I i) (Pi.ringHom fun i : ι ↦ Quotient.mk (I i)) (by simp [← RingHom.mem_ker, ker_Pi_Quotient_mk]) -lemma quotientInfToPiQuotient_mk (I : ι → Ideal R) (x : R) : +lemma quotientInfToPiQuotient_mk (I : ι → Ideal R) [∀ i, (I i).IsTwoSided] (x : R) : quotientInfToPiQuotient I (Quotient.mk _ x) = fun i : ι ↦ Quotient.mk (I i) x := rfl -lemma quotientInfToPiQuotient_mk' (I : ι → Ideal R) (x : R) (i : ι) : +lemma quotientInfToPiQuotient_mk' (I : ι → Ideal R) [∀ i, (I i).IsTwoSided] (x : R) (i : ι) : quotientInfToPiQuotient I (Quotient.mk _ x) i = Quotient.mk (I i) x := rfl -lemma quotientInfToPiQuotient_inj (I : ι → Ideal R) : Injective (quotientInfToPiQuotient I) := by +lemma quotientInfToPiQuotient_inj (I : ι → Ideal R) [∀ i, (I i).IsTwoSided] : + Injective (quotientInfToPiQuotient I) := by rw [quotientInfToPiQuotient, injective_lift_iff, ker_Pi_Quotient_mk] -lemma quotientInfToPiQuotient_surj [Finite ι] {I : ι → Ideal R} +variable {R : Type*} [CommRing R] {ι : Type*} [Finite ι] + +lemma quotientInfToPiQuotient_surj {I : ι → Ideal R} (hI : Pairwise (IsCoprime on I)) : Surjective (quotientInfToPiQuotient I) := by classical cases nonempty_fintype ι @@ -223,14 +231,14 @@ lemma quotientInfToPiQuotient_surj [Finite ι] {I : ι → Ideal R} /-- **Chinese Remainder Theorem**. Eisenbud Ex.2.6. Similar to Atiyah-Macdonald 1.10 and Stacks 00DT -/ -noncomputable def quotientInfRingEquivPiQuotient [Finite ι] (f : ι → Ideal R) +noncomputable def quotientInfRingEquivPiQuotient (f : ι → Ideal R) (hf : Pairwise (IsCoprime on f)) : (R ⧸ ⨅ i, f i) ≃+* ∀ i, R ⧸ f i := { Equiv.ofBijective _ ⟨quotientInfToPiQuotient_inj f, quotientInfToPiQuotient_surj hf⟩, quotientInfToPiQuotient f with } /-- Corollary of Chinese Remainder Theorem: if `Iᵢ` are pairwise coprime ideals in a commutative ring then the canonical map `R → ∏ (R ⧸ Iᵢ)` is surjective. -/ -lemma pi_quotient_surjective {R : Type*} [CommRing R] {ι : Type*} [Finite ι] {I : ι → Ideal R} +lemma pi_quotient_surjective {I : ι → Ideal R} (hf : Pairwise fun i j ↦ IsCoprime (I i) (I j)) (x : (i : ι) → R ⧸ I i) : ∃ r : R, ∀ i, r = x i := by obtain ⟨y, rfl⟩ := Ideal.quotientInfToPiQuotient_surj hf x @@ -240,7 +248,7 @@ lemma pi_quotient_surjective {R : Type*} [CommRing R] {ι : Type*} [Finite ι] { -- variant of `IsDedekindDomain.exists_forall_sub_mem_ideal` which doesn't assume Dedekind domain! /-- Corollary of Chinese Remainder Theorem: if `Iᵢ` are pairwise coprime ideals in a commutative ring then given elements `xᵢ` you can find `r` with `r - xᵢ ∈ Iᵢ` for all `i`. -/ -lemma exists_forall_sub_mem_ideal {R : Type*} [CommRing R] {ι : Type*} [Finite ι] +lemma exists_forall_sub_mem_ideal {I : ι → Ideal R} (hI : Pairwise fun i j ↦ IsCoprime (I i) (I j)) (x : ι → R) : ∃ r : R, ∀ i, r - x i ∈ I i := by obtain ⟨y, hy⟩ := Ideal.pi_quotient_surjective hI (fun i ↦ x i) @@ -321,65 +329,71 @@ end ChineseRemainder section QuotientAlgebra variable (R₁ R₂ : Type*) {A B : Type*} -variable [CommSemiring R₁] [CommSemiring R₂] [CommRing A] +variable [CommSemiring R₁] [CommSemiring R₂] [Ring A] variable [Algebra R₁ A] [Algebra R₂ A] /-- The `R₁`-algebra structure on `A/I` for an `R₁`-algebra `A` -/ -instance Quotient.algebra {I : Ideal A} : Algebra R₁ (A ⧸ I) where +instance Quotient.algebra {I : Ideal A} [I.IsTwoSided] : Algebra R₁ (A ⧸ I) where algebraMap := (Ideal.Quotient.mk I).comp (algebraMap R₁ A) smul_def' := fun _ x => Quotient.inductionOn' x fun _ => ((Quotient.mk I).congr_arg <| Algebra.smul_def _ _).trans (RingHom.map_mul _ _ _) - commutes' := fun _ _ => mul_comm _ _ + commutes' := by rintro r ⟨x⟩; exact congr_arg (⟦·⟧) (Algebra.commutes r x) + +instance {A} [CommRing A] [Algebra R₁ A] (I : Ideal A) : Algebra R₁ (A ⧸ I) := inferInstance -- Lean can struggle to find this instance later if we don't provide this shortcut -- Porting note: this can probably now be deleted -- update: maybe not - removal causes timeouts instance Quotient.isScalarTower [SMul R₁ R₂] [IsScalarTower R₁ R₂ A] (I : Ideal A) : - IsScalarTower R₁ R₂ (A ⧸ I) := by infer_instance + IsScalarTower R₁ R₂ (A ⧸ I) := inferInstance /-- The canonical morphism `A →ₐ[R₁] A ⧸ I` as morphism of `R₁`-algebras, for `I` an ideal of `A`, where `A` is an `R₁`-algebra. -/ -def Quotient.mkₐ (I : Ideal A) : A →ₐ[R₁] A ⧸ I := +def Quotient.mkₐ (I : Ideal A) [I.IsTwoSided] : A →ₐ[R₁] A ⧸ I := ⟨⟨⟨⟨fun a => Submodule.Quotient.mk a, rfl⟩, fun _ _ => rfl⟩, rfl, fun _ _ => rfl⟩, fun _ => rfl⟩ -theorem Quotient.algHom_ext {I : Ideal A} {S} [Semiring S] [Algebra R₁ S] ⦃f g : A ⧸ I →ₐ[R₁] S⦄ +theorem Quotient.algHom_ext {I : Ideal A} [I.IsTwoSided] + {S} [Semiring S] [Algebra R₁ S] ⦃f g : A ⧸ I →ₐ[R₁] S⦄ (h : f.comp (Quotient.mkₐ R₁ I) = g.comp (Quotient.mkₐ R₁ I)) : f = g := AlgHom.ext fun x => Quotient.inductionOn' x <| AlgHom.congr_fun h -theorem Quotient.alg_map_eq (I : Ideal A) : +theorem Quotient.alg_map_eq {A} [CommRing A] [Algebra R₁ A] (I : Ideal A) : algebraMap R₁ (A ⧸ I) = (algebraMap A (A ⧸ I)).comp (algebraMap R₁ A) := rfl -theorem Quotient.mkₐ_toRingHom (I : Ideal A) : +theorem Quotient.mkₐ_toRingHom (I : Ideal A) [I.IsTwoSided] : (Quotient.mkₐ R₁ I).toRingHom = Ideal.Quotient.mk I := rfl @[simp] -theorem Quotient.mkₐ_eq_mk (I : Ideal A) : ⇑(Quotient.mkₐ R₁ I) = Quotient.mk I := +theorem Quotient.mkₐ_eq_mk (I : Ideal A) [I.IsTwoSided] : ⇑(Quotient.mkₐ R₁ I) = Quotient.mk I := rfl @[simp] -theorem Quotient.algebraMap_eq (I : Ideal R) : algebraMap R (R ⧸ I) = Quotient.mk I := +theorem Quotient.algebraMap_eq {R} [CommRing R] (I : Ideal R) : + algebraMap R (R ⧸ I) = Quotient.mk I := rfl @[simp] -theorem Quotient.mk_comp_algebraMap (I : Ideal A) : +theorem Quotient.mk_comp_algebraMap (I : Ideal A) [I.IsTwoSided] : (Quotient.mk I).comp (algebraMap R₁ A) = algebraMap R₁ (A ⧸ I) := rfl @[simp] -theorem Quotient.mk_algebraMap (I : Ideal A) (x : R₁) : +theorem Quotient.mk_algebraMap (I : Ideal A) [I.IsTwoSided] (x : R₁) : Quotient.mk I (algebraMap R₁ A x) = algebraMap R₁ (A ⧸ I) x := rfl /-- The canonical morphism `A →ₐ[R₁] I.quotient` is surjective. -/ -theorem Quotient.mkₐ_surjective (I : Ideal A) : Function.Surjective (Quotient.mkₐ R₁ I) := +theorem Quotient.mkₐ_surjective (I : Ideal A) [I.IsTwoSided] : + Function.Surjective (Quotient.mkₐ R₁ I) := Quot.mk_surjective /-- The kernel of `A →ₐ[R₁] I.quotient` is `I`. -/ @[simp] -theorem Quotient.mkₐ_ker (I : Ideal A) : RingHom.ker (Quotient.mkₐ R₁ I : A →+* A ⧸ I) = I := +theorem Quotient.mkₐ_ker (I : Ideal A) [I.IsTwoSided] : + RingHom.ker (Quotient.mkₐ R₁ I : A →+* A ⧸ I) = I := Ideal.mk_ker variable {R₁} @@ -389,25 +403,26 @@ section variable [Semiring B] [Algebra R₁ B] /-- `Ideal.quotient.lift` as an `AlgHom`. -/ -def Quotient.liftₐ (I : Ideal A) (f : A →ₐ[R₁] B) (hI : ∀ a : A, a ∈ I → f a = 0) : +def Quotient.liftₐ (I : Ideal A) [I.IsTwoSided] (f : A →ₐ[R₁] B) (hI : ∀ a : A, a ∈ I → f a = 0) : A ⧸ I →ₐ[R₁] B := {-- this is IsScalarTower.algebraMap_apply R₁ A (A ⧸ I) but the file `Algebra.Algebra.Tower` -- imports this file. Ideal.Quotient.lift I (f : A →+* B) hI with commutes' := fun r => by - have : algebraMap R₁ (A ⧸ I) r = algebraMap A (A ⧸ I) (algebraMap R₁ A r) := by - simp_rw [Algebra.algebraMap_eq_smul_one, smul_assoc, one_smul] - rw [this, Ideal.Quotient.algebraMap_eq, RingHom.toFun_eq_coe, Ideal.Quotient.lift_mk, + have : algebraMap R₁ (A ⧸ I) r = Ideal.Quotient.mk I (algebraMap R₁ A r) := rfl + rw [this, RingHom.toFun_eq_coe, Ideal.Quotient.lift_mk, AlgHom.coe_toRingHom, Algebra.algebraMap_eq_smul_one, Algebra.algebraMap_eq_smul_one, map_smul, map_one] } @[simp] -theorem Quotient.liftₐ_apply (I : Ideal A) (f : A →ₐ[R₁] B) (hI : ∀ a : A, a ∈ I → f a = 0) (x) : +theorem Quotient.liftₐ_apply (I : Ideal A) [I.IsTwoSided] + (f : A →ₐ[R₁] B) (hI : ∀ a : A, a ∈ I → f a = 0) (x) : Ideal.Quotient.liftₐ I f hI x = Ideal.Quotient.lift I (f : A →+* B) hI x := rfl -theorem Quotient.liftₐ_comp (I : Ideal A) (f : A →ₐ[R₁] B) (hI : ∀ a : A, a ∈ I → f a = 0) : +theorem Quotient.liftₐ_comp (I : Ideal A) [I.IsTwoSided] + (f : A →ₐ[R₁] B) (hI : ∀ a : A, a ∈ I → f a = 0) : (Ideal.Quotient.liftₐ I f hI).comp (Ideal.Quotient.mkₐ R₁ I) = f := AlgHom.ext fun _ => (Ideal.Quotient.lift_mk I (f : A →+* B) hI :) @@ -453,91 +468,96 @@ noncomputable def quotientKerAlgEquivOfSurjective {f : A →ₐ[R₁] B} (hf : F end -section CommRing_CommRing +section Ring_Ring + +variable {S : Type v} [Ring S] -variable {S : Type v} [CommRing S] /-- The ring hom `R/I →+* S/J` induced by a ring hom `f : R →+* S` with `I ≤ f⁻¹(J)` -/ -def quotientMap {I : Ideal R} (J : Ideal S) (f : R →+* S) (hIJ : I ≤ J.comap f) : R ⧸ I →+* S ⧸ J := +def quotientMap {I : Ideal R} (J : Ideal S) [I.IsTwoSided] [J.IsTwoSided] (f : R →+* S) + (hIJ : I ≤ J.comap f) : R ⧸ I →+* S ⧸ J := Quotient.lift I ((Quotient.mk J).comp f) fun _ ha => by simpa [Function.comp_apply, RingHom.coe_comp, Quotient.eq_zero_iff_mem] using hIJ ha @[simp] -theorem quotientMap_mk {J : Ideal R} {I : Ideal S} {f : R →+* S} {H : J ≤ I.comap f} {x : R} : +theorem quotientMap_mk {J : Ideal R} {I : Ideal S} [I.IsTwoSided] [J.IsTwoSided] + {f : R →+* S} {H : J ≤ I.comap f} {x : R} : quotientMap I f H (Quotient.mk J x) = Quotient.mk I (f x) := Quotient.lift_mk J _ _ @[simp] -theorem quotientMap_algebraMap {J : Ideal A} {I : Ideal S} {f : A →+* S} {H : J ≤ I.comap f} +theorem quotientMap_algebraMap {J : Ideal A} {I : Ideal S} [I.IsTwoSided] [J.IsTwoSided] + {f : A →+* S} {H : J ≤ I.comap f} {x : R₁} : quotientMap I f H (algebraMap R₁ (A ⧸ J) x) = Quotient.mk I (f (algebraMap _ _ x)) := Quotient.lift_mk J _ _ -theorem quotientMap_comp_mk {J : Ideal R} {I : Ideal S} {f : R →+* S} (H : J ≤ I.comap f) : +theorem quotientMap_comp_mk {J : Ideal R} {I : Ideal S} [I.IsTwoSided] [J.IsTwoSided] + {f : R →+* S} (H : J ≤ I.comap f) : (quotientMap I f H).comp (Quotient.mk J) = (Quotient.mk I).comp f := RingHom.ext fun x => by simp only [Function.comp_apply, RingHom.coe_comp, Ideal.quotientMap_mk] -lemma ker_quotientMap_mk {I J : Ideal R} : +lemma ker_quotientMap_mk {I J : Ideal R} [I.IsTwoSided] [J.IsTwoSided] : RingHom.ker (quotientMap (J.map _) (Quotient.mk I) le_comap_map) = I.map (Quotient.mk J) := by rw [Ideal.quotientMap, Ideal.ker_quotient_lift, ← RingHom.comap_ker, Ideal.mk_ker, Ideal.comap_map_of_surjective _ Ideal.Quotient.mk_surjective, ← RingHom.ker_eq_comap_bot, Ideal.mk_ker, Ideal.map_sup, Ideal.map_quotient_self, bot_sup_eq] +section quotientEquiv + +variable (I : Ideal R) (J : Ideal S) [I.IsTwoSided] [J.IsTwoSided] + (f : R ≃+* S) (hIJ : J = I.map (f : R →+* S)) + /-- The ring equiv `R/I ≃+* S/J` induced by a ring equiv `f : R ≃+* S`, where `J = f(I)`. -/ @[simps] -def quotientEquiv (I : Ideal R) (J : Ideal S) (f : R ≃+* S) (hIJ : J = I.map (f : R →+* S)) : - R ⧸ I ≃+* S ⧸ J := - { - quotientMap J (↑f) (by - rw [hIJ] - exact le_comap_map) - with - invFun := - quotientMap I (↑f.symm) - (by - rw [hIJ] - exact le_of_eq (map_comap_of_equiv f)) - left_inv := by - rintro ⟨r⟩ - simp only [Submodule.Quotient.quot_mk_eq_mk, Quotient.mk_eq_mk, RingHom.toFun_eq_coe, - quotientMap_mk, RingEquiv.coe_toRingHom, RingEquiv.symm_apply_apply] - right_inv := by - rintro ⟨s⟩ - simp only [Submodule.Quotient.quot_mk_eq_mk, Quotient.mk_eq_mk, RingHom.toFun_eq_coe, - quotientMap_mk, RingEquiv.coe_toRingHom, RingEquiv.apply_symm_apply] } +def quotientEquiv : R ⧸ I ≃+* S ⧸ J where + __ := quotientMap J f (hIJ ▸ le_comap_map) + invFun := quotientMap I f.symm (hIJ ▸ (map_comap_of_equiv f).le) + left_inv := by + rintro ⟨r⟩ + simp only [Submodule.Quotient.quot_mk_eq_mk, Quotient.mk_eq_mk, RingHom.toFun_eq_coe, + quotientMap_mk, RingEquiv.coe_toRingHom, RingEquiv.symm_apply_apply] + right_inv := by + rintro ⟨s⟩ + simp only [Submodule.Quotient.quot_mk_eq_mk, Quotient.mk_eq_mk, RingHom.toFun_eq_coe, + quotientMap_mk, RingEquiv.coe_toRingHom, RingEquiv.apply_symm_apply] /- Porting note: removed simp. LHS simplified. Slightly different version of the simplified form closed this and was itself closed by simp -/ -theorem quotientEquiv_mk (I : Ideal R) (J : Ideal S) (f : R ≃+* S) (hIJ : J = I.map (f : R →+* S)) - (x : R) : quotientEquiv I J f hIJ (Ideal.Quotient.mk I x) = Ideal.Quotient.mk J (f x) := +theorem quotientEquiv_mk (x : R) : + quotientEquiv I J f hIJ (Ideal.Quotient.mk I x) = Ideal.Quotient.mk J (f x) := rfl @[simp] -theorem quotientEquiv_symm_mk (I : Ideal R) (J : Ideal S) (f : R ≃+* S) - (hIJ : J = I.map (f : R →+* S)) (x : S) : +theorem quotientEquiv_symm_mk (x : S) : (quotientEquiv I J f hIJ).symm (Ideal.Quotient.mk J x) = Ideal.Quotient.mk I (f.symm x) := rfl +end quotientEquiv + /-- `H` and `h` are kept as separate hypothesis since H is used in constructing the quotient map. -/ -theorem quotientMap_injective' {J : Ideal R} {I : Ideal S} {f : R →+* S} {H : J ≤ I.comap f} - (h : I.comap f ≤ J) : Function.Injective (quotientMap I f H) := by +theorem quotientMap_injective' {J : Ideal R} {I : Ideal S} [I.IsTwoSided] [J.IsTwoSided] + {f : R →+* S} {H : J ≤ I.comap f} (h : I.comap f ≤ J) : + Function.Injective (quotientMap I f H) := by refine (injective_iff_map_eq_zero (quotientMap I f H)).2 fun a ha => ?_ obtain ⟨r, rfl⟩ := Quotient.mk_surjective a rw [quotientMap_mk, Quotient.eq_zero_iff_mem] at ha exact Quotient.eq_zero_iff_mem.mpr (h ha) /-- If we take `J = I.comap f` then `quotientMap` is injective automatically. -/ -theorem quotientMap_injective {I : Ideal S} {f : R →+* S} : +theorem quotientMap_injective {I : Ideal S} {f : R →+* S} [I.IsTwoSided] : Function.Injective (quotientMap I f le_rfl) := quotientMap_injective' le_rfl -theorem quotientMap_surjective {J : Ideal R} {I : Ideal S} {f : R →+* S} {H : J ≤ I.comap f} +theorem quotientMap_surjective {J : Ideal R} {I : Ideal S} [I.IsTwoSided] [J.IsTwoSided] + {f : R →+* S} {H : J ≤ I.comap f} (hf : Function.Surjective f) : Function.Surjective (quotientMap I f H) := fun x => let ⟨x, hx⟩ := Quotient.mk_surjective x let ⟨y, hy⟩ := hf x ⟨(Quotient.mk J) y, by simp [hx, hy]⟩ /-- Commutativity of a square is preserved when taking quotients by an ideal. -/ -theorem comp_quotientMap_eq_of_comp_eq {R' S' : Type*} [CommRing R'] [CommRing S'] {f : R →+* S} - {f' : R' →+* S'} {g : R →+* R'} {g' : S →+* S'} (hfg : f'.comp g = g'.comp f) (I : Ideal S') : +theorem comp_quotientMap_eq_of_comp_eq {R' S' : Type*} [Ring R'] [Ring S'] {f : R →+* S} + {f' : R' →+* S'} {g : R →+* R'} {g' : S →+* S'} (hfg : f'.comp g = g'.comp f) + (I : Ideal S') [I.IsTwoSided] : -- Porting note: was losing track of I let leq := le_of_eq (_root_.trans (comap_comap (I := I) f g') (hfg ▸ comap_comap (I := I) g f')) (quotientMap I g' le_rfl).comp (quotientMap (I.comap g') f le_rfl) = @@ -548,31 +568,32 @@ theorem comp_quotientMap_eq_of_comp_eq {R' S' : Type*} [CommRing R'] [CommRing S exact (Ideal.Quotient.mk I).congr_arg (_root_.trans (g'.comp_apply f r).symm (hfg ▸ f'.comp_apply g r)) -end CommRing_CommRing +end Ring_Ring section -variable [CommRing B] [Algebra R₁ B] +variable [Ring B] [Algebra R₁ B] {I : Ideal A} (J : Ideal B) [I.IsTwoSided] [J.IsTwoSided] /-- The algebra hom `A/I →+* B/J` induced by an algebra hom `f : A →ₐ[R₁] B` with `I ≤ f⁻¹(J)`. -/ -def quotientMapₐ {I : Ideal A} (J : Ideal B) (f : A →ₐ[R₁] B) (hIJ : I ≤ J.comap f) : +def quotientMapₐ (f : A →ₐ[R₁] B) (hIJ : I ≤ J.comap f) : A ⧸ I →ₐ[R₁] B ⧸ J := { quotientMap J (f : A →+* B) hIJ with commutes' := fun r => by simp only [RingHom.toFun_eq_coe, quotientMap_algebraMap, AlgHom.coe_toRingHom, AlgHom.commutes, Quotient.mk_algebraMap] } @[simp] -theorem quotient_map_mkₐ {I : Ideal A} (J : Ideal B) (f : A →ₐ[R₁] B) (H : I ≤ J.comap f) {x : A} : +theorem quotient_map_mkₐ (f : A →ₐ[R₁] B) (H : I ≤ J.comap f) {x : A} : quotientMapₐ J f H (Quotient.mk I x) = Quotient.mkₐ R₁ J (f x) := rfl -theorem quotient_map_comp_mkₐ {I : Ideal A} (J : Ideal B) (f : A →ₐ[R₁] B) (H : I ≤ J.comap f) : +theorem quotient_map_comp_mkₐ (f : A →ₐ[R₁] B) (H : I ≤ J.comap f) : (quotientMapₐ J f H).comp (Quotient.mkₐ R₁ I) = (Quotient.mkₐ R₁ J).comp f := AlgHom.ext fun x => by simp only [quotient_map_mkₐ, Quotient.mkₐ_eq_mk, AlgHom.comp_apply] +variable (I) in /-- The algebra equiv `A/I ≃ₐ[R] B/J` induced by an algebra equiv `f : A ≃ₐ[R] B`, where`J = f(I)`. -/ -def quotientEquivAlg (I : Ideal A) (J : Ideal B) (f : A ≃ₐ[R₁] B) (hIJ : J = I.map (f : A →+* B)) : +def quotientEquivAlg (f : A ≃ₐ[R₁] B) (hIJ : J = I.map (f : A →+* B)) : (A ⧸ I) ≃ₐ[R₁] B ⧸ J := { quotientEquiv I J (f : A ≃+* B) hIJ with commutes' := fun r => by @@ -586,8 +607,9 @@ def quotientEquivAlg (I : Ideal A) (J : Ideal B) (f : A ≃ₐ[R₁] B) (hIJ : J end /-- If `P` lies over `p`, then `R / p` has a canonical map to `A / P`. -/ -abbrev Quotient.algebraQuotientOfLEComap [Algebra R A] {p : Ideal R} {P : Ideal A} - (h : p ≤ comap (algebraMap R A) P) : Algebra (R ⧸ p) (A ⧸ P) where +abbrev Quotient.algebraQuotientOfLEComap {R} [CommRing R] [Algebra R A] {p : Ideal R} + {P : Ideal A} [P.IsTwoSided] (h : p ≤ comap (algebraMap R A) P) : + Algebra (R ⧸ p) (A ⧸ P) where algebraMap := quotientMap P (algebraMap R A) h smul := Quotient.lift₂ (⟦· • ·⟧) fun r₁ a₁ r₂ a₂ hr ha ↦ Quotient.sound <| by have := h (p.quotientRel_def.mp hr) @@ -597,11 +619,14 @@ abbrev Quotient.algebraQuotientOfLEComap [Algebra R A] {p : Ideal R} {P : Ideal smul_def' := by rintro ⟨_⟩ ⟨_⟩; exact congr_arg (⟦·⟧) (Algebra.smul_def _ _) commutes' := by rintro ⟨_⟩ ⟨_⟩; exact congr_arg (⟦·⟧) (Algebra.commutes _ _) -instance (priority := 100) quotientAlgebra {I : Ideal A} [Algebra R A] : - Algebra (R ⧸ I.comap (algebraMap R A)) (A ⧸ I) := +instance (priority := 100) quotientAlgebra {R} [CommRing R] {I : Ideal A} [I.IsTwoSided] + [Algebra R A] : Algebra (R ⧸ I.comap (algebraMap R A)) (A ⧸ I) := Quotient.algebraQuotientOfLEComap le_rfl -theorem algebraMap_quotient_injective {I : Ideal A} [Algebra R A] : +instance (R) {A} [CommRing R] [CommRing A] (I : Ideal A) [Algebra R A] : + Algebra (R ⧸ I.comap (algebraMap R A)) (A ⧸ I) := inferInstance + +theorem algebraMap_quotient_injective {R} [CommRing R] {I : Ideal A} [I.IsTwoSided] [Algebra R A] : Function.Injective (algebraMap (R ⧸ I.comap (algebraMap R A)) (A ⧸ I)) := by rintro ⟨a⟩ ⟨b⟩ hab replace hab := Quotient.eq.mp hab @@ -611,29 +636,30 @@ theorem algebraMap_quotient_injective {I : Ideal A} [Algebra R A] : variable (R₁) /-- Quotienting by equal ideals gives equivalent algebras. -/ -def quotientEquivAlgOfEq {I J : Ideal A} (h : I = J) : (A ⧸ I) ≃ₐ[R₁] A ⧸ J := +def quotientEquivAlgOfEq {I J : Ideal A} [I.IsTwoSided] [J.IsTwoSided] (h : I = J) : + (A ⧸ I) ≃ₐ[R₁] A ⧸ J := quotientEquivAlg I J AlgEquiv.refl <| h ▸ (map_id I).symm @[simp] -theorem quotientEquivAlgOfEq_mk {I J : Ideal A} (h : I = J) (x : A) : +theorem quotientEquivAlgOfEq_mk {I J : Ideal A} [I.IsTwoSided] [J.IsTwoSided] (h : I = J) (x : A) : quotientEquivAlgOfEq R₁ h (Ideal.Quotient.mk I x) = Ideal.Quotient.mk J x := rfl @[simp] -theorem quotientEquivAlgOfEq_symm {I J : Ideal A} (h : I = J) : +theorem quotientEquivAlgOfEq_symm {I J : Ideal A} [I.IsTwoSided] [J.IsTwoSided] (h : I = J) : (quotientEquivAlgOfEq R₁ h).symm = quotientEquivAlgOfEq R₁ h.symm := by ext rfl -lemma comap_map_mk {I J : Ideal R} (h : I ≤ J) : +lemma comap_map_mk {I J : Ideal R} [I.IsTwoSided] (h : I ≤ J) : Ideal.comap (Ideal.Quotient.mk I) (Ideal.map (Ideal.Quotient.mk I) J) = J := by ext; rw [← Ideal.mem_quotient_iff_mem h, Ideal.mem_comap] /-- The **first isomorphism theorem** for commutative algebras (`AlgHom.range` version). -/ noncomputable def quotientKerEquivRange - {A B : Type*} [CommRing A] [Algebra R A] [Semiring B] [Algebra R B] - (f : A →ₐ[R] B) : - (A ⧸ RingHom.ker f) ≃ₐ[R] f.range := + {R A B : Type*} [CommSemiring R] [Ring A] [Algebra R A] [Semiring B] [Algebra R B] + (f : A →ₐ[R] B) : + (A ⧸ RingHom.ker f) ≃ₐ[R] f.range := (Ideal.quotientEquivAlgOfEq R (AlgHom.ker_rangeRestrict f).symm).trans <| Ideal.quotientKerAlgEquivOfSurjective f.rangeRestrict_surjective diff --git a/Mathlib/RingTheory/Jacobson/Ring.lean b/Mathlib/RingTheory/Jacobson/Ring.lean index aca96b49168c8..da7752d6430d3 100644 --- a/Mathlib/RingTheory/Jacobson/Ring.lean +++ b/Mathlib/RingTheory/Jacobson/Ring.lean @@ -548,7 +548,8 @@ theorem quotient_mk_comp_C_isIntegral_of_isJacobsonRing : refine fun p hp => polynomial_mem_ideal_of_coeff_mem_ideal P p fun n => Quotient.eq_zero_iff_mem.mp ?_ simpa only [f, coeff_map, coe_mapRingHom] using (Polynomial.ext_iff.mp hp) n - refine RingHom.IsIntegral.tower_bot _ _ (injective_quotient_le_comap_map P) ?_ + refine RingHom.IsIntegral.tower_bot + (T := (R ⧸ comap C P)[X] ⧸ _) _ _ (injective_quotient_le_comap_map P) ?_ rw [← quotient_mk_maps_eq] refine ((Ideal.Quotient.mk P').isIntegral_of_surjective Quotient.mk_surjective).trans _ _ ?_ have : IsMaximal (Ideal.map (mapRingHom (Ideal.Quotient.mk (comap C P))) P) := diff --git a/Mathlib/RingTheory/Polynomial/Quotient.lean b/Mathlib/RingTheory/Polynomial/Quotient.lean index ec63a3a57ca23..210c79ff2adf7 100644 --- a/Mathlib/RingTheory/Polynomial/Quotient.lean +++ b/Mathlib/RingTheory/Polynomial/Quotient.lean @@ -30,7 +30,7 @@ noncomputable def quotientSpanXSubCAlgEquivAux2 (x : R) : noncomputable def quotientSpanXSubCAlgEquivAux1 (x : R) : (R[X] ⧸ Ideal.span {X - C x}) ≃ₐ[R] (R[X] ⧸ (RingHom.ker (aeval x).toRingHom : Ideal R[X])) := - @Ideal.quotientEquivAlgOfEq R R[X] _ _ _ _ _ (ker_evalRingHom x).symm + Ideal.quotientEquivAlgOfEq R (ker_evalRingHom x).symm -- Porting note: need to split this definition into two sub-definitions to prevent time out /-- For a commutative ring $R$, evaluating a polynomial at an element $x \in R$ induces an diff --git a/docs/overview.yaml b/docs/overview.yaml index 8a37e088447d8..eb1ed4c1001c6 100644 --- a/docs/overview.yaml +++ b/docs/overview.yaml @@ -63,7 +63,7 @@ General algebra: Ideals and quotients: ideal of a commutative ring: 'Ideal' - quotient ring: 'Ideal.instHasQuotient' + quotient ring: 'Ideal.Quotient.ring' prime ideal: 'Ideal.IsPrime' maximal ideal: 'Ideal.IsMaximal' Chinese remainder theorem: 'Ideal.quotientInfRingEquivPiQuotient' diff --git a/docs/undergrad.yaml b/docs/undergrad.yaml index 7b92a0cf93e13..2edba86a22602 100644 --- a/docs/undergrad.yaml +++ b/docs/undergrad.yaml @@ -130,7 +130,7 @@ Ring Theory: product of rings: 'Pi.ring' Ideals and Quotients: ideal of a commutative ring: 'Ideal' - quotient rings: 'Ideal.instHasQuotient' + quotient rings: 'Ideal.Quotient.ring' prime ideals: 'Ideal.IsPrime' maximal ideals: 'Ideal.IsMaximal' Chinese remainder theorem: 'Ideal.quotientInfRingEquivPiQuotient' From b4c61c012f88770ee888c9fb6f40fee0ff33c339 Mon Sep 17 00:00:00 2001 From: grunweg Date: Tue, 4 Feb 2025 15:13:05 +0000 Subject: [PATCH 071/103] chore(Geometry/Manifold/IsManifold): split out material on extended charts (#21219) Fixes a `longFile` linter warning. A few lemmas about topological manifolds also used extended charts, hence were moved to the new file also. --- Mathlib.lean | 1 + Mathlib/Geometry/Manifold/ContMDiff/Defs.lean | 2 +- .../Geometry/Manifold/IsManifold/Basic.lean | 794 +---------------- .../Manifold/IsManifold/ExtChartAt.lean | 816 ++++++++++++++++++ .../Manifold/IsManifold/InteriorBoundary.lean | 2 +- Mathlib/Geometry/Manifold/MFDeriv/Defs.lean | 2 +- 6 files changed, 821 insertions(+), 796 deletions(-) create mode 100644 Mathlib/Geometry/Manifold/IsManifold/ExtChartAt.lean diff --git a/Mathlib.lean b/Mathlib.lean index 338fabb0ba3dc..e569f1892a12f 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -3249,6 +3249,7 @@ import Mathlib.Geometry.Manifold.IntegralCurve.ExistUnique import Mathlib.Geometry.Manifold.IntegralCurve.Transform import Mathlib.Geometry.Manifold.IntegralCurve.UniformTime import Mathlib.Geometry.Manifold.IsManifold.Basic +import Mathlib.Geometry.Manifold.IsManifold.ExtChartAt import Mathlib.Geometry.Manifold.IsManifold.InteriorBoundary import Mathlib.Geometry.Manifold.LocalDiffeomorph import Mathlib.Geometry.Manifold.LocalInvariantProperties diff --git a/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean b/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean index ee537cfccc4d7..2852c1af58ac8 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel, Floris van Doorn -/ -import Mathlib.Geometry.Manifold.IsManifold.Basic +import Mathlib.Geometry.Manifold.IsManifold.ExtChartAt import Mathlib.Geometry.Manifold.LocalInvariantProperties /-! diff --git a/Mathlib/Geometry/Manifold/IsManifold/Basic.lean b/Mathlib/Geometry/Manifold/IsManifold/Basic.lean index 069cea5c3f202..9b9e495736d1a 100644 --- a/Mathlib/Geometry/Manifold/IsManifold/Basic.lean +++ b/Mathlib/Geometry/Manifold/IsManifold/Basic.lean @@ -39,12 +39,6 @@ but add these assumptions later as needed. (Quite a few results still do not req a type class saying that the charted space `M`, modelled on the space `H`, has `C^n` changes of coordinates with respect to the model with corners `I` on `(𝕜, E, H)`. This type class is just a shortcut for `HasGroupoid M (contDiffGroupoid n I)`. -* `extChartAt I x`: - in a `C^n` manifold with corners with the model `I` on `(E, H)`, the charts take values in `H`, - but often we may want to use their `E`-valued version, obtained by composing the charts with `I`. - Since the target is in general not open, we can not register them as partial homeomorphisms, but - we register them as `PartialEquiv`s. - `extChartAt I x` is the canonical such partial equiv around `x`. We define a few constructions of smooth manifolds: * every empty type is a smooth manifold @@ -138,7 +132,7 @@ universe u v w u' v' w' open Set Filter Function -open scoped Manifold Filter Topology ContDiff +open scoped Manifold Topology ContDiff /-! ### Models with corners. -/ @@ -893,790 +887,6 @@ instance : IsManifold I n s := end TopologicalSpace.Opens -section ExtendedCharts - -open scoped Topology - -variable {𝕜 E M H E' M' H' : Type*} [NontriviallyNormedField 𝕜] [NormedAddCommGroup E] - [NormedSpace 𝕜 E] [TopologicalSpace H] [TopologicalSpace M] {n : WithTop ℕ∞} - (f f' : PartialHomeomorph M H) - {I : ModelWithCorners 𝕜 E H} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] [TopologicalSpace H'] - [TopologicalSpace M'] {I' : ModelWithCorners 𝕜 E' H'} {s t : Set M} - -/-! -### Extended charts - -In a `C^n` 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 `PartialHomeomorph` as the target is not open in `E` in general, but we can still register them -as `PartialEquiv`. --/ - - -namespace PartialHomeomorph - -variable (I) in -/-- 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 : PartialEquiv M E := - f.toPartialEquiv ≫ I.toPartialEquiv - -theorem extend_coe : ⇑(f.extend I) = I ∘ f := - rfl - -theorem extend_coe_symm : ⇑(f.extend I).symm = f.symm ∘ I.symm := - rfl - -theorem extend_source : (f.extend I).source = f.source := by - rw [extend, PartialEquiv.trans_source, I.source_eq, preimage_univ, inter_univ] - -theorem isOpen_extend_source : IsOpen (f.extend I).source := by - rw [extend_source] - exact f.open_source - -theorem extend_target : (f.extend I).target = I.symm ⁻¹' f.target ∩ range I := by - simp_rw [extend, PartialEquiv.trans_target, I.target_eq, I.toPartialEquiv_coe_symm, inter_comm] - -theorem extend_target' : (f.extend I).target = I '' f.target := by - rw [extend, PartialEquiv.trans_target'', I.source_eq, univ_inter, I.toPartialEquiv_coe] - -lemma isOpen_extend_target [I.Boundaryless] : IsOpen (f.extend I).target := by - rw [extend_target, I.range_eq_univ, inter_univ] - exact I.continuous_symm.isOpen_preimage _ f.open_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 - -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] - -/-- 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 := - EqOn.image_eq_self (fun _ hx ↦ f.extend_left_inv (ht hx)) - -theorem extend_source_mem_nhds {x : M} (h : x ∈ f.source) : (f.extend I).source ∈ 𝓝 x := - (isOpen_extend_source f).mem_nhds <| by rwa [f.extend_source] - -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 h - -theorem continuousOn_extend : ContinuousOn (f.extend I) (f.extend I).source := by - refine I.continuous.comp_continuousOn ?_ - rw [extend_source] - exact f.continuousOn - -theorem continuousAt_extend {x : M} (h : x ∈ f.source) : ContinuousAt (f.extend I) x := - (continuousOn_extend f).continuousAt <| extend_source_mem_nhds f h - -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] - -theorem map_extend_nhds_of_mem_interior_range {x : M} (hx : x ∈ f.source) - (h'x : f.extend I x ∈ interior (range I)) : - map (f.extend I) (𝓝 x) = 𝓝 (f.extend I x) := by - rw [f.map_extend_nhds hx, nhdsWithin_eq_nhds] - exact mem_of_superset (isOpen_interior.mem_nhds h'x) interior_subset - -theorem map_extend_nhds_of_boundaryless [I.Boundaryless] {x : M} (hx : x ∈ f.source) : - map (f.extend I) (𝓝 x) = 𝓝 (f.extend I x) := by - rw [f.map_extend_nhds hx, I.range_eq_univ, nhdsWithin_univ] - -theorem extend_target_mem_nhdsWithin {y : M} (hy : y ∈ f.source) : - (f.extend I).target ∈ 𝓝[range I] f.extend I y := by - rw [← PartialEquiv.image_source_eq_target, ← map_extend_nhds f hy] - exact image_mem_map (extend_source_mem_nhds _ hy) - -theorem extend_image_nhd_mem_nhds_of_boundaryless [I.Boundaryless] {x} (hx : x ∈ f.source) - {s : Set M} (h : s ∈ 𝓝 x) : (f.extend I) '' s ∈ 𝓝 ((f.extend I) x) := by - rw [← f.map_extend_nhds_of_boundaryless hx, Filter.mem_map] - filter_upwards [h] using subset_preimage_image (f.extend I) s - -theorem extend_image_nhd_mem_nhds_of_mem_interior_range {x} (hx : x ∈ f.source) - (h'x : f.extend I x ∈ interior (range I)) {s : Set M} (h : s ∈ 𝓝 x) : - (f.extend I) '' s ∈ 𝓝 ((f.extend I) x) := by - rw [← f.map_extend_nhds_of_mem_interior_range hx h'x, Filter.mem_map] - filter_upwards [h] using subset_preimage_image (f.extend I) s - -theorem extend_target_subset_range : (f.extend I).target ⊆ range I := by simp only [mfld_simps] - -lemma interior_extend_target_subset_interior_range : - interior (f.extend I).target ⊆ interior (range I) := by - rw [f.extend_target, interior_inter, (f.open_target.preimage I.continuous_symm).interior_eq] - exact inter_subset_right - -/-- If `y ∈ f.target` and `I y ∈ interior (range I)`, - then `I y` is an interior point of `(I ∘ f).target`. -/ -lemma mem_interior_extend_target {y : H} (hy : y ∈ f.target) - (hy' : I y ∈ interior (range I)) : I y ∈ interior (f.extend I).target := by - rw [f.extend_target, interior_inter, (f.open_target.preimage I.continuous_symm).interior_eq, - mem_inter_iff, mem_preimage] - exact ⟨mem_of_eq_of_mem (I.left_inv (y)) hy, hy'⟩ - -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) - -theorem extend_target_eventuallyEq {y : M} (hy : y ∈ f.source) : - (f.extend I).target =ᶠ[𝓝 (f.extend I y)] range I := - nhdsWithin_eq_iff_eventuallyEq.1 (nhdsWithin_extend_target_eq _ hy) - -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 - -theorem continuousAt_extend_symm {x : M} (h : x ∈ f.source) : - ContinuousAt (f.extend I).symm (f.extend I x) := - continuousAt_extend_symm' f <| (f.extend I).map_source <| by rwa [f.extend_source] - -theorem continuousOn_extend_symm : ContinuousOn (f.extend I).symm (f.extend I).target := fun _ h => - (continuousAt_extend_symm' _ h).continuousWithinAt - -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 - -theorem isOpen_extend_preimage' {s : Set E} (hs : IsOpen s) : - IsOpen ((f.extend I).source ∩ f.extend I ⁻¹' s) := - (continuousOn_extend f).isOpen_inter_preimage (isOpen_extend_source _) hs - -theorem isOpen_extend_preimage {s : Set E} (hs : IsOpen s) : - IsOpen (f.source ∩ f.extend I ⁻¹' s) := by - rw [← extend_source f (I := I)]; exact isOpen_extend_preimage' f hs - -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 - set e := f.extend I - calc - map e (𝓝[s] y) = map e (𝓝[e.source ∩ s] y) := - congr_arg (map e) (nhdsWithin_inter_of_mem (extend_source_mem_nhdsWithin f hy)).symm - _ = 𝓝[e '' (e.source ∩ s)] e y := - ((f.extend I).leftInvOn.mono inter_subset_left).map_nhdsWithin_eq - ((f.extend I).left_inv <| by rwa [f.extend_source]) - (continuousAt_extend_symm f hy).continuousWithinAt - (continuousAt_extend f hy).continuousWithinAt - -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 - rw [map_extend_nhdsWithin_eq_image _ hy, inter_eq_self_of_subset_right] - rwa [extend_source] - -theorem map_extend_nhdsWithin {y : M} (hy : y ∈ f.source) : - map (f.extend I) (𝓝[s] y) = 𝓝[(f.extend I).symm ⁻¹' s ∩ range I] f.extend I y := by - rw [map_extend_nhdsWithin_eq_image f hy, nhdsWithin_inter, ← - nhdsWithin_extend_target_eq _ hy, ← nhdsWithin_inter, (f.extend I).image_source_inter_eq', - inter_comm] - -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 hy, map_map, Filter.map_congr, map_id] - exact (f.extend I).leftInvOn.eqOn.eventuallyEq_of_mem (extend_source_mem_nhdsWithin _ hy) - -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 := I) hy, preimage_univ, univ_inter] - -theorem tendsto_extend_comp_iff {α : Type*} {l : Filter α} {g : α → M} - (hg : ∀ᶠ z in l, g z ∈ f.source) {y : M} (hy : y ∈ f.source) : - Tendsto (f.extend I ∘ g) l (𝓝 (f.extend I y)) ↔ Tendsto g l (𝓝 y) := by - refine ⟨fun h u hu ↦ mem_map.2 ?_, (continuousAt_extend _ hy).tendsto.comp⟩ - have := (f.continuousAt_extend_symm hy).tendsto.comp h - rw [extend_left_inv _ hy] at this - filter_upwards [hg, mem_map.1 (this hu)] with z hz hzu - 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' : PartialHomeomorph M' H'} {g : M → M'} {y : 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 - unfold ContinuousWithinAt - simp only [comp_apply] - rw [extend_left_inv _ hy, f'.tendsto_extend_comp_iff _ hgy, - ← f.map_extend_symm_nhdsWithin (I := I) hy, tendsto_map'_iff] - rw [← f.map_extend_nhdsWithin (I := I) hy, eventually_map] - filter_upwards [inter_mem_nhdsWithin _ (f.open_source.mem_nhds hy)] with z hz - rw [comp_apply, extend_left_inv _ hz.2] - exact hmaps hz.1 - --- there is no definition `writtenInExtend` but we already use some made-up names in this file - -/-- 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' : 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 forall_mem_image.trans <| forall₂_congr fun x hx ↦ ?_ - refine (continuousWithinAt_congr_set ?_).trans - (continuousWithinAt_writtenInExtend_iff _ (hs hx) (hmaps hx) hmaps) - rw [← nhdsWithin_eq_iff_eventuallyEq, ← map_extend_nhdsWithin_eq_image_of_subset, - ← map_extend_nhdsWithin] - exacts [hs hx, hs hx, hs] - -/-- Technical lemma ensuring that the preimage under an extended chart of a neighborhood of a point -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 := I) h, mem_map] at ht - -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 h).preimage_mem_nhds - rwa [(f.extend I).left_inv] - rwa [f.extend_source] - -/-- 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. -/ -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 - --- 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) : - ((f.extend I).symm ⁻¹' s ∩ range I : Set _) =ᶠ[𝓝 (f.extend I x)] - ((f.extend I).target ∩ (f.extend I).symm ⁻¹' s : Set _) := by - rw [f.extend_target, inter_assoc, inter_comm (range I)] - conv => - congr - · skip - rw [← univ_inter (_ ∩ range I)] - 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] - -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] - -/-! 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 [PartialEquiv.trans_source, I.image_eq, extend_source, PartialEquiv.symm_source, - extend_target, inter_right_comm _ (range I)] - rfl - -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] - -theorem extend_coord_change_source_mem_nhdsWithin {x : E} - (hx : x ∈ ((f.extend I).symm ≫ f'.extend I).source) : - ((f.extend I).symm ≫ f'.extend I).source ∈ 𝓝[range I] x := by - rw [f.extend_coord_change_source] at hx ⊢ - obtain ⟨x, hx, rfl⟩ := hx - refine I.image_mem_nhdsWithin ?_ - exact (PartialHomeomorph.open_source _).mem_nhds hx - -theorem extend_coord_change_source_mem_nhdsWithin' {x : M} (hxf : x ∈ f.source) - (hxf' : x ∈ f'.source) : - ((f.extend I).symm ≫ f'.extend I).source ∈ 𝓝[range I] f.extend I x := by - apply extend_coord_change_source_mem_nhdsWithin - rw [← extend_image_source_inter] - exact mem_image_of_mem _ ⟨hxf, hxf'⟩ - -variable {f f'} - -open IsManifold - -theorem contDiffOn_extend_coord_change [ChartedSpace H M] (hf : f ∈ maximalAtlas I n M) - (hf' : f' ∈ maximalAtlas I n M) : - ContDiffOn 𝕜 n (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 - -theorem contDiffWithinAt_extend_coord_change [ChartedSpace H M] (hf : f ∈ maximalAtlas I n M) - (hf' : f' ∈ maximalAtlas I n M) {x : E} (hx : x ∈ ((f'.extend I).symm ≫ f.extend I).source) : - ContDiffWithinAt 𝕜 n (f.extend I ∘ (f'.extend I).symm) (range I) x := by - apply (contDiffOn_extend_coord_change hf hf' x hx).mono_of_mem_nhdsWithin - rw [extend_coord_change_source] at hx ⊢ - obtain ⟨z, hz, rfl⟩ := hx - exact I.image_mem_nhdsWithin ((PartialHomeomorph.open_source _).mem_nhds hz) - -theorem contDiffWithinAt_extend_coord_change' [ChartedSpace H M] (hf : f ∈ maximalAtlas I n M) - (hf' : f' ∈ maximalAtlas I n M) {x : M} (hxf : x ∈ f.source) (hxf' : x ∈ f'.source) : - ContDiffWithinAt 𝕜 n (f.extend I ∘ (f'.extend I).symm) (range I) (f'.extend I x) := by - refine contDiffWithinAt_extend_coord_change hf hf' ?_ - rw [← extend_image_source_inter] - exact mem_image_of_mem _ ⟨hxf', hxf⟩ - -end PartialHomeomorph - -open PartialHomeomorph - -variable [ChartedSpace H M] [ChartedSpace H' M'] - -variable (I) in -/-- 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) : PartialEquiv M E := - (chartAt H x).extend I - -theorem extChartAt_coe (x : M) : ⇑(extChartAt I x) = I ∘ chartAt H x := - rfl - -theorem extChartAt_coe_symm (x : M) : ⇑(extChartAt I x).symm = (chartAt H x).symm ∘ I.symm := - rfl - -variable (I) in -theorem extChartAt_source (x : M) : (extChartAt I x).source = (chartAt H x).source := - extend_source _ - -theorem isOpen_extChartAt_source (x : M) : IsOpen (extChartAt I x).source := - isOpen_extend_source _ - -theorem mem_extChartAt_source (x : M) : x ∈ (extChartAt I x).source := by - simp only [extChartAt_source, mem_chart_source] - -theorem mem_extChartAt_target (x : M) : extChartAt I x x ∈ (extChartAt I x).target := - (extChartAt I x).map_source <| mem_extChartAt_source _ - -variable (I) in -theorem extChartAt_target (x : M) : - (extChartAt I x).target = I.symm ⁻¹' (chartAt H x).target ∩ range I := - extend_target _ - -theorem uniqueDiffOn_extChartAt_target (x : M) : UniqueDiffOn 𝕜 (extChartAt I x).target := by - rw [extChartAt_target] - exact I.uniqueDiffOn_preimage (chartAt H x).open_target - -theorem uniqueDiffWithinAt_extChartAt_target (x : M) : - UniqueDiffWithinAt 𝕜 (extChartAt I x).target (extChartAt I x x) := - uniqueDiffOn_extChartAt_target x _ <| mem_extChartAt_target x - -theorem extChartAt_to_inv (x : M) : (extChartAt I x).symm ((extChartAt I x) x) = x := - (extChartAt I x).left_inv (mem_extChartAt_source x) - -theorem mapsTo_extChartAt {x : M} (hs : s ⊆ (chartAt H x).source) : - MapsTo (extChartAt I x) s ((extChartAt I x).symm ⁻¹' s ∩ range I) := - mapsTo_extend _ hs - -theorem extChartAt_source_mem_nhds' {x x' : M} (h : x' ∈ (extChartAt I x).source) : - (extChartAt I x).source ∈ 𝓝 x' := - extend_source_mem_nhds _ <| by rwa [← extChartAt_source I] - -theorem extChartAt_source_mem_nhds (x : M) : (extChartAt I x).source ∈ 𝓝 x := - extChartAt_source_mem_nhds' (mem_extChartAt_source x) - -theorem extChartAt_source_mem_nhdsWithin' {x x' : M} (h : x' ∈ (extChartAt I x).source) : - (extChartAt I x).source ∈ 𝓝[s] x' := - mem_nhdsWithin_of_mem_nhds (extChartAt_source_mem_nhds' h) - -theorem extChartAt_source_mem_nhdsWithin (x : M) : (extChartAt I x).source ∈ 𝓝[s] x := - mem_nhdsWithin_of_mem_nhds (extChartAt_source_mem_nhds x) - -theorem continuousOn_extChartAt (x : M) : ContinuousOn (extChartAt I x) (extChartAt I x).source := - continuousOn_extend _ - -theorem continuousAt_extChartAt' {x x' : M} (h : x' ∈ (extChartAt I x).source) : - ContinuousAt (extChartAt I x) x' := - continuousAt_extend _ <| by rwa [← extChartAt_source I] - -theorem continuousAt_extChartAt (x : M) : ContinuousAt (extChartAt I x) x := - continuousAt_extChartAt' (mem_extChartAt_source x) - -theorem map_extChartAt_nhds' {x y : M} (hy : y ∈ (extChartAt I x).source) : - map (extChartAt I x) (𝓝 y) = 𝓝[range I] extChartAt I x y := - map_extend_nhds _ <| by rwa [← extChartAt_source I] - -theorem map_extChartAt_nhds (x : M) : map (extChartAt I x) (𝓝 x) = 𝓝[range I] extChartAt I x x := - map_extChartAt_nhds' <| mem_extChartAt_source x - -theorem map_extChartAt_nhds_of_boundaryless [I.Boundaryless] (x : M) : - map (extChartAt I x) (𝓝 x) = 𝓝 (extChartAt I x x) := by - rw [extChartAt] - exact map_extend_nhds_of_boundaryless (chartAt H x) (mem_chart_source H x) - -theorem extChartAt_image_nhd_mem_nhds_of_mem_interior_range {x y} (hx : y ∈ (extChartAt I x).source) - (h'x : extChartAt I x y ∈ interior (range I)) {s : Set M} (h : s ∈ 𝓝 y) : - (extChartAt I x) '' s ∈ 𝓝 (extChartAt I x y) := by - rw [extChartAt] - exact extend_image_nhd_mem_nhds_of_mem_interior_range _ (by simpa using hx) h'x h - -variable {x} in -theorem extChartAt_image_nhd_mem_nhds_of_boundaryless [I.Boundaryless] - {x : M} (hx : s ∈ 𝓝 x) : extChartAt I x '' s ∈ 𝓝 (extChartAt I x x) := by - rw [extChartAt] - exact extend_image_nhd_mem_nhds_of_boundaryless _ (mem_chart_source H x) hx - -theorem extChartAt_target_mem_nhdsWithin' {x y : M} (hy : y ∈ (extChartAt I x).source) : - (extChartAt I x).target ∈ 𝓝[range I] extChartAt I x y := - extend_target_mem_nhdsWithin _ <| by rwa [← extChartAt_source I] - -theorem extChartAt_target_mem_nhdsWithin (x : M) : - (extChartAt I x).target ∈ 𝓝[range I] extChartAt I x x := - extChartAt_target_mem_nhdsWithin' (mem_extChartAt_source x) - -theorem extChartAt_target_mem_nhdsWithin_of_mem {x : M} {y : E} (hy : y ∈ (extChartAt I x).target) : - (extChartAt I x).target ∈ 𝓝[range I] y := by - rw [← (extChartAt I x).right_inv hy] - apply extChartAt_target_mem_nhdsWithin' - exact (extChartAt I x).map_target hy - -theorem extChartAt_target_union_compl_range_mem_nhds_of_mem {y : E} {x : M} - (hy : y ∈ (extChartAt I x).target) : (extChartAt I x).target ∪ (range I)ᶜ ∈ 𝓝 y := by - rw [← nhdsWithin_univ, ← union_compl_self (range I), nhdsWithin_union] - exact Filter.union_mem_sup (extChartAt_target_mem_nhdsWithin_of_mem hy) self_mem_nhdsWithin - -@[deprecated (since := "2024-11-27")] alias -extChartAt_target_union_comp_range_mem_nhds_of_mem := -extChartAt_target_union_compl_range_mem_nhds_of_mem - -/-- If we're boundaryless, `extChartAt` has open target -/ -theorem isOpen_extChartAt_target [I.Boundaryless] (x : M) : IsOpen (extChartAt I x).target := by - simp_rw [extChartAt_target, I.range_eq_univ, inter_univ] - exact (PartialHomeomorph.open_target _).preimage I.continuous_symm - -/-- If we're boundaryless, `(extChartAt I x).target` is a neighborhood of the key point -/ -theorem extChartAt_target_mem_nhds [I.Boundaryless] (x : M) : - (extChartAt I x).target ∈ 𝓝 (extChartAt I x x) := by - convert extChartAt_target_mem_nhdsWithin x - simp only [I.range_eq_univ, nhdsWithin_univ] - -/-- If we're boundaryless, `(extChartAt I x).target` is a neighborhood of any of its points -/ -theorem extChartAt_target_mem_nhds' [I.Boundaryless] {x : M} {y : E} - (m : y ∈ (extChartAt I x).target) : (extChartAt I x).target ∈ 𝓝 y := - (isOpen_extChartAt_target x).mem_nhds m - -theorem extChartAt_target_subset_range (x : M) : (extChartAt I x).target ⊆ range I := by - simp only [mfld_simps] - -/-- Around the image of a point in the source, the neighborhoods are the same -within `(extChartAt I x).target` and within `range I`. -/ -theorem nhdsWithin_extChartAt_target_eq' {x y : M} (hy : y ∈ (extChartAt I x).source) : - 𝓝[(extChartAt I x).target] extChartAt I x y = 𝓝[range I] extChartAt I x y := - nhdsWithin_extend_target_eq _ <| by rwa [← extChartAt_source I] - -/-- Around a point in the target, the neighborhoods are the same within `(extChartAt I x).target` -and within `range I`. -/ -theorem nhdsWithin_extChartAt_target_eq_of_mem {x : M} {z : E} (hz : z ∈ (extChartAt I x).target) : - 𝓝[(extChartAt I x).target] z = 𝓝[range I] z := by - rw [← PartialEquiv.right_inv (extChartAt I x) hz] - exact nhdsWithin_extChartAt_target_eq' ((extChartAt I x).map_target hz) - -/-- Around the image of the base point, the neighborhoods are the same -within `(extChartAt I x).target` and within `range I`. -/ -theorem nhdsWithin_extChartAt_target_eq (x : M) : - 𝓝[(extChartAt I x).target] (extChartAt I x) x = 𝓝[range I] (extChartAt I x) x := - nhdsWithin_extChartAt_target_eq' (mem_extChartAt_source x) - -/-- Around the image of a point in the source, `(extChartAt I x).target` and `range I` -coincide locally. -/ -theorem extChartAt_target_eventuallyEq' {x y : M} (hy : y ∈ (extChartAt I x).source) : - (extChartAt I x).target =ᶠ[𝓝 (extChartAt I x y)] range I := - nhdsWithin_eq_iff_eventuallyEq.1 (nhdsWithin_extChartAt_target_eq' hy) - -/-- Around a point in the target, `(extChartAt I x).target` and `range I` coincide locally. -/ -theorem extChartAt_target_eventuallyEq_of_mem {x : M} {z : E} (hz : z ∈ (extChartAt I x).target) : - (extChartAt I x).target =ᶠ[𝓝 z] range I := - nhdsWithin_eq_iff_eventuallyEq.1 (nhdsWithin_extChartAt_target_eq_of_mem hz) - -/-- Around the image of the base point, `(extChartAt I x).target` and `range I` coincide locally. -/ -theorem extChartAt_target_eventuallyEq {x : M} : - (extChartAt I x).target =ᶠ[𝓝 (extChartAt I x x)] range I := - nhdsWithin_eq_iff_eventuallyEq.1 (nhdsWithin_extChartAt_target_eq x) - -theorem continuousAt_extChartAt_symm'' {x : M} {y : E} (h : y ∈ (extChartAt I x).target) : - ContinuousAt (extChartAt I x).symm y := - continuousAt_extend_symm' _ h - -theorem continuousAt_extChartAt_symm' {x x' : M} (h : x' ∈ (extChartAt I x).source) : - ContinuousAt (extChartAt I x).symm (extChartAt I x x') := - continuousAt_extChartAt_symm'' <| (extChartAt I x).map_source h - -theorem continuousAt_extChartAt_symm (x : M) : - ContinuousAt (extChartAt I x).symm ((extChartAt I x) x) := - continuousAt_extChartAt_symm' (mem_extChartAt_source x) - -theorem continuousOn_extChartAt_symm (x : M) : - ContinuousOn (extChartAt I x).symm (extChartAt I x).target := - fun _y hy => (continuousAt_extChartAt_symm'' hy).continuousWithinAt - -lemma extChartAt_target_subset_closure_interior {x : M} : - (extChartAt I x).target ⊆ closure (interior (extChartAt I x).target) := by - intro y hy - rw [mem_closure_iff_nhds] - intro t ht - have A : t ∩ ((extChartAt I x).target ∪ (range I)ᶜ) ∈ 𝓝 y := - inter_mem ht (extChartAt_target_union_compl_range_mem_nhds_of_mem hy) - have B : y ∈ closure (interior (range I)) := by - apply I.range_subset_closure_interior (extChartAt_target_subset_range x hy) - obtain ⟨z, ⟨tz, h'z⟩, hz⟩ : - (t ∩ ((extChartAt I x).target ∪ (range ↑I)ᶜ) ∩ interior (range I)).Nonempty := - mem_closure_iff_nhds.1 B _ A - refine ⟨z, ⟨tz, ?_⟩⟩ - have h''z : z ∈ (extChartAt I x).target := by simpa [interior_subset hz] using h'z - exact (extChartAt_target_eventuallyEq_of_mem h''z).symm.mem_interior hz - -variable (I) in -theorem interior_extChartAt_target_nonempty (x : M) : - (interior (extChartAt I x).target).Nonempty := by - by_contra! H - have := extChartAt_target_subset_closure_interior (mem_extChartAt_target (I := I) x) - simp only [H, closure_empty, mem_empty_iff_false] at this - -lemma extChartAt_mem_closure_interior {x₀ x : M} - (hx : x ∈ closure (interior s)) (h'x : x ∈ (extChartAt I x₀).source) : - extChartAt I x₀ x ∈ - closure (interior ((extChartAt I x₀).symm ⁻¹' s ∩ (extChartAt I x₀).target)) := by - simp_rw [mem_closure_iff, interior_inter, ← inter_assoc] - intro o o_open ho - obtain ⟨y, ⟨yo, hy⟩, ys⟩ : - ((extChartAt I x₀) ⁻¹' o ∩ (extChartAt I x₀).source ∩ interior s).Nonempty := by - have : (extChartAt I x₀) ⁻¹' o ∈ 𝓝 x := by - apply (continuousAt_extChartAt' h'x).preimage_mem_nhds (o_open.mem_nhds ho) - refine (mem_closure_iff_nhds.1 hx) _ (inter_mem this ?_) - apply (isOpen_extChartAt_source x₀).mem_nhds h'x - have A : interior (↑(extChartAt I x₀).symm ⁻¹' s) ∈ 𝓝 (extChartAt I x₀ y) := by - simp only [interior_mem_nhds] - apply (continuousAt_extChartAt_symm' hy).preimage_mem_nhds - simp only [hy, PartialEquiv.left_inv] - exact mem_interior_iff_mem_nhds.mp ys - have B : (extChartAt I x₀) y ∈ closure (interior (extChartAt I x₀).target) := by - apply extChartAt_target_subset_closure_interior (x := x₀) - exact (extChartAt I x₀).map_source hy - exact mem_closure_iff_nhds.1 B _ (inter_mem (o_open.mem_nhds yo) A) - -theorem isOpen_extChartAt_preimage' (x : M) {s : Set E} (hs : IsOpen s) : - IsOpen ((extChartAt I x).source ∩ extChartAt I x ⁻¹' s) := - isOpen_extend_preimage' _ hs - -theorem isOpen_extChartAt_preimage (x : M) {s : Set E} (hs : IsOpen s) : - IsOpen ((chartAt H x).source ∩ extChartAt I x ⁻¹' s) := by - rw [← extChartAt_source I] - exact isOpen_extChartAt_preimage' x hs - -theorem map_extChartAt_nhdsWithin_eq_image' {x y : M} (hy : y ∈ (extChartAt I x).source) : - map (extChartAt I x) (𝓝[s] y) = - 𝓝[extChartAt I x '' ((extChartAt I x).source ∩ s)] extChartAt I x y := - map_extend_nhdsWithin_eq_image _ <| by rwa [← extChartAt_source I] - -theorem map_extChartAt_nhdsWithin_eq_image (x : M) : - map (extChartAt I x) (𝓝[s] x) = - 𝓝[extChartAt I x '' ((extChartAt I x).source ∩ s)] extChartAt I x x := - map_extChartAt_nhdsWithin_eq_image' (mem_extChartAt_source x) - -theorem map_extChartAt_nhdsWithin' {x y : M} (hy : y ∈ (extChartAt I x).source) : - map (extChartAt I x) (𝓝[s] y) = 𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] extChartAt I x y := - map_extend_nhdsWithin _ <| by rwa [← extChartAt_source I] - -theorem map_extChartAt_nhdsWithin (x : M) : - map (extChartAt I x) (𝓝[s] x) = 𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] extChartAt I x x := - map_extChartAt_nhdsWithin' (mem_extChartAt_source x) - -theorem map_extChartAt_symm_nhdsWithin' {x y : M} (hy : y ∈ (extChartAt I x).source) : - map (extChartAt I x).symm (𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] extChartAt I x y) = - 𝓝[s] y := - map_extend_symm_nhdsWithin _ <| by rwa [← extChartAt_source I] - -theorem map_extChartAt_symm_nhdsWithin_range' {x y : M} (hy : y ∈ (extChartAt I x).source) : - map (extChartAt I x).symm (𝓝[range I] extChartAt I x y) = 𝓝 y := - map_extend_symm_nhdsWithin_range _ <| by rwa [← extChartAt_source I] - -theorem map_extChartAt_symm_nhdsWithin (x : M) : - map (extChartAt I x).symm (𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] extChartAt I x x) = - 𝓝[s] x := - map_extChartAt_symm_nhdsWithin' (mem_extChartAt_source x) - -theorem map_extChartAt_symm_nhdsWithin_range (x : M) : - map (extChartAt I x).symm (𝓝[range I] extChartAt I x x) = 𝓝 x := - map_extChartAt_symm_nhdsWithin_range' (mem_extChartAt_source x) - -/-- Technical lemma ensuring that the preimage under an extended chart of a neighborhood of a point -in the source is a neighborhood of the preimage, within a set. -/ -theorem extChartAt_preimage_mem_nhdsWithin' {x x' : M} (h : x' ∈ (extChartAt I x).source) - (ht : t ∈ 𝓝[s] x') : - (extChartAt I x).symm ⁻¹' t ∈ 𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] (extChartAt I x) x' := by - rwa [← map_extChartAt_symm_nhdsWithin' h, mem_map] at ht - -/-- Technical lemma ensuring that the preimage under an extended chart of a neighborhood of the -base point is a neighborhood of the preimage, within a set. -/ -theorem extChartAt_preimage_mem_nhdsWithin {x : M} (ht : t ∈ 𝓝[s] x) : - (extChartAt I x).symm ⁻¹' t ∈ 𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] (extChartAt I x) x := - extChartAt_preimage_mem_nhdsWithin' (mem_extChartAt_source x) ht - -theorem extChartAt_preimage_mem_nhds' {x x' : M} (h : x' ∈ (extChartAt I x).source) - (ht : t ∈ 𝓝 x') : (extChartAt I x).symm ⁻¹' t ∈ 𝓝 (extChartAt I x x') := - extend_preimage_mem_nhds _ (by rwa [← extChartAt_source I]) ht - -/-- Technical lemma ensuring that the preimage under an extended chart of a neighborhood of a point -is a neighborhood of the preimage. -/ -theorem extChartAt_preimage_mem_nhds {x : M} (ht : t ∈ 𝓝 x) : - (extChartAt I x).symm ⁻¹' t ∈ 𝓝 ((extChartAt I x) x) := by - apply (continuousAt_extChartAt_symm x).preimage_mem_nhds - rwa [(extChartAt I x).left_inv (mem_extChartAt_source _)] - -/-- 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. -/ -theorem extChartAt_preimage_inter_eq (x : M) : - (extChartAt I x).symm ⁻¹' (s ∩ t) ∩ range I = - (extChartAt I x).symm ⁻¹' s ∩ range I ∩ (extChartAt I x).symm ⁻¹' t := by - mfld_set_tac - -theorem ContinuousWithinAt.nhdsWithin_extChartAt_symm_preimage_inter_range - {f : M → M'} {x : M} (hc : ContinuousWithinAt f s x) : - 𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] (extChartAt I x x) = - 𝓝[(extChartAt I x).target ∩ - (extChartAt I x).symm ⁻¹' (s ∩ f ⁻¹' (extChartAt I' (f x)).source)] (extChartAt I x x) := by - rw [← (extChartAt I x).image_source_inter_eq', ← map_extChartAt_nhdsWithin_eq_image, - ← map_extChartAt_nhdsWithin, nhdsWithin_inter_of_mem'] - exact hc (extChartAt_source_mem_nhds _) - -theorem ContinuousWithinAt.extChartAt_symm_preimage_inter_range_eventuallyEq - {f : M → M'} {x : M} (hc : ContinuousWithinAt f s x) : - ((extChartAt I x).symm ⁻¹' s ∩ range I : Set E) =ᶠ[𝓝 (extChartAt I x x)] - ((extChartAt I x).target ∩ - (extChartAt I x).symm ⁻¹' (s ∩ f ⁻¹' (extChartAt I' (f x)).source) : Set E) := by - rw [← nhdsWithin_eq_iff_eventuallyEq] - exact hc.nhdsWithin_extChartAt_symm_preimage_inter_range - -/-! We use the name `ext_coord_change` for `(extChartAt I x').symm ≫ extChartAt I x`. -/ - -theorem ext_coord_change_source (x x' : M) : - ((extChartAt I x').symm ≫ extChartAt I x).source = - I '' ((chartAt H x').symm ≫ₕ chartAt H x).source := - extend_coord_change_source _ _ - -open IsManifold - -theorem contDiffOn_ext_coord_change [IsManifold I n M] (x x' : M) : - ContDiffOn 𝕜 n (extChartAt I x ∘ (extChartAt I x').symm) - ((extChartAt I x').symm ≫ extChartAt I x).source := - contDiffOn_extend_coord_change (chart_mem_maximalAtlas x) (chart_mem_maximalAtlas x') - -theorem contDiffWithinAt_ext_coord_change [IsManifold I n M] (x x' : M) {y : E} - (hy : y ∈ ((extChartAt I x').symm ≫ extChartAt I x).source) : - ContDiffWithinAt 𝕜 n (extChartAt I x ∘ (extChartAt I x').symm) (range I) y := - contDiffWithinAt_extend_coord_change (chart_mem_maximalAtlas x) (chart_mem_maximalAtlas x') hy - -variable (I I') in -/-- Conjugating a function to write it in the preferred charts around `x`. -The manifold derivative of `f` will just be the derivative of this conjugated function. -/ -@[simp, mfld_simps] -def writtenInExtChartAt (x : M) (f : M → M') : E → E' := - extChartAt I' (f x) ∘ f ∘ (extChartAt I x).symm - -theorem writtenInExtChartAt_chartAt {x : M} {y : E} (h : y ∈ (extChartAt I x).target) : - writtenInExtChartAt I I x (chartAt H x) y = y := by simp_all only [mfld_simps] - -theorem writtenInExtChartAt_chartAt_symm {x : M} {y : E} (h : y ∈ (extChartAt I x).target) : - writtenInExtChartAt I I (chartAt H x x) (chartAt H x).symm y = y := by - simp_all only [mfld_simps] - -theorem writtenInExtChartAt_extChartAt {x : M} {y : E} (h : y ∈ (extChartAt I x).target) : - writtenInExtChartAt I 𝓘(𝕜, E) x (extChartAt I x) y = y := by - simp_all only [mfld_simps] - -theorem writtenInExtChartAt_extChartAt_symm {x : M} {y : E} (h : y ∈ (extChartAt I x).target) : - writtenInExtChartAt 𝓘(𝕜, E) I (extChartAt I x x) (extChartAt I x).symm y = y := by - simp_all only [mfld_simps] - -variable (𝕜) - -theorem extChartAt_self_eq {x : H} : ⇑(extChartAt I x) = I := - rfl - -theorem extChartAt_self_apply {x y : H} : extChartAt I x y = I y := - rfl - -/-- 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 = PartialEquiv.refl E := by - simp only [mfld_simps] - -theorem ext_chart_model_space_apply {x y : E} : extChartAt 𝓘(𝕜, E) x y = y := - rfl - -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 `PartialEquiv.prod_trans` here because of a type - -- synonym - rw [PartialEquiv.prod_trans] - -theorem extChartAt_comp [ChartedSpace H H'] (x : M') : - (letI := ChartedSpace.comp H H' M'; extChartAt I x) = - (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) : - (letI := ChartedSpace.comp H H' M'; writtenInExtChartAt I I x (chartAt H' x) y) = y := by - letI := ChartedSpace.comp H H' M' - simp_all only [mfld_simps, chartAt_comp] - -theorem writtenInExtChartAt_chartAt_symm_comp [ChartedSpace H H'] (x : M') {y} - (hy : y ∈ letI := ChartedSpace.comp H H' M'; (extChartAt I x).target) : - ( letI := ChartedSpace.comp H H' M' - writtenInExtChartAt I I (chartAt H' x x) (chartAt H' x).symm y) = y := by - letI := ChartedSpace.comp H H' M' - simp_all only [mfld_simps, chartAt_comp] - -end ExtendedCharts - -section Topology - --- Let `M` be a topological manifold over the field 𝕜. -variable - {E : Type*} {𝕜 : Type*} [NontriviallyNormedField 𝕜] - [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] - {M : Type*} [TopologicalSpace M] [ChartedSpace H M] - -/-- A finite-dimensional manifold modelled on a locally compact field - (such as ℝ, ℂ or the `p`-adic numbers) is locally compact. -/ -lemma Manifold.locallyCompact_of_finiteDimensional - (I : ModelWithCorners 𝕜 E H) [LocallyCompactSpace 𝕜] [FiniteDimensional 𝕜 E] : - LocallyCompactSpace M := by - have : ProperSpace E := FiniteDimensional.proper 𝕜 E - have : LocallyCompactSpace H := I.locallyCompactSpace - exact ChartedSpace.locallyCompactSpace H M - -variable (M) - -/-- A locally compact manifold must be modelled on a locally compact space. -/ -lemma LocallyCompactSpace.of_locallyCompact_manifold (I : ModelWithCorners 𝕜 E H) - [h : Nonempty M] [LocallyCompactSpace M] : - LocallyCompactSpace E := by - rcases h with ⟨x⟩ - obtain ⟨y, hy⟩ := interior_extChartAt_target_nonempty I x - have h'y : y ∈ (extChartAt I x).target := interior_subset hy - obtain ⟨s, hmem, hss, hcom⟩ := - LocallyCompactSpace.local_compact_nhds ((extChartAt I x).symm y) (extChartAt I x).source - ((isOpen_extChartAt_source x).mem_nhds ((extChartAt I x).map_target h'y)) - have : IsCompact <| (extChartAt I x) '' s := - hcom.image_of_continuousOn <| (continuousOn_extChartAt x).mono hss - apply this.locallyCompactSpace_of_mem_nhds_of_addGroup (x := y) - rw [← (extChartAt I x).right_inv h'y] - apply extChartAt_image_nhd_mem_nhds_of_mem_interior_range - (PartialEquiv.map_target (extChartAt I x) h'y) _ hmem - simp only [(extChartAt I x).right_inv h'y] - exact interior_mono (extChartAt_target_subset_range x) hy - -/-- Riesz's theorem applied to manifolds: a locally compact manifolds must be modelled on a - finite-dimensional space. This is the converse to - `Manifold.locallyCompact_of_finiteDimensional`. -/ -theorem FiniteDimensional.of_locallyCompact_manifold - [CompleteSpace 𝕜] (I : ModelWithCorners 𝕜 E H) [Nonempty M] [LocallyCompactSpace M] : - FiniteDimensional 𝕜 E := by - have := LocallyCompactSpace.of_locallyCompact_manifold M I - exact FiniteDimensional.of_locallyCompactSpace 𝕜 - -end Topology - section TangentSpace /- We define the tangent space to `M` modelled on `I : ModelWithCorners 𝕜 E H` as a type synonym @@ -1727,5 +937,3 @@ variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] {H : Type*} [Top instance : PathConnectedSpace (TangentSpace I x) := inferInstanceAs (PathConnectedSpace E) end Real - -set_option linter.style.longFile 1900 diff --git a/Mathlib/Geometry/Manifold/IsManifold/ExtChartAt.lean b/Mathlib/Geometry/Manifold/IsManifold/ExtChartAt.lean new file mode 100644 index 0000000000000..124cb42ac10c0 --- /dev/null +++ b/Mathlib/Geometry/Manifold/IsManifold/ExtChartAt.lean @@ -0,0 +1,816 @@ +/- +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.Geometry.Manifold.IsManifold.Basic + +/-! +# Extended charts in smooth manifolds + +In a `C^n` manifold with corners with the model `I` on `(E, H)`, the charts take values in the +model space `H`. However, we also need to use extended charts taking values in the model vector +space `E`. These extended charts are not `PartialHomeomorph` as the target is not open in `E` +in general, but we can still register them as `PartialEquiv`. + +## Main definitions + +* `PartialHomeomorph.extend`: compose a partial homeomorphism into `H` with the model `I`, +to obtain a `PartialEquiv` into `E`. Extended charts are an example of this. +* `extChartAt I x`: the extended chart at `x`, obtained by composing the `chartAt H x` with `I`. + Since the target is in general not open, this is not a partial homeomorphism in general, but + we register them as `PartialEquiv`s. + +## Main results + +* `contDiffOn_extend_coord_change`: if `f` and `f'` lie in the maximal atlas on `M`, +`f.extend I ∘ (f'.extend I).symm` is continuous on its source + +* `contDiffOn_ext_coord_change`: for `x x : M`, the coordinate change +`(extChartAt I x').symm ≫ extChartAt I x` is continuous on its source + +* `Manifold.locallyCompact_of_finiteDimensional`: a finite-dimensional manifold +modelled on a locally compact field (such as ℝ, ℂ or the `p`-adic numbers) is locally compact +* `LocallyCompactSpace.of_locallyCompact_manifold`: a locally compact manifold must be modelled +on a locally compact space. +* `FiniteDimensional.of_locallyCompact_manifold`: a locally compact manifolds must be modelled +on a finite-dimensional space + +-/ + +noncomputable section + +open Set Filter Function +open scoped Manifold Topology + +variable {𝕜 E M H E' M' H' : Type*} [NontriviallyNormedField 𝕜] [NormedAddCommGroup E] + [NormedSpace 𝕜 E] [TopologicalSpace H] [TopologicalSpace M] {n : WithTop ℕ∞} + (f f' : PartialHomeomorph M H) + {I : ModelWithCorners 𝕜 E H} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] [TopologicalSpace H'] + [TopologicalSpace M'] {I' : ModelWithCorners 𝕜 E' H'} {s t : Set M} + +section ExtendedCharts + +namespace PartialHomeomorph + +variable (I) in +/-- 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 : PartialEquiv M E := + f.toPartialEquiv ≫ I.toPartialEquiv + +theorem extend_coe : ⇑(f.extend I) = I ∘ f := + rfl + +theorem extend_coe_symm : ⇑(f.extend I).symm = f.symm ∘ I.symm := + rfl + +theorem extend_source : (f.extend I).source = f.source := by + rw [extend, PartialEquiv.trans_source, I.source_eq, preimage_univ, inter_univ] + +theorem isOpen_extend_source : IsOpen (f.extend I).source := by + rw [extend_source] + exact f.open_source + +theorem extend_target : (f.extend I).target = I.symm ⁻¹' f.target ∩ range I := by + simp_rw [extend, PartialEquiv.trans_target, I.target_eq, I.toPartialEquiv_coe_symm, inter_comm] + +theorem extend_target' : (f.extend I).target = I '' f.target := by + rw [extend, PartialEquiv.trans_target'', I.source_eq, univ_inter, I.toPartialEquiv_coe] + +lemma isOpen_extend_target [I.Boundaryless] : IsOpen (f.extend I).target := by + rw [extend_target, I.range_eq_univ, inter_univ] + exact I.continuous_symm.isOpen_preimage _ f.open_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 + +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] + +/-- 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 := + EqOn.image_eq_self (fun _ hx ↦ f.extend_left_inv (ht hx)) + +theorem extend_source_mem_nhds {x : M} (h : x ∈ f.source) : (f.extend I).source ∈ 𝓝 x := + (isOpen_extend_source f).mem_nhds <| by rwa [f.extend_source] + +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 h + +theorem continuousOn_extend : ContinuousOn (f.extend I) (f.extend I).source := by + refine I.continuous.comp_continuousOn ?_ + rw [extend_source] + exact f.continuousOn + +theorem continuousAt_extend {x : M} (h : x ∈ f.source) : ContinuousAt (f.extend I) x := + (continuousOn_extend f).continuousAt <| extend_source_mem_nhds f h + +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] + +theorem map_extend_nhds_of_mem_interior_range {x : M} (hx : x ∈ f.source) + (h'x : f.extend I x ∈ interior (range I)) : + map (f.extend I) (𝓝 x) = 𝓝 (f.extend I x) := by + rw [f.map_extend_nhds hx, nhdsWithin_eq_nhds] + exact mem_of_superset (isOpen_interior.mem_nhds h'x) interior_subset + +theorem map_extend_nhds_of_boundaryless [I.Boundaryless] {x : M} (hx : x ∈ f.source) : + map (f.extend I) (𝓝 x) = 𝓝 (f.extend I x) := by + rw [f.map_extend_nhds hx, I.range_eq_univ, nhdsWithin_univ] + +theorem extend_target_mem_nhdsWithin {y : M} (hy : y ∈ f.source) : + (f.extend I).target ∈ 𝓝[range I] f.extend I y := by + rw [← PartialEquiv.image_source_eq_target, ← map_extend_nhds f hy] + exact image_mem_map (extend_source_mem_nhds _ hy) + +theorem extend_image_nhd_mem_nhds_of_boundaryless [I.Boundaryless] {x} (hx : x ∈ f.source) + {s : Set M} (h : s ∈ 𝓝 x) : (f.extend I) '' s ∈ 𝓝 ((f.extend I) x) := by + rw [← f.map_extend_nhds_of_boundaryless hx, Filter.mem_map] + filter_upwards [h] using subset_preimage_image (f.extend I) s + +theorem extend_image_nhd_mem_nhds_of_mem_interior_range {x} (hx : x ∈ f.source) + (h'x : f.extend I x ∈ interior (range I)) {s : Set M} (h : s ∈ 𝓝 x) : + (f.extend I) '' s ∈ 𝓝 ((f.extend I) x) := by + rw [← f.map_extend_nhds_of_mem_interior_range hx h'x, Filter.mem_map] + filter_upwards [h] using subset_preimage_image (f.extend I) s + +theorem extend_target_subset_range : (f.extend I).target ⊆ range I := by simp only [mfld_simps] + +lemma interior_extend_target_subset_interior_range : + interior (f.extend I).target ⊆ interior (range I) := by + rw [f.extend_target, interior_inter, (f.open_target.preimage I.continuous_symm).interior_eq] + exact inter_subset_right + +/-- If `y ∈ f.target` and `I y ∈ interior (range I)`, + then `I y` is an interior point of `(I ∘ f).target`. -/ +lemma mem_interior_extend_target {y : H} (hy : y ∈ f.target) + (hy' : I y ∈ interior (range I)) : I y ∈ interior (f.extend I).target := by + rw [f.extend_target, interior_inter, (f.open_target.preimage I.continuous_symm).interior_eq, + mem_inter_iff, mem_preimage] + exact ⟨mem_of_eq_of_mem (I.left_inv (y)) hy, hy'⟩ + +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) + +theorem extend_target_eventuallyEq {y : M} (hy : y ∈ f.source) : + (f.extend I).target =ᶠ[𝓝 (f.extend I y)] range I := + nhdsWithin_eq_iff_eventuallyEq.1 (nhdsWithin_extend_target_eq _ hy) + +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 + +theorem continuousAt_extend_symm {x : M} (h : x ∈ f.source) : + ContinuousAt (f.extend I).symm (f.extend I x) := + continuousAt_extend_symm' f <| (f.extend I).map_source <| by rwa [f.extend_source] + +theorem continuousOn_extend_symm : ContinuousOn (f.extend I).symm (f.extend I).target := fun _ h => + (continuousAt_extend_symm' _ h).continuousWithinAt + +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 + +theorem isOpen_extend_preimage' {s : Set E} (hs : IsOpen s) : + IsOpen ((f.extend I).source ∩ f.extend I ⁻¹' s) := + (continuousOn_extend f).isOpen_inter_preimage (isOpen_extend_source _) hs + +theorem isOpen_extend_preimage {s : Set E} (hs : IsOpen s) : + IsOpen (f.source ∩ f.extend I ⁻¹' s) := by + rw [← extend_source f (I := I)]; exact isOpen_extend_preimage' f hs + +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 + set e := f.extend I + calc + map e (𝓝[s] y) = map e (𝓝[e.source ∩ s] y) := + congr_arg (map e) (nhdsWithin_inter_of_mem (extend_source_mem_nhdsWithin f hy)).symm + _ = 𝓝[e '' (e.source ∩ s)] e y := + ((f.extend I).leftInvOn.mono inter_subset_left).map_nhdsWithin_eq + ((f.extend I).left_inv <| by rwa [f.extend_source]) + (continuousAt_extend_symm f hy).continuousWithinAt + (continuousAt_extend f hy).continuousWithinAt + +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 + rw [map_extend_nhdsWithin_eq_image _ hy, inter_eq_self_of_subset_right] + rwa [extend_source] + +theorem map_extend_nhdsWithin {y : M} (hy : y ∈ f.source) : + map (f.extend I) (𝓝[s] y) = 𝓝[(f.extend I).symm ⁻¹' s ∩ range I] f.extend I y := by + rw [map_extend_nhdsWithin_eq_image f hy, nhdsWithin_inter, ← + nhdsWithin_extend_target_eq _ hy, ← nhdsWithin_inter, (f.extend I).image_source_inter_eq', + inter_comm] + +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 hy, map_map, Filter.map_congr, map_id] + exact (f.extend I).leftInvOn.eqOn.eventuallyEq_of_mem (extend_source_mem_nhdsWithin _ hy) + +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 := I) hy, preimage_univ, univ_inter] + +theorem tendsto_extend_comp_iff {α : Type*} {l : Filter α} {g : α → M} + (hg : ∀ᶠ z in l, g z ∈ f.source) {y : M} (hy : y ∈ f.source) : + Tendsto (f.extend I ∘ g) l (𝓝 (f.extend I y)) ↔ Tendsto g l (𝓝 y) := by + refine ⟨fun h u hu ↦ mem_map.2 ?_, (continuousAt_extend _ hy).tendsto.comp⟩ + have := (f.continuousAt_extend_symm hy).tendsto.comp h + rw [extend_left_inv _ hy] at this + filter_upwards [hg, mem_map.1 (this hu)] with z hz hzu + 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' : PartialHomeomorph M' H'} {g : M → M'} {y : 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 + unfold ContinuousWithinAt + simp only [comp_apply] + rw [extend_left_inv _ hy, f'.tendsto_extend_comp_iff _ hgy, + ← f.map_extend_symm_nhdsWithin (I := I) hy, tendsto_map'_iff] + rw [← f.map_extend_nhdsWithin (I := I) hy, eventually_map] + filter_upwards [inter_mem_nhdsWithin _ (f.open_source.mem_nhds hy)] with z hz + rw [comp_apply, extend_left_inv _ hz.2] + exact hmaps hz.1 + +-- there is no definition `writtenInExtend` but we already use some made-up names in this file + +/-- 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' : 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 forall_mem_image.trans <| forall₂_congr fun x hx ↦ ?_ + refine (continuousWithinAt_congr_set ?_).trans + (continuousWithinAt_writtenInExtend_iff _ (hs hx) (hmaps hx) hmaps) + rw [← nhdsWithin_eq_iff_eventuallyEq, ← map_extend_nhdsWithin_eq_image_of_subset, + ← map_extend_nhdsWithin] + exacts [hs hx, hs hx, hs] + +/-- Technical lemma ensuring that the preimage under an extended chart of a neighborhood of a point +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 := I) h, mem_map] at ht + +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 h).preimage_mem_nhds + rwa [(f.extend I).left_inv] + rwa [f.extend_source] + +/-- 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. -/ +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 + +-- 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) : + ((f.extend I).symm ⁻¹' s ∩ range I : Set _) =ᶠ[𝓝 (f.extend I x)] + ((f.extend I).target ∩ (f.extend I).symm ⁻¹' s : Set _) := by + rw [f.extend_target, inter_assoc, inter_comm (range I)] + conv => + congr + · skip + rw [← univ_inter (_ ∩ range I)] + 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] + +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] + +/-! 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 [PartialEquiv.trans_source, I.image_eq, extend_source, PartialEquiv.symm_source, + extend_target, inter_right_comm _ (range I)] + rfl + +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] + +theorem extend_coord_change_source_mem_nhdsWithin {x : E} + (hx : x ∈ ((f.extend I).symm ≫ f'.extend I).source) : + ((f.extend I).symm ≫ f'.extend I).source ∈ 𝓝[range I] x := by + rw [f.extend_coord_change_source] at hx ⊢ + obtain ⟨x, hx, rfl⟩ := hx + refine I.image_mem_nhdsWithin ?_ + exact (PartialHomeomorph.open_source _).mem_nhds hx + +theorem extend_coord_change_source_mem_nhdsWithin' {x : M} (hxf : x ∈ f.source) + (hxf' : x ∈ f'.source) : + ((f.extend I).symm ≫ f'.extend I).source ∈ 𝓝[range I] f.extend I x := by + apply extend_coord_change_source_mem_nhdsWithin + rw [← extend_image_source_inter] + exact mem_image_of_mem _ ⟨hxf, hxf'⟩ + +variable {f f'} + +open IsManifold + +theorem contDiffOn_extend_coord_change [ChartedSpace H M] (hf : f ∈ maximalAtlas I n M) + (hf' : f' ∈ maximalAtlas I n M) : + ContDiffOn 𝕜 n (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 + +theorem contDiffWithinAt_extend_coord_change [ChartedSpace H M] (hf : f ∈ maximalAtlas I n M) + (hf' : f' ∈ maximalAtlas I n M) {x : E} (hx : x ∈ ((f'.extend I).symm ≫ f.extend I).source) : + ContDiffWithinAt 𝕜 n (f.extend I ∘ (f'.extend I).symm) (range I) x := by + apply (contDiffOn_extend_coord_change hf hf' x hx).mono_of_mem_nhdsWithin + rw [extend_coord_change_source] at hx ⊢ + obtain ⟨z, hz, rfl⟩ := hx + exact I.image_mem_nhdsWithin ((PartialHomeomorph.open_source _).mem_nhds hz) + +theorem contDiffWithinAt_extend_coord_change' [ChartedSpace H M] (hf : f ∈ maximalAtlas I n M) + (hf' : f' ∈ maximalAtlas I n M) {x : M} (hxf : x ∈ f.source) (hxf' : x ∈ f'.source) : + ContDiffWithinAt 𝕜 n (f.extend I ∘ (f'.extend I).symm) (range I) (f'.extend I x) := by + refine contDiffWithinAt_extend_coord_change hf hf' ?_ + rw [← extend_image_source_inter] + exact mem_image_of_mem _ ⟨hxf', hxf⟩ + +end PartialHomeomorph + +open PartialHomeomorph + +variable [ChartedSpace H M] [ChartedSpace H' M'] + +variable (I) in +/-- 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) : PartialEquiv M E := + (chartAt H x).extend I + +theorem extChartAt_coe (x : M) : ⇑(extChartAt I x) = I ∘ chartAt H x := + rfl + +theorem extChartAt_coe_symm (x : M) : ⇑(extChartAt I x).symm = (chartAt H x).symm ∘ I.symm := + rfl + +variable (I) in +theorem extChartAt_source (x : M) : (extChartAt I x).source = (chartAt H x).source := + extend_source _ + +theorem isOpen_extChartAt_source (x : M) : IsOpen (extChartAt I x).source := + isOpen_extend_source _ + +theorem mem_extChartAt_source (x : M) : x ∈ (extChartAt I x).source := by + simp only [extChartAt_source, mem_chart_source] + +theorem mem_extChartAt_target (x : M) : extChartAt I x x ∈ (extChartAt I x).target := + (extChartAt I x).map_source <| mem_extChartAt_source _ + +variable (I) in +theorem extChartAt_target (x : M) : + (extChartAt I x).target = I.symm ⁻¹' (chartAt H x).target ∩ range I := + extend_target _ + +theorem uniqueDiffOn_extChartAt_target (x : M) : UniqueDiffOn 𝕜 (extChartAt I x).target := by + rw [extChartAt_target] + exact I.uniqueDiffOn_preimage (chartAt H x).open_target + +theorem uniqueDiffWithinAt_extChartAt_target (x : M) : + UniqueDiffWithinAt 𝕜 (extChartAt I x).target (extChartAt I x x) := + uniqueDiffOn_extChartAt_target x _ <| mem_extChartAt_target x + +theorem extChartAt_to_inv (x : M) : (extChartAt I x).symm ((extChartAt I x) x) = x := + (extChartAt I x).left_inv (mem_extChartAt_source x) + +theorem mapsTo_extChartAt {x : M} (hs : s ⊆ (chartAt H x).source) : + MapsTo (extChartAt I x) s ((extChartAt I x).symm ⁻¹' s ∩ range I) := + mapsTo_extend _ hs + +theorem extChartAt_source_mem_nhds' {x x' : M} (h : x' ∈ (extChartAt I x).source) : + (extChartAt I x).source ∈ 𝓝 x' := + extend_source_mem_nhds _ <| by rwa [← extChartAt_source I] + +theorem extChartAt_source_mem_nhds (x : M) : (extChartAt I x).source ∈ 𝓝 x := + extChartAt_source_mem_nhds' (mem_extChartAt_source x) + +theorem extChartAt_source_mem_nhdsWithin' {x x' : M} (h : x' ∈ (extChartAt I x).source) : + (extChartAt I x).source ∈ 𝓝[s] x' := + mem_nhdsWithin_of_mem_nhds (extChartAt_source_mem_nhds' h) + +theorem extChartAt_source_mem_nhdsWithin (x : M) : (extChartAt I x).source ∈ 𝓝[s] x := + mem_nhdsWithin_of_mem_nhds (extChartAt_source_mem_nhds x) + +theorem continuousOn_extChartAt (x : M) : ContinuousOn (extChartAt I x) (extChartAt I x).source := + continuousOn_extend _ + +theorem continuousAt_extChartAt' {x x' : M} (h : x' ∈ (extChartAt I x).source) : + ContinuousAt (extChartAt I x) x' := + continuousAt_extend _ <| by rwa [← extChartAt_source I] + +theorem continuousAt_extChartAt (x : M) : ContinuousAt (extChartAt I x) x := + continuousAt_extChartAt' (mem_extChartAt_source x) + +theorem map_extChartAt_nhds' {x y : M} (hy : y ∈ (extChartAt I x).source) : + map (extChartAt I x) (𝓝 y) = 𝓝[range I] extChartAt I x y := + map_extend_nhds _ <| by rwa [← extChartAt_source I] + +theorem map_extChartAt_nhds (x : M) : map (extChartAt I x) (𝓝 x) = 𝓝[range I] extChartAt I x x := + map_extChartAt_nhds' <| mem_extChartAt_source x + +theorem map_extChartAt_nhds_of_boundaryless [I.Boundaryless] (x : M) : + map (extChartAt I x) (𝓝 x) = 𝓝 (extChartAt I x x) := by + rw [extChartAt] + exact map_extend_nhds_of_boundaryless (chartAt H x) (mem_chart_source H x) + +theorem extChartAt_image_nhd_mem_nhds_of_mem_interior_range {x y} (hx : y ∈ (extChartAt I x).source) + (h'x : extChartAt I x y ∈ interior (range I)) {s : Set M} (h : s ∈ 𝓝 y) : + (extChartAt I x) '' s ∈ 𝓝 (extChartAt I x y) := by + rw [extChartAt] + exact extend_image_nhd_mem_nhds_of_mem_interior_range _ (by simpa using hx) h'x h + +variable {x} in +theorem extChartAt_image_nhd_mem_nhds_of_boundaryless [I.Boundaryless] + {x : M} (hx : s ∈ 𝓝 x) : extChartAt I x '' s ∈ 𝓝 (extChartAt I x x) := by + rw [extChartAt] + exact extend_image_nhd_mem_nhds_of_boundaryless _ (mem_chart_source H x) hx + +theorem extChartAt_target_mem_nhdsWithin' {x y : M} (hy : y ∈ (extChartAt I x).source) : + (extChartAt I x).target ∈ 𝓝[range I] extChartAt I x y := + extend_target_mem_nhdsWithin _ <| by rwa [← extChartAt_source I] + +theorem extChartAt_target_mem_nhdsWithin (x : M) : + (extChartAt I x).target ∈ 𝓝[range I] extChartAt I x x := + extChartAt_target_mem_nhdsWithin' (mem_extChartAt_source x) + +theorem extChartAt_target_mem_nhdsWithin_of_mem {x : M} {y : E} (hy : y ∈ (extChartAt I x).target) : + (extChartAt I x).target ∈ 𝓝[range I] y := by + rw [← (extChartAt I x).right_inv hy] + apply extChartAt_target_mem_nhdsWithin' + exact (extChartAt I x).map_target hy + +theorem extChartAt_target_union_compl_range_mem_nhds_of_mem {y : E} {x : M} + (hy : y ∈ (extChartAt I x).target) : (extChartAt I x).target ∪ (range I)ᶜ ∈ 𝓝 y := by + rw [← nhdsWithin_univ, ← union_compl_self (range I), nhdsWithin_union] + exact Filter.union_mem_sup (extChartAt_target_mem_nhdsWithin_of_mem hy) self_mem_nhdsWithin + +@[deprecated (since := "2024-11-27")] alias +extChartAt_target_union_comp_range_mem_nhds_of_mem := +extChartAt_target_union_compl_range_mem_nhds_of_mem + +/-- If we're boundaryless, `extChartAt` has open target -/ +theorem isOpen_extChartAt_target [I.Boundaryless] (x : M) : IsOpen (extChartAt I x).target := by + simp_rw [extChartAt_target, I.range_eq_univ, inter_univ] + exact (PartialHomeomorph.open_target _).preimage I.continuous_symm + +/-- If we're boundaryless, `(extChartAt I x).target` is a neighborhood of the key point -/ +theorem extChartAt_target_mem_nhds [I.Boundaryless] (x : M) : + (extChartAt I x).target ∈ 𝓝 (extChartAt I x x) := by + convert extChartAt_target_mem_nhdsWithin x + simp only [I.range_eq_univ, nhdsWithin_univ] + +/-- If we're boundaryless, `(extChartAt I x).target` is a neighborhood of any of its points -/ +theorem extChartAt_target_mem_nhds' [I.Boundaryless] {x : M} {y : E} + (m : y ∈ (extChartAt I x).target) : (extChartAt I x).target ∈ 𝓝 y := + (isOpen_extChartAt_target x).mem_nhds m + +theorem extChartAt_target_subset_range (x : M) : (extChartAt I x).target ⊆ range I := by + simp only [mfld_simps] + +/-- Around the image of a point in the source, the neighborhoods are the same +within `(extChartAt I x).target` and within `range I`. -/ +theorem nhdsWithin_extChartAt_target_eq' {x y : M} (hy : y ∈ (extChartAt I x).source) : + 𝓝[(extChartAt I x).target] extChartAt I x y = 𝓝[range I] extChartAt I x y := + nhdsWithin_extend_target_eq _ <| by rwa [← extChartAt_source I] + +/-- Around a point in the target, the neighborhoods are the same within `(extChartAt I x).target` +and within `range I`. -/ +theorem nhdsWithin_extChartAt_target_eq_of_mem {x : M} {z : E} (hz : z ∈ (extChartAt I x).target) : + 𝓝[(extChartAt I x).target] z = 𝓝[range I] z := by + rw [← PartialEquiv.right_inv (extChartAt I x) hz] + exact nhdsWithin_extChartAt_target_eq' ((extChartAt I x).map_target hz) + +/-- Around the image of the base point, the neighborhoods are the same +within `(extChartAt I x).target` and within `range I`. -/ +theorem nhdsWithin_extChartAt_target_eq (x : M) : + 𝓝[(extChartAt I x).target] (extChartAt I x) x = 𝓝[range I] (extChartAt I x) x := + nhdsWithin_extChartAt_target_eq' (mem_extChartAt_source x) + +/-- Around the image of a point in the source, `(extChartAt I x).target` and `range I` +coincide locally. -/ +theorem extChartAt_target_eventuallyEq' {x y : M} (hy : y ∈ (extChartAt I x).source) : + (extChartAt I x).target =ᶠ[𝓝 (extChartAt I x y)] range I := + nhdsWithin_eq_iff_eventuallyEq.1 (nhdsWithin_extChartAt_target_eq' hy) + +/-- Around a point in the target, `(extChartAt I x).target` and `range I` coincide locally. -/ +theorem extChartAt_target_eventuallyEq_of_mem {x : M} {z : E} (hz : z ∈ (extChartAt I x).target) : + (extChartAt I x).target =ᶠ[𝓝 z] range I := + nhdsWithin_eq_iff_eventuallyEq.1 (nhdsWithin_extChartAt_target_eq_of_mem hz) + +/-- Around the image of the base point, `(extChartAt I x).target` and `range I` coincide locally. -/ +theorem extChartAt_target_eventuallyEq {x : M} : + (extChartAt I x).target =ᶠ[𝓝 (extChartAt I x x)] range I := + nhdsWithin_eq_iff_eventuallyEq.1 (nhdsWithin_extChartAt_target_eq x) + +theorem continuousAt_extChartAt_symm'' {x : M} {y : E} (h : y ∈ (extChartAt I x).target) : + ContinuousAt (extChartAt I x).symm y := + continuousAt_extend_symm' _ h + +theorem continuousAt_extChartAt_symm' {x x' : M} (h : x' ∈ (extChartAt I x).source) : + ContinuousAt (extChartAt I x).symm (extChartAt I x x') := + continuousAt_extChartAt_symm'' <| (extChartAt I x).map_source h + +theorem continuousAt_extChartAt_symm (x : M) : + ContinuousAt (extChartAt I x).symm ((extChartAt I x) x) := + continuousAt_extChartAt_symm' (mem_extChartAt_source x) + +theorem continuousOn_extChartAt_symm (x : M) : + ContinuousOn (extChartAt I x).symm (extChartAt I x).target := + fun _y hy => (continuousAt_extChartAt_symm'' hy).continuousWithinAt + +lemma extChartAt_target_subset_closure_interior {x : M} : + (extChartAt I x).target ⊆ closure (interior (extChartAt I x).target) := by + intro y hy + rw [mem_closure_iff_nhds] + intro t ht + have A : t ∩ ((extChartAt I x).target ∪ (range I)ᶜ) ∈ 𝓝 y := + inter_mem ht (extChartAt_target_union_compl_range_mem_nhds_of_mem hy) + have B : y ∈ closure (interior (range I)) := by + apply I.range_subset_closure_interior (extChartAt_target_subset_range x hy) + obtain ⟨z, ⟨tz, h'z⟩, hz⟩ : + (t ∩ ((extChartAt I x).target ∪ (range ↑I)ᶜ) ∩ interior (range I)).Nonempty := + mem_closure_iff_nhds.1 B _ A + refine ⟨z, ⟨tz, ?_⟩⟩ + have h''z : z ∈ (extChartAt I x).target := by simpa [interior_subset hz] using h'z + exact (extChartAt_target_eventuallyEq_of_mem h''z).symm.mem_interior hz + +variable (I) in +theorem interior_extChartAt_target_nonempty (x : M) : + (interior (extChartAt I x).target).Nonempty := by + by_contra! H + have := extChartAt_target_subset_closure_interior (mem_extChartAt_target (I := I) x) + simp only [H, closure_empty, mem_empty_iff_false] at this + +lemma extChartAt_mem_closure_interior {x₀ x : M} + (hx : x ∈ closure (interior s)) (h'x : x ∈ (extChartAt I x₀).source) : + extChartAt I x₀ x ∈ + closure (interior ((extChartAt I x₀).symm ⁻¹' s ∩ (extChartAt I x₀).target)) := by + simp_rw [mem_closure_iff, interior_inter, ← inter_assoc] + intro o o_open ho + obtain ⟨y, ⟨yo, hy⟩, ys⟩ : + ((extChartAt I x₀) ⁻¹' o ∩ (extChartAt I x₀).source ∩ interior s).Nonempty := by + have : (extChartAt I x₀) ⁻¹' o ∈ 𝓝 x := by + apply (continuousAt_extChartAt' h'x).preimage_mem_nhds (o_open.mem_nhds ho) + refine (mem_closure_iff_nhds.1 hx) _ (inter_mem this ?_) + apply (isOpen_extChartAt_source x₀).mem_nhds h'x + have A : interior (↑(extChartAt I x₀).symm ⁻¹' s) ∈ 𝓝 (extChartAt I x₀ y) := by + simp only [interior_mem_nhds] + apply (continuousAt_extChartAt_symm' hy).preimage_mem_nhds + simp only [hy, PartialEquiv.left_inv] + exact mem_interior_iff_mem_nhds.mp ys + have B : (extChartAt I x₀) y ∈ closure (interior (extChartAt I x₀).target) := by + apply extChartAt_target_subset_closure_interior (x := x₀) + exact (extChartAt I x₀).map_source hy + exact mem_closure_iff_nhds.1 B _ (inter_mem (o_open.mem_nhds yo) A) + +theorem isOpen_extChartAt_preimage' (x : M) {s : Set E} (hs : IsOpen s) : + IsOpen ((extChartAt I x).source ∩ extChartAt I x ⁻¹' s) := + isOpen_extend_preimage' _ hs + +theorem isOpen_extChartAt_preimage (x : M) {s : Set E} (hs : IsOpen s) : + IsOpen ((chartAt H x).source ∩ extChartAt I x ⁻¹' s) := by + rw [← extChartAt_source I] + exact isOpen_extChartAt_preimage' x hs + +theorem map_extChartAt_nhdsWithin_eq_image' {x y : M} (hy : y ∈ (extChartAt I x).source) : + map (extChartAt I x) (𝓝[s] y) = + 𝓝[extChartAt I x '' ((extChartAt I x).source ∩ s)] extChartAt I x y := + map_extend_nhdsWithin_eq_image _ <| by rwa [← extChartAt_source I] + +theorem map_extChartAt_nhdsWithin_eq_image (x : M) : + map (extChartAt I x) (𝓝[s] x) = + 𝓝[extChartAt I x '' ((extChartAt I x).source ∩ s)] extChartAt I x x := + map_extChartAt_nhdsWithin_eq_image' (mem_extChartAt_source x) + +theorem map_extChartAt_nhdsWithin' {x y : M} (hy : y ∈ (extChartAt I x).source) : + map (extChartAt I x) (𝓝[s] y) = 𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] extChartAt I x y := + map_extend_nhdsWithin _ <| by rwa [← extChartAt_source I] + +theorem map_extChartAt_nhdsWithin (x : M) : + map (extChartAt I x) (𝓝[s] x) = 𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] extChartAt I x x := + map_extChartAt_nhdsWithin' (mem_extChartAt_source x) + +theorem map_extChartAt_symm_nhdsWithin' {x y : M} (hy : y ∈ (extChartAt I x).source) : + map (extChartAt I x).symm (𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] extChartAt I x y) = + 𝓝[s] y := + map_extend_symm_nhdsWithin _ <| by rwa [← extChartAt_source I] + +theorem map_extChartAt_symm_nhdsWithin_range' {x y : M} (hy : y ∈ (extChartAt I x).source) : + map (extChartAt I x).symm (𝓝[range I] extChartAt I x y) = 𝓝 y := + map_extend_symm_nhdsWithin_range _ <| by rwa [← extChartAt_source I] + +theorem map_extChartAt_symm_nhdsWithin (x : M) : + map (extChartAt I x).symm (𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] extChartAt I x x) = + 𝓝[s] x := + map_extChartAt_symm_nhdsWithin' (mem_extChartAt_source x) + +theorem map_extChartAt_symm_nhdsWithin_range (x : M) : + map (extChartAt I x).symm (𝓝[range I] extChartAt I x x) = 𝓝 x := + map_extChartAt_symm_nhdsWithin_range' (mem_extChartAt_source x) + +/-- Technical lemma ensuring that the preimage under an extended chart of a neighborhood of a point +in the source is a neighborhood of the preimage, within a set. -/ +theorem extChartAt_preimage_mem_nhdsWithin' {x x' : M} (h : x' ∈ (extChartAt I x).source) + (ht : t ∈ 𝓝[s] x') : + (extChartAt I x).symm ⁻¹' t ∈ 𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] (extChartAt I x) x' := by + rwa [← map_extChartAt_symm_nhdsWithin' h, mem_map] at ht + +/-- Technical lemma ensuring that the preimage under an extended chart of a neighborhood of the +base point is a neighborhood of the preimage, within a set. -/ +theorem extChartAt_preimage_mem_nhdsWithin {x : M} (ht : t ∈ 𝓝[s] x) : + (extChartAt I x).symm ⁻¹' t ∈ 𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] (extChartAt I x) x := + extChartAt_preimage_mem_nhdsWithin' (mem_extChartAt_source x) ht + +theorem extChartAt_preimage_mem_nhds' {x x' : M} (h : x' ∈ (extChartAt I x).source) + (ht : t ∈ 𝓝 x') : (extChartAt I x).symm ⁻¹' t ∈ 𝓝 (extChartAt I x x') := + extend_preimage_mem_nhds _ (by rwa [← extChartAt_source I]) ht + +/-- Technical lemma ensuring that the preimage under an extended chart of a neighborhood of a point +is a neighborhood of the preimage. -/ +theorem extChartAt_preimage_mem_nhds {x : M} (ht : t ∈ 𝓝 x) : + (extChartAt I x).symm ⁻¹' t ∈ 𝓝 ((extChartAt I x) x) := by + apply (continuousAt_extChartAt_symm x).preimage_mem_nhds + rwa [(extChartAt I x).left_inv (mem_extChartAt_source _)] + +/-- 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. -/ +theorem extChartAt_preimage_inter_eq (x : M) : + (extChartAt I x).symm ⁻¹' (s ∩ t) ∩ range I = + (extChartAt I x).symm ⁻¹' s ∩ range I ∩ (extChartAt I x).symm ⁻¹' t := by + mfld_set_tac + +theorem ContinuousWithinAt.nhdsWithin_extChartAt_symm_preimage_inter_range + {f : M → M'} {x : M} (hc : ContinuousWithinAt f s x) : + 𝓝[(extChartAt I x).symm ⁻¹' s ∩ range I] (extChartAt I x x) = + 𝓝[(extChartAt I x).target ∩ + (extChartAt I x).symm ⁻¹' (s ∩ f ⁻¹' (extChartAt I' (f x)).source)] (extChartAt I x x) := by + rw [← (extChartAt I x).image_source_inter_eq', ← map_extChartAt_nhdsWithin_eq_image, + ← map_extChartAt_nhdsWithin, nhdsWithin_inter_of_mem'] + exact hc (extChartAt_source_mem_nhds _) + +theorem ContinuousWithinAt.extChartAt_symm_preimage_inter_range_eventuallyEq + {f : M → M'} {x : M} (hc : ContinuousWithinAt f s x) : + ((extChartAt I x).symm ⁻¹' s ∩ range I : Set E) =ᶠ[𝓝 (extChartAt I x x)] + ((extChartAt I x).target ∩ + (extChartAt I x).symm ⁻¹' (s ∩ f ⁻¹' (extChartAt I' (f x)).source) : Set E) := by + rw [← nhdsWithin_eq_iff_eventuallyEq] + exact hc.nhdsWithin_extChartAt_symm_preimage_inter_range + +/-! We use the name `ext_coord_change` for `(extChartAt I x').symm ≫ extChartAt I x`. -/ + +theorem ext_coord_change_source (x x' : M) : + ((extChartAt I x').symm ≫ extChartAt I x).source = + I '' ((chartAt H x').symm ≫ₕ chartAt H x).source := + extend_coord_change_source _ _ + +open IsManifold + +theorem contDiffOn_ext_coord_change [IsManifold I n M] (x x' : M) : + ContDiffOn 𝕜 n (extChartAt I x ∘ (extChartAt I x').symm) + ((extChartAt I x').symm ≫ extChartAt I x).source := + contDiffOn_extend_coord_change (chart_mem_maximalAtlas x) (chart_mem_maximalAtlas x') + +theorem contDiffWithinAt_ext_coord_change [IsManifold I n M] (x x' : M) {y : E} + (hy : y ∈ ((extChartAt I x').symm ≫ extChartAt I x).source) : + ContDiffWithinAt 𝕜 n (extChartAt I x ∘ (extChartAt I x').symm) (range I) y := + contDiffWithinAt_extend_coord_change (chart_mem_maximalAtlas x) (chart_mem_maximalAtlas x') hy + +variable (I I') in +/-- Conjugating a function to write it in the preferred charts around `x`. +The manifold derivative of `f` will just be the derivative of this conjugated function. -/ +@[simp, mfld_simps] +def writtenInExtChartAt (x : M) (f : M → M') : E → E' := + extChartAt I' (f x) ∘ f ∘ (extChartAt I x).symm + +theorem writtenInExtChartAt_chartAt {x : M} {y : E} (h : y ∈ (extChartAt I x).target) : + writtenInExtChartAt I I x (chartAt H x) y = y := by simp_all only [mfld_simps] + +theorem writtenInExtChartAt_chartAt_symm {x : M} {y : E} (h : y ∈ (extChartAt I x).target) : + writtenInExtChartAt I I (chartAt H x x) (chartAt H x).symm y = y := by + simp_all only [mfld_simps] + +theorem writtenInExtChartAt_extChartAt {x : M} {y : E} (h : y ∈ (extChartAt I x).target) : + writtenInExtChartAt I 𝓘(𝕜, E) x (extChartAt I x) y = y := by + simp_all only [mfld_simps] + +theorem writtenInExtChartAt_extChartAt_symm {x : M} {y : E} (h : y ∈ (extChartAt I x).target) : + writtenInExtChartAt 𝓘(𝕜, E) I (extChartAt I x x) (extChartAt I x).symm y = y := by + simp_all only [mfld_simps] + +variable (𝕜) + +theorem extChartAt_self_eq {x : H} : ⇑(extChartAt I x) = I := + rfl + +theorem extChartAt_self_apply {x y : H} : extChartAt I x y = I y := + rfl + +/-- 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 = PartialEquiv.refl E := by + simp only [mfld_simps] + +theorem ext_chart_model_space_apply {x y : E} : extChartAt 𝓘(𝕜, E) x y = y := + rfl + +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 `PartialEquiv.prod_trans` here because of a type + -- synonym + rw [PartialEquiv.prod_trans] + +theorem extChartAt_comp [ChartedSpace H H'] (x : M') : + (letI := ChartedSpace.comp H H' M'; extChartAt I x) = + (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) : + (letI := ChartedSpace.comp H H' M'; writtenInExtChartAt I I x (chartAt H' x) y) = y := by + letI := ChartedSpace.comp H H' M' + simp_all only [mfld_simps, chartAt_comp] + +theorem writtenInExtChartAt_chartAt_symm_comp [ChartedSpace H H'] (x : M') {y} + (hy : y ∈ letI := ChartedSpace.comp H H' M'; (extChartAt I x).target) : + ( letI := ChartedSpace.comp H H' M' + writtenInExtChartAt I I (chartAt H' x x) (chartAt H' x).symm y) = y := by + letI := ChartedSpace.comp H H' M' + simp_all only [mfld_simps, chartAt_comp] + +end ExtendedCharts + +section Topology + +-- Let `M` be a topological manifold over the field 𝕜. +variable + {E : Type*} {𝕜 : Type*} [NontriviallyNormedField 𝕜] + [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] + {M : Type*} [TopologicalSpace M] [ChartedSpace H M] + +/-- A finite-dimensional manifold modelled on a locally compact field + (such as ℝ, ℂ or the `p`-adic numbers) is locally compact. -/ +lemma Manifold.locallyCompact_of_finiteDimensional + (I : ModelWithCorners 𝕜 E H) [LocallyCompactSpace 𝕜] [FiniteDimensional 𝕜 E] : + LocallyCompactSpace M := by + have : ProperSpace E := FiniteDimensional.proper 𝕜 E + have : LocallyCompactSpace H := I.locallyCompactSpace + exact ChartedSpace.locallyCompactSpace H M + +variable (M) + +/-- A locally compact manifold must be modelled on a locally compact space. -/ +lemma LocallyCompactSpace.of_locallyCompact_manifold (I : ModelWithCorners 𝕜 E H) + [h : Nonempty M] [LocallyCompactSpace M] : + LocallyCompactSpace E := by + rcases h with ⟨x⟩ + obtain ⟨y, hy⟩ := interior_extChartAt_target_nonempty I x + have h'y : y ∈ (extChartAt I x).target := interior_subset hy + obtain ⟨s, hmem, hss, hcom⟩ := + LocallyCompactSpace.local_compact_nhds ((extChartAt I x).symm y) (extChartAt I x).source + ((isOpen_extChartAt_source x).mem_nhds ((extChartAt I x).map_target h'y)) + have : IsCompact <| (extChartAt I x) '' s := + hcom.image_of_continuousOn <| (continuousOn_extChartAt x).mono hss + apply this.locallyCompactSpace_of_mem_nhds_of_addGroup (x := y) + rw [← (extChartAt I x).right_inv h'y] + apply extChartAt_image_nhd_mem_nhds_of_mem_interior_range + (PartialEquiv.map_target (extChartAt I x) h'y) _ hmem + simp only [(extChartAt I x).right_inv h'y] + exact interior_mono (extChartAt_target_subset_range x) hy + +/-- Riesz's theorem applied to manifolds: a locally compact manifolds must be modelled on a + finite-dimensional space. This is the converse to + `Manifold.locallyCompact_of_finiteDimensional`. -/ +theorem FiniteDimensional.of_locallyCompact_manifold + [CompleteSpace 𝕜] (I : ModelWithCorners 𝕜 E H) [Nonempty M] [LocallyCompactSpace M] : + FiniteDimensional 𝕜 E := by + have := LocallyCompactSpace.of_locallyCompact_manifold M I + exact FiniteDimensional.of_locallyCompactSpace 𝕜 + +end Topology diff --git a/Mathlib/Geometry/Manifold/IsManifold/InteriorBoundary.lean b/Mathlib/Geometry/Manifold/IsManifold/InteriorBoundary.lean index 9cc24f55b4158..261cdd9783237 100644 --- a/Mathlib/Geometry/Manifold/IsManifold/InteriorBoundary.lean +++ b/Mathlib/Geometry/Manifold/IsManifold/InteriorBoundary.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Michael Rothgang -/ -import Mathlib.Geometry.Manifold.IsManifold.Basic +import Mathlib.Geometry.Manifold.IsManifold.ExtChartAt /-! # Interior and boundary of a manifold diff --git a/Mathlib/Geometry/Manifold/MFDeriv/Defs.lean b/Mathlib/Geometry/Manifold/MFDeriv/Defs.lean index 311efe82069d7..71937ee9d70ed 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv/Defs.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv/Defs.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel, Floris van Doorn -/ -import Mathlib.Geometry.Manifold.IsManifold.Basic +import Mathlib.Geometry.Manifold.IsManifold.ExtChartAt import Mathlib.Geometry.Manifold.LocalInvariantProperties /-! From 9931616554f7beb267a945604756d0e90fa97a70 Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Tue, 4 Feb 2025 15:13:06 +0000 Subject: [PATCH 072/103] chore: tidy various files (#21406) --- Mathlib/Algebra/Lie/Engel.lean | 4 +- Mathlib/Algebra/Lie/Nilpotent.lean | 3 +- Mathlib/Algebra/Lie/Solvable.lean | 4 +- Mathlib/Algebra/Order/Floor.lean | 5 +-- Mathlib/Algebra/Order/Round.lean | 6 +-- Mathlib/Algebra/Polynomial/Degree/Lemmas.lean | 8 ++-- .../Algebra/Polynomial/Degree/Operations.lean | 2 +- Mathlib/Algebra/Polynomial/Laurent.lean | 2 +- .../Morphisms/RingHomProperties.lean | 6 +-- Mathlib/Analysis/Calculus/Deriv/Prod.lean | 3 +- .../Analysis/Calculus/FDeriv/Bilinear.lean | 2 +- .../Analysis/Calculus/IteratedDeriv/Defs.lean | 2 +- .../Analysis/SpecialFunctions/Integrals.lean | 16 ++++---- Mathlib/CategoryTheory/Comma/Final.lean | 2 + .../Filtered/CostructuredArrow.lean | 6 +-- Mathlib/Data/Complex/Exponential.lean | 8 ++-- Mathlib/Data/Matroid/Basic.lean | 2 +- Mathlib/Data/Matroid/Restrict.lean | 2 +- Mathlib/FieldTheory/Galois/Infinite.lean | 40 +++++++++---------- .../LinearAlgebra/Matrix/SchurComplement.lean | 2 +- .../PerfectPairing/Restrict.lean | 2 +- Mathlib/MeasureTheory/Function/L2Space.lean | 10 +---- Mathlib/MeasureTheory/Integral/Bochner.lean | 1 - .../Integral/IntervalIntegral.lean | 12 +++--- .../Zsqrtd/QuadraticReciprocity.lean | 9 ++--- .../Probability/Moments/IntegrableExpMul.lean | 2 +- Mathlib/RingTheory/Binomial.lean | 2 +- Mathlib/RingTheory/Ideal/Height.lean | 15 ++++--- Mathlib/RingTheory/Ideal/MinimalPrime.lean | 14 +++---- Mathlib/SetTheory/Game/PGame.lean | 2 +- .../Algebra/Module/ModuleTopology.lean | 4 +- 31 files changed, 88 insertions(+), 110 deletions(-) diff --git a/Mathlib/Algebra/Lie/Engel.lean b/Mathlib/Algebra/Lie/Engel.lean index 1ce0e3176e8a1..12ae048c8bacc 100644 --- a/Mathlib/Algebra/Lie/Engel.lean +++ b/Mathlib/Algebra/Lie/Engel.lean @@ -243,9 +243,7 @@ theorem LieAlgebra.isEngelian_of_isNoetherian [IsNoetherian R L] : LieAlgebra.Is K.toSubmodule_inj] exact Submodule.Quotient.nontrivial_of_lt_top _ hK₂.lt_top have : LieModule.IsNilpotent K (L' ⧸ K.toLieSubmodule) := by - -- Porting note: was refine' hK₁ _ fun x => _ - apply hK₁ - intro x + refine hK₁ _ fun x => ?_ have hx := LieAlgebra.isNilpotent_ad_of_isNilpotent (h x) apply Module.End.IsNilpotent.mapQ ?_ hx -- Porting note: mathlib3 solved this on its own with `submodule.mapq_linear._proof_5` diff --git a/Mathlib/Algebra/Lie/Nilpotent.lean b/Mathlib/Algebra/Lie/Nilpotent.lean index f190849ca1436..5d806dcf51bcc 100644 --- a/Mathlib/Algebra/Lie/Nilpotent.lean +++ b/Mathlib/Algebra/Lie/Nilpotent.lean @@ -105,8 +105,7 @@ private theorem coe_lowerCentralSeries_eq_int_aux (R₁ R₂ L M : Type*) theorem coe_lowerCentralSeries_eq_int [LieModule R L M] (k : ℕ) : (lowerCentralSeries R L M k : Set M) = (lowerCentralSeries ℤ L M k : Set M) := by - show ((lowerCentralSeries R L M k).toSubmodule : Set M) = - ((lowerCentralSeries ℤ L M k).toSubmodule : Set M) + rw [← LieSubmodule.coe_toSubmodule, ← LieSubmodule.coe_toSubmodule] induction k with | zero => rfl | succ k ih => diff --git a/Mathlib/Algebra/Lie/Solvable.lean b/Mathlib/Algebra/Lie/Solvable.lean index 0a2796b4bdcc8..83abb377ca689 100644 --- a/Mathlib/Algebra/Lie/Solvable.lean +++ b/Mathlib/Algebra/Lie/Solvable.lean @@ -226,8 +226,8 @@ private theorem coe_derivedSeries_eq_int_aux (R₁ R₂ L : Type*) [CommRing R theorem coe_derivedSeries_eq_int (k : ℕ) : (derivedSeries R L k : Set L) = (derivedSeries ℤ L k : Set L) := by - show ((derivedSeries R L k).toSubmodule : Set L) = ((derivedSeries ℤ L k).toSubmodule : Set L) - rw [derivedSeries_def, derivedSeries_def] + rw [← LieSubmodule.coe_toSubmodule, ← LieSubmodule.coe_toSubmodule, derivedSeries_def, + derivedSeries_def] induction k with | zero => rfl | succ k ih => diff --git a/Mathlib/Algebra/Order/Floor.lean b/Mathlib/Algebra/Order/Floor.lean index e8c16c967f796..bcf1055814d61 100644 --- a/Mathlib/Algebra/Order/Floor.lean +++ b/Mathlib/Algebra/Order/Floor.lean @@ -1009,8 +1009,7 @@ theorem sub_floor_div_mul_nonneg (a : k) (hb : 0 < b) : 0 ≤ a - ⌊a / b⌋ * theorem sub_floor_div_mul_lt (a : k) (hb : 0 < b) : a - ⌊a / b⌋ * b < b := sub_lt_iff_lt_add.2 <| by - -- Porting note: `← one_add_mul` worked in mathlib3 without the argument - rw [← one_add_mul _ b, ← div_lt_iff₀ hb, add_comm] + rw [← one_add_mul, ← div_lt_iff₀ hb, add_comm] exact lt_floor_add_one _ theorem fract_div_natCast_eq_div_natCast_mod {m n : ℕ} : fract ((m : k) / n) = ↑(m % n) / n := by @@ -1055,7 +1054,7 @@ theorem fract_div_intCast_eq_div_intCast_mod {m : ℤ} {n : ℕ} : -- Porting note: the `simp` was `push_cast` simp [m₁] · congr 2 - change (q * ↑n - (↑m₀ : ℤ)) % ↑n = _ + simp only [m₁] rw [sub_eq_add_neg, add_comm (q * ↑n), add_mul_emod_self] end LinearOrderedField diff --git a/Mathlib/Algebra/Order/Round.lean b/Mathlib/Algebra/Order/Round.lean index 126741c7c3750..98d020e054484 100644 --- a/Mathlib/Algebra/Order/Round.lean +++ b/Mathlib/Algebra/Order/Round.lean @@ -205,10 +205,6 @@ variable [LinearOrderedField α] [LinearOrderedField β] [FloorRing α] [FloorRi variable [FunLike F α β] [RingHomClass F α β] {a : α} {b : β} theorem map_round (f : F) (hf : StrictMono f) (a : α) : round (f a) = round a := by - have H : f 2 = 2 := map_natCast f 2 - simp_rw [round_eq, ← map_floor _ hf, map_add, one_div, map_inv₀, H] - -- Porting note: was - -- simp_rw [round_eq, ← map_floor _ hf, map_add, one_div, map_inv₀, map_bit0, map_one] - -- Would have thought that `map_natCast` would replace `map_bit0, map_one` but seems not + simp_rw [round_eq, ← map_floor _ hf, map_add, one_div, map_inv₀, map_ofNat] end Int diff --git a/Mathlib/Algebra/Polynomial/Degree/Lemmas.lean b/Mathlib/Algebra/Polynomial/Degree/Lemmas.lean index 2d34e2ee59a96..ca530ccc1d463 100644 --- a/Mathlib/Algebra/Polynomial/Degree/Lemmas.lean +++ b/Mathlib/Algebra/Polynomial/Degree/Lemmas.lean @@ -116,8 +116,8 @@ theorem natDegree_mul_C_eq_of_mul_eq_one {ai : R} (au : a * ai = 1) : _ = (p * C a * C ai).natDegree := by rw [← C_1, ← au, RingHom.map_mul, ← mul_assoc] _ ≤ (p * C a).natDegree := natDegree_mul_C_le (p * C a) ai) -/-- Although not explicitly stated, the assumptions of lemma `nat_degree_mul_C_eq_of_mul_ne_zero` -force the polynomial `p` to be non-zero, via `p.leading_coeff ≠ 0`. +/-- Although not explicitly stated, the assumptions of lemma `natDegree_mul_C_eq_of_mul_ne_zero` +force the polynomial `p` to be non-zero, via `p.leadingCoeff ≠ 0`. -/ theorem natDegree_mul_C_eq_of_mul_ne_zero (h : p.leadingCoeff * a ≠ 0) : (p * C a).natDegree = p.natDegree := by @@ -125,8 +125,8 @@ theorem natDegree_mul_C_eq_of_mul_ne_zero (h : p.leadingCoeff * a ≠ 0) : refine mem_support_iff.mpr ?_ rwa [coeff_mul_C] -/-- Although not explicitly stated, the assumptions of lemma `nat_degree_C_mul_eq_of_mul_ne_zero` -force the polynomial `p` to be non-zero, via `p.leading_coeff ≠ 0`. +/-- Although not explicitly stated, the assumptions of lemma `natDegree_C_mul_of_mul_ne_zero` +force the polynomial `p` to be non-zero, via `p.leadingCoeff ≠ 0`. -/ theorem natDegree_C_mul_of_mul_ne_zero (h : a * p.leadingCoeff ≠ 0) : (C a * p).natDegree = p.natDegree := by diff --git a/Mathlib/Algebra/Polynomial/Degree/Operations.lean b/Mathlib/Algebra/Polynomial/Degree/Operations.lean index eab53a116f2eb..d623a5455b4d1 100644 --- a/Mathlib/Algebra/Polynomial/Degree/Operations.lean +++ b/Mathlib/Algebra/Polynomial/Degree/Operations.lean @@ -12,7 +12,7 @@ import Mathlib.Algebra.Polynomial.Degree.Definitions ## Main results - `degree_mul` : The degree of the product is the sum of degrees - `leadingCoeff_add_of_degree_eq` and `leadingCoeff_add_of_degree_lt` : - The leading_coefficient of a sum is determined by the leading coefficients and degrees + The leading coefficient of a sum is determined by the leading coefficients and degrees -/ noncomputable section diff --git a/Mathlib/Algebra/Polynomial/Laurent.lean b/Mathlib/Algebra/Polynomial/Laurent.lean index 2116b5e76bff0..c669a6de7e268 100644 --- a/Mathlib/Algebra/Polynomial/Laurent.lean +++ b/Mathlib/Algebra/Polynomial/Laurent.lean @@ -66,7 +66,7 @@ Lots is missing! -- This would likely involve adding a `comapDomain` analogue of -- `AddMonoidAlgebra.mapDomainAlgHom` and an `R`-linear version of -- `Polynomial.toFinsuppIso`. --- Add `degree, int_degree, int_trailing_degree, leading_coeff, trailing_coeff,...`. +-- Add `degree, intDegree, intTrailingDegree, leadingCoeff, trailingCoeff,...`. -/ diff --git a/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.lean b/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.lean index 625901a76887e..1bd50f02d696b 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.lean @@ -676,9 +676,9 @@ lemma of_stalkMap (hQ : OfLocalizationPrime Q) (H : ∀ x, Q (f.stalkMap x).hom) /-- Let `Q` be a property of ring maps that is stable under localization. Then if the associated property of scheme morphisms holds for `f`, `Q` holds on all stalks. -/ lemma stalkMap - (hQ : ∀ {R S : Type u} [CommRing R] [CommRing S] (f : R →+* S) (_ : Q f) - (J : Ideal S) (_ : J.IsPrime), Q (Localization.localRingHom _ J f rfl)) - (hf : P f) (x : X) : Q (f.stalkMap x).hom := by + (hQ : ∀ {R S : Type u} [CommRing R] [CommRing S] (f : R →+* S) (_ : Q f) + (J : Ideal S) (_ : J.IsPrime), Q (Localization.localRingHom _ J f rfl)) + (hf : P f) (x : X) : Q (f.stalkMap x).hom := by have hQi := (HasRingHomProperty.isLocal_ringHomProperty P).respectsIso wlog h : IsAffine X ∧ IsAffine Y generalizing X Y f · obtain ⟨U, hU, hfx, _⟩ := Opens.isBasis_iff_nbhd.mp (isBasis_affine_open Y) diff --git a/Mathlib/Analysis/Calculus/Deriv/Prod.lean b/Mathlib/Analysis/Calculus/Deriv/Prod.lean index 61e10a2f7aeef..44a1730403f4b 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Prod.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Prod.lean @@ -82,8 +82,7 @@ theorem derivWithin_pi (h : ∀ i, DifferentiableWithinAt 𝕜 (fun x => φ x i) derivWithin φ s x = fun i => derivWithin (fun x => φ x i) s x := by rcases uniqueDiffWithinAt_or_nhdsWithin_eq_bot s x with hxs | hxs · exact (hasDerivWithinAt_pi.2 fun i => (h i).hasDerivWithinAt).derivWithin hxs - · simp only [derivWithin_zero_of_isolated hxs] - rfl + · simp only [derivWithin_zero_of_isolated hxs, Pi.zero_def] theorem deriv_pi (h : ∀ i, DifferentiableAt 𝕜 (fun x => φ x i) x) : deriv φ x = fun i => deriv (fun x => φ x i) x := diff --git a/Mathlib/Analysis/Calculus/FDeriv/Bilinear.lean b/Mathlib/Analysis/Calculus/FDeriv/Bilinear.lean index ccf4ec329f8cb..d846c94c4f76d 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Bilinear.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Bilinear.lean @@ -9,7 +9,7 @@ import Mathlib.Analysis.Calculus.FDeriv.Prod # The derivative of bounded bilinear maps For detailed documentation of the Fréchet derivative, -see the module docstring of `Analysis/Calculus/FDeriv/Basic.lean`. +see the module docstring of `Mathlib/Analysis/Calculus/FDeriv/Basic.lean`. This file contains the usual formulas (and existence assertions) for the derivative of bounded bilinear maps. diff --git a/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean b/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean index d51fff9a736c0..92f314805b5c8 100644 --- a/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean +++ b/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean @@ -105,7 +105,7 @@ theorem iteratedDerivWithin_zero : iteratedDerivWithin 0 f s = f := by theorem iteratedDerivWithin_one {x : 𝕜} : iteratedDerivWithin 1 f s x = derivWithin f s x := by rcases uniqueDiffWithinAt_or_nhdsWithin_eq_bot s x with hxs | hxs - · simp only [iteratedDerivWithin, iteratedFDerivWithin_one_apply hxs]; rfl + · simp only [iteratedDerivWithin, iteratedFDerivWithin_one_apply hxs, derivWithin] · simp [derivWithin_zero_of_isolated hxs, iteratedDerivWithin, iteratedFDerivWithin, fderivWithin_zero_of_isolated hxs] diff --git a/Mathlib/Analysis/SpecialFunctions/Integrals.lean b/Mathlib/Analysis/SpecialFunctions/Integrals.lean index ee0b68c3a430b..560a30990050b 100644 --- a/Mathlib/Analysis/SpecialFunctions/Integrals.lean +++ b/Mathlib/Analysis/SpecialFunctions/Integrals.lean @@ -498,14 +498,14 @@ lemma integral_log_from_zero_of_pos (ht : 0 < b) : ∫ s in (0)..b, log s = b * /-- Helper lemma for `integral_log`: case where `a = 0`. -/ lemma integral_log_from_zero {b : ℝ} : ∫ s in (0)..b, log s = b * log b - b := by - rcases lt_trichotomy b 0 with h | h | h - · -- If t is negative, use that log is an even function to reduce to the positive case. - conv => arg 1; arg 1; intro t; rw [← log_neg_eq_log] - rw [intervalIntegral.integral_comp_neg, intervalIntegral.integral_symm, neg_zero, - integral_log_from_zero_of_pos (Left.neg_pos_iff.mpr h), log_neg_eq_log] - ring - · simp [h] - · exact integral_log_from_zero_of_pos h + rcases lt_trichotomy b 0 with h | h | h + · -- If t is negative, use that log is an even function to reduce to the positive case. + conv => arg 1; arg 1; intro t; rw [← log_neg_eq_log] + rw [intervalIntegral.integral_comp_neg, intervalIntegral.integral_symm, neg_zero, + integral_log_from_zero_of_pos (Left.neg_pos_iff.mpr h), log_neg_eq_log] + ring + · simp [h] + · exact integral_log_from_zero_of_pos h @[simp] theorem integral_log : ∫ s in a..b, log s = b * log b - a * log a - b + a := by diff --git a/Mathlib/CategoryTheory/Comma/Final.lean b/Mathlib/CategoryTheory/Comma/Final.lean index 23e5a76639305..572e5b6e2afbc 100644 --- a/Mathlib/CategoryTheory/Comma/Final.lean +++ b/Mathlib/CategoryTheory/Comma/Final.lean @@ -104,6 +104,7 @@ end NonSmall /-- Let the following diagram commute up to isomorphism: +``` L R A ---→ T ←--- B | | | @@ -111,6 +112,7 @@ end NonSmall ↓ ↓ ↓ A' ---→ T' ←--- B' L' R' +``` Let `F`, `G`, `R` and `R'` be final and `B` be filtered. Then, the induced functor between the comma categories of the first and second row of the diagram is final. -/ diff --git a/Mathlib/CategoryTheory/Filtered/CostructuredArrow.lean b/Mathlib/CategoryTheory/Filtered/CostructuredArrow.lean index 2e51870130933..20a9f5e28a65b 100644 --- a/Mathlib/CategoryTheory/Filtered/CostructuredArrow.lean +++ b/Mathlib/CategoryTheory/Filtered/CostructuredArrow.lean @@ -30,8 +30,8 @@ variable {A : Type u₁} [SmallCategory A] {B : Type u₁} [SmallCategory B] variable {T : Type u₁} [SmallCategory T] private lemma isFiltered_of_isFiltered_costructuredArrow_small (L : A ⥤ T) (R : B ⥤ T) - [IsFiltered B] [Final R] [∀ b, IsFiltered (CostructuredArrow L (R.obj b))] : IsFiltered A := - isFiltered_of_nonempty_limit_colimit_to_colimit_limit fun J {_ _} F => ⟨by + [IsFiltered B] [Final R] [∀ b, IsFiltered (CostructuredArrow L (R.obj b))] : IsFiltered A := by + refine isFiltered_of_nonempty_limit_colimit_to_colimit_limit fun J {_ _} F => ⟨?_⟩ let R' := Grothendieck.pre (CostructuredArrow.functor L) R haveI : ∀ b, PreservesLimitsOfShape J (colim (J := (R ⋙ CostructuredArrow.functor L).obj b) (C := Type u₁)) := fun b => by @@ -43,7 +43,7 @@ private lemma isFiltered_of_isFiltered_costructuredArrow_small (L : A ⥤ T) (R colim.map ?_ ≫ colimit.pre _ R' ≫ (colimitIsoColimitGrothendieck L (limit F)).inv - exact (limitCompWhiskeringLeftIsoCompLimit F (R' ⋙ CostructuredArrow.grothendieckProj L)).hom⟩ + exact (limitCompWhiskeringLeftIsoCompLimit F (R' ⋙ CostructuredArrow.grothendieckProj L)).hom end Small diff --git a/Mathlib/Data/Complex/Exponential.lean b/Mathlib/Data/Complex/Exponential.lean index fd4dfde3db5b6..91706fba563af 100644 --- a/Mathlib/Data/Complex/Exponential.lean +++ b/Mathlib/Data/Complex/Exponential.lean @@ -656,10 +656,10 @@ theorem one_sub_div_pow_le_exp_neg {n : ℕ} {t : ℝ} (ht' : t ≤ n) : (1 - t _ = rexp (-t) := by rw [← Real.exp_nat_mul, mul_neg, mul_comm, div_mul_cancel₀]; positivity lemma le_inv_mul_exp (x : ℝ) {c : ℝ} (hc : 0 < c) : x ≤ c⁻¹ * exp (c * x) := by - rw [le_inv_mul_iff₀ hc] - calc c * x - _ ≤ c * x + 1 := le_add_of_nonneg_right zero_le_one - _ ≤ _ := Real.add_one_le_exp (c * x) + rw [le_inv_mul_iff₀ hc] + calc c * x + _ ≤ c * x + 1 := le_add_of_nonneg_right zero_le_one + _ ≤ _ := Real.add_one_le_exp (c * x) end Real diff --git a/Mathlib/Data/Matroid/Basic.lean b/Mathlib/Data/Matroid/Basic.lean index 4bef987a38c32..cccb0d008e9f6 100644 --- a/Mathlib/Data/Matroid/Basic.lean +++ b/Mathlib/Data/Matroid/Basic.lean @@ -709,7 +709,7 @@ theorem Base.exists_insert_of_ssubset (hB : M.Base B) (hIB : I ⊂ B) (hB' : M.B theorem ext_iff_indep {M₁ M₂ : Matroid α} : M₁ = M₂ ↔ (M₁.E = M₂.E) ∧ ∀ ⦃I⦄, I ⊆ M₁.E → (M₁.Indep I ↔ M₂.Indep I) := -⟨fun h ↦ by (subst h; simp), fun h ↦ ext_indep h.1 h.2⟩ + ⟨fun h ↦ by (subst h; simp), fun h ↦ ext_indep h.1 h.2⟩ @[deprecated (since := "2024-12-25")] alias eq_iff_indep_iff_indep_forall := ext_iff_indep diff --git a/Mathlib/Data/Matroid/Restrict.lean b/Mathlib/Data/Matroid/Restrict.lean index fbb0716dcb9e3..b41c114c7aa41 100644 --- a/Mathlib/Data/Matroid/Restrict.lean +++ b/Mathlib/Data/Matroid/Restrict.lean @@ -458,7 +458,7 @@ theorem Indep.augment (hI : M.Indep I) (hJ : M.Indep J) (hIJ : I.encard < J.enca lemma Indep.augment_finset {I J : Finset α} (hI : M.Indep I) (hJ : M.Indep J) (hIJ : I.card < J.card) : ∃ e ∈ J, e ∉ I ∧ M.Indep (insert e I) := by - obtain ⟨x, hx, hxI⟩ := hI.augment hJ (by simpa [encard_eq_coe_toFinset_card] ) + obtain ⟨x, hx, hxI⟩ := hI.augment hJ (by simpa [encard_eq_coe_toFinset_card]) simp only [mem_diff, Finset.mem_coe] at hx exact ⟨x, hx.1, hx.2, hxI⟩ diff --git a/Mathlib/FieldTheory/Galois/Infinite.lean b/Mathlib/FieldTheory/Galois/Infinite.lean index d93b6f9fec8dc..f5077f4f72c7c 100644 --- a/Mathlib/FieldTheory/Galois/Infinite.lean +++ b/Mathlib/FieldTheory/Galois/Infinite.lean @@ -57,24 +57,24 @@ open Pointwise FiniteGaloisIntermediateField AlgEquiv lemma fixingSubgroup_isClosed (L : IntermediateField k K) [IsGalois k K] : IsClosed (L.fixingSubgroup : Set (K ≃ₐ[k] K)) where - isOpen_compl := isOpen_iff_mem_nhds.mpr fun σ h => by - apply mem_nhds_iff.mpr - rcases Set.not_subset.mp ((mem_fixingSubgroup_iff (K ≃ₐ[k] K)).not.mp h) with ⟨y, yL, ne⟩ - use σ • ((adjoin k {y}).1.fixingSubgroup : Set (K ≃ₐ[k] K)) - constructor - · intro f hf - rcases (Set.mem_smul_set.mp hf) with ⟨g, hg, eq⟩ - simp only [Set.mem_compl_iff, SetLike.mem_coe, ← eq] - apply (mem_fixingSubgroup_iff (K ≃ₐ[k] K)).not.mpr - push_neg - use y - simp only [yL, smul_eq_mul, AlgEquiv.smul_def, AlgEquiv.mul_apply, ne_eq, true_and] - have : g y = y := (mem_fixingSubgroup_iff (K ≃ₐ[k] K)).mp hg y <| - adjoin_simple_le_iff.mp le_rfl - simpa only [this, ne_eq, AlgEquiv.smul_def] using ne - · simp only [(IntermediateField.fixingSubgroup_isOpen (adjoin k {y}).1).smul σ, true_and] - use 1 - simp only [SetLike.mem_coe, smul_eq_mul, mul_one, and_true, Subgroup.one_mem] + isOpen_compl := isOpen_iff_mem_nhds.mpr fun σ h => by + apply mem_nhds_iff.mpr + rcases Set.not_subset.mp ((mem_fixingSubgroup_iff (K ≃ₐ[k] K)).not.mp h) with ⟨y, yL, ne⟩ + use σ • ((adjoin k {y}).1.fixingSubgroup : Set (K ≃ₐ[k] K)) + constructor + · intro f hf + rcases (Set.mem_smul_set.mp hf) with ⟨g, hg, eq⟩ + simp only [Set.mem_compl_iff, SetLike.mem_coe, ← eq] + apply (mem_fixingSubgroup_iff (K ≃ₐ[k] K)).not.mpr + push_neg + use y + simp only [yL, smul_eq_mul, AlgEquiv.smul_def, AlgEquiv.mul_apply, ne_eq, true_and] + have : g y = y := (mem_fixingSubgroup_iff (K ≃ₐ[k] K)).mp hg y <| + adjoin_simple_le_iff.mp le_rfl + simpa only [this, ne_eq, AlgEquiv.smul_def] using ne + · simp only [(IntermediateField.fixingSubgroup_isOpen (adjoin k {y}).1).smul σ, true_and] + use 1 + simp only [SetLike.mem_coe, smul_eq_mul, mul_one, and_true, Subgroup.one_mem] lemma fixedField_fixingSubgroup (L : IntermediateField k K) [IsGalois k K] : IntermediateField.fixedField L.fixingSubgroup = L := by @@ -119,7 +119,7 @@ lemma restrict_fixedField (H : Subgroup (K ≃ₐ[k] K)) (L : IntermediateField nth_rw 2 [← (h.out.1 ⟨σ, hσ⟩)] exact AlgEquiv.restrictNormal_commutes σ L ⟨x, xL⟩ · have xL := lift_le _ h - apply (mem_lift (⟨x,xL⟩ : L)).mp at h + apply (mem_lift (⟨x, xL⟩ : L)).mp at h simp only [mem_fixedField_iff, Subgroup.mem_map, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂] at h simp only [coe_inf, Set.mem_inter_iff, SetLike.mem_coe, mem_fixedField_iff, xL, and_true] @@ -221,7 +221,7 @@ theorem isOpen_iff_finite (L : IntermediateField k K) [IsGalois k K] : finiteDimensional := normalClosure.is_finiteDimensional k M K isGalois := IsGalois.normalClosure k M K } have : L ≤ L'.1 := by - apply LE.le.trans _ (IntermediateField.le_normalClosure M) + apply le_trans _ (IntermediateField.le_normalClosure M) rw [← fixedField_fixingSubgroup M, IntermediateField.le_iff_le] exact sub let _ : Algebra L L'.1 := RingHom.toAlgebra (IntermediateField.inclusion this) diff --git a/Mathlib/LinearAlgebra/Matrix/SchurComplement.lean b/Mathlib/LinearAlgebra/Matrix/SchurComplement.lean index eb134172c1ac3..8fd9d30fb4e36 100644 --- a/Mathlib/LinearAlgebra/Matrix/SchurComplement.lean +++ b/Mathlib/LinearAlgebra/Matrix/SchurComplement.lean @@ -13,7 +13,7 @@ This file proves properties of 2×2 block matrices `[A B; C D]` that relate to t `D - C*A⁻¹*B`. Some of the results here generalize to 2×2 matrices in a category, rather than just a ring. A few -results in this direction can be found in the file `CategoryTheory.Preadditive.Biproducts`, +results in this direction can be found in the file `Mathlib.CategoryTheory.Preadditive.Biproducts`, especially the declarations `CategoryTheory.Biprod.gaussian` and `CategoryTheory.Biprod.isoElim`. Compare with `Matrix.invertibleOfFromBlocks₁₁Invertible`. diff --git a/Mathlib/LinearAlgebra/PerfectPairing/Restrict.lean b/Mathlib/LinearAlgebra/PerfectPairing/Restrict.lean index 91153233ec4dc..2ae2dbfa6958e 100644 --- a/Mathlib/LinearAlgebra/PerfectPairing/Restrict.lean +++ b/Mathlib/LinearAlgebra/PerfectPairing/Restrict.lean @@ -181,7 +181,7 @@ lemma exists_basis_basis_of_span_eq_top_of_mem_algebraMap replace hv₃ := hv₃.restrict_scalars (R := K) <| by simp_rw [← Algebra.algebraMap_eq_smul_one] exact FaithfulSMul.algebraMap_injective K L - rw [show ((↑) : v → M) = M'.subtype ∘ v' from rfl] at hv₃ + rw [show ((↑) : v → M) = M'.subtype ∘ v' by ext; simp [v']] at hv₃ exact hv₃.of_comp suffices span K (Set.range v') = ⊤ by let e := (Module.Finite.finite_basis b).equivFin diff --git a/Mathlib/MeasureTheory/Function/L2Space.lean b/Mathlib/MeasureTheory/Function/L2Space.lean index 4fd62f0ddf78d..98ad6ab5d3964 100644 --- a/Mathlib/MeasureTheory/Function/L2Space.lean +++ b/Mathlib/MeasureTheory/Function/L2Space.lean @@ -180,21 +180,13 @@ private theorem add_left' (f f' g : α →₂[μ] E) : ⟪f + f', g⟫ = inner f simp_rw [inner_def, ← integral_add (integrable_inner (𝕜 := 𝕜) f g) (integrable_inner f' g), ← inner_add_left] refine integral_congr_ae ((coeFn_add f f').mono fun x hx => ?_) - -- Porting note: was - -- congr - -- rwa [Pi.add_apply] at hx - simp only - congr + simp only [hx, Pi.add_apply] private theorem smul_left' (f g : α →₂[μ] E) (r : 𝕜) : ⟪r • f, g⟫ = conj r * inner f g := by rw [inner_def, inner_def, ← smul_eq_mul, ← integral_smul] refine integral_congr_ae ((coeFn_smul r f).mono fun x hx => ?_) simp only rw [smul_eq_mul, ← inner_smul_left, hx, Pi.smul_apply] - -- Porting note: was - -- rw [smul_eq_mul, ← inner_smul_left] - -- congr - -- rwa [Pi.smul_apply] at hx instance innerProductSpace : InnerProductSpace 𝕜 (α →₂[μ] E) where norm_sq_eq_inner := norm_sq_eq_inner' diff --git a/Mathlib/MeasureTheory/Integral/Bochner.lean b/Mathlib/MeasureTheory/Integral/Bochner.lean index ffe1348391420..9f2447bb8437d 100644 --- a/Mathlib/MeasureTheory/Integral/Bochner.lean +++ b/Mathlib/MeasureTheory/Integral/Bochner.lean @@ -1072,7 +1072,6 @@ theorem lintegral_coe_eq_integral (f : α → ℝ≥0) (hfi : Integrable (fun x rw [ENNReal.ofReal_toReal] rw [← lt_top_iff_ne_top] convert hfi.hasFiniteIntegral - -- Porting note: `convert` no longer unfolds `HasFiniteIntegral` simp_rw [hasFiniteIntegral_iff_enorm, NNReal.enorm_eq] theorem ofReal_integral_eq_lintegral_ofReal {f : α → ℝ} (hfi : Integrable f μ) (f_nn : 0 ≤ᵐ[μ] f) : diff --git a/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean b/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean index 67539055e3558..3d35b526f3143 100644 --- a/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean +++ b/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean @@ -398,8 +398,8 @@ lemma intervalIntegrable_of_even₀ (h₁f : ∀ x, f x = f (-x)) if it is interval integrable (with respect to the volume measure) on every interval of the form `0..x`, for positive `x`. -/ theorem intervalIntegrable_of_even - (h₁f : ∀ x, f x = f (-x)) (h₂f : ∀ x, 0 < x → IntervalIntegrable f volume 0 x) (a b : ℝ) : - IntervalIntegrable f volume a b := + (h₁f : ∀ x, f x = f (-x)) (h₂f : ∀ x, 0 < x → IntervalIntegrable f volume 0 x) (a b : ℝ) : + IntervalIntegrable f volume a b := -- Split integral and apply lemma (intervalIntegrable_of_even₀ h₁f h₂f a).symm.trans (b := 0) (intervalIntegrable_of_even₀ h₁f h₂f b) @@ -410,8 +410,8 @@ interval of the form `0..x`, for positive `x`. See `intervalIntegrable_of_odd` for a stronger result.-/ lemma intervalIntegrable_of_odd₀ - (h₁f : ∀ x, -f x = f (-x)) (h₂f : ∀ x, 0 < x → IntervalIntegrable f volume 0 x) (t : ℝ) : - IntervalIntegrable f volume 0 t := by + (h₁f : ∀ x, -f x = f (-x)) (h₂f : ∀ x, 0 < x → IntervalIntegrable f volume 0 x) (t : ℝ) : + IntervalIntegrable f volume 0 t := by rcases lt_trichotomy t 0 with h | h | h · rw [IntervalIntegrable.iff_comp_neg] conv => arg 1; intro t; rw [← h₁f] @@ -424,8 +424,8 @@ lemma intervalIntegrable_of_odd₀ iff it is interval integrable (with respect to the volume measure) on every interval of the form `0..x`, for positive `x`. -/ theorem intervalIntegrable_of_odd - (h₁f : ∀ x, -f x = f (-x)) (h₂f : ∀ x, 0 < x → IntervalIntegrable f volume 0 x) (a b : ℝ) : - IntervalIntegrable f volume a b := + (h₁f : ∀ x, -f x = f (-x)) (h₂f : ∀ x, 0 < x → IntervalIntegrable f volume 0 x) (a b : ℝ) : + IntervalIntegrable f volume a b := -- Split integral and apply lemma (intervalIntegrable_of_odd₀ h₁f h₂f a).symm.trans (b := 0) (intervalIntegrable_of_odd₀ h₁f h₂f b) diff --git a/Mathlib/NumberTheory/Zsqrtd/QuadraticReciprocity.lean b/Mathlib/NumberTheory/Zsqrtd/QuadraticReciprocity.lean index 46d933b28d37c..a515d65ea4d3c 100644 --- a/Mathlib/NumberTheory/Zsqrtd/QuadraticReciprocity.lean +++ b/Mathlib/NumberTheory/Zsqrtd/QuadraticReciprocity.lean @@ -31,12 +31,9 @@ open PrincipalIdealRing theorem mod_four_eq_three_of_nat_prime_of_prime (p : ℕ) [hp : Fact p.Prime] (hpi : Prime (p : ℤ[i])) : p % 4 = 3 := hp.1.eq_two_or_odd.elim - (fun hp2 => - absurd hpi - (mt irreducible_iff_prime.2 fun ⟨_, h⟩ => by - have := h ⟨1, 1⟩ ⟨1, -1⟩ (hp2.symm ▸ rfl) - rw [← norm_eq_one_iff, ← norm_eq_one_iff] at this - exact absurd this (by decide))) + (fun hp2 => by + have := hpi.irreducible.isUnit_or_isUnit (a := ⟨1, 1⟩) (b := ⟨1, -1⟩) + simp [hp2, Zsqrtd.ext_iff, ← norm_eq_one_iff, norm_def] at this) fun hp1 => by_contradiction fun hp3 : p % 4 ≠ 3 => by have hp41 : p % 4 = 1 := by omega diff --git a/Mathlib/Probability/Moments/IntegrableExpMul.lean b/Mathlib/Probability/Moments/IntegrableExpMul.lean index 74d8ee95ca940..59cead7acca2f 100644 --- a/Mathlib/Probability/Moments/IntegrableExpMul.lean +++ b/Mathlib/Probability/Moments/IntegrableExpMul.lean @@ -137,7 +137,7 @@ lemma aemeasurable_of_integrable_exp_mul (huv : u ≠ v) (hv_int : Integrable (fun ω ↦ exp (v * X ω)) μ) : AEMeasurable X μ := by by_cases hu : u = 0 - · have hv : v ≠ 0 := fun h_eq ↦ huv (h_eq ▸ hu) + · have hv : v ≠ 0 := ne_of_ne_of_eq huv.symm hu exact aemeasurable_of_aemeasurable_exp_mul hv hv_int.aemeasurable · exact aemeasurable_of_aemeasurable_exp_mul hu hu_int.aemeasurable diff --git a/Mathlib/RingTheory/Binomial.lean b/Mathlib/RingTheory/Binomial.lean index ed46beb83286a..9905f7d8a6497 100644 --- a/Mathlib/RingTheory/Binomial.lean +++ b/Mathlib/RingTheory/Binomial.lean @@ -358,7 +358,7 @@ variable {R : Type*} section -/-- The binomial coefficient `choose r n` generalizes the natural number `choose` function, +/-- The binomial coefficient `choose r n` generalizes the natural number `Nat.choose` function, interpreted in terms of choosing without replacement. -/ def choose [AddCommGroupWithOne R] [Pow R ℕ] [BinomialRing R] (r : R) (n : ℕ) : R := multichoose (r - n + 1) n diff --git a/Mathlib/RingTheory/Ideal/Height.lean b/Mathlib/RingTheory/Ideal/Height.lean index 965faae6a18cf..ba0b56ba522ca 100644 --- a/Mathlib/RingTheory/Ideal/Height.lean +++ b/Mathlib/RingTheory/Ideal/Height.lean @@ -66,17 +66,17 @@ lemma Ideal.height_ne_top {I : Ideal R} (hI : I ≠ ⊤) [h : I.FiniteHeight] : lemma Ideal.height_lt_top {I : Ideal R} (hI : I ≠ ⊤) [h : I.FiniteHeight] : I.height < ⊤ := - lt_of_le_of_ne le_top (Ideal.height_ne_top hI) + (Ideal.height_ne_top hI).lt_top lemma Ideal.primeHeight_ne_top (I : Ideal R) [I.FiniteHeight] [h : I.IsPrime] : I.primeHeight ≠ ⊤ := by rw [← I.height_eq_primeHeight] - exact Ideal.height_ne_top (by exact h.ne_top) + exact Ideal.height_ne_top h.ne_top lemma Ideal.primeHeight_lt_top (I : Ideal R) [I.FiniteHeight] [h : I.IsPrime] : I.primeHeight < ⊤ := by rw [← I.height_eq_primeHeight] - exact Ideal.height_lt_top (by exact h.ne_top) + exact Ideal.height_lt_top h.ne_top @[gcongr] lemma Ideal.primeHeight_mono {I J : Ideal R} [I.IsPrime] [J.IsPrime] (h : I ≤ J) : @@ -101,15 +101,14 @@ lemma Ideal.primeHeight_strict_mono {I J : Ideal R} [I.IsPrime] [J.IsPrime] @[simp] theorem Ideal.height_top : (⊤ : Ideal R).height = ⊤ := by - simp only [height, minimalPrimes_top] - rw [iInf₂_eq_top]; intro i hi; exact False.elim hi + simp [height, minimalPrimes_top, iInf₂_eq_top] @[gcongr] theorem Ideal.height_mono {I J : Ideal R} (h : I ≤ J) : I.height ≤ J.height := by simp only [height] - apply le_iInf₂; intro p hp; haveI := hp.1.1 + apply le_iInf₂; intro p hp; have := Ideal.minimalPrimes_isPrime hp obtain ⟨q, hq, e⟩ := Ideal.exists_minimalPrimes_le (h.trans hp.1.2) - haveI := hq.1.1 + haveI := Ideal.minimalPrimes_isPrime hq exact (iInf₂_le q hq).trans (Ideal.primeHeight_mono e) @[gcongr] @@ -119,6 +118,6 @@ lemma Ideal.height_strict_mono_of_is_prime {I J : Ideal R} [I.IsPrime] by_cases hJ : J = ⊤ · rw [hJ, height_top]; exact I.primeHeight_lt_top · rw [← ENat.add_one_le_iff I.primeHeight_ne_top, Ideal.height] - apply le_iInf₂; intro K hK; haveI := hK.1.1 + apply le_iInf₂; intro K hK; haveI := Ideal.minimalPrimes_isPrime hK have : I < K := lt_of_lt_of_le h hK.1.2 exact Ideal.primeHeight_add_one_le_of_lt this diff --git a/Mathlib/RingTheory/Ideal/MinimalPrime.lean b/Mathlib/RingTheory/Ideal/MinimalPrime.lean index 018eb06f8338f..f64ffa92a936f 100644 --- a/Mathlib/RingTheory/Ideal/MinimalPrime.lean +++ b/Mathlib/RingTheory/Ideal/MinimalPrime.lean @@ -308,11 +308,9 @@ variable {R : Type*} [CommSemiring R] theorem Ideal.minimalPrimes_top : (⊤ : Ideal R).minimalPrimes = ∅ := by ext p - constructor - · intro h - exact False.elim (h.1.1.ne_top (top_le_iff.mp h.1.2)) - · intro h - exact False.elim (Set.not_mem_empty p h) + simp only [Set.not_mem_empty, iff_false] + intro h + exact h.1.1.ne_top (top_le_iff.mp h.1.2) theorem Ideal.minimalPrimes_eq_empty_iff (I : Ideal R) : I.minimalPrimes = ∅ ↔ I = ⊤ := by @@ -321,9 +319,9 @@ theorem Ideal.minimalPrimes_eq_empty_iff (I : Ideal R) : by_contra h have ⟨M, hM, hM'⟩ := Ideal.exists_le_maximal I h have ⟨p, hp⟩ := Ideal.exists_minimalPrimes_le hM' - show p ∈ (∅ : Set (Ideal R)) - rw [← e]; exact hp.1 - · intro h; rw [h] + rw [e] at hp + apply Set.not_mem_empty _ hp.1 + · rintro rfl exact Ideal.minimalPrimes_top end diff --git a/Mathlib/SetTheory/Game/PGame.lean b/Mathlib/SetTheory/Game/PGame.lean index ac6caee7a3166..8701a3953d5d5 100644 --- a/Mathlib/SetTheory/Game/PGame.lean +++ b/Mathlib/SetTheory/Game/PGame.lean @@ -26,7 +26,7 @@ We may denote a game as $\{L | R\}$, where $L$ and $R$ stand for the collections moves. This notation is not currently used in Mathlib. Combinatorial games themselves, as a quotient of pregames, are constructed in -`SetTheory.Game.Basic`. +`Mathlib.SetTheory.Game.Basic`. ## Conway induction diff --git a/Mathlib/Topology/Algebra/Module/ModuleTopology.lean b/Mathlib/Topology/Algebra/Module/ModuleTopology.lean index f0e637c7c1fdf..086a0e3afa9b4 100644 --- a/Mathlib/Topology/Algebra/Module/ModuleTopology.lean +++ b/Mathlib/Topology/Algebra/Module/ModuleTopology.lean @@ -309,8 +309,8 @@ theorem continuousNeg (C : Type*) [AddCommGroup C] [Module R C] [TopologicalSpac variable (R) in theorem topologicalAddGroup (C : Type*) [AddCommGroup C] [Module R C] [TopologicalSpace C] [IsModuleTopology R C] : TopologicalAddGroup C where - continuous_add := (IsModuleTopology.toContinuousAdd R C).1 - continuous_neg := continuous_neg R C + continuous_add := (IsModuleTopology.toContinuousAdd R C).1 + continuous_neg := continuous_neg R C @[fun_prop, continuity] theorem continuous_of_ringHom {R A B} [CommSemiring R] [Semiring A] [Algebra R A] [Semiring B] From 4c7f6697b4ae6d5085f8fff064f8e25c5b1f06ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Tue, 4 Feb 2025 15:53:27 +0000 Subject: [PATCH 073/103] chore: add `simp` to `Setoid.refl` (#21107) This is needed for #21086. --- Mathlib/Data/Setoid/Basic.lean | 2 +- Mathlib/NumberTheory/Padics/PadicNumbers.lean | 11 ++++------- Mathlib/SetTheory/Game/PGame.lean | 1 - 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Mathlib/Data/Setoid/Basic.lean b/Mathlib/Data/Setoid/Basic.lean index 0759b4e495bcf..4ab1fa18bdf68 100644 --- a/Mathlib/Data/Setoid/Basic.lean +++ b/Mathlib/Data/Setoid/Basic.lean @@ -30,7 +30,7 @@ reason about them using the existing `Setoid` and its infrastructure. setoid, equivalence, iseqv, relation, equivalence relation -/ -attribute [refl] Setoid.refl +attribute [refl, simp] Setoid.refl attribute [symm] Setoid.symm attribute [trans] Setoid.trans diff --git a/Mathlib/NumberTheory/Padics/PadicNumbers.lean b/Mathlib/NumberTheory/Padics/PadicNumbers.lean index c03112d1c05ed..95ddc736d2ed5 100644 --- a/Mathlib/NumberTheory/Padics/PadicNumbers.lean +++ b/Mathlib/NumberTheory/Padics/PadicNumbers.lean @@ -280,13 +280,10 @@ theorem eq_zero_iff_equiv_zero (f : PadicSeq p) : mk f = 0 ↔ f ≈ 0 := theorem ne_zero_iff_nequiv_zero (f : PadicSeq p) : mk f ≠ 0 ↔ ¬f ≈ 0 := eq_zero_iff_equiv_zero _ |>.not -theorem norm_const (q : ℚ) : norm (const (padicNorm p) q) = padicNorm p q := - if hq : q = 0 then by - have : const (padicNorm p) q ≈ 0 := by simpa [hq] using Setoid.refl (const (padicNorm p) 0) - subst hq; simp [norm, this] - else by - have : ¬const (padicNorm p) q ≈ 0 := not_equiv_zero_const_of_nonzero hq - simp [norm, this] +theorem norm_const (q : ℚ) : norm (const (padicNorm p) q) = padicNorm p q := by + obtain rfl | hq := eq_or_ne q 0 + · simp [norm] + · simp [norm, not_equiv_zero_const_of_nonzero hq] theorem norm_values_discrete (a : PadicSeq p) (ha : ¬a ≈ 0) : ∃ z : ℤ, a.norm = (p : ℚ) ^ (-z) := by let ⟨k, hk, hk'⟩ := norm_eq_norm_app_of_nonzero ha diff --git a/Mathlib/SetTheory/Game/PGame.lean b/Mathlib/SetTheory/Game/PGame.lean index 8701a3953d5d5..081885538dc04 100644 --- a/Mathlib/SetTheory/Game/PGame.lean +++ b/Mathlib/SetTheory/Game/PGame.lean @@ -850,7 +850,6 @@ theorem Equiv.le {x y : PGame} (h : x ≈ y) : x ≤ y := theorem Equiv.ge {x y : PGame} (h : x ≈ y) : y ≤ x := h.2 -@[refl, simp] theorem equiv_rfl {x : PGame} : x ≈ x := refl x From 70cd82c143a09a409476b885ae6880cdc8509243 Mon Sep 17 00:00:00 2001 From: grunweg Date: Tue, 4 Feb 2025 15:53:29 +0000 Subject: [PATCH 074/103] chore: generalise lemmas to `ENorm` spaces, part 1 (#21380) Extracted from #21375: these lemmas only change the assumption on the co-domain, but not any hypothesis. This continues the work started in #20121, #20122 and #21306: those PRs generalised the definitions resp. made lemma statements use the enorm. This PR starts generalising the lemmas using those definitions. This work is part of (and a necessary pre-requisite for) the Carleson project. --- .../NormedSpace/IndicatorFunction.lean | 16 +++- Mathlib/MeasureTheory/Function/L2Space.lean | 4 +- .../Function/LpSeminorm/Basic.lean | 95 ++++++++++--------- 3 files changed, 66 insertions(+), 49 deletions(-) diff --git a/Mathlib/Analysis/NormedSpace/IndicatorFunction.lean b/Mathlib/Analysis/NormedSpace/IndicatorFunction.lean index 22a5c81e03806..284e9dc79e286 100644 --- a/Mathlib/Analysis/NormedSpace/IndicatorFunction.lean +++ b/Mathlib/Analysis/NormedSpace/IndicatorFunction.lean @@ -7,9 +7,9 @@ import Mathlib.Algebra.Order.Group.Indicator import Mathlib.Analysis.Normed.Group.Basic /-! -# Indicator function and norm +# Indicator function and (e)norm -This file contains a few simple lemmas about `Set.indicator` and `norm`. +This file contains a few simple lemmas about `Set.indicator`, `norm` and `enorm`. ## Tags indicator, norm @@ -36,9 +36,21 @@ theorem norm_indicator_le_of_subset (h : s ⊆ t) (f : α → E) (a : α) : simp only [norm_indicator_eq_indicator_norm] exact indicator_le_indicator_of_subset ‹_› (fun _ => norm_nonneg _) _ +theorem enorm_indicator_le_of_subset (h : s ⊆ t) (f : α → E) (a : α) : + ‖indicator s f a‖ₑ ≤ ‖indicator t f a‖ₑ := by + simp only [enorm_indicator_eq_indicator_enorm] + apply indicator_le_indicator_of_subset ‹_› (zero_le _) + theorem indicator_norm_le_norm_self : indicator s (fun a => ‖f a‖) a ≤ ‖f a‖ := indicator_le_self' (fun _ _ => norm_nonneg _) a +theorem indicator_enorm_le_enorm_self : indicator s (fun a => ‖f a‖ₑ) a ≤ ‖f a‖ₑ := + indicator_le_self' (fun _ _ ↦ zero_le _) a + theorem norm_indicator_le_norm_self : ‖indicator s f a‖ ≤ ‖f a‖ := by rw [norm_indicator_eq_indicator_norm] apply indicator_norm_le_norm_self + +theorem enorm_indicator_le_enorm_self : ‖indicator s f a‖ₑ ≤ ‖f a‖ₑ := by + rw [enorm_indicator_eq_indicator_enorm] + apply indicator_enorm_le_enorm_self diff --git a/Mathlib/MeasureTheory/Function/L2Space.lean b/Mathlib/MeasureTheory/Function/L2Space.lean index 98ad6ab5d3964..61927ea1332e4 100644 --- a/Mathlib/MeasureTheory/Function/L2Space.lean +++ b/Mathlib/MeasureTheory/Function/L2Space.lean @@ -20,10 +20,8 @@ is also an inner product space, with inner product defined as `inner f g = ∫ a * `integrable_inner` : for `f` and `g` in `Lp E 2 μ`, the pointwise inner product `fun x ↦ ⟪f x, g x⟫` is integrable. * `L2.innerProductSpace` : `Lp E 2 μ` is an inner product space. - -/ - noncomputable section open TopologicalSpace MeasureTheory MeasureTheory.Lp Filter @@ -160,7 +158,7 @@ private theorem norm_sq_eq_inner' (f : α →₂[μ] E) : ‖f‖ ^ 2 = RCLike.r · rw [← ENNReal.rpow_natCast, eLpNorm_eq_eLpNorm' two_ne_zero ENNReal.ofNat_ne_top, eLpNorm', ← ENNReal.rpow_mul, one_div, h_two] simp [enorm_eq_nnnorm] - · refine (lintegral_rpow_enorm_lt_top_of_eLpNorm'_lt_top zero_lt_two ?_).ne + · refine (lintegral_rpow_enorm_lt_top_of_eLpNorm'_lt_top zero_lt_two (ε := E) ?_).ne rw [← h_two, ← eLpNorm_eq_eLpNorm' two_ne_zero ENNReal.ofNat_ne_top] exact Lp.eLpNorm_lt_top f diff --git a/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean b/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean index 99a81102f651b..671619df9c05a 100644 --- a/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean +++ b/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean @@ -70,7 +70,7 @@ this quantity is finite -/ def eLpNorm' {_ : MeasurableSpace α} (f : α → ε) (q : ℝ) (μ : Measure α) : ℝ≥0∞ := (∫⁻ a, ‖f a‖ₑ ^ q ∂μ) ^ (1 / q) -lemma eLpNorm'_eq_lintegral_enorm {_ : MeasurableSpace α} (f : α → F) (q : ℝ) (μ : Measure α) : +lemma eLpNorm'_eq_lintegral_enorm {_ : MeasurableSpace α} (f : α → ε) (q : ℝ) (μ : Measure α) : eLpNorm' f q μ = (∫⁻ a, ‖f a‖ₑ ^ q ∂μ) ^ (1 / q) := rfl @@ -81,7 +81,7 @@ alias eLpNorm'_eq_lintegral_nnnorm := eLpNorm'_eq_lintegral_enorm def eLpNormEssSup {_ : MeasurableSpace α} (f : α → ε) (μ : Measure α) := essSup (fun x => ‖f x‖ₑ) μ -lemma eLpNormEssSup_eq_essSup_enorm {_ : MeasurableSpace α} (f : α → F) (μ : Measure α) : +lemma eLpNormEssSup_eq_essSup_enorm {_ : MeasurableSpace α} (f : α → ε) (μ : Measure α) : eLpNormEssSup f μ = essSup (‖f ·‖ₑ) μ := rfl @[deprecated (since := "2025-01-17")] @@ -93,25 +93,25 @@ def eLpNorm {_ : MeasurableSpace α} (f : α → ε) (p : ℝ≥0∞) (μ : Measure α := by volume_tac) : ℝ≥0∞ := if p = 0 then 0 else if p = ∞ then eLpNormEssSup f μ else eLpNorm' f (ENNReal.toReal p) μ -theorem eLpNorm_eq_eLpNorm' (hp_ne_zero : p ≠ 0) (hp_ne_top : p ≠ ∞) {f : α → F} : +theorem eLpNorm_eq_eLpNorm' (hp_ne_zero : p ≠ 0) (hp_ne_top : p ≠ ∞) {f : α → ε} : eLpNorm f p μ = eLpNorm' f (ENNReal.toReal p) μ := by simp [eLpNorm, hp_ne_zero, hp_ne_top] -lemma eLpNorm_nnreal_eq_eLpNorm' {f : α → F} {p : ℝ≥0} (hp : p ≠ 0) : +lemma eLpNorm_nnreal_eq_eLpNorm' {f : α → ε} {p : ℝ≥0} (hp : p ≠ 0) : eLpNorm f p μ = eLpNorm' f p μ := eLpNorm_eq_eLpNorm' (by exact_mod_cast hp) ENNReal.coe_ne_top -theorem eLpNorm_eq_lintegral_rpow_enorm (hp_ne_zero : p ≠ 0) (hp_ne_top : p ≠ ∞) {f : α → F} : +theorem eLpNorm_eq_lintegral_rpow_enorm (hp_ne_zero : p ≠ 0) (hp_ne_top : p ≠ ∞) {f : α → ε} : eLpNorm f p μ = (∫⁻ x, ‖f x‖ₑ ^ p.toReal ∂μ) ^ (1 / p.toReal) := by rw [eLpNorm_eq_eLpNorm' hp_ne_zero hp_ne_top, eLpNorm'_eq_lintegral_enorm] @[deprecated (since := "2025-01-17")] alias eLpNorm_eq_lintegral_rpow_nnnorm := eLpNorm_eq_lintegral_rpow_enorm -lemma eLpNorm_nnreal_eq_lintegral {f : α → F} {p : ℝ≥0} (hp : p ≠ 0) : +lemma eLpNorm_nnreal_eq_lintegral {f : α → ε} {p : ℝ≥0} (hp : p ≠ 0) : eLpNorm f p μ = (∫⁻ x, ‖f x‖ₑ ^ (p : ℝ) ∂μ) ^ (1 / (p : ℝ)) := eLpNorm_nnreal_eq_eLpNorm' hp -theorem eLpNorm_one_eq_lintegral_enorm {f : α → F} : eLpNorm f 1 μ = ∫⁻ x, ‖f x‖ₑ ∂μ := by +theorem eLpNorm_one_eq_lintegral_enorm {f : α → ε} : eLpNorm f 1 μ = ∫⁻ x, ‖f x‖ₑ ∂μ := by simp_rw [eLpNorm_eq_lintegral_rpow_enorm one_ne_zero ENNReal.coe_ne_top, ENNReal.one_toReal, one_div_one, ENNReal.rpow_one] @@ -119,7 +119,7 @@ theorem eLpNorm_one_eq_lintegral_enorm {f : α → F} : eLpNorm f 1 μ = ∫⁻ alias eLpNorm_one_eq_lintegral_nnnorm := eLpNorm_one_eq_lintegral_enorm @[simp] -theorem eLpNorm_exponent_top {f : α → F} : eLpNorm f ∞ μ = eLpNormEssSup f μ := by simp [eLpNorm] +theorem eLpNorm_exponent_top {f : α → ε} : eLpNorm f ∞ μ = eLpNormEssSup f μ := by simp [eLpNorm] /-- The property that `f:α→E` is ae strongly measurable and `(∫ ‖f a‖^p ∂μ)^(1/p)` is finite if `p < ∞`, or `essSup f < ∞` if `p = ∞`. -/ @@ -127,11 +127,11 @@ def Memℒp {α} {_ : MeasurableSpace α} [TopologicalSpace ε] (f : α → ε) (μ : Measure α := by volume_tac) : Prop := AEStronglyMeasurable f μ ∧ eLpNorm f p μ < ∞ -theorem Memℒp.aestronglyMeasurable {f : α → E} {p : ℝ≥0∞} (h : Memℒp f p μ) : +theorem Memℒp.aestronglyMeasurable [TopologicalSpace ε] {f : α → ε} {p : ℝ≥0∞} (h : Memℒp f p μ) : AEStronglyMeasurable f μ := h.1 -theorem lintegral_rpow_enorm_eq_rpow_eLpNorm' {f : α → F} (hq0_lt : 0 < q) : +theorem lintegral_rpow_enorm_eq_rpow_eLpNorm' {f : α → ε} (hq0_lt : 0 < q) : ∫⁻ a, ‖f a‖ₑ ^ q ∂μ = eLpNorm' f q μ ^ q := by rw [eLpNorm'_eq_lintegral_enorm, ← ENNReal.rpow_mul, one_div, inv_mul_cancel₀, ENNReal.rpow_one] exact hq0_lt.ne' @@ -139,7 +139,7 @@ theorem lintegral_rpow_enorm_eq_rpow_eLpNorm' {f : α → F} (hq0_lt : 0 < q) : @[deprecated (since := "2025-01-17")] alias lintegral_rpow_nnnorm_eq_rpow_eLpNorm' := lintegral_rpow_enorm_eq_rpow_eLpNorm' -lemma eLpNorm_nnreal_pow_eq_lintegral {f : α → F} {p : ℝ≥0} (hp : p ≠ 0) : +lemma eLpNorm_nnreal_pow_eq_lintegral {f : α → ε} {p : ℝ≥0} (hp : p ≠ 0) : eLpNorm f p μ ^ (p : ℝ) = ∫⁻ x, ‖f x‖ₑ ^ (p : ℝ) ∂μ := by simp [eLpNorm_eq_eLpNorm' (by exact_mod_cast hp) ENNReal.coe_ne_top, lintegral_rpow_enorm_eq_rpow_eLpNorm' ((NNReal.coe_pos.trans pos_iff_ne_zero).mpr hp)] @@ -148,13 +148,15 @@ end ℒpSpaceDefinition section Top -theorem Memℒp.eLpNorm_lt_top {f : α → E} (hfp : Memℒp f p μ) : eLpNorm f p μ < ∞ := +theorem Memℒp.eLpNorm_lt_top [TopologicalSpace ε] {f : α → ε} (hfp : Memℒp f p μ) : + eLpNorm f p μ < ∞ := hfp.2 -theorem Memℒp.eLpNorm_ne_top {f : α → E} (hfp : Memℒp f p μ) : eLpNorm f p μ ≠ ∞ := +theorem Memℒp.eLpNorm_ne_top [TopologicalSpace ε] {f : α → ε} (hfp : Memℒp f p μ) : + eLpNorm f p μ ≠ ∞ := ne_of_lt hfp.2 -theorem lintegral_rpow_enorm_lt_top_of_eLpNorm'_lt_top {f : α → F} (hq0_lt : 0 < q) +theorem lintegral_rpow_enorm_lt_top_of_eLpNorm'_lt_top {f : α → ε} (hq0_lt : 0 < q) (hfq : eLpNorm' f q μ < ∞) : ∫⁻ a, ‖f a‖ₑ ^ q ∂μ < ∞ := by rw [lintegral_rpow_enorm_eq_rpow_eLpNorm' hq0_lt] exact ENNReal.rpow_lt_top_of_nonneg (le_of_lt hq0_lt) (ne_of_lt hfq) @@ -163,7 +165,7 @@ theorem lintegral_rpow_enorm_lt_top_of_eLpNorm'_lt_top {f : α → F} (hq0_lt : alias lintegral_rpow_nnnorm_lt_top_of_eLpNorm'_lt_top' := lintegral_rpow_enorm_lt_top_of_eLpNorm'_lt_top -theorem lintegral_rpow_enorm_lt_top_of_eLpNorm_lt_top {f : α → F} (hp_ne_zero : p ≠ 0) +theorem lintegral_rpow_enorm_lt_top_of_eLpNorm_lt_top {f : α → ε} (hp_ne_zero : p ≠ 0) (hp_ne_top : p ≠ ∞) (hfp : eLpNorm f p μ < ∞) : ∫⁻ a, ‖f a‖ₑ ^ p.toReal ∂μ < ∞ := by apply lintegral_rpow_enorm_lt_top_of_eLpNorm'_lt_top · exact ENNReal.toReal_pos hp_ne_zero hp_ne_top @@ -173,7 +175,7 @@ theorem lintegral_rpow_enorm_lt_top_of_eLpNorm_lt_top {f : α → F} (hp_ne_zero alias lintegral_rpow_nnnorm_lt_top_of_eLpNorm_lt_top := lintegral_rpow_enorm_lt_top_of_eLpNorm_lt_top -theorem eLpNorm_lt_top_iff_lintegral_rpow_nnnorm_lt_top {f : α → F} (hp_ne_zero : p ≠ 0) +theorem eLpNorm_lt_top_iff_lintegral_rpow_nnnorm_lt_top {f : α → ε} (hp_ne_zero : p ≠ 0) (hp_ne_top : p ≠ ∞) : eLpNorm f p μ < ∞ ↔ ∫⁻ a, (‖f a‖ₑ) ^ p.toReal ∂μ < ∞ := ⟨lintegral_rpow_enorm_lt_top_of_eLpNorm_lt_top hp_ne_zero hp_ne_top, by intro h @@ -187,14 +189,14 @@ end Top section Zero @[simp] -theorem eLpNorm'_exponent_zero {f : α → F} : eLpNorm' f 0 μ = 1 := by +theorem eLpNorm'_exponent_zero {f : α → ε} : eLpNorm' f 0 μ = 1 := by rw [eLpNorm', div_zero, ENNReal.rpow_zero] @[simp] -theorem eLpNorm_exponent_zero {f : α → F} : eLpNorm f 0 μ = 0 := by simp [eLpNorm] +theorem eLpNorm_exponent_zero {f : α → ε} : eLpNorm f 0 μ = 0 := by simp [eLpNorm] @[simp] -theorem memℒp_zero_iff_aestronglyMeasurable {f : α → E} : +theorem memℒp_zero_iff_aestronglyMeasurable [TopologicalSpace ε] {f : α → ε} : Memℒp f 0 μ ↔ AEStronglyMeasurable f μ := by simp [Memℒp, eLpNorm_exponent_zero] @[simp] @@ -233,21 +235,21 @@ theorem eLpNorm_zero' : eLpNorm (fun _ : α => (0 : F)) p μ = 0 := by convert e variable [MeasurableSpace α] -theorem eLpNorm'_measure_zero_of_pos {f : α → F} (hq_pos : 0 < q) : +theorem eLpNorm'_measure_zero_of_pos {f : α → ε} (hq_pos : 0 < q) : eLpNorm' f q (0 : Measure α) = 0 := by simp [eLpNorm', hq_pos] -theorem eLpNorm'_measure_zero_of_exponent_zero {f : α → F} : eLpNorm' f 0 (0 : Measure α) = 1 := by +theorem eLpNorm'_measure_zero_of_exponent_zero {f : α → ε} : eLpNorm' f 0 (0 : Measure α) = 1 := by simp [eLpNorm'] -theorem eLpNorm'_measure_zero_of_neg {f : α → F} (hq_neg : q < 0) : +theorem eLpNorm'_measure_zero_of_neg {f : α → ε} (hq_neg : q < 0) : eLpNorm' f q (0 : Measure α) = ∞ := by simp [eLpNorm', hq_neg] @[simp] -theorem eLpNormEssSup_measure_zero {f : α → F} : eLpNormEssSup f (0 : Measure α) = 0 := by +theorem eLpNormEssSup_measure_zero {f : α → ε} : eLpNormEssSup f (0 : Measure α) = 0 := by simp [eLpNormEssSup] @[simp] -theorem eLpNorm_measure_zero {f : α → F} : eLpNorm f p (0 : Measure α) = 0 := by +theorem eLpNorm_measure_zero {f : α → ε} : eLpNorm f p (0 : Measure α) = 0 := by by_cases h0 : p = 0 · simp [h0] by_cases h_top : p = ∞ @@ -255,7 +257,8 @@ theorem eLpNorm_measure_zero {f : α → F} : eLpNorm f p (0 : Measure α) = 0 : rw [← Ne] at h0 simp [eLpNorm_eq_eLpNorm' h0 h_top, eLpNorm', ENNReal.toReal_pos h0 h_top] -@[simp] lemma memℒp_measure_zero {f : α → F} : Memℒp f p (0 : Measure α) := by simp [Memℒp] +@[simp] lemma memℒp_measure_zero [TopologicalSpace ε] {f : α → ε} : Memℒp f p (0 : Measure α) := by + simp [Memℒp] end Zero @@ -286,7 +289,7 @@ end Neg section Const -theorem eLpNorm'_const (c : F) (hq_pos : 0 < q) : +theorem eLpNorm'_const (c : ε) (hq_pos : 0 < q) : eLpNorm' (fun _ : α => c) q μ = ‖c‖ₑ * μ Set.univ ^ (1 / q) := by rw [eLpNorm'_eq_lintegral_enorm, lintegral_const, ENNReal.mul_rpow_of_nonneg _ _ (by simp [hq_pos.le] : 0 ≤ 1 / q)] @@ -306,19 +309,19 @@ theorem eLpNorm'_const' [IsFiniteMeasure μ] (c : F) (hc_ne_zero : c ≠ 0) (hq_ · rw [Ne, ENNReal.rpow_eq_top_iff, not_or, not_and_or, not_and_or] simp [hc_ne_zero] -theorem eLpNormEssSup_const (c : F) (hμ : μ ≠ 0) : eLpNormEssSup (fun _ : α => c) μ = ‖c‖ₑ := by +theorem eLpNormEssSup_const (c : ε) (hμ : μ ≠ 0) : eLpNormEssSup (fun _ : α => c) μ = ‖c‖ₑ := by rw [eLpNormEssSup_eq_essSup_enorm, essSup_const _ hμ] -theorem eLpNorm'_const_of_isProbabilityMeasure (c : F) (hq_pos : 0 < q) [IsProbabilityMeasure μ] : +theorem eLpNorm'_const_of_isProbabilityMeasure (c : ε) (hq_pos : 0 < q) [IsProbabilityMeasure μ] : eLpNorm' (fun _ : α => c) q μ = ‖c‖ₑ := by simp [eLpNorm'_const c hq_pos, measure_univ] -theorem eLpNorm_const (c : F) (h0 : p ≠ 0) (hμ : μ ≠ 0) : +theorem eLpNorm_const (c : ε) (h0 : p ≠ 0) (hμ : μ ≠ 0) : eLpNorm (fun _ : α => c) p μ = ‖c‖ₑ * μ Set.univ ^ (1 / ENNReal.toReal p) := by by_cases h_top : p = ∞ · simp [h_top, eLpNormEssSup_const c hμ] simp [eLpNorm_eq_eLpNorm' h0 h_top, eLpNorm'_const, ENNReal.toReal_pos h0 h_top] -theorem eLpNorm_const' (c : F) (h0 : p ≠ 0) (h_top : p ≠ ∞) : +theorem eLpNorm_const' (c : ε) (h0 : p ≠ 0) (h_top : p ≠ ∞) : eLpNorm (fun _ : α => c) p μ = ‖c‖ₑ * μ Set.univ ^ (1 / ENNReal.toReal p) := by simp [eLpNorm_eq_eLpNorm' h0 h_top, eLpNorm'_const, ENNReal.toReal_pos h0 h_top] @@ -552,20 +555,20 @@ theorem memℒp_of_bounded [IsFiniteMeasure μ] (memℒp_const (max |a| |b|)).mono' hX (by filter_upwards [ha, hb] with x using abs_le_max_abs_abs) @[gcongr, mono] -theorem eLpNorm'_mono_measure (f : α → F) (hμν : ν ≤ μ) (hq : 0 ≤ q) : +theorem eLpNorm'_mono_measure (f : α → ε) (hμν : ν ≤ μ) (hq : 0 ≤ q) : eLpNorm' f q ν ≤ eLpNorm' f q μ := by simp_rw [eLpNorm'] gcongr exact lintegral_mono' hμν le_rfl @[gcongr, mono] -theorem eLpNormEssSup_mono_measure (f : α → F) (hμν : ν ≪ μ) : +theorem eLpNormEssSup_mono_measure (f : α → ε) (hμν : ν ≪ μ) : eLpNormEssSup f ν ≤ eLpNormEssSup f μ := by simp_rw [eLpNormEssSup] exact essSup_mono_measure hμν @[gcongr, mono] -theorem eLpNorm_mono_measure (f : α → F) (hμν : ν ≤ μ) : eLpNorm f p ν ≤ eLpNorm f p μ := by +theorem eLpNorm_mono_measure (f : α → ε) (hμν : ν ≤ μ) : eLpNorm f p ν ≤ eLpNorm f p μ := by by_cases hp0 : p = 0 · simp [hp0] by_cases hp_top : p = ∞ @@ -573,11 +576,12 @@ theorem eLpNorm_mono_measure (f : α → F) (hμν : ν ≤ μ) : eLpNorm f p ν simp_rw [eLpNorm_eq_eLpNorm' hp0 hp_top] exact eLpNorm'_mono_measure f hμν ENNReal.toReal_nonneg -theorem Memℒp.mono_measure {f : α → E} (hμν : ν ≤ μ) (hf : Memℒp f p μ) : Memℒp f p ν := +theorem Memℒp.mono_measure [TopologicalSpace ε] {f : α → ε} (hμν : ν ≤ μ) (hf : Memℒp f p μ) : + Memℒp f p ν := ⟨hf.1.mono_measure hμν, (eLpNorm_mono_measure f hμν).trans_lt hf.2⟩ section Indicator -variable {c : F} {hf : AEStronglyMeasurable f μ} {s : Set α} +variable {c : ε} {hf : AEStronglyMeasurable f μ} {s : Set α} lemma eLpNorm_indicator_eq_eLpNorm_restrict (hs : MeasurableSet s) : eLpNorm (s.indicator f) p μ = eLpNorm f p (μ.restrict s) := by @@ -635,6 +639,9 @@ lemma eLpNormEssSup_indicator_const_eq (s : Set α) (c : G) (hμs : μ s ≠ 0) refine hμs (measure_mono_null (fun x hx_mem => ?_) h') rw [Set.mem_setOf_eq, Set.indicator_of_mem hx_mem, enorm_eq_nnnorm] +-- The following lemmas require [Zero F]. +variable {c : F} + lemma eLpNorm_indicator_const₀ (hs : NullMeasurableSet s μ) (hp : p ≠ 0) (hp_top : p ≠ ∞) : eLpNorm (s.indicator fun _ => c) p μ = ‖c‖ₑ * μ s ^ (1 / p.toReal) := have hp_pos : 0 < p.toReal := ENNReal.toReal_pos hp hp_top @@ -692,14 +699,14 @@ lemma memℒp_indicator_const (p : ℝ≥0∞) (hs : MeasurableSet s) (c : E) (h · have := Fact.mk hμ.lt_top apply memℒp_const -lemma eLpNormEssSup_piecewise (f g : α → E) [DecidablePred (· ∈ s)] (hs : MeasurableSet s) : +lemma eLpNormEssSup_piecewise (f g : α → ε) [DecidablePred (· ∈ s)] (hs : MeasurableSet s) : eLpNormEssSup (Set.piecewise s f g) μ = max (eLpNormEssSup f (μ.restrict s)) (eLpNormEssSup g (μ.restrict sᶜ)) := by simp only [eLpNormEssSup, ← ENNReal.essSup_piecewise hs] congr with x by_cases hx : x ∈ s <;> simp [hx] -lemma eLpNorm_top_piecewise (f g : α → E) [DecidablePred (· ∈ s)] (hs : MeasurableSet s) : +lemma eLpNorm_top_piecewise (f g : α → ε) [DecidablePred (· ∈ s)] (hs : MeasurableSet s) : eLpNorm (Set.piecewise s f g) ∞ μ = max (eLpNorm f ∞ (μ.restrict s)) (eLpNorm g ∞ (μ.restrict sᶜ)) := eLpNormEssSup_piecewise f g hs @@ -745,10 +752,11 @@ theorem eLpNorm_restrict_eq_of_support_subset {s : Set α} {f : α → F} (hsf : have : ¬(p.toReal ≤ 0) := by simpa only [not_le] using ENNReal.toReal_pos hp0 hp_top simpa [this] using hsf -theorem Memℒp.restrict (s : Set α) {f : α → E} (hf : Memℒp f p μ) : Memℒp f p (μ.restrict s) := +theorem Memℒp.restrict [TopologicalSpace ε] (s : Set α) {f : α → ε} (hf : Memℒp f p μ) : + Memℒp f p (μ.restrict s) := hf.mono_measure Measure.restrict_le_self -theorem eLpNorm'_smul_measure {p : ℝ} (hp : 0 ≤ p) {f : α → F} (c : ℝ≥0∞) : +theorem eLpNorm'_smul_measure {p : ℝ} (hp : 0 ≤ p) {f : α → ε} (c : ℝ≥0∞) : eLpNorm' f p (c • μ) = c ^ (1 / p) * eLpNorm' f p μ := by rw [eLpNorm', lintegral_smul_measure, ENNReal.mul_rpow_of_nonneg, eLpNorm'] simp [hp] @@ -766,7 +774,7 @@ end SMul /-- Use `eLpNorm_smul_measure_of_ne_top` instead. -/ private theorem eLpNorm_smul_measure_of_ne_zero_of_ne_top {p : ℝ≥0∞} (hp_ne_zero : p ≠ 0) - (hp_ne_top : p ≠ ∞) {f : α → F} (c : ℝ≥0∞) : + (hp_ne_top : p ≠ ∞) {f : α → ε} (c : ℝ≥0∞) : eLpNorm f p (c • μ) = c ^ (1 / p).toReal • eLpNorm f p μ := by simp_rw [eLpNorm_eq_eLpNorm' hp_ne_zero hp_ne_top] rw [eLpNorm'_smul_measure ENNReal.toReal_nonneg] @@ -872,7 +880,7 @@ theorem eLpNorm'_eq_zero_iff (hq0_lt : 0 < q) {f : α → E} (hf : AEStronglyMea eLpNorm' f q μ = 0 ↔ f =ᵐ[μ] 0 := ⟨ae_eq_zero_of_eLpNorm'_eq_zero (le_of_lt hq0_lt) hf, eLpNorm'_eq_zero_of_ae_zero hq0_lt⟩ -theorem coe_nnnorm_ae_le_eLpNormEssSup {_ : MeasurableSpace α} (f : α → F) (μ : Measure α) : +theorem coe_nnnorm_ae_le_eLpNormEssSup {_ : MeasurableSpace α} (f : α → ε) (μ : Measure α) : ∀ᵐ x ∂μ, ‖f x‖ₑ ≤ eLpNormEssSup f μ := ENNReal.ae_le_essSup fun x => ‖f x‖ₑ @@ -891,7 +899,7 @@ theorem eLpNorm_eq_zero_of_ae_zero {f : α → E} (hf : f =ᵐ[μ] 0) : eLpNorm rw [← eLpNorm_zero (p := p) (μ := μ) (α := α) (F := E)] exact eLpNorm_congr_ae hf -theorem ae_le_eLpNormEssSup {f : α → F} : ∀ᵐ y ∂μ, ‖f y‖ₑ ≤ eLpNormEssSup f μ := +theorem ae_le_eLpNormEssSup {f : α → ε} : ∀ᵐ y ∂μ, ‖f y‖ₑ ≤ eLpNormEssSup f μ := ae_le_essSup lemma eLpNormEssSup_lt_top_iff_isBoundedUnder : @@ -900,7 +908,7 @@ lemma eLpNormEssSup_lt_top_iff_isBoundedUnder : simp_rw [← ENNReal.coe_le_coe, ENNReal.coe_toNNReal h.ne]; exact ae_le_eLpNormEssSup⟩ mpr := by rintro ⟨C, hC⟩; exact eLpNormEssSup_lt_top_of_ae_nnnorm_bound (C := C) hC -theorem meas_eLpNormEssSup_lt {f : α → F} : μ { y | eLpNormEssSup f μ < ‖f y‖ₑ } = 0 := +theorem meas_eLpNormEssSup_lt {f : α → ε} : μ { y | eLpNormEssSup f μ < ‖f y‖ₑ } = 0 := meas_essSup_lt lemma eLpNorm_lt_top_of_finite [Finite α] [IsFiniteMeasure μ] : eLpNorm f p μ < ∞ := by @@ -1097,7 +1105,6 @@ end BoundedSMul The inequalities in the previous section are now tight. -/ - section NormedSpace variable {𝕜 : Type*} [NormedDivisionRing 𝕜] [MulActionWithZero 𝕜 E] [Module 𝕜 F] From abba725927369cca24aff82d02b70755c4f80e82 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Tue, 4 Feb 2025 15:53:30 +0000 Subject: [PATCH 075/103] chore: split mapDomain out of MonoidAlgebra.Defs (#21398) This is not the most inspired split, but it gets MonoidAlgebra.Defs below the longFile limit. If this provokes someone into working out how to do a better split, that's wonderful. :-) --- Mathlib.lean | 1 + Mathlib/Algebra/MonoidAlgebra/Basic.lean | 2 +- Mathlib/Algebra/MonoidAlgebra/Defs.lean | 143 +------------- Mathlib/Algebra/MonoidAlgebra/Ideal.lean | 2 +- Mathlib/Algebra/MonoidAlgebra/MapDomain.lean | 189 +++++++++++++++++++ Mathlib/Algebra/MonoidAlgebra/Support.lean | 2 +- Mathlib/Algebra/Polynomial/Basic.lean | 2 +- 7 files changed, 197 insertions(+), 144 deletions(-) create mode 100644 Mathlib/Algebra/MonoidAlgebra/MapDomain.lean diff --git a/Mathlib.lean b/Mathlib.lean index e569f1892a12f..dcc248dd73a0c 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -634,6 +634,7 @@ import Mathlib.Algebra.MonoidAlgebra.Degree import Mathlib.Algebra.MonoidAlgebra.Division import Mathlib.Algebra.MonoidAlgebra.Grading import Mathlib.Algebra.MonoidAlgebra.Ideal +import Mathlib.Algebra.MonoidAlgebra.MapDomain import Mathlib.Algebra.MonoidAlgebra.NoZeroDivisors import Mathlib.Algebra.MonoidAlgebra.Support import Mathlib.Algebra.MonoidAlgebra.ToDirectSum diff --git a/Mathlib/Algebra/MonoidAlgebra/Basic.lean b/Mathlib/Algebra/MonoidAlgebra/Basic.lean index a7b104c761768..9f7015455cb3b 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Basic.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Basic.lean @@ -7,7 +7,7 @@ import Mathlib.Algebra.Algebra.Equiv import Mathlib.Algebra.Algebra.NonUnitalHom import Mathlib.Algebra.BigOperators.Finsupp import Mathlib.Algebra.Module.BigOperators -import Mathlib.Algebra.MonoidAlgebra.Defs +import Mathlib.Algebra.MonoidAlgebra.MapDomain import Mathlib.Data.Finsupp.SMul import Mathlib.LinearAlgebra.Finsupp.SumProd diff --git a/Mathlib/Algebra/MonoidAlgebra/Defs.lean b/Mathlib/Algebra/MonoidAlgebra/Defs.lean index b8b39be30757e..6bd2c664a5817 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Defs.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Defs.lean @@ -52,8 +52,6 @@ assert_not_exists NonUnitalAlgHom AlgEquiv noncomputable section -open Finset - open Finsupp hiding single mapDomain universe u₁ u₂ u₃ u₄ @@ -74,11 +72,9 @@ endowed with the convolution product. def MonoidAlgebra : Type max u₁ u₂ := G →₀ k --- Porting note: The compiler couldn't derive this. instance MonoidAlgebra.inhabited : Inhabited (MonoidAlgebra k G) := inferInstanceAs (Inhabited (G →₀ k)) --- Porting note: The compiler couldn't derive this. instance MonoidAlgebra.addCommMonoid : AddCommMonoid (MonoidAlgebra k G) := inferInstanceAs (AddCommMonoid (G →₀ k)) @@ -124,14 +120,6 @@ theorem single_apply {a a' : G} {b : k} [Decidable (a = a')] : @[simp] theorem single_eq_zero {a : G} {b : k} : single a b = 0 ↔ b = 0 := Finsupp.single_eq_zero -abbrev mapDomain {G' : Type*} (f : G → G') (v : MonoidAlgebra k G) : MonoidAlgebra k G' := - Finsupp.mapDomain f v - -theorem mapDomain_sum {k' G' : Type*} [Semiring k'] {f : G → G'} {s : MonoidAlgebra k' G} - {v : G → k' → MonoidAlgebra k G} : - mapDomain f (s.sum v) = s.sum fun a b => mapDomain f (v a b) := - Finsupp.mapDomain_sum - /-- A non-commutative version of `MonoidAlgebra.lift`: given an additive homomorphism `f : k →+ R` and a homomorphism `g : G → R`, returns the additive homomorphism from `MonoidAlgebra k G` such that `liftNC f g (single a b) = f b * g a`. If `f` is a ring homomorphism @@ -441,8 +429,6 @@ section MiscTheorems variable [Semiring k] --- attribute [local reducible] MonoidAlgebra -- Porting note: `reducible` cannot be `local`. - theorem mul_apply [DecidableEq G] [Mul G] (f g : MonoidAlgebra k G) (x : G) : (f * g) x = f.sum fun a₁ b₁ => g.sum fun a₂ b₂ => if a₁ * a₂ = x then b₁ * b₂ else 0 := by -- Porting note: `reducible` cannot be `local` so proof gets long. @@ -450,6 +436,7 @@ theorem mul_apply [DecidableEq G] [Mul G] (f g : MonoidAlgebra k G) (x : G) : rw [Finsupp.sum_apply]; congr; ext apply single_apply +open Finset in theorem mul_apply_antidiagonal [Mul G] (f g : MonoidAlgebra k G) (x : G) (s : Finset (G × G)) (hs : ∀ {p : G × G}, p ∈ s ↔ p.1 * p.2 = x) : (f * g) x = ∑ p ∈ s, f p.1 * g p.2 := by classical exact @@ -495,27 +482,6 @@ theorem single_pow [Monoid G] {a : G} {b : k} : ∀ n : ℕ, single a b ^ n = si section -/-- Like `Finsupp.mapDomain_zero`, but for the `1` we define in this file -/ -@[simp] -theorem mapDomain_one {α : Type*} {β : Type*} {α₂ : Type*} [Semiring β] [One α] [One α₂] - {F : Type*} [FunLike F α α₂] [OneHomClass F α α₂] (f : F) : - (mapDomain f (1 : MonoidAlgebra β α) : MonoidAlgebra β α₂) = (1 : MonoidAlgebra β α₂) := by - simp_rw [one_def, mapDomain_single, map_one] - -/-- Like `Finsupp.mapDomain_add`, but for the convolutive multiplication we define in this file -/ -theorem mapDomain_mul {α : Type*} {β : Type*} {α₂ : Type*} [Semiring β] [Mul α] [Mul α₂] - {F : Type*} [FunLike F α α₂] [MulHomClass F α α₂] (f : F) (x y : MonoidAlgebra β α) : - mapDomain f (x * y) = mapDomain f x * mapDomain f y := by - simp_rw [mul_def, mapDomain_sum, mapDomain_single, map_mul] - rw [Finsupp.sum_mapDomain_index] - · congr - ext a b - rw [Finsupp.sum_mapDomain_index] - · simp - · simp [mul_add] - · simp - · simp [add_mul] - variable (k G) /-- The embedding of a magma into its magma algebra. -/ @@ -684,15 +650,6 @@ def singleOneRingHom [Semiring k] [MulOneClass G] : k →+* MonoidAlgebra k G := map_one' := rfl map_mul' := fun x y => by simp } -/-- If `f : G → H` is a multiplicative homomorphism between two monoids, then -`Finsupp.mapDomain f` is a ring homomorphism between their monoid algebras. -/ -@[simps] -def mapDomainRingHom (k : Type*) {H F : Type*} [Semiring k] [Monoid G] [Monoid H] - [FunLike F G H] [MonoidHomClass F G H] (f : F) : MonoidAlgebra k G →+* MonoidAlgebra k H := - { (Finsupp.mapDomain.addMonoidHom f : MonoidAlgebra k G →+ MonoidAlgebra k H) with - map_one' := mapDomain_one f - map_mul' := fun x y => mapDomain_mul f x y } - /-- If two ring homomorphisms from `MonoidAlgebra k G` are equal on all `single a 1` and `single 1 b`, then they are equal. -/ theorem ringHom_ext {R} [Semiring k] [MulOneClass G] [Semiring R] {f g : MonoidAlgebra k G →+* R} @@ -730,8 +687,7 @@ universe ui variable {ι : Type ui} --- attribute [local reducible] MonoidAlgebra -- Porting note: `reducible` cannot be `local`. - +open Finset in theorem prod_single [CommSemiring k] [CommMonoid G] {s : Finset ι} {a : ι → G} {b : ι → k} : (∏ i ∈ s, single (a i) (b i)) = single (∏ i ∈ s, a i) (∏ i ∈ s, b i) := Finset.cons_induction_on s rfl fun a s has ih => by @@ -744,8 +700,6 @@ section -- We now prove some additional statements that hold for group algebras. variable [Semiring k] [Group G] --- attribute [local reducible] MonoidAlgebra -- Porting note: `reducible` cannot be `local`. - @[simp] theorem mul_single_apply (f : MonoidAlgebra k G) (r : k) (x y : G) : (f * single x r) y = f (y * x⁻¹) * r := @@ -865,11 +819,9 @@ scoped[AddMonoidAlgebra] notation:9000 R:max "[" A "]" => AddMonoidAlgebra R A namespace AddMonoidAlgebra --- Porting note: The compiler couldn't derive this. instance inhabited : Inhabited k[G] := inferInstanceAs (Inhabited (G →₀ k)) --- Porting note: The compiler couldn't derive this. instance addCommMonoid : AddCommMonoid k[G] := inferInstanceAs (AddCommMonoid (G →₀ k)) @@ -891,9 +843,6 @@ section variable [Semiring k] [NonUnitalNonAssocSemiring R] --- Porting note: `reducible` cannot be `local`, so we replace some definitions and theorems with --- new ones which have new types. - abbrev single (a : G) (b : k) : k[G] := Finsupp.single a b theorem single_zero (a : G) : (single a 0 : k[G]) = 0 := Finsupp.single_zero a @@ -917,18 +866,6 @@ theorem single_apply {a a' : G} {b : k} [Decidable (a = a')] : @[simp] theorem single_eq_zero {a : G} {b : k} : single a b = 0 ↔ b = 0 := Finsupp.single_eq_zero -abbrev mapDomain {G' : Type*} (f : G → G') (v : k[G]) : k[G'] := - Finsupp.mapDomain f v - -theorem mapDomain_sum {k' G' : Type*} [Semiring k'] {f : G → G'} {s : AddMonoidAlgebra k' G} - {v : G → k' → k[G]} : - mapDomain f (s.sum v) = s.sum fun a b => mapDomain f (v a b) := - Finsupp.mapDomain_sum - -theorem mapDomain_single {G' : Type*} {f : G → G'} {a : G} {b : k} : - mapDomain f (single a b) = single (f a) b := - Finsupp.mapDomain_single - /-- A non-commutative version of `AddMonoidAlgebra.lift`: given an additive homomorphism `f : k →+ R` and a map `g : Multiplicative G → R`, returns the additive homomorphism from `k[G]` such that `liftNC f g (single a b) = f b * g a`. If `f` @@ -1266,28 +1203,6 @@ theorem single_pow [AddMonoid G] {a : G} {b : k} : ∀ n : ℕ, single a b ^ n = | n + 1 => by rw [pow_succ, pow_succ, single_pow n, single_mul_single, add_nsmul, one_nsmul] -/-- Like `Finsupp.mapDomain_zero`, but for the `1` we define in this file -/ -@[simp] -theorem mapDomain_one {α : Type*} {β : Type*} {α₂ : Type*} [Semiring β] [Zero α] [Zero α₂] - {F : Type*} [FunLike F α α₂] [ZeroHomClass F α α₂] (f : F) : - (mapDomain f (1 : AddMonoidAlgebra β α) : AddMonoidAlgebra β α₂) = - (1 : AddMonoidAlgebra β α₂) := by - simp_rw [one_def, mapDomain_single, map_zero] - -/-- Like `Finsupp.mapDomain_add`, but for the convolutive multiplication we define in this file -/ -theorem mapDomain_mul {α : Type*} {β : Type*} {α₂ : Type*} [Semiring β] [Add α] [Add α₂] - {F : Type*} [FunLike F α α₂] [AddHomClass F α α₂] (f : F) (x y : AddMonoidAlgebra β α) : - mapDomain f (x * y) = mapDomain f x * mapDomain f y := by - simp_rw [mul_def, mapDomain_sum, mapDomain_single, map_add] - rw [Finsupp.sum_mapDomain_index] - · congr - ext a b - rw [Finsupp.sum_mapDomain_index] - · simp - · simp [mul_add] - · simp - · simp [add_mul] - section variable (k G) @@ -1389,56 +1304,10 @@ theorem induction_on [AddMonoid G] {p : k[G] → Prop} (f : k[G]) · convert hsmul r (of k G (Multiplicative.ofAdd g)) (hM g) simp -/-- If `f : G → H` is an additive homomorphism between two additive monoids, then -`Finsupp.mapDomain f` is a ring homomorphism between their add monoid algebras. -/ -@[simps] -def mapDomainRingHom (k : Type*) [Semiring k] {H F : Type*} [AddMonoid G] [AddMonoid H] - [FunLike F G H] [AddMonoidHomClass F G H] (f : F) : k[G] →+* k[H] := - { (Finsupp.mapDomain.addMonoidHom f : MonoidAlgebra k G →+ MonoidAlgebra k H) with - map_one' := mapDomain_one f - map_mul' := fun x y => mapDomain_mul f x y } - end MiscTheorems end AddMonoidAlgebra -/-! -#### Conversions between `AddMonoidAlgebra` and `MonoidAlgebra` - -We have not defined `k[G] = MonoidAlgebra k (Multiplicative G)` -because historically this caused problems; -since the changes that have made `nsmul` definitional, this would be possible, -but for now we just construct the ring isomorphisms using `RingEquiv.refl _`. --/ - - -/-- The equivalence between `AddMonoidAlgebra` and `MonoidAlgebra` in terms of -`Multiplicative` -/ -protected def AddMonoidAlgebra.toMultiplicative [Semiring k] [Add G] : - AddMonoidAlgebra k G ≃+* MonoidAlgebra k (Multiplicative G) := - { Finsupp.domCongr - Multiplicative.ofAdd with - toFun := equivMapDomain Multiplicative.ofAdd - map_mul' := fun x y => by - -- Porting note: added `dsimp only`; `beta_reduce` alone is not sufficient - dsimp only - repeat' rw [equivMapDomain_eq_mapDomain (M := k)] - dsimp [Multiplicative.ofAdd] - exact MonoidAlgebra.mapDomain_mul (α := Multiplicative G) (β := k) - (MulHom.id (Multiplicative G)) x y } - -/-- The equivalence between `MonoidAlgebra` and `AddMonoidAlgebra` in terms of `Additive` -/ -protected def MonoidAlgebra.toAdditive [Semiring k] [Mul G] : - MonoidAlgebra k G ≃+* AddMonoidAlgebra k (Additive G) := - { Finsupp.domCongr Additive.ofMul with - toFun := equivMapDomain Additive.ofMul - map_mul' := fun x y => by - -- Porting note: added `dsimp only`; `beta_reduce` alone is not sufficient - dsimp only - repeat' rw [equivMapDomain_eq_mapDomain (M := k)] - dsimp [Additive.ofMul] - convert MonoidAlgebra.mapDomain_mul (β := k) (MulHom.id G) x y } - namespace AddMonoidAlgebra variable {k G H} @@ -1469,11 +1338,8 @@ end NonUnitalNonAssocAlgebra /-! #### Algebra structure -/ - section Algebra --- attribute [local reducible] MonoidAlgebra -- Porting note: `reducible` cannot be `local`. - /-- `Finsupp.single 0` as a `RingHom` -/ @[simps] def singleZeroRingHom [Semiring k] [AddMonoid G] : k →+* k[G] := @@ -1545,12 +1411,11 @@ end Algebra section --- attribute [local reducible] MonoidAlgebra -- Porting note: `reducible` cannot be `local`. - universe ui variable {ι : Type ui} +open Finset in theorem prod_single [CommSemiring k] [AddCommMonoid G] {s : Finset ι} {a : ι → G} {b : ι → k} : (∏ i ∈ s, single (a i) (b i)) = single (∑ i ∈ s, a i) (∏ i ∈ s, b i) := Finset.cons_induction_on s rfl fun a s has ih => by @@ -1563,5 +1428,3 @@ instance isLocalHom_singleZeroRingHom [Semiring k] [AddMonoid G] : MonoidAlgebra.isLocalHom_singleOneRingHom (G := Multiplicative G) end AddMonoidAlgebra - -set_option linter.style.longFile 1700 diff --git a/Mathlib/Algebra/MonoidAlgebra/Ideal.lean b/Mathlib/Algebra/MonoidAlgebra/Ideal.lean index 26a39f72d9030..7e56b5d744657 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Ideal.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Ideal.lean @@ -3,9 +3,9 @@ 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.Algebra.MonoidAlgebra.Defs import Mathlib.RingTheory.Ideal.BigOperators import Mathlib.RingTheory.Ideal.Span +import Mathlib.Algebra.MonoidAlgebra.Defs /-! # Lemmas about ideals of `MonoidAlgebra` and `AddMonoidAlgebra` diff --git a/Mathlib/Algebra/MonoidAlgebra/MapDomain.lean b/Mathlib/Algebra/MonoidAlgebra/MapDomain.lean new file mode 100644 index 0000000000000..44e2a523eaf9a --- /dev/null +++ b/Mathlib/Algebra/MonoidAlgebra/MapDomain.lean @@ -0,0 +1,189 @@ +/- +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, Yury Kudryashov, Kim Morrison +-/ +import Mathlib.Algebra.BigOperators.Finsupp +import Mathlib.Algebra.Module.BigOperators +import Mathlib.Data.Finsupp.SMul +import Mathlib.LinearAlgebra.Finsupp.LSum +import Mathlib.Algebra.Module.Submodule.Basic +import Mathlib.Algebra.MonoidAlgebra.Defs + +/-! +# MonoidAlgebra.mapDomain + +-/ + +assert_not_exists NonUnitalAlgHom AlgEquiv + +noncomputable section + +open Finsupp hiding single mapDomain + +universe u₁ u₂ u₃ u₄ + +variable (k : Type u₁) (G : Type u₂) (H : Type*) {R : Type*} + +/-! ### Multiplicative monoids -/ + +namespace MonoidAlgebra + +variable {k G} + +section + +variable [Semiring k] [NonUnitalNonAssocSemiring R] + +abbrev mapDomain {G' : Type*} (f : G → G') (v : MonoidAlgebra k G) : MonoidAlgebra k G' := + Finsupp.mapDomain f v + +theorem mapDomain_sum {k' G' : Type*} [Semiring k'] {f : G → G'} {s : MonoidAlgebra k' G} + {v : G → k' → MonoidAlgebra k G} : + mapDomain f (s.sum v) = s.sum fun a b => mapDomain f (v a b) := + Finsupp.mapDomain_sum + +end + + +section MiscTheorems + +variable [Semiring k] + +section + +/-- Like `Finsupp.mapDomain_zero`, but for the `1` we define in this file -/ +@[simp] +theorem mapDomain_one {α : Type*} {β : Type*} {α₂ : Type*} [Semiring β] [One α] [One α₂] + {F : Type*} [FunLike F α α₂] [OneHomClass F α α₂] (f : F) : + (mapDomain f (1 : MonoidAlgebra β α) : MonoidAlgebra β α₂) = (1 : MonoidAlgebra β α₂) := by + simp_rw [one_def, mapDomain_single, map_one] + +/-- Like `Finsupp.mapDomain_add`, but for the convolutive multiplication we define in this file -/ +theorem mapDomain_mul {α : Type*} {β : Type*} {α₂ : Type*} [Semiring β] [Mul α] [Mul α₂] + {F : Type*} [FunLike F α α₂] [MulHomClass F α α₂] (f : F) (x y : MonoidAlgebra β α) : + mapDomain f (x * y) = mapDomain f x * mapDomain f y := by + simp_rw [mul_def, mapDomain_sum, mapDomain_single, map_mul] + rw [Finsupp.sum_mapDomain_index] + · congr + ext a b + rw [Finsupp.sum_mapDomain_index] + · simp + · simp [mul_add] + · simp + · simp [add_mul] + +end + +end MiscTheorems + +/-- If `f : G → H` is a multiplicative homomorphism between two monoids, then +`Finsupp.mapDomain f` is a ring homomorphism between their monoid algebras. -/ +@[simps] +def mapDomainRingHom (k : Type*) {H F : Type*} [Semiring k] [Monoid G] [Monoid H] + [FunLike F G H] [MonoidHomClass F G H] (f : F) : MonoidAlgebra k G →+* MonoidAlgebra k H := + { (Finsupp.mapDomain.addMonoidHom f : MonoidAlgebra k G →+ MonoidAlgebra k H) with + map_one' := mapDomain_one f + map_mul' := fun x y => mapDomain_mul f x y } + +end MonoidAlgebra + +/-! ### Additive monoids -/ + +namespace AddMonoidAlgebra + +variable {k G} + +section + +variable [Semiring k] [NonUnitalNonAssocSemiring R] + +abbrev mapDomain {G' : Type*} (f : G → G') (v : k[G]) : k[G'] := + Finsupp.mapDomain f v + +theorem mapDomain_sum {k' G' : Type*} [Semiring k'] {f : G → G'} {s : AddMonoidAlgebra k' G} + {v : G → k' → k[G]} : + mapDomain f (s.sum v) = s.sum fun a b => mapDomain f (v a b) := + Finsupp.mapDomain_sum + +theorem mapDomain_single {G' : Type*} {f : G → G'} {a : G} {b : k} : + mapDomain f (single a b) = single (f a) b := + Finsupp.mapDomain_single + +end + +section MiscTheorems + +variable [Semiring k] + +/-- Like `Finsupp.mapDomain_zero`, but for the `1` we define in this file -/ +@[simp] +theorem mapDomain_one {α : Type*} {β : Type*} {α₂ : Type*} [Semiring β] [Zero α] [Zero α₂] + {F : Type*} [FunLike F α α₂] [ZeroHomClass F α α₂] (f : F) : + (mapDomain f (1 : AddMonoidAlgebra β α) : AddMonoidAlgebra β α₂) = + (1 : AddMonoidAlgebra β α₂) := by + simp_rw [one_def, mapDomain_single, map_zero] + +/-- Like `Finsupp.mapDomain_add`, but for the convolutive multiplication we define in this file -/ +theorem mapDomain_mul {α : Type*} {β : Type*} {α₂ : Type*} [Semiring β] [Add α] [Add α₂] + {F : Type*} [FunLike F α α₂] [AddHomClass F α α₂] (f : F) (x y : AddMonoidAlgebra β α) : + mapDomain f (x * y) = mapDomain f x * mapDomain f y := by + simp_rw [mul_def, mapDomain_sum, mapDomain_single, map_add] + rw [Finsupp.sum_mapDomain_index] + · congr + ext a b + rw [Finsupp.sum_mapDomain_index] + · simp + · simp [mul_add] + · simp + · simp [add_mul] + +/-- If `f : G → H` is an additive homomorphism between two additive monoids, then +`Finsupp.mapDomain f` is a ring homomorphism between their add monoid algebras. -/ +@[simps] +def mapDomainRingHom (k : Type*) [Semiring k] {H F : Type*} [AddMonoid G] [AddMonoid H] + [FunLike F G H] [AddMonoidHomClass F G H] (f : F) : k[G] →+* k[H] := + { (Finsupp.mapDomain.addMonoidHom f : MonoidAlgebra k G →+ MonoidAlgebra k H) with + map_one' := mapDomain_one f + map_mul' := fun x y => mapDomain_mul f x y } + +end MiscTheorems + +end AddMonoidAlgebra + +/-! +#### Conversions between `AddMonoidAlgebra` and `MonoidAlgebra` + +We have not defined `k[G] = MonoidAlgebra k (Multiplicative G)` +because historically this caused problems; +since the changes that have made `nsmul` definitional, this would be possible, +but for now we just construct the ring isomorphisms using `RingEquiv.refl _`. +-/ + + +/-- The equivalence between `AddMonoidAlgebra` and `MonoidAlgebra` in terms of +`Multiplicative` -/ +protected def AddMonoidAlgebra.toMultiplicative [Semiring k] [Add G] : + AddMonoidAlgebra k G ≃+* MonoidAlgebra k (Multiplicative G) := + { Finsupp.domCongr + Multiplicative.ofAdd with + toFun := equivMapDomain Multiplicative.ofAdd + map_mul' := fun x y => by + -- Porting note: added `dsimp only`; `beta_reduce` alone is not sufficient + dsimp only + repeat' rw [equivMapDomain_eq_mapDomain (M := k)] + dsimp [Multiplicative.ofAdd] + exact MonoidAlgebra.mapDomain_mul (α := Multiplicative G) (β := k) + (MulHom.id (Multiplicative G)) x y } + +/-- The equivalence between `MonoidAlgebra` and `AddMonoidAlgebra` in terms of `Additive` -/ +protected def MonoidAlgebra.toAdditive [Semiring k] [Mul G] : + MonoidAlgebra k G ≃+* AddMonoidAlgebra k (Additive G) := + { Finsupp.domCongr Additive.ofMul with + toFun := equivMapDomain Additive.ofMul + map_mul' := fun x y => by + -- Porting note: added `dsimp only`; `beta_reduce` alone is not sufficient + dsimp only + repeat' rw [equivMapDomain_eq_mapDomain (M := k)] + dsimp [Additive.ofMul] + convert MonoidAlgebra.mapDomain_mul (β := k) (MulHom.id G) x y } diff --git a/Mathlib/Algebra/MonoidAlgebra/Support.lean b/Mathlib/Algebra/MonoidAlgebra/Support.lean index d57cfcbdc5733..28eae4038cb45 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Support.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Support.lean @@ -3,9 +3,9 @@ Copyright (c) 2022 Damiano Testa. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa -/ -import Mathlib.Algebra.MonoidAlgebra.Defs import Mathlib.Algebra.Group.Pointwise.Finset.Basic import Mathlib.LinearAlgebra.Finsupp.Supported +import Mathlib.Algebra.MonoidAlgebra.Defs /-! # Lemmas about the support of a finitely supported function diff --git a/Mathlib/Algebra/Polynomial/Basic.lean b/Mathlib/Algebra/Polynomial/Basic.lean index 6ed5fbfe49788..ccb37ec72957d 100644 --- a/Mathlib/Algebra/Polynomial/Basic.lean +++ b/Mathlib/Algebra/Polynomial/Basic.lean @@ -4,11 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker -/ import Mathlib.Algebra.GroupWithZero.Divisibility -import Mathlib.Algebra.MonoidAlgebra.Defs import Mathlib.Algebra.Order.Monoid.Unbundled.WithTop import Mathlib.Data.Finset.Sort import Mathlib.Tactic.FastInstance import Mathlib.Algebra.Group.Submonoid.Operations +import Mathlib.Algebra.MonoidAlgebra.Defs /-! # Theory of univariate polynomials From bb2bafa04a5599c65eb50c53e99ca49a84629372 Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Tue, 4 Feb 2025 15:53:31 +0000 Subject: [PATCH 076/103] chore: rename isUnit_ofPowEqOne (#21407) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Units.ofPowEqOne is not present in the signature. Co-authored-by: Yaël Dillies --- Mathlib/Algebra/Group/Commute/Units.lean | 5 ++++- Mathlib/Algebra/Polynomial/UnitTrinomial.lean | 2 +- Mathlib/Data/Int/GCD.lean | 2 +- Mathlib/RingTheory/RootsOfUnity/PrimitiveRoots.lean | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Mathlib/Algebra/Group/Commute/Units.lean b/Mathlib/Algebra/Group/Commute/Units.lean index b137a7af7c509..79f9b5b4a8605 100644 --- a/Mathlib/Algebra/Group/Commute/Units.lean +++ b/Mathlib/Algebra/Group/Commute/Units.lean @@ -106,9 +106,12 @@ lemma Units.pow_ofPowEqOne (ha : a ^ n = 1) (hn : n ≠ 0) : Units.ofPowEqOne _ n ha hn ^ n = 1 := Units.ext <| by simp [ha] @[to_additive] -lemma isUnit_ofPowEqOne (ha : a ^ n = 1) (hn : n ≠ 0) : IsUnit a := +lemma IsUnit.of_pow_eq_one (ha : a ^ n = 1) (hn : n ≠ 0) : IsUnit a := (Units.ofPowEqOne _ n ha hn).isUnit +@[deprecated (since := "2025-02-03")] alias isUnit_ofPowEqOne := IsUnit.of_pow_eq_one +@[deprecated (since := "2025-02-03")] alias isAddUnit_ofNSMulEqZero := IsAddUnit.of_nsmul_eq_zero + end Monoid section DivisionMonoid diff --git a/Mathlib/Algebra/Polynomial/UnitTrinomial.lean b/Mathlib/Algebra/Polynomial/UnitTrinomial.lean index 2e735b5d986a1..d691cb2e8bde3 100644 --- a/Mathlib/Algebra/Polynomial/UnitTrinomial.lean +++ b/Mathlib/Algebra/Polynomial/UnitTrinomial.lean @@ -188,7 +188,7 @@ theorem isUnitTrinomial_iff' : · have key : ∀ k ∈ p.support, p.coeff k ^ 2 = 1 := fun k hk => Int.sq_eq_one_of_sq_le_three ((single_le_sum (fun k _ => sq_nonneg (p.coeff k)) hk).trans hp.le) (mem_support_iff.mp hk) - refine isUnitTrinomial_iff.mpr ⟨?_, fun k hk => isUnit_ofPowEqOne (key k hk) two_ne_zero⟩ + refine isUnitTrinomial_iff.mpr ⟨?_, fun k hk => .of_pow_eq_one (key k hk) two_ne_zero⟩ rw [sum_def, sum_congr rfl key, sum_const, Nat.smul_one_eq_cast] at hp exact Nat.cast_injective hp diff --git a/Mathlib/Data/Int/GCD.lean b/Mathlib/Data/Int/GCD.lean index 22963db04965e..344859d47e1f3 100644 --- a/Mathlib/Data/Int/GCD.lean +++ b/Mathlib/Data/Int/GCD.lean @@ -374,7 +374,7 @@ end Int theorem pow_gcd_eq_one {M : Type*} [Monoid M] (x : M) {m n : ℕ} (hm : x ^ m = 1) (hn : x ^ n = 1) : x ^ m.gcd n = 1 := by rcases m with (rfl | m); · simp [hn] - obtain ⟨y, rfl⟩ := isUnit_ofPowEqOne hm m.succ_ne_zero + obtain ⟨y, rfl⟩ := IsUnit.of_pow_eq_one hm m.succ_ne_zero rw [← Units.val_pow_eq_pow_val, ← Units.val_one (α := M), ← zpow_natCast, ← Units.ext_iff] at * rw [Nat.gcd_eq_gcd_ab, zpow_add, zpow_mul, zpow_mul, hn, hm, one_zpow, one_zpow, one_mul] diff --git a/Mathlib/RingTheory/RootsOfUnity/PrimitiveRoots.lean b/Mathlib/RingTheory/RootsOfUnity/PrimitiveRoots.lean index 731cc72273b2b..1c7bfbb6cfaac 100644 --- a/Mathlib/RingTheory/RootsOfUnity/PrimitiveRoots.lean +++ b/Mathlib/RingTheory/RootsOfUnity/PrimitiveRoots.lean @@ -525,7 +525,7 @@ theorem eq_pow_of_pow_eq_one {k : ℕ} [NeZero k] {ζ ξ : R} (h : IsPrimitiveRo (hξ : ξ ^ k = 1) : ∃ i < k, ζ ^ i = ξ := by lift ζ to Rˣ using h.isUnit <| NeZero.pos k - lift ξ to Rˣ using isUnit_ofPowEqOne hξ <| NeZero.ne k + lift ξ to Rˣ using .of_pow_eq_one hξ <| NeZero.ne k simp only [← Units.val_pow_eq_pow_val, ← Units.ext_iff] rw [coe_units_iff] at h exact h.eq_pow_of_mem_rootsOfUnity <| (mem_rootsOfUnity' k ξ).mpr hξ From f6c7ab8ce8a86ca1015ed8f485a559bd538f396b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Tue, 4 Feb 2025 16:47:21 +0000 Subject: [PATCH 077/103] feat(CategoryTheory): (co)limits of constant functors (#21412) Constant functors from connected categories have a limit and a colimit. --- Mathlib/CategoryTheory/Limits/Connected.lean | 56 ++++++++++++++++++-- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/Mathlib/CategoryTheory/Limits/Connected.lean b/Mathlib/CategoryTheory/Limits/Connected.lean index 0d9777ebc99b8..1664e1c9ef4d7 100644 --- a/Mathlib/CategoryTheory/Limits/Connected.lean +++ b/Mathlib/CategoryTheory/Limits/Connected.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2020 Bhavik Mehta. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Bhavik Mehta +Authors: Bhavik Mehta, Joël Riou -/ import Mathlib.CategoryTheory.Limits.Shapes.BinaryProducts import Mathlib.CategoryTheory.Limits.Shapes.Equalizers @@ -14,9 +14,11 @@ import Mathlib.CategoryTheory.Limits.Preserves.Basic A connected limit is a limit whose shape is a connected category. -We give examples of connected categories, and prove that the functor given -by `(X × -)` preserves any connected limit. That is, any limit of shape `J` -where `J` is a connected category is preserved by the functor `(X × -)`. +We show that constant functors from a connected category have a limit +and a colimit, give examples of connected categories, and prove +that the functor given by `(X × -)` preserves any connected limit. +That is, any limit of shape `J` where `J` is a connected category is +preserved by the functor `(X × -)`. -/ @@ -28,6 +30,52 @@ open CategoryTheory CategoryTheory.Category CategoryTheory.Limits namespace CategoryTheory +section Const + +namespace Limits + +variable (J : Type u₁) [Category.{v₁} J] {C : Type u₂} [Category.{v₂} C] (X : C) + +/-- The obvious cone of a constant functor. -/ +@[simps] +def constCone : Cone ((Functor.const J).obj X) where + pt := X + π := 𝟙 _ + +/-- The obvious cocone of a constant functor. -/ +@[simps] +def constCocone : Cocone ((Functor.const J).obj X) where + pt := X + ι := 𝟙 _ + +variable [IsConnected J] + +/-- When `J` is a connected category, the limit of a +constant functor `J ⥤ C` with value `X : C` identifies to `X`. -/ +def isLimitConstCone : IsLimit (constCone J X) where + lift s := s.π.app (Classical.arbitrary _) + fac s j := by + dsimp + rw [comp_id] + exact constant_of_preserves_morphisms _ + (fun _ _ f ↦ by simpa using s.w f) _ _ + uniq s m hm := by simpa using hm (Classical.arbitrary _) + +/-- When `J` is a connected category, the colimit of a +constant functor `J ⥤ C` with value `X : C` identifies to `X`. -/ +def isColimitConstCocone : IsColimit (constCocone J X) where + desc s := s.ι.app (Classical.arbitrary _) + fac s j := by + dsimp + rw [id_comp] + exact constant_of_preserves_morphisms _ + (fun _ _ f ↦ by simpa using (s.w f).symm) _ _ + uniq s m hm := by simpa using hm (Classical.arbitrary _) + +end Limits + +end Const + section Examples instance widePullbackShape_connected (J : Type v₁) : IsConnected (WidePullbackShape J) := by From ee457abc32933cb3e887e54b00f46574563f1ffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Tue, 4 Feb 2025 17:11:26 +0000 Subject: [PATCH 078/103] feat(CategoryTheory): small classes of morphisms (#21411) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR introduces a typeclass `IsSmall.{w} W` for `W : MorphismProperty C`. It means that the morphisms in `C` can be parametrized by a `w`-small type. Co-authored-by: Joël Riou <37772949+joelriou@users.noreply.github.com> --- Mathlib.lean | 1 + .../MorphismProperty/IsSmall.lean | 61 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 Mathlib/CategoryTheory/MorphismProperty/IsSmall.lean diff --git a/Mathlib.lean b/Mathlib.lean index dcc248dd73a0c..287698b41b2b4 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2131,6 +2131,7 @@ import Mathlib.CategoryTheory.MorphismProperty.Composition import Mathlib.CategoryTheory.MorphismProperty.Concrete import Mathlib.CategoryTheory.MorphismProperty.Factorization import Mathlib.CategoryTheory.MorphismProperty.IsInvertedBy +import Mathlib.CategoryTheory.MorphismProperty.IsSmall import Mathlib.CategoryTheory.MorphismProperty.LiftingProperty import Mathlib.CategoryTheory.MorphismProperty.Limits import Mathlib.CategoryTheory.MorphismProperty.OverAdjunction diff --git a/Mathlib/CategoryTheory/MorphismProperty/IsSmall.lean b/Mathlib/CategoryTheory/MorphismProperty/IsSmall.lean new file mode 100644 index 0000000000000..0b361867a8f94 --- /dev/null +++ b/Mathlib/CategoryTheory/MorphismProperty/IsSmall.lean @@ -0,0 +1,61 @@ +/- +Copyright (c) 2025 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ +import Mathlib.CategoryTheory.MorphismProperty.Basic +import Mathlib.Logic.Small.Basic + +/-! +# Small classes of morphisms + +A class of morphisms `W : MorphismProperty C` is `w`-small +if the corresponding set in `Set (Arrow C)` is. + +-/ + +universe w t v u + +namespace CategoryTheory + +variable {C : Type u} [Category.{v} C] + +namespace MorphismProperty + +variable (W : MorphismProperty C) + +/-- A class of morphisms `W : MorphismProperty C` is `w`-small +if the corresponding set in `Set (Arrow C)` is. -/ +@[pp_with_univ] +class IsSmall : Prop where + small_toSet : Small.{w} W.toSet + +attribute [instance] IsSmall.small_toSet + +instance isSmall_ofHoms {ι : Type t} [Small.{w} ι] {A B : ι → C} (f : ∀ i, A i ⟶ B i) : + IsSmall.{w} (ofHoms f) := by + let φ (i : ι) : (ofHoms f).toSet := ⟨Arrow.mk (f i), ⟨i⟩⟩ + have hφ : Function.Surjective φ := by + rintro ⟨⟨_, _, f⟩, ⟨i⟩⟩ + exact ⟨i, rfl⟩ + exact ⟨small_of_surjective hφ⟩ + +lemma isSmall_iff_eq_ofHoms : + IsSmall.{w} W ↔ ∃ (ι : Type w) (A B : ι → C) (f : ∀ i, A i ⟶ B i), + W = ofHoms f := by + constructor + · intro + refine ⟨Shrink.{w} W.toSet, _, _, fun i ↦ ((equivShrink _).symm i).1.hom, ?_⟩ + ext A B f + rw [ofHoms_iff] + constructor + · intro hf + exact ⟨equivShrink _ ⟨f, hf⟩, by simp⟩ + · rintro ⟨i, hi⟩ + simp only [← W.arrow_mk_mem_toSet_iff, hi, Arrow.mk_eq, Subtype.coe_prop] + · rintro ⟨_, _, _, _, rfl⟩ + infer_instance + +end MorphismProperty + +end CategoryTheory From f70851e492cb131329c023e6738ad74bf5d99180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20In=C3=A9s=20de=20Frutos-Fern=C3=A1ndez?= Date: Tue, 4 Feb 2025 18:27:56 +0000 Subject: [PATCH 079/103] feat(Algebra/GroupWithZero/Int): add lemmas about Zm0 (#21370) Co-authored-by: Filippo A. E. Nuccio --- Mathlib.lean | 1 + Mathlib/Algebra/Group/Basic.lean | 3 +++ Mathlib/Algebra/GroupWithZero/Int.lean | 28 ++++++++++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 Mathlib/Algebra/GroupWithZero/Int.lean diff --git a/Mathlib.lean b/Mathlib.lean index 287698b41b2b4..e282d000ab5ab 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -403,6 +403,7 @@ import Mathlib.Algebra.GroupWithZero.Hom import Mathlib.Algebra.GroupWithZero.Idempotent import Mathlib.Algebra.GroupWithZero.Indicator import Mathlib.Algebra.GroupWithZero.InjSurj +import Mathlib.Algebra.GroupWithZero.Int import Mathlib.Algebra.GroupWithZero.Invertible import Mathlib.Algebra.GroupWithZero.Nat import Mathlib.Algebra.GroupWithZero.NeZero diff --git a/Mathlib/Algebra/Group/Basic.lean b/Mathlib/Algebra/Group/Basic.lean index f95267bddc8a0..66e2a34c78b26 100644 --- a/Mathlib/Algebra/Group/Basic.lean +++ b/Mathlib/Algebra/Group/Basic.lean @@ -491,6 +491,9 @@ theorem eq_of_one_div_eq_one_div (h : 1 / a = 1 / b) : a = b := by @[to_additive mul_zsmul] lemma zpow_mul' (a : α) (m n : ℤ) : a ^ (m * n) = (a ^ n) ^ m := by rw [Int.mul_comm, zpow_mul] +@[to_additive] +theorem zpow_comm (a : α) (m n : ℤ) : (a ^ m) ^ n = (a ^ n) ^ m := by rw [← zpow_mul, zpow_mul'] + variable (a b c) @[to_additive, field_simps] -- The attributes are out of order on purpose diff --git a/Mathlib/Algebra/GroupWithZero/Int.lean b/Mathlib/Algebra/GroupWithZero/Int.lean new file mode 100644 index 0000000000000..c1bb6553c1fe9 --- /dev/null +++ b/Mathlib/Algebra/GroupWithZero/Int.lean @@ -0,0 +1,28 @@ +/- +Copyright (c) 2025 María Inés de Frutos-Fernández, Filippo A. E. Nuccio. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: María Inés de Frutos-Fernández, Filippo A. E. Nuccio +-/ +import Mathlib.Algebra.Group.Int.TypeTags +import Mathlib.Algebra.GroupWithZero.WithZero + +/-! +# Lemmas about `ℤₘ₀`. +-/ + +local notation "ℤₘ₀" => WithZero (Multiplicative ℤ) + +namespace WithZero + +open Multiplicative + +theorem ofAdd_zpow (a : ℤ) : (↑(ofAdd a) : ℤₘ₀) = ofAdd (1 : ℤ) ^ a := by + rw [← WithZero.coe_zpow, WithZero.coe_inj, ← Int.ofAdd_mul, one_mul] + +theorem ofAdd_neg_one_pow_comm (a : ℤ) (n : ℕ) : + ((↑(ofAdd (-1 : ℤ)) : ℤₘ₀) ^ (-a)) ^ n = ofAdd (n : ℤ) ^ a := by + rw [ofAdd_zpow (-1)] + simp only [zpow_neg, zpow_one, inv_zpow', inv_inv, coe_zpow] + rw [← zpow_natCast, zpow_comm, ← ofAdd_zpow] + +end WithZero From 3f98c55d948037224768fbdb5aaceaffe0b6c86a Mon Sep 17 00:00:00 2001 From: Antoine Chambert-Loir Date: Tue, 4 Feb 2025 20:48:46 +0000 Subject: [PATCH 080/103] feat: primitive group actions (#12052) This PR defines the notion of a primitive action. This concept is used to state the Iwasawa criterion for simplicity of #12048 --- Mathlib.lean | 1 + Mathlib/GroupTheory/GroupAction/Basic.lean | 33 ++- Mathlib/GroupTheory/GroupAction/Blocks.lean | 4 +- .../GroupTheory/GroupAction/Primitive.lean | 279 ++++++++++++++++++ .../GroupTheory/GroupAction/Transitive.lean | 7 +- 5 files changed, 310 insertions(+), 14 deletions(-) create mode 100644 Mathlib/GroupTheory/GroupAction/Primitive.lean diff --git a/Mathlib.lean b/Mathlib.lean index e282d000ab5ab..bc5021e153012 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -3343,6 +3343,7 @@ import Mathlib.GroupTheory.GroupAction.Hom import Mathlib.GroupTheory.GroupAction.IterateAct import Mathlib.GroupTheory.GroupAction.Period import Mathlib.GroupTheory.GroupAction.Pointwise +import Mathlib.GroupTheory.GroupAction.Primitive import Mathlib.GroupTheory.GroupAction.Quotient import Mathlib.GroupTheory.GroupAction.Ring import Mathlib.GroupTheory.GroupAction.SubMulAction diff --git a/Mathlib/GroupTheory/GroupAction/Basic.lean b/Mathlib/GroupTheory/GroupAction/Basic.lean index 520ead2860814..9d00eff182f9d 100644 --- a/Mathlib/GroupTheory/GroupAction/Basic.lean +++ b/Mathlib/GroupTheory/GroupAction/Basic.lean @@ -69,17 +69,21 @@ section FixedPoints variable {M α} +@[to_additive (attr := simp)] +theorem subsingleton_orbit_iff_mem_fixedPoints {a : α} : + (orbit M a).Subsingleton ↔ a ∈ fixedPoints M α := by + rw [mem_fixedPoints] + constructor + · exact fun h m ↦ h (mem_orbit a m) (mem_orbit_self a) + · rintro h _ ⟨m, rfl⟩ y ⟨p, rfl⟩ + simp only [h] + @[to_additive mem_fixedPoints_iff_card_orbit_eq_one] theorem mem_fixedPoints_iff_card_orbit_eq_one {a : α} [Fintype (orbit M a)] : a ∈ fixedPoints M α ↔ Fintype.card (orbit M a) = 1 := by - rw [Fintype.card_eq_one_iff, mem_fixedPoints] - constructor - · exact fun h => ⟨⟨a, mem_orbit_self _⟩, fun ⟨a, ⟨x, hx⟩⟩ => Subtype.eq <| by simp [h x, hx.symm]⟩ - · intro h x - rcases h with ⟨⟨z, hz⟩, hz₁⟩ - calc - x • a = z := Subtype.mk.inj (hz₁ ⟨x • a, mem_orbit _ _⟩) - _ = a := (Subtype.mk.inj (hz₁ ⟨a, mem_orbit_self _⟩)).symm + simp only [← subsingleton_orbit_iff_mem_fixedPoints, le_antisymm_iff, + Fintype.card_le_one_iff_subsingleton, Nat.add_one_le_iff, Fintype.card_pos_iff, + Set.subsingleton_coe, iff_self_and, Set.nonempty_coe_sort, orbit_nonempty, implies_true] @[to_additive instDecidablePredMemSetFixedByAddOfDecidableEq] instance (m : M) [DecidableEq β] : @@ -104,6 +108,19 @@ theorem smul_cancel_of_non_zero_divisor {M R : Type*} [Monoid M] [NonUnitalNonAs namespace MulAction variable {G α β : Type*} [Group G] [MulAction G α] [MulAction G β] +@[to_additive] theorem fixedPoints_of_subsingleton [Subsingleton α] : + fixedPoints G α = .univ := by + apply Set.eq_univ_of_forall + simp only [mem_fixedPoints] + intro x hx + apply Subsingleton.elim .. + +/-- If a group acts nontrivially, then the type is nontrivial -/ +@[to_additive "If a subgroup acts nontrivially, then the type is nontrivial."] +theorem nontrivial_of_fixedPoints_ne_univ (h : fixedPoints G α ≠ .univ) : + Nontrivial α := + (subsingleton_or_nontrivial α).resolve_left fun _ ↦ h fixedPoints_of_subsingleton + section Orbit -- TODO: This proof is redoing a special case of `MulAction.IsInvariantBlock.isBlock`. Can we move diff --git a/Mathlib/GroupTheory/GroupAction/Blocks.lean b/Mathlib/GroupTheory/GroupAction/Blocks.lean index 3e5d7dc084e08..d01368d312f96 100644 --- a/Mathlib/GroupTheory/GroupAction/Blocks.lean +++ b/Mathlib/GroupTheory/GroupAction/Blocks.lean @@ -38,8 +38,8 @@ The non-existence of nontrivial blocks is the definition of primitive actions. - `MulAction.BlockMem` : the type of blocks containing a given element -- `MulAction.BlockMem.boundedOrder` : - the type of blocks containing a given element is a bounded order. +- `MulAction.BlockMem.instBoundedOrder` : + The type of blocks containing a given element is a bounded order. ## References diff --git a/Mathlib/GroupTheory/GroupAction/Primitive.lean b/Mathlib/GroupTheory/GroupAction/Primitive.lean new file mode 100644 index 0000000000000..a05c637db665b --- /dev/null +++ b/Mathlib/GroupTheory/GroupAction/Primitive.lean @@ -0,0 +1,279 @@ +/- +Copyright (c) 2024 Antoine Chambert-Loir. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Antoine Chambert-Loir +-/ + +import Mathlib.Data.Setoid.Partition +import Mathlib.GroupTheory.GroupAction.Blocks +import Mathlib.GroupTheory.GroupAction.Transitive + +/-! +# Primitive actions + +## Definitions + +- `MulAction.IsPreprimitive G X` + A structure that says that the action of a type `G` on a type `X` + (defined by an instance `SMul G X`) is *preprimitive*, + namely, it is pretransitive and the only blocks are ⊤ and subsingletons. + (The pretransitivity assumption is essentially trivial, + because orbits are blocks, unless the action itself is trivial.) + + The notion which is introduced in classical books on group theory + is restricted to group actions. + In fact, it may be irrelevant if the action is degenerate, + when “trivial blocks” might not be blocks. + Moreover, the classical notion is *primitive*, + which further assumes that `X` is not empty. + +- `MulAction.IsQuasiPreprimitive G X` + A structure that says that the action of the group `G` on the type `X` is *quasipreprimitive*, + namely, normal subgroups of `G` which act nontrivially act pretransitively. + +- We prove some straightforward theorems that relate preprimitivity + under equivariant maps, for images and preimages. + +## Relation with stabilizers + +- `MulAction.isSimpleOrderBlockMem_iff_isPreprimitive` + relates primitivity and the fact that the inclusion order on blocks containing is simple. + +- `MulAction.isCoatom_stabilizer_iff_preprimitive` + An action is preprimitive iff the stabilizers of points are maximal subgroups. + +- `MulAction.IsPreprimitive.isCoatom_stabilizer_of_isPreprimitive` + Stabilizers of points under a preprimitive action are maximal subgroups. + +## Relation with normal subgroups + +- `MulAction.IsPreprimitive.isQuasipreprimitive` + Preprimitive actions are quasipreprimitive. + +-/ + +open Pointwise + +namespace MulAction + +variable (G : Type*) (X : Type*) + +-- Note : if the action is degenerate, singletons may not be blocks. +/-- An additive action is preprimitive if it is pretransitive and +the only blocks are the trivial ones -/ +class _root_.AddAction.IsPreprimitive [VAdd G X] extends AddAction.IsPretransitive G X : Prop where + /-- An action is preprimitive if it is pretransitive and + the only blocks are the trivial ones -/ + isTrivialBlock_of_isBlock : ∀ {B : Set X}, AddAction.IsBlock G B → AddAction.IsTrivialBlock B + +/-- An action is preprimitive if it is pretransitive and +the only blocks are the trivial ones -/ +@[to_additive] +class IsPreprimitive [SMul G X] extends IsPretransitive G X : Prop where +/-- An action is preprimitive if it is pretransitive and +the only blocks are the trivial ones -/ + isTrivialBlock_of_isBlock : ∀ {B : Set X}, IsBlock G B → IsTrivialBlock B + +open IsPreprimitive + +/-- An additive action of an additive group is quasipreprimitive if any normal subgroup +that has no fixed point acts pretransitively -/ +class _root_.AddAction.IsQuasiPreprimitive + [AddGroup G] [AddAction G X] extends AddAction.IsPretransitive G X : Prop where + isPretransitive_of_normal : + ∀ {N : AddSubgroup G} [N.Normal], AddAction.fixedPoints N X ≠ .univ → + AddAction.IsPretransitive N X + +/-- An action of a group is quasipreprimitive if any normal subgroup +that has no fixed point acts pretransitively -/ +@[to_additive] +class IsQuasiPreprimitive [Group G] [MulAction G X] extends IsPretransitive G X : Prop where + isPretransitive_of_normal : + ∀ {N : Subgroup G} [N.Normal], fixedPoints N X ≠ .univ → IsPretransitive N X + +variable {G X} + +@[to_additive] +theorem IsBlock.subsingleton_or_eq_univ + [SMul G X] [IsPreprimitive G X] {B : Set X} (hB : IsBlock G B) : + B.Subsingleton ∨ B = .univ := + isTrivialBlock_of_isBlock hB + +@[to_additive (attr := nontriviality)] +theorem IsPreprimitive.of_subsingleton [SMul G X] [Nonempty G] [Subsingleton X] : + IsPreprimitive G X where + exists_smul_eq (x y) := by + use Classical.arbitrary G + rw [eq_iff_true_of_subsingleton] + trivial + isTrivialBlock_of_isBlock B := by + left + exact Set.subsingleton_of_subsingleton + +variable [Group G] [MulAction G X] + +open scoped BigOperators Pointwise + +/-- If the action is pretransitive, then the trivial blocks condition implies preprimitivity +(based condition) -/ +@[to_additive +"If the action is pretransitive, then the trivial blocks condition implies preprimitivity +(based condition)"] +theorem IsPreprimitive.of_isTrivialBlock_base [IsPretransitive G X] (a : X) + (H : ∀ {B : Set X} (_ : a ∈ B) (_ : IsBlock G B), IsTrivialBlock B) : + IsPreprimitive G X where + isTrivialBlock_of_isBlock {B} hB := by + obtain rfl | ⟨b, hb⟩ := B.eq_empty_or_nonempty + · simp [IsTrivialBlock] + · obtain ⟨g, hg⟩ := exists_smul_eq G b a + rw [← IsTrivialBlock.smul_iff g] + apply H _ (hB.translate g) + rw [← hg] + use b + +/-- If the action is not trivial, then the trivial blocks condition implies preprimitivity +(pretransitivity is automatic) (based condition) -/ +@[to_additive + "If the action is not trivial, then the trivial blocks condition implies preprimitivity + (pretransitivity is automatic) (based condition)"] +theorem IsPreprimitive.of_isTrivialBlock_of_not_mem_fixedPoints {a : X} (ha : a ∉ fixedPoints G X) + (H : ∀ ⦃B : Set X⦄, a ∈ B → IsBlock G B → IsTrivialBlock B) : + IsPreprimitive G X := + have : IsPretransitive G X := by + rw [isPretransitive_iff_base a] + cases' H (mem_orbit_self a) (IsBlock.orbit a) with H H + · exfalso; apply ha + rw [Set.subsingleton_iff_singleton (mem_orbit_self a)] at H + simp only [mem_fixedPoints] + intro g + rw [← Set.mem_singleton_iff]; rw [← H] + exact mem_orbit a g + · intro x; rw [← MulAction.mem_orbit_iff, H]; exact Set.mem_univ x + { isTrivialBlock_of_isBlock {B} hB := by + obtain rfl | ⟨b, hb⟩ := B.eq_empty_or_nonempty + · simp [IsTrivialBlock] + · obtain ⟨g, hg⟩ := exists_smul_eq G b a + rw [← IsTrivialBlock.smul_iff g] + exact H ⟨b, hb, hg⟩ (hB.translate g) } + +/-- If the action is not trivial, then the trivial blocks condition implies preprimitivity +(pretransitivity is automatic) -/ +@[to_additive + "If the action is not trivial, then the trivial blocks condition implies preprimitivity +(pretransitivity is automatic)"] +theorem mk' (Hnt : fixedPoints G X ≠ ⊤) + (H : ∀ {B : Set X} (_ : IsBlock G B), IsTrivialBlock B) : + IsPreprimitive G X := by + simp only [Set.top_eq_univ, Set.ne_univ_iff_exists_not_mem] at Hnt + obtain ⟨_, ha⟩ := Hnt + exact .of_isTrivialBlock_of_not_mem_fixedPoints ha fun {B} _ ↦ H + +section EquivariantMap + +variable {M : Type*} [Group M] {α : Type*} [MulAction M α] +variable {N β : Type*} [Group N] [MulAction N β] +variable {φ : M →* N} {f : α →ₑ[φ] β} + +@[to_additive] +theorem IsPreprimitive.of_surjective [IsPreprimitive M α] (hf : Function.Surjective f) : + IsPreprimitive N β where + toIsPretransitive := toIsPretransitive.of_surjective_map hf + isTrivialBlock_of_isBlock {B} hB := by + rw [← Set.image_preimage_eq B hf] + apply IsTrivialBlock.image hf + exact isTrivialBlock_of_isBlock (IsBlock.preimage f hB) + +@[to_additive] +theorem isPreprimitive_congr (hφ : Function.Surjective φ) (hf : Function.Bijective f) : + IsPreprimitive M α ↔ IsPreprimitive N β := by + constructor + · intro _ + apply IsPreprimitive.of_surjective hf.surjective + · intro _ + haveI := (isPretransitive_congr hφ hf).mpr toIsPretransitive + exact { + isTrivialBlock_of_isBlock {B} hB := by + rw [← Set.preimage_image_eq B hf.injective] + exact IsTrivialBlock.preimage hf.injective + (isTrivialBlock_of_isBlock (hB.image f hφ hf.injective)) } + +end EquivariantMap + +section Stabilizer + +variable (G : Type*) [Group G] {X : Type*} [MulAction G X] + +open scoped BigOperators Pointwise + +/-- A pretransitive action on a nontrivial type is preprimitive iff +the set of blocks containing a given element is a simple order -/ +@[to_additive (attr := simp) + "A pretransitive action on a nontrivial type is preprimitive iff + the set of blocks containing a given element is a simple order"] +theorem isSimpleOrder_blockMem_iff_isPreprimitive [IsPretransitive G X] [Nontrivial X] (a : X) : + IsSimpleOrder (BlockMem G a) ↔ IsPreprimitive G X := by + constructor + · intro h; let h_bot_or_top := h.eq_bot_or_eq_top + apply IsPreprimitive.of_isTrivialBlock_base a + intro B haB hB + cases' h_bot_or_top ⟨B, haB, hB⟩ with hB' hB' <;> + simp only [← Subtype.coe_inj, Subtype.coe_mk] at hB' + · left; rw [hB']; exact Set.subsingleton_singleton + · right; rw [hB']; rfl + · intro hGX'; apply IsSimpleOrder.mk + rintro ⟨B, haB, hB⟩ + simp only [← Subtype.coe_inj, Subtype.coe_mk] + cases hGX'.isTrivialBlock_of_isBlock hB with + | inl h => + simp [BlockMem.coe_bot, h.eq_singleton_of_mem haB] + | inr h => + simp [BlockMem.coe_top, h] + +/-- A pretransitive action is preprimitive +iff the stabilizer of any point is a maximal subgroup (Wielandt, th. 7.5) -/ +@[to_additive + "A pretransitive action is preprimitive + iff the stabilizer of any point is a maximal subgroup (Wielandt, th. 7.5)"] +theorem isCoatom_stabilizer_iff_preprimitive [IsPretransitive G X] [Nontrivial X] (a : X) : + IsCoatom (stabilizer G a) ↔ IsPreprimitive G X := by + rw [← isSimpleOrder_blockMem_iff_isPreprimitive G a, ← Set.isSimpleOrder_Ici_iff_isCoatom] + simp only [isSimpleOrder_iff_isCoatom_bot] + rw [← OrderIso.isCoatom_iff (block_stabilizerOrderIso G a), OrderIso.map_bot] + +/-- In a preprimitive action, stabilizers are maximal subgroups -/ +@[to_additive "In a preprimitive action, stabilizers are maximal subgroups."] +theorem IsPreprimitive.isCoatom_stabilizer_of_isPreprimitive + [Nontrivial X] [IsPreprimitive G X] (a : X) : + IsCoatom (stabilizer G a) := by + rwa [isCoatom_stabilizer_iff_preprimitive] + +end Stabilizer + +section Normal + +variable {M : Type*} [Group M] {α : Type*} [MulAction M α] + +/-- In a preprimitive action, any normal subgroup that acts nontrivially is pretransitive +(Wielandt, th. 7.1)-/ +@[to_additive "In a preprimitive additive action, + any normal subgroup that acts nontrivially is pretransitive (Wielandt, th. 7.1)"] +-- See note [lower instance priority] +instance (priority := 100) IsPreprimitive.isQuasiPreprimitive [IsPreprimitive M α] : + IsQuasiPreprimitive M α where + isPretransitive_of_normal {N} _ hNX := by + rw [Set.ne_univ_iff_exists_not_mem] at hNX + obtain ⟨a, ha⟩ := hNX + rw [isPretransitive_iff_orbit_eq_univ a] + apply Or.resolve_left (isTrivialBlock_of_isBlock (IsBlock.orbit_of_normal a)) + intro h + apply ha + simp only [mem_fixedPoints] + intro n + rw [← Set.mem_singleton_iff] + suffices orbit N a = {a} by rw [← this]; use n + ext b + rw [Set.Subsingleton.eq_singleton_of_mem h (MulAction.mem_orbit_self a)] + +end Normal + +end MulAction diff --git a/Mathlib/GroupTheory/GroupAction/Transitive.lean b/Mathlib/GroupTheory/GroupAction/Transitive.lean index 809d8d2f03834..cc3ffd00f5484 100644 --- a/Mathlib/GroupTheory/GroupAction/Transitive.lean +++ b/Mathlib/GroupTheory/GroupAction/Transitive.lean @@ -20,7 +20,6 @@ of monoids `φ: M → N`, iff that of `M` on `X` is pretransitive. Given `MulAction G X` where `G` is a group, - - `MulAction.isPretransitive_iff_base G a` shows that `IsPretransitive G X` iff every element is translated from `a` @@ -48,12 +47,12 @@ theorem isPretransitive_iff_base (a : X) : /-- An action of a group is pretransitive iff the orbit of every given element is full -/ @[to_additive "An action of a group is pretransitive iff the orbit of every given element is full"] -theorem isPretransitive_iff_orbit_eq_top (a : X) : - IsPretransitive G X ↔ orbit G a = ⊤ := by +theorem isPretransitive_iff_orbit_eq_univ (a : X) : + IsPretransitive G X ↔ orbit G a = .univ := by rw [isPretransitive_iff_base a, Set.ext_iff] apply forall_congr' intro x - simp_rw [Set.top_eq_univ, Set.mem_univ, iff_true, mem_orbit_iff] + simp_rw [Set.mem_univ, iff_true, mem_orbit_iff] variable {M N α β : Type*} [Monoid M] [Monoid N] [MulAction M α] [MulAction N β] From de715a348f421a70c608a4cfa6a5c107944c914a Mon Sep 17 00:00:00 2001 From: damiano Date: Tue, 4 Feb 2025 22:10:34 +0000 Subject: [PATCH 081/103] feat(CI): bench-after-CI (#21414) Adds a CI step that checks if the `bench-after-CI` label is present. If so, it adds a comment `!bench` once CI passes, triggering a benchmarking run. The management is as follow: * the label `bench-after-CI` is applied manually while CI is running; * once CI passes the lint phase, if the label is present, a bot comments `!bench`, starting the bench process; * when the bench process terminates, it posts the report; * this triggers the bench-summary bot to post the summary *and* to remove the label. Meanwhile, the label `bench-after-CI` is in the list of labels that `bors` rejects. [Zulip](https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/.60bench-after-CI.60.3F) I added the label to this PR, ~~but I am not sure whether the workflow will act on it, since the code is not in `master`~~ and the automation worked. --- .github/build.in.yml | 9 +++++++++ .github/workflows/bench_summary_comment.yml | 8 ++++++++ .github/workflows/bors.yml | 9 +++++++++ .github/workflows/build.yml | 9 +++++++++ .github/workflows/build_fork.yml | 9 +++++++++ bors.toml | 2 +- 6 files changed, 45 insertions(+), 1 deletion(-) diff --git a/.github/build.in.yml b/.github/build.in.yml index 4eb85a0b9604d..593c78f510d6e 100644 --- a/.github/build.in.yml +++ b/.github/build.in.yml @@ -339,6 +339,15 @@ jobs: # Only return if PR is still open filterOutClosed: true + - if: contains(steps.PR.outputs.pr_labels, 'bench-after-CI') + name: If `bench-after-CI` is present, add a `!bench` comment. + uses: GrantBirki/comment@v2 + with: + token: ${{ secrets.AUTO_MERGE_TOKEN }} + issue-number: ${{ steps.PR.outputs.number }} + body: | + !bench + - id: remove_labels name: Remove "awaiting-CI" # we use curl rather than octokit/request-action so that the job won't fail diff --git a/.github/workflows/bench_summary_comment.yml b/.github/workflows/bench_summary_comment.yml index fe14ecdc32a79..4d3c99a8f2c43 100644 --- a/.github/workflows/bench_summary_comment.yml +++ b/.github/workflows/bench_summary_comment.yml @@ -33,3 +33,11 @@ jobs: env: PR: ${{ github.event.issue.number }} GH_TOKEN: ${{secrets.GITHUB_TOKEN}} + + - name: Remove "bench-after-CI" + # we use curl rather than octokit/request-action so that the job won't fail + # (and send an annoying email) if the labels don't exist + run: | + curl --request DELETE \ + --url https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/labels/bench-after-CI \ + --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' diff --git a/.github/workflows/bors.yml b/.github/workflows/bors.yml index fb5ff88ad3a1a..5b83fb5a7f76a 100644 --- a/.github/workflows/bors.yml +++ b/.github/workflows/bors.yml @@ -349,6 +349,15 @@ jobs: # Only return if PR is still open filterOutClosed: true + - if: contains(steps.PR.outputs.pr_labels, 'bench-after-CI') + name: If `bench-after-CI` is present, add a `!bench` comment. + uses: GrantBirki/comment@v2 + with: + token: ${{ secrets.AUTO_MERGE_TOKEN }} + issue-number: ${{ steps.PR.outputs.number }} + body: | + !bench + - id: remove_labels name: Remove "awaiting-CI" # we use curl rather than octokit/request-action so that the job won't fail diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 10dec2ea56665..ab86ffa0c70cc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -356,6 +356,15 @@ jobs: # Only return if PR is still open filterOutClosed: true + - if: contains(steps.PR.outputs.pr_labels, 'bench-after-CI') + name: If `bench-after-CI` is present, add a `!bench` comment. + uses: GrantBirki/comment@v2 + with: + token: ${{ secrets.AUTO_MERGE_TOKEN }} + issue-number: ${{ steps.PR.outputs.number }} + body: | + !bench + - id: remove_labels name: Remove "awaiting-CI" # we use curl rather than octokit/request-action so that the job won't fail diff --git a/.github/workflows/build_fork.yml b/.github/workflows/build_fork.yml index b2ee7842e042e..a01496b0a267e 100644 --- a/.github/workflows/build_fork.yml +++ b/.github/workflows/build_fork.yml @@ -353,6 +353,15 @@ jobs: # Only return if PR is still open filterOutClosed: true + - if: contains(steps.PR.outputs.pr_labels, 'bench-after-CI') + name: If `bench-after-CI` is present, add a `!bench` comment. + uses: GrantBirki/comment@v2 + with: + token: ${{ secrets.AUTO_MERGE_TOKEN }} + issue-number: ${{ steps.PR.outputs.number }} + body: | + !bench + - id: remove_labels name: Remove "awaiting-CI" # we use curl rather than octokit/request-action so that the job won't fail diff --git a/bors.toml b/bors.toml index a94f6e08beeac..e549f7e5ad474 100644 --- a/bors.toml +++ b/bors.toml @@ -1,7 +1,7 @@ status = ["Build", "Lint style"] use_squash_merge = true timeout_sec = 28800 -block_labels = ["WIP", "blocked-by-other-PR", "merge-conflict", "awaiting-CI"] +block_labels = ["WIP", "blocked-by-other-PR", "merge-conflict", "awaiting-CI", "bench-after-CI"] delete_merged_branches = true update_base_for_deletes = true cut_body_after = "---" From 8c7a6879291233f82072dcc7d6930f06162c972f Mon Sep 17 00:00:00 2001 From: Julian Berman Date: Wed, 5 Feb 2025 00:24:45 +0000 Subject: [PATCH 082/103] feat(Factorial): k! divides the product of any k successive integers (#21332) Co-authored-by: Aaron Hill Co-authored-by: Matej Penciak Co-authored-by: Austin Letson --- Mathlib/Data/Nat/Factorial/BigOperators.lean | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Mathlib/Data/Nat/Factorial/BigOperators.lean b/Mathlib/Data/Nat/Factorial/BigOperators.lean index 606f5b7c49b2d..45b4068aa1eea 100644 --- a/Mathlib/Data/Nat/Factorial/BigOperators.lean +++ b/Mathlib/Data/Nat/Factorial/BigOperators.lean @@ -5,6 +5,7 @@ Authors: Kyle Miller, Pim Otte -/ import Mathlib.Data.Nat.Factorial.Basic import Mathlib.Algebra.Order.BigOperators.Ring.Finset +import Mathlib.Tactic.Zify /-! # Factorial with big operators @@ -41,4 +42,14 @@ theorem descFactorial_eq_prod_range (n : ℕ) : ∀ k, n.descFactorial k = ∏ i | 0 => rfl | k + 1 => by rw [descFactorial, prod_range_succ, mul_comm, descFactorial_eq_prod_range n k] +/-- `k!` divides the product of any `k` consecutive integers. -/ +lemma factorial_coe_dvd_prod (k : ℕ) (n : ℤ) : (k ! : ℤ) ∣ ∏ i ∈ range k, (n + i) := by + rw [Int.dvd_iff_emod_eq_zero, Finset.prod_int_mod] + simp_rw [← Int.emod_add_emod n] + have hn : 0 ≤ n % k ! := Int.emod_nonneg n <| Int.natCast_ne_zero.mpr k.factorial_ne_zero + obtain ⟨x, hx⟩ := Int.eq_ofNat_of_zero_le hn + have hdivk := x.factorial_dvd_ascFactorial k + zify [x.ascFactorial_eq_prod_range k] at hdivk + rwa [← Finset.prod_int_mod, ← Int.dvd_iff_emod_eq_zero, hx] + end Nat From 8827be0aa6ad51884048a112d095f955f3e2cb24 Mon Sep 17 00:00:00 2001 From: Peter Nelson <71660771+apnelson1@users.noreply.github.com> Date: Wed, 5 Feb 2025 02:03:37 +0000 Subject: [PATCH 083/103] feat(Data/Set/Lattice): iUnion + insertion (#21322) Another distributivity lemma with iUnion and insertions, needed for #21172. This could maybe be `@[simp]` --- Mathlib/Data/Set/Lattice.lean | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Mathlib/Data/Set/Lattice.lean b/Mathlib/Data/Set/Lattice.lean index e92c7a3eb1bc6..f98ccb56ccfed 100644 --- a/Mathlib/Data/Set/Lattice.lean +++ b/Mathlib/Data/Set/Lattice.lean @@ -1125,10 +1125,14 @@ theorem iUnion_subset_iUnion_const {s : Set α} (h : ι → ι₂) : ⋃ _ : ι, iSup_const_mono (α := Set α) h @[simp] -theorem iUnion_singleton_eq_range {α β : Type*} (f : α → β) : ⋃ x : α, {f x} = range f := by +theorem iUnion_singleton_eq_range (f : α → β) : ⋃ x : α, {f x} = range f := by ext x simp [@eq_comm _ x] +theorem iUnion_insert_eq_range_union_iUnion {ι : Type*} (x : ι → β) (t : ι → Set β) : + ⋃ i, insert (x i) (t i) = range x ∪ ⋃ i, t i := by + simp_rw [← union_singleton, iUnion_union_distrib, union_comm, iUnion_singleton_eq_range] + theorem iUnion_of_singleton (α : Type*) : (⋃ x, {x} : Set α) = univ := by simp [Set.ext_iff] theorem iUnion_of_singleton_coe (s : Set α) : ⋃ i : s, ({(i : α)} : Set α) = s := by simp From 460a8b0954e83a0dc1719aba4a9aa2c46f3ee4e3 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Wed, 5 Feb 2025 04:27:41 +0000 Subject: [PATCH 084/103] feat/doc: split files, add documentation (#21421) Move the material on orders of analytic functions out of the file `Mathlib/Analysis/Analytic/IsolatedZeros.lean`. Create a directory `Mathlib/Analysis/Meromorphic`. Move the file `Mathlib/Analysis/Analytic/Meromorphic.lean` to `Mathlib/Analysis/Meromorphic/Basic.lean`. Move the material on orders of meromorphic functions to the file `Mathlib/Analysis/Meromorphic/Order.lean`. Add documentation. This PR does not add new theorems or change existing ones. As discussed with @TwoFX (and others) during the Lean Meeting at Freiburg, I would like to move material on orders of analytic/meromorphic functions to independent files. Reasons: - The material on order in `Mathlib/Analysis/Analytic/IsolatedZeros.lean` was never referenced from anywhere else in this file. This is now seen by the fact that `Mathlib/Analysis/Analytic/IsolatedZeros.lean` does not reference the new file `Mathlib/Analysis/Analytic/Order.lean`. Similarly in the meromorphic setting. - The material on orders is bound to grow quite a bit, as I plan to add the missing material on the behavior of orders under addition and composition, both in the analytic and meromorphic settings. I will also need to say more about the topology of the level sets. - I intend to add more material on meromorphic functions, including a discussion of (and API for) continuous extension, and extraction of zeros/poles. The amount of material justifies that meromorphic functions get their own directory. --- Mathlib.lean | 4 +- Mathlib/Analysis/Analytic/IsolatedZeros.lean | 135 ----------- Mathlib/Analysis/Analytic/Order.lean | 195 +++++++++++++++ .../Basic.lean} | 166 ------------- Mathlib/Analysis/Meromorphic/Order.lean | 229 ++++++++++++++++++ 5 files changed, 427 insertions(+), 302 deletions(-) create mode 100644 Mathlib/Analysis/Analytic/Order.lean rename Mathlib/Analysis/{Analytic/Meromorphic.lean => Meromorphic/Basic.lean} (58%) create mode 100644 Mathlib/Analysis/Meromorphic/Order.lean diff --git a/Mathlib.lean b/Mathlib.lean index bc5021e153012..8bb17b047f6ca 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -1149,8 +1149,8 @@ import Mathlib.Analysis.Analytic.Inverse import Mathlib.Analysis.Analytic.IsolatedZeros import Mathlib.Analysis.Analytic.IteratedFDeriv import Mathlib.Analysis.Analytic.Linear -import Mathlib.Analysis.Analytic.Meromorphic import Mathlib.Analysis.Analytic.OfScalars +import Mathlib.Analysis.Analytic.Order import Mathlib.Analysis.Analytic.Polynomial import Mathlib.Analysis.Analytic.RadiusLiminf import Mathlib.Analysis.Analytic.Uniqueness @@ -1448,6 +1448,8 @@ import Mathlib.Analysis.MeanInequalities import Mathlib.Analysis.MeanInequalitiesPow import Mathlib.Analysis.MellinInversion import Mathlib.Analysis.MellinTransform +import Mathlib.Analysis.Meromorphic.Basic +import Mathlib.Analysis.Meromorphic.Order import Mathlib.Analysis.Normed.Affine.AddTorsor import Mathlib.Analysis.Normed.Affine.AddTorsorBases import Mathlib.Analysis.Normed.Affine.ContinuousAffineMap diff --git a/Mathlib/Analysis/Analytic/IsolatedZeros.lean b/Mathlib/Analysis/Analytic/IsolatedZeros.lean index d976c6b046c7f..1191247cf4290 100644 --- a/Mathlib/Analysis/Analytic/IsolatedZeros.lean +++ b/Mathlib/Analysis/Analytic/IsolatedZeros.lean @@ -190,98 +190,6 @@ theorem exists_eventuallyEq_pow_smul_nonzero_iff (hf : AnalyticAt 𝕜 f z₀) : hp.iterate_dslope_fslope_ne_zero (hf_ne.imp hp.locally_zero_iff.mpr), hp.eq_pow_order_mul_iterate_dslope⟩ -open scoped Classical in -/-- The order of vanishing of `f` at `z₀`, as an element of `ℕ∞`. - -This is defined to be `∞` if `f` is identically 0 on a neighbourhood of `z₀`, and otherwise the -unique `n` such that `f z = (z - z₀) ^ n • g z` with `g` analytic and non-vanishing at `z₀`. See -`AnalyticAt.order_eq_top_iff` and `AnalyticAt.order_eq_nat_iff` for these equivalences. -/ -noncomputable def order (hf : AnalyticAt 𝕜 f z₀) : ENat := - if h : ∀ᶠ z in 𝓝 z₀, f z = 0 then ⊤ - else ↑(hf.exists_eventuallyEq_pow_smul_nonzero_iff.mpr h).choose - -lemma order_eq_top_iff (hf : AnalyticAt 𝕜 f z₀) : hf.order = ⊤ ↔ ∀ᶠ z in 𝓝 z₀, f z = 0 := by - unfold order - split_ifs with h - · rwa [eq_self, true_iff] - · simpa only [ne_eq, ENat.coe_ne_top, false_iff] using h - -lemma order_eq_nat_iff (hf : AnalyticAt 𝕜 f z₀) (n : ℕ) : hf.order = ↑n ↔ - ∃ (g : 𝕜 → E), AnalyticAt 𝕜 g z₀ ∧ g z₀ ≠ 0 ∧ ∀ᶠ z in 𝓝 z₀, f z = (z - z₀) ^ n • g z := by - unfold order - split_ifs with h - · simp only [ENat.top_ne_coe, false_iff] - contrapose! h - rw [← hf.exists_eventuallyEq_pow_smul_nonzero_iff] - exact ⟨n, h⟩ - · rw [← hf.exists_eventuallyEq_pow_smul_nonzero_iff] at h - refine ⟨fun hn ↦ (WithTop.coe_inj.mp hn : h.choose = n) ▸ h.choose_spec, fun h' ↦ ?_⟩ - rw [unique_eventuallyEq_pow_smul_nonzero h.choose_spec h'] - -/-- An analytic function `f` has finite order at a point `z₀` iff it locally looks - like `(z - z₀) ^ order • g`, where `g` is analytic and does not vanish at - `z₀`. -/ -lemma order_ne_top_iff (hf : AnalyticAt 𝕜 f z₀) : - hf.order ≠ ⊤ ↔ ∃ (g : 𝕜 → E), AnalyticAt 𝕜 g z₀ ∧ g z₀ ≠ 0 - ∧ f =ᶠ[𝓝 z₀] fun z ↦ (z - z₀) ^ (hf.order.toNat) • g z := by - simp only [← ENat.coe_toNat_eq_self, Eq.comm, EventuallyEq, ← hf.order_eq_nat_iff] - -@[deprecated (since := "2025-02-03")] -alias order_neq_top_iff := order_ne_top_iff - -/-- An analytic function has order zero at a point iff it does not vanish there. -/ -lemma order_eq_zero_iff (hf : AnalyticAt 𝕜 f z₀) : - hf.order = 0 ↔ f z₀ ≠ 0 := by - rw [← ENat.coe_zero, order_eq_nat_iff hf 0] - constructor - · intro ⟨g, _, _, hg⟩ - simpa [hg.self_of_nhds] - · exact fun hz ↦ ⟨f, hf, hz, by simp⟩ - -/-- An analytic function vanishes at a point if its order is nonzero when converted to ℕ. -/ -lemma apply_eq_zero_of_order_toNat_ne_zero (hf : AnalyticAt 𝕜 f z₀) : - hf.order.toNat ≠ 0 → f z₀ = 0 := by - simp [hf.order_eq_zero_iff] - tauto - -/- Helper lemma for `AnalyticAt.order_mul` -/ -lemma order_mul_of_order_eq_top {f g : 𝕜 → 𝕜} (hf : AnalyticAt 𝕜 f z₀) - (hg : AnalyticAt 𝕜 g z₀) (h'f : hf.order = ⊤) : - (hf.mul hg).order = ⊤ := by - rw [AnalyticAt.order_eq_top_iff, eventually_nhds_iff] at * - obtain ⟨t, h₁t, h₂t, h₃t⟩ := h'f - exact ⟨t, fun y hy ↦ (by simp [h₁t y hy]), h₂t, h₃t⟩ - -/-- The order is additive when multiplying analytic functions. -/ -theorem order_mul {f g : 𝕜 → 𝕜} (hf : AnalyticAt 𝕜 f z₀) (hg : AnalyticAt 𝕜 g z₀) : - (hf.mul hg).order = hf.order + hg.order := by - -- Trivial cases: one of the functions vanishes around z₀ - by_cases h₂f : hf.order = ⊤ - · simp [hf.order_mul_of_order_eq_top hg h₂f, h₂f] - by_cases h₂g : hg.order = ⊤ - · simp [mul_comm f g, hg.order_mul_of_order_eq_top hf h₂g, h₂g] - -- Non-trivial case: both functions do not vanish around z₀ - obtain ⟨g₁, h₁g₁, h₂g₁, h₃g₁⟩ := hf.order_ne_top_iff.1 h₂f - obtain ⟨g₂, h₁g₂, h₂g₂, h₃g₂⟩ := hg.order_ne_top_iff.1 h₂g - rw [← ENat.coe_toNat h₂f, ← ENat.coe_toNat h₂g, ← ENat.coe_add, (hf.mul hg).order_eq_nat_iff] - use g₁ * g₂, by exact h₁g₁.mul h₁g₂ - constructor - · simp - tauto - · obtain ⟨t, h₁t, h₂t, h₃t⟩ := eventually_nhds_iff.1 h₃g₁ - obtain ⟨s, h₁s, h₂s, h₃s⟩ := eventually_nhds_iff.1 h₃g₂ - exact eventually_nhds_iff.2 - ⟨t ∩ s, fun y hy ↦ (by simp [h₁t y hy.1, h₁s y hy.2]; ring), h₂t.inter h₂s, h₃t, h₃s⟩ - -/-- The order multiplies by `n` when taking an analytic function to its `n`th power. -/ -theorem order_pow {f : 𝕜 → 𝕜} (hf : AnalyticAt 𝕜 f z₀) {n : ℕ} : - (hf.pow n).order = n • hf.order := by - induction n - case zero => - simp [AnalyticAt.order_eq_zero_iff] - case succ n hn => - simp [add_mul, pow_add, (hf.pow n).order_mul hf, hn] - end AnalyticAt namespace AnalyticOnNhd @@ -348,49 +256,6 @@ theorem eq_of_frequently_eq [ConnectedSpace 𝕜] (hf : AnalyticOnNhd 𝕜 f uni @[deprecated (since := "2024-09-26")] alias _root_.AnalyticOn.eq_of_frequently_eq := eq_of_frequently_eq -/-- The set where an analytic function has infinite order is clopen in its domain of analyticity. -/ -theorem isClopen_setOf_order_eq_top (h₁f : AnalyticOnNhd 𝕜 f U) : - IsClopen { u : U | (h₁f u.1 u.2).order = ⊤ } := by - constructor - · rw [← isOpen_compl_iff, isOpen_iff_forall_mem_open] - intro z hz - rcases (h₁f z.1 z.2).eventually_eq_zero_or_eventually_ne_zero with h | h - · -- Case: f is locally zero in a punctured neighborhood of z - rw [← (h₁f z.1 z.2).order_eq_top_iff] at h - tauto - · -- Case: f is locally nonzero in a punctured neighborhood of z - obtain ⟨t', h₁t', h₂t', h₃t'⟩ := eventually_nhds_iff.1 (eventually_nhdsWithin_iff.1 h) - use Subtype.val ⁻¹' t' - constructor - · intro w hw - simp only [mem_compl_iff, mem_setOf_eq] - by_cases h₁w : w = z - · rwa [h₁w] - · rw [(h₁f _ w.2).order_eq_zero_iff.2 ((h₁t' w hw) (Subtype.coe_ne_coe.mpr h₁w))] - exact ENat.zero_ne_top - · exact ⟨isOpen_induced h₂t', h₃t'⟩ - · apply isOpen_iff_forall_mem_open.mpr - intro z hz - conv => - arg 1; intro; left; right; arg 1; intro - rw [AnalyticAt.order_eq_top_iff, eventually_nhds_iff] - simp only [Set.mem_setOf_eq] at hz - rw [AnalyticAt.order_eq_top_iff, eventually_nhds_iff] at hz - obtain ⟨t', h₁t', h₂t', h₃t'⟩ := hz - use Subtype.val ⁻¹' t' - simp only [Set.mem_compl_iff, Set.mem_singleton_iff, isOpen_induced h₂t', Set.mem_preimage, - h₃t', and_self, and_true] - intro w hw - simp only [mem_setOf_eq] - -- Trivial case: w = z - by_cases h₁w : w = z - · rw [h₁w] - tauto - -- Nontrivial case: w ≠ z - use t' \ {z.1}, fun y h₁y ↦ h₁t' y h₁y.1, h₂t'.sdiff isClosed_singleton - apply (Set.mem_diff w).1 - exact ⟨hw, Set.mem_singleton_iff.not.1 (Subtype.coe_ne_coe.2 h₁w)⟩ - section Mul /-! ### Vanishing of products of analytic functions diff --git a/Mathlib/Analysis/Analytic/Order.lean b/Mathlib/Analysis/Analytic/Order.lean new file mode 100644 index 0000000000000..b811b79d7734a --- /dev/null +++ b/Mathlib/Analysis/Analytic/Order.lean @@ -0,0 +1,195 @@ +/- +Copyright (c) 2022 Vincent Beffara. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Vincent Beffara, Stefan Kebekus +-/ +import Mathlib.Analysis.Analytic.IsolatedZeros + +/-! +# Vanishing Order of Analytic Functions + +This file defines the order of vanishing of an analytic function `f` at a point `z₀`, as an element +of `ℕ∞`. + +TODO: Uniformize API between analytic and meromorphic functions +-/ + +open Filter Set +open scoped Topology + +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] + [NormedSpace 𝕜 E] {f g : 𝕜 → E} {n : ℕ} {z₀ : 𝕜} + +/-! +## Vanishing Order at a Point: Definition and Characterization +-/ + +namespace AnalyticAt + +open scoped Classical in + +/-- The order of vanishing of `f` at `z₀`, as an element of `ℕ∞`. + +The order is defined to be `∞` if `f` is identically 0 on a neighbourhood of `z₀`, and otherwise the +unique `n` such that `f` can locally be written as `f z = (z - z₀) ^ n • g z`, where `g` is analytic +and does not vanish at `z₀`. See `AnalyticAt.order_eq_top_iff` and `AnalyticAt.order_eq_nat_iff` for +these equivalences. -/ +noncomputable def order (hf : AnalyticAt 𝕜 f z₀) : ENat := + if h : ∀ᶠ z in 𝓝 z₀, f z = 0 then ⊤ + else ↑(hf.exists_eventuallyEq_pow_smul_nonzero_iff.mpr h).choose + +/-- The order of an analytic function `f` at a `z₀` is infinity iff `f` vanishes locally around +`z₀`. -/ +lemma order_eq_top_iff (hf : AnalyticAt 𝕜 f z₀) : hf.order = ⊤ ↔ ∀ᶠ z in 𝓝 z₀, f z = 0 := by + unfold order + split_ifs with h + · rwa [eq_self, true_iff] + · simpa only [ne_eq, ENat.coe_ne_top, false_iff] using h + +/-- The order of an analytic function `f` at `z₀` equals a natural number `n` iff `f` can locally +be written as `f z = (z - z₀) ^ n • g z`, where `g` is analytic and does not vanish at `z₀`. -/ +lemma order_eq_nat_iff (hf : AnalyticAt 𝕜 f z₀) (n : ℕ) : hf.order = ↑n ↔ + ∃ (g : 𝕜 → E), AnalyticAt 𝕜 g z₀ ∧ g z₀ ≠ 0 ∧ ∀ᶠ z in 𝓝 z₀, f z = (z - z₀) ^ n • g z := by + unfold order + split_ifs with h + · simp only [ENat.top_ne_coe, false_iff] + contrapose! h + rw [← hf.exists_eventuallyEq_pow_smul_nonzero_iff] + exact ⟨n, h⟩ + · rw [← hf.exists_eventuallyEq_pow_smul_nonzero_iff] at h + refine ⟨fun hn ↦ (WithTop.coe_inj.mp hn : h.choose = n) ▸ h.choose_spec, fun h' ↦ ?_⟩ + rw [unique_eventuallyEq_pow_smul_nonzero h.choose_spec h'] + +/-- The order of an analytic function `f` at `z₀` is finite iff `f` can locally be written as +`f z = (z - z₀) ^ order • g z`, where `g` is analytic and does not vanish at `z₀`. -/ +lemma order_ne_top_iff (hf : AnalyticAt 𝕜 f z₀) : + hf.order ≠ ⊤ ↔ ∃ (g : 𝕜 → E), AnalyticAt 𝕜 g z₀ ∧ g z₀ ≠ 0 + ∧ f =ᶠ[𝓝 z₀] fun z ↦ (z - z₀) ^ (hf.order.toNat) • g z := by + simp only [← ENat.coe_toNat_eq_self, Eq.comm, EventuallyEq, ← hf.order_eq_nat_iff] + +@[deprecated (since := "2025-02-03")] +alias order_neq_top_iff := order_ne_top_iff + +/-- The order of an analytic function `f` at `z₀` is zero iff `f` does not vanish at `z₀`. -/ +lemma order_eq_zero_iff (hf : AnalyticAt 𝕜 f z₀) : + hf.order = 0 ↔ f z₀ ≠ 0 := by + rw [← ENat.coe_zero, order_eq_nat_iff hf 0] + constructor + · intro ⟨g, _, _, hg⟩ + simpa [hg.self_of_nhds] + · exact fun hz ↦ ⟨f, hf, hz, by simp⟩ + +/-- An analytic function vanishes at a point if its order is nonzero when converted to ℕ. -/ +lemma apply_eq_zero_of_order_toNat_ne_zero (hf : AnalyticAt 𝕜 f z₀) : + hf.order.toNat ≠ 0 → f z₀ = 0 := by + simp [hf.order_eq_zero_iff] + tauto + +/-! +## Vanishing Order at a Point: Behaviour under Ring Operations + +The theorem `AnalyticAt.order_mul` and `AnalyticAt.order_pow` establish additivity of the order +under multiplication and taking powers. + +TODO: Behaviour under Addition/Subtraction +-/ + +/-- Helper lemma for `AnalyticAt.order_mul` -/ +lemma order_mul_of_order_eq_top {f g : 𝕜 → 𝕜} (hf : AnalyticAt 𝕜 f z₀) + (hg : AnalyticAt 𝕜 g z₀) (h'f : hf.order = ⊤) : + (hf.mul hg).order = ⊤ := by + rw [AnalyticAt.order_eq_top_iff, eventually_nhds_iff] at * + obtain ⟨t, h₁t, h₂t, h₃t⟩ := h'f + exact ⟨t, fun y hy ↦ (by simp [h₁t y hy]), h₂t, h₃t⟩ + +/-- The order is additive when multiplying analytic functions. -/ +theorem order_mul {f g : 𝕜 → 𝕜} (hf : AnalyticAt 𝕜 f z₀) (hg : AnalyticAt 𝕜 g z₀) : + (hf.mul hg).order = hf.order + hg.order := by + -- Trivial cases: one of the functions vanishes around z₀ + by_cases h₂f : hf.order = ⊤ + · simp [hf.order_mul_of_order_eq_top hg h₂f, h₂f] + by_cases h₂g : hg.order = ⊤ + · simp [mul_comm f g, hg.order_mul_of_order_eq_top hf h₂g, h₂g] + -- Non-trivial case: both functions do not vanish around z₀ + obtain ⟨g₁, h₁g₁, h₂g₁, h₃g₁⟩ := hf.order_ne_top_iff.1 h₂f + obtain ⟨g₂, h₁g₂, h₂g₂, h₃g₂⟩ := hg.order_ne_top_iff.1 h₂g + rw [← ENat.coe_toNat h₂f, ← ENat.coe_toNat h₂g, ← ENat.coe_add, (hf.mul hg).order_eq_nat_iff] + use g₁ * g₂, by exact h₁g₁.mul h₁g₂ + constructor + · simp + tauto + · obtain ⟨t, h₁t, h₂t, h₃t⟩ := eventually_nhds_iff.1 h₃g₁ + obtain ⟨s, h₁s, h₂s, h₃s⟩ := eventually_nhds_iff.1 h₃g₂ + exact eventually_nhds_iff.2 + ⟨t ∩ s, fun y hy ↦ (by simp [h₁t y hy.1, h₁s y hy.2]; ring), h₂t.inter h₂s, h₃t, h₃s⟩ + +/-- The order multiplies by `n` when taking an analytic function to its `n`th power. -/ +theorem order_pow {f : 𝕜 → 𝕜} (hf : AnalyticAt 𝕜 f z₀) {n : ℕ} : + (hf.pow n).order = n • hf.order := by + induction n + case zero => + simp [AnalyticAt.order_eq_zero_iff] + case succ n hn => + simp [add_mul, pow_add, (hf.pow n).order_mul hf, hn] + +end AnalyticAt + +/-! +## Level Sets of the Order Function + +TODO: + +- Draw conclusions about behaviour of the order function on connected domains of analyticity. + +- Prove that the set where an analytic function has order in [1,∞) is discrete within its domain of + analyticity. +-/ + +namespace AnalyticOnNhd + +variable {U : Set 𝕜} + +/-- The set where an analytic function has infinite order is clopen in its domain of analyticity. -/ +theorem isClopen_setOf_order_eq_top (h₁f : AnalyticOnNhd 𝕜 f U) : + IsClopen { u : U | (h₁f u.1 u.2).order = ⊤ } := by + constructor + · rw [← isOpen_compl_iff, isOpen_iff_forall_mem_open] + intro z hz + rcases (h₁f z.1 z.2).eventually_eq_zero_or_eventually_ne_zero with h | h + · -- Case: f is locally zero in a punctured neighborhood of z + rw [← (h₁f z.1 z.2).order_eq_top_iff] at h + tauto + · -- Case: f is locally nonzero in a punctured neighborhood of z + obtain ⟨t', h₁t', h₂t', h₃t'⟩ := eventually_nhds_iff.1 (eventually_nhdsWithin_iff.1 h) + use Subtype.val ⁻¹' t' + constructor + · intro w hw + simp only [mem_compl_iff, mem_setOf_eq] + by_cases h₁w : w = z + · rwa [h₁w] + · rw [(h₁f _ w.2).order_eq_zero_iff.2 ((h₁t' w hw) (Subtype.coe_ne_coe.mpr h₁w))] + exact ENat.zero_ne_top + · exact ⟨isOpen_induced h₂t', h₃t'⟩ + · apply isOpen_iff_forall_mem_open.mpr + intro z hz + conv => + arg 1; intro; left; right; arg 1; intro + rw [AnalyticAt.order_eq_top_iff, eventually_nhds_iff] + simp only [mem_setOf_eq] at hz + rw [AnalyticAt.order_eq_top_iff, eventually_nhds_iff] at hz + obtain ⟨t', h₁t', h₂t', h₃t'⟩ := hz + use Subtype.val ⁻¹' t' + simp only [mem_compl_iff, mem_singleton_iff, isOpen_induced h₂t', mem_preimage, + h₃t', and_self, and_true] + intro w hw + simp only [mem_setOf_eq] + -- Trivial case: w = z + by_cases h₁w : w = z + · rw [h₁w] + tauto + -- Nontrivial case: w ≠ z + use t' \ {z.1}, fun y h₁y ↦ h₁t' y h₁y.1, h₂t'.sdiff isClosed_singleton + apply (mem_diff w).1 + exact ⟨hw, mem_singleton_iff.not.1 (Subtype.coe_ne_coe.2 h₁w)⟩ + +end AnalyticOnNhd diff --git a/Mathlib/Analysis/Analytic/Meromorphic.lean b/Mathlib/Analysis/Meromorphic/Basic.lean similarity index 58% rename from Mathlib/Analysis/Analytic/Meromorphic.lean rename to Mathlib/Analysis/Meromorphic/Basic.lean index caf3414b30d5f..223aade943866 100644 --- a/Mathlib/Analysis/Analytic/Meromorphic.lean +++ b/Mathlib/Analysis/Meromorphic/Basic.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: David Loeffler, Stefan Kebekus -/ import Mathlib.Analysis.Analytic.IsolatedZeros -import Mathlib.Algebra.Order.AddGroupWithTop /-! # Meromorphic functions @@ -14,7 +13,6 @@ Main statements: * `MeromorphicAt`: definition of meromorphy at a point * `MeromorphicAt.iff_eventuallyEq_zpow_smul_analyticAt`: `f` is meromorphic at `z₀` iff we have `f z = (z - z₀) ^ n • g z` on a punctured nhd of `z₀`, for some `n : ℤ` and `g` analytic at z₀. -* `MeromorphicAt.order`: order of vanishing at `z₀`, as an element of `ℤ ∪ {∞}` -/ open Filter @@ -231,94 +229,6 @@ theorem eventually_analyticAt [CompleteSpace E] {f : 𝕜 → E} {x : 𝕜} intro z hz simp [smul_smul, hz, sub_eq_zero] -/-- The order of vanishing of a meromorphic function, as an element of `ℤ ∪ ∞` (to include the -case of functions identically 0 near `x`). -/ -noncomputable def order {f : 𝕜 → E} {x : 𝕜} (hf : MeromorphicAt f x) : WithTop ℤ := - (hf.choose_spec.order.map (↑· : ℕ → ℤ)) - hf.choose - -open WithTop.LinearOrderedAddCommGroup - -lemma order_eq_top_iff {f : 𝕜 → E} {x : 𝕜} (hf : MeromorphicAt f x) : - hf.order = ⊤ ↔ ∀ᶠ z in 𝓝[≠] x, f z = 0 := by - unfold order - by_cases h : hf.choose_spec.order = ⊤ - · rw [h, ENat.map_top, ← WithTop.coe_natCast, - top_sub, eq_self, true_iff, eventually_nhdsWithin_iff] - rw [AnalyticAt.order_eq_top_iff] at h - filter_upwards [h] with z hf hz - rwa [smul_eq_zero_iff_right <| pow_ne_zero _ (sub_ne_zero.mpr hz)] at hf - · obtain ⟨m, hm⟩ := ENat.ne_top_iff_exists.mp h - simp only [← hm, ENat.map_coe, WithTop.coe_natCast, sub_eq_top_iff, WithTop.natCast_ne_top, - or_self, false_iff] - contrapose! h - rw [AnalyticAt.order_eq_top_iff] - rw [← hf.choose_spec.frequently_eq_iff_eventually_eq analyticAt_const] - apply Eventually.frequently - filter_upwards [h] with z hfz - rw [hfz, smul_zero] - -lemma order_eq_int_iff {f : 𝕜 → E} {x : 𝕜} (hf : MeromorphicAt f x) (n : ℤ) : hf.order = n ↔ - ∃ g : 𝕜 → E, AnalyticAt 𝕜 g x ∧ g x ≠ 0 ∧ ∀ᶠ z in 𝓝[≠] x, f z = (z - x) ^ n • g z := by - unfold order - by_cases h : hf.choose_spec.order = ⊤ - · rw [h, ENat.map_top, ← WithTop.coe_natCast, top_sub, - eq_false_intro WithTop.top_ne_coe, false_iff] - rw [AnalyticAt.order_eq_top_iff] at h - refine fun ⟨g, hg_an, hg_ne, hg_eq⟩ ↦ hg_ne ?_ - apply EventuallyEq.eq_of_nhds - rw [EventuallyEq, ← AnalyticAt.frequently_eq_iff_eventually_eq hg_an analyticAt_const] - apply Eventually.frequently - rw [eventually_nhdsWithin_iff] at hg_eq ⊢ - filter_upwards [h, hg_eq] with z hfz hfz_eq hz - rwa [hfz_eq hz, ← mul_smul, smul_eq_zero_iff_right] at hfz - exact mul_ne_zero (pow_ne_zero _ (sub_ne_zero.mpr hz)) (zpow_ne_zero _ (sub_ne_zero.mpr hz)) - · obtain ⟨m, h⟩ := ENat.ne_top_iff_exists.mp h - rw [← h, ENat.map_coe, ← WithTop.coe_natCast, ← coe_sub, WithTop.coe_inj] - obtain ⟨g, hg_an, hg_ne, hg_eq⟩ := (AnalyticAt.order_eq_nat_iff _ _).mp h.symm - replace hg_eq : ∀ᶠ (z : 𝕜) in 𝓝[≠] x, f z = (z - x) ^ (↑m - ↑hf.choose : ℤ) • g z := by - rw [eventually_nhdsWithin_iff] - filter_upwards [hg_eq] with z hg_eq hz - rwa [← smul_right_inj <| zpow_ne_zero _ (sub_ne_zero.mpr hz), ← mul_smul, - ← zpow_add₀ (sub_ne_zero.mpr hz), ← add_sub_assoc, add_sub_cancel_left, zpow_natCast, - zpow_natCast] - exact ⟨fun h ↦ ⟨g, hg_an, hg_ne, h ▸ hg_eq⟩, - AnalyticAt.unique_eventuallyEq_zpow_smul_nonzero ⟨g, hg_an, hg_ne, hg_eq⟩⟩ - -/-- Compatibility of notions of `order` for analytic and meromorphic functions. -/ -lemma _root_.AnalyticAt.meromorphicAt_order {f : 𝕜 → E} {x : 𝕜} (hf : AnalyticAt 𝕜 f x) : - hf.meromorphicAt.order = hf.order.map (↑) := by - rcases eq_or_ne hf.order ⊤ with ho | ho - · rw [ho, ENat.map_top, order_eq_top_iff] - exact (hf.order_eq_top_iff.mp ho).filter_mono nhdsWithin_le_nhds - · obtain ⟨n, hn⟩ := ENat.ne_top_iff_exists.mp ho - simp_rw [← hn, ENat.map_coe, order_eq_int_iff, zpow_natCast] - rcases (hf.order_eq_nat_iff _).mp hn.symm with ⟨g, h1, h2, h3⟩ - exact ⟨g, h1, h2, h3.filter_mono nhdsWithin_le_nhds⟩ - -/-- The order is additive when multiplying scalar-valued and vector-valued meromorphic functions. -/ -theorem order_smul {f : 𝕜 → 𝕜} {g : 𝕜 → E} {x : 𝕜} - (hf : MeromorphicAt f x) (hg : MeromorphicAt g x) : - (hf.smul hg).order = hf.order + hg.order := by - -- Trivial cases: one of the functions vanishes around z₀ - cases' h₂f : hf.order with m h₂f - · simp only [top_add, order_eq_top_iff] at h₂f ⊢ - filter_upwards [h₂f] with z hz using by simp [hz] - cases' h₂g : hg.order with n h₂f - · simp only [add_top, order_eq_top_iff] at h₂g ⊢ - filter_upwards [h₂g] with z hz using by simp [hz] - -- Non-trivial case: both functions do not vanish around z₀ - rw [← WithTop.coe_add, order_eq_int_iff] - obtain ⟨F, h₁F, h₂F, h₃F⟩ := (hf.order_eq_int_iff _).1 h₂f - obtain ⟨G, h₁G, h₂G, h₃G⟩ := (hg.order_eq_int_iff _).1 h₂g - use F • G, h₁F.smul h₁G, by simp [h₂F, h₂G] - filter_upwards [self_mem_nhdsWithin, h₃F, h₃G] with a ha hfa hga - simp [hfa, hga, smul_comm (F a), zpow_add₀ (sub_ne_zero.mpr ha), mul_smul] - -/-- The order is additive when multiplying meromorphic functions. -/ -theorem order_mul {f g : 𝕜 → 𝕜} {x : 𝕜} (hf : MeromorphicAt f x) (hg : MeromorphicAt g x) : - (hf.mul hg).order = hf.order + hg.order := - hf.order_smul hg - lemma iff_eventuallyEq_zpow_smul_analyticAt {f : 𝕜 → E} {x : 𝕜} : MeromorphicAt f x ↔ ∃ (n : ℤ) (g : 𝕜 → E), AnalyticAt 𝕜 g x ∧ ∀ᶠ z in 𝓝[≠] x, f z = (z - x) ^ n • g z := by refine ⟨fun ⟨n, hn⟩ ↦ ⟨-n, _, ⟨hn, eventually_nhdsWithin_iff.mpr ?_⟩⟩, ?_⟩ @@ -351,82 +261,6 @@ lemma id {U : Set 𝕜} : MeromorphicOn id U := fun x _ ↦ .id x lemma const (e : E) {U : Set 𝕜} : MeromorphicOn (fun _ ↦ e) U := fun x _ ↦ .const e x -/-- The set where a meromorphic function has infinite order is clopen in its domain of meromorphy. --/ -theorem isClopen_setOf_order_eq_top {U : Set 𝕜} (hf : MeromorphicOn f U) : - IsClopen { u : U | (hf u.1 u.2).order = ⊤ } := by - constructor - · rw [← isOpen_compl_iff, isOpen_iff_forall_mem_open] - intro z hz - rcases (hf z.1 z.2).eventually_eq_zero_or_eventually_ne_zero with h | h - · -- Case: f is locally zero in a punctured neighborhood of z - rw [← (hf z.1 z.2).order_eq_top_iff] at h - tauto - · -- Case: f is locally nonzero in a punctured neighborhood of z - obtain ⟨t', h₁t', h₂t', h₃t'⟩ := eventually_nhds_iff.1 (eventually_nhdsWithin_iff.1 h) - use Subtype.val ⁻¹' t' - constructor - · intro w hw - simp only [Set.mem_compl_iff, Set.mem_setOf_eq] - by_cases h₁w : w = z - · rwa [h₁w] - · rw [MeromorphicAt.order_eq_top_iff, not_eventually] - apply Filter.Eventually.frequently - rw [eventually_nhdsWithin_iff, eventually_nhds_iff] - use t' \ {z.1}, fun y h₁y h₂y ↦ h₁t' y h₁y.1 h₁y.2, h₂t'.sdiff isClosed_singleton, hw, - Set.mem_singleton_iff.not.2 (Subtype.coe_ne_coe.mpr h₁w) - · exact ⟨isOpen_induced h₂t', h₃t'⟩ - · apply isOpen_iff_forall_mem_open.mpr - intro z hz - conv => - arg 1; intro; left; right; arg 1; intro - rw [MeromorphicAt.order_eq_top_iff, eventually_nhdsWithin_iff, eventually_nhds_iff] - simp only [Set.mem_setOf_eq] at hz - rw [MeromorphicAt.order_eq_top_iff, eventually_nhdsWithin_iff, eventually_nhds_iff] at hz - obtain ⟨t', h₁t', h₂t', h₃t'⟩ := hz - use Subtype.val ⁻¹' t' - simp only [Set.mem_compl_iff, Set.mem_singleton_iff, isOpen_induced h₂t', Set.mem_preimage, - h₃t', and_self, and_true] - intro w hw - simp only [Set.mem_setOf_eq] - -- Trivial case: w = z - by_cases h₁w : w = z - · rw [h₁w] - tauto - -- Nontrivial case: w ≠ z - use t' \ {z.1}, fun y h₁y _ ↦ h₁t' y (Set.mem_of_mem_diff h₁y) (Set.mem_of_mem_inter_right h₁y) - constructor - · exact h₂t'.sdiff isClosed_singleton - · apply (Set.mem_diff w).1 - exact ⟨hw, Set.mem_singleton_iff.not.1 (Subtype.coe_ne_coe.2 h₁w)⟩ - -/-- On a connected set, there exists a point where a meromorphic function `f` has finite order iff -`f` has finite order at every point. -/ -theorem exists_order_ne_top_iff_forall {U : Set 𝕜} (hf : MeromorphicOn f U) (hU : IsConnected U) : - (∃ u : U, (hf u u.2).order ≠ ⊤) ↔ (∀ u : U, (hf u u.2).order ≠ ⊤) := by - constructor - · intro h₂f - have := isPreconnected_iff_preconnectedSpace.1 hU.isPreconnected - rcases isClopen_iff.1 hf.isClopen_setOf_order_eq_top with h | h - · intro u - have : u ∉ (∅ : Set U) := by exact fun a => a - rw [← h] at this - tauto - · obtain ⟨u, hU⟩ := h₂f - have : u ∈ Set.univ := by trivial - rw [← h] at this - tauto - · intro h₂f - obtain ⟨v, hv⟩ := hU.nonempty - use ⟨v, hv⟩, h₂f ⟨v, hv⟩ - -/-- On a preconnected set, a meromorphic function has finite order at one point if it has finite -order at another point. -/ -theorem order_ne_top_of_isPreconnected {U : Set 𝕜} {x y : 𝕜} (hf : MeromorphicOn f U) - (hU : IsPreconnected U) (h₁x : x ∈ U) (hy : y ∈ U) (h₂x : (hf x h₁x).order ≠ ⊤) : - (hf y hy).order ≠ ⊤ := - (hf.exists_order_ne_top_iff_forall ⟨Set.nonempty_of_mem h₁x, hU⟩).1 (by use ⟨x, h₁x⟩) ⟨y, hy⟩ - section arithmetic include hf in diff --git a/Mathlib/Analysis/Meromorphic/Order.lean b/Mathlib/Analysis/Meromorphic/Order.lean new file mode 100644 index 0000000000000..c979618577aa3 --- /dev/null +++ b/Mathlib/Analysis/Meromorphic/Order.lean @@ -0,0 +1,229 @@ +/- +Copyright (c) 2024 David Loeffler. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: David Loeffler, Stefan Kebekus +-/ +import Mathlib.Analysis.Analytic.Order +import Mathlib.Analysis.Meromorphic.Basic + +/-! +# Orders of Meromorphic Functions + +This file defines the order of a meromorphic function `f` at a point `z₀`, as an element of +`ℤ ∪ {∞}`. + +TODO: Uniformize API between analytic and meromorphic functions +-/ + +open Filter Set WithTop.LinearOrderedAddCommGroup +open scoped Topology + +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] + {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] + +/-! +## Order at a Point: Definition and Characterization + +This file defines the order of a meromorphic analytic function `f` at a point `z₀`, as an element of +`ℤ ∪ {∞}`. + +TODO: Uniformize API between analytic and meromorphic functions +-/ + +/-! +## Order at a Point: Definition and Characterization +-/ + +namespace MeromorphicAt + +/-- The order of a meromorphic function `f` at `z₀`, as an element of `ℤ ∪ {∞}`. + +The order is defined to be `∞` if `f` is identically 0 on a neighbourhood of `z₀`, and otherwise the +unique `n` such that `f` can locally be written as `f z = (z - z₀) ^ n • g z`, where `g` is analytic +and does not vanish at `z₀`. See `MeromorphicAt.order_eq_top_iff` and +`MeromorphicAt.order_eq_nat_iff` for these equivalences. -/ +noncomputable def order {f : 𝕜 → E} {x : 𝕜} (hf : MeromorphicAt f x) : WithTop ℤ := + (hf.choose_spec.order.map (↑· : ℕ → ℤ)) - hf.choose + +/-- The order of a meromorphic function `f` at a `z₀` is infinity iff `f` vanishes locally around +`z₀`. -/ +lemma order_eq_top_iff {f : 𝕜 → E} {x : 𝕜} (hf : MeromorphicAt f x) : + hf.order = ⊤ ↔ ∀ᶠ z in 𝓝[≠] x, f z = 0 := by + unfold order + by_cases h : hf.choose_spec.order = ⊤ + · rw [h, ENat.map_top, ← WithTop.coe_natCast, + top_sub, eq_self, true_iff, eventually_nhdsWithin_iff] + rw [AnalyticAt.order_eq_top_iff] at h + filter_upwards [h] with z hf hz + rwa [smul_eq_zero_iff_right <| pow_ne_zero _ (sub_ne_zero.mpr hz)] at hf + · obtain ⟨m, hm⟩ := ENat.ne_top_iff_exists.mp h + simp only [← hm, ENat.map_coe, WithTop.coe_natCast, sub_eq_top_iff, WithTop.natCast_ne_top, + or_self, false_iff] + contrapose! h + rw [AnalyticAt.order_eq_top_iff] + rw [← hf.choose_spec.frequently_eq_iff_eventually_eq analyticAt_const] + apply Eventually.frequently + filter_upwards [h] with z hfz + rw [hfz, smul_zero] + +/-- The order of a meromorphic function `f` at `z₀` equals an integer `n` iff `f` can locally be +written as `f z = (z - z₀) ^ n • g z`, where `g` is analytic and does not vanish at `z₀`. -/ +lemma order_eq_int_iff {f : 𝕜 → E} {x : 𝕜} (hf : MeromorphicAt f x) (n : ℤ) : hf.order = n ↔ + ∃ g : 𝕜 → E, AnalyticAt 𝕜 g x ∧ g x ≠ 0 ∧ ∀ᶠ z in 𝓝[≠] x, f z = (z - x) ^ n • g z := by + unfold order + by_cases h : hf.choose_spec.order = ⊤ + · rw [h, ENat.map_top, ← WithTop.coe_natCast, top_sub, + eq_false_intro WithTop.top_ne_coe, false_iff] + rw [AnalyticAt.order_eq_top_iff] at h + refine fun ⟨g, hg_an, hg_ne, hg_eq⟩ ↦ hg_ne ?_ + apply EventuallyEq.eq_of_nhds + rw [EventuallyEq, ← AnalyticAt.frequently_eq_iff_eventually_eq hg_an analyticAt_const] + apply Eventually.frequently + rw [eventually_nhdsWithin_iff] at hg_eq ⊢ + filter_upwards [h, hg_eq] with z hfz hfz_eq hz + rwa [hfz_eq hz, ← mul_smul, smul_eq_zero_iff_right] at hfz + exact mul_ne_zero (pow_ne_zero _ (sub_ne_zero.mpr hz)) (zpow_ne_zero _ (sub_ne_zero.mpr hz)) + · obtain ⟨m, h⟩ := ENat.ne_top_iff_exists.mp h + rw [← h, ENat.map_coe, ← WithTop.coe_natCast, ← coe_sub, WithTop.coe_inj] + obtain ⟨g, hg_an, hg_ne, hg_eq⟩ := (AnalyticAt.order_eq_nat_iff _ _).mp h.symm + replace hg_eq : ∀ᶠ (z : 𝕜) in 𝓝[≠] x, f z = (z - x) ^ (↑m - ↑hf.choose : ℤ) • g z := by + rw [eventually_nhdsWithin_iff] + filter_upwards [hg_eq] with z hg_eq hz + rwa [← smul_right_inj <| zpow_ne_zero _ (sub_ne_zero.mpr hz), ← mul_smul, + ← zpow_add₀ (sub_ne_zero.mpr hz), ← add_sub_assoc, add_sub_cancel_left, zpow_natCast, + zpow_natCast] + exact ⟨fun h ↦ ⟨g, hg_an, hg_ne, h ▸ hg_eq⟩, + AnalyticAt.unique_eventuallyEq_zpow_smul_nonzero ⟨g, hg_an, hg_ne, hg_eq⟩⟩ + +/-- Compatibility of notions of `order` for analytic and meromorphic functions. -/ +lemma _root_.AnalyticAt.meromorphicAt_order {f : 𝕜 → E} {x : 𝕜} (hf : AnalyticAt 𝕜 f x) : + hf.meromorphicAt.order = hf.order.map (↑) := by + rcases eq_or_ne hf.order ⊤ with ho | ho + · rw [ho, ENat.map_top, order_eq_top_iff] + exact (hf.order_eq_top_iff.mp ho).filter_mono nhdsWithin_le_nhds + · obtain ⟨n, hn⟩ := ENat.ne_top_iff_exists.mp ho + simp_rw [← hn, ENat.map_coe, order_eq_int_iff, zpow_natCast] + rcases (hf.order_eq_nat_iff _).mp hn.symm with ⟨g, h1, h2, h3⟩ + exact ⟨g, h1, h2, h3.filter_mono nhdsWithin_le_nhds⟩ + +/-! +## Order at a Point: Behaviour under Ring Operations + +We establish additivity of the order under multiplication and taking powers. + +TODO: Behaviour under Addition/Subtraction. API unification with analytic functions +-/ + +/-- The order is additive when multiplying scalar-valued and vector-valued meromorphic functions. -/ +theorem order_smul {f : 𝕜 → 𝕜} {g : 𝕜 → E} {x : 𝕜} + (hf : MeromorphicAt f x) (hg : MeromorphicAt g x) : + (hf.smul hg).order = hf.order + hg.order := by + -- Trivial cases: one of the functions vanishes around z₀ + cases' h₂f : hf.order with m h₂f + · simp only [top_add, order_eq_top_iff] at h₂f ⊢ + filter_upwards [h₂f] with z hz using by simp [hz] + cases' h₂g : hg.order with n h₂f + · simp only [add_top, order_eq_top_iff] at h₂g ⊢ + filter_upwards [h₂g] with z hz using by simp [hz] + -- Non-trivial case: both functions do not vanish around z₀ + rw [← WithTop.coe_add, order_eq_int_iff] + obtain ⟨F, h₁F, h₂F, h₃F⟩ := (hf.order_eq_int_iff _).1 h₂f + obtain ⟨G, h₁G, h₂G, h₃G⟩ := (hg.order_eq_int_iff _).1 h₂g + use F • G, h₁F.smul h₁G, by simp [h₂F, h₂G] + filter_upwards [self_mem_nhdsWithin, h₃F, h₃G] with a ha hfa hga + simp [hfa, hga, smul_comm (F a), zpow_add₀ (sub_ne_zero.mpr ha), mul_smul] + +/-- The order is additive when multiplying meromorphic functions. -/ +theorem order_mul {f g : 𝕜 → 𝕜} {x : 𝕜} (hf : MeromorphicAt f x) (hg : MeromorphicAt g x) : + (hf.mul hg).order = hf.order + hg.order := + hf.order_smul hg + +end MeromorphicAt + +/-! +## Level Sets of the Order Function + +TODO: Prove that the set where an analytic function has order in [1,∞) is discrete within its domain +of meromorphy. +-/ + +namespace MeromorphicOn + +variable {f : 𝕜 → E} {U : Set 𝕜} (hf : MeromorphicOn f U) + +/-- The set where a meromorphic function has infinite order is clopen in its domain of meromorphy. +-/ +theorem isClopen_setOf_order_eq_top : IsClopen { u : U | (hf u.1 u.2).order = ⊤ } := by + constructor + · rw [← isOpen_compl_iff, isOpen_iff_forall_mem_open] + intro z hz + rcases (hf z.1 z.2).eventually_eq_zero_or_eventually_ne_zero with h | h + · -- Case: f is locally zero in a punctured neighborhood of z + rw [← (hf z.1 z.2).order_eq_top_iff] at h + tauto + · -- Case: f is locally nonzero in a punctured neighborhood of z + obtain ⟨t', h₁t', h₂t', h₃t'⟩ := eventually_nhds_iff.1 (eventually_nhdsWithin_iff.1 h) + use Subtype.val ⁻¹' t' + constructor + · intro w hw + simp only [mem_compl_iff, mem_setOf_eq] + by_cases h₁w : w = z + · rwa [h₁w] + · rw [MeromorphicAt.order_eq_top_iff, not_eventually] + apply Filter.Eventually.frequently + rw [eventually_nhdsWithin_iff, eventually_nhds_iff] + use t' \ {z.1}, fun y h₁y h₂y ↦ h₁t' y h₁y.1 h₁y.2, h₂t'.sdiff isClosed_singleton, hw, + mem_singleton_iff.not.2 (Subtype.coe_ne_coe.mpr h₁w) + · exact ⟨isOpen_induced h₂t', h₃t'⟩ + · apply isOpen_iff_forall_mem_open.mpr + intro z hz + conv => + arg 1; intro; left; right; arg 1; intro + rw [MeromorphicAt.order_eq_top_iff, eventually_nhdsWithin_iff, eventually_nhds_iff] + simp only [mem_setOf_eq] at hz + rw [MeromorphicAt.order_eq_top_iff, eventually_nhdsWithin_iff, eventually_nhds_iff] at hz + obtain ⟨t', h₁t', h₂t', h₃t'⟩ := hz + use Subtype.val ⁻¹' t' + simp only [mem_compl_iff, mem_singleton_iff, isOpen_induced h₂t', mem_preimage, + h₃t', and_self, and_true] + intro w hw + simp only [mem_setOf_eq] + -- Trivial case: w = z + by_cases h₁w : w = z + · rw [h₁w] + tauto + -- Nontrivial case: w ≠ z + use t' \ {z.1}, fun y h₁y _ ↦ h₁t' y (mem_of_mem_diff h₁y) (mem_of_mem_inter_right h₁y) + constructor + · exact h₂t'.sdiff isClosed_singleton + · apply (mem_diff w).1 + exact ⟨hw, mem_singleton_iff.not.1 (Subtype.coe_ne_coe.2 h₁w)⟩ + +/-- On a connected set, there exists a point where a meromorphic function `f` has finite order iff +`f` has finite order at every point. -/ +theorem exists_order_ne_top_iff_forall (hU : IsConnected U) : + (∃ u : U, (hf u u.2).order ≠ ⊤) ↔ (∀ u : U, (hf u u.2).order ≠ ⊤) := by + constructor + · intro h₂f + have := isPreconnected_iff_preconnectedSpace.1 hU.isPreconnected + rcases isClopen_iff.1 hf.isClopen_setOf_order_eq_top with h | h + · intro u + have : u ∉ (∅ : Set U) := by exact fun a => a + rw [← h] at this + tauto + · obtain ⟨u, hU⟩ := h₂f + have : u ∈ univ := by trivial + rw [← h] at this + tauto + · intro h₂f + obtain ⟨v, hv⟩ := hU.nonempty + use ⟨v, hv⟩, h₂f ⟨v, hv⟩ + +/-- On a preconnected set, a meromorphic function has finite order at one point if it has finite +order at another point. -/ +theorem order_ne_top_of_isPreconnected {x y : 𝕜} (hU : IsPreconnected U) (h₁x : x ∈ U) (hy : y ∈ U) + (h₂x : (hf x h₁x).order ≠ ⊤) : + (hf y hy).order ≠ ⊤ := + (hf.exists_order_ne_top_iff_forall ⟨nonempty_of_mem h₁x, hU⟩).1 (by use ⟨x, h₁x⟩) ⟨y, hy⟩ + +end MeromorphicOn From 79b481d4f1305a1799cee060afffd272e28e018c Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 5 Feb 2025 04:55:41 +0000 Subject: [PATCH 085/103] chore: remove @[simp] when the discr_key is a lambda (#21395) This PR removes `@[simp]` from all the lemma with a lambda as the #discr_tree_simp_key. These @[simp] annotations were not used anywhere in Mathlib, and are potentially expensive as they will fire anytime the simp target is a lambda. See [zulip](https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/bad.20simp.20discrimination.20tree.20keys/near/497258784), and thanks for @JovanGerb and @kbuzzard for diagnosing. --- Mathlib/Data/Fin/VecNotation.lean | 1 - MathlibTest/matrix.lean | 15 +++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Mathlib/Data/Fin/VecNotation.lean b/Mathlib/Data/Fin/VecNotation.lean index 9e242fbf4e9e3..4871ceea06886 100644 --- a/Mathlib/Data/Fin/VecNotation.lean +++ b/Mathlib/Data/Fin/VecNotation.lean @@ -143,7 +143,6 @@ theorem tail_cons (x : α) (u : Fin m → α) : vecTail (vecCons x u) = u := by ext simp [vecTail] -@[simp] theorem empty_val' {n' : Type*} (j : n') : (fun i => (![] : Fin 0 → n' → α) i j) = ![] := empty_eq _ diff --git a/MathlibTest/matrix.lean b/MathlibTest/matrix.lean index 36e1a2a9d1c9a..a211705fd1c96 100644 --- a/MathlibTest/matrix.lean +++ b/MathlibTest/matrix.lean @@ -148,13 +148,12 @@ 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.succ_eq_add_one, Nat.reduceAdd, - Fin.isValue, 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, 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.val_eq_zero, zero_add, pow_one, cons_val_succ, neg_mul, - Fin.succ_succAbove_zero, Finset.sum_neg_distrib, Finset.sum_const, Finset.card_singleton, - one_smul] + simp only [det_succ_row_zero, Nat.succ_eq_add_one, Nat.reduceAdd, Fin.isValue, of_apply, + cons_val', cons_val_fin_one, cons_val_zero, det_unique, Fin.default_eq_zero, submatrix_apply, + 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.val_eq_zero, + zero_add, pow_one, cons_val_succ, neg_mul, Fin.succ_succAbove_zero, Finset.sum_neg_distrib, + Finset.sum_const, Finset.card_singleton, one_smul] ring example {α : Type _} [CommRing α] {a b c d e f g h i : α} : @@ -162,7 +161,7 @@ example {α : Type _} [CommRing α] {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.succ_eq_add_one, Nat.reduceAdd, Fin.isValue, of_apply, - cons_val', empty_val', cons_val_fin_one, cons_val_zero, submatrix_apply, Fin.succ_zero_eq_one, + cons_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, From 61e40897aa7abbbddb25430786fb959935a7efb1 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 5 Feb 2025 05:32:07 +0000 Subject: [PATCH 086/103] chore: cleanup porting notes in TuringMachine (#20821) Many `local notation`s were added during porting. To my eye, they don't improve readability at all, but if others disagree we can do something else. However, if you don't like this PR, please either resolve the porting notes alternately, or at least let me know how you would like it done (possibly just deleting them). --- Mathlib/Computability/TuringMachine.lean | 325 ++++++++++------------- 1 file changed, 141 insertions(+), 184 deletions(-) diff --git a/Mathlib/Computability/TuringMachine.lean b/Mathlib/Computability/TuringMachine.lean index 423c7c3acaf78..fe75a14a3281a 100644 --- a/Mathlib/Computability/TuringMachine.lean +++ b/Mathlib/Computability/TuringMachine.lean @@ -326,9 +326,7 @@ inductive Stmt | move : Dir → Stmt | write : Γ → Stmt -local notation "Stmt₀" => Stmt Γ -- Porting note (https://github.com/leanprover-community/mathlib4/issues/10750): added this to clean up types. - -instance Stmt.inhabited [Inhabited Γ] : Inhabited Stmt₀ := +instance Stmt.inhabited [Inhabited Γ] : Inhabited (Stmt Γ) := ⟨Stmt.write default⟩ /-- A Post-Turing machine with symbol type `Γ` and label type `Λ` @@ -342,11 +340,9 @@ instance Stmt.inhabited [Inhabited Γ] : Inhabited Stmt₀ := the initial state. -/ @[nolint unusedArguments] -- this is a deliberate addition, see comment def Machine [Inhabited Λ] := - Λ → Γ → Option (Λ × Stmt₀) - -local notation "Machine₀" => Machine Γ Λ -- Porting note (https://github.com/leanprover-community/mathlib4/issues/10750): added this to clean up types. + Λ → Γ → Option (Λ × (Stmt Γ)) -instance Machine.inhabited [Inhabited Λ] : Inhabited Machine₀ := by +instance Machine.inhabited [Inhabited Λ] : Inhabited (Machine Γ Λ) := by unfold Machine; infer_instance /-- The configuration state of a Turing machine during operation @@ -360,32 +356,30 @@ structure Cfg [Inhabited Γ] where /-- The current state of the tape: current symbol, left and right parts. -/ Tape : Tape Γ -local notation "Cfg₀" => Cfg Γ Λ -- Porting note (https://github.com/leanprover-community/mathlib4/issues/10750): added this to clean up types. - variable {Γ Λ} variable [Inhabited Λ] section variable [Inhabited Γ] -instance Cfg.inhabited : Inhabited Cfg₀ := ⟨⟨default, default⟩⟩ +instance Cfg.inhabited : Inhabited (Cfg Γ Λ) := ⟨⟨default, default⟩⟩ /-- Execution semantics of the Turing machine. -/ -def step (M : Machine₀) : Cfg₀ → Option Cfg₀ := +def step (M : Machine Γ Λ) : Cfg Γ Λ → Option (Cfg Γ Λ) := fun ⟨q, T⟩ ↦ (M q T.1).map fun ⟨q', a⟩ ↦ ⟨q', match a with | Stmt.move d => T.move d | Stmt.write a => T.write a⟩ /-- The statement `Reaches M s₁ s₂` means that `s₂` is obtained starting from `s₁` after a finite number of steps from `s₂`. -/ -def Reaches (M : Machine₀) : Cfg₀ → Cfg₀ → Prop := ReflTransGen fun a b ↦ b ∈ step M a +def Reaches (M : Machine Γ Λ) : Cfg Γ Λ → Cfg Γ Λ → Prop := ReflTransGen fun a b ↦ b ∈ step M a /-- The initial configuration. -/ -def init (l : List Γ) : Cfg₀ := ⟨default, Tape.mk₁ l⟩ +def init (l : List Γ) : Cfg Γ Λ := ⟨default, Tape.mk₁ l⟩ /-- Evaluate a Turing machine on initial input to a final state, if it terminates. -/ -def eval (M : Machine₀) (l : List Γ) : Part (ListBlank Γ) := +def eval (M : Machine Γ Λ) (l : List Γ) : Part (ListBlank Γ) := (Turing.eval (step M) (init l)).map fun c ↦ c.Tape.right₀ /-- The raw definition of a Turing machine does not require that @@ -395,18 +389,18 @@ def eval (M : Machine₀) (l : List Γ) : Part (ListBlank Γ) := finite subset of their states. We say that a set `S ⊆ Λ` supports a Turing machine `M` if `S` is closed under the transition function and contains the initial state. -/ -def Supports (M : Machine₀) (S : Set Λ) := +def Supports (M : Machine Γ Λ) (S : Set Λ) := default ∈ S ∧ ∀ {q a q' s}, (q', s) ∈ M q a → q ∈ S → q' ∈ S -theorem step_supports (M : Machine₀) {S : Set Λ} (ss : Supports M S) : - ∀ {c c' : Cfg₀}, c' ∈ step M c → c.q ∈ S → c'.q ∈ S := by +theorem step_supports (M : Machine Γ Λ) {S : Set Λ} (ss : Supports M S) : + ∀ {c c' : Cfg Γ Λ}, c' ∈ step M c → c.q ∈ S → c'.q ∈ S := by intro ⟨q, T⟩ c' h₁ h₂ rcases Option.map_eq_some'.1 h₁ with ⟨⟨q', a⟩, h, rfl⟩ exact ss.2 h h₂ end -theorem univ_supports (M : Machine₀) : Supports M Set.univ := by +theorem univ_supports (M : Machine Γ Λ) : Supports M Set.univ := by constructor <;> intros <;> apply Set.mem_univ end @@ -532,11 +526,9 @@ inductive Stmt | goto : (Γ → σ → Λ) → Stmt | halt : Stmt -local notation "Stmt₁" => Stmt Γ Λ σ -- Porting note (https://github.com/leanprover-community/mathlib4/issues/10750): added this to clean up types. - open Stmt -instance Stmt.inhabited : Inhabited Stmt₁ := ⟨halt⟩ +instance Stmt.inhabited : Inhabited (Stmt Γ Λ σ) := ⟨halt⟩ /-- The configuration of a TM1 machine is given by the currently evaluating statement, the variable store value, and the tape. -/ @@ -548,15 +540,13 @@ structure Cfg [Inhabited Γ] where /-- The current state of the tape -/ Tape : Tape Γ -local notation "Cfg₁" => Cfg Γ Λ σ -- Porting note (https://github.com/leanprover-community/mathlib4/issues/10750): added this to clean up types. - -instance Cfg.inhabited [Inhabited Γ] [Inhabited σ] : Inhabited Cfg₁ := +instance Cfg.inhabited [Inhabited Γ] [Inhabited σ] : Inhabited (Cfg Γ Λ σ) := ⟨⟨default, default, default⟩⟩ variable {Γ Λ σ} /-- The semantics of TM1 evaluation. -/ -def stepAux [Inhabited Γ] : Stmt₁ → σ → Tape Γ → Cfg₁ +def stepAux [Inhabited Γ] : Stmt Γ Λ σ → σ → Tape Γ → Cfg Γ Λ σ | move d q, v, T => stepAux q v (T.move d) | write a q, v, T => stepAux q v (T.write (a T.1 v)) | load s q, v, T => stepAux q (s T.1 v) T @@ -565,13 +555,13 @@ def stepAux [Inhabited Γ] : Stmt₁ → σ → Tape Γ → Cfg₁ | halt, v, T => ⟨none, v, T⟩ /-- The state transition function. -/ -def step [Inhabited Γ] (M : Λ → Stmt₁) : Cfg₁ → Option Cfg₁ +def step [Inhabited Γ] (M : Λ → Stmt Γ Λ σ) : Cfg Γ Λ σ → Option (Cfg Γ Λ σ) | ⟨none, _, _⟩ => none | ⟨some l, v, T⟩ => some (stepAux (M l) v T) /-- A set `S` of labels supports the statement `q` if all the `goto` statements in `q` refer only to other functions in `S`. -/ -def SupportsStmt (S : Finset Λ) : Stmt₁ → Prop +def SupportsStmt (S : Finset Λ) : Stmt Γ Λ σ → Prop | move _ q => SupportsStmt S q | write _ q => SupportsStmt S q | load _ q => SupportsStmt S q @@ -581,17 +571,17 @@ def SupportsStmt (S : Finset Λ) : Stmt₁ → Prop open scoped Classical in /-- The subterm closure of a statement. -/ -noncomputable def stmts₁ : Stmt₁ → Finset Stmt₁ +noncomputable def stmts₁ : Stmt Γ Λ σ → Finset (Stmt Γ Λ σ) | Q@(move _ q) => insert Q (stmts₁ q) | Q@(write _ q) => insert Q (stmts₁ q) | Q@(load _ q) => insert Q (stmts₁ q) | Q@(branch _ q₁ q₂) => insert Q (stmts₁ q₁ ∪ stmts₁ q₂) | Q => {Q} -theorem stmts₁_self {q : Stmt₁} : q ∈ stmts₁ q := by +theorem stmts₁_self {q : Stmt Γ Λ σ} : q ∈ stmts₁ q := by cases q <;> simp only [stmts₁, Finset.mem_insert_self, Finset.mem_singleton_self] -theorem stmts₁_trans {q₁ q₂ : Stmt₁} : q₁ ∈ stmts₁ q₂ → stmts₁ q₁ ⊆ stmts₁ q₂ := by +theorem stmts₁_trans {q₁ q₂ : Stmt Γ Λ σ} : q₁ ∈ stmts₁ q₂ → stmts₁ q₁ ⊆ stmts₁ q₂ := by classical intro h₁₂ q₀ h₀₁ induction q₂ with ( @@ -610,7 +600,7 @@ theorem stmts₁_trans {q₁ q₂ : Stmt₁} : q₁ ∈ stmts₁ q₂ → stmts · exact h₀₁ · exact Finset.mem_insert_of_mem (IH h₁₂) -theorem stmts₁_supportsStmt_mono {S : Finset Λ} {q₁ q₂ : Stmt₁} (h : q₁ ∈ stmts₁ q₂) +theorem stmts₁_supportsStmt_mono {S : Finset Λ} {q₁ q₂ : Stmt Γ Λ σ} (h : q₁ ∈ stmts₁ q₂) (hs : SupportsStmt S q₂) : SupportsStmt S q₁ := by induction q₂ with simp only [stmts₁, SupportsStmt, Finset.mem_insert, Finset.mem_union, Finset.mem_singleton] @@ -623,10 +613,10 @@ theorem stmts₁_supportsStmt_mono {S : Finset Λ} {q₁ q₂ : Stmt₁} (h : q open scoped Classical in /-- The set of all statements in a Turing machine, plus one extra value `none` representing the halt state. This is used in the TM1 to TM0 reduction. -/ -noncomputable def stmts (M : Λ → Stmt₁) (S : Finset Λ) : Finset (Option Stmt₁) := +noncomputable def stmts (M : Λ → Stmt Γ Λ σ) (S : Finset Λ) : Finset (Option (Stmt Γ Λ σ)) := Finset.insertNone (S.biUnion fun q ↦ stmts₁ (M q)) -theorem stmts_trans {M : Λ → Stmt₁} {S : Finset Λ} {q₁ q₂ : Stmt₁} (h₁ : q₁ ∈ stmts₁ q₂) : +theorem stmts_trans {M : Λ → Stmt Γ Λ σ} {S : Finset Λ} {q₁ q₂ : Stmt Γ Λ σ} (h₁ : q₁ ∈ stmts₁ q₂) : some q₂ ∈ stmts M S → some q₁ ∈ stmts M S := by simp only [stmts, Finset.mem_insertNone, Finset.mem_biUnion, Option.mem_def, Option.some.injEq, forall_eq', exists_imp, and_imp] @@ -637,19 +627,19 @@ variable [Inhabited Λ] /-- A set `S` of labels supports machine `M` if all the `goto` statements in the functions in `S` refer only to other functions in `S`. -/ -def Supports (M : Λ → Stmt₁) (S : Finset Λ) := +def Supports (M : Λ → Stmt Γ Λ σ) (S : Finset Λ) := default ∈ S ∧ ∀ q ∈ S, SupportsStmt S (M q) -theorem stmts_supportsStmt {M : Λ → Stmt₁} {S : Finset Λ} {q : Stmt₁} (ss : Supports M S) : - some q ∈ stmts M S → SupportsStmt S q := by +theorem stmts_supportsStmt {M : Λ → Stmt Γ Λ σ} {S : Finset Λ} {q : Stmt Γ Λ σ} + (ss : Supports M S) : some q ∈ stmts M S → SupportsStmt S q := by simp only [stmts, Finset.mem_insertNone, Finset.mem_biUnion, Option.mem_def, Option.some.injEq, forall_eq', exists_imp, and_imp] exact fun l ls h ↦ stmts₁_supportsStmt_mono h (ss.2 _ ls) variable [Inhabited Γ] -theorem step_supports (M : Λ → Stmt₁) {S : Finset Λ} (ss : Supports M S) : - ∀ {c c' : Cfg₁}, c' ∈ step M c → c.l ∈ Finset.insertNone S → c'.l ∈ Finset.insertNone S +theorem step_supports (M : Λ → Stmt Γ Λ σ) {S : Finset Λ} (ss : Supports M S) : + ∀ {c c' : Cfg Γ Λ σ}, c' ∈ step M c → c.l ∈ Finset.insertNone S → c'.l ∈ Finset.insertNone S | ⟨some l₁, v, T⟩, c', h₁, h₂ => by replace h₂ := ss.2 _ (Finset.some_mem_insertNone.1 h₂) simp only [step, Option.mem_def, Option.some.injEq] at h₁; subst c' @@ -666,12 +656,12 @@ variable [Inhabited σ] /-- The initial state, given a finite input that is placed on the tape starting at the TM head and going to the right. -/ -def init (l : List Γ) : Cfg₁ := +def init (l : List Γ) : Cfg Γ Λ σ := ⟨some default, default, Tape.mk₁ l⟩ /-- Evaluate a TM to completion, resulting in an output list on the tape (with an indeterminate number of blanks on the end). -/ -def eval (M : Λ → Stmt₁) (l : List Γ) : Part (ListBlank Γ) := +def eval (M : Λ → Stmt Γ Λ σ) (l : List Γ) : Part (ListBlank Γ) := (Turing.eval (step M) (init l)).map fun c ↦ c.Tape.right₀ end @@ -703,15 +693,8 @@ variable {Γ : Type*} variable {Λ : Type*} [Inhabited Λ] variable {σ : Type*} [Inhabited σ] -local notation "Stmt₁" => TM1.Stmt Γ Λ σ - -local notation "Cfg₁" => TM1.Cfg Γ Λ σ - -local notation "Stmt₀" => TM0.Stmt Γ - -variable (M : Λ → TM1.Stmt Γ Λ σ) -- Porting note: Unfolded `Stmt₁`. +variable (M : Λ → TM1.Stmt Γ Λ σ) --- Porting note: `Inhabited`s are not necessary, but `M` is necessary. set_option linter.unusedVariables false in /-- The base machine state space is a pair of an `Option Stmt₁` representing the current program to be executed, or `none` for the halt state, and a `σ` which is the local state (stored in the TM, @@ -720,11 +703,9 @@ for a finitely supported TM1 machine and a finite type `σ`, only finitely many reachable. -/ @[nolint unusedArguments] -- We need the M assumption def Λ' (M : Λ → TM1.Stmt Γ Λ σ) := - Option Stmt₁ × σ + Option (TM1.Stmt Γ Λ σ) × σ -local notation "Λ'₁₀" => Λ' M -- Porting note (https://github.com/leanprover-community/mathlib4/issues/10750): added this to clean up types. - -instance : Inhabited Λ'₁₀ := +instance : Inhabited (Λ' M) := ⟨(some (M default), default)⟩ open TM0.Stmt @@ -733,7 +714,7 @@ open TM0.Stmt `Stmt₁` is the TM1 statement to translate, with local state `v : σ`. We evaluate all regular instructions recursively until we reach either a `move` or `write` command, or a `goto`; in the latter case we emit a dummy `write s` step and transition to the new target location. -/ -def trAux (s : Γ) : Stmt₁ → σ → Λ'₁₀ × Stmt₀ +def trAux (s : Γ) : TM1.Stmt Γ Λ σ → σ → Λ' M × TM0.Stmt Γ | TM1.Stmt.move d q, v => ((some q, v), move d) | TM1.Stmt.write a q, v => ((some q, v), write (a s v)) | TM1.Stmt.load a q, v => trAux s q (a s v) @@ -741,19 +722,18 @@ def trAux (s : Γ) : Stmt₁ → σ → Λ'₁₀ × Stmt₀ | TM1.Stmt.goto l, v => ((some (M (l s v)), v), write s) | TM1.Stmt.halt, v => ((none, v), write s) -local notation "Cfg₁₀" => TM0.Cfg Γ Λ'₁₀ - /-- The translated TM0 machine (given the TM1 machine input). -/ -def tr : TM0.Machine Γ Λ'₁₀ +def tr : TM0.Machine Γ (Λ' M) | (none, _), _ => none | (some q, v), s => some (trAux M s q v) /-- Translate configurations from TM1 to TM0. -/ -def trCfg [Inhabited Γ] : Cfg₁ → Cfg₁₀ +def trCfg [Inhabited Γ] : TM1.Cfg Γ Λ σ → TM0.Cfg Γ (Λ' M) | ⟨l, v, T⟩ => ⟨(l.map M, v), T⟩ theorem tr_respects [Inhabited Γ] : - Respects (TM1.step M) (TM0.step (tr M)) fun (c₁ : Cfg₁) (c₂ : Cfg₁₀) ↦ trCfg M c₁ = c₂ := + Respects (TM1.step M) (TM0.step (tr M)) + fun (c₁ : TM1.Cfg Γ Λ σ) (c₂ : TM0.Cfg Γ (Λ' M)) ↦ trCfg M c₁ = c₂ := fun_respects.2 fun ⟨l₁, v, T⟩ ↦ by cases' l₁ with l₁; · exact rfl simp only [trCfg, TM1.step, FRespects, Option.map] @@ -778,7 +758,7 @@ variable [Fintype σ] /-- Given a finite set of accessible `Λ` machine states, there is a finite set of accessible machine states in the target (even though the type `Λ'` is infinite). -/ -noncomputable def trStmts (S : Finset Λ) : Finset Λ'₁₀ := +noncomputable def trStmts (S : Finset Λ) : Finset (Λ' M) := (TM1.stmts M S) ×ˢ Finset.univ attribute [local simp] TM1.stmts₁_self @@ -871,55 +851,48 @@ theorem exists_enc_dec [Inhabited Γ] [Finite Γ] : let enc := H.setValue default (Vector.replicate n false) exact ⟨_, enc, Function.invFun enc, H.setValue_eq _ _, Function.leftInverse_invFun enc.2⟩ -variable {Λ σ : Type*} - -local notation "Stmt₁" => Stmt Γ Λ σ - -local notation "Cfg₁" => Cfg Γ Λ σ +variable (Γ) +variable (Λ σ : Type*) /-- The configuration state of the TM. -/ inductive Λ' | normal : Λ → Λ' - | write : Γ → Stmt₁ → Λ' + | write : Γ → Stmt Γ Λ σ → Λ' -local notation "Λ'₁" => @Λ' Γ Λ σ -- Porting note (https://github.com/leanprover-community/mathlib4/issues/10750): added this to clean up types. +variable {Γ Λ σ} -instance [Inhabited Λ] : Inhabited Λ'₁ := +instance [Inhabited Λ] : Inhabited (Λ' Γ Λ σ) := ⟨Λ'.normal default⟩ -local notation "Stmt'₁" => Stmt Bool Λ'₁ σ - -local notation "Cfg'₁" => Cfg Bool Λ'₁ σ - /-- Read a vector of length `n` from the tape. -/ -def readAux : ∀ n, (List.Vector Bool n → Stmt'₁) → Stmt'₁ +def readAux : ∀ n, (List.Vector Bool n → Stmt Bool (Λ' Γ Λ σ) σ) → Stmt Bool (Λ' Γ Λ σ) σ | 0, f => f Vector.nil | i + 1, f => Stmt.branch (fun a _ ↦ a) (Stmt.move Dir.right <| readAux i fun v ↦ f (true ::ᵥ v)) (Stmt.move Dir.right <| readAux i fun v ↦ f (false ::ᵥ v)) -variable {n : ℕ} (enc : Γ → List.Vector Bool n) (dec : List.Vector Bool n → Γ) +variable (n : ℕ) (enc : Γ → List.Vector Bool n) (dec : List.Vector Bool n → Γ) /-- A move left or right corresponds to `n` moves across the super-cell. -/ -def move (d : Dir) (q : Stmt'₁) : Stmt'₁ := +def move (d : Dir) (q : Stmt Bool (Λ' Γ Λ σ) σ) : Stmt Bool (Λ' Γ Λ σ) σ := (Stmt.move d)^[n] q -local notation "moveₙ" => @move Γ Λ σ n -- Porting note (https://github.com/leanprover-community/mathlib4/issues/10750): added this to clean up types. +variable {n} /-- To read a symbol from the tape, we use `readAux` to traverse the symbol, then return to the original position with `n` moves to the left. -/ -def read (f : Γ → Stmt'₁) : Stmt'₁ := - readAux n fun v ↦ moveₙ Dir.left <| f (dec v) +def read (f : Γ → Stmt Bool (Λ' Γ Λ σ) σ) : Stmt Bool (Λ' Γ Λ σ) σ := + readAux n fun v ↦ move n Dir.left <| f (dec v) /-- Write a list of bools on the tape. -/ -def write : List Bool → Stmt'₁ → Stmt'₁ +def write : List Bool → Stmt Bool (Λ' Γ Λ σ) σ → Stmt Bool (Λ' Γ Λ σ) σ | [], q => q | a :: l, q => (Stmt.write fun _ _ ↦ a) <| Stmt.move Dir.right <| write l q /-- Translate a normal instruction. For the `write` command, we use a `goto` indirection so that we can access the current value of the tape. -/ -def trNormal : Stmt₁ → Stmt'₁ - | Stmt.move d q => moveₙ d <| trNormal q +def trNormal : Stmt Γ Λ σ → Stmt Bool (Λ' Γ Λ σ) σ + | Stmt.move d q => move n d <| trNormal q | Stmt.write f q => read dec fun a ↦ Stmt.goto fun _ s ↦ Λ'.write (f a s) q | Stmt.load f q => read dec fun a ↦ (Stmt.load fun _ s ↦ f a s) <| trNormal q | Stmt.branch p q₁ q₂ => @@ -927,34 +900,35 @@ def trNormal : Stmt₁ → Stmt'₁ | Stmt.goto l => read dec fun a ↦ Stmt.goto fun _ s ↦ Λ'.normal (l a s) | Stmt.halt => Stmt.halt -theorem stepAux_move (d : Dir) (q : Stmt'₁) (v : σ) (T : Tape Bool) : - stepAux (moveₙ d q) v T = stepAux q v ((Tape.move d)^[n] T) := by +theorem stepAux_move (d : Dir) (q : Stmt Bool (Λ' Γ Λ σ) σ) (v : σ) (T : Tape Bool) : + stepAux (move n d q) v T = stepAux q v ((Tape.move d)^[n] T) := by suffices ∀ i, stepAux ((Stmt.move d)^[i] q) v T = stepAux q v ((Tape.move d)^[i] T) from this n intro i; induction' i with i IH generalizing T; · rfl rw [iterate_succ', iterate_succ] simp only [stepAux, Function.comp_apply] rw [IH] -theorem supportsStmt_move {S : Finset Λ'₁} {d : Dir} {q : Stmt'₁} : - SupportsStmt S (moveₙ d q) = SupportsStmt S q := by +theorem supportsStmt_move {S : Finset (Λ' Γ Λ σ)} {d : Dir} {q : Stmt Bool (Λ' Γ Λ σ) σ} : + SupportsStmt S (move n d q) = SupportsStmt S q := by suffices ∀ {i}, SupportsStmt S ((Stmt.move d)^[i] q) = _ from this intro i; induction i generalizing q <;> simp only [*, iterate]; rfl -theorem supportsStmt_write {S : Finset Λ'₁} {l : List Bool} {q : Stmt'₁} : +theorem supportsStmt_write {S : Finset (Λ' Γ Λ σ)} {l : List Bool} {q : Stmt Bool (Λ' Γ Λ σ) σ} : SupportsStmt S (write l q) = SupportsStmt S q := by induction' l with _ l IH <;> simp only [write, SupportsStmt, *] -theorem supportsStmt_read {S : Finset Λ'₁} : - ∀ {f : Γ → Stmt'₁}, (∀ a, SupportsStmt S (f a)) → SupportsStmt S (read dec f) := +theorem supportsStmt_read {S : Finset (Λ' Γ Λ σ)} : + ∀ {f : Γ → Stmt Bool (Λ' Γ Λ σ) σ}, (∀ a, SupportsStmt S (f a)) → + SupportsStmt S (read dec f) := suffices - ∀ (i) (f : List.Vector Bool i → Stmt'₁), + ∀ (i) (f : List.Vector Bool i → Stmt Bool (Λ' Γ Λ σ) σ), (∀ v, SupportsStmt S (f v)) → SupportsStmt S (readAux i f) from fun hf ↦ this n _ (by intro; simp only [supportsStmt_move, hf]) fun i f hf ↦ by induction' i with i IH; · exact hf _ constructor <;> apply IH <;> intro <;> apply hf -variable (M : Λ → TM1.Stmt Γ Λ σ) -- Porting note: Unfolded `Stmt₁`. +variable (M : Λ → TM1.Stmt Γ Λ σ) section variable [Inhabited Γ] (enc0 : enc default = Vector.replicate n false) @@ -979,12 +953,12 @@ theorem trTape_mk' (L R : ListBlank Γ) : trTape enc0 (Tape.mk' L R) = trTape' e end /-- The top level program. -/ -def tr : Λ'₁ → Stmt'₁ +def tr : Λ' Γ Λ σ → Stmt Bool (Λ' Γ Λ σ) σ | Λ'.normal l => trNormal dec (M l) - | Λ'.write a q => write (enc a).toList <| moveₙ Dir.left <| trNormal dec q + | Λ'.write a q => write (enc a).toList <| move n Dir.left <| trNormal dec q /-- The machine configuration translation. -/ -def trCfg : Cfg₁ → Cfg'₁ +def trCfg : Cfg Γ Λ σ → Cfg Bool (Λ' Γ Λ σ) σ | ⟨l, v, T⟩ => ⟨l.map Λ'.normal, v, trTape enc0 T⟩ variable {enc} @@ -1017,7 +991,7 @@ theorem trTape'_move_right (L R : ListBlank Γ) : · rfl rw [iterate_succ_apply, iterate_succ_apply', Tape.move_left_right, IH] -theorem stepAux_write (q : Stmt'₁) (v : σ) (a b : Γ) (L R : ListBlank Γ) : +theorem stepAux_write (q : Stmt Bool (Λ' Γ Λ σ) σ) (v : σ) (a b : Γ) (L R : ListBlank Γ) : stepAux (write (enc a).toList q) v (trTape' enc0 L (ListBlank.cons b R)) = stepAux q v (trTape' enc0 (ListBlank.cons a L) R) := by simp only [trTape', ListBlank.cons_flatMap] @@ -1038,7 +1012,7 @@ theorem stepAux_write (q : Stmt'₁) (v : σ) (a b : Γ) (L R : ListBlank Γ) : variable (encdec : ∀ a, dec (enc a) = a) include encdec -theorem stepAux_read (f : Γ → Stmt'₁) (v : σ) (L R : ListBlank Γ) : +theorem stepAux_read (f : Γ → Stmt Bool (Λ' Γ Λ σ) σ) (v : σ) (L R : ListBlank Γ) : stepAux (read dec f) v (trTape' enc0 L R) = stepAux (f R.head) v (trTape' enc0 L R) := by suffices ∀ f, stepAux (readAux n f) v (trTape' enc0 L R) = stepAux (f (enc R.head)) v (trTape' enc0 (L.cons R.head) R.tail) by @@ -1051,7 +1025,6 @@ theorem stepAux_read (f : Γ → Stmt'₁) (v : σ) (L R : ListBlank Γ) : stepAux (readAux i f) v (Tape.mk' (ListBlank.append l₁ L') (ListBlank.append l₂ R')) = stepAux (f ⟨l₂, h⟩) v (Tape.mk' (ListBlank.append (l₂.reverseAux l₁) L') R') by intro f - -- Porting note: Here was `change`. exact this n f (L.flatMap (fun x => (enc x).1.reverse) _) (R.flatMap (fun x => (enc x).1) _) [] _ (enc a).2 clear f L a R @@ -1117,7 +1090,7 @@ variable [Fintype Γ] open scoped Classical in /-- The set of accessible `Λ'.write` machine states. -/ -noncomputable def writes : Stmt₁ → Finset Λ'₁ +noncomputable def writes : Stmt Γ Λ σ → Finset (Λ' Γ Λ σ) | Stmt.move _ q => writes q | Stmt.write _ q => (Finset.univ.image fun a ↦ Λ'.write a q) ∪ writes q | Stmt.load _ q => writes q @@ -1128,7 +1101,7 @@ noncomputable def writes : Stmt₁ → Finset Λ'₁ open scoped Classical in /-- The set of accessible machine states, assuming that the input machine is supported on `S`, are the normal states embedded from `S`, plus all write states accessible from these states. -/ -noncomputable def trSupp (S : Finset Λ) : Finset Λ'₁ := +noncomputable def trSupp (S : Finset Λ) : Finset (Λ' Γ Λ σ) := S.biUnion fun l ↦ insert (Λ'.normal l) (writes (M l)) open scoped Classical in @@ -1195,8 +1168,8 @@ unreachable branch). namespace TM0to1 -variable {Γ : Type*} [Inhabited Γ] -variable {Λ : Type*} [Inhabited Λ] +variable (Γ : Type*) [Inhabited Γ] +variable (Λ : Type*) [Inhabited Λ] /-- The machine states for a TM1 emulating a TM0 machine. States of the TM0 machine are embedded as `normal q` states, but the actual operation is split into two parts, a jump to `act s q` @@ -1205,23 +1178,17 @@ inductive Λ' | normal : Λ → Λ' | act : TM0.Stmt Γ → Λ → Λ' -local notation "Λ'₁" => @Λ' Γ Λ -- Porting note (https://github.com/leanprover-community/mathlib4/issues/10750): added this to clean up types. +variable {Γ Λ} -instance : Inhabited Λ'₁ := +instance : Inhabited (Λ' Γ Λ) := ⟨Λ'.normal default⟩ -local notation "Cfg₀" => TM0.Cfg Γ Λ - -local notation "Stmt₁" => TM1.Stmt Γ Λ'₁ Unit - -local notation "Cfg₁" => TM1.Cfg Γ Λ'₁ Unit - variable (M : TM0.Machine Γ Λ) open TM1.Stmt /-- The program. -/ -def tr : Λ'₁ → Stmt₁ +def tr : Λ' Γ Λ → TM1.Stmt Γ (Λ' Γ Λ) Unit | Λ'.normal q => branch (fun a _ ↦ (M q a).isNone) halt <| goto fun a _ ↦ match M q a with @@ -1231,7 +1198,7 @@ def tr : Λ'₁ → Stmt₁ | Λ'.act (TM0.Stmt.write a) q => (write fun _ _ ↦ a) <| goto fun _ _ ↦ Λ'.normal q /-- The configuration translation. -/ -def trCfg : Cfg₀ → Cfg₁ +def trCfg : TM0.Cfg Γ Λ → TM1.Cfg Γ (Λ' Γ Λ) Unit | ⟨q, T⟩ => ⟨cond (M q T.1).isSome (some (Λ'.normal q)) none, (), T⟩ theorem tr_respects : Respects (TM0.step M) (TM1.step (tr M)) fun a b ↦ trCfg M a = b := @@ -1240,7 +1207,7 @@ theorem tr_respects : Respects (TM0.step M) (TM1.step (tr M)) fun a b ↦ trCfg · simp only [TM0.step, trCfg, e]; exact Eq.refl none cases' val with q' s simp only [FRespects, TM0.step, trCfg, e, Option.isSome, cond, Option.map_some'] - revert e -- Porting note: Added this so that `e` doesn't get into the `match`. + revert e have : TM1.step (tr M) ⟨some (Λ'.act s q'), (), T⟩ = some ⟨some (Λ'.normal q'), (), match s with | TM0.Stmt.move d => T.move d | TM0.Stmt.write a => T.write a⟩ := by @@ -1316,11 +1283,9 @@ inductive Stmt | goto : (σ → Λ) → Stmt | halt : Stmt -local notation "Stmt₂" => Stmt Γ Λ σ -- Porting note (https://github.com/leanprover-community/mathlib4/issues/10750): added this to clean up types. - open Stmt -instance Stmt.inhabited : Inhabited Stmt₂ := +instance Stmt.inhabited : Inhabited (Stmt Γ Λ σ) := ⟨halt⟩ /-- A configuration in the TM2 model is a label (or `none` for the halt state), the state of @@ -1334,9 +1299,7 @@ structure Cfg where /-- The (finite) collection of internal stacks -/ stk : ∀ k, List (Γ k) -local notation "Cfg₂" => Cfg Γ Λ σ -- Porting note (https://github.com/leanprover-community/mathlib4/issues/10750): added this to clean up types. - -instance Cfg.inhabited [Inhabited σ] : Inhabited Cfg₂ := +instance Cfg.inhabited [Inhabited σ] : Inhabited (Cfg Γ Λ σ) := ⟨⟨default, default, default⟩⟩ variable {Γ Λ σ} @@ -1345,7 +1308,7 @@ section variable [DecidableEq K] /-- The step function for the TM2 model. -/ -def stepAux : Stmt₂ → σ → (∀ k, List (Γ k)) → Cfg₂ +def stepAux : Stmt Γ Λ σ → σ → (∀ k, List (Γ k)) → Cfg Γ Λ σ | push k f q, v, S => stepAux q v (update S k (f v :: S k)) | peek k f q, v, S => stepAux q (f v (S k).head?) S | pop k f q, v, S => stepAux q (f v (S k).head?) (update S k (S k).tail) @@ -1355,7 +1318,7 @@ def stepAux : Stmt₂ → σ → (∀ k, List (Γ k)) → Cfg₂ | halt, v, S => ⟨none, v, S⟩ /-- The step function for the TM2 model. -/ -def step (M : Λ → Stmt₂) : Cfg₂ → Option Cfg₂ +def step (M : Λ → Stmt Γ Λ σ) : Cfg Γ Λ σ → Option (Cfg Γ Λ σ) | ⟨none, _, _⟩ => none | ⟨some l, v, S⟩ => some (stepAux (M l) v S) @@ -1363,13 +1326,13 @@ attribute [simp] stepAux.eq_1 stepAux.eq_2 stepAux.eq_3 stepAux.eq_4 stepAux.eq_5 stepAux.eq_6 stepAux.eq_7 step.eq_1 step.eq_2 /-- The (reflexive) reachability relation for the TM2 model. -/ -def Reaches (M : Λ → Stmt₂) : Cfg₂ → Cfg₂ → Prop := +def Reaches (M : Λ → Stmt Γ Λ σ) : Cfg Γ Λ σ → Cfg Γ Λ σ → Prop := ReflTransGen fun a b ↦ b ∈ step M a end /-- Given a set `S` of states, `SupportsStmt S q` means that `q` only jumps to states in `S`. -/ -def SupportsStmt (S : Finset Λ) : Stmt₂ → Prop +def SupportsStmt (S : Finset Λ) : Stmt Γ Λ σ → Prop | push _ _ q => SupportsStmt S q | peek _ _ q => SupportsStmt S q | pop _ _ q => SupportsStmt S q @@ -1382,7 +1345,7 @@ section open scoped Classical in /-- The set of subtree statements in a statement. -/ -noncomputable def stmts₁ : Stmt₂ → Finset Stmt₂ +noncomputable def stmts₁ : Stmt Γ Λ σ → Finset (Stmt Γ Λ σ) | Q@(push _ _ q) => insert Q (stmts₁ q) | Q@(peek _ _ q) => insert Q (stmts₁ q) | Q@(pop _ _ q) => insert Q (stmts₁ q) @@ -1391,10 +1354,10 @@ noncomputable def stmts₁ : Stmt₂ → Finset Stmt₂ | Q@(goto _) => {Q} | Q@halt => {Q} -theorem stmts₁_self {q : Stmt₂} : q ∈ stmts₁ q := by +theorem stmts₁_self {q : Stmt Γ Λ σ} : q ∈ stmts₁ q := by cases q <;> simp only [Finset.mem_insert_self, Finset.mem_singleton_self, stmts₁] -theorem stmts₁_trans {q₁ q₂ : Stmt₂} : q₁ ∈ stmts₁ q₂ → stmts₁ q₁ ⊆ stmts₁ q₂ := by +theorem stmts₁_trans {q₁ q₂ : Stmt Γ Λ σ} : q₁ ∈ stmts₁ q₂ → stmts₁ q₁ ⊆ stmts₁ q₂ := by classical intro h₁₂ q₀ h₀₁ induction q₂ with ( @@ -1414,7 +1377,7 @@ theorem stmts₁_trans {q₁ q₂ : Stmt₂} : q₁ ∈ stmts₁ q₂ → stmts exact h₀₁ · exact Finset.mem_insert_of_mem (IH h₁₂) -theorem stmts₁_supportsStmt_mono {S : Finset Λ} {q₁ q₂ : Stmt₂} (h : q₁ ∈ stmts₁ q₂) +theorem stmts₁_supportsStmt_mono {S : Finset Λ} {q₁ q₂ : Stmt Γ Λ σ} (h : q₁ ∈ stmts₁ q₂) (hs : SupportsStmt S q₂) : SupportsStmt S q₁ := by induction q₂ with simp only [stmts₁, SupportsStmt, Finset.mem_insert, Finset.mem_union, Finset.mem_singleton] @@ -1426,10 +1389,10 @@ theorem stmts₁_supportsStmt_mono {S : Finset Λ} {q₁ q₂ : Stmt₂} (h : q open scoped Classical in /-- The set of statements accessible from initial set `S` of labels. -/ -noncomputable def stmts (M : Λ → Stmt₂) (S : Finset Λ) : Finset (Option Stmt₂) := +noncomputable def stmts (M : Λ → Stmt Γ Λ σ) (S : Finset Λ) : Finset (Option (Stmt Γ Λ σ)) := Finset.insertNone (S.biUnion fun q ↦ stmts₁ (M q)) -theorem stmts_trans {M : Λ → Stmt₂} {S : Finset Λ} {q₁ q₂ : Stmt₂} (h₁ : q₁ ∈ stmts₁ q₂) : +theorem stmts_trans {M : Λ → Stmt Γ Λ σ} {S : Finset Λ} {q₁ q₂ : Stmt Γ Λ σ} (h₁ : q₁ ∈ stmts₁ q₂) : some q₂ ∈ stmts M S → some q₁ ∈ stmts M S := by simp only [stmts, Finset.mem_insertNone, Finset.mem_biUnion, Option.mem_def, Option.some.injEq, forall_eq', exists_imp, and_imp] @@ -1441,19 +1404,19 @@ variable [Inhabited Λ] /-- Given a TM2 machine `M` and a set `S` of states, `Supports M S` means that all states in `S` jump only to other states in `S`. -/ -def Supports (M : Λ → Stmt₂) (S : Finset Λ) := +def Supports (M : Λ → Stmt Γ Λ σ) (S : Finset Λ) := default ∈ S ∧ ∀ q ∈ S, SupportsStmt S (M q) -theorem stmts_supportsStmt {M : Λ → Stmt₂} {S : Finset Λ} {q : Stmt₂} (ss : Supports M S) : - some q ∈ stmts M S → SupportsStmt S q := by +theorem stmts_supportsStmt {M : Λ → Stmt Γ Λ σ} {S : Finset Λ} {q : Stmt Γ Λ σ} + (ss : Supports M S) : some q ∈ stmts M S → SupportsStmt S q := by simp only [stmts, Finset.mem_insertNone, Finset.mem_biUnion, Option.mem_def, Option.some.injEq, forall_eq', exists_imp, and_imp] exact fun l ls h ↦ stmts₁_supportsStmt_mono h (ss.2 _ ls) variable [DecidableEq K] -theorem step_supports (M : Λ → Stmt₂) {S : Finset Λ} (ss : Supports M S) : - ∀ {c c' : Cfg₂}, c' ∈ step M c → c.l ∈ Finset.insertNone S → c'.l ∈ Finset.insertNone S +theorem step_supports (M : Λ → Stmt Γ Λ σ) {S : Finset Λ} (ss : Supports M S) : + ∀ {c c' : Cfg Γ Λ σ}, c' ∈ step M c → c.l ∈ Finset.insertNone S → c'.l ∈ Finset.insertNone S | ⟨some l₁, v, T⟩, c', h₁, h₂ => by replace h₂ := ss.2 _ (Finset.some_mem_insertNone.1 h₂) simp only [step, Option.mem_def, Option.some.injEq] at h₁; subst c' @@ -1469,11 +1432,11 @@ theorem step_supports (M : Λ → Stmt₂) {S : Finset Λ} (ss : Supports M S) : variable [Inhabited σ] /-- The initial state of the TM2 model. The input is provided on a designated stack. -/ -def init (k : K) (L : List (Γ k)) : Cfg₂ := +def init (k : K) (L : List (Γ k)) : Cfg Γ Λ σ := ⟨some default, default, update (fun _ ↦ []) k L⟩ /-- Evaluates a TM2 program to completion, with the output on the same stack as the input. -/ -def eval (M : Λ → Stmt₂) (k : K) (L : List (Γ k)) : Part (List (Γ k)) := +def eval (M : Λ → Stmt Γ Λ σ) (k : K) (L : List (Γ k)) : Part (List (Γ k)) := (Turing.eval (step M) (init k L)).map fun c ↦ c.stk k end TM2 @@ -1527,31 +1490,26 @@ theorem stk_nth_val {K : Type*} {Γ : K → Type*} {L : ListBlank (∀ k, Option List.getI_eq_iget_getElem?, List.getElem?_map] cases S.reverse[n]? <;> rfl -variable {K : Type*} -variable {Γ : K → Type*} +variable (K : Type*) +variable (Γ : K → Type*) variable {Λ σ : Type*} -local notation "Stmt₂" => TM2.Stmt Γ Λ σ - -local notation "Cfg₂" => TM2.Cfg Γ Λ σ - --- Porting note: `DecidableEq K` is not necessary. /-- The alphabet of the TM2 simulator on TM1 is a marker for the stack bottom, plus a vector of stack elements for each stack, or none if the stack does not extend this far. -/ def Γ' := Bool × ∀ k, Option (Γ k) -local notation "Γ'₂₁" => @Γ' K Γ -- Porting note (https://github.com/leanprover-community/mathlib4/issues/10750): added this to clean up types. +variable {K Γ} -instance Γ'.inhabited : Inhabited Γ'₂₁ := +instance Γ'.inhabited : Inhabited (Γ' K Γ) := ⟨⟨false, fun _ ↦ none⟩⟩ -instance Γ'.fintype [DecidableEq K] [Fintype K] [∀ k, Fintype (Γ k)] : Fintype Γ'₂₁ := +instance Γ'.fintype [DecidableEq K] [Fintype K] [∀ k, Fintype (Γ k)] : Fintype (Γ' K Γ) := instFintypeProd _ _ /-- The bottom marker is fixed throughout the calculation, so we use the `addBottom` function to express the program state in terms of a tape with only the stacks themselves. -/ -def addBottom (L : ListBlank (∀ k, Option (Γ k))) : ListBlank Γ'₂₁ := +def addBottom (L : ListBlank (∀ k, Option (Γ k))) : ListBlank (Γ' K Γ) := ListBlank.cons (true, L.head) (L.tail.map ⟨Prod.mk false, rfl⟩) theorem addBottom_map (L : ListBlank (∀ k, Option (Γ k))) : @@ -1579,6 +1537,7 @@ theorem addBottom_nth_succ_fst (L : ListBlank (∀ k, Option (Γ k))) (n : ℕ) theorem addBottom_head_fst (L : ListBlank (∀ k, Option (Γ k))) : (addBottom L).head.1 = true := by rw [addBottom, ListBlank.head_cons] +variable (K Γ σ) in /-- A stack action is a command that interacts with the top of a stack. Our default position is at the bottom of all the stacks, so we have to hold on to this action while going to the end to modify the stack. -/ @@ -1587,30 +1546,27 @@ inductive StAct (k : K) | peek : (σ → Option (Γ k) → σ) → StAct k | pop : (σ → Option (Γ k) → σ) → StAct k -local notation "StAct₂" => @StAct K Γ σ -- Porting note (https://github.com/leanprover-community/mathlib4/issues/10750): added this to clean up types. - -instance StAct.inhabited {k : K} : Inhabited (StAct₂ k) := +instance StAct.inhabited {k : K} : Inhabited (StAct K Γ σ k) := ⟨StAct.peek fun s _ ↦ s⟩ section open StAct --- Porting note: `Inhabited Γ` is not necessary. /-- The TM2 statement corresponding to a stack action. -/ -def stRun {k : K} : StAct₂ k → Stmt₂ → Stmt₂ +def stRun {k : K} : StAct K Γ σ k → TM2.Stmt Γ Λ σ → TM2.Stmt Γ Λ σ | push f => TM2.Stmt.push k f | peek f => TM2.Stmt.peek k f | pop f => TM2.Stmt.pop k f /-- The effect of a stack action on the local variables, given the value of the stack. -/ -def stVar {k : K} (v : σ) (l : List (Γ k)) : StAct₂ k → σ +def stVar {k : K} (v : σ) (l : List (Γ k)) : StAct K Γ σ k → σ | push _ => v | peek f => f v l.head? | pop f => f v l.head? /-- The effect of a stack action on the stack. -/ -def stWrite {k : K} (v : σ) (l : List (Γ k)) : StAct₂ k → List (Γ k) +def stWrite {k : K} (v : σ) (l : List (Γ k)) : StAct K Γ σ k → List (Γ k) | push f => f v :: l | peek _ => l | pop _ => l.tail @@ -1619,7 +1575,8 @@ def stWrite {k : K} (v : σ) (l : List (Γ k)) : StAct₂ k → List (Γ k) of the stack, and all other actions, which do not. This is a modified recursor which lumps the stack actions into one. -/ @[elab_as_elim] -def stmtStRec.{l} {C : Stmt₂ → Sort l} (H₁ : ∀ (k) (s : StAct₂ k) (q) (_ : C q), C (stRun s q)) +def stmtStRec.{l} {C : TM2.Stmt Γ Λ σ → Sort l} (H₁ : ∀ (k) (s : StAct K Γ σ k) (q) + (_ : C q), C (stRun s q)) (H₂ : ∀ (a q) (_ : C q), C (TM2.Stmt.load a q)) (H₃ : ∀ (p q₁ q₂) (_ : C q₁) (_ : C q₂), C (TM2.Stmt.branch p q₁ q₂)) (H₄ : ∀ l, C (TM2.Stmt.goto l)) (H₅ : C TM2.Stmt.halt) : ∀ n, C n @@ -1631,30 +1588,29 @@ def stmtStRec.{l} {C : Stmt₂ → Sort l} (H₁ : ∀ (k) (s : StAct₂ k) (q) | TM2.Stmt.goto _ => H₄ _ | TM2.Stmt.halt => H₅ -theorem supports_run (S : Finset Λ) {k : K} (s : StAct₂ k) (q : Stmt₂) : +theorem supports_run (S : Finset Λ) {k : K} (s : StAct K Γ σ k) (q : TM2.Stmt Γ Λ σ) : TM2.SupportsStmt S (stRun s q) ↔ TM2.SupportsStmt S q := by cases s <;> rfl end +variable (K Γ Λ σ) + /-- The machine states of the TM2 emulator. We can either be in a normal state when waiting for the next TM2 action, or we can be in the "go" and "return" states to go to the top of the stack and return to the bottom, respectively. -/ inductive Λ' | normal : Λ → Λ' - | go (k : K) : StAct₂ k → Stmt₂ → Λ' - | ret : Stmt₂ → Λ' + | go (k : K) : StAct K Γ σ k → TM2.Stmt Γ Λ σ → Λ' + | ret : TM2.Stmt Γ Λ σ → Λ' -local notation "Λ'₂₁" => @Λ' K Γ Λ σ -- Porting note (https://github.com/leanprover-community/mathlib4/issues/10750): added this to clean up types. +variable {K Γ Λ σ} open Λ' -instance Λ'.inhabited [Inhabited Λ] : Inhabited Λ'₂₁ := +instance Λ'.inhabited [Inhabited Λ] : Inhabited (Λ' K Γ Λ σ) := ⟨normal default⟩ -local notation "Stmt₂₁" => TM1.Stmt Γ'₂₁ Λ'₂₁ σ -local notation "Cfg₂₁" => TM1.Cfg Γ'₂₁ Λ'₂₁ σ - open TM1.Stmt section @@ -1662,7 +1618,8 @@ variable [DecidableEq K] /-- The program corresponding to state transitions at the end of a stack. Here we start out just after the top of the stack, and should end just after the new top of the stack. -/ -def trStAct {k : K} (q : Stmt₂₁) : StAct₂ k → Stmt₂₁ +def trStAct {k : K} (q : TM1.Stmt (Γ' K Γ) (Λ' K Γ Λ σ) σ) : + StAct K Γ σ k → TM1.Stmt (Γ' K Γ) (Λ' K Γ Λ σ) σ | StAct.push f => (write fun a s ↦ (a.1, update a.2 k <| some <| f s)) <| move Dir.right q | StAct.peek f => move Dir.left <| (load fun a s ↦ f s (a.2 k)) <| move Dir.right q | StAct.pop f => @@ -1672,11 +1629,11 @@ def trStAct {k : K} (q : Stmt₂₁) : StAct₂ k → Stmt₂₁ /-- The initial state for the TM2 emulator, given an initial TM2 state. All stacks start out empty except for the input stack, and the stack bottom mark is set at the head. -/ -def trInit (k : K) (L : List (Γ k)) : List Γ'₂₁ := - let L' : List Γ'₂₁ := L.reverse.map fun a ↦ (false, update (fun _ ↦ none) k (some a)) +def trInit (k : K) (L : List (Γ k)) : List (Γ' K Γ) := + let L' : List (Γ' K Γ) := L.reverse.map fun a ↦ (false, update (fun _ ↦ none) k (some a)) (true, L'.headI.2) :: L'.tail -theorem step_run {k : K} (q : Stmt₂) (v : σ) (S : ∀ k, List (Γ k)) : ∀ s : StAct₂ k, +theorem step_run {k : K} (q : TM2.Stmt Γ Λ σ) (v : σ) (S : ∀ k, List (Γ k)) : ∀ s : StAct K Γ σ k, TM2.stepAux (stRun s q) v S = TM2.stepAux q (stVar v (S k) s) (update S k (stWrite v (S k) s)) | StAct.push _ => rfl | StAct.peek f => by unfold stWrite; rw [Function.update_eq_self]; rfl @@ -1687,7 +1644,7 @@ end /-- The translation of TM2 statements to TM1 statements. regular actions have direct equivalents, but stack actions are deferred by going to the corresponding `go` state, so that we can find the appropriate stack top. -/ -def trNormal : Stmt₂ → Stmt₂₁ +def trNormal : TM2.Stmt Γ Λ σ → TM1.Stmt (Γ' K Γ) (Λ' K Γ Λ σ) σ | TM2.Stmt.push k f q => goto fun _ _ ↦ go k (StAct.push f) q | TM2.Stmt.peek k f q => goto fun _ _ ↦ go k (StAct.peek f) q | TM2.Stmt.pop k f q => goto fun _ _ ↦ go k (StAct.pop f) q @@ -1696,7 +1653,7 @@ def trNormal : Stmt₂ → Stmt₂₁ | TM2.Stmt.goto l => goto fun _ s ↦ normal (l s) | TM2.Stmt.halt => halt -theorem trNormal_run {k : K} (s : StAct₂ k) (q : Stmt₂) : +theorem trNormal_run {k : K} (s : StAct K Γ σ k) (q : TM2.Stmt Γ Λ σ) : trNormal (stRun s q) = goto fun _ _ ↦ go k s q := by cases s <;> rfl @@ -1704,7 +1661,7 @@ section open scoped Classical in /-- The set of machine states accessible from an initial TM2 statement. -/ -noncomputable def trStmts₁ : Stmt₂ → Finset Λ'₂₁ +noncomputable def trStmts₁ : TM2.Stmt Γ Λ σ → Finset (Λ' K Γ Λ σ) | TM2.Stmt.push k f q => {go k (StAct.push f) q, ret q} ∪ trStmts₁ q | TM2.Stmt.peek k f q => {go k (StAct.peek f) q, ret q} ∪ trStmts₁ q | TM2.Stmt.pop k f q => {go k (StAct.pop f) q, ret q} ∪ trStmts₁ q @@ -1712,14 +1669,14 @@ noncomputable def trStmts₁ : Stmt₂ → Finset Λ'₂₁ | TM2.Stmt.branch _ q₁ q₂ => trStmts₁ q₁ ∪ trStmts₁ q₂ | _ => ∅ +theorem trStmts₁_run {k : K} {s : StAct K Γ σ k} {q : TM2.Stmt Γ Λ σ} : open scoped Classical in -theorem trStmts₁_run {k : K} {s : StAct₂ k} {q : Stmt₂} : trStmts₁ (stRun s q) = {go k s q, ret q} ∪ trStmts₁ q := by cases s <;> simp only [trStmts₁, stRun] -theorem tr_respects_aux₂ [DecidableEq K] {k : K} {q : Stmt₂₁} {v : σ} {S : ∀ k, List (Γ k)} - {L : ListBlank (∀ k, Option (Γ k))} - (hL : ∀ k, L.map (proj k) = ListBlank.mk ((S k).map some).reverse) (o : StAct₂ k) : +theorem tr_respects_aux₂ [DecidableEq K] {k : K} {q : TM1.Stmt (Γ' K Γ) (Λ' K Γ Λ σ) σ} {v : σ} + {S : ∀ k, List (Γ k)} {L : ListBlank (∀ k, Option (Γ k))} + (hL : ∀ k, L.map (proj k) = ListBlank.mk ((S k).map some).reverse) (o : StAct K Γ σ k) : let v' := stVar v (S k) o let Sk' := stWrite v (S k) o let S' := update S k Sk' @@ -1730,13 +1687,14 @@ theorem tr_respects_aux₂ [DecidableEq K] {k : K} {q : Stmt₂₁} {v : σ} {S TM1.stepAux q v' ((Tape.move Dir.right)^[(S' k).length] (Tape.mk' ∅ (addBottom L'))) := by simp only [Function.update_self]; cases o with simp only [stWrite, stVar, trStAct, TM1.stepAux] | push f => - have := Tape.write_move_right_n fun a : Γ' ↦ (a.1, update a.2 k (some (f v))) + have := Tape.write_move_right_n fun a : Γ' K Γ ↦ (a.1, update a.2 k (some (f v))) refine ⟨_, fun k' ↦ ?_, by -- Porting note: `rw [...]` to `erw [...]; rfl`. -- https://github.com/leanprover-community/mathlib4/issues/5164 - erw [Tape.move_right_n_head, List.length, Tape.mk'_nth_nat, this, - addBottom_modifyNth fun a ↦ update a k (some (f v)), Nat.add_one, iterate_succ'] + rw [Tape.move_right_n_head, List.length, Tape.mk'_nth_nat, this] + erw [addBottom_modifyNth fun a ↦ update a k (some (f v))] + rw [Nat.add_one, iterate_succ'] rfl⟩ refine ListBlank.ext fun i ↦ ?_ rw [ListBlank.nth_map, ListBlank.nth_modifyNth, proj, PointedMap.mk_val] @@ -1776,7 +1734,7 @@ theorem tr_respects_aux₂ [DecidableEq K] {k : K} {q : Stmt₂₁} {v : σ} {S ⟨_, fun k' ↦ ?_, by erw [List.length_cons, Tape.move_right_n_head, Tape.mk'_nth_nat, addBottom_nth_succ_fst, cond_false, iterate_succ', Function.comp, Tape.move_right_left, Tape.move_right_n_head, - Tape.mk'_nth_nat, Tape.write_move_right_n fun a : Γ' ↦ (a.1, update a.2 k none), + Tape.mk'_nth_nat, Tape.write_move_right_n fun a : Γ' K Γ ↦ (a.1, update a.2 k none), addBottom_modifyNth fun a ↦ update a k none, addBottom_nth_snd, stk_nth_val _ (hL k), e, show (List.cons hd tl).reverse[tl.length]? = some hd by @@ -1804,22 +1762,19 @@ theorem tr_respects_aux₂ [DecidableEq K] {k : K} {q : Stmt₂₁} {v : σ} {S end variable [DecidableEq K] -variable (M : Λ → TM2.Stmt Γ Λ σ) -- Porting note: Unfolded `Stmt₂`. +variable (M : Λ → TM2.Stmt Γ Λ σ) /-- The TM2 emulator machine states written as a TM1 program. This handles the `go` and `ret` states, which shuttle to and from a stack top. -/ -def tr : Λ'₂₁ → Stmt₂₁ +def tr : Λ' K Γ Λ σ → TM1.Stmt (Γ' K Γ) (Λ' K Γ Λ σ) σ | normal q => trNormal (M q) | go k s q => branch (fun a _ ↦ (a.2 k).isNone) (trStAct (goto fun _ _ ↦ ret q) s) (move Dir.right <| goto fun _ _ ↦ go k s q) | ret q => branch (fun a _ ↦ a.1) (trNormal q) (move Dir.left <| goto fun _ _ ↦ ret q) --- Porting note: unknown attribute --- attribute [local pp_using_anonymous_constructor] Turing.TM1.Cfg - /-- The relation between TM2 configurations and TM1 configurations of the TM2 emulator. -/ -inductive TrCfg : Cfg₂ → Cfg₂₁ → Prop +inductive TrCfg : TM2.Cfg Γ Λ σ → TM1.Cfg (Γ' K Γ) (Λ' K Γ Λ σ) σ → Prop | mk {q : Option Λ} {v : σ} {S : ∀ k, List (Γ k)} (L : ListBlank (∀ k, Option (Γ k))) : (∀ k, L.map (proj k) = ListBlank.mk ((S k).map some).reverse) → TrCfg ⟨q, v, S⟩ ⟨q.map normal, v, Tape.mk' ∅ (addBottom L)⟩ @@ -1848,7 +1803,8 @@ theorem tr_respects_aux₃ {q v} {L : ListBlank (∀ k, Option (Γ k))} (n) : Re rfl theorem tr_respects_aux {q v T k} {S : ∀ k, List (Γ k)} - (hT : ∀ k, ListBlank.map (proj k) T = ListBlank.mk ((S k).map some).reverse) (o : StAct₂ k) + (hT : ∀ k, ListBlank.map (proj k) T = ListBlank.mk ((S k).map some).reverse) + (o : StAct K Γ σ k) (IH : ∀ {v : σ} {S : ∀ k : K, List (Γ k)} {T : ListBlank (∀ k, Option (Γ k))}, (∀ k, ListBlank.map (proj k) T = ListBlank.mk ((S k).map some).reverse) → ∃ b, TrCfg (TM2.stepAux q v S) b ∧ @@ -1892,7 +1848,8 @@ theorem tr_respects : Respects (TM2.step M) (TM1.step (tr M)) TrCfg := by section variable [Inhabited Λ] [Inhabited σ] -theorem trCfg_init (k) (L : List (Γ k)) : TrCfg (TM2.init k L) (TM1.init (trInit k L) : Cfg₂₁) := by +theorem trCfg_init (k) (L : List (Γ k)) : TrCfg (TM2.init k L) + (TM1.init (trInit k L) : TM1.Cfg (Γ' K Γ) (Λ' K Γ Λ σ) σ) := by rw [(_ : TM1.init _ = _)] · refine ⟨ListBlank.mk (L.reverse.map fun a ↦ update default k (some a)), fun k' ↦ ?_⟩ refine ListBlank.ext fun i ↦ ?_ @@ -1936,7 +1893,7 @@ variable [Inhabited Λ] open scoped Classical in /-- The support of a set of TM2 states in the TM2 emulator. -/ -noncomputable def trSupp (S : Finset Λ) : Finset Λ'₂₁ := +noncomputable def trSupp (S : Finset Λ) : Finset (Λ' K Γ Λ σ) := S.biUnion fun l ↦ insert (normal l) (trStmts₁ (M l)) open scoped Classical in From 803e276b1534131f153dc0041e499435ca9e27b6 Mon Sep 17 00:00:00 2001 From: Bergschaf Date: Wed, 5 Feb 2025 05:32:08 +0000 Subject: [PATCH 087/103] refactor(Order/CompleteBooleanAlgebra): a complete lattice which is a Heyting algebra is automatically a frame (#21391) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every complete lattice that is a heyting algebra is also a frame. This is because the Heyting implication is the right adjoint to `⊓`, which means that `⊓` now preserves infinite suprema (because it is a left adjoint). --- Mathlib/Data/Fintype/Order.lean | 2 + Mathlib/Order/CompleteBooleanAlgebra.lean | 58 ++++++++++++----------- Mathlib/Order/Copy.lean | 4 -- Mathlib/Order/Heyting/Basic.lean | 7 +++ 4 files changed, 39 insertions(+), 32 deletions(-) diff --git a/Mathlib/Data/Fintype/Order.lean b/Mathlib/Data/Fintype/Order.lean index 67390d4754196..36cb954104962 100644 --- a/Mathlib/Data/Fintype/Order.lean +++ b/Mathlib/Data/Fintype/Order.lean @@ -125,6 +125,8 @@ noncomputable abbrev toCompleteLinearOrder noncomputable abbrev toCompleteBooleanAlgebra [BooleanAlgebra α] : CompleteBooleanAlgebra α where __ := ‹BooleanAlgebra α› __ := Fintype.toCompleteDistribLattice α + inf_sSup_le_iSup_inf _ _ := inf_sSup_eq.le + iInf_sup_le_sup_sInf _ _ := sup_sInf_eq.ge -- See note [reducible non-instances] /-- A finite boolean algebra is complete and atomic. -/ diff --git a/Mathlib/Order/CompleteBooleanAlgebra.lean b/Mathlib/Order/CompleteBooleanAlgebra.lean index 19949f24acf4d..3256e29ddbdc6 100644 --- a/Mathlib/Order/CompleteBooleanAlgebra.lean +++ b/Mathlib/Order/CompleteBooleanAlgebra.lean @@ -6,6 +6,7 @@ Authors: Johannes Hölzl, Yaël Dillies import Mathlib.Order.CompleteLattice import Mathlib.Order.Directed import Mathlib.Logic.Equiv.Set +import Mathlib.Order.GaloisConnection.Basic /-! # Frames, completely distributive lattices and complete Boolean algebras @@ -72,14 +73,20 @@ class Order.Coframe.MinimalAxioms (α : Type u) extends CompleteLattice α where /-- A frame, aka complete Heyting algebra, is a complete lattice whose `⊓` distributes over `⨆`. -/ class Order.Frame (α : Type*) extends CompleteLattice α, HeytingAlgebra α where - /-- `⊓` distributes over `⨆`. -/ - inf_sSup_le_iSup_inf (a : α) (s : Set α) : a ⊓ sSup s ≤ ⨆ b ∈ s, a ⊓ b + +/-- `⊓` distributes over `⨆`. -/ +theorem inf_sSup_eq {α : Type*} [Order.Frame α] {s : Set α} {a : α} : + a ⊓ sSup s = ⨆ b ∈ s, a ⊓ b := + gc_inf_himp.l_sSup /-- A coframe, aka complete Brouwer algebra or complete co-Heyting algebra, is a complete lattice whose `⊔` distributes over `⨅`. -/ class Order.Coframe (α : Type*) extends CompleteLattice α, CoheytingAlgebra α where - /-- `⊔` distributes over `⨅`. -/ - iInf_sup_le_sup_sInf (a : α) (s : Set α) : ⨅ b ∈ s, a ⊔ b ≤ a ⊔ sInf s + +/-- `⊔` distributes over `⨅`. -/ +theorem sup_sInf_eq {α : Type*} [Order.Coframe α] {s : Set α} {a : α} : + a ⊔ sInf s = ⨅ b ∈ s, a ⊔ b:= + gc_sdiff_sup.u_sInf open Order @@ -100,9 +107,6 @@ attribute [nolint docBlame] CompleteDistribLattice.MinimalAxioms.toMinimalAxioms distribute over `⨅` and `⨆`. -/ class CompleteDistribLattice (α : Type*) extends Frame α, Coframe α, BiheytingAlgebra α -/-- In a complete distributive lattice, `⊔` distributes over `⨅`. -/ -add_decl_doc CompleteDistribLattice.iInf_sup_le_sup_sInf - /-- Structure containing the minimal axioms required to check that an order is a completely distributive. Do NOT use, except for implementing `CompletelyDistribLattice` via `CompletelyDistribLattice.ofMinimalAxioms`. @@ -146,7 +150,9 @@ lemma inf_iSup₂_eq {f : ∀ i, κ i → α} (a : α) : (a ⊓ ⨆ i, ⨆ j, f simp only [inf_iSup_eq] /-- The `Order.Frame.MinimalAxioms` element corresponding to a frame. -/ -def of [Frame α] : MinimalAxioms α := { ‹Frame α› with } +def of [Frame α] : MinimalAxioms α where + __ := ‹Frame α› + inf_sSup_le_iSup_inf a s := _root_.inf_sSup_eq.le end MinimalAxioms @@ -182,7 +188,9 @@ lemma sup_iInf₂_eq {f : ∀ i, κ i → α} (a : α) : (a ⊔ ⨅ i, ⨅ j, f simp only [sup_iInf_eq] /-- The `Order.Coframe.MinimalAxioms` element corresponding to a frame. -/ -def of [Coframe α] : MinimalAxioms α := { ‹Coframe α› with } +def of [Coframe α] : MinimalAxioms α where + __ := ‹Coframe α› + iInf_sup_le_sup_sInf a s := _root_.sup_sInf_eq.ge end MinimalAxioms @@ -204,7 +212,10 @@ variable (minAx : MinimalAxioms α) /-- The `CompleteDistribLattice.MinimalAxioms` element corresponding to a complete distrib lattice. -/ -def of [CompleteDistribLattice α] : MinimalAxioms α := { ‹CompleteDistribLattice α› with } +def of [CompleteDistribLattice α] : MinimalAxioms α where + __ := ‹CompleteDistribLattice α› + inf_sSup_le_iSup_inf a s:= inf_sSup_eq.le + iInf_sup_le_sup_sInf a s:= sup_sInf_eq.ge /-- Turn minimal axioms for `CompleteDistribLattice` into minimal axioms for `Order.Frame`. -/ abbrev toFrame : Frame.MinimalAxioms α := minAx.toMinimalAxioms @@ -311,7 +322,6 @@ theorem iSup_iInf_eq [CompletelyDistribLattice α] {f : ∀ a, κ a → α} : instance (priority := 100) CompletelyDistribLattice.toCompleteDistribLattice [CompletelyDistribLattice α] : CompleteDistribLattice α where __ := ‹CompletelyDistribLattice α› - __ := CompleteDistribLattice.ofMinimalAxioms MinimalAxioms.of.toCompleteDistribLattice -- See note [lower instance priority] instance (priority := 100) CompleteLinearOrder.toCompletelyDistribLattice [CompleteLinearOrder α] : @@ -349,10 +359,6 @@ variable [Frame α] {s t : Set α} {a b : α} instance OrderDual.instCoframe : Coframe αᵒᵈ where __ := instCompleteLattice __ := instCoheytingAlgebra - iInf_sup_le_sup_sInf := @Frame.inf_sSup_le_iSup_inf α _ - -theorem inf_sSup_eq : a ⊓ sSup s = ⨆ b ∈ s, a ⊓ b := - (Frame.inf_sSup_le_iSup_inf _ _).antisymm iSup_inf_le_inf_sSup theorem sSup_inf_eq : sSup s ⊓ b = ⨆ a ∈ s, a ⊓ b := by simpa only [inf_comm] using @inf_sSup_eq α _ s b @@ -429,14 +435,10 @@ instance (priority := 100) Frame.toDistribLattice : DistribLattice α := instance Prod.instFrame [Frame α] [Frame β] : Frame (α × β) where __ := instCompleteLattice __ := instHeytingAlgebra - inf_sSup_le_iSup_inf a s := by - simp [Prod.le_def, sSup_eq_iSup, fst_iSup, snd_iSup, fst_iInf, snd_iInf, inf_iSup_eq] instance Pi.instFrame {ι : Type*} {π : ι → Type*} [∀ i, Frame (π i)] : Frame (∀ i, π i) where __ := instCompleteLattice __ := instHeytingAlgebra - inf_sSup_le_iSup_inf a s i := by - simp only [sSup_apply, iSup_apply, inf_apply, inf_iSup_eq, ← iSup_subtype'']; rfl end Frame @@ -447,10 +449,6 @@ variable [Coframe α] {s t : Set α} {a b : α} instance OrderDual.instFrame : Frame αᵒᵈ where __ := instCompleteLattice __ := instHeytingAlgebra - inf_sSup_le_iSup_inf := @Coframe.iInf_sup_le_sup_sInf α _ - -theorem sup_sInf_eq : a ⊔ sInf s = ⨅ b ∈ s, a ⊔ b := - @inf_sSup_eq αᵒᵈ _ _ _ theorem sInf_sup_eq : sInf s ⊔ b = ⨅ a ∈ s, a ⊔ b := @sSup_inf_eq αᵒᵈ _ _ _ @@ -501,14 +499,10 @@ instance (priority := 100) Coframe.toDistribLattice : DistribLattice α where instance Prod.instCoframe [Coframe β] : Coframe (α × β) where __ := instCompleteLattice __ := instCoheytingAlgebra - iInf_sup_le_sup_sInf a s := by - simp [Prod.le_def, sInf_eq_iInf, fst_iSup, snd_iSup, fst_iInf, snd_iInf, sup_iInf_eq] instance Pi.instCoframe {ι : Type*} {π : ι → Type*} [∀ i, Coframe (π i)] : Coframe (∀ i, π i) where __ := instCompleteLattice __ := instCoheytingAlgebra - iInf_sup_le_sup_sInf a s i := by - simp only [sInf_apply, iInf_apply, sup_apply, sup_iInf_eq, ← iInf_subtype'']; rfl end Coframe @@ -577,16 +571,22 @@ instance Prod.instCompleteBooleanAlgebra [CompleteBooleanAlgebra α] [CompleteBo CompleteBooleanAlgebra (α × β) where __ := instBooleanAlgebra __ := instCompleteDistribLattice + inf_sSup_le_iSup_inf _ _ := inf_sSup_eq.le + iInf_sup_le_sup_sInf _ _ := sup_sInf_eq.ge instance Pi.instCompleteBooleanAlgebra {ι : Type*} {π : ι → Type*} [∀ i, CompleteBooleanAlgebra (π i)] : CompleteBooleanAlgebra (∀ i, π i) where __ := instBooleanAlgebra __ := instCompleteDistribLattice + inf_sSup_le_iSup_inf _ _ := inf_sSup_eq.le + iInf_sup_le_sup_sInf _ _ := sup_sInf_eq.ge instance OrderDual.instCompleteBooleanAlgebra [CompleteBooleanAlgebra α] : CompleteBooleanAlgebra αᵒᵈ where __ := instBooleanAlgebra __ := instCompleteDistribLattice + inf_sSup_le_iSup_inf _ _ := inf_sSup_eq.le + iInf_sup_le_sup_sInf _ _ := sup_sInf_eq.ge section CompleteBooleanAlgebra @@ -650,8 +650,10 @@ instance (priority := 100) CompleteAtomicBooleanAlgebra.toCompletelyDistribLatti -- See note [lower instance priority] instance (priority := 100) CompleteAtomicBooleanAlgebra.toCompleteBooleanAlgebra [CompleteAtomicBooleanAlgebra α] : CompleteBooleanAlgebra α where - __ := ‹CompleteAtomicBooleanAlgebra α› __ := CompletelyDistribLattice.toCompleteDistribLattice + __ := ‹CompleteAtomicBooleanAlgebra α› + inf_sSup_le_iSup_inf _ _ := inf_sSup_eq.le + iInf_sup_le_sup_sInf _ _ := sup_sInf_eq.ge instance Prod.instCompleteAtomicBooleanAlgebra [CompleteAtomicBooleanAlgebra α] [CompleteAtomicBooleanAlgebra β] : CompleteAtomicBooleanAlgebra (α × β) where diff --git a/Mathlib/Order/Copy.lean b/Mathlib/Order/Copy.lean index 7e6d798c8101e..ed9a434d81bf5 100644 --- a/Mathlib/Order/Copy.lean +++ b/Mathlib/Order/Copy.lean @@ -194,8 +194,6 @@ def Frame.copy (c : Frame α) (le : α → α → Prop) (eq_le : le = (by infer_ (sInf : Set α → α) (eq_sInf : sInf = (by infer_instance : InfSet α).sInf) : Frame α where toCompleteLattice := CompleteLattice.copy (@Frame.toCompleteLattice α c) le eq_le top eq_top bot eq_bot sup eq_sup inf eq_inf sSup eq_sSup sInf eq_sInf - inf_sSup_le_iSup_inf := fun a s => by - simp [eq_le, eq_sup, eq_inf, eq_sSup, @Order.Frame.inf_sSup_le_iSup_inf α _ a s] __ := HeytingAlgebra.copy (@Frame.toHeytingAlgebra α c) le eq_le top eq_top bot eq_bot sup eq_sup inf eq_inf himp eq_himp compl eq_compl @@ -212,8 +210,6 @@ def Coframe.copy (c : Coframe α) (le : α → α → Prop) (eq_le : le = (by in (sInf : Set α → α) (eq_sInf : sInf = (by infer_instance : InfSet α).sInf) : Coframe α where toCompleteLattice := CompleteLattice.copy (@Coframe.toCompleteLattice α c) le eq_le top eq_top bot eq_bot sup eq_sup inf eq_inf sSup eq_sSup sInf eq_sInf - iInf_sup_le_sup_sInf := fun a s => by - simp [eq_le, eq_sup, eq_inf, eq_sInf, @Order.Coframe.iInf_sup_le_sup_sInf α _ a s] __ := CoheytingAlgebra.copy (@Coframe.toCoheytingAlgebra α c) le eq_le top eq_top bot eq_bot sup eq_sup inf eq_inf sdiff eq_sdiff hnot eq_hnot diff --git a/Mathlib/Order/Heyting/Basic.lean b/Mathlib/Order/Heyting/Basic.lean index ac82b721c02fd..3637b9cc6eddc 100644 --- a/Mathlib/Order/Heyting/Basic.lean +++ b/Mathlib/Order/Heyting/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ import Mathlib.Order.PropInstances +import Mathlib.Order.GaloisConnection.Defs /-! # Heyting algebras @@ -350,6 +351,9 @@ theorem himp_triangle (a b c : α) : (a ⇨ b) ⊓ (b ⇨ c) ≤ a ⇨ c := by theorem himp_inf_himp_cancel (hba : b ≤ a) (hcb : c ≤ b) : (a ⇨ b) ⊓ (b ⇨ c) = a ⇨ c := (himp_triangle _ _ _).antisymm <| le_inf (himp_le_himp_left hcb) (himp_le_himp_right hba) +theorem gc_inf_himp : GaloisConnection (a ⊓ ·) (a ⇨ ·) := + fun _ _ ↦ Iff.symm le_himp_iff' + -- See note [lower instance priority] instance (priority := 100) GeneralizedHeytingAlgebra.toDistribLattice : DistribLattice α := DistribLattice.ofInfSupLe fun a b c => by @@ -567,6 +571,9 @@ theorem inf_sdiff_sup_left : a \ c ⊓ (a ⊔ b) = a \ c := theorem inf_sdiff_sup_right : a \ c ⊓ (b ⊔ a) = a \ c := inf_of_le_left <| sdiff_le.trans le_sup_right +theorem gc_sdiff_sup : GaloisConnection (· \ a) (a ⊔ ·) := + fun _ _ ↦ sdiff_le_iff + -- See note [lower instance priority] instance (priority := 100) GeneralizedCoheytingAlgebra.toDistribLattice : DistribLattice α := { ‹GeneralizedCoheytingAlgebra α› with From 0642034a4e45d5b21dbf5d4cdd8141ef7c0c686a Mon Sep 17 00:00:00 2001 From: Yuma Mizuno Date: Wed, 5 Feb 2025 07:04:39 +0000 Subject: [PATCH 088/103] doc(CategoryTheory/Monoidal/Category): fix expression in docs (#21445) --- Mathlib/CategoryTheory/Monoidal/Category.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/CategoryTheory/Monoidal/Category.lean b/Mathlib/CategoryTheory/Monoidal/Category.lean index 4c815f65d7fca..96a871d7faed0 100644 --- a/Mathlib/CategoryTheory/Monoidal/Category.lean +++ b/Mathlib/CategoryTheory/Monoidal/Category.lean @@ -166,8 +166,8 @@ class MonoidalCategory (C : Type u) [𝒞 : Category.{v} C] extends MonoidalCate /-- Tensor product of identity maps is the identity: `(𝟙 X₁ ⊗ 𝟙 X₂) = 𝟙 (X₁ ⊗ X₂)` -/ tensor_id : ∀ X₁ X₂ : C, 𝟙 X₁ ⊗ 𝟙 X₂ = 𝟙 (X₁ ⊗ X₂) := by aesop_cat /-- - Composition of tensor products is tensor product of compositions: - `(f₁ ⊗ g₁) ∘ (f₂ ⊗ g₂) = (f₁ ∘ f₂) ⊗ (g₁ ⊗ g₂)` + Tensor product of compositions is composition of tensor products: + `(f₁ ≫ g₁) ⊗ (f₂ ≫ g₂) = (f₁ ⊗ f₂) ≫ (g₁ ⊗ g₂)` -/ tensor_comp : ∀ {X₁ Y₁ Z₁ X₂ Y₂ Z₂ : C} (f₁ : X₁ ⟶ Y₁) (f₂ : X₂ ⟶ Y₂) (g₁ : Y₁ ⟶ Z₁) (g₂ : Y₂ ⟶ Z₂), From 0636ded8fb79ebc55b8b0600bb198460523d82dc Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Wed, 5 Feb 2025 09:23:29 +0000 Subject: [PATCH 089/103] chore(Topology/Algebra/ContinuousMonoidHom): do not depend on `ContinuousLinearMap` (#21443) The dependency should go in the other direction. --- Mathlib.lean | 1 + .../Topology/Algebra/ContinuousMonoidHom.lean | 194 +--------------- .../Topology/Algebra/Group/CompactOpen.lean | 209 ++++++++++++++++++ Mathlib/Topology/Algebra/PontryaginDual.lean | 2 +- 4 files changed, 215 insertions(+), 191 deletions(-) create mode 100644 Mathlib/Topology/Algebra/Group/CompactOpen.lean diff --git a/Mathlib.lean b/Mathlib.lean index 8bb17b047f6ca..d45d091582d9c 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -5234,6 +5234,7 @@ import Mathlib.Topology.Algebra.Field import Mathlib.Topology.Algebra.FilterBasis import Mathlib.Topology.Algebra.Group.Basic import Mathlib.Topology.Algebra.Group.Compact +import Mathlib.Topology.Algebra.Group.CompactOpen import Mathlib.Topology.Algebra.Group.OpenMapping import Mathlib.Topology.Algebra.Group.Quotient import Mathlib.Topology.Algebra.Group.SubmonoidClosure diff --git a/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean b/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean index 50608fec314d0..bf1025bebc1d2 100644 --- a/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean +++ b/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean @@ -3,10 +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, Nailin Guan -/ -import Mathlib.Topology.Algebra.Equicontinuity -import Mathlib.Topology.Algebra.Group.Compact -import Mathlib.Topology.ContinuousMap.Algebra -import Mathlib.Topology.UniformSpace.Ascoli +import Mathlib.Topology.Algebra.Group.Basic /-! @@ -20,6 +17,9 @@ This file defines the space of continuous homomorphisms between two topological * `ContinuousAddMonoidHom A B`: The continuous additive homomorphisms `A →+ B`. -/ +assert_not_exists ContinuousLinearMap +assert_not_exists ContinuousLinearEquiv + section open Function Topology @@ -278,192 +278,6 @@ instance : CommGroup (ContinuousMonoidHom A E) where inv f := (inv E).comp f inv_mul_cancel f := ext fun x => inv_mul_cancel (f x) -@[to_additive] -instance : TopologicalSpace (ContinuousMonoidHom A B) := - TopologicalSpace.induced toContinuousMap ContinuousMap.compactOpen - -variable (A B C D E) - -@[to_additive] -theorem isInducing_toContinuousMap : - IsInducing (toContinuousMap : ContinuousMonoidHom A B → C(A, B)) := ⟨rfl⟩ - -@[deprecated (since := "2024-10-28")] alias inducing_toContinuousMap := isInducing_toContinuousMap - -@[to_additive] -theorem isEmbedding_toContinuousMap : - IsEmbedding (toContinuousMap : ContinuousMonoidHom A B → C(A, B)) := - ⟨isInducing_toContinuousMap A B, toContinuousMap_injective⟩ - -@[deprecated (since := "2024-10-26")] -alias embedding_toContinuousMap := isEmbedding_toContinuousMap - -@[to_additive] -instance instContinuousEvalConst : ContinuousEvalConst (ContinuousMonoidHom A B) A B := - .of_continuous_forget (isInducing_toContinuousMap A B).continuous - -@[to_additive] -instance instContinuousEval [LocallyCompactPair A B] : - ContinuousEval (ContinuousMonoidHom A B) A B := - .of_continuous_forget (isInducing_toContinuousMap A B).continuous - -@[to_additive] -lemma range_toContinuousMap : - Set.range (toContinuousMap : ContinuousMonoidHom A B → C(A, B)) = - {f : C(A, B) | f 1 = 1 ∧ ∀ x y, f (x * y) = f x * f y} := by - refine Set.Subset.antisymm (Set.range_subset_iff.2 fun f ↦ ⟨map_one f, map_mul f⟩) ?_ - rintro f ⟨h1, hmul⟩ - exact ⟨{ f with map_one' := h1, map_mul' := hmul }, rfl⟩ - -@[to_additive] -theorem isClosedEmbedding_toContinuousMap [ContinuousMul B] [T2Space B] : - IsClosedEmbedding (toContinuousMap : ContinuousMonoidHom A B → C(A, B)) where - toIsEmbedding := isEmbedding_toContinuousMap A B - isClosed_range := by - simp only [range_toContinuousMap, Set.setOf_and, Set.setOf_forall] - refine .inter (isClosed_singleton.preimage (continuous_eval_const 1)) <| - isClosed_iInter fun x ↦ isClosed_iInter fun y ↦ ?_ - exact isClosed_eq (continuous_eval_const (x * y)) <| - .mul (continuous_eval_const x) (continuous_eval_const y) - -@[deprecated (since := "2024-10-20")] -alias closedEmbedding_toContinuousMap := isClosedEmbedding_toContinuousMap - -variable {A B C D E} - -@[to_additive] -instance [T2Space B] : T2Space (ContinuousMonoidHom A B) := - (isEmbedding_toContinuousMap A B).t2Space - -@[to_additive] -instance : TopologicalGroup (ContinuousMonoidHom A E) := - let hi := isInducing_toContinuousMap A E - let hc := hi.continuous - { continuous_mul := hi.continuous_iff.mpr (continuous_mul.comp (Continuous.prodMap hc hc)) - continuous_inv := hi.continuous_iff.mpr (continuous_inv.comp hc) } - -@[to_additive] -theorem continuous_of_continuous_uncurry {A : Type*} [TopologicalSpace A] - (f : A → ContinuousMonoidHom B C) (h : Continuous (Function.uncurry fun x y => f x y)) : - Continuous f := - (isInducing_toContinuousMap _ _).continuous_iff.mpr - (ContinuousMap.continuous_of_continuous_uncurry _ h) - -@[to_additive] -theorem continuous_comp [LocallyCompactSpace B] : - Continuous fun f : ContinuousMonoidHom A B × ContinuousMonoidHom B C => f.2.comp f.1 := - (isInducing_toContinuousMap A C).continuous_iff.2 <| - ContinuousMap.continuous_comp'.comp - ((isInducing_toContinuousMap A B).prodMap (isInducing_toContinuousMap B C)).continuous - -@[to_additive] -theorem continuous_comp_left (f : ContinuousMonoidHom A B) : - Continuous fun g : ContinuousMonoidHom B C => g.comp f := - (isInducing_toContinuousMap A C).continuous_iff.2 <| - f.toContinuousMap.continuous_precomp.comp (isInducing_toContinuousMap B C).continuous - -@[to_additive] -theorem continuous_comp_right (f : ContinuousMonoidHom B C) : - Continuous fun g : ContinuousMonoidHom A B => f.comp g := - (isInducing_toContinuousMap A C).continuous_iff.2 <| - f.toContinuousMap.continuous_postcomp.comp (isInducing_toContinuousMap A B).continuous - -variable (E) - -/-- `ContinuousMonoidHom _ f` is a functor. -/ -@[to_additive "`ContinuousAddMonoidHom _ f` is a functor."] -def compLeft (f : ContinuousMonoidHom A B) : - ContinuousMonoidHom (ContinuousMonoidHom B E) (ContinuousMonoidHom A E) where - toFun g := g.comp f - map_one' := rfl - map_mul' _g _h := rfl - continuous_toFun := f.continuous_comp_left - -variable (A) {E} - -/-- `ContinuousMonoidHom f _` is a functor. -/ -@[to_additive "`ContinuousAddMonoidHom f _` is a functor."] -def compRight {B : Type*} [CommGroup B] [TopologicalSpace B] [TopologicalGroup B] - (f : ContinuousMonoidHom B E) : - ContinuousMonoidHom (ContinuousMonoidHom A B) (ContinuousMonoidHom A E) where - toFun g := f.comp g - map_one' := ext fun _a => map_one f - map_mul' g h := ext fun a => map_mul f (g a) (h a) - continuous_toFun := f.continuous_comp_right - -section LocallyCompact - -variable {X Y : Type*} [TopologicalSpace X] [Group X] [TopologicalGroup X] - [UniformSpace Y] [CommGroup Y] [UniformGroup Y] [T0Space Y] [CompactSpace Y] - -@[to_additive] -theorem locallyCompactSpace_of_equicontinuousAt (U : Set X) (V : Set Y) - (hU : IsCompact U) (hV : V ∈ nhds (1 : Y)) - (h : EquicontinuousAt (fun f : {f : X →* Y | Set.MapsTo f U V} ↦ (f : X → Y)) 1) : - LocallyCompactSpace (ContinuousMonoidHom X Y) := by - replace h := equicontinuous_of_equicontinuousAt_one _ h - obtain ⟨W, hWo, hWV, hWc⟩ := local_compact_nhds hV - let S1 : Set (X →* Y) := {f | Set.MapsTo f U W} - let S2 : Set (ContinuousMonoidHom X Y) := {f | Set.MapsTo f U W} - let S3 : Set C(X, Y) := (↑) '' S2 - let S4 : Set (X → Y) := (↑) '' S3 - replace h : Equicontinuous ((↑) : S1 → X → Y) := - h.comp (Subtype.map _root_.id fun f hf ↦ hf.mono_right hWV) - have hS4 : S4 = (↑) '' S1 := by - ext - constructor - · rintro ⟨-, ⟨f, hf, rfl⟩, rfl⟩ - exact ⟨f, hf, rfl⟩ - · rintro ⟨f, hf, rfl⟩ - exact ⟨⟨f, h.continuous ⟨f, hf⟩⟩, ⟨⟨f, h.continuous ⟨f, hf⟩⟩, hf, rfl⟩, rfl⟩ - replace h : Equicontinuous ((↑) : S3 → X → Y) := by - rw [equicontinuous_iff_range, ← Set.image_eq_range] at h ⊢ - rwa [← hS4] at h - replace hS4 : S4 = Set.pi U (fun _ ↦ W) ∩ Set.range ((↑) : (X →* Y) → (X → Y)) := by - simp_rw [hS4, Set.ext_iff, Set.mem_image, S1, Set.mem_setOf_eq] - exact fun f ↦ ⟨fun ⟨g, hg, hf⟩ ↦ hf ▸ ⟨hg, g, rfl⟩, fun ⟨hg, g, hf⟩ ↦ ⟨g, hf ▸ hg, hf⟩⟩ - replace hS4 : IsClosed S4 := - hS4.symm ▸ (isClosed_set_pi (fun _ _ ↦ hWc.isClosed)).inter (MonoidHom.isClosed_range_coe X Y) - have hS2 : (interior S2).Nonempty := by - let T : Set (ContinuousMonoidHom X Y) := {f | Set.MapsTo f U (interior W)} - have h1 : T.Nonempty := ⟨1, fun _ _ ↦ mem_interior_iff_mem_nhds.mpr hWo⟩ - have h2 : T ⊆ S2 := fun f hf ↦ hf.mono_right interior_subset - have h3 : IsOpen T := isOpen_induced (ContinuousMap.isOpen_setOf_mapsTo hU isOpen_interior) - exact h1.mono (interior_maximal h2 h3) - exact TopologicalSpace.PositiveCompacts.locallyCompactSpace_of_group - ⟨⟨S2, (isInducing_toContinuousMap X Y).isCompact_iff.mpr - (ArzelaAscoli.isCompact_of_equicontinuous S3 hS4.isCompact h)⟩, hS2⟩ - -variable [LocallyCompactSpace X] - -@[to_additive] -theorem locallyCompactSpace_of_hasBasis (V : ℕ → Set Y) - (hV : ∀ {n x}, x ∈ V n → x * x ∈ V n → x ∈ V (n + 1)) - (hVo : Filter.HasBasis (nhds 1) (fun _ ↦ True) V) : - LocallyCompactSpace (ContinuousMonoidHom X Y) := by - obtain ⟨U0, hU0c, hU0o⟩ := exists_compact_mem_nhds (1 : X) - let U_aux : ℕ → {S : Set X | S ∈ nhds 1} := - Nat.rec ⟨U0, hU0o⟩ <| fun _ S ↦ let h := exists_closed_nhds_one_inv_eq_mul_subset S.2 - ⟨Classical.choose h, (Classical.choose_spec h).1⟩ - let U : ℕ → Set X := fun n ↦ (U_aux n).1 - have hU1 : ∀ n, U n ∈ nhds 1 := fun n ↦ (U_aux n).2 - have hU2 : ∀ n, U (n + 1) * U (n + 1) ⊆ U n := - fun n ↦ (Classical.choose_spec (exists_closed_nhds_one_inv_eq_mul_subset (U_aux n).2)).2.2.2 - have hU3 : ∀ n, U (n + 1) ⊆ U n := - fun n x hx ↦ hU2 n (mul_one x ▸ Set.mul_mem_mul hx (mem_of_mem_nhds (hU1 (n + 1)))) - have hU4 : ∀ f : X →* Y, Set.MapsTo f (U 0) (V 0) → ∀ n, Set.MapsTo f (U n) (V n) := by - intro f hf n - induction' n with n ih - · exact hf - · exact fun x hx ↦ hV (ih (hU3 n hx)) (map_mul f x x ▸ ih (hU2 n (Set.mul_mem_mul hx hx))) - apply locallyCompactSpace_of_equicontinuousAt (U 0) (V 0) hU0c (hVo.mem_of_mem trivial) - rw [hVo.uniformity_of_nhds_one.equicontinuousAt_iff_right] - refine fun n _ ↦ Filter.eventually_iff_exists_mem.mpr ⟨U n, hU1 n, fun x hx ⟨f, hf⟩ ↦ ?_⟩ - rw [Set.mem_setOf_eq, map_one, div_one] - exact hU4 f hf n hx - -end LocallyCompact - end ContinuousMonoidHom end diff --git a/Mathlib/Topology/Algebra/Group/CompactOpen.lean b/Mathlib/Topology/Algebra/Group/CompactOpen.lean new file mode 100644 index 0000000000000..09f3be5f1fac3 --- /dev/null +++ b/Mathlib/Topology/Algebra/Group/CompactOpen.lean @@ -0,0 +1,209 @@ +/- +Copyright (c) 2022 Thomas Browning. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Thomas Browning, Nailin Guan +-/ +import Mathlib.Topology.Algebra.ContinuousMonoidHom +import Mathlib.Topology.Algebra.Equicontinuity +import Mathlib.Topology.Algebra.Group.Compact +import Mathlib.Topology.ContinuousMap.Algebra +import Mathlib.Topology.UniformSpace.Ascoli + +/-! +# The compact-open topology on continuous monoid morphisms. +-/ + +open Function Topology +open scoped Pointwise + +variable (F A B C D E : Type*) [Monoid A] [Monoid B] [Monoid C] [Monoid D] [CommGroup E] + [TopologicalSpace A] [TopologicalSpace B] [TopologicalSpace C] [TopologicalSpace D] + [TopologicalSpace E] [TopologicalGroup E] + +namespace ContinuousMonoidHom + +@[to_additive] +instance : TopologicalSpace (ContinuousMonoidHom A B) := + TopologicalSpace.induced toContinuousMap ContinuousMap.compactOpen + +@[to_additive] +theorem isInducing_toContinuousMap : + IsInducing (toContinuousMap : ContinuousMonoidHom A B → C(A, B)) := ⟨rfl⟩ + +@[deprecated (since := "2024-10-28")] alias inducing_toContinuousMap := isInducing_toContinuousMap + +@[to_additive] +theorem isEmbedding_toContinuousMap : + IsEmbedding (toContinuousMap : ContinuousMonoidHom A B → C(A, B)) := + ⟨isInducing_toContinuousMap A B, toContinuousMap_injective⟩ + +@[deprecated (since := "2024-10-26")] +alias embedding_toContinuousMap := isEmbedding_toContinuousMap + +@[to_additive] +instance instContinuousEvalConst : ContinuousEvalConst (ContinuousMonoidHom A B) A B := + .of_continuous_forget (isInducing_toContinuousMap A B).continuous + +@[to_additive] +instance instContinuousEval [LocallyCompactPair A B] : + ContinuousEval (ContinuousMonoidHom A B) A B := + .of_continuous_forget (isInducing_toContinuousMap A B).continuous + +@[to_additive] +lemma range_toContinuousMap : + Set.range (toContinuousMap : ContinuousMonoidHom A B → C(A, B)) = + {f : C(A, B) | f 1 = 1 ∧ ∀ x y, f (x * y) = f x * f y} := by + refine Set.Subset.antisymm (Set.range_subset_iff.2 fun f ↦ ⟨map_one f, map_mul f⟩) ?_ + rintro f ⟨h1, hmul⟩ + exact ⟨{ f with map_one' := h1, map_mul' := hmul }, rfl⟩ + +@[to_additive] +theorem isClosedEmbedding_toContinuousMap [ContinuousMul B] [T2Space B] : + IsClosedEmbedding (toContinuousMap : ContinuousMonoidHom A B → C(A, B)) where + toIsEmbedding := isEmbedding_toContinuousMap A B + isClosed_range := by + simp only [range_toContinuousMap, Set.setOf_and, Set.setOf_forall] + refine .inter (isClosed_singleton.preimage (continuous_eval_const 1)) <| + isClosed_iInter fun x ↦ isClosed_iInter fun y ↦ ?_ + exact isClosed_eq (continuous_eval_const (x * y)) <| + .mul (continuous_eval_const x) (continuous_eval_const y) + +@[deprecated (since := "2024-10-20")] +alias closedEmbedding_toContinuousMap := isClosedEmbedding_toContinuousMap + +variable {A B C D E} + +@[to_additive] +instance [T2Space B] : T2Space (ContinuousMonoidHom A B) := + (isEmbedding_toContinuousMap A B).t2Space + +@[to_additive] +instance : TopologicalGroup (ContinuousMonoidHom A E) := + let hi := isInducing_toContinuousMap A E + let hc := hi.continuous + { continuous_mul := hi.continuous_iff.mpr (continuous_mul.comp (Continuous.prodMap hc hc)) + continuous_inv := hi.continuous_iff.mpr (continuous_inv.comp hc) } + +@[to_additive] +theorem continuous_of_continuous_uncurry {A : Type*} [TopologicalSpace A] + (f : A → ContinuousMonoidHom B C) (h : Continuous (Function.uncurry fun x y => f x y)) : + Continuous f := + (isInducing_toContinuousMap _ _).continuous_iff.mpr + (ContinuousMap.continuous_of_continuous_uncurry _ h) + +@[to_additive] +theorem continuous_comp [LocallyCompactSpace B] : + Continuous fun f : ContinuousMonoidHom A B × ContinuousMonoidHom B C => f.2.comp f.1 := + (isInducing_toContinuousMap A C).continuous_iff.2 <| + ContinuousMap.continuous_comp'.comp + ((isInducing_toContinuousMap A B).prodMap (isInducing_toContinuousMap B C)).continuous + +@[to_additive] +theorem continuous_comp_left (f : ContinuousMonoidHom A B) : + Continuous fun g : ContinuousMonoidHom B C => g.comp f := + (isInducing_toContinuousMap A C).continuous_iff.2 <| + f.toContinuousMap.continuous_precomp.comp (isInducing_toContinuousMap B C).continuous + +@[to_additive] +theorem continuous_comp_right (f : ContinuousMonoidHom B C) : + Continuous fun g : ContinuousMonoidHom A B => f.comp g := + (isInducing_toContinuousMap A C).continuous_iff.2 <| + f.toContinuousMap.continuous_postcomp.comp (isInducing_toContinuousMap A B).continuous + +variable (E) + +/-- `ContinuousMonoidHom _ f` is a functor. -/ +@[to_additive "`ContinuousAddMonoidHom _ f` is a functor."] +def compLeft (f : ContinuousMonoidHom A B) : + ContinuousMonoidHom (ContinuousMonoidHom B E) (ContinuousMonoidHom A E) where + toFun g := g.comp f + map_one' := rfl + map_mul' _g _h := rfl + continuous_toFun := f.continuous_comp_left + +variable (A) {E} + +/-- `ContinuousMonoidHom f _` is a functor. -/ +@[to_additive "`ContinuousAddMonoidHom f _` is a functor."] +def compRight {B : Type*} [CommGroup B] [TopologicalSpace B] [TopologicalGroup B] + (f : ContinuousMonoidHom B E) : + ContinuousMonoidHom (ContinuousMonoidHom A B) (ContinuousMonoidHom A E) where + toFun g := f.comp g + map_one' := ext fun _a => map_one f + map_mul' g h := ext fun a => map_mul f (g a) (h a) + continuous_toFun := f.continuous_comp_right + +section LocallyCompact + +variable {X Y : Type*} [TopologicalSpace X] [Group X] [TopologicalGroup X] + [UniformSpace Y] [CommGroup Y] [UniformGroup Y] [T0Space Y] [CompactSpace Y] + +@[to_additive] +theorem locallyCompactSpace_of_equicontinuousAt (U : Set X) (V : Set Y) + (hU : IsCompact U) (hV : V ∈ nhds (1 : Y)) + (h : EquicontinuousAt (fun f : {f : X →* Y | Set.MapsTo f U V} ↦ (f : X → Y)) 1) : + LocallyCompactSpace (ContinuousMonoidHom X Y) := by + replace h := equicontinuous_of_equicontinuousAt_one _ h + obtain ⟨W, hWo, hWV, hWc⟩ := local_compact_nhds hV + let S1 : Set (X →* Y) := {f | Set.MapsTo f U W} + let S2 : Set (ContinuousMonoidHom X Y) := {f | Set.MapsTo f U W} + let S3 : Set C(X, Y) := (↑) '' S2 + let S4 : Set (X → Y) := (↑) '' S3 + replace h : Equicontinuous ((↑) : S1 → X → Y) := + h.comp (Subtype.map _root_.id fun f hf ↦ hf.mono_right hWV) + have hS4 : S4 = (↑) '' S1 := by + ext + constructor + · rintro ⟨-, ⟨f, hf, rfl⟩, rfl⟩ + exact ⟨f, hf, rfl⟩ + · rintro ⟨f, hf, rfl⟩ + exact ⟨⟨f, h.continuous ⟨f, hf⟩⟩, ⟨⟨f, h.continuous ⟨f, hf⟩⟩, hf, rfl⟩, rfl⟩ + replace h : Equicontinuous ((↑) : S3 → X → Y) := by + rw [equicontinuous_iff_range, ← Set.image_eq_range] at h ⊢ + rwa [← hS4] at h + replace hS4 : S4 = Set.pi U (fun _ ↦ W) ∩ Set.range ((↑) : (X →* Y) → (X → Y)) := by + simp_rw [hS4, Set.ext_iff, Set.mem_image, S1, Set.mem_setOf_eq] + exact fun f ↦ ⟨fun ⟨g, hg, hf⟩ ↦ hf ▸ ⟨hg, g, rfl⟩, fun ⟨hg, g, hf⟩ ↦ ⟨g, hf ▸ hg, hf⟩⟩ + replace hS4 : IsClosed S4 := + hS4.symm ▸ (isClosed_set_pi (fun _ _ ↦ hWc.isClosed)).inter (MonoidHom.isClosed_range_coe X Y) + have hS2 : (interior S2).Nonempty := by + let T : Set (ContinuousMonoidHom X Y) := {f | Set.MapsTo f U (interior W)} + have h1 : T.Nonempty := ⟨1, fun _ _ ↦ mem_interior_iff_mem_nhds.mpr hWo⟩ + have h2 : T ⊆ S2 := fun f hf ↦ hf.mono_right interior_subset + have h3 : IsOpen T := isOpen_induced (ContinuousMap.isOpen_setOf_mapsTo hU isOpen_interior) + exact h1.mono (interior_maximal h2 h3) + exact TopologicalSpace.PositiveCompacts.locallyCompactSpace_of_group + ⟨⟨S2, (isInducing_toContinuousMap X Y).isCompact_iff.mpr + (ArzelaAscoli.isCompact_of_equicontinuous S3 hS4.isCompact h)⟩, hS2⟩ + +variable [LocallyCompactSpace X] + +@[to_additive] +theorem locallyCompactSpace_of_hasBasis (V : ℕ → Set Y) + (hV : ∀ {n x}, x ∈ V n → x * x ∈ V n → x ∈ V (n + 1)) + (hVo : Filter.HasBasis (nhds 1) (fun _ ↦ True) V) : + LocallyCompactSpace (ContinuousMonoidHom X Y) := by + obtain ⟨U0, hU0c, hU0o⟩ := exists_compact_mem_nhds (1 : X) + let U_aux : ℕ → {S : Set X | S ∈ nhds 1} := + Nat.rec ⟨U0, hU0o⟩ <| fun _ S ↦ let h := exists_closed_nhds_one_inv_eq_mul_subset S.2 + ⟨Classical.choose h, (Classical.choose_spec h).1⟩ + let U : ℕ → Set X := fun n ↦ (U_aux n).1 + have hU1 : ∀ n, U n ∈ nhds 1 := fun n ↦ (U_aux n).2 + have hU2 : ∀ n, U (n + 1) * U (n + 1) ⊆ U n := + fun n ↦ (Classical.choose_spec (exists_closed_nhds_one_inv_eq_mul_subset (U_aux n).2)).2.2.2 + have hU3 : ∀ n, U (n + 1) ⊆ U n := + fun n x hx ↦ hU2 n (mul_one x ▸ Set.mul_mem_mul hx (mem_of_mem_nhds (hU1 (n + 1)))) + have hU4 : ∀ f : X →* Y, Set.MapsTo f (U 0) (V 0) → ∀ n, Set.MapsTo f (U n) (V n) := by + intro f hf n + induction' n with n ih + · exact hf + · exact fun x hx ↦ hV (ih (hU3 n hx)) (map_mul f x x ▸ ih (hU2 n (Set.mul_mem_mul hx hx))) + apply locallyCompactSpace_of_equicontinuousAt (U 0) (V 0) hU0c (hVo.mem_of_mem trivial) + rw [hVo.uniformity_of_nhds_one.equicontinuousAt_iff_right] + refine fun n _ ↦ Filter.eventually_iff_exists_mem.mpr ⟨U n, hU1 n, fun x hx ⟨f, hf⟩ ↦ ?_⟩ + rw [Set.mem_setOf_eq, map_one, div_one] + exact hU4 f hf n hx + +end LocallyCompact + +end ContinuousMonoidHom diff --git a/Mathlib/Topology/Algebra/PontryaginDual.lean b/Mathlib/Topology/Algebra/PontryaginDual.lean index 2b24a7b06909d..919b40c6d919f 100644 --- a/Mathlib/Topology/Algebra/PontryaginDual.lean +++ b/Mathlib/Topology/Algebra/PontryaginDual.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Thomas Browning -/ import Mathlib.Analysis.SpecialFunctions.Complex.Circle -import Mathlib.Topology.Algebra.ContinuousMonoidHom +import Mathlib.Topology.Algebra.Group.CompactOpen /-! # Pontryagin dual From 6449d921f64fe4672e94c415a0b43b7c7a2f8e82 Mon Sep 17 00:00:00 2001 From: Yoh Tanimoto Date: Wed, 5 Feb 2025 09:36:37 +0000 Subject: [PATCH 090/103] feat(MeasureTheory/Integral/RieszMarkovKakutani) prove that the Riesz content is regular and define the Riesz measure (#20040) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prove regularity of `RieszContent`, define the Riesz measure `μ Λ` and prove basic properties. Motivation: these definitions and lemmas will be used to prove the Riesz-Markov-Kakutani theorem, characterizing `μ Λ`. In this PR, it is assumed to be NNReal-linear. In this way, the proof of the RMK theorem will be twice as long as a proof for `Real`-linear `Λ` because one cannot define `-f`. #12290 proves the RMK theorem for real linear `Λ`, using the Riesz measure defined in this PR through `toNNRealLinear`. Co-authored-by: Yoh Tanimoto <57562556+yoh-tanimoto@users.noreply.github.com> --- .../Integral/RieszMarkovKakutani.lean | 88 +++++++++++++++++++ .../ContinuousMap/CompactlySupported.lean | 14 +++ 2 files changed, 102 insertions(+) diff --git a/Mathlib/MeasureTheory/Integral/RieszMarkovKakutani.lean b/Mathlib/MeasureTheory/Integral/RieszMarkovKakutani.lean index 4bb72f9cfdf1e..7d1ee3405b1cd 100644 --- a/Mathlib/MeasureTheory/Integral/RieszMarkovKakutani.lean +++ b/Mathlib/MeasureTheory/Integral/RieszMarkovKakutani.lean @@ -36,6 +36,16 @@ variable (Λ : C_c(X, ℝ≥0) →ₗ[ℝ≥0] ℝ≥0) /-! ### Construction of the content: -/ +section Monotone + +lemma CompactlySupportedContinuousMap.monotone_of_nnreal : Monotone Λ := by + intro f₁ f₂ h + obtain ⟨g, hg⟩ := CompactlySupportedContinuousMap.exists_add_of_le h + rw [← hg] + simp + +end Monotone + /-- Given a positive linear functional `Λ` on continuous compactly supported functions on `X` with values in `ℝ≥0`, for `K ⊆ X` compact define `λ(K) = inf {Λf | 1≤f on K}`. When `X` is a locally compact T2 space, this will be shown to be a @@ -208,6 +218,8 @@ lemma exists_continuous_add_one_of_isCompact_nnreal end PartitionOfUnity +section RieszContentAdditive + variable [T2Space X] [LocallyCompactSpace X] lemma rieszContentAux_union {K₁ K₂ : TopologicalSpace.Compacts X} @@ -245,9 +257,85 @@ lemma rieszContentAux_union {K₁ K₂ : TopologicalSpace.Compacts X} simp [hg₂ x_in_K₂, hf x (mem_union_right _ x_in_K₂)] exact add_le_add (rieszContentAux_le Λ aux₁) (rieszContentAux_le Λ aux₂) +end RieszContentAdditive + +section RieszContentRegular + +variable [T2Space X] [LocallyCompactSpace X] + /-- The content induced by the linear functional `Λ`. -/ noncomputable def rieszContent (Λ : C_c(X, ℝ≥0) →ₗ[ℝ≥0] ℝ≥0) : Content X where toFun := rieszContentAux Λ mono' := fun _ _ ↦ rieszContentAux_mono Λ sup_disjoint' := fun _ _ disj _ _ ↦ rieszContentAux_union Λ disj sup_le' := rieszContentAux_sup_le Λ + +lemma rieszContent_ne_top {K : Compacts X} : rieszContent Λ K ≠ ⊤ := by + simp only [ne_eq, ENNReal.coe_ne_top, not_false_eq_true] + +lemma contentRegular_rieszContent : (rieszContent Λ).ContentRegular := by + intro K + simp only [rieszContent, le_antisymm_iff, le_iInf_iff, ENNReal.coe_le_coe] + refine ⟨fun K' hK' ↦ rieszContentAux_mono Λ (hK'.trans interior_subset), ?_⟩ + rw [iInf_le_iff] + intro b hb + rw [rieszContentAux, ENNReal.le_coe_iff] + have : b < ⊤ := by + obtain ⟨F, hF⟩ := exists_compact_superset K.2 + exact (le_iInf_iff.mp (hb ⟨F, hF.1⟩) hF.2).trans_lt ENNReal.coe_lt_top + refine ⟨b.toNNReal, (ENNReal.coe_toNNReal this.ne).symm, NNReal.coe_le_coe.mp ?_⟩ + apply le_iff_forall_pos_le_add.mpr + intro ε hε + lift ε to ℝ≥0 using hε.le + obtain ⟨f, hfleoneonK, hfle⟩ := exists_lt_rieszContentAux_add_pos Λ K (Real.toNNReal_pos.mpr hε) + rw [rieszContentAux, Real.toNNReal_of_nonneg hε.le, ← NNReal.coe_lt_coe] at hfle + refine ((le_iff_forall_one_lt_le_mul₀ (zero_le (Λ f))).mpr fun α hα ↦ ?_).trans hfle.le + rw [mul_comm, ← smul_eq_mul, ← map_smul] + set K' := f ⁻¹' Ici α⁻¹ + have hKK' : ↑K ⊆ interior K' := + subset_interior_iff.2 ⟨f ⁻¹' Ioi α⁻¹, isOpen_Ioi.preimage f.1.2, + fun x hx ↦ (inv_lt_one_of_one_lt₀ hα).trans_le (hfleoneonK x hx), + preimage_mono Ioi_subset_Ici_self⟩ + have hK'cp : IsCompact K' := .of_isClosed_subset f.2 (isClosed_Ici.preimage f.1.2) fun x hx ↦ + subset_closure ((inv_pos_of_pos <| zero_lt_one.trans hα).trans_le hx).ne' + set hb' := hb ⟨K', hK'cp⟩ + simp only [Compacts.coe_mk, le_iInf_iff] at hb' + exact (ENNReal.toNNReal_mono (by simp) <| hb' hKK').trans <| csInf_le' + ⟨α • f, fun x ↦ (inv_le_iff_one_le_mul₀' (zero_lt_one.trans hα)).mp, by simp⟩ + +end RieszContentRegular + +section RieszMeasure + +variable [T2Space X] [LocallyCompactSpace X] [MeasurableSpace X] [BorelSpace X] + +/-- `rieszContent` gives a `Content` from `Λ : C_c(X, ℝ≥0) →ₗ[ℝ≥0] ℝ≥0`. Here `rieszContent Λ` is +promoted to a measure. It will be later shown that +`∫ (x : X), f x ∂(rieszMeasure Λ hΛ) = Λ f` for all `f : C_c(X, ℝ≥0)`. -/ +def rieszMeasure := (rieszContent Λ).measure + +lemma le_rieszMeasure_of_isCompact_tsupport_subset {f : C_c(X, ℝ≥0)} (hf : ∀ x, f x ≤ 1) + {K : Set X} (hK : IsCompact K) (h : tsupport f ⊆ K) : .ofNNReal (Λ f) ≤ rieszMeasure Λ K := by + rw [← TopologicalSpace.Compacts.coe_mk K hK] + simp only [rieszMeasure, Content.measure_eq_content_of_regular (rieszContent Λ) + (contentRegular_rieszContent Λ)] + simp only [rieszContent, ENNReal.ofReal_coe_nnreal, ENNReal.coe_le_coe] + apply le_iff_forall_pos_le_add.mpr + intro ε hε + obtain ⟨g, hg⟩ := exists_lt_rieszContentAux_add_pos Λ ⟨K, hK⟩ hε + apply le_trans _ hg.2.le + apply monotone_of_nnreal Λ + intro x + simp only [ContinuousMap.toFun_eq_coe, CompactlySupportedContinuousMap.coe_toContinuousMap] + by_cases hx : x ∈ tsupport f + · exact le_trans (hf x) (hg.1 x (Set.mem_of_subset_of_mem h hx)) + · rw [image_eq_zero_of_nmem_tsupport hx] + exact zero_le (g x) + +lemma le_rieszMeasure_of_tsupport_subset {f : C_c(X, ℝ≥0)} (hf : ∀ x, f x ≤ 1) {V : Set X} + (h : tsupport f ⊆ V) : .ofNNReal (Λ f) ≤ rieszMeasure Λ V := by + apply le_trans _ (measure_mono h) + apply le_rieszMeasure_of_isCompact_tsupport_subset Λ hf f.hasCompactSupport + exact subset_rfl + +end RieszMeasure diff --git a/Mathlib/Topology/ContinuousMap/CompactlySupported.lean b/Mathlib/Topology/ContinuousMap/CompactlySupported.lean index b7975118f44fa..5f36e0f2e2324 100644 --- a/Mathlib/Topology/ContinuousMap/CompactlySupported.lean +++ b/Mathlib/Topology/ContinuousMap/CompactlySupported.lean @@ -629,6 +629,20 @@ open NNReal namespace CompactlySupportedContinuousMap +protected lemma exists_add_of_le {f₁ f₂ : C_c(α, ℝ≥0)} (h : f₁ ≤ f₂) : ∃ (g : C_c(α, ℝ≥0)), + f₁ + g = f₂ := by + refine ⟨⟨f₂.1 - f₁.1, ?_⟩, ?_⟩ + · apply (f₁.hasCompactSupport'.union f₂.hasCompactSupport').of_isClosed_subset isClosed_closure + rw [tsupport, tsupport, ← closure_union] + apply closure_mono + intro x hx + contrapose! hx + simp only [ContinuousMap.toFun_eq_coe, coe_toContinuousMap, Set.mem_union, Function.mem_support, + ne_eq, not_or, Decidable.not_not, ContinuousMap.coe_sub, Pi.sub_apply] at hx ⊢ + simp [hx.1, hx.2] + · ext x + simpa [← NNReal.coe_add] using add_tsub_cancel_of_le (h x) + /-- The nonnegative part of a bounded continuous `ℝ`-valued function as a bounded continuous `ℝ≥0`-valued function. -/ noncomputable def nnrealPart (f : C_c(α, ℝ)) : C_c(α, ℝ≥0) where From 435383539c55f501dedaa2ae9462bcef3d5f8882 Mon Sep 17 00:00:00 2001 From: JovanGerb Date: Wed, 5 Feb 2025 09:36:38 +0000 Subject: [PATCH 091/103] chore: remove unused argument (#21393) This was found by the linter in a different PR. --- Mathlib/Topology/Sheaves/SheafCondition/OpensLeCover.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Topology/Sheaves/SheafCondition/OpensLeCover.lean b/Mathlib/Topology/Sheaves/SheafCondition/OpensLeCover.lean index d316325a6727d..510b94940d45e 100644 --- a/Mathlib/Topology/Sheaves/SheafCondition/OpensLeCover.lean +++ b/Mathlib/Topology/Sheaves/SheafCondition/OpensLeCover.lean @@ -107,7 +107,7 @@ variable {Y : Opens X} in the sieve. This full subcategory is equivalent to `OpensLeCover U`, the (poset) category of opens contained in some `U i`. -/ @[simps] -def generateEquivalenceOpensLe_functor' (hY : Y = iSup U) : +def generateEquivalenceOpensLe_functor' : (FullSubcategory fun f : Over Y => (Sieve.generate (presieveOfCoveringAux U Y)).arrows f.hom) ⥤ OpensLeCover U := { obj := fun f => @@ -150,7 +150,7 @@ def generateEquivalenceOpensLe (hY : Y = iSup U) : (FullSubcategory fun f : Over Y => (Sieve.generate (presieveOfCoveringAux U Y)).arrows f.hom) ≌ OpensLeCover U where -- Porting note: split it out to prevent timeout - functor := generateEquivalenceOpensLe_functor' _ hY + functor := generateEquivalenceOpensLe_functor' _ inverse := generateEquivalenceOpensLe_inverse' _ hY unitIso := eqToIso <| CategoryTheory.Functor.ext (by rintro ⟨⟨_, _⟩, _⟩; dsimp; congr) From 25a796f1e88457a35448ad1699478f23c7831f58 Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Wed, 5 Feb 2025 10:31:35 +0000 Subject: [PATCH 092/103] chore(Probability/ProbabilityMassFunction/Binomial): typo "bernoulli" (#21455) Co-authored-by: Moritz Firsching --- Mathlib/Probability/ProbabilityMassFunction/Binomial.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Probability/ProbabilityMassFunction/Binomial.lean b/Mathlib/Probability/ProbabilityMassFunction/Binomial.lean index bb40a90012017..5613be8d40759 100644 --- a/Mathlib/Probability/ProbabilityMassFunction/Binomial.lean +++ b/Mathlib/Probability/ProbabilityMassFunction/Binomial.lean @@ -50,7 +50,7 @@ theorem binomial_apply_last (p : ℝ≥0∞) (h : p ≤ 1) (n : ℕ) : theorem binomial_apply_self (p : ℝ≥0∞) (h : p ≤ 1) (n : ℕ) : binomial p h n n = p^n := by simp -/-- The binomial distribution on one coin is the bernoully distribution. -/ +/-- The binomial distribution on one coin is the Bernoulli distribution. -/ theorem binomial_one_eq_bernoulli (p : ℝ≥0∞) (h : p ≤ 1) : binomial p h 1 = (bernoulli p h).map (cond · 1 0) := by ext i; fin_cases i <;> simp [tsum_bool, binomial_apply] From 76560a8a880c034f0b828b13a7ad35f6f64c9c1f Mon Sep 17 00:00:00 2001 From: Andrew Yang Date: Wed, 5 Feb 2025 10:58:18 +0000 Subject: [PATCH 093/103] feat(RingTheory): `Ring.KrullDimLE` type class (#21452) Also split `RingTheory/Ideal/MinimalPrimes.lean` into `RingTheory/Ideal/MinimalPrimes/Basic.lean` and `RingTheory/Ideal/MinimalPrimes/Localization.lean`. Co-authored-by: Andrew Yang <36414270+erdOne@users.noreply.github.com> --- Mathlib.lean | 3 +- Mathlib/Order/KrullDimension.lean | 13 ++ Mathlib/RingTheory/Ideal/Height.lean | 2 +- .../RingTheory/Ideal/MinimalPrime/Basic.lean | 151 ++++++++++++++++++ .../Localization.lean} | 127 +-------------- Mathlib/RingTheory/KrullDimension/Basic.lean | 65 +++++++- Mathlib/RingTheory/Spectrum/Prime/Basic.lean | 15 ++ .../RingTheory/Spectrum/Prime/Topology.lean | 16 +- 8 files changed, 250 insertions(+), 142 deletions(-) create mode 100644 Mathlib/RingTheory/Ideal/MinimalPrime/Basic.lean rename Mathlib/RingTheory/Ideal/{MinimalPrime.lean => MinimalPrime/Localization.lean} (67%) diff --git a/Mathlib.lean b/Mathlib.lean index d45d091582d9c..e4c60a8859f48 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -4594,7 +4594,8 @@ import Mathlib.RingTheory.Ideal.IsPrincipalPowQuotient import Mathlib.RingTheory.Ideal.Lattice import Mathlib.RingTheory.Ideal.Maps import Mathlib.RingTheory.Ideal.Maximal -import Mathlib.RingTheory.Ideal.MinimalPrime +import Mathlib.RingTheory.Ideal.MinimalPrime.Basic +import Mathlib.RingTheory.Ideal.MinimalPrime.Localization import Mathlib.RingTheory.Ideal.Nonunits import Mathlib.RingTheory.Ideal.Norm.AbsNorm import Mathlib.RingTheory.Ideal.Norm.RelNorm diff --git a/Mathlib/Order/KrullDimension.lean b/Mathlib/Order/KrullDimension.lean index f55cfb93fbc83..8062b57148d8c 100644 --- a/Mathlib/Order/KrullDimension.lean +++ b/Mathlib/Order/KrullDimension.lean @@ -780,6 +780,19 @@ lemma coheight_bot_eq_krullDim [OrderBot α] : coheight (⊥ : α) = krullDim α end krullDim +section typeclass + +/-- Typeclass for orders with krull dimension at most `n`. -/ +@[mk_iff] +class KrullDimLE (n : ℕ) (α : Type*) [Preorder α] : Prop where + krullDim_le : krullDim α ≤ n + +lemma KrullDimLE.mono {n m : ℕ} (e : n ≤ m) (α : Type*) [Preorder α] [KrullDimLE n α] : + KrullDimLE m α := + ⟨KrullDimLE.krullDim_le (n := n).trans (Nat.cast_le.mpr e)⟩ + +end typeclass + /-! ## Concrete calculations -/ diff --git a/Mathlib/RingTheory/Ideal/Height.lean b/Mathlib/RingTheory/Ideal/Height.lean index ba0b56ba522ca..31312f3c08c91 100644 --- a/Mathlib/RingTheory/Ideal/Height.lean +++ b/Mathlib/RingTheory/Ideal/Height.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jiedong Jiang, Jingting Wang, Andrew Yang -/ import Mathlib.Order.KrullDimension -import Mathlib.RingTheory.Ideal.MinimalPrime +import Mathlib.RingTheory.Ideal.MinimalPrime.Basic import Mathlib.RingTheory.Spectrum.Prime.Basic /-! # The Height of an Ideal diff --git a/Mathlib/RingTheory/Ideal/MinimalPrime/Basic.lean b/Mathlib/RingTheory/Ideal/MinimalPrime/Basic.lean new file mode 100644 index 0000000000000..51ff95f92736d --- /dev/null +++ b/Mathlib/RingTheory/Ideal/MinimalPrime/Basic.lean @@ -0,0 +1,151 @@ +/- +Copyright (c) 2022 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.RingTheory.Ideal.IsPrimary +import Mathlib.Order.Minimal + +/-! + +# Minimal primes + +We provide various results concerning the minimal primes above an ideal + +## Main results +- `Ideal.minimalPrimes`: `I.minimalPrimes` is the set of ideals that are minimal primes over `I`. +- `minimalPrimes`: `minimalPrimes R` is the set of minimal primes of `R`. +- `Ideal.exists_minimalPrimes_le`: Every prime ideal over `I` contains a minimal prime over `I`. +- `Ideal.radical_minimalPrimes`: The minimal primes over `I.radical` are precisely + the minimal primes over `I`. +- `Ideal.sInf_minimalPrimes`: The intersection of minimal primes over `I` is `I.radical`. + +Further results that need the theory of localizations can be found in +`RingTheory/Ideal/Minimal/Localization.lean`. + +-/ + +assert_not_exists Localization -- See `RingTheory/Ideal/Minimal/Localization.lean` + +section + +variable {R S : Type*} [CommSemiring R] [CommSemiring S] (I J : Ideal R) + +/-- `I.minimalPrimes` is the set of ideals that are minimal primes over `I`. -/ +protected def Ideal.minimalPrimes : Set (Ideal R) := + {p | Minimal (fun q ↦ q.IsPrime ∧ I ≤ q) p} + +variable (R) in +/-- `minimalPrimes R` is the set of minimal primes of `R`. +This is defined as `Ideal.minimalPrimes ⊥`. -/ +def minimalPrimes : Set (Ideal R) := + Ideal.minimalPrimes ⊥ + +lemma minimalPrimes_eq_minimals : minimalPrimes R = {x | Minimal Ideal.IsPrime x} := + congr_arg Minimal (by simp) + +variable {I J} + +theorem Ideal.minimalPrimes_isPrime {p : Ideal R} (h : p ∈ I.minimalPrimes) : p.IsPrime := + h.1.1 + +theorem Ideal.exists_minimalPrimes_le [J.IsPrime] (e : I ≤ J) : ∃ p ∈ I.minimalPrimes, p ≤ J := by + set S := { p : (Ideal R)ᵒᵈ | Ideal.IsPrime p ∧ I ≤ OrderDual.ofDual p } + suffices h : ∃ m, OrderDual.toDual J ≤ m ∧ Maximal (· ∈ S) m by + obtain ⟨p, hJp, hp⟩ := h + exact ⟨p, ⟨hp.prop, fun q hq hle ↦ hp.le_of_ge hq hle⟩, hJp⟩ + apply zorn_le_nonempty₀ + swap + · refine ⟨show J.IsPrime by infer_instance, e⟩ + rintro (c : Set (Ideal R)) hc hc' J' hJ' + refine + ⟨OrderDual.toDual (sInf c), + ⟨Ideal.sInf_isPrime_of_isChain ⟨J', hJ'⟩ hc'.symm fun x hx => (hc hx).1, ?_⟩, ?_⟩ + · rw [OrderDual.ofDual_toDual, le_sInf_iff] + exact fun _ hx => (hc hx).2 + · rintro z hz + rw [OrderDual.le_toDual] + exact sInf_le hz + +theorem Ideal.nonempty_minimalPrimes (h : I ≠ ⊤) : Nonempty I.minimalPrimes := by + obtain ⟨m, hm, hle⟩ := Ideal.exists_le_maximal I h + obtain ⟨p, hp, -⟩ := Ideal.exists_minimalPrimes_le hle + exact ⟨p, hp⟩ + +theorem Ideal.eq_bot_of_minimalPrimes_eq_empty (h : I.minimalPrimes = ∅) : I = ⊤ := by + by_contra hI + obtain ⟨p, hp⟩ := Ideal.nonempty_minimalPrimes hI + exact Set.not_mem_empty p (h ▸ hp) + +@[simp] +theorem Ideal.radical_minimalPrimes : I.radical.minimalPrimes = I.minimalPrimes := by + rw [Ideal.minimalPrimes, Ideal.minimalPrimes] + ext p + refine ⟨?_, ?_⟩ <;> rintro ⟨⟨a, ha⟩, b⟩ + · refine ⟨⟨a, a.radical_le_iff.1 ha⟩, ?_⟩ + simp only [Set.mem_setOf_eq, and_imp] at * + exact fun _ h2 h3 h4 => b h2 (h2.radical_le_iff.2 h3) h4 + · refine ⟨⟨a, a.radical_le_iff.2 ha⟩, ?_⟩ + simp only [Set.mem_setOf_eq, and_imp] at * + exact fun _ h2 h3 h4 => b h2 (h2.radical_le_iff.1 h3) h4 + +@[simp] +theorem Ideal.sInf_minimalPrimes : sInf I.minimalPrimes = I.radical := by + rw [I.radical_eq_sInf] + apply le_antisymm + · intro x hx + rw [Ideal.mem_sInf] at hx ⊢ + rintro J ⟨e, hJ⟩ + obtain ⟨p, hp, hp'⟩ := Ideal.exists_minimalPrimes_le e + exact hp' (hx hp) + · apply sInf_le_sInf _ + intro I hI + exact hI.1.symm + +end + +section + +variable {R S : Type*} [CommRing R] [CommRing S] {I J : Ideal R} + +theorem Ideal.minimalPrimes_eq_subsingleton (hI : I.IsPrimary) : I.minimalPrimes = {I.radical} := by + ext J + constructor + · exact fun H => + let e := H.1.1.radical_le_iff.mpr H.1.2 + (H.2 ⟨Ideal.isPrime_radical hI, Ideal.le_radical⟩ e).antisymm e + · rintro (rfl : J = I.radical) + exact ⟨⟨Ideal.isPrime_radical hI, Ideal.le_radical⟩, fun _ H _ => H.1.radical_le_iff.mpr H.2⟩ + +theorem Ideal.minimalPrimes_eq_subsingleton_self [I.IsPrime] : I.minimalPrimes = {I} := by + ext J + constructor + · exact fun H => (H.2 ⟨inferInstance, rfl.le⟩ H.1.2).antisymm H.1.2 + · rintro (rfl : J = I) + exact ⟨⟨inferInstance, rfl.le⟩, fun _ h _ => h.2⟩ + +end + +section + +variable {R : Type*} [CommSemiring R] + +theorem Ideal.minimalPrimes_top : (⊤ : Ideal R).minimalPrimes = ∅ := by + ext p + simp only [Set.not_mem_empty, iff_false] + intro h + exact h.1.1.ne_top (top_le_iff.mp h.1.2) + +theorem Ideal.minimalPrimes_eq_empty_iff (I : Ideal R) : + I.minimalPrimes = ∅ ↔ I = ⊤ := by + constructor + · intro e + by_contra h + have ⟨M, hM, hM'⟩ := Ideal.exists_le_maximal I h + have ⟨p, hp⟩ := Ideal.exists_minimalPrimes_le hM' + rw [e] at hp + apply Set.not_mem_empty _ hp.1 + · rintro rfl + exact Ideal.minimalPrimes_top + +end diff --git a/Mathlib/RingTheory/Ideal/MinimalPrime.lean b/Mathlib/RingTheory/Ideal/MinimalPrime/Localization.lean similarity index 67% rename from Mathlib/RingTheory/Ideal/MinimalPrime.lean rename to Mathlib/RingTheory/Ideal/MinimalPrime/Localization.lean index f64ffa92a936f..ffc4253f87297 100644 --- a/Mathlib/RingTheory/Ideal/MinimalPrime.lean +++ b/Mathlib/RingTheory/Ideal/MinimalPrime/Localization.lean @@ -3,23 +3,17 @@ Copyright (c) 2022 Andrew Yang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ -import Mathlib.RingTheory.Ideal.IsPrimary +import Mathlib.RingTheory.Ideal.MinimalPrime.Basic import Mathlib.RingTheory.Localization.AtPrime -import Mathlib.Order.Minimal /-! -# Minimal primes +# Minimal primes and localization -We provide various results concerning the minimal primes above an ideal +We provide various results concerning the minimal primes above an ideal that needs the theory +of localizations ## Main results -- `Ideal.minimalPrimes`: `I.minimalPrimes` is the set of ideals that are minimal primes over `I`. -- `minimalPrimes`: `minimalPrimes R` is the set of minimal primes of `R`. -- `Ideal.exists_minimalPrimes_le`: Every prime ideal over `I` contains a minimal prime over `I`. -- `Ideal.radical_minimalPrimes`: The minimal primes over `I.radical` are precisely - the minimal primes over `I`. -- `Ideal.sInf_minimalPrimes`: The intersection of minimal primes over `I` is `I.radical`. - `Ideal.exists_minimalPrimes_comap_eq` If `p` is a minimal prime over `f ⁻¹ I`, then it is the preimage of some minimal prime over `I`. - `Ideal.minimalPrimes_eq_comap`: The minimal primes over `I` are precisely the preimages of @@ -32,78 +26,7 @@ We provide various results concerning the minimal primes above an ideal section -variable {R S : Type*} [CommSemiring R] [CommSemiring S] (I J : Ideal R) - -/-- `I.minimalPrimes` is the set of ideals that are minimal primes over `I`. -/ -protected def Ideal.minimalPrimes : Set (Ideal R) := - {p | Minimal (fun q ↦ q.IsPrime ∧ I ≤ q) p} - -variable (R) in -/-- `minimalPrimes R` is the set of minimal primes of `R`. -This is defined as `Ideal.minimalPrimes ⊥`. -/ -def minimalPrimes : Set (Ideal R) := - Ideal.minimalPrimes ⊥ - -lemma minimalPrimes_eq_minimals : minimalPrimes R = {x | Minimal Ideal.IsPrime x} := - congr_arg Minimal (by simp) - -variable {I J} - -theorem Ideal.minimalPrimes_isPrime {p : Ideal R} (h : p ∈ I.minimalPrimes) : p.IsPrime := - h.1.1 - -theorem Ideal.exists_minimalPrimes_le [J.IsPrime] (e : I ≤ J) : ∃ p ∈ I.minimalPrimes, p ≤ J := by - set S := { p : (Ideal R)ᵒᵈ | Ideal.IsPrime p ∧ I ≤ OrderDual.ofDual p } - suffices h : ∃ m, OrderDual.toDual J ≤ m ∧ Maximal (· ∈ S) m by - obtain ⟨p, hJp, hp⟩ := h - exact ⟨p, ⟨hp.prop, fun q hq hle ↦ hp.le_of_ge hq hle⟩, hJp⟩ - apply zorn_le_nonempty₀ - swap - · refine ⟨show J.IsPrime by infer_instance, e⟩ - rintro (c : Set (Ideal R)) hc hc' J' hJ' - refine - ⟨OrderDual.toDual (sInf c), - ⟨Ideal.sInf_isPrime_of_isChain ⟨J', hJ'⟩ hc'.symm fun x hx => (hc hx).1, ?_⟩, ?_⟩ - · rw [OrderDual.ofDual_toDual, le_sInf_iff] - exact fun _ hx => (hc hx).2 - · rintro z hz - rw [OrderDual.le_toDual] - exact sInf_le hz - -theorem Ideal.nonempty_minimalPrimes (h : I ≠ ⊤) : Nonempty I.minimalPrimes := by - obtain ⟨m, hm, hle⟩ := Ideal.exists_le_maximal I h - obtain ⟨p, hp, -⟩ := Ideal.exists_minimalPrimes_le hle - exact ⟨p, hp⟩ - -theorem Ideal.eq_bot_of_minimalPrimes_eq_empty (h : I.minimalPrimes = ∅) : I = ⊤ := by - by_contra hI - obtain ⟨p, hp⟩ := Ideal.nonempty_minimalPrimes hI - exact Set.not_mem_empty p (h ▸ hp) - -@[simp] -theorem Ideal.radical_minimalPrimes : I.radical.minimalPrimes = I.minimalPrimes := by - rw [Ideal.minimalPrimes, Ideal.minimalPrimes] - ext p - refine ⟨?_, ?_⟩ <;> rintro ⟨⟨a, ha⟩, b⟩ - · refine ⟨⟨a, a.radical_le_iff.1 ha⟩, ?_⟩ - simp only [Set.mem_setOf_eq, and_imp] at * - exact fun _ h2 h3 h4 => b h2 (h2.radical_le_iff.2 h3) h4 - · refine ⟨⟨a, a.radical_le_iff.2 ha⟩, ?_⟩ - simp only [Set.mem_setOf_eq, and_imp] at * - exact fun _ h2 h3 h4 => b h2 (h2.radical_le_iff.1 h3) h4 - -@[simp] -theorem Ideal.sInf_minimalPrimes : sInf I.minimalPrimes = I.radical := by - rw [I.radical_eq_sInf] - apply le_antisymm - · intro x hx - rw [Ideal.mem_sInf] at hx ⊢ - rintro J ⟨e, hJ⟩ - obtain ⟨p, hp, hp'⟩ := Ideal.exists_minimalPrimes_le e - exact hp' (hx hp) - · apply sInf_le_sInf _ - intro I hI - exact hI.1.symm +variable {R S : Type*} [CommSemiring R] [CommSemiring S] {I J : Ideal R} theorem Ideal.iUnion_minimalPrimes : ⋃ p ∈ I.minimalPrimes, p = { x | ∃ y ∉ I.radical, x * y ∈ I.radical } := by @@ -255,22 +178,6 @@ theorem Ideal.minimalPrimes_eq_comap : rw [minimalPrimes, ← Ideal.comap_minimalPrimes_eq_of_surjective Ideal.Quotient.mk_surjective, ← RingHom.ker_eq_comap_bot, Ideal.mk_ker] -theorem Ideal.minimalPrimes_eq_subsingleton (hI : I.IsPrimary) : I.minimalPrimes = {I.radical} := by - ext J - constructor - · exact fun H => - let e := H.1.1.radical_le_iff.mpr H.1.2 - (H.2 ⟨Ideal.isPrime_radical hI, Ideal.le_radical⟩ e).antisymm e - · rintro (rfl : J = I.radical) - exact ⟨⟨Ideal.isPrime_radical hI, Ideal.le_radical⟩, fun _ H _ => H.1.radical_le_iff.mpr H.2⟩ - -theorem Ideal.minimalPrimes_eq_subsingleton_self [I.IsPrime] : I.minimalPrimes = {I} := by - ext J - constructor - · exact fun H => (H.2 ⟨inferInstance, rfl.le⟩ H.1.2).antisymm H.1.2 - · rintro (rfl : J = I) - exact ⟨⟨inferInstance, rfl.le⟩, fun _ h _ => h.2⟩ - end namespace Localization.AtPrime @@ -301,27 +208,3 @@ theorem nilpotent_iff_not_unit_of_minimal {x : Localization I.primeCompl} : simpa only [← IsLocalRing.mem_maximalIdeal] using nilpotent_iff_mem_maximal_of_minimal hMin end Localization.AtPrime - -section - -variable {R : Type*} [CommSemiring R] - -theorem Ideal.minimalPrimes_top : (⊤ : Ideal R).minimalPrimes = ∅ := by - ext p - simp only [Set.not_mem_empty, iff_false] - intro h - exact h.1.1.ne_top (top_le_iff.mp h.1.2) - -theorem Ideal.minimalPrimes_eq_empty_iff (I : Ideal R) : - I.minimalPrimes = ∅ ↔ I = ⊤ := by - constructor - · intro e - by_contra h - have ⟨M, hM, hM'⟩ := Ideal.exists_le_maximal I h - have ⟨p, hp⟩ := Ideal.exists_minimalPrimes_le hM' - rw [e] at hp - apply Set.not_mem_empty _ hp.1 - · rintro rfl - exact Ideal.minimalPrimes_top - -end diff --git a/Mathlib/RingTheory/KrullDimension/Basic.lean b/Mathlib/RingTheory/KrullDimension/Basic.lean index 13baff3915c07..d3c36feadac90 100644 --- a/Mathlib/RingTheory/KrullDimension/Basic.lean +++ b/Mathlib/RingTheory/KrullDimension/Basic.lean @@ -8,6 +8,7 @@ import Mathlib.Algebra.Polynomial.Basic import Mathlib.RingTheory.Ideal.Quotient.Defs import Mathlib.RingTheory.Spectrum.Prime.Basic import Mathlib.Order.KrullDimension +import Mathlib.RingTheory.Ideal.MinimalPrime.Basic /-! # Krull dimensions of (commutative) rings @@ -22,10 +23,14 @@ open Order /-- The ring theoretic Krull dimension is the Krull dimension of its spectrum ordered by inclusion. -/ -noncomputable def ringKrullDim (R : Type*) [CommRing R] : WithBot ℕ∞ := +noncomputable def ringKrullDim (R : Type*) [CommSemiring R] : WithBot ℕ∞ := krullDim (PrimeSpectrum R) -variable {R S : Type*} [CommRing R] [CommRing S] +/-- Type class for rings with krull dimension at most `n`. -/ +abbrev Ring.KrullDimLE (n : ℕ) (R : Type*) [CommSemiring R] : Prop := + Order.KrullDimLE n (PrimeSpectrum R) + +variable {R S : Type*} [CommSemiring R] [CommSemiring S] @[nontriviality] lemma ringKrullDim_eq_bot_of_subsingleton [Subsingleton R] : @@ -45,7 +50,7 @@ theorem ringKrullDim_le_of_surjective (f : R →+* S) (hf : Function.Surjective simpa using h)) /-- If `I` is an ideal of `R`, then `ringKrullDim (R ⧸ I) ≤ ringKrullDim R`. -/ -theorem ringKrullDim_quotient_le (I : Ideal R) : +theorem ringKrullDim_quotient_le {R : Type*} [CommRing R] (I : Ideal R) : ringKrullDim (R ⧸ I) ≤ ringKrullDim R := ringKrullDim_le_of_surjective _ Ideal.Quotient.mk_surjective @@ -63,3 +68,57 @@ proof_wanted Polynomial.ringKrullDim_le : proof_wanted MvPolynomial.fin_ringKrullDim_eq_add_of_isNoetherianRing [IsNoetherianRing R] (n : ℕ) : ringKrullDim (MvPolynomial (Fin n) R) = ringKrullDim R + n + +section Zero + +lemma Ring.krullDimLE_zero_iff : Ring.KrullDimLE 0 R ↔ ∀ I : Ideal R, I.IsPrime → I.IsMaximal := by + simp_rw [Ring.KrullDimLE, Order.krullDimLE_iff, Nat.cast_zero, + Order.krullDim_nonpos_iff_forall_isMax, + (PrimeSpectrum.equivSubtype R).forall_congr_left, Subtype.forall, PrimeSpectrum.isMax_iff] + rfl + +lemma Ring.KrullDimLE.mk₀ (H : ∀ I : Ideal R, I.IsPrime → I.IsMaximal) : Ring.KrullDimLE 0 R := by + rwa [Ring.krullDimLE_zero_iff] + +instance (priority := 100) Ideal.isMaximal_of_isPrime [Ring.KrullDimLE 0 R] + (I : Ideal R) [I.IsPrime] : I.IsMaximal := + Ring.krullDimLE_zero_iff.mp ‹_› I ‹_› + +end Zero + +section One + +lemma Ring.krullDimLE_one_iff : Ring.KrullDimLE 1 R ↔ + ∀ I : Ideal R, I.IsPrime → I ∈ minimalPrimes R ∨ I.IsMaximal := by + simp_rw [Ring.KrullDimLE, Order.krullDimLE_iff, Nat.cast_one, + Order.krullDim_le_one_iff, (PrimeSpectrum.equivSubtype R).forall_congr_left, + Subtype.forall, PrimeSpectrum.isMax_iff, PrimeSpectrum.isMin_iff] + rfl + +lemma Ring.KrullDimLE.mk₁ (H : ∀ I : Ideal R, I.IsPrime → I ∈ minimalPrimes R ∨ I.IsMaximal) : + Ring.KrullDimLE 1 R := by + rwa [Ring.krullDimLE_one_iff] + +lemma Ring.krullDimLE_one_iff_of_isPrime_bot [(⊥ : Ideal R).IsPrime] : + Ring.KrullDimLE 1 R ↔ ∀ I : Ideal R, I ≠ ⊥ → I.IsPrime → I.IsMaximal := by + letI : OrderBot (PrimeSpectrum R) := { bot := ⟨⊥, ‹_›⟩, bot_le I := bot_le (a := I.1) } + simp_rw [Ring.KrullDimLE, Order.krullDimLE_iff, Nat.cast_one, + Order.krullDim_le_one_iff_forall_isMax, (PrimeSpectrum.equivSubtype R).forall_congr_left, + Subtype.forall, PrimeSpectrum.isMax_iff, forall_comm (α := _ ≠ ⊥), + ne_eq, PrimeSpectrum.ext_iff] + rfl + +attribute [local instance] Ideal.bot_prime in +lemma Ring.krullDimLE_one_iff_of_isDomain [IsDomain R] : + Ring.KrullDimLE 1 R ↔ ∀ I : Ideal R, I ≠ ⊥ → I.IsPrime → I.IsMaximal := + Ring.krullDimLE_one_iff_of_isPrime_bot + +/-- Alternative constructor for `Ring.KrullDimLE 1`, convenient for domains. -/ +lemma Ring.KrullDimLE.mk₁' (H : ∀ I : Ideal R, I ≠ ⊥ → I.IsPrime → I.IsMaximal) : + Ring.KrullDimLE 1 R := by + by_cases hR : (⊥ : Ideal R).IsPrime + · rwa [Ring.krullDimLE_one_iff_of_isPrime_bot] + suffices Ring.KrullDimLE 0 R from .mono zero_le_one _ + exact .mk₀ fun I hI ↦ H I (fun e ↦ hR (e ▸ hI)) hI + +end One diff --git a/Mathlib/RingTheory/Spectrum/Prime/Basic.lean b/Mathlib/RingTheory/Spectrum/Prime/Basic.lean index 92132833e5f2f..61a117a6ee842 100644 --- a/Mathlib/RingTheory/Spectrum/Prime/Basic.lean +++ b/Mathlib/RingTheory/Spectrum/Prime/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin, Filippo A. E. Nuccio, Andrew Yang -/ import Mathlib.LinearAlgebra.Finsupp.SumProd +import Mathlib.RingTheory.Ideal.MinimalPrime.Basic import Mathlib.RingTheory.Ideal.Prod import Mathlib.RingTheory.Nilpotent.Lemmas import Mathlib.RingTheory.Noetherian.Basic @@ -404,6 +405,20 @@ instance {R : Type*} [Field R] : Unique (PrimeSpectrum R) where default := ⊥ uniq x := PrimeSpectrum.ext ((IsSimpleOrder.eq_bot_or_eq_top _).resolve_right x.2.ne_top) +/-- Also see `PrimeSpectrum.isClosed_singleton_iff_isMaximal` -/ +lemma isMax_iff {x : PrimeSpectrum R} : + IsMax x ↔ x.asIdeal.IsMaximal := by + refine ⟨fun hx ↦ ⟨⟨x.2.ne_top, fun I hI ↦ ?_⟩⟩, fun hx y e ↦ (hx.eq_of_le y.2.ne_top e).ge⟩ + by_contra e + obtain ⟨m, hm, hm'⟩ := Ideal.exists_le_maximal I e + exact hx.not_lt (show x < ⟨m, hm.isPrime⟩ from hI.trans_le hm') + +lemma isMin_iff {x : PrimeSpectrum R} : + IsMin x ↔ x.asIdeal ∈ minimalPrimes R := by + show IsMin _ ↔ Minimal (fun q : Ideal R ↦ q.IsPrime ∧ ⊥ ≤ q) _ + simp only [IsMin, Minimal, x.2, bot_le, and_self, and_true, true_and] + exact ⟨fun H y hy e ↦ @H ⟨y, hy⟩ e, fun H y e ↦ H y.2 e⟩ + end Order section Noetherian diff --git a/Mathlib/RingTheory/Spectrum/Prime/Topology.lean b/Mathlib/RingTheory/Spectrum/Prime/Topology.lean index 352cd2a76b48a..787204a3926ba 100644 --- a/Mathlib/RingTheory/Spectrum/Prime/Topology.lean +++ b/Mathlib/RingTheory/Spectrum/Prime/Topology.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin -/ import Mathlib.RingTheory.Finiteness.Ideal -import Mathlib.RingTheory.Ideal.MinimalPrime +import Mathlib.RingTheory.Ideal.MinimalPrime.Localization import Mathlib.RingTheory.Ideal.Over import Mathlib.RingTheory.KrullDimension.Basic import Mathlib.RingTheory.LocalRing.ResidueField.Defs @@ -794,26 +794,12 @@ protected def pointsEquivIrreducibleCloseds : map_rel_iff' {p q} := (RelIso.symm irreducibleSetEquivPoints).map_rel_iff.trans (le_iff_specializes p q).symm -/-- Also see `PrimeSpectrum.isClosed_singleton_iff_isMaximal` -/ -lemma isMax_iff {x : PrimeSpectrum R} : - IsMax x ↔ x.asIdeal.IsMaximal := by - refine ⟨fun hx ↦ ⟨⟨x.2.ne_top, fun I hI ↦ ?_⟩⟩, fun hx y e ↦ (hx.eq_of_le y.2.ne_top e).ge⟩ - by_contra e - obtain ⟨m, hm, hm'⟩ := Ideal.exists_le_maximal I e - exact hx.not_lt (show x < ⟨m, hm.isPrime⟩ from hI.trans_le hm') - lemma stableUnderSpecialization_singleton {x : PrimeSpectrum R} : StableUnderSpecialization {x} ↔ x.asIdeal.IsMaximal := by simp_rw [← isMax_iff, StableUnderSpecialization, ← le_iff_specializes, Set.mem_singleton_iff, @forall_comm _ (_ = _), forall_eq] exact ⟨fun H a h ↦ (H a h).le, fun H a h ↦ le_antisymm (H h) h⟩ -lemma isMin_iff {x : PrimeSpectrum R} : - IsMin x ↔ x.asIdeal ∈ minimalPrimes R := by - show IsMin _ ↔ Minimal (fun q : Ideal R ↦ q.IsPrime ∧ ⊥ ≤ q) _ - simp only [IsMin, Minimal, x.2, bot_le, and_self, and_true, true_and] - exact ⟨fun H y hy e ↦ @H ⟨y, hy⟩ e, fun H y e ↦ H y.2 e⟩ - lemma stableUnderGeneralization_singleton {x : PrimeSpectrum R} : StableUnderGeneralization {x} ↔ x.asIdeal ∈ minimalPrimes R := by simp_rw [← isMin_iff, StableUnderGeneralization, ← le_iff_specializes, Set.mem_singleton_iff, From ad7930c3f767a589b1fc696529af28a97f714308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Degenne?= Date: Wed, 5 Feb 2025 11:40:10 +0000 Subject: [PATCH 094/103] feat(Probability): first two derivatives of `cgf` (#21223) --- .../SpecialFunctions/Complex/Analytic.lean | 36 ++++ Mathlib/Probability/Moments/Basic.lean | 5 +- Mathlib/Probability/Moments/MGFAnalytic.lean | 157 ++++++++++++++++-- 3 files changed, 185 insertions(+), 13 deletions(-) diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/Analytic.lean b/Mathlib/Analysis/SpecialFunctions/Complex/Analytic.lean index aec0cfaa5eab1..708d78cdedd9e 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/Analytic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/Analytic.lean @@ -78,10 +78,12 @@ section ReOfReal variable {f : ℂ → ℂ} {s : Set ℝ} {x : ℝ} +@[fun_prop] lemma AnalyticAt.re_ofReal (hf : AnalyticAt ℂ f x) : AnalyticAt ℝ (fun x : ℝ ↦ (f x).re) x := (Complex.reCLM.analyticAt _).comp (hf.restrictScalars.comp (Complex.ofRealCLM.analyticAt _)) +@[fun_prop] lemma AnalyticAt.im_ofReal (hf : AnalyticAt ℂ f x) : AnalyticAt ℝ (fun x : ℝ ↦ (f x).im) x := (Complex.imCLM.analyticAt _).comp (hf.restrictScalars.comp (Complex.ofRealCLM.analyticAt _)) @@ -117,3 +119,37 @@ lemma AnalyticOnNhd.im_ofReal (hf : AnalyticOnNhd ℂ f (ofReal '' s)) : (Complex.ofRealCLM.analyticOnNhd _) (mapsTo_image ofReal s) end ReOfReal + +section Real + +variable {f : ℝ → ℝ} {s : Set ℝ} {x : ℝ} + +@[fun_prop] +lemma analyticAt_log (hx : 0 < x) : AnalyticAt ℝ Real.log x := by + have : Real.log = fun x : ℝ ↦ (Complex.log x).re := by ext x; exact (Complex.log_ofReal_re x).symm + rw [this] + refine AnalyticAt.re_ofReal <| analyticAt_clog ?_ + simp [hx] + +lemma analyticOnNhd_log : AnalyticOnNhd ℝ Real.log (Set.Ioi 0) := fun _ hx ↦ analyticAt_log hx + +lemma analyticOn_log : AnalyticOn ℝ Real.log (Set.Ioi 0) := analyticOnNhd_log.analyticOn + +@[fun_prop] +lemma AnalyticAt.log (fa : AnalyticAt ℝ f x) (m : 0 < f x) : + AnalyticAt ℝ (fun z ↦ Real.log (f z)) x := + (analyticAt_log m).comp fa + +lemma AnalyticWithinAt.log (fa : AnalyticWithinAt ℝ f s x) (m : 0 < f x) : + AnalyticWithinAt ℝ (fun z ↦ Real.log (f z)) s x := + (analyticAt_log m).comp_analyticWithinAt fa + +lemma AnalyticOnNhd.log (fs : AnalyticOnNhd ℝ f s) (m : ∀ x ∈ s, 0 < f x) : + AnalyticOnNhd ℝ (fun z ↦ Real.log (f z)) s := + fun z n ↦ (analyticAt_log (m z n)).comp (fs z n) + +lemma AnalyticOn.log (fs : AnalyticOn ℝ f s) (m : ∀ x ∈ s, 0 < f x) : + AnalyticOn ℝ (fun z ↦ Real.log (f z)) s := + fun z n ↦ (analyticAt_log (m z n)).analyticWithinAt.comp (fs z n) m + +end Real diff --git a/Mathlib/Probability/Moments/Basic.lean b/Mathlib/Probability/Moments/Basic.lean index 77fdebb9480ab..d5ff05a1eac13 100644 --- a/Mathlib/Probability/Moments/Basic.lean +++ b/Mathlib/Probability/Moments/Basic.lean @@ -114,11 +114,10 @@ theorem mgf_zero_fun : mgf 0 μ t = (μ Set.univ).toReal := by theorem cgf_zero_fun : cgf 0 μ t = log (μ Set.univ).toReal := by simp only [cgf, mgf_zero_fun] @[simp] -theorem mgf_zero_measure : mgf X (0 : Measure Ω) t = 0 := by simp only [mgf, integral_zero_measure] +theorem mgf_zero_measure : mgf X (0 : Measure Ω) = 0 := by ext; simp [mgf] @[simp] -theorem cgf_zero_measure : cgf X (0 : Measure Ω) t = 0 := by - simp only [cgf, log_zero, mgf_zero_measure] +theorem cgf_zero_measure : cgf X (0 : Measure Ω) = 0 := by ext; simp [cgf] @[simp] theorem mgf_const' (c : ℝ) : mgf (fun _ => c) μ t = (μ Set.univ).toReal * exp (t * c) := by diff --git a/Mathlib/Probability/Moments/MGFAnalytic.lean b/Mathlib/Probability/Moments/MGFAnalytic.lean index 57f5d8242d2e6..9181a453dddd3 100644 --- a/Mathlib/Probability/Moments/MGFAnalytic.lean +++ b/Mathlib/Probability/Moments/MGFAnalytic.lean @@ -18,6 +18,9 @@ is analytic on the interior of `integrableExpSet X μ`, the interval on which it on which it is defined. * `iteratedDeriv_mgf`: the n-th derivative of the mgf at `t` is `μ[X ^ n * exp (t * X)]`. +* `analyticOn_cgf`: the cumulant generating function is analytic on the interior of the interval + `integrableExpSet X μ`. + -/ @@ -29,25 +32,25 @@ namespace ProbabilityTheory variable {Ω ι : Type*} {m : MeasurableSpace Ω} {X : Ω → ℝ} {μ : Measure Ω} {t u v : ℝ} -section Deriv - /-- For `t : ℝ` with `t ∈ interior (integrableExpSet X μ)`, the derivative of the function -`x ↦ μ[X ^ n * rexp (x * X)]` at `t` is `μ[X ^ (n + 1) * rexp (t * X)]`. -/ +`x ↦ μ[X ^ n * exp (x * X)]` at `t` is `μ[X ^ (n + 1) * exp (t * X)]`. -/ lemma hasDerivAt_integral_pow_mul_exp_real (ht : t ∈ interior (integrableExpSet X μ)) (n : ℕ) : - HasDerivAt (fun t ↦ μ[fun ω ↦ X ω ^ n * rexp (t * X ω)]) - μ[fun ω ↦ X ω ^ (n + 1) * rexp (t * X ω)] t := by + HasDerivAt (fun t ↦ μ[fun ω ↦ X ω ^ n * exp (t * X ω)]) + μ[fun ω ↦ X ω ^ (n + 1) * exp (t * X ω)] t := by have h_re_of_mem n t (ht' : t ∈ interior (integrableExpSet X μ)) : - (∫ ω, X ω ^ n * Complex.exp (t * X ω) ∂μ).re = ∫ ω, X ω ^ n * rexp (t * X ω) ∂μ := by + (∫ ω, X ω ^ n * Complex.exp (t * X ω) ∂μ).re = ∫ ω, X ω ^ n * exp (t * X ω) ∂μ := by rw [← RCLike.re_eq_complex_re, ← integral_re] · norm_cast · refine integrable_pow_mul_cexp_of_re_mem_interior_integrableExpSet ?_ n simpa using ht' have h_re n : ∀ᶠ t' : ℝ in 𝓝 t, (∫ ω, X ω ^ n * Complex.exp (t' * X ω) ∂μ).re - = ∫ ω, X ω ^ n * rexp (t' * X ω) ∂μ := by + = ∫ ω, X ω ^ n * exp (t' * X ω) ∂μ := by filter_upwards [isOpen_interior.eventually_mem ht] with t ht' using h_re_of_mem n t ht' rw [← EventuallyEq.hasDerivAt_iff (h_re _), ← h_re_of_mem _ t ht] exact (hasDerivAt_integral_pow_mul_exp (by simp [ht]) n).real_of_complex +section DerivMGF + /-- For `t ∈ interior (integrableExpSet X μ)`, the derivative of `mgf X μ` at `t` is `μ[X * exp (t * X)]`. -/ lemma hasDerivAt_mgf (h : t ∈ interior (integrableExpSet X μ)) : @@ -94,9 +97,9 @@ lemma deriv_mgf (h : t ∈ interior (integrableExpSet X μ)) : lemma deriv_mgf_zero (h : 0 ∈ interior (integrableExpSet X μ)) : deriv (mgf X μ) 0 = μ[X] := by simp [deriv_mgf h] -end Deriv +end DerivMGF -section Analytic +section AnalyticMGF /-- The moment generating function is analytic at every `t ∈ interior (integrableExpSet X μ)`. -/ lemma analyticAt_mgf (ht : t ∈ interior (integrableExpSet X μ)) : @@ -119,6 +122,140 @@ lemma hasFPowerSeriesAt_mgf (hv : v ∈ interior (integrableExpSet X μ)) : convert (analyticAt_mgf hv).hasFPowerSeriesAt rw [iteratedDeriv_mgf hv] -end Analytic +lemma differentiableAt_mgf (ht : t ∈ interior (integrableExpSet X μ)) : + DifferentiableAt ℝ (mgf X μ) t := (analyticAt_mgf ht).differentiableAt + +lemma analyticOnNhd_iteratedDeriv_mgf (n : ℕ) : + AnalyticOnNhd ℝ (iteratedDeriv n (mgf X μ)) (interior (integrableExpSet X μ)) := by + rw [iteratedDeriv_eq_iterate] + exact analyticOnNhd_mgf.iterated_deriv n + +lemma analyticOn_iteratedDeriv_mgf (n : ℕ) : + AnalyticOn ℝ (iteratedDeriv n (mgf X μ)) (interior (integrableExpSet X μ)) := + (analyticOnNhd_iteratedDeriv_mgf n).analyticOn + +lemma analyticAt_iteratedDeriv_mgf (hv : v ∈ interior (integrableExpSet X μ)) (n : ℕ) : + AnalyticAt ℝ (iteratedDeriv n (mgf X μ)) v := + analyticOnNhd_iteratedDeriv_mgf n v hv + +lemma differentiableAt_iteratedDeriv_mgf (hv : v ∈ interior (integrableExpSet X μ)) (n : ℕ) : + DifferentiableAt ℝ (iteratedDeriv n (mgf X μ)) v := + (analyticAt_iteratedDeriv_mgf hv n).differentiableAt + +end AnalyticMGF + +section AnalyticCGF + +lemma analyticAt_cgf (h : v ∈ interior (integrableExpSet X μ)) : AnalyticAt ℝ (cgf X μ) v := by + by_cases hμ : μ = 0 + · simp only [hμ, cgf_zero_measure] + exact analyticAt_const + · exact (analyticAt_mgf h).log <| mgf_pos' hμ (interior_subset (s := integrableExpSet X μ) h) + +lemma analyticOnNhd_cgf : AnalyticOnNhd ℝ (cgf X μ) (interior (integrableExpSet X μ)) := + fun _ hx ↦ analyticAt_cgf hx + +/-- The cumulant generating function is analytic on the interior of the interval + `integrableExpSet X μ`. -/ +lemma analyticOn_cgf : AnalyticOn ℝ (cgf X μ) (interior (integrableExpSet X μ)) := + analyticOnNhd_cgf.analyticOn + +end AnalyticCGF + +section DerivCGF + +lemma deriv_cgf (h : v ∈ interior (integrableExpSet X μ)) : + deriv (cgf X μ) v = μ[fun ω ↦ X ω * exp (v * X ω)] / mgf X μ v := by + by_cases hμ : μ = 0 + · simp only [hμ, cgf_zero_measure, integral_zero_measure, mgf_zero_measure, div_zero, + Pi.zero_apply] + exact deriv_const v 0 + have hv : Integrable (fun ω ↦ exp (v * X ω)) μ := interior_subset (s := integrableExpSet X μ) h + calc deriv (fun x ↦ log (mgf X μ x)) v + _ = deriv (mgf X μ) v / mgf X μ v := by + rw [deriv.log (differentiableAt_mgf h) ((mgf_pos' hμ hv).ne')] + _ = μ[fun ω ↦ X ω * exp (v * X ω)] / mgf X μ v := by rw [deriv_mgf h] + +lemma deriv_cgf_zero (h : 0 ∈ interior (integrableExpSet X μ)) : + deriv (cgf X μ) 0 = μ[X] / (μ Set.univ).toReal := by simp [deriv_cgf h] + +lemma iteratedDeriv_two_cgf (h : v ∈ interior (integrableExpSet X μ)) : + iteratedDeriv 2 (cgf X μ) v + = μ[fun ω ↦ (X ω)^2 * exp (v * X ω)] / mgf X μ v - deriv (cgf X μ) v ^ 2 := by + rw [iteratedDeriv_succ, iteratedDeriv_one] + by_cases hμ : μ = 0 + · have : deriv (0 : ℝ → ℝ) = 0 := by ext; exact deriv_const _ 0 + simp [hμ, this] + have h_mem : ∀ᶠ y in 𝓝 v, y ∈ interior (integrableExpSet X μ) := + isOpen_interior.eventually_mem h + have h_d_cgf : deriv (cgf X μ) =ᶠ[𝓝 v] fun u ↦ μ[fun ω ↦ X ω * exp (u * X ω)] / mgf X μ u := by + filter_upwards [h_mem] with u hu using deriv_cgf hu + have h_d_mgf : deriv (mgf X μ) =ᶠ[𝓝 v] fun u ↦ μ[fun ω ↦ X ω * exp (u * X ω)] := by + filter_upwards [h_mem] with u hu using deriv_mgf hu + rw [h_d_cgf.deriv_eq] + calc deriv (fun u ↦ (∫ ω, X ω * exp (u * X ω) ∂μ) / mgf X μ u) v + _ = (deriv (fun u ↦ ∫ ω, X ω * exp (u * X ω) ∂μ) v * mgf X μ v - + (∫ ω, X ω * exp (v * X ω) ∂μ) * deriv (mgf X μ) v) / mgf X μ v ^ 2 := by + rw [deriv_div] + · rw [h_d_mgf.symm.differentiableAt_iff, ← iteratedDeriv_one] + exact differentiableAt_iteratedDeriv_mgf h 1 + · exact differentiableAt_mgf h + · exact (mgf_pos' hμ (interior_subset (s := integrableExpSet X μ) h)).ne' + _ = (deriv (fun u ↦ ∫ ω, X ω * exp (u * X ω) ∂μ) v * mgf X μ v - + (∫ ω, X ω * exp (v * X ω) ∂μ) * ∫ ω, X ω * exp (v * X ω) ∂μ) / mgf X μ v ^ 2 := by + rw [deriv_mgf h] + _ = deriv (fun u ↦ ∫ ω, X ω * exp (u * X ω) ∂μ) v / mgf X μ v - deriv (cgf X μ) v ^ 2 := by + rw [sub_div] + congr 1 + · rw [pow_two, div_mul_eq_div_div, mul_div_assoc, div_self, mul_one] + exact (mgf_pos' hμ (interior_subset (s := integrableExpSet X μ) h)).ne' + · rw [deriv_cgf h] + ring + _ = (∫ ω, (X ω) ^ 2 * exp (v * X ω) ∂μ) / mgf X μ v - deriv (cgf X μ) v ^ 2 := by + congr + convert (hasDerivAt_integral_pow_mul_exp_real h 1).deriv using 1 + simp + +lemma iteratedDeriv_two_cgf_eq_integral (h : v ∈ interior (integrableExpSet X μ)) : + iteratedDeriv 2 (cgf X μ) v + = μ[fun ω ↦ (X ω - deriv (cgf X μ) v)^2 * exp (v * X ω)] / mgf X μ v := by + by_cases hμ : μ = 0 + · have : deriv (0 : ℝ → ℝ) = 0 := by ext; exact deriv_const _ 0 + simp [hμ, this, iteratedDeriv_succ] + rw [iteratedDeriv_two_cgf h] + calc (∫ ω, (X ω) ^ 2 * exp (v * X ω) ∂μ) / mgf X μ v - deriv (cgf X μ) v ^ 2 + _ = (∫ ω, (X ω) ^ 2 * exp (v * X ω) ∂μ - 2 * (∫ ω, X ω * exp (v * X ω) ∂μ) * deriv (cgf X μ) v + + deriv (cgf X μ) v ^ 2 * mgf X μ v) / mgf X μ v := by + rw [add_div, sub_div, sub_add] + congr 1 + rw [mul_div_cancel_right₀, deriv_cgf h] + · ring + · exact (mgf_pos' hμ (interior_subset (s := integrableExpSet X μ) h)).ne' + _ = (∫ ω, ((X ω) ^ 2 - 2 * X ω * deriv (cgf X μ) v + deriv (cgf X μ) v ^ 2) * exp (v * X ω) ∂μ) + / mgf X μ v := by + congr 1 + simp_rw [add_mul, sub_mul] + have h_int : Integrable (fun ω ↦ 2 * X ω * deriv (cgf X μ) v * exp (v * X ω)) μ := by + simp_rw [mul_assoc, mul_comm (deriv (cgf X μ) v)] + refine Integrable.const_mul ?_ _ + simp_rw [← mul_assoc] + refine Integrable.mul_const ?_ _ + convert integrable_pow_mul_exp_of_mem_interior_integrableExpSet h 1 + simp + rw [integral_add] + rotate_left + · exact (integrable_pow_mul_exp_of_mem_interior_integrableExpSet h 2).sub h_int + · exact (interior_subset (s := integrableExpSet X μ) h).const_mul _ + rw [integral_sub (integrable_pow_mul_exp_of_mem_interior_integrableExpSet h 2) h_int] + congr + · rw [← integral_mul_left, ← integral_mul_right] + congr with ω + ring + · rw [integral_mul_left, mgf] + _ = (∫ ω, (X ω - deriv (cgf X μ) v) ^ 2 * exp (v * X ω) ∂μ) / mgf X μ v := by + congr with ω + ring + +end DerivCGF end ProbabilityTheory From 0ab778078424767adb0b8dbb8e6b12d541f93506 Mon Sep 17 00:00:00 2001 From: JovanGerb Date: Wed, 5 Feb 2025 12:55:14 +0000 Subject: [PATCH 095/103] perf(RingTheory/Artinian): reorder arguments in `IsArtinianRing.isMaximal_of_isPrime` (#21449) Reordering the arguments flips the type class synthesis order, so that it fails more quickly when there is no instance. https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/Strange.20simpNF.20error.20.22at.20a.20distance.22/near/497687170 --- Mathlib/RingTheory/Artinian/Module.lean | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Mathlib/RingTheory/Artinian/Module.lean b/Mathlib/RingTheory/Artinian/Module.lean index 17341d196f991..afbbcfb181333 100644 --- a/Mathlib/RingTheory/Artinian/Module.lean +++ b/Mathlib/RingTheory/Artinian/Module.lean @@ -485,7 +485,10 @@ lemma isField_of_isDomain [IsDomain R] : IsField R := by /- Does not hold in a commutative semiring: consider {0, 0.5, 1} with ⊔ as + and ⊓ as *, then both {0} and {0, 0.5} are prime ideals. -/ -instance isMaximal_of_isPrime (p : Ideal R) [p.IsPrime] : p.IsMaximal := +-- Note: type class synthesis should try to synthesize `p.IsPrime` before `IsArtinianRing R`, +-- hence the argument order. +instance isMaximal_of_isPrime {R : Type*} [CommRing R] (p : Ideal R) [p.IsPrime] + [IsArtinianRing R] : p.IsMaximal := Ideal.Quotient.maximal_of_isField _ (isField_of_isDomain _) lemma isPrime_iff_isMaximal (p : Ideal R) : p.IsPrime ↔ p.IsMaximal := From 6cfdcb3a36987c334499899e69612df43a3c8113 Mon Sep 17 00:00:00 2001 From: grunweg Date: Wed, 5 Feb 2025 14:21:27 +0000 Subject: [PATCH 096/103] doc: document design choice of (AE)StronglyMeasurable.enorm and `edist` (#21423) It intentionally only proves (a.e.) measurability, not (a.e.) strong measurability. Discovered while generalising lemmas to enormed spaces, for the Carleson project. --- .../AEStronglyMeasurable.lean | 17 ++++++++++++++--- .../Function/StronglyMeasurable/Basic.lean | 7 ++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Mathlib/MeasureTheory/Function/StronglyMeasurable/AEStronglyMeasurable.lean b/Mathlib/MeasureTheory/Function/StronglyMeasurable/AEStronglyMeasurable.lean index 961c4dfeeb999..86427fc95c7c2 100644 --- a/Mathlib/MeasureTheory/Function/StronglyMeasurable/AEStronglyMeasurable.lean +++ b/Mathlib/MeasureTheory/Function/StronglyMeasurable/AEStronglyMeasurable.lean @@ -429,14 +429,25 @@ protected theorem nnnorm {β : Type*} [SeminormedAddCommGroup β] {f : α → β (hf : AEStronglyMeasurable f μ) : AEStronglyMeasurable (fun x => ‖f x‖₊) μ := continuous_nnnorm.comp_aestronglyMeasurable hf -@[measurability] +/-- The `enorm` of a strongly a.e. measurable function is a.e. measurable. + +Note that unlike `AEStrongMeasurable.norm` and `AEStronglyMeasurable.nnnorm`, this lemma proves +a.e. measurability, **not** a.e. strong measurability. This is an intentional decision: +for functions taking values in ℝ≥0∞, a.e. measurability is much more useful than +a.e. strong measurability. -/ +@[fun_prop, measurability] protected theorem enorm {β : Type*} [SeminormedAddCommGroup β] {f : α → β} (hf : AEStronglyMeasurable f μ) : AEMeasurable (‖f ·‖ₑ) μ := - (ENNReal.continuous_coe.comp_aestronglyMeasurable hf.nnnorm).aemeasurable + (continuous_enorm.comp_aestronglyMeasurable hf).aemeasurable @[deprecated (since := "2025-01-20")] alias ennnorm := AEStronglyMeasurable.enorm -@[aesop safe 20 apply (rule_sets := [Measurable])] +/-- Given a.e. strongly measurable functions `f` and `g`, `edist f g` is measurable. + +Note that this lemma proves a.e. measurability, **not** a.e. strong measurability. +This is an intentional decision: for functions taking values in ℝ≥0∞, +a.e. measurability is much more useful than a.e. strong measurability. -/ +@[aesop safe 20 apply (rule_sets := [Measurable]), fun_prop] protected theorem edist {β : Type*} [SeminormedAddCommGroup β] {f g : α → β} (hf : AEStronglyMeasurable f μ) (hg : AEStronglyMeasurable g μ) : AEMeasurable (fun a => edist (f a) (g a)) μ := diff --git a/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean b/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean index cbe0a39e7bd91..6cc4dededea26 100644 --- a/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean +++ b/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean @@ -775,7 +775,12 @@ protected theorem nnnorm {_ : MeasurableSpace α} {β : Type*} [SeminormedAddCom (hf : StronglyMeasurable f) : StronglyMeasurable fun x => ‖f x‖₊ := continuous_nnnorm.comp_stronglyMeasurable hf -@[measurability] +/-- The `enorm` of a strongly measurable function is measurable. + +Unlike `StrongMeasurable.norm` and `StronglyMeasurable.nnnorm`, this lemma proves measurability, +**not** strong measurability. This is an intentional decision: for functions taking values in +ℝ≥0∞, measurability is much more useful than strong measurability. -/ +@[fun_prop, measurability] protected theorem enorm {_ : MeasurableSpace α} {β : Type*} [SeminormedAddCommGroup β] {f : α → β} (hf : StronglyMeasurable f) : Measurable (‖f ·‖ₑ) := (ENNReal.continuous_coe.comp_stronglyMeasurable hf.nnnorm).measurable From d6eaa9a04735d65fd71484fa836b0824af9356c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Dvo=C5=99=C3=A1k?= Date: Wed, 5 Feb 2025 14:36:49 +0000 Subject: [PATCH 097/103] style(Logic/Embedding/Set): unindent (#21457) --- Mathlib/Logic/Embedding/Set.lean | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Mathlib/Logic/Embedding/Set.lean b/Mathlib/Logic/Embedding/Set.lean index 1c85ef2c28d32..0a0e0d999f822 100644 --- a/Mathlib/Logic/Embedding/Set.lean +++ b/Mathlib/Logic/Embedding/Set.lean @@ -107,17 +107,17 @@ def subtypeOrEquiv (p q : α → Prop) [DecidablePred p] (h : Disjoint p q) : right_inv x := by cases x with | inl x => - simp only [Sum.elim_inl] - rw [subtypeOrLeftEmbedding_apply_left] - · simp - · simpa using x.prop + simp only [Sum.elim_inl] + rw [subtypeOrLeftEmbedding_apply_left] + · simp + · simpa using x.prop | inr x => - simp only [Sum.elim_inr] - rw [subtypeOrLeftEmbedding_apply_right] - · simp - · suffices ¬p x by simpa - intro hp - simpa using h.le_bot x ⟨hp, x.prop⟩ + simp only [Sum.elim_inr] + rw [subtypeOrLeftEmbedding_apply_right] + · simp + · suffices ¬p x by simpa + intro hp + simpa using h.le_bot x ⟨hp, x.prop⟩ @[simp] theorem subtypeOrEquiv_symm_inl (p q : α → Prop) [DecidablePred p] (h : Disjoint p q) From fd7df666f1587c9294d5d364519b088b2f3fb790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Dvo=C5=99=C3=A1k?= Date: Wed, 5 Feb 2025 14:36:50 +0000 Subject: [PATCH 098/103] docs(Logic/Function/Defs): missing backticks (#21459) --- Mathlib/Logic/Function/Defs.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Logic/Function/Defs.lean b/Mathlib/Logic/Function/Defs.lean index 79adace923e87..0a3d3d7b55de8 100644 --- a/Mathlib/Logic/Function/Defs.lean +++ b/Mathlib/Logic/Function/Defs.lean @@ -85,7 +85,7 @@ def Bijective (f : α → β) := theorem Bijective.comp {g : β → φ} {f : α → β} : Bijective g → Bijective f → Bijective (g ∘ f) | ⟨h_ginj, h_gsurj⟩, ⟨h_finj, h_fsurj⟩ => ⟨h_ginj.comp h_finj, h_gsurj.comp h_fsurj⟩ -/-- `LeftInverse g f` means that g is a left inverse to f. That is, `g ∘ f = id`. -/ +/-- `LeftInverse g f` means that `g` is a left inverse to `f`. That is, `g ∘ f = id`. -/ def LeftInverse (g : β → α) (f : α → β) : Prop := ∀ x, g (f x) = x @@ -93,7 +93,7 @@ def LeftInverse (g : β → α) (f : α → β) : Prop := def HasLeftInverse (f : α → β) : Prop := ∃ finv : β → α, LeftInverse finv f -/-- `RightInverse g f` means that g is a right inverse to f. That is, `f ∘ g = id`. -/ +/-- `RightInverse g f` means that `g` is a right inverse to `f`. That is, `f ∘ g = id`. -/ def RightInverse (g : β → α) (f : α → β) : Prop := LeftInverse f g From 6b45fb55e5b125ef2fbd254c618f8a2f022c6314 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Wed, 5 Feb 2025 15:13:17 +0000 Subject: [PATCH 099/103] chore(LinearAlgebra/TensorProduct): upgrade `TensorProduct.prodRight` (#21432) ... to a linear map over an `R`-algebra `S`. Co-authored-by: Christian Merten <136261474+chrisflav@users.noreply.github.com> --- Mathlib/Algebra/Module/Equiv/Defs.lean | 4 ++ Mathlib/LinearAlgebra/TensorProduct/Prod.lean | 43 ++++++++++--------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/Mathlib/Algebra/Module/Equiv/Defs.lean b/Mathlib/Algebra/Module/Equiv/Defs.lean index e2acc6cc59c16..92aaa242e4352 100644 --- a/Mathlib/Algebra/Module/Equiv/Defs.lean +++ b/Mathlib/Algebra/Module/Equiv/Defs.lean @@ -310,6 +310,10 @@ variable {e₁₂} {e₂₃} theorem coe_toAddEquiv : e.toAddEquiv = e := rfl +@[simp] +lemma coe_addEquiv_apply (x : M) : (e : M ≃+ M₂) x = e x := by + rfl + /-- The two paths coercion can take to an `AddMonoidHom` are equivalent -/ theorem toAddMonoidHom_commutes : e.toLinearMap.toAddMonoidHom = e.toAddEquiv.toAddMonoidHom := rfl diff --git a/Mathlib/LinearAlgebra/TensorProduct/Prod.lean b/Mathlib/LinearAlgebra/TensorProduct/Prod.lean index 70179a735dc31..32882dffac235 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/Prod.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/Prod.lean @@ -3,8 +3,8 @@ 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.LinearAlgebra.TensorProduct.Basic import Mathlib.LinearAlgebra.Prod +import Mathlib.LinearAlgebra.TensorProduct.Tower /-! # Tensor products of products @@ -22,50 +22,53 @@ See `Mathlib.LinearAlgebra.TensorProduct.Pi` for arbitrary products. -/ -universe uR uM₁ uM₂ uM₃ -variable (R : Type uR) (M₁ : Type uM₁) (M₂ : Type uM₂) (M₃ : Type uM₃) +variable (R S M₁ M₂ M₃ : Type*) suppress_compilation namespace TensorProduct -variable [CommSemiring R] [AddCommMonoid M₁] [AddCommMonoid M₂] [AddCommMonoid M₃] -variable [Module R M₁] [Module R M₂] [Module R M₃] +variable [CommSemiring R] [Semiring S] [AddCommMonoid M₁] [AddCommMonoid M₂] [AddCommMonoid M₃] +variable [Algebra R S] +variable [Module R M₁] [Module S M₁] [IsScalarTower R S M₁] [Module R M₂] [Module R M₃] attribute [ext] TensorProduct.ext /-- Tensor products distribute over a product on the right. -/ -def prodRight : M₁ ⊗[R] (M₂ × M₃) ≃ₗ[R] ((M₁ ⊗[R] M₂) × (M₁ ⊗[R] M₃)) := +def prodRight : M₁ ⊗[R] (M₂ × M₃) ≃ₗ[S] (M₁ ⊗[R] M₂) × (M₁ ⊗[R] M₃) := LinearEquiv.ofLinear - (lift <| - LinearMap.prodMapLinear R M₂ M₃ (M₁ ⊗[R] M₂) (M₁ ⊗[R] M₃) R - ∘ₗ LinearMap.prod (mk _ _ _) (mk _ _ _)) + (TensorProduct.AlgebraTensorModule.lift <| + LinearMap.prodMapLinear R M₂ M₃ (M₁ ⊗[R] M₂) (M₁ ⊗[R] M₃) S ∘ₗ + LinearMap.prod (AlgebraTensorModule.mk R S M₁ M₂) (AlgebraTensorModule.mk R S M₁ M₃)) (LinearMap.coprod - (LinearMap.lTensor _ <| LinearMap.inl _ _ _) - (LinearMap.lTensor _ <| LinearMap.inr _ _ _)) + (AlgebraTensorModule.lTensor _ _ <| LinearMap.inl _ _ _) + (AlgebraTensorModule.lTensor _ _ <| LinearMap.inr _ _ _)) (by ext <;> simp) (by ext <;> simp) -@[simp] theorem prodRight_tmul (m₁ : M₁) (m₂ : M₂) (m₃ : M₃) : - prodRight R M₁ M₂ M₃ (m₁ ⊗ₜ (m₂, m₃)) = (m₁ ⊗ₜ m₂, m₁ ⊗ₜ m₃) := +@[simp] theorem prodRight_tmul (m₁ : M₁) (m : M₂ × M₃) : + prodRight R S M₁ M₂ M₃ (m₁ ⊗ₜ m) = (m₁ ⊗ₜ m.1, m₁ ⊗ₜ m.2) := rfl @[simp] theorem prodRight_symm_tmul (m₁ : M₁) (m₂ : M₂) (m₃ : M₃) : - (prodRight R M₁ M₂ M₃).symm (m₁ ⊗ₜ m₂, m₁ ⊗ₜ m₃) = (m₁ ⊗ₜ (m₂, m₃)) := + (prodRight R S M₁ M₂ M₃).symm (m₁ ⊗ₜ m₂, m₁ ⊗ₜ m₃) = (m₁ ⊗ₜ (m₂, m₃)) := (LinearEquiv.symm_apply_eq _).mpr rfl +variable [Module S M₂] [IsScalarTower R S M₂] + /-- Tensor products distribute over a product on the left . -/ -def prodLeft : (M₁ × M₂) ⊗[R] M₃ ≃ₗ[R] ((M₁ ⊗[R] M₃) × (M₂ ⊗[R] M₃)) := - TensorProduct.comm _ _ _ - ≪≫ₗ TensorProduct.prodRight R _ _ _ - ≪≫ₗ (TensorProduct.comm R _ _).prod (TensorProduct.comm R _ _) +def prodLeft : (M₁ × M₂) ⊗[R] M₃ ≃ₗ[S] (M₁ ⊗[R] M₃) × (M₂ ⊗[R] M₃) := + AddEquiv.toLinearEquiv (TensorProduct.comm _ _ _ ≪≫ₗ + TensorProduct.prodRight R R _ _ _ ≪≫ₗ + (TensorProduct.comm R _ _).prod (TensorProduct.comm R _ _)).toAddEquiv + fun c x ↦ x.induction_on (by simp) (by simp [TensorProduct.smul_tmul']) (by simp_all) @[simp] theorem prodLeft_tmul (m₁ : M₁) (m₂ : M₂) (m₃ : M₃) : - prodLeft R M₁ M₂ M₃ ((m₁, m₂) ⊗ₜ m₃) = (m₁ ⊗ₜ m₃, m₂ ⊗ₜ m₃) := + prodLeft R S M₁ M₂ M₃ ((m₁, m₂) ⊗ₜ m₃) = (m₁ ⊗ₜ m₃, m₂ ⊗ₜ m₃) := rfl @[simp] theorem prodLeft_symm_tmul (m₁ : M₁) (m₂ : M₂) (m₃ : M₃) : - (prodLeft R M₁ M₂ M₃).symm (m₁ ⊗ₜ m₃, m₂ ⊗ₜ m₃) = ((m₁, m₂) ⊗ₜ m₃) := + (prodLeft R S M₁ M₂ M₃).symm (m₁ ⊗ₜ m₃, m₂ ⊗ₜ m₃) = ((m₁, m₂) ⊗ₜ m₃) := (LinearEquiv.symm_apply_eq _).mpr rfl end TensorProduct From 3eb0ff709449ce0401b0032e17d61dd0f5d51b46 Mon Sep 17 00:00:00 2001 From: Xavier Roblot Date: Wed, 5 Feb 2025 15:13:18 +0000 Subject: [PATCH 100/103] chore(Algebra/Field/Basic): make some arguments implicit (#21453) Make the first three arguments of `sub_div'` and `div_sub'` implicit. Note that these arguments were (almost) never explicitly provided whenever these functions were used. --- Mathlib/Algebra/Field/Basic.lean | 4 ++-- Mathlib/Analysis/SpecialFunctions/Gamma/BohrMollerup.lean | 2 +- Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean | 2 +- Mathlib/Data/Real/Pi/Wallis.lean | 2 +- Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean | 2 +- Mathlib/NumberTheory/DiophantineApproximation/Basic.lean | 2 +- Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean | 3 +-- .../NumberTheory/Transcendental/Liouville/LiouvilleWith.lean | 2 +- Mathlib/NumberTheory/Transcendental/Liouville/Measure.lean | 4 ++-- 9 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Mathlib/Algebra/Field/Basic.lean b/Mathlib/Algebra/Field/Basic.lean index e98a7a85d09fc..80ec7d0f22e19 100644 --- a/Mathlib/Algebra/Field/Basic.lean +++ b/Mathlib/Algebra/Field/Basic.lean @@ -154,11 +154,11 @@ theorem inv_sub_inv {a b : K} (ha : a ≠ 0) (hb : b ≠ 0) : a⁻¹ - b⁻¹ = rw [inv_eq_one_div, inv_eq_one_div, div_sub_div _ _ ha hb, one_mul, mul_one] @[field_simps] -theorem sub_div' (a b c : K) (hc : c ≠ 0) : b - a / c = (b * c - a) / c := by +theorem sub_div' {a b c : K} (hc : c ≠ 0) : b - a / c = (b * c - a) / c := by simpa using div_sub_div b a one_ne_zero hc @[field_simps] -theorem div_sub' (a b c : K) (hc : c ≠ 0) : a / c - b = (a - c * b) / c := by +theorem div_sub' {a b c : K} (hc : c ≠ 0) : a / c - b = (a - c * b) / c := by simpa using div_sub_div a b hc one_ne_zero -- see Note [lower instance priority] diff --git a/Mathlib/Analysis/SpecialFunctions/Gamma/BohrMollerup.lean b/Mathlib/Analysis/SpecialFunctions/Gamma/BohrMollerup.lean index ef7ef15bafc12..a9fdd2b7d413f 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gamma/BohrMollerup.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gamma/BohrMollerup.lean @@ -339,7 +339,7 @@ theorem Gamma_three_div_two_lt_one : Gamma (3 / 2) < 1 := by log_mul A.ne' (Gamma_pos_of_pos A).ne', ← le_sub_iff_add_le', log_le_iff_le_exp (Gamma_pos_of_pos A)] at this refine this.trans_lt (exp_lt_one_iff.mpr ?_) - rw [mul_comm, ← mul_div_assoc, div_sub' _ _ (2 : ℝ) two_ne_zero] + rw [mul_comm, ← mul_div_assoc, div_sub' two_ne_zero] refine div_neg_of_neg_of_pos ?_ two_pos rw [sub_neg, mul_one, ← Nat.cast_two, ← log_pow, ← exp_lt_exp, Nat.cast_two, exp_log two_pos, exp_log] <;> diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean index 6e1c8c2dbb00b..3a73bdefe94e5 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean @@ -221,7 +221,7 @@ theorem add_div_le_sum_sq_div_card (hst : s ⊆ t) (f : ι → 𝕜) (d : 𝕜) -- simp [← mul_div_right_comm _ (#t : 𝕜), sub_div' _ _ _ htcard.ne', ← sum_div, ← add_div, -- mul_pow, div_le_iff₀ (sq_pos_of_ne_zero htcard.ne'), sub_sq, sum_add_distrib, ← sum_mul, -- ← mul_sum] - simp_rw [sub_div' _ _ _ htcard.ne'] + simp_rw [sub_div' htcard.ne'] conv_lhs => enter [2, 2, x]; rw [div_pow] rw [div_pow, ← sum_div, ← mul_div_right_comm _ (#t : 𝕜), ← add_div, div_le_iff₀ (sq_pos_of_ne_zero htcard.ne')] diff --git a/Mathlib/Data/Real/Pi/Wallis.lean b/Mathlib/Data/Real/Pi/Wallis.lean index 23aca82d62f0e..33775cd43456c 100644 --- a/Mathlib/Data/Real/Pi/Wallis.lean +++ b/Mathlib/Data/Real/Pi/Wallis.lean @@ -93,7 +93,7 @@ theorem tendsto_W_nhds_pi_div_two : Tendsto W atTop (𝓝 <| π / 2) := by refine Tendsto.mul ?_ tendsto_const_nhds have h : ∀ n : ℕ, ((2 : ℝ) * n + 1) / (2 * n + 2) = 1 - 1 / (2 * n + 2) := by intro n - rw [sub_div' _ _ _ (ne_of_gt (add_pos_of_nonneg_of_pos (mul_nonneg + rw [sub_div' (ne_of_gt (add_pos_of_nonneg_of_pos (mul_nonneg (two_pos : 0 < (2 : ℝ)).le (Nat.cast_nonneg _)) two_pos)), one_mul] congr 1; ring simp_rw [h] diff --git a/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean b/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean index 4cacc2763a035..ac45276aef9ba 100644 --- a/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean +++ b/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean @@ -673,7 +673,7 @@ theorem tendsto_translation_number₀' : ((tendsto_const_div_atTop_nhds_zero_nat 1).comp (tendsto_add_atTop_nat 1)) dsimp have : (0 : ℝ) < n + 1 := n.cast_add_one_pos - rw [Real.dist_eq, div_sub' _ _ _ (ne_of_gt this), abs_div, ← Real.dist_eq, abs_of_pos this, + rw [Real.dist_eq, div_sub' (ne_of_gt this), abs_div, ← Real.dist_eq, abs_of_pos this, Nat.cast_add_one, div_le_div_iff_of_pos_right this, ← Nat.cast_add_one] apply dist_pow_map_zero_mul_translationNumber_le diff --git a/Mathlib/NumberTheory/DiophantineApproximation/Basic.lean b/Mathlib/NumberTheory/DiophantineApproximation/Basic.lean index 66f093b9e5047..b1073bfcafbc6 100644 --- a/Mathlib/NumberTheory/DiophantineApproximation/Basic.lean +++ b/Mathlib/NumberTheory/DiophantineApproximation/Basic.lean @@ -234,7 +234,7 @@ theorem den_le_and_le_num_le_of_sub_lt_one_div_den_sq {ξ q : ℚ} · rcases eq_or_ne ξ q with (rfl | H) · exact le_rfl · have hξ₀ : (0 : ℚ) < ξ.den := Nat.cast_pos.mpr ξ.pos - rw [← Rat.num_div_den ξ, div_mul_eq_mul_div, div_sub' _ _ _ hξ₀.ne', abs_div, abs_of_pos hξ₀, + rw [← Rat.num_div_den ξ, div_mul_eq_mul_div, div_sub' hξ₀.ne', abs_div, abs_of_pos hξ₀, div_lt_iff₀ hξ₀, div_mul_comm, mul_one] at h refine Nat.cast_le.mp ((one_lt_div hq₀).mp <| lt_of_le_of_lt ?_ h).le norm_cast diff --git a/Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean b/Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean index 92a7baa1debe2..40fdaa42bd92f 100644 --- a/Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean +++ b/Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean @@ -368,8 +368,7 @@ lemma tendsto_Gamma_term_aux : Tendsto (fun s ↦ 1 / (s - 1) - 1 / Gammaℝ s / simp only [mem_preimage, one_re, mem_Ioi, zero_lt_one] rw [EventuallyEq, eventually_nhdsWithin_iff] filter_upwards [this] with a ha _ - rw [Pi.div_apply, ← sub_div, div_right_comm, sub_div' _ _ _ (Gammaℝ_ne_zero_of_re_pos ha), - one_mul] + rw [Pi.div_apply, ← sub_div, div_right_comm, sub_div' (Gammaℝ_ne_zero_of_re_pos ha), one_mul] lemma tendsto_riemannZeta_sub_one_div_Gammaℝ : Tendsto (fun s ↦ riemannZeta s - 1 / Gammaℝ s / (s - 1)) (𝓝[≠] 1) diff --git a/Mathlib/NumberTheory/Transcendental/Liouville/LiouvilleWith.lean b/Mathlib/NumberTheory/Transcendental/Liouville/LiouvilleWith.lean index 6e1ac10afa4e9..5881e446c8236 100644 --- a/Mathlib/NumberTheory/Transcendental/Liouville/LiouvilleWith.lean +++ b/Mathlib/NumberTheory/Transcendental/Liouville/LiouvilleWith.lean @@ -268,7 +268,7 @@ theorem ne_cast_int (h : LiouvilleWith p x) (hp : 1 < p) (m : ℤ) : x ≠ m := ⟨n : ℕ, hn : 0 < n, m : ℤ, hne : (M : ℝ) ≠ m / n, hlt : |(M - m / n : ℝ)| < n ^ (-1 : ℝ)⟩ refine hlt.not_le ?_ have hn' : (0 : ℝ) < n := by simpa - rw [rpow_neg_one, ← one_div, sub_div' _ _ _ hn'.ne', abs_div, Nat.abs_cast] + rw [rpow_neg_one, ← one_div, sub_div' hn'.ne', abs_div, Nat.abs_cast] gcongr norm_cast rw [← zero_add (1 : ℤ), Int.add_one_le_iff, abs_pos, sub_ne_zero] diff --git a/Mathlib/NumberTheory/Transcendental/Liouville/Measure.lean b/Mathlib/NumberTheory/Transcendental/Liouville/Measure.lean index 8421fa4e65ef5..53a1246ff1f9f 100644 --- a/Mathlib/NumberTheory/Transcendental/Liouville/Measure.lean +++ b/Mathlib/NumberTheory/Transcendental/Liouville/Measure.lean @@ -58,8 +58,8 @@ theorem setOf_liouvilleWith_subset_aux : _ ≤ (b : ℝ) ^ (2 + 1 / (n + 1 : ℕ) : ℝ) := rpow_le_rpow_of_exponent_le hb (one_le_two.trans ?_) simpa using n.cast_add_one_pos.le - rw [sub_div' _ _ _ hb0.ne', abs_div, abs_of_pos hb0, div_lt_div_iff_of_pos_right hb0, - abs_sub_lt_iff, sub_lt_iff_lt_add, sub_lt_iff_lt_add, ← sub_lt_iff_lt_add'] at hlt + rw [sub_div' hb0.ne', abs_div, abs_of_pos hb0, div_lt_div_iff_of_pos_right hb0, abs_sub_lt_iff, + sub_lt_iff_lt_add, sub_lt_iff_lt_add, ← sub_lt_iff_lt_add'] at hlt rw [Finset.mem_Icc, ← Int.lt_add_one_iff, ← Int.lt_add_one_iff, ← neg_lt_iff_pos_add, add_comm, ← @Int.cast_lt ℝ, ← @Int.cast_lt ℝ] push_cast From d7a81bf7535b20878aaa2c383df397749f4e52e2 Mon Sep 17 00:00:00 2001 From: Anne Baanen Date: Wed, 5 Feb 2025 17:02:51 +0000 Subject: [PATCH 101/103] refactor(Algebra/Category): clean up remaining uses of `HasForget` (#21460) This removes the remaining references to `HasForget` in the folder `Mathlib/Algebra/Category`, upgrading all instances to `ConcreteCategory`. --- .../Algebra/Category/BialgebraCat/Basic.lean | 32 +++++++---- Mathlib/Algebra/Category/BoolRing.lean | 24 ++++---- .../Algebra/Category/CoalgebraCat/Basic.lean | 41 +++++++------- .../CoalgebraCat/ComonEquivalence.lean | 20 +++---- .../Algebra/Category/FGModuleCat/Basic.lean | 2 +- Mathlib/Algebra/Category/GrpWithZero.lean | 55 +++++++++---------- .../Category/HopfAlgebraCat/Basic.lean | 41 +++++++------- 7 files changed, 110 insertions(+), 105 deletions(-) diff --git a/Mathlib/Algebra/Category/BialgebraCat/Basic.lean b/Mathlib/Algebra/Category/BialgebraCat/Basic.lean index 8b85af2ed6e36..174a8025bfbab 100644 --- a/Mathlib/Algebra/Category/BialgebraCat/Basic.lean +++ b/Mathlib/Algebra/Category/BialgebraCat/Basic.lean @@ -64,28 +64,36 @@ algebraic spellings of composition. -/ @[ext] structure Hom (V W : BialgebraCat.{v} R) where /-- The underlying `BialgHom` -/ - toBialgHom : V →ₐc[R] W - -lemma Hom.toBialgHom_injective (V W : BialgebraCat.{v} R) : - Function.Injective (Hom.toBialgHom : Hom V W → _) := - fun ⟨f⟩ ⟨g⟩ _ => by congr + toBialgHom' : V →ₐc[R] W instance category : Category (BialgebraCat.{v} R) where Hom X Y := Hom X Y id X := ⟨BialgHom.id R X⟩ - comp f g := ⟨BialgHom.comp g.toBialgHom f.toBialgHom⟩ + comp f g := ⟨BialgHom.comp g.toBialgHom' f.toBialgHom'⟩ --- TODO: if `Quiver.Hom` and the instance above were `reducible`, this wouldn't be needed. -@[ext] -lemma hom_ext {X Y : BialgebraCat.{v} R} (f g : X ⟶ Y) (h : f.toBialgHom = g.toBialgHom) : - f = g := - Hom.ext h +instance concreteCategory : ConcreteCategory (BialgebraCat.{v} R) (· →ₐc[R] ·) where + hom f := f.toBialgHom' + ofHom f := ⟨f⟩ + +/-- Turn a morphism in `BialgebraCat` back into a `BialgHom`. -/ +abbrev Hom.toBialgHom {X Y : BialgebraCat R} (f : Hom X Y) := + ConcreteCategory.hom (C := BialgebraCat R) f /-- Typecheck a `BialgHom` as a morphism in `BialgebraCat R`. -/ abbrev ofHom {X Y : Type v} [Ring X] [Ring Y] [Bialgebra R X] [Bialgebra R Y] (f : X →ₐc[R] Y) : of R X ⟶ of R Y := - ⟨f⟩ + ConcreteCategory.ofHom f + +lemma Hom.toBialgHom_injective (V W : BialgebraCat.{v} R) : + Function.Injective (Hom.toBialgHom : Hom V W → _) := + fun ⟨f⟩ ⟨g⟩ _ => by congr + +-- TODO: if `Quiver.Hom` and the instance above were `reducible`, this wouldn't be needed. +@[ext] +lemma hom_ext {X Y : BialgebraCat.{v} R} (f g : X ⟶ Y) (h : f.toBialgHom = g.toBialgHom) : + f = g := + Hom.ext h @[simp] theorem toBialgHom_comp {X Y Z : BialgebraCat.{v} R} (f : X ⟶ Y) (g : Y ⟶ Z) : (f ≫ g).toBialgHom = g.toBialgHom.comp f.toBialgHom := diff --git a/Mathlib/Algebra/Category/BoolRing.lean b/Mathlib/Algebra/Category/BoolRing.lean index b0203ab1b4600..c3e925cdbe139 100644 --- a/Mathlib/Algebra/Category/BoolRing.lean +++ b/Mathlib/Algebra/Category/BoolRing.lean @@ -56,26 +56,28 @@ variable {R} in structure Hom (R S : BoolRing) where private mk :: /-- The underlying ring hom. -/ - hom : R →+* S + hom' : R →+* S instance : Category BoolRing where Hom R S := Hom R S id R := ⟨RingHom.id R⟩ - comp f g := ⟨g.hom.comp f.hom⟩ + comp f g := ⟨g.hom'.comp f.hom'⟩ -@[ext] -lemma hom_ext {R S : BoolRing} {f g : R ⟶ S} (hf : f.hom = g.hom) : f = g := - Hom.ext hf +instance : ConcreteCategory BoolRing (· →+* ·) where + hom f := f.hom' + ofHom f := ⟨f⟩ + +/-- Turn a morphism in `BoolRing` back into a `RingHom`. -/ +abbrev Hom.hom {X Y : BoolRing} (f : Hom X Y) := + ConcreteCategory.hom (C := BoolRing) f /-- Typecheck a `RingHom` as a morphism in `BoolRing`. -/ abbrev ofHom {R S : Type u} [BooleanRing R] [BooleanRing S] (f : R →+* S) : of R ⟶ of S := - ⟨f⟩ + ConcreteCategory.ofHom f -instance : HasForget BoolRing where - forget := - { obj := fun R ↦ R - map := fun f ↦ f.hom } - forget_faithful := ⟨fun h ↦ by ext x; simpa using congrFun h x⟩ +@[ext] +lemma hom_ext {R S : BoolRing} {f g : R ⟶ S} (hf : f.hom = g.hom) : f = g := + Hom.ext hf instance hasForgetToCommRing : HasForget₂ BoolRing CommRingCat where forget₂ := diff --git a/Mathlib/Algebra/Category/CoalgebraCat/Basic.lean b/Mathlib/Algebra/Category/CoalgebraCat/Basic.lean index f880f10b534ae..11f547b110c73 100644 --- a/Mathlib/Algebra/Category/CoalgebraCat/Basic.lean +++ b/Mathlib/Algebra/Category/CoalgebraCat/Basic.lean @@ -44,8 +44,7 @@ instance : CoeSort (CoalgebraCat.{v} R) (Type v) := variable (R) /-- The object in the category of `R`-coalgebras associated to an `R`-coalgebra. -/ -@[simps] -def of (X : Type v) [AddCommGroup X] [Module R X] [Coalgebra R X] : +abbrev of (X : Type v) [AddCommGroup X] [Module R X] [Coalgebra R X] : CoalgebraCat R := { ModuleCat.of R X with instCoalgebra := (inferInstance : Coalgebra R X) } @@ -65,28 +64,35 @@ algebraic spellings of composition. -/ @[ext] structure Hom (V W : CoalgebraCat.{v} R) where /-- The underlying `CoalgHom` -/ - toCoalgHom : V →ₗc[R] W - -lemma Hom.toCoalgHom_injective (V W : CoalgebraCat.{v} R) : - Function.Injective (Hom.toCoalgHom : Hom V W → _) := - fun ⟨f⟩ ⟨g⟩ _ => by congr + toCoalgHom' : V →ₗc[R] W instance category : Category (CoalgebraCat.{v} R) where Hom M N := Hom M N id M := ⟨CoalgHom.id R M⟩ - comp f g := ⟨CoalgHom.comp g.toCoalgHom f.toCoalgHom⟩ + comp f g := ⟨CoalgHom.comp g.toCoalgHom' f.toCoalgHom'⟩ --- TODO: if `Quiver.Hom` and the instance above were `reducible`, this wouldn't be needed. -@[ext] -lemma hom_ext {M N : CoalgebraCat.{v} R} (f g : M ⟶ N) (h : f.toCoalgHom = g.toCoalgHom) : - f = g := - Hom.ext h +instance concreteCategory : ConcreteCategory (CoalgebraCat.{v} R) (· →ₗc[R] ·) where + hom f := f.toCoalgHom' + ofHom f := ⟨f⟩ + +/-- Turn a morphism in `CoalgebraCat` back into a `CoalgHom`. -/ +abbrev Hom.toCoalgHom {X Y : CoalgebraCat.{v} R} (f : Hom X Y) : X →ₗc[R] Y := + ConcreteCategory.hom (C := CoalgebraCat.{v} R) f /-- Typecheck a `CoalgHom` as a morphism in `CoalgebraCat R`. -/ abbrev ofHom {X Y : Type v} [AddCommGroup X] [Module R X] [AddCommGroup Y] [Module R Y] [Coalgebra R X] [Coalgebra R Y] (f : X →ₗc[R] Y) : of R X ⟶ of R Y := - ⟨f⟩ + ConcreteCategory.ofHom f + +lemma Hom.toCoalgHom_injective (V W : CoalgebraCat.{v} R) : + Function.Injective (Hom.toCoalgHom' : Hom V W → _) := + fun ⟨f⟩ ⟨g⟩ _ => by congr + +@[ext] +lemma hom_ext {M N : CoalgebraCat.{v} R} (f g : M ⟶ N) (h : f.toCoalgHom = g.toCoalgHom) : + f = g := + Hom.ext h @[simp] theorem toCoalgHom_comp {M N U : CoalgebraCat.{v} R} (f : M ⟶ N) (g : N ⟶ U) : (f ≫ g).toCoalgHom = g.toCoalgHom.comp f.toCoalgHom := @@ -96,13 +102,6 @@ abbrev ofHom {X Y : Type v} [AddCommGroup X] [Module R X] [AddCommGroup Y] [Modu Hom.toCoalgHom (𝟙 M) = CoalgHom.id _ _ := rfl -instance hasForget : HasForget.{v} (CoalgebraCat.{v} R) where - forget := - { obj := fun M => M - map := fun f => f.toCoalgHom } - forget_faithful := - { map_injective := fun {_ _} => DFunLike.coe_injective.comp <| Hom.toCoalgHom_injective _ _ } - instance hasForgetToModule : HasForget₂ (CoalgebraCat R) (ModuleCat R) where forget₂ := { obj := fun M => ModuleCat.of R M diff --git a/Mathlib/Algebra/Category/CoalgebraCat/ComonEquivalence.lean b/Mathlib/Algebra/Category/CoalgebraCat/ComonEquivalence.lean index 51ff35c7035db..4a3d2a72f723e 100644 --- a/Mathlib/Algebra/Category/CoalgebraCat/ComonEquivalence.lean +++ b/Mathlib/Algebra/Category/CoalgebraCat/ComonEquivalence.lean @@ -78,7 +78,7 @@ variable (R) def ofComon : Comon_ (ModuleCat R) ⥤ CoalgebraCat R where obj X := ofComonObj X map f := - { toCoalgHom := + { toCoalgHom' := { f.hom.hom with counit_comp := ModuleCat.hom_ext_iff.mp f.hom_counit map_comp_comul := ModuleCat.hom_ext_iff.mp f.hom_comul.symm }} @@ -146,8 +146,8 @@ theorem comul_tensorObj : rw [ofComonObjCoalgebraStruct_comul] dsimp only [Equivalence.symm_inverse, comonEquivalence_functor, toComon_obj, instCoalgebraStruct_comul] - simp only [Comon_.monoidal_tensorObj_comul, toComonObj_X, of_carrier, of_isAddCommGroup, - of_isModule, toComonObj_comul, of_instCoalgebra, tensorμ_eq_tensorTensorTensorComm] + simp only [Comon_.monoidal_tensorObj_comul, toComonObj_X, + toComonObj_comul, tensorμ_eq_tensorTensorTensorComm] rfl theorem comul_tensorObj_tensorObj_right : @@ -157,13 +157,12 @@ theorem comul_tensorObj_tensorObj_right : rw [ofComonObjCoalgebraStruct_comul] dsimp only [Equivalence.symm_inverse, comonEquivalence_functor, toComon_obj, instCoalgebraStruct_comul] - simp only [Comon_.monoidal_tensorObj_comul, toComonObj_X, of_carrier, of_isAddCommGroup, - of_isModule, ModuleCat.of_coe, toComonObj_comul, of_instCoalgebra] + simp only [Comon_.monoidal_tensorObj_comul, toComonObj_X, ModuleCat.of_coe, toComonObj_comul] rw [ofComonObjCoalgebraStruct_comul] dsimp only [Equivalence.symm_inverse, comonEquivalence_functor, toComon_obj] simp only [instMonoidalCategoryStruct_tensorObj, ModuleCat.MonoidalCategory.tensorObj, - ModuleCat.coe_of, Comon_.monoidal_tensorObj_comul, toComonObj_X, of_carrier, of_isAddCommGroup, - of_isModule, toComonObj_comul, of_instCoalgebra, tensorμ_eq_tensorTensorTensorComm] + ModuleCat.coe_of, Comon_.monoidal_tensorObj_comul, toComonObj_X, toComonObj_comul, + tensorμ_eq_tensorTensorTensorComm] rfl theorem comul_tensorObj_tensorObj_left : @@ -173,13 +172,12 @@ theorem comul_tensorObj_tensorObj_left : rw [ofComonObjCoalgebraStruct_comul] dsimp only [Equivalence.symm_inverse, comonEquivalence_functor, toComon_obj, instCoalgebraStruct_comul] - simp only [Comon_.monoidal_tensorObj_comul, toComonObj_X, ModuleCat.of_coe, of_carrier, - of_isAddCommGroup, of_isModule, toComonObj_comul, of_instCoalgebra] + simp only [Comon_.monoidal_tensorObj_comul, toComonObj_X, ModuleCat.of_coe, toComonObj_comul] rw [ofComonObjCoalgebraStruct_comul] dsimp only [Equivalence.symm_inverse, comonEquivalence_functor, toComon_obj] simp only [instMonoidalCategoryStruct_tensorObj, ModuleCat.MonoidalCategory.tensorObj, - ModuleCat.coe_of, Comon_.monoidal_tensorObj_comul, toComonObj_X, of_carrier, of_isAddCommGroup, - of_isModule, toComonObj_comul, of_instCoalgebra, tensorμ_eq_tensorTensorTensorComm] + ModuleCat.coe_of, Comon_.monoidal_tensorObj_comul, toComonObj_X, toComonObj_comul, + tensorμ_eq_tensorTensorTensorComm] rfl theorem counit_tensorObj : diff --git a/Mathlib/Algebra/Category/FGModuleCat/Basic.lean b/Mathlib/Algebra/Category/FGModuleCat/Basic.lean index 227bef9faa458..de87bc98820db 100644 --- a/Mathlib/Algebra/Category/FGModuleCat/Basic.lean +++ b/Mathlib/Algebra/Category/FGModuleCat/Basic.lean @@ -72,7 +72,7 @@ instance : LargeCategory (FGModuleCat R) := by dsimp [FGModuleCat] infer_instance -instance : HasForget (FGModuleCat R) := by +instance : ConcreteCategory (FGModuleCat R) (· →ₗ[R] ·) := by dsimp [FGModuleCat] infer_instance diff --git a/Mathlib/Algebra/Category/GrpWithZero.lean b/Mathlib/Algebra/Category/GrpWithZero.lean index 7b63ccb5a2f17..75fd5cbd442ac 100644 --- a/Mathlib/Algebra/Category/GrpWithZero.lean +++ b/Mathlib/Algebra/Category/GrpWithZero.lean @@ -6,7 +6,6 @@ Authors: Yaël Dillies import Mathlib.Algebra.Category.MonCat.Basic import Mathlib.Algebra.GroupWithZero.WithZero import Mathlib.CategoryTheory.Category.Bipointed -import Mathlib.CategoryTheory.ConcreteCategory.Bundled /-! # The category of groups with zero @@ -19,20 +18,21 @@ universe u open CategoryTheory Order /-- The category of groups with zero. -/ -def GrpWithZero := - Bundled GroupWithZero +structure GrpWithZero where + /-- The underlying group with zero. -/ + carrier : Type* + [str : GroupWithZero carrier] + +attribute [instance] GrpWithZero.str namespace GrpWithZero instance : CoeSort GrpWithZero Type* := - Bundled.coeSort - -instance (X : GrpWithZero) : GroupWithZero X := - X.str + ⟨carrier⟩ /-- Construct a bundled `GrpWithZero` from a `GroupWithZero`. -/ -def of (α : Type*) [GroupWithZero α] : GrpWithZero := - Bundled.of α +abbrev of (α : Type*) [GroupWithZero α] : GrpWithZero where + carrier := α instance : Inhabited GrpWithZero := ⟨of (WithZero PUnit)⟩ @@ -41,28 +41,27 @@ instance : LargeCategory.{u} GrpWithZero where Hom X Y := MonoidWithZeroHom X Y id X := MonoidWithZeroHom.id X comp f g := g.comp f - id_comp := MonoidWithZeroHom.comp_id - comp_id := MonoidWithZeroHom.id_comp - assoc _ _ _ := MonoidWithZeroHom.comp_assoc _ _ _ - -instance {M N : GrpWithZero} : FunLike (M ⟶ N) M N := - ⟨fun f => f.toFun, fun f g h => by - cases f - cases g - congr - apply DFunLike.coe_injective' - exact h⟩ + +instance groupWithZeroConcreteCategory : ConcreteCategory GrpWithZero (MonoidWithZeroHom · ·) where + hom f := f + ofHom f := f + +/-- Typecheck a `MonoidWithZeroHom` as a morphism in `GrpWithZero`. -/ +abbrev ofHom {X Y : Type u} [GroupWithZero X] [GroupWithZero Y] + (f : MonoidWithZeroHom X Y) : of X ⟶ of Y := + ConcreteCategory.ofHom f + +@[simp] +lemma hom_id {X : GrpWithZero} : ConcreteCategory.hom (𝟙 X : X ⟶ X) = MonoidWithZeroHom.id X := rfl + +@[simp] +lemma hom_comp {X Y Z : GrpWithZero} {f : X ⟶ Y} {g : Y ⟶ Z} : + ConcreteCategory.hom (f ≫ g) = g.comp f := rfl lemma coe_id {X : GrpWithZero} : (𝟙 X : X → X) = id := rfl lemma coe_comp {X Y Z : GrpWithZero} {f : X ⟶ Y} {g : Y ⟶ Z} : (f ≫ g : X → Z) = g ∘ f := rfl -instance groupWithZeroHasForget : HasForget GrpWithZero where - forget := - { obj := fun G => G - map := fun f => f.toFun } - forget_faithful := ⟨fun h => DFunLike.coe_injective h⟩ - @[simp] lemma forget_map {X Y : GrpWithZero} (f : X ⟶ Y) : (forget GrpWithZero).map f = f := rfl @@ -79,8 +78,8 @@ instance hasForgetToMon : HasForget₂ GrpWithZero MonCat where /-- Constructs an isomorphism of groups with zero from a group isomorphism between them. -/ @[simps] def Iso.mk {α β : GrpWithZero.{u}} (e : α ≃* β) : α ≅ β where - hom := (e : α →*₀ β) - inv := (e.symm : β →*₀ α) + hom := ofHom e + inv := ofHom e.symm hom_inv_id := by ext exact e.symm_apply_apply _ diff --git a/Mathlib/Algebra/Category/HopfAlgebraCat/Basic.lean b/Mathlib/Algebra/Category/HopfAlgebraCat/Basic.lean index 81952cef5ef08..adbba8507ca5b 100644 --- a/Mathlib/Algebra/Category/HopfAlgebraCat/Basic.lean +++ b/Mathlib/Algebra/Category/HopfAlgebraCat/Basic.lean @@ -43,8 +43,7 @@ instance : CoeSort (HopfAlgebraCat.{v} R) (Type v) := variable (R) /-- The object in the category of `R`-Hopf algebras associated to an `R`-Hopf algebra. -/ -@[simps] -def of (X : Type v) [Ring X] [HopfAlgebra R X] : +abbrev of (X : Type v) [Ring X] [HopfAlgebra R X] : HopfAlgebraCat R where carrier := X @@ -63,28 +62,35 @@ algebraic spellings of composition. -/ @[ext] structure Hom (V W : HopfAlgebraCat.{v} R) where /-- The underlying `BialgHom`. -/ - toBialgHom : V →ₐc[R] W - -lemma Hom.toBialgHom_injective (V W : HopfAlgebraCat.{v} R) : - Function.Injective (Hom.toBialgHom : Hom V W → _) := - fun ⟨f⟩ ⟨g⟩ _ => by congr + toBialgHom' : V →ₐc[R] W instance category : Category (HopfAlgebraCat.{v} R) where Hom X Y := Hom X Y id X := ⟨BialgHom.id R X⟩ - comp f g := ⟨BialgHom.comp g.toBialgHom f.toBialgHom⟩ + comp f g := ⟨BialgHom.comp g.toBialgHom' f.toBialgHom'⟩ --- TODO: if `Quiver.Hom` and the instance above were `reducible`, this wouldn't be needed. -@[ext] -lemma hom_ext {X Y : HopfAlgebraCat.{v} R} (f g : X ⟶ Y) (h : f.toBialgHom = g.toBialgHom) : - f = g := - Hom.ext h +instance concreteCategory : ConcreteCategory (HopfAlgebraCat.{v} R) (· →ₐc[R] ·) where + hom f := f.toBialgHom' + ofHom f := ⟨f⟩ + +/-- Turn a morphism in `HopfAlgebraCat` back into a `BialgHom`. -/ +abbrev Hom.toBialgHom {X Y : HopfAlgebraCat R} (f : Hom X Y) := + ConcreteCategory.hom (C := HopfAlgebraCat R) f /-- Typecheck a `BialgHom` as a morphism in `HopfAlgebraCat R`. -/ abbrev ofHom {X Y : Type v} [Ring X] [Ring Y] [HopfAlgebra R X] [HopfAlgebra R Y] (f : X →ₐc[R] Y) : of R X ⟶ of R Y := - ⟨f⟩ + ConcreteCategory.ofHom f + +lemma Hom.toBialgHom_injective (V W : HopfAlgebraCat.{v} R) : + Function.Injective (Hom.toBialgHom : Hom V W → _) := + fun ⟨f⟩ ⟨g⟩ _ => by congr + +@[ext] +lemma hom_ext {X Y : HopfAlgebraCat.{v} R} (f g : X ⟶ Y) (h : f.toBialgHom = g.toBialgHom) : + f = g := + Hom.ext h @[simp] theorem toBialgHom_comp {X Y Z : HopfAlgebraCat.{v} R} (f : X ⟶ Y) (g : Y ⟶ Z) : (f ≫ g).toBialgHom = g.toBialgHom.comp f.toBialgHom := @@ -94,13 +100,6 @@ abbrev ofHom {X Y : Type v} [Ring X] [Ring Y] Hom.toBialgHom (𝟙 M) = BialgHom.id _ _ := rfl -instance hasForget : HasForget.{v} (HopfAlgebraCat.{v} R) where - forget := - { obj := fun M => M - map := fun f => f.toBialgHom } - forget_faithful := - { map_injective := fun {_ _} => DFunLike.coe_injective.comp <| Hom.toBialgHom_injective _ _ } - instance hasForgetToBialgebra : HasForget₂ (HopfAlgebraCat R) (BialgebraCat R) where forget₂ := { obj := fun X => BialgebraCat.of R X From 6aadd7f3ee513f64143679175b6131b36822e1af Mon Sep 17 00:00:00 2001 From: Anne Baanen Date: Wed, 5 Feb 2025 17:15:11 +0000 Subject: [PATCH 102/103] refactor(CategoryTheory): `ConcreteCategory` instance for `FintypeCat` (#21466) Upgrade the `HasForget` instance on `FintypeCat` to a `ConcreteCategory`. --- Mathlib/CategoryTheory/FintypeCat.lean | 31 +++++++++++++-------- Mathlib/CategoryTheory/Preadditive/Mat.lean | 4 +-- Mathlib/Order/Category/FinPartOrd.lean | 6 ++-- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/Mathlib/CategoryTheory/FintypeCat.lean b/Mathlib/CategoryTheory/FintypeCat.lean index 8eb20b5d8481b..fe44973860f9b 100644 --- a/Mathlib/CategoryTheory/FintypeCat.lean +++ b/Mathlib/CategoryTheory/FintypeCat.lean @@ -24,17 +24,21 @@ We prove that `FintypeCat.Skeleton` is a skeleton of `FintypeCat` in `FintypeCat open CategoryTheory /-- The category of finite types. -/ -def FintypeCat := - Bundled Fintype +structure FintypeCat where + /-- The underlying type. -/ + carrier : Type* + [str : Fintype carrier] + +attribute [instance] FintypeCat.str namespace FintypeCat -instance : CoeSort FintypeCat Type* := - Bundled.coeSort +instance instCoeSort : CoeSort FintypeCat Type* := + ⟨carrier⟩ /-- Construct a bundled `FintypeCat` from the underlying type and typeclass. -/ -def of (X : Type*) [Fintype X] : FintypeCat := - Bundled.of X +abbrev of (X : Type*) [Fintype X] : FintypeCat where + carrier := X instance : Inhabited FintypeCat := ⟨of PEmpty⟩ @@ -43,7 +47,7 @@ instance {X : FintypeCat} : Fintype X := X.2 instance : Category FintypeCat := - InducedCategory.category Bundled.α + InducedCategory.category carrier /-- The fully faithful embedding of `FintypeCat` into the category of types. -/ @[simps!] @@ -53,8 +57,13 @@ def incl : FintypeCat ⥤ Type* := instance : incl.Full := InducedCategory.full _ instance : incl.Faithful := InducedCategory.faithful _ -instance hasForgetFintype : HasForget FintypeCat := - ⟨incl⟩ +instance (X Y : FintypeCat) : FunLike (X ⟶ Y) X Y where + coe f := f + coe_injective' _ _ h := h + +instance concreteCategoryFintype : ConcreteCategory FintypeCat (· ⟶ ·) where + hom f := f + ofHom f := f /- Help typeclass inference infer fullness of forgetful functor. -/ instance : (forget FintypeCat).Full := inferInstanceAs <| FintypeCat.incl.Full @@ -217,9 +226,7 @@ noncomputable def uSwitchEquiv (X : FintypeCat.{u}) : lemma uSwitchEquiv_naturality {X Y : FintypeCat.{u}} (f : X ⟶ Y) (x : uSwitch.{u, v}.obj X) : f (X.uSwitchEquiv x) = Y.uSwitchEquiv (uSwitch.map f x) := by - simp only [uSwitch, uSwitchEquiv, Equiv.trans_apply] - erw [Equiv.ulift_apply, Equiv.ulift_apply] - simp only [Equiv.symm_apply_apply] + simp only [uSwitch, uSwitchEquiv, Equiv.trans_apply, Equiv.ulift_apply, Equiv.symm_apply_apply] lemma uSwitchEquiv_symm_naturality {X Y : FintypeCat.{u}} (f : X ⟶ Y) (x : X) : uSwitch.map f (X.uSwitchEquiv.symm x) = Y.uSwitchEquiv.symm (f x) := by diff --git a/Mathlib/CategoryTheory/Preadditive/Mat.lean b/Mathlib/CategoryTheory/Preadditive/Mat.lean index f323817080a5e..b999af9efd183 100644 --- a/Mathlib/CategoryTheory/Preadditive/Mat.lean +++ b/Mathlib/CategoryTheory/Preadditive/Mat.lean @@ -497,7 +497,7 @@ instance (R : Type u) : Inhabited (Mat R) := by infer_instance instance (R : Type u) : CoeSort (Mat R) (Type u) := - Bundled.coeSort + FintypeCat.instCoeSort open Matrix @@ -580,7 +580,7 @@ instance : (equivalenceSingleObjInverse R).Full where instance : (equivalenceSingleObjInverse R).EssSurj where mem_essImage X := ⟨{ ι := X - X := fun _ => PUnit.unit }, ⟨eqToIso (by dsimp; cases X; congr)⟩⟩ + X := fun _ => PUnit.unit }, ⟨eqToIso (by cases X; congr)⟩⟩ instance : (equivalenceSingleObjInverse R).IsEquivalence where diff --git a/Mathlib/Order/Category/FinPartOrd.lean b/Mathlib/Order/Category/FinPartOrd.lean index 58d87401fa722..963a9ed0b5971 100644 --- a/Mathlib/Order/Category/FinPartOrd.lean +++ b/Mathlib/Order/Category/FinPartOrd.lean @@ -62,10 +62,8 @@ instance hasForgetToPartOrd : HasForget₂ FinPartOrd PartOrd := InducedCategory.hasForget₂ FinPartOrd.toPartOrd instance hasForgetToFintype : HasForget₂ FinPartOrd FintypeCat where - forget₂ := - { obj := fun X => ⟨X, inferInstance⟩ - -- Porting note: Originally `map := fun X Y => coeFn` - map := fun {X Y} (f : OrderHom X Y) => ⇑f } + forget₂.obj X := FintypeCat.of X + forget₂.map {X Y} (f : OrderHom X Y) := (f : X → Y) /-- Constructs an isomorphism of finite partial orders from an order isomorphism between them. -/ @[simps] From 24c597596e1eab32ef9047e2ca944e099df3d294 Mon Sep 17 00:00:00 2001 From: Matthew Robert Ballard Date: Wed, 5 Feb 2025 17:40:12 +0000 Subject: [PATCH 103/103] chore(PresheafedSpace): remove `mk_coe` and some comments from porting (#21382) My experience with `SimpVarHead` is that declarations flagged are something that Lean can handle with eta-reduction/expansion. Either way, this declaration is not used in mathlib and the commented out code doesn't seem to be missed. --- Mathlib/Geometry/RingedSpace/PresheafedSpace.lean | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Mathlib/Geometry/RingedSpace/PresheafedSpace.lean b/Mathlib/Geometry/RingedSpace/PresheafedSpace.lean index 818fe3e6d019b..3514ef5438f88 100644 --- a/Mathlib/Geometry/RingedSpace/PresheafedSpace.lean +++ b/Mathlib/Geometry/RingedSpace/PresheafedSpace.lean @@ -59,11 +59,6 @@ attribute [coe] PresheafedSpace.carrier instance : CoeSort (PresheafedSpace C) Type* where coe X := X.carrier -theorem mk_coe (carrier) (presheaf) : - (({ carrier - presheaf } : PresheafedSpace C) : TopCat) = carrier := - rfl - instance (X : PresheafedSpace C) : TopologicalSpace X := X.carrier.str