diff --git a/Archive/Sensitivity.lean b/Archive/Sensitivity.lean index 53a2ef0b6f..b48847812a 100644 --- a/Archive/Sensitivity.lean +++ b/Archive/Sensitivity.lean @@ -329,7 +329,7 @@ set_option backward.isDefEq.respectTransparency false in theorem g_injective : Injective (g m) := by rw [g] intro x₁ x₂ h - simp only [V, LinearMap.prod_apply, LinearMap.id_apply, Prod.mk_inj, Pi.prod] at h + simp only [V, LinearMap.prod_apply, LinearMap.id_apply, Prod.mk_inj, Function.prod_apply] at h exact h.right set_option backward.isDefEq.respectTransparency false in diff --git a/Mathlib.lean b/Mathlib.lean index 82154452e7..eaa7c935f1 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -643,6 +643,7 @@ public import Mathlib.Algebra.Homology.HomotopyCategory.SingleFunctors public import Mathlib.Algebra.Homology.HomotopyCategory.SpectralObject public import Mathlib.Algebra.Homology.HomotopyCategory.Triangulated public import Mathlib.Algebra.Homology.HomotopyCofiber +public import Mathlib.Algebra.Homology.HomotopyFiber public import Mathlib.Algebra.Homology.ImageToKernel public import Mathlib.Algebra.Homology.LeftResolution.Basic public import Mathlib.Algebra.Homology.LeftResolution.Reduced @@ -1379,6 +1380,7 @@ public import Mathlib.AlgebraicGeometry.Morphisms.FiniteType public import Mathlib.AlgebraicGeometry.Morphisms.Flat public import Mathlib.AlgebraicGeometry.Morphisms.FlatDescent public import Mathlib.AlgebraicGeometry.Morphisms.FlatMono +public import Mathlib.AlgebraicGeometry.Morphisms.FlatRank public import Mathlib.AlgebraicGeometry.Morphisms.FormallyUnramified public import Mathlib.AlgebraicGeometry.Morphisms.Immersion public import Mathlib.AlgebraicGeometry.Morphisms.Integral @@ -1493,6 +1495,7 @@ public import Mathlib.AlgebraicTopology.ModelCategory.RightHomotopy public import Mathlib.AlgebraicTopology.ModelCategory.Transport public import Mathlib.AlgebraicTopology.MooreComplex public import Mathlib.AlgebraicTopology.Quasicategory.Basic +public import Mathlib.AlgebraicTopology.Quasicategory.InnerFibration public import Mathlib.AlgebraicTopology.Quasicategory.Nerve public import Mathlib.AlgebraicTopology.Quasicategory.StrictBicategory public import Mathlib.AlgebraicTopology.Quasicategory.StrictSegal @@ -1519,11 +1522,13 @@ public import Mathlib.AlgebraicTopology.SimplicialNerve public import Mathlib.AlgebraicTopology.SimplicialObject.Basic public import Mathlib.AlgebraicTopology.SimplicialObject.ChainHomotopy public import Mathlib.AlgebraicTopology.SimplicialObject.Coskeletal +public import Mathlib.AlgebraicTopology.SimplicialObject.DeltaZeroIter public import Mathlib.AlgebraicTopology.SimplicialObject.Homotopy public import Mathlib.AlgebraicTopology.SimplicialObject.II public import Mathlib.AlgebraicTopology.SimplicialObject.Op public import Mathlib.AlgebraicTopology.SimplicialObject.Split public import Mathlib.AlgebraicTopology.SimplicialSet.AnodyneExtensions.Basic +public import Mathlib.AlgebraicTopology.SimplicialSet.AnodyneExtensions.Inner.Basic public import Mathlib.AlgebraicTopology.SimplicialSet.AnodyneExtensions.IsUniquelyCodimOneFace public import Mathlib.AlgebraicTopology.SimplicialSet.AnodyneExtensions.Op public import Mathlib.AlgebraicTopology.SimplicialSet.AnodyneExtensions.Pairing @@ -2718,6 +2723,7 @@ public import Mathlib.CategoryTheory.Groupoid.Grpd.Basic public import Mathlib.CategoryTheory.Groupoid.Subgroupoid public import Mathlib.CategoryTheory.Groupoid.VertexGroup public import Mathlib.CategoryTheory.GuitartExact.Basic +public import Mathlib.CategoryTheory.GuitartExact.HorizontalComposition public import Mathlib.CategoryTheory.GuitartExact.KanExtension public import Mathlib.CategoryTheory.GuitartExact.Opposite public import Mathlib.CategoryTheory.GuitartExact.Over @@ -3037,6 +3043,7 @@ public import Mathlib.CategoryTheory.Monoidal.Cartesian.Mon public import Mathlib.CategoryTheory.Monoidal.Cartesian.Mon_ public import Mathlib.CategoryTheory.Monoidal.Cartesian.Normal public import Mathlib.CategoryTheory.Monoidal.Cartesian.Over +public import Mathlib.CategoryTheory.Monoidal.Cartesian.Ring public import Mathlib.CategoryTheory.Monoidal.Cartesian.ShrinkYoneda public import Mathlib.CategoryTheory.Monoidal.Category public import Mathlib.CategoryTheory.Monoidal.Center @@ -5673,7 +5680,6 @@ public import Mathlib.NumberTheory.ModularForms.Cusps public import Mathlib.NumberTheory.ModularForms.DedekindEta public import Mathlib.NumberTheory.ModularForms.Delta public import Mathlib.NumberTheory.ModularForms.Derivative -public import Mathlib.NumberTheory.ModularForms.DimensionFormulas.LevelOne public import Mathlib.NumberTheory.ModularForms.Discriminant public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.Basic public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.Defs @@ -5691,7 +5697,9 @@ public import Mathlib.NumberTheory.ModularForms.JacobiTheta.Bounds public import Mathlib.NumberTheory.ModularForms.JacobiTheta.Manifold public import Mathlib.NumberTheory.ModularForms.JacobiTheta.OneVariable public import Mathlib.NumberTheory.ModularForms.JacobiTheta.TwoVariable -public import Mathlib.NumberTheory.ModularForms.LevelOne +public import Mathlib.NumberTheory.ModularForms.LevelOne.Basic +public import Mathlib.NumberTheory.ModularForms.LevelOne.DimensionFormula +public import Mathlib.NumberTheory.ModularForms.LevelOne.GradedRing public import Mathlib.NumberTheory.ModularForms.NormTrace public import Mathlib.NumberTheory.ModularForms.Petersson public import Mathlib.NumberTheory.ModularForms.ProperlyDiscontinuous @@ -6569,6 +6577,7 @@ public import Mathlib.RingTheory.LaurentSeries public import Mathlib.RingTheory.Length public import Mathlib.RingTheory.LinearDisjoint public import Mathlib.RingTheory.LittleWedderburn +public import Mathlib.RingTheory.LocalIso public import Mathlib.RingTheory.LocalProperties.Basic public import Mathlib.RingTheory.LocalProperties.Exactness public import Mathlib.RingTheory.LocalProperties.Injective @@ -6958,7 +6967,8 @@ public import Mathlib.RingTheory.ZariskisMainTheorem public import Mathlib.SetTheory.Cardinal.Aleph public import Mathlib.SetTheory.Cardinal.Arithmetic public import Mathlib.SetTheory.Cardinal.Basic -public import Mathlib.SetTheory.Cardinal.Cofinality +public import Mathlib.SetTheory.Cardinal.Cofinality.Basic +public import Mathlib.SetTheory.Cardinal.Cofinality.Ordinal public import Mathlib.SetTheory.Cardinal.Continuum public import Mathlib.SetTheory.Cardinal.CountableCover public import Mathlib.SetTheory.Cardinal.Defs @@ -7722,6 +7732,7 @@ public import Mathlib.Topology.Instances.AddCircle.Real public import Mathlib.Topology.Instances.CantorSet public import Mathlib.Topology.Instances.Complex public import Mathlib.Topology.Instances.Discrete +public import Mathlib.Topology.Instances.ENNReal.ENatENNReal public import Mathlib.Topology.Instances.ENNReal.Lemmas public import Mathlib.Topology.Instances.ENat public import Mathlib.Topology.Instances.EReal.Lemmas diff --git a/Mathlib/Algebra/Algebra/NonUnitalHom.lean b/Mathlib/Algebra/Algebra/NonUnitalHom.lean index d3986be73b..f84999ab77 100644 --- a/Mathlib/Algebra/Algebra/NonUnitalHom.lean +++ b/Mathlib/Algebra/Algebra/NonUnitalHom.lean @@ -371,13 +371,13 @@ variable [DistribMulAction R C] /-- The prod of two morphisms is a morphism. -/ @[simps] def prod (f : A →ₙₐ[R] B) (g : A →ₙₐ[R] C) : A →ₙₐ[R] B × C where - toFun := Pi.prod f g - map_zero' := by simp only [Pi.prod, Prod.mk_zero_zero, map_zero] - map_add' x y := by simp only [Pi.prod, Prod.mk_add_mk, map_add] - map_mul' x y := by simp only [Pi.prod, Prod.mk_mul_mk, map_mul] - map_smul' c x := by simp only [Pi.prod, map_smul, MonoidHom.id_apply, Prod.smul_mk] + toFun := Function.prod f g + map_zero' := by simp only [Function.prod_apply, Prod.mk_zero_zero, map_zero] + map_add' x y := by simp only [Function.prod_apply, Prod.mk_add_mk, map_add] + map_mul' x y := by simp only [Function.prod_apply, Prod.mk_mul_mk, map_mul] + map_smul' c x := by simp only [Function.prod_apply, map_smul, MonoidHom.id_apply, Prod.smul_mk] -theorem coe_prod (f : A →ₙₐ[R] B) (g : A →ₙₐ[R] C) : ⇑(f.prod g) = Pi.prod f g := +theorem coe_prod (f : A →ₙₐ[R] B) (g : A →ₙₐ[R] C) : ⇑(f.prod g) = Function.prod f g := rfl @[simp] @@ -390,7 +390,7 @@ theorem snd_prod (f : A →ₙₐ[R] B) (g : A →ₙₐ[R] C) : (snd R B C).com @[simp] theorem prod_fst_snd : prod (fst R A B) (snd R A B) = 1 := - coe_injective Pi.prod_fst_snd + coe_injective Function.prod_fst_snd /-- Taking the product of two maps with the same domain is equivalent to taking the product of their codomains. -/ diff --git a/Mathlib/Algebra/Algebra/Prod.lean b/Mathlib/Algebra/Algebra/Prod.lean index 46058dff5a..66cd3bf80c 100644 --- a/Mathlib/Algebra/Algebra/Prod.lean +++ b/Mathlib/Algebra/Algebra/Prod.lean @@ -77,7 +77,7 @@ theorem snd_apply (a) : snd R A B a = a.2 := rfl variable {R} -/-- The `Pi.prod` of two morphisms is a morphism. -/ +/-- The `Function.prod` of two morphisms is a morphism. -/ @[simps!] def prod (f : A →ₐ[R] B) (g : A →ₐ[R] C) : A →ₐ[R] B × C := { f.toRingHom.prod g.toRingHom with @@ -85,7 +85,7 @@ def prod (f : A →ₐ[R] B) (g : A →ₐ[R] C) : A →ₐ[R] B × C := simp only [toRingHom_eq_coe, RingHom.toFun_eq_coe, RingHom.prod_apply, coe_toRingHom, commutes, Prod.algebraMap_apply] } -theorem coe_prod (f : A →ₐ[R] B) (g : A →ₐ[R] C) : ⇑(f.prod g) = Pi.prod f g := +theorem coe_prod (f : A →ₐ[R] B) (g : A →ₐ[R] C) : ⇑(f.prod g) = Function.prod f g := rfl @[simp] diff --git a/Mathlib/Algebra/Algebra/Subalgebra/Lattice.lean b/Mathlib/Algebra/Algebra/Subalgebra/Lattice.lean index 451c38998d..5e4698cedb 100644 --- a/Mathlib/Algebra/Algebra/Subalgebra/Lattice.lean +++ b/Mathlib/Algebra/Algebra/Subalgebra/Lattice.lean @@ -700,19 +700,11 @@ theorem adjoin_span {s : Set A} : adjoin R (Submodule.span R s : Set A) = adjoin le_antisymm (adjoin_le (span_le_adjoin _ _)) (adjoin_mono Submodule.subset_span) theorem adjoin_image (f : A →ₐ[R] B) (s : Set A) : adjoin R (f '' s) = (adjoin R s).map f := - le_antisymm (adjoin_le <| Set.image_mono subset_adjoin) <| - Subalgebra.map_le.2 <| adjoin_le <| Set.image_subset_iff.1 <| by - simp only [Set.image_id', coe_carrier_toSubmonoid, Subalgebra.coe_toSubsemiring, - Subalgebra.coe_comap] - exact fun x hx => subset_adjoin ⟨x, hx, rfl⟩ + eq_of_forall_ge_iff fun t ↦ by simp [Subalgebra.map_le, adjoin_le_iff] @[simp] theorem adjoin_insert_adjoin (x : A) : adjoin R (insert x ↑(adjoin R s)) = adjoin R (insert x s) := - le_antisymm - (adjoin_le - (Set.insert_subset_iff.mpr - ⟨subset_adjoin (Set.mem_insert _ _), adjoin_mono (Set.subset_insert _ _)⟩)) - (Algebra.adjoin_mono (Set.insert_subset_insert Algebra.subset_adjoin)) + eq_of_forall_ge_iff fun t ↦ by simp [adjoin_le_iff, Set.insert_subset_iff] theorem mem_adjoin_of_map_mul {s} {x : A} {f : A →ₗ[R] B} (hf : ∀ a₁ a₂, f (a₁ * a₂) = f a₁ * f a₂) (h : x ∈ adjoin R s) : f x ∈ adjoin R (f '' (s ∪ {1})) := by diff --git a/Mathlib/Algebra/Algebra/Tower.lean b/Mathlib/Algebra/Algebra/Tower.lean index f02b2ee027..9b1be4777b 100644 --- a/Mathlib/Algebra/Algebra/Tower.lean +++ b/Mathlib/Algebra/Algebra/Tower.lean @@ -405,7 +405,7 @@ section Algebra.algebraMapSubmonoid @[simp] theorem Algebra.algebraMapSubmonoid_map_map {R A B : Type*} [CommSemiring R] [CommSemiring A] - [Algebra R A] (M : Submonoid R) [CommRing B] [Algebra R B] [Algebra A B] [IsScalarTower R A B] : + [Algebra R A] (M : Submonoid R) [Semiring B] [Algebra R B] [Algebra A B] [IsScalarTower R A B] : algebraMapSubmonoid B (algebraMapSubmonoid A M) = algebraMapSubmonoid B M := algebraMapSubmonoid_map_eq _ (IsScalarTower.toAlgHom R A B) diff --git a/Mathlib/Algebra/BigOperators/Finprod.lean b/Mathlib/Algebra/BigOperators/Finprod.lean index 0df8c87f58..1de4d50576 100644 --- a/Mathlib/Algebra/BigOperators/Finprod.lean +++ b/Mathlib/Algebra/BigOperators/Finprod.lean @@ -277,7 +277,7 @@ lemma one_le_finprod {M : Type*} [CommMonoidWithZero M] [Preorder M] [ZeroLEOneC theorem MonoidHom.map_finprod_plift (f : M →* N) (g : α → M) (h : HasFiniteMulSupport <| g ∘ PLift.down) : f (∏ᶠ x, g x) = ∏ᶠ x, f (g x) := by rw [finprod_eq_prod_plift_of_mulSupport_subset h.coe_toFinset.ge, - finprod_eq_prod_plift_of_mulSupport_subset, map_prod] + finprod_eq_prod_plift_of_mulSupport_subset, _root_.map_prod] rw [h.coe_toFinset] exact mulSupport_comp_subset f.map_one (g ∘ PLift.down) diff --git a/Mathlib/Algebra/BigOperators/Ring/Finset.lean b/Mathlib/Algebra/BigOperators/Ring/Finset.lean index 7b038d906a..e38c701f8e 100644 --- a/Mathlib/Algebra/BigOperators/Ring/Finset.lean +++ b/Mathlib/Algebra/BigOperators/Ring/Finset.lean @@ -45,6 +45,9 @@ lemma natCast_card_filter (p) [DecidablePred p] (s : Finset ι) : (∑ x ∈ s, if p x then 1 else 0 : R) = #{x ∈ s | p x} := (natCast_card_filter _ _).symm +lemma card_eq_sum_ite {s t : Finset ι} [DecidablePred (· ∈ s)] (hst : s ⊆ t) : + s.card = ∑ i ∈ t, if i ∈ s then 1 else 0 := by simp [hst] + end AddCommMonoidWithOne section NonUnitalNonAssocSemiring diff --git a/Mathlib/Algebra/Category/BialgCat/Basic.lean b/Mathlib/Algebra/Category/BialgCat/Basic.lean index b8985f97d7..f23b362003 100644 --- a/Mathlib/Algebra/Category/BialgCat/Basic.lean +++ b/Mathlib/Algebra/Category/BialgCat/Basic.lean @@ -34,6 +34,7 @@ structure BialgCat where [instRing : Ring carrier] [instBialgebra : Bialgebra R carrier] +initialize_simps_projections BialgCat (-instRing, -instBialgebra) attribute [instance] BialgCat.instBialgebra BialgCat.instRing variable {R} diff --git a/Mathlib/Algebra/Category/HopfAlgCat/Basic.lean b/Mathlib/Algebra/Category/HopfAlgCat/Basic.lean index 1637b25bca..9b15fb679a 100644 --- a/Mathlib/Algebra/Category/HopfAlgCat/Basic.lean +++ b/Mathlib/Algebra/Category/HopfAlgCat/Basic.lean @@ -35,6 +35,7 @@ structure HopfAlgCat where [instRing : Ring carrier] [instHopfAlgebra : HopfAlgebra R carrier] +initialize_simps_projections HopfAlgCat (-instRing, -instHopfAlgebra) attribute [instance] HopfAlgCat.instHopfAlgebra HopfAlgCat.instRing variable {R} diff --git a/Mathlib/Algebra/Category/ModuleCat/Basic.lean b/Mathlib/Algebra/Category/ModuleCat/Basic.lean index dca2a34dfc..d4d14bdef1 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Basic.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Basic.lean @@ -60,6 +60,7 @@ structure ModuleCat where [isAddCommGroup : AddCommGroup carrier] [isModule : Module R carrier] +initialize_simps_projections ModuleCat (-isModule, -isAddCommGroup) attribute [instance] ModuleCat.isAddCommGroup attribute [instance 1100] ModuleCat.isModule diff --git a/Mathlib/Algebra/Category/ModuleCat/Semi.lean b/Mathlib/Algebra/Category/ModuleCat/Semi.lean index 0e9b0a944f..951b0e0834 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Semi.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Semi.lean @@ -59,6 +59,7 @@ structure SemimoduleCat where [isAddCommMonoid : AddCommMonoid carrier] [isModule : Module R carrier] +initialize_simps_projections SemimoduleCat (-isModule, -isAddCommMonoid) attribute [instance] SemimoduleCat.isAddCommMonoid SemimoduleCat.isModule namespace SemimoduleCat diff --git a/Mathlib/Algebra/Colimit/DirectLimit.lean b/Mathlib/Algebra/Colimit/DirectLimit.lean index 3c8edf2185..5c33f2bbbe 100644 --- a/Mathlib/Algebra/Colimit/DirectLimit.lean +++ b/Mathlib/Algebra/Colimit/DirectLimit.lean @@ -538,6 +538,24 @@ instance [Semiring R] [∀ i, AddCommMonoid (G i)] [∀ i, Module R (G i)] { add_smul _ _ := DirectLimit.induction _ fun i _ ↦ by simp_rw [smul_def, add_smul, add_def], zero_smul := DirectLimit.induction _ fun i _ ↦ by simp_rw [smul_def, zero_smul, zero_def i] } +instance [∀ i, Mul (G i)] [∀ i, SMul R (G i)] [∀ i, IsScalarTower R (G i) (G i)] + [∀ i j h, MulHomClass (T h) (G i) (G j)] [∀ i j h, MulActionHomClass (T h) R (G i) (G j)] : + IsScalarTower R (DirectLimit G f) (DirectLimit G f) where + smul_assoc r := DirectLimit.induction₂ _ fun i _ _ ↦ by + simp_rw [smul_eq_mul, smul_def, mul_def, smul_def, smul_mul_assoc] + +instance [∀ i, Mul (G i)] [∀ i, SMul R (G i)] [∀ i, SMulCommClass R (G i) (G i)] + [∀ i j h, MulHomClass (T h) (G i) (G j)] [∀ i j h, MulActionHomClass (T h) R (G i) (G j)] : + SMulCommClass R (DirectLimit G f) (DirectLimit G f) where + smul_comm r := DirectLimit.induction₂ _ fun i _ _ ↦ by + simp_rw [smul_eq_mul, smul_def, mul_def, smul_def, mul_smul_comm] + +instance [∀ i, Mul (G i)] [∀ i, SMul R (G i)] [∀ i, SMulCommClass (G i) R (G i)] + [∀ i j h, MulHomClass (T h) (G i) (G j)] [∀ i j h, MulActionHomClass (T h) R (G i) (G j)] : + SMulCommClass (DirectLimit G f) R (DirectLimit G f) := + have _ (i) : SMulCommClass R (G i) (G i) := SMulCommClass.symm _ _ _ + SMulCommClass.symm _ _ _ + end Action section DivisionSemiring diff --git a/Mathlib/Algebra/Exact.lean b/Mathlib/Algebra/Exact.lean index 0a9beae3a2..5c0e741a20 100644 --- a/Mathlib/Algebra/Exact.lean +++ b/Mathlib/Algebra/Exact.lean @@ -40,7 +40,7 @@ namespace Function variable (f : M → N) (g : N → P) (g' : P → P') /-- The maps `f` and `g` form an exact pair: `g y = 1` iff `y` belongs to the image of `f`. -/ -@[to_additive Exact /-- The maps `f` and `g` form an exact pair: +@[to_additive /-- The maps `f` and `g` form an exact pair: `g y = 0` iff `y` belongs to the image of `f`. -/] def MulExact [One P] : Prop := ∀ y, g y = 1 ↔ y ∈ Set.range f @@ -428,7 +428,7 @@ def Exact.splitInjectiveEquiv have h₂ : ∀ x, g (f x) = 0 := congr_fun h.comp_eq_zero constructor · intro x y e - simp only [prod_apply, Pi.prod, Prod.mk.injEq] at e + simp only [LinearMap.prod_apply, Function.prod_apply, Prod.mk.injEq] at e obtain ⟨z, hz⟩ := (h (x - y)).mp (by simpa [sub_eq_zero] using e.2) rw [← sub_eq_zero, ← hz, ← h₁ z, hz, map_sub, e.1, sub_self, map_zero] · rintro ⟨x, y⟩ diff --git a/Mathlib/Algebra/Group/Prod.lean b/Mathlib/Algebra/Group/Prod.lean index 7b6de8812c..2b516ede3c 100644 --- a/Mathlib/Algebra/Group/Prod.lean +++ b/Mathlib/Algebra/Group/Prod.lean @@ -221,11 +221,11 @@ theorem coe_snd : ⇑(snd M N) = Prod.snd := `f.prod g : AddHom M (N × P)` given by `(f.prod g) x = (f x, g x)` -/] protected def prod (f : M →ₙ* N) (g : M →ₙ* P) : M →ₙ* N × P where - toFun := Pi.prod f g + toFun := Function.prod f g map_mul' x y := Prod.ext (f.map_mul x y) (g.map_mul x y) @[to_additive coe_prod] -theorem coe_prod (f : M →ₙ* N) (g : M →ₙ* P) : ⇑(f.prod g) = Pi.prod f g := +theorem coe_prod (f : M →ₙ* N) (g : M →ₙ* P) : ⇑(f.prod g) = Function.prod f g := rfl @[to_additive (attr := simp) prod_apply] @@ -387,12 +387,12 @@ given by `(f.prod g) x = (f x, g x)`. -/ `f.prod g : M →+ N × P` given by `(f.prod g) x = (f x, g x)` -/] protected def prod (f : M →* N) (g : M →* P) : M →* N × P where - toFun := Pi.prod f g + toFun := Function.prod f g map_one' := Prod.ext f.map_one g.map_one map_mul' x y := Prod.ext (f.map_mul x y) (g.map_mul x y) @[to_additive coe_prod] -theorem coe_prod (f : M →* N) (g : M →* P) : ⇑(f.prod g) = Pi.prod f g := +theorem coe_prod (f : M →* N) (g : M →* P) : ⇑(f.prod g) = Function.prod f g := rfl @[to_additive (attr := simp) prod_apply] diff --git a/Mathlib/Algebra/Group/Subgroup/Basic.lean b/Mathlib/Algebra/Group/Subgroup/Basic.lean index 533e1dc3b4..83b4cc4a47 100644 --- a/Mathlib/Algebra/Group/Subgroup/Basic.lean +++ b/Mathlib/Algebra/Group/Subgroup/Basic.lean @@ -559,6 +559,10 @@ theorem normalClosure_le_normal {N : Subgroup G} [N.Normal] (h : s ⊆ N) : norm theorem normalClosure_subset_iff {N : Subgroup G} [N.Normal] : s ⊆ N ↔ normalClosure s ≤ N := ⟨normalClosure_le_normal, Set.Subset.trans subset_normalClosure⟩ +@[simp] +theorem normalClosure_eq_bot_iff : normalClosure s = ⊥ ↔ s ⊆ {1} := by + rw [eq_bot_iff, ← normalClosure_subset_iff, coe_bot] + @[to_additive (attr := gcongr)] theorem normalClosure_mono {s t : Set G} (h : s ⊆ t) : normalClosure s ≤ normalClosure t := normalClosure_le_normal (Set.Subset.trans h subset_normalClosure) diff --git a/Mathlib/Algebra/Homology/ComplexShape.lean b/Mathlib/Algebra/Homology/ComplexShape.lean index 66899bc102..7db47640aa 100644 --- a/Mathlib/Algebra/Homology/ComplexShape.lean +++ b/Mathlib/Algebra/Homology/ComplexShape.lean @@ -94,6 +94,13 @@ def symm (c : ComplexShape ι) : ComplexShape ι where next_eq w w' := c.prev_eq w w' prev_eq w w' := c.next_eq w w' +/-- If `c : ComplexShape α` is such that `c.Rel` is decidable, it is also the +case of `c.symm.Rel`. -/ +@[implicit_reducible] +def decidableRelSymm {α : Type*} (c : ComplexShape α) [DecidableRel c.Rel] : + DecidableRel c.symm.Rel := + fun a b ↦ decidable_of_iff (c.Rel b a) Iff.rfl + @[simp] theorem symm_symm (c : ComplexShape ι) : c.symm.symm = c := rfl diff --git a/Mathlib/Algebra/Homology/HomotopyCofiber.lean b/Mathlib/Algebra/Homology/HomotopyCofiber.lean index 099b803017..da1b6d6faf 100644 --- a/Mathlib/Algebra/Homology/HomotopyCofiber.lean +++ b/Mathlib/Algebra/Homology/HomotopyCofiber.lean @@ -79,6 +79,16 @@ noncomputable def XIso (i : ι) (hi : ¬ c.Rel i (c.next i)) : X φ i ≅ G.X i := eqToIso (dif_neg hi) +lemma isZero_X (i : ι) (hG : IsZero (G.X i)) + (hF : ∀ (j : ι), c.Rel i j → IsZero (F.X j)) : + IsZero (X φ i) := by + by_cases h : c.Rel i (c.next i) + · haveI := HasHomotopyCofiber.hasBinaryBiproduct φ _ _ h + refine IsZero.of_iso ?_ (XIsoBiprod φ _ _ h) + simp only [biprod_isZero_iff] + exact ⟨hF _ h, hG⟩ + · exact hG.of_iso (XIso φ i h) + /-- The second projection `(homotopyCofiber φ).X i ⟶ G.X i`. -/ noncomputable def sndX (i : ι) : X φ i ⟶ G.X i := if hi : c.Rel i (c.next i) @@ -376,7 +386,13 @@ section variable (K) variable [∀ i, HasBinaryBiproduct (K.X i) (K.X i)] - [HasHomotopyCofiber (biprod.lift (𝟙 K) (-𝟙 K))] + +/-- Given a homological complex `K`, this is the property that the morphism +`K ⟶ K ⊞ K` induced by `𝟙 K` and `-𝟙 K` has a cofiber, which allows +to define `K.cylinder` as this cofiber. -/ +abbrev HasCylinder : Prop := HasHomotopyCofiber (biprod.lift (𝟙 K) (-𝟙 K)) + +variable [K.HasCylinder] /-- The cylinder object of a homological complex `K` is the homotopy cofiber of the morphism `biprod.lift (𝟙 K) (-𝟙 K) : K ⟶ K ⊞ K`. -/ @@ -525,6 +541,7 @@ noncomputable def πCompι₀Homotopy : Homotopy (π K ≫ ι₀ K) (𝟙 K.cyli (πCompι₀Homotopy.nullHomotopy K)) /-- The homotopy equivalence between `K.cylinder` and `K`. -/ +@[simps] noncomputable def homotopyEquiv : HomotopyEquiv K.cylinder K where hom := π K inv := ι₀ K diff --git a/Mathlib/Algebra/Homology/HomotopyFiber.lean b/Mathlib/Algebra/Homology/HomotopyFiber.lean new file mode 100644 index 0000000000..e5efe421ca --- /dev/null +++ b/Mathlib/Algebra/Homology/HomotopyFiber.lean @@ -0,0 +1,163 @@ +/- +Copyright (c) 2023 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ +module + +public import Mathlib.Algebra.Homology.HomotopyCofiber +public import Mathlib.Algebra.Homology.Opposite + +/-! +# The homotopy fiber of a morphism of homological complexes + +In this file, we construct the homotopy fiber of a morphism `φ : F ⟶ G` +between homological complexes. Moreover, we dualise the definition +of the cylinder (which is a particular case of a homotopy cofiber) +in order to define the path object of a homological complex. + +-/ + +@[expose] public section + +open CategoryTheory Category Limits Preadditive Opposite + +variable {C : Type*} [Category* C] [Preadditive C] + +namespace HomologicalComplex + +attribute [local instance] ComplexShape.decidableRelSymm + +variable {α : Type*} {c : ComplexShape α} {F G K : HomologicalComplex C c} (φ : F ⟶ G) + +variable [DecidableRel c.Rel] + +section + +/-- A morphism of homological complexes `φ : F ⟶ G` has a homotopy fiber if for all +indices `i` and `j` such that `c.Rel i j`, the binary biproduct `F.X i ⊞ G.X j` exists. -/ +class HasHomotopyFiber (φ : F ⟶ G) : Prop where + hasBinaryBiproduct (φ) (i j : α) (hij : c.Rel i j) : HasBinaryBiproduct (G.X i) (F.X j) + +instance [HasBinaryBiproducts C] : HasHomotopyFiber φ where + hasBinaryBiproduct _ _ _ := inferInstance + +variable [HasHomotopyFiber φ] [DecidableRel c.Rel] + +instance : HasHomotopyCofiber ((opFunctor C c).map φ.op) where + hasBinaryBiproduct i j hij := by + have := HasHomotopyFiber.hasBinaryBiproduct φ j i hij + dsimp + infer_instance + +/-- The homotopy fiber of a morphism between homological complexes. -/ +noncomputable def homotopyFiber : HomologicalComplex C c := + (unopFunctor C c.symm).obj (op (homotopyCofiber ((opFunctor C c).map φ.op))) + +end + +variable (K) [∀ i, HasBinaryBiproduct (K.X i) (K.X i)] + +instance (i : α) : HasBinaryBiproduct (K.op.X i) (K.op.X i) := by + dsimp; infer_instance + +/-- The property that a homological complex `K` has a path object, +i.e. that the morphism `K ⟶ K ⊞ K` induced by `𝟙 K` and `-𝟙 K` +has a homotopy fiber. -/ +abbrev HasPathObject := HasHomotopyFiber (biprod.desc (𝟙 K) (-𝟙 K)) + +instance [K.HasPathObject] : + HasHomotopyCofiber (biprod.lift (𝟙 K.op) (-𝟙 K.op)) where + hasBinaryBiproduct i j hij := by + have := HasHomotopyFiber.hasBinaryBiproduct (biprod.desc (𝟙 K) (-𝟙 K)) j i hij + exact hasBinaryBiproduct_of_iso (Iso.refl _ : op (K.X j) ≅ K.op.X j) + (show op ((K ⊞ K).X i) ≅ (K.op ⊞ K.op).X i from + ((eval _ _ i).mapBiprod K K).op.symm ≪≫ biprod.opIso _ _ ≪≫ + ((eval _ _ i).mapBiprod K.op K.op).symm) + +variable [K.HasPathObject] + +/-- The path object of a homological complex is defined here by dualizing +the cylinder object of `K.op`. -/ +@[no_expose] +noncomputable def pathObject := (unopFunctor C c.symm).obj (op K.op.cylinder) + +namespace pathObject + +lemma isZero_X (i : α) (h₁ : IsZero (K.X i)) (h₂ : ∀ (j : α), c.Rel j i → IsZero (K.X j)) : + IsZero (K.pathObject.X i) := by + apply IsZero.unop + dsimp [pathObject] + refine homotopyCofiber.isZero_X _ _ ?_ (fun j hj ↦ IsZero.op (h₂ _ hj)) + exact IsZero.of_iso (by simpa using h₁.op) + ((eval Cᵒᵖ c.symm i).mapBiprod K.op K.op) + +/-- The first projection `K.pathObject ⟶ K`. -/ +@[no_expose] +noncomputable def π₀ : K.pathObject ⟶ K := + (unopFunctor C c.symm).map (cylinder.ι₀ K.op).op + +/-- The second projection `K.pathObject ⟶ K`. -/ +@[no_expose] +noncomputable def π₁ : K.pathObject ⟶ K := + (unopFunctor C c.symm).map (cylinder.ι₁ K.op).op + +/-- The inclusion `K ⟶ K.pathObject`. -/ +@[no_expose] +noncomputable def ι : K ⟶ K.pathObject := + (unopFunctor C c.symm).map (cylinder.π K.op).op + +@[reassoc (attr := simp)] +lemma π₀_ι : ι K ≫ π₀ K = 𝟙 K := + Quiver.Hom.op_inj ((opFunctor C c).map_injective (cylinder.ι₀_π K.op)) + +@[reassoc (attr := simp)] +lemma π₁_ι : ι K ≫ π₁ K = 𝟙 K := + Quiver.Hom.op_inj ((opFunctor C c).map_injective (cylinder.ι₁_π K.op)) + +/-- The homotopy between `π₀ K ≫ ι K` and `𝟙 K.pathObject`. -/ +@[no_expose] +noncomputable def π₀CompιHomotopy (hc : ∀ (i : α), ∃ j, c.Rel i j) : + Homotopy (π₀ K ≫ ι K) (𝟙 K.pathObject) := + (cylinder.πCompι₀Homotopy K.op hc).unop + +/-- The homotopy equivalence between `K` and `K.pathObject`. -/ +@[simps] +noncomputable def homotopyEquiv (hc : ∀ (i : α), ∃ j, c.Rel i j) : + HomotopyEquiv K K.pathObject where + hom := ι K + inv := π₀ K + homotopyHomInvId := Homotopy.ofEq (by simp) + homotopyInvHomId := π₀CompιHomotopy K hc + +/-- The homotopy between `pathObject.ι₀ K` and `pathObject.ι₁ K`. -/ +@[no_expose] +noncomputable def homotopy₀₁ (hc : ∀ (i : α), ∃ j, c.Rel i j) : Homotopy (π₀ K) (π₁ K) := + (cylinder.homotopy₀₁ K.op hc).unop + +section + +variable {K} (φ₀ φ₁ : F ⟶ K) (h : Homotopy φ₀ φ₁) + +/-- The morphism `F ⟶ K.pathObject` that is induced by two morphisms `φ₀ φ₁ : F ⟶ K` +and a homotopy `h : Homotopy φ₀ φ₁`. -/ +@[no_expose] +noncomputable def lift : F ⟶ K.pathObject := + letI φ : K.op.cylinder ⟶ (opFunctor C c).obj (op F) := + cylinder.desc ((opFunctor C c).map φ₀.op) + ((opFunctor C c).map φ₁.op) h.op + (unopFunctor C c.symm).map φ.op + +@[reassoc (attr := simp)] +lemma lift_π₀ : lift φ₀ φ₁ h ≫ π₀ K = φ₀ := + Quiver.Hom.op_inj ((opFunctor C c).map_injective (cylinder.ι₀_desc _ _ _)) + +@[reassoc (attr := simp)] +lemma lift_π₁ : lift φ₀ φ₁ h ≫ π₁ K = φ₁ := + Quiver.Hom.op_inj ((opFunctor C c).map_injective (cylinder.ι₁_desc _ _ _)) + +end + +end pathObject + +end HomologicalComplex diff --git a/Mathlib/Algebra/Homology/Opposite.lean b/Mathlib/Algebra/Homology/Opposite.lean index 10e5d2d49f..6810dd4cd7 100644 --- a/Mathlib/Algebra/Homology/Opposite.lean +++ b/Mathlib/Algebra/Homology/Opposite.lean @@ -160,6 +160,9 @@ def opEquivalence : (HomologicalComplex V c)ᵒᵖ ≌ HomologicalComplex Vᵒ opFunctor_map_f, Hom.isoOfComponents_hom_f] exact Category.comp_id _ +instance : (opFunctor V c).IsEquivalence := (opEquivalence V c).isEquivalence_functor +instance : (opInverse V c).IsEquivalence := (opEquivalence V c).isEquivalence_inverse + set_option backward.isDefEq.respectTransparency false in /-- Auxiliary definition for `unopEquivalence`. -/ @[simps] @@ -211,6 +214,9 @@ def unopEquivalence : (HomologicalComplex Vᵒᵖ c)ᵒᵖ ≌ HomologicalComple simp only [comp_f] exact Category.comp_id _ +instance : (unopFunctor V c).IsEquivalence := (unopEquivalence V c).isEquivalence_functor +instance : (unopInverse V c).IsEquivalence := (unopEquivalence V c).isEquivalence_inverse + instance (K : HomologicalComplex V c) (i : ι) [K.HasHomology i] : K.op.HasHomology i := inferInstanceAs <| (K.sc i).op.HasHomology @@ -435,3 +441,36 @@ instance unopFunctor_additive : (@unopFunctor ι V _ c _).Additive where end end HomologicalComplex + +namespace Homotopy + +open HomologicalComplex + +variable {V : Type*} [Category* V] {ι : Type*} {c : ComplexShape ι} [Preadditive V] + +/-- The opposite of a homotopy between morphisms of homological complexes. -/ +@[simps] +def op {F G : HomologicalComplex V c} {φ₁ φ₂ : F ⟶ G} (h : Homotopy φ₁ φ₂) : + Homotopy ((opFunctor V c).map φ₁.op) ((opFunctor V c).map φ₂.op) where + hom i j := (h.hom j i).op + zero i j hij := Quiver.Hom.unop_inj (h.zero _ _ hij) + comm n := Quiver.Hom.unop_inj (by + dsimp + rw [h.comm n] + nth_rw 2 [add_comm] + rfl) + +/-- The homotopy between morphisms of homological complexes that is deduced +from a homotopy in the opposite category. -/ +@[simps] +def unop {F G : HomologicalComplex Vᵒᵖ c} {φ₁ φ₂ : F ⟶ G} (h : Homotopy φ₁ φ₂) : + Homotopy ((unopFunctor V c).map φ₁.op) ((unopFunctor V c).map φ₂.op) where + hom i j := (h.hom j i).unop + zero i j hij := Quiver.Hom.op_inj (h.zero _ _ hij) + comm n := Quiver.Hom.op_inj (by + dsimp + rw [h.comm n] + nth_rw 2 [add_comm] + rfl) + +end Homotopy diff --git a/Mathlib/Algebra/Lie/Prod.lean b/Mathlib/Algebra/Lie/Prod.lean index 21936d6d5d..48e9844cd6 100644 --- a/Mathlib/Algebra/Lie/Prod.lean +++ b/Mathlib/Algebra/Lie/Prod.lean @@ -99,7 +99,7 @@ def prod (f : L →ₗ⁅R⁆ L₁) (g : L →ₗ⁅R⁆ L₂) : L →ₗ⁅R⁆ toLinearMap := LinearMap.prod f g map_lie' := by simp -theorem coe_prod (f : L →ₗ⁅R⁆ L₁) (g : L →ₗ⁅R⁆ L₂) : ⇑(f.prod g) = Pi.prod f g := +theorem coe_prod (f : L →ₗ⁅R⁆ L₁) (g : L →ₗ⁅R⁆ L₂) : ⇑(f.prod g) = Function.prod f g := rfl @[simp] diff --git a/Mathlib/Algebra/Module/FinitePresentation.lean b/Mathlib/Algebra/Module/FinitePresentation.lean index 36e3c5985d..ba90a5cd24 100644 --- a/Mathlib/Algebra/Module/FinitePresentation.lean +++ b/Mathlib/Algebra/Module/FinitePresentation.lean @@ -475,7 +475,7 @@ lemma exists_bijective_map_powers [Module.Finite R M] [Module.FinitePresentation ext x have : s₁.1 • l (l' x) = s₁.1 • s₀.1 • x := congr($hs₁ x) simp [lₛ, lₛ', LocalizedModule.smul'_mk, this] - let eₛ : LocalizedModule (.powers t) M ≃ₗ[Rₛ] LocalizedModule (.powers t) N := + let eₛ : LocalizedModule.Away t M ≃ₗ[Rₛ] LocalizedModule.Away t N := { __ := lₛ, invFun := ((hu₀.unit⁻¹).1 • lₛ'), left_inv := fun x ↦ congr($H_left x), @@ -505,8 +505,8 @@ lemma Module.FinitePresentation.exists_lift_equiv_of_isLocalizedModule [Module.FinitePresentation R M] [Module.FinitePresentation R N] (l : M' ≃ₗ[R] N') : ∃ (r : R) (hr : r ∈ S) - (l' : LocalizedModule (.powers r) M ≃ₗ[Localization (.powers r)] - LocalizedModule (.powers r) N), + (l' : LocalizedModule.Away r M ≃ₗ[Localization (.powers r)] + LocalizedModule.Away r N), (LocalizedModule.lift (.powers r) g fun s ↦ map_units g ⟨s.1, SetLike.le_def.mp (Submonoid.powers_le.mpr hr) s.2⟩) ∘ₗ l'.toLinearMap = l ∘ₗ (LocalizedModule.lift (.powers r) f fun s ↦ map_units f ⟨s.1, SetLike.le_def.mp @@ -581,7 +581,7 @@ instance [Module.FinitePresentation R M] : is finitely presented, then `Mₛ = M[1/r]` for some `r ∈ S`. -/ lemma IsLocalizedModule.exists_isLocalizedModule_powers_of_finitePresentation [Module.Finite R M] [Module.FinitePresentation R M'] : - ∃ r ∈ S, IsLocalizedModule (.powers r) f := by + ∃ r ∈ S, IsLocalizedModule.Away r f := by have : IsLocalizedModule S (.id (R := R) (M := M')) := ⟨IsLocalizedModule.map_units f, fun y ↦ ⟨⟨y, 1⟩, by simp⟩, by simpa using ⟨1, S.one_mem⟩⟩ obtain ⟨r, hrp, H⟩ := exists_bijective_map_powers S diff --git a/Mathlib/Algebra/Module/GradedModule.lean b/Mathlib/Algebra/Module/GradedModule.lean index 4a8a2e32e3..ef3b584f93 100644 --- a/Mathlib/Algebra/Module/GradedModule.lean +++ b/Mathlib/Algebra/Module/GradedModule.lean @@ -104,7 +104,6 @@ theorem of_smul_of [DecidableEq ιA] [DecidableEq ιB] [GMonoid A] [Gmodule A M] open AddMonoidHom -- Almost identical to the proof of `direct_sum.one_mul` -set_option backward.privateInPublic true in private theorem one_smul' [DecidableEq ιA] [DecidableEq ιB] [GMonoid A] [Gmodule A M] (x : ⨁ i, M i) : (1 : ⨁ i, A i) • x = x := by @@ -115,7 +114,6 @@ private theorem one_smul' [DecidableEq ιA] [DecidableEq ιB] [GMonoid A] [Gmodu exact DirectSum.of_eq_of_gradedMonoid_eq (one_smul (GradedMonoid A) <| GradedMonoid.mk i xi) -- Almost identical to the proof of `direct_sum.mul_assoc` -set_option backward.privateInPublic true in private theorem mul_smul' [DecidableEq ιA] [DecidableEq ιB] [GSemiring A] [Gmodule A M] (a b : ⨁ i, A i) (c : ⨁ i, M i) : (a * b) • c = a • b • c := by @@ -136,13 +134,11 @@ private theorem mul_smul' [DecidableEq ιA] [DecidableEq ιB] [GSemiring A] [Gmo DirectSum.of_eq_of_gradedMonoid_eq (mul_smul (GradedMonoid.mk ai ax) (GradedMonoid.mk bi bx) (GradedMonoid.mk ci cx)) -set_option backward.privateInPublic true in -set_option backward.privateInPublic.warn false in /-- The `Module` derived from `gmodule A M`. -/ instance module [DecidableEq ιA] [DecidableEq ιB] [GSemiring A] [Gmodule A M] : Module (⨁ i, A i) (⨁ i, M i) where - one_smul := one_smul' _ _ - mul_smul := mul_smul' _ _ + one_smul := by exact one_smul' _ _ + mul_smul := by exact mul_smul' _ _ smul_add r := (smulAddMonoidHom A M r).map_add smul_zero r := (smulAddMonoidHom A M r).map_zero add_smul r s x := by simp only [smul_def, map_add, AddMonoidHom.add_apply] diff --git a/Mathlib/Algebra/Module/LocalizedModule/Away.lean b/Mathlib/Algebra/Module/LocalizedModule/Away.lean index 9fbe7c96d9..1513c0b071 100644 --- a/Mathlib/Algebra/Module/LocalizedModule/Away.lean +++ b/Mathlib/Algebra/Module/LocalizedModule/Away.lean @@ -1,26 +1,5 @@ -/- -Copyright (c) 2025 Yongle Hu. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Yongle Hu --/ -module +module -- shake: keep-all public import Mathlib.Algebra.Module.LocalizedModule.Basic -/-! -# Localizations of modules away from an element --/ - -public section - -/-- Given `x : R` and `f : M →ₗ[R] M'`, `IsLocalization.Away x f` states that `M'` - is isomorphic to the localization of `M` at the submonoid generated by `x`. -/ -protected abbrev IsLocalizedModule.Away {R M M' : Type*} [CommSemiring R] (x : R) [AddCommMonoid M] - [Module R M] [AddCommMonoid M'] [Module R M'] (f : M →ₗ[R] M') := - IsLocalizedModule (Submonoid.powers x) f - -/-- Given `x : R`, `LocalizedModule.Away x M` is the localization of `M` at the - submonoid generated by `x`. -/ -protected abbrev LocalizedModule.Away {R : Type*} [CommSemiring R] (x : R) - (M : Type*) [AddCommMonoid M] [Module R M] := - LocalizedModule (Submonoid.powers x) M +deprecated_module (since := "2026-04-23") diff --git a/Mathlib/Algebra/Module/LocalizedModule/Basic.lean b/Mathlib/Algebra/Module/LocalizedModule/Basic.lean index 8ba95aca42..07dd45e351 100644 --- a/Mathlib/Algebra/Module/LocalizedModule/Basic.lean +++ b/Mathlib/Algebra/Module/LocalizedModule/Basic.lean @@ -1377,3 +1377,19 @@ instance [IsDomain R] (S : Submonoid R) [IsTorsionFree R M] : isTorsionFree (LocalizedModule.mkLinearMap S M) S end IsLocalizedModule + +/-! +## Localizations of modules away from an element +-/ + +/-- Given `x : R` and `f : M →ₗ[R] M'`, `IsLocalizedModule.Away x f` states that `M'` + is isomorphic to the localization of `M` at the submonoid generated by `x`. -/ +protected abbrev IsLocalizedModule.Away {R M M' : Type*} [CommSemiring R] (x : R) [AddCommMonoid M] + [Module R M] [AddCommMonoid M'] [Module R M'] (f : M →ₗ[R] M') := + IsLocalizedModule (Submonoid.powers x) f + +/-- Given `x : R`, `LocalizedModule.Away x M` is the localization of `M` at the + submonoid generated by `x`. -/ +protected abbrev LocalizedModule.Away {R : Type*} [CommSemiring R] (x : R) + (M : Type*) [AddCommMonoid M] [Module R M] := + LocalizedModule (Submonoid.powers x) M diff --git a/Mathlib/Algebra/Module/Submodule/Lattice.lean b/Mathlib/Algebra/Module/Submodule/Lattice.lean index 0295f2eb9b..8f2375d830 100644 --- a/Mathlib/Algebra/Module/Submodule/Lattice.lean +++ b/Mathlib/Algebra/Module/Submodule/Lattice.lean @@ -184,14 +184,6 @@ instance : InfSet (Submodule R M) := add_mem' := by simp +contextual [add_mem] smul_mem' := by simp +contextual [smul_mem] }⟩ -set_option backward.privateInPublic true in -private theorem sInf_le' {S : Set (Submodule R M)} {p} : p ∈ S → sInf S ≤ p := - Set.biInter_subset_of_mem - -set_option backward.privateInPublic true in -private theorem le_sInf' {S : Set (Submodule R M)} {p} : (∀ q ∈ S, p ≤ q) → p ≤ sInf S := - Set.subset_iInter₂ - protected theorem isGLB_sInf {S : Set (Submodule R M)} : IsGLB S (sInf S) := .of_image SetLike.coe_subset_coe isGLB_biInf @@ -202,22 +194,18 @@ instance : Min (Submodule R M) := add_mem' := by simp +contextual [add_mem] smul_mem' := by simp +contextual [smul_mem] }⟩ -set_option backward.privateInPublic true in -set_option backward.privateInPublic.warn false in -instance completeLattice : CompleteLattice (Submodule R M) := - { (inferInstance : OrderTop (Submodule R M)), - (inferInstance : OrderBot (Submodule R M)) with - sup := fun a b ↦ sInf { x | a ≤ x ∧ b ≤ x } - le_sup_left := fun _ _ ↦ le_sInf' fun _ ⟨h, _⟩ ↦ h - le_sup_right := fun _ _ ↦ le_sInf' fun _ ⟨_, h⟩ ↦ h - sup_le := fun _ _ _ h₁ h₂ ↦ sInf_le' ⟨h₁, h₂⟩ - inf := (· ⊓ ·) - le_inf := fun _ _ _ ↦ Set.subset_inter - inf_le_left := fun _ _ ↦ Set.inter_subset_left - inf_le_right := fun _ _ ↦ Set.inter_subset_right - sSup S := sInf {sm | ∀ s ∈ S, s ≤ sm} - isLUB_sSup _ := isGLB_upperBounds.mp Submodule.isGLB_sInf - isGLB_sInf _ := Submodule.isGLB_sInf } +instance completeLattice : CompleteLattice (Submodule R M) where + sup a b := sInf { x | a ≤ x ∧ b ≤ x } + le_sup_left _ _ := Set.subset_iInter₂ fun _ ⟨h, _⟩ ↦ h + le_sup_right _ _ := Set.subset_iInter₂ fun _ ⟨_, h⟩ ↦ h + sup_le _ _ _ h₁ h₂ := Set.biInter_subset_of_mem ⟨h₁, h₂⟩ + inf := (· ⊓ ·) + le_inf _ _ _ := Set.subset_inter + inf_le_left _ _ := Set.inter_subset_left + inf_le_right _ _ := Set.inter_subset_right + sSup S := sInf {sm | ∀ s ∈ S, s ≤ sm} + isLUB_sSup _ := isGLB_upperBounds.mp Submodule.isGLB_sInf + isGLB_sInf _ := Submodule.isGLB_sInf @[simp] theorem coe_inf : ↑(p ⊓ q) = (p ∩ q : Set M) := diff --git a/Mathlib/Algebra/MvPolynomial/Equiv.lean b/Mathlib/Algebra/MvPolynomial/Equiv.lean index 674bcf626b..a66ed77243 100644 --- a/Mathlib/Algebra/MvPolynomial/Equiv.lean +++ b/Mathlib/Algebra/MvPolynomial/Equiv.lean @@ -639,7 +639,7 @@ theorem finSuccEquiv_coeff_coeff (m : Fin n →₀ ℕ) (f : MvPolynomial (Fin ( | monomial j r => simp only [finSuccEquiv_apply, coe_eval₂Hom, eval₂_monomial, RingHom.coe_comp, Finsupp.prod_pow, Polynomial.coeff_C_mul, coeff_C_mul, coeff_monomial, Fin.prod_univ_succ, Fin.cases_zero, - Fin.cases_succ, ← map_prod, ← map_pow, Function.comp_apply] + Fin.cases_succ, ← _root_.map_prod, ← map_pow, Function.comp_apply] rw [← mul_boole, mul_comm (Polynomial.X ^ j 0), Polynomial.coeff_C_mul_X_pow]; congr 1 obtain rfl | hjmi := eq_or_ne j (m.cons i) · simpa only [cons_zero, cons_succ, if_pos rfl, monomial_eq, C_1, one_mul, diff --git a/Mathlib/Algebra/MvPolynomial/Eval.lean b/Mathlib/Algebra/MvPolynomial/Eval.lean index 574e7e2fc7..0e13948de3 100644 --- a/Mathlib/Algebra/MvPolynomial/Eval.lean +++ b/Mathlib/Algebra/MvPolynomial/Eval.lean @@ -197,7 +197,7 @@ theorem map_eval₂Hom [CommSemiring S₂] (f : R →+* S₁) (g : σ → S₁) theorem eval₂Hom_monomial (f : R →+* S₁) (g : σ → S₁) (d : σ →₀ ℕ) (r : R) : eval₂Hom f g (monomial d r) = f r * d.prod fun i k => g i ^ k := by - simp only [monomial_eq, map_mul, eval₂Hom_C, Finsupp.prod, map_prod, map_pow, eval₂Hom_X'] + simp only [coe_eval₂Hom, eval₂_monomial] @[simp] theorem eval₂Hom_smul (f : R →+* S₁) (g : σ → S₁) (r : R) (P : MvPolynomial σ R) : diff --git a/Mathlib/Algebra/Notation/Pi/Defs.lean b/Mathlib/Algebra/Notation/Pi/Defs.lean index 56fb6e8772..77be7fd2c8 100644 --- a/Mathlib/Algebra/Notation/Pi/Defs.lean +++ b/Mathlib/Algebra/Notation/Pi/Defs.lean @@ -7,6 +7,8 @@ module public import Mathlib.Algebra.Notation.Defs public import Mathlib.Tactic.Push.Attr +public import Mathlib.Logic.Function.Defs +public import Batteries.Tactic.Alias /-! # Notation for algebraic operators on pi types @@ -26,13 +28,14 @@ variable {ι α β : Type*} {G M R : ι → Type*} namespace Pi --- TODO: Do we really need this definition? If so, where to put it? -/-- The mapping into a product type built from maps into each component. -/ -@[simp] -protected def prod {α β : ι → Type*} (f : ∀ i, α i) (g : ∀ i, β i) (i : ι) : α i × β i := (f i, g i) +@[deprecated (since := "2026-04-21")] +alias prod := Function.prod + +@[deprecated (since := "2026-04-21")] +alias prod_fst_snd := Function.prod_fst_snd -lemma prod_fst_snd : Pi.prod (Prod.fst : α × β → α) (Prod.snd : α × β → β) = id := rfl -lemma prod_snd_fst : Pi.prod (Prod.snd : α × β → β) (Prod.fst : α × β → α) = .swap := rfl +@[deprecated (since := "2026-04-21")] +alias prod_snd_fst := Function.prod_snd_fst /-! `1`, `0`, `+`, `*`, `+ᵥ`, `•`, `^`, `-`, `⁻¹`, and `/` are defined pointwise. -/ diff --git a/Mathlib/Algebra/Order/BigOperators/Ring/Finset.lean b/Mathlib/Algebra/Order/BigOperators/Ring/Finset.lean index aeb1f3feb8..d027146042 100644 --- a/Mathlib/Algebra/Order/BigOperators/Ring/Finset.lean +++ b/Mathlib/Algebra/Order/BigOperators/Ring/Finset.lean @@ -141,8 +141,8 @@ lemma sum_sq_le_sum_mul_sum_of_sq_eq_mul [CommSemiring R] [LinearOrder R] [IsStr gcongr with i hi have ht : (r i * (∑ j ∈ s, g j) * (∑ j ∈ s, r j)) ^ 2 = (f i * (∑ j ∈ s, g j) ^ 2) * (g i * (∑ j ∈ s, r j) ^ 2) := by grind - refine le_of_eq_of_le ?_ (two_mul_le_add_of_sq_eq_mul - (mul_nonneg (hf i hi) (sq_nonneg _)) (mul_nonneg (hg i hi) (sq_nonneg _)) ht) + refine le_of_eq_of_le ?_ (two_mul_le_add_of_sq_le_mul + (mul_nonneg (hf i hi) (sq_nonneg _)) (mul_nonneg (hg i hi) (sq_nonneg _)) ht.le) repeat rw [mul_assoc] _ = _ := by simp_rw [sum_add_distrib, ← sum_mul]; ring diff --git a/Mathlib/Algebra/Order/Floor/Extended.lean b/Mathlib/Algebra/Order/Floor/Extended.lean index 40946b6c4e..f746b8d71f 100644 --- a/Mathlib/Algebra/Order/Floor/Extended.lean +++ b/Mathlib/Algebra/Order/Floor/Extended.lean @@ -216,6 +216,30 @@ lemma ceil_add_le : ∀ (r s : ℝ≥0∞), ⌈r + s⌉ₑ ≤ ⌈r⌉ₑ + ⌈s @[simp] lemma toENNReal_iInf {ι : Sort*} (f : ι → ℕ∞) : toENNReal (⨅ i, f i) = ⨅ i, toENNReal (f i) := eq_of_forall_le_iff fun _ ↦ by simp [← ceil_le] +@[simp] lemma preimage_toENNReal_Ioi (a : ℝ≥0∞) : + toENNReal ⁻¹' Set.Ioi a = Set.Ioi ⌊a⌋ₑ := by ext; simp + +@[simp] lemma preimage_toENNReal_Iio (a : ℝ≥0∞) : + toENNReal ⁻¹' Set.Iio a = Set.Iio ⌈a⌉ₑ := by ext; simp + +@[simp] lemma preimage_toENNReal_Iic (a : ℝ≥0∞) : + toENNReal ⁻¹' Set.Iic a = Set.Iic ⌊a⌋ₑ := by ext; simp + +@[simp] lemma preimage_toENNReal_Ici (a : ℝ≥0∞) : + toENNReal ⁻¹' Set.Ici a = Set.Ici ⌈a⌉ₑ := by ext; simp + +@[simp] lemma preimage_toENNReal_Icc (a b : ℝ≥0∞) : + toENNReal ⁻¹' Set.Icc a b = Set.Icc ⌈a⌉ₑ ⌊b⌋ₑ := by ext; simp + +@[simp] lemma preimage_toENNReal_Ico (a b : ℝ≥0∞) : + toENNReal ⁻¹' Set.Ico a b = Set.Ico ⌈a⌉ₑ ⌈b⌉ₑ := by ext; simp + +@[simp] lemma preimage_toENNReal_Ioc (a b : ℝ≥0∞) : + toENNReal ⁻¹' Set.Ioc a b = Set.Ioc ⌊a⌋ₑ ⌊b⌋ₑ := by ext; simp + +@[simp] lemma preimage_toENNReal_Ioo (a b : ℝ≥0∞) : + toENNReal ⁻¹' Set.Ioo a b = Set.Ioo ⌊a⌋ₑ ⌈b⌉ₑ := by ext; simp + end ENat namespace Mathlib.Meta.Positivity diff --git a/Mathlib/Algebra/Order/IsBotOne.lean b/Mathlib/Algebra/Order/IsBotOne.lean index 6396efb92d..8ddae9cfba 100644 --- a/Mathlib/Algebra/Order/IsBotOne.lean +++ b/Mathlib/Algebra/Order/IsBotOne.lean @@ -45,7 +45,7 @@ alias zero_le' := zero_le variable (α) in /-- Create an `OrderBot` instance, setting `1` as the bottom element. -/ -@[to_additive (attr := implicit_reducible) +@[expose, to_additive (attr := implicit_reducible) /-- Create an `OrderBot` instance, setting `0` as the bottom element. -/] def IsBotOneClass.toOrderBot : OrderBot α where bot := 1 diff --git a/Mathlib/Algebra/Order/Ring/Unbundled/Basic.lean b/Mathlib/Algebra/Order/Ring/Unbundled/Basic.lean index 2c62bef203..cd50c66319 100644 --- a/Mathlib/Algebra/Order/Ring/Unbundled/Basic.lean +++ b/Mathlib/Algebra/Order/Ring/Unbundled/Basic.lean @@ -711,6 +711,10 @@ alias pow_two_nonneg := sq_nonneg lemma mul_self_nonneg [ExistsAddOfLE R] [PosMulMono R] [AddLeftMono R] (a : R) : 0 ≤ a * a := by simpa only [sq] using sq_nonneg a +instance (priority := 100) [ExistsAddOfLE R] [PosMulMono R] [AddLeftMono R] : + ZeroLEOneClass R where + zero_le_one := by simpa only [one_mul] using mul_self_nonneg (1 : R) + /-- The sum of two squares is zero iff both elements are zero. -/ lemma mul_self_add_mul_self_eq_zero [NoZeroDivisors R] [ExistsAddOfLE R] [PosMulMono R] [AddLeftMono R] : @@ -779,13 +783,18 @@ alias four_mul_le_pow_two_add := four_mul_le_sq_add /-- Binary and division-free **arithmetic mean-geometric mean inequality** (aka AM-GM inequality) for linearly ordered commutative semirings. -/ -lemma two_mul_le_add_of_sq_eq_mul [ExistsAddOfLE R] [MulPosStrictMono R] [PosMulStrictMono R] +lemma two_mul_le_add_of_sq_le_mul [ExistsAddOfLE R] [MulPosStrictMono R] [PosMulStrictMono R] [AddLeftReflectLE R] [AddLeftMono R] {a b r : R} - (ha : 0 ≤ a) (hb : 0 ≤ b) (ht : r ^ 2 = a * b) : 2 * r ≤ a + b := by + (ha : 0 ≤ a) (hb : 0 ≤ b) (ht : r ^ 2 ≤ a * b) : 2 * r ≤ a + b := by apply nonneg_le_nonneg_of_sq_le_sq (Left.add_nonneg ha hb) - conv_rhs => rw [← pow_two] - convert four_mul_le_sq_add a b using 1 - rw [mul_mul_mul_comm, two_mul, two_add_two_eq_four, ← pow_two, ht, mul_assoc] + rw [mul_mul_mul_comm, ← pow_two r, two_mul, two_add_two_eq_four] + grw [mul_le_mul_of_nonneg_left ht zero_le_four, ← mul_assoc, four_mul_le_sq_add a b, sq] + +@[deprecated two_mul_le_add_of_sq_le_mul (since := "2026-04-20")] +lemma two_mul_le_add_of_sq_eq_mul [ExistsAddOfLE R] [MulPosStrictMono R] [PosMulStrictMono R] + [AddLeftReflectLE R] [AddLeftMono R] {a b r : R} + (ha : 0 ≤ a) (hb : 0 ≤ b) (ht : r ^ 2 = a * b) : 2 * r ≤ a + b := + two_mul_le_add_of_sq_le_mul ha hb ht.le end LinearOrderedCommSemiring diff --git a/Mathlib/Algebra/Order/SuccPred.lean b/Mathlib/Algebra/Order/SuccPred.lean index 86a9441c1c..cea3e544d7 100644 --- a/Mathlib/Algebra/Order/SuccPred.lean +++ b/Mathlib/Algebra/Order/SuccPred.lean @@ -132,8 +132,8 @@ theorem one_le_iff_pos [AddMonoidWithOne α] [ZeroLEOneClass α] [NeZero (1 : α [SuccAddOrder α] : 1 ≤ x ↔ 0 < x := by rw [← succ_le_iff_of_not_isMax not_isMax_zero, succ_eq_add_one, zero_add] -theorem one_le_iff_ne_zero [AddMonoidWithOne α] [ZeroLEOneClass α] [NeZero (1 : α)] - [SuccAddOrder α] [CanonicallyOrderedAdd α] : 1 ≤ x ↔ x ≠ 0 := by +theorem one_le_iff_ne_zero [AddMonoidWithOne α] [NeZero (1 : α)] + [SuccAddOrder α] [IsBotZeroClass α] : 1 ≤ x ↔ x ≠ 0 := by rw [Order.one_le_iff_pos, pos_iff_ne_zero] theorem covBy_iff_add_one_eq [Add α] [One α] [SuccAddOrder α] [NoMaxOrder α] : @@ -186,14 +186,12 @@ theorem IsPredLimit.lt_sub_natCast [AddCommGroupWithOne α] [PredSubOrder α] (hx : IsPredLimit x) (hy : x < y) : ∀ n : ℕ, x < y - n := hx.isPredPrelimit.lt_sub_natCast hy -theorem IsSuccLimit.natCast_lt [AddMonoidWithOne α] [SuccAddOrder α] - [OrderBot α] [CanonicallyOrderedAdd α] +theorem IsSuccLimit.natCast_lt [AddMonoidWithOne α] [SuccAddOrder α] [IsBotZeroClass α] (hx : IsSuccLimit x) : ∀ n : ℕ, n < x := by - simpa [bot_eq_zero] using hx.add_natCast_lt hx.bot_lt + simpa using hx.add_natCast_lt hx.pos -theorem not_isSuccLimit_natCast [AddMonoidWithOne α] [SuccAddOrder α] - [OrderBot α] [CanonicallyOrderedAdd α] - (n : ℕ) : ¬ IsSuccLimit (n : α) := +theorem not_isSuccLimit_natCast [AddMonoidWithOne α] [SuccAddOrder α] [IsBotZeroClass α] (n : ℕ) : + ¬ IsSuccLimit (n : α) := fun h ↦ (h.natCast_lt n).false @[simp] @@ -207,7 +205,7 @@ theorem not_isSuccLimit_add_one (a : α) [Add α] [One α] [SuccAddOrder α] [No succ_eq_add_one a ▸ not_isSuccLimit_succ a @[simp] -theorem succ_eq_zero [AddZeroClass α] [OrderBot α] [CanonicallyOrderedAdd α] [One α] [NoMaxOrder α] +theorem succ_eq_zero [AddZeroClass α] [OrderBot α] [IsBotZeroClass α] [One α] [NoMaxOrder α] [SuccAddOrder α] {a : WithBot α} : WithBot.succ a = 0 ↔ a = ⊥ := by cases a · simp [bot_eq_zero] @@ -247,30 +245,30 @@ section AddMonoidWithOne variable [AddMonoidWithOne α] [NoMaxOrder α] [SuccAddOrder α] @[simp] -theorem lt_one_iff [CanonicallyOrderedAdd α] : x < 1 ↔ x = 0 := by +theorem lt_one_iff [IsBotZeroClass α] : x < 1 ↔ x = 0 := by rw [← zero_add 1, lt_add_one_iff, nonpos_iff_eq_zero] -theorem le_one_iff [CanonicallyOrderedAdd α] : x ≤ 1 ↔ x = 0 ∨ x = 1 := by +theorem le_one_iff [IsBotZeroClass α] : x ≤ 1 ↔ x = 0 ∨ x = 1 := by rw [le_iff_lt_or_eq, lt_one_iff] @[simp] -theorem Iio_one [CanonicallyOrderedAdd α] : Set.Iio (1 : α) = {0} := by +theorem Iio_one [IsBotZeroClass α] : Set.Iio (1 : α) = {0} := by ext; simp -theorem Iic_one [CanonicallyOrderedAdd α] : Set.Iic (1 : α) = {0, 1} := by +theorem Iic_one [IsBotZeroClass α] : Set.Iic (1 : α) = {0, 1} := by ext; simp [le_one_iff] @[simp] theorem lt_two_iff : x < 2 ↔ x ≤ 1 := by rw [← one_add_one_eq_two, lt_add_one_iff] -theorem le_two_iff [CanonicallyOrderedAdd α] : x ≤ 2 ↔ x = 0 ∨ x = 1 ∨ x = 2 := by +theorem le_two_iff [IsBotZeroClass α] : x ≤ 2 ↔ x = 0 ∨ x = 1 ∨ x = 2 := by rw [le_iff_lt_or_eq, lt_two_iff, le_one_iff, or_assoc] -theorem Iio_two [CanonicallyOrderedAdd α] : Set.Iio (2 : α) = {0, 1} := by +theorem Iio_two [IsBotZeroClass α] : Set.Iio (2 : α) = {0, 1} := by ext; simp [le_one_iff] -theorem Iic_two [CanonicallyOrderedAdd α] : Set.Iic (2 : α) = {0, 1, 2} := by +theorem Iic_two [IsBotZeroClass α] : Set.Iic (2 : α) = {0, 1, 2} := by ext; simp [le_two_iff] end AddMonoidWithOne diff --git a/Mathlib/Algebra/Ring/Subring/MulOpposite.lean b/Mathlib/Algebra/Ring/Subring/MulOpposite.lean index df84955c6f..f92b3d0ab5 100644 --- a/Mathlib/Algebra/Ring/Subring/MulOpposite.lean +++ b/Mathlib/Algebra/Ring/Subring/MulOpposite.lean @@ -26,7 +26,7 @@ variable {ι : Sort*} {R : Type*} [NonAssocRing R] @[simps! coe toSubsemiring] protected def op (S : Subring R) : Subring Rᵐᵒᵖ where toSubsemiring := S.toSubsemiring.op - neg_mem' {x} hx := neg_mem (show x.unop ∈ S from hx) + neg_mem' := by simp attribute [norm_cast] coe_op @@ -37,7 +37,7 @@ theorem mem_op {x : Rᵐᵒᵖ} {S : Subring R} : x ∈ S.op ↔ x.unop ∈ S := @[simps! coe toSubsemiring] protected def unop (S : Subring Rᵐᵒᵖ) : Subring R where toSubsemiring := S.toSubsemiring.unop - neg_mem' {x} hx := neg_mem (show MulOpposite.op x ∈ S from hx) + neg_mem' := by simp attribute [norm_cast] coe_unop diff --git a/Mathlib/Algebra/Star/StarAlgHom.lean b/Mathlib/Algebra/Star/StarAlgHom.lean index c72de1d2ca..75751b30f7 100644 --- a/Mathlib/Algebra/Star/StarAlgHom.lean +++ b/Mathlib/Algebra/Star/StarAlgHom.lean @@ -488,13 +488,13 @@ def snd : A × B →⋆ₙₐ[R] B := variable {R A B C} -/-- The `Pi.prod` of two morphisms is a morphism. -/ +/-- The `Function.prod` of two morphisms is a morphism. -/ @[simps!] def prod (f : A →⋆ₙₐ[R] B) (g : A →⋆ₙₐ[R] C) : A →⋆ₙₐ[R] B × C := { f.toNonUnitalAlgHom.prod g.toNonUnitalAlgHom with - map_star' := fun x => by simp [map_star, Prod.star_def] } + map_star' := fun x => by simp [map_star, Prod.ext_iff] } -theorem coe_prod (f : A →⋆ₙₐ[R] B) (g : A →⋆ₙₐ[R] C) : ⇑(f.prod g) = Pi.prod f g := +theorem coe_prod (f : A →⋆ₙₐ[R] B) (g : A →⋆ₙₐ[R] C) : ⇑(f.prod g) = Function.prod f g := rfl @[simp] @@ -507,7 +507,7 @@ theorem snd_prod (f : A →⋆ₙₐ[R] B) (g : A →⋆ₙₐ[R] C) : (snd R B @[simp] theorem prod_fst_snd : prod (fst R A B) (snd R A B) = 1 := - DFunLike.coe_injective Pi.prod_fst_snd + DFunLike.coe_injective Function.prod_fst_snd /-- Taking the product of two maps with the same domain is equivalent to taking the product of their codomains. -/ @@ -593,12 +593,12 @@ def snd : A × B →⋆ₐ[R] B := variable {R A B C} -/-- The `Pi.prod` of two morphisms is a morphism. -/ +/-- The `Function.prod` of two morphisms is a morphism. -/ @[simps!] def prod (f : A →⋆ₐ[R] B) (g : A →⋆ₐ[R] C) : A →⋆ₐ[R] B × C := { f.toAlgHom.prod g.toAlgHom with map_star' := fun x => by simp [Prod.star_def, map_star] } -theorem coe_prod (f : A →⋆ₐ[R] B) (g : A →⋆ₐ[R] C) : ⇑(f.prod g) = Pi.prod f g := +theorem coe_prod (f : A →⋆ₐ[R] B) (g : A →⋆ₐ[R] C) : ⇑(f.prod g) = Function.prod f g := rfl @[simp] @@ -611,7 +611,7 @@ theorem snd_prod (f : A →⋆ₐ[R] B) (g : A →⋆ₐ[R] C) : (snd R B C).com @[simp] theorem prod_fst_snd : prod (fst R A B) (snd R A B) = 1 := - DFunLike.coe_injective Pi.prod_fst_snd + DFunLike.coe_injective Function.prod_fst_snd /-- Taking the product of two maps with the same domain is equivalent to taking the product of their codomains. -/ diff --git a/Mathlib/AlgebraicGeometry/AffineScheme.lean b/Mathlib/AlgebraicGeometry/AffineScheme.lean index 0c784ad637..6d88881da5 100644 --- a/Mathlib/AlgebraicGeometry/AffineScheme.lean +++ b/Mathlib/AlgebraicGeometry/AffineScheme.lean @@ -274,6 +274,11 @@ theorem exists_isAffineOpen_mem_and_subset {X : Scheme.{u}} {x : X} exact ⟨Scheme.Hom.opensRange f (H := hf.1), ⟨AlgebraicGeometry.isAffineOpen_opensRange f (H := hf.1), hf.2.1, hf.2.2⟩⟩ +lemma Scheme.exists_Spec_apply_eq {X : Scheme.{u}} (x : X) : + ∃ (R : CommRingCat.{u}) (f : Spec R ⟶ X) (_ : IsOpenImmersion f) (y : Spec R), + f.base y = x := + ⟨X.affineOpenCover.X _, X.affineOpenCover.f _, inferInstance, X.affineOpenCover.covers x⟩ + instance Scheme.isAffine_affineCover (X : Scheme) (i : X.affineCover.I₀) : IsAffine (X.affineCover.X i) := isAffine_Spec _ diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/Affine/Point.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/Affine/Point.lean index 117f2ad7e9..f1b4331644 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/Affine/Point.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/Affine/Point.lean @@ -377,16 +377,21 @@ lemma XYIdeal'_eq {x y : F} (h : W.Nonsingular x y) : (XYIdeal' h : FractionalIdeal W.CoordinateRing⁰ W.FunctionField) = XYIdeal W x (C y) := rfl +-- note: giving `W` to `XYIdeal'` explicitly hugely speeds up elaboration for some reason. +-- see https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/Field.20.28FunctionField.20.3Fm.2E19.29/near/594011283 lemma mk_XYIdeal'_neg_mul {x y : F} (h : W.Nonsingular x y) : - ClassGroup.mk (XYIdeal' <| (nonsingular_neg ..).mpr h) * ClassGroup.mk (XYIdeal' h) = 1 := by + ClassGroup.mk (XYIdeal' (W := W) <| (nonsingular_neg ..).mpr h) * + ClassGroup.mk (XYIdeal' (W := W) h) = 1 := by rw [← map_mul] exact (ClassGroup.mk_eq_one_of_coe_ideal <| (coeIdeal_mul ..).symm.trans <| FractionalIdeal.coeIdeal_inj.mpr <| XYIdeal_neg_mul h).mpr ⟨_, XClass_ne_zero x, rfl⟩ +-- note: giving `W` to `XYIdeal'` explicitly hugely speeds up elaboration for some reason. +-- see https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/Field.20.28FunctionField.20.3Fm.2E19.29/near/594011283 lemma mk_XYIdeal'_mul_mk_XYIdeal' [DecidableEq F] {x₁ x₂ y₁ y₂ : F} (h₁ : W.Nonsingular x₁ y₁) (h₂ : W.Nonsingular x₂ y₂) (hxy : ¬(x₁ = x₂ ∧ y₁ = W.negY x₂ y₂)) : - ClassGroup.mk (XYIdeal' h₁) * ClassGroup.mk (XYIdeal' h₂) = - ClassGroup.mk (XYIdeal' <| nonsingular_add h₁ h₂ hxy) := by + ClassGroup.mk (XYIdeal' (W := W) h₁) * ClassGroup.mk (XYIdeal' (W := W) h₂) = + ClassGroup.mk (XYIdeal' (W := W) <| nonsingular_add h₁ h₂ hxy) := by rw [← map_mul] exact (ClassGroup.mk_eq_mk_of_coe_ideal (coeIdeal_mul ..).symm <| XYIdeal'_eq _).mpr ⟨_, _, XClass_ne_zero _, YClass_ne_zero _, XYIdeal_mul_XYIdeal h₁.left h₂.left hxy⟩ @@ -723,8 +728,10 @@ noncomputable def toClass : W.Point →+ Additive (ClassGroup W.CoordinateRing) lemma toClass_zero : toClass (0 : W.Point) = 0 := rfl +-- note: giving `W` to `XYIdeal'` explicitly hugely speeds up elaboration for some reason. +-- see https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/Field.20.28FunctionField.20.3Fm.2E19.29/near/594011283 lemma toClass_some {x y : F} (h : W.Nonsingular x y) : - toClass (some _ _ h) = ClassGroup.mk (CoordinateRing.XYIdeal' h) := + toClass (some _ _ h) = ClassGroup.mk (CoordinateRing.XYIdeal' (W := W) h) := rfl private lemma add_eq_zero (P Q : W.Point) : P + Q = 0 ↔ P = -Q := by diff --git a/Mathlib/AlgebraicGeometry/Modules/Tilde.lean b/Mathlib/AlgebraicGeometry/Modules/Tilde.lean index 28f7e535af..b5d687ac24 100644 --- a/Mathlib/AlgebraicGeometry/Modules/Tilde.lean +++ b/Mathlib/AlgebraicGeometry/Modules/Tilde.lean @@ -112,7 +112,7 @@ theorem toOpen_res (U V : Opens (PrimeSpectrum.Top R)) (i : V ⟶ U) : toOpen M U ≫ (modulesSpecToSheaf.obj (tilde M)).presheaf.map i.op = toOpen M V := rfl -instance (f : R) : IsLocalizedModule (.powers f) (toOpen M (basicOpen f)).hom := +instance (f : R) : IsLocalizedModule.Away f (toOpen M (basicOpen f)).hom := .of_linearEquiv (.powers f) (StructureSheaf.toOpenₗ R M (basicOpen f)) ((modulesSpecToSheafIso M).app _).toLinearEquiv.symm diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Affine.lean b/Mathlib/AlgebraicGeometry/Morphisms/Affine.lean index 5a61725e13..648670f27f 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Affine.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Affine.lean @@ -200,6 +200,20 @@ instance {X Y S : Scheme} (f : X ⟶ S) (g : Y ⟶ S) [IsAffineHom g] [IsAffine letI : IsAffineHom (pullback.fst f g) := MorphismProperty.pullback_fst _ _ ‹_› isAffine_of_isAffineHom (pullback.fst f g) +lemma IsAffine.of_isPullback {P : Scheme.{u}} {fst : P ⟶ X} {snd : P ⟶ Y} {f : X ⟶ Z} {g : Y ⟶ Z} + [IsAffine X] [IsAffineHom g] (h : IsPullback fst snd f g) : + IsAffine P := + .of_isIso h.isoPullback.hom + +lemma isPushout_appTop_of_isPullback {P : Scheme.{u}} {fst : P ⟶ X} {snd : P ⟶ Y} {f : X ⟶ Z} + {g : Y ⟶ Z} [IsAffine X] [IsAffine Y] [IsAffine Z] (h : IsPullback fst snd f g) : + IsPushout f.appTop g.appTop fst.appTop snd.appTop := by + have : IsAffine P := .of_isPullback h + have : IsPullback (AffineScheme.ofHom fst) (AffineScheme.ofHom snd) (AffineScheme.ofHom f) + (AffineScheme.ofHom g) := + IsPullback.of_map_of_faithful AffineScheme.forgetToScheme.{u} h + exact (IsPullback.map AffineScheme.Γ.rightOp this).unop.flip + set_option backward.isDefEq.respectTransparency false in instance {U V X : Scheme.{u}} (f : U ⟶ X) (g : V ⟶ X) [IsAffineHom f] [IsAffineHom g] : IsAffineHom (coprod.desc f g) := by diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Finite.lean b/Mathlib/AlgebraicGeometry/Morphisms/Finite.lean index 1374d1d091..86a83253b5 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Finite.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Finite.lean @@ -64,6 +64,7 @@ instance : ContainsIdentities @IsFinite := instance : IsMultiplicative @IsFinite where +@[simp] lemma SpecMap_iff {R S : CommRingCat.{u}} (f : R ⟶ S) : IsFinite (Spec.map f) ↔ f.hom.Finite := by rw [HasAffineProperty.iff_of_isAffine (P := @IsFinite), and_iff_right (by infer_instance), @@ -153,6 +154,11 @@ instance {U V X : Scheme.{u}} (f : U ⟶ X) (g : V ⟶ X) [IsFinite f] [IsFinite end IsFinite +lemma Scheme.Hom.finite_appTop {X Y : Scheme.{u}} (f : X ⟶ Y) [IsAffine X] [IsAffine Y] + [IsFinite f] : + f.appTop.hom.Finite := + (HasAffineProperty.iff_of_isAffine (P := @IsFinite).mp inferInstance).2 + /-- If `X` is a Jacobson scheme and `k` is a field, `Spec(k) ⟶ X` is finite iff it is (locally) of finite type. (The statement is more general to allow the empty scheme as well) -/ diff --git a/Mathlib/AlgebraicGeometry/Morphisms/FinitePresentation.lean b/Mathlib/AlgebraicGeometry/Morphisms/FinitePresentation.lean index a2f6479c47..20b222fa62 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/FinitePresentation.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/FinitePresentation.lean @@ -67,6 +67,16 @@ instance (priority := 900) locallyOfFinitePresentation_of_isOpenImmersion [IsOpe instance : MorphismProperty.IsStableUnderComposition @LocallyOfFinitePresentation := HasRingHomProperty.stableUnderComposition RingHom.finitePresentation_stableUnderComposition +@[simp] +lemma LocallyOfFinitePresentation.SpecMap_iff {R S : CommRingCat.{u}} (f : R ⟶ S) : + LocallyOfFinitePresentation (Spec.map f) ↔ f.hom.FinitePresentation := + HasRingHomProperty.Spec_iff + +lemma Scheme.Hom.finitePresentation_appTop {X Y : Scheme.{u}} (f : X ⟶ Y) [IsAffine X] [IsAffine Y] + [LocallyOfFinitePresentation f] : + f.appTop.hom.FinitePresentation := + HasRingHomProperty.appTop (P := @LocallyOfFinitePresentation) _ inferInstance + instance locallyOfFinitePresentation_comp {X Y Z : Scheme.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) [hf : LocallyOfFinitePresentation f] [hg : LocallyOfFinitePresentation g] : LocallyOfFinitePresentation (f ≫ g) := diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Flat.lean b/Mathlib/AlgebraicGeometry/Morphisms/Flat.lean index 2461f84450..ea2689ea7b 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Flat.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Flat.lean @@ -63,6 +63,10 @@ instance (priority := 900) [IsOpenImmersion f] : Flat f := instance : MorphismProperty.IsStableUnderComposition @Flat := HasRingHomProperty.stableUnderComposition RingHom.Flat.stableUnderComposition +@[simp] +lemma SpecMap_iff {R S : CommRingCat.{u}} {f : R ⟶ S} : Flat (Spec.map f) ↔ f.hom.Flat := + HasRingHomProperty.Spec_iff + instance comp {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [hf : Flat f] [hg : Flat g] : Flat (f ≫ g) := MorphismProperty.comp_mem _ f g hf hg @@ -166,6 +170,10 @@ lemma flat_and_surjective_iff_faithfullyFlat_of_isAffine [IsAffine X] [IsAffine end Flat +lemma Scheme.Hom.flat_appTop [IsAffine X] [IsAffine Y] [Flat f] : + f.appTop.hom.Flat := + HasRingHomProperty.appTop (P := @Flat) _ inferInstance + lemma flat_and_surjective_SpecMap_iff {R S : CommRingCat.{u}} (f : R ⟶ S) : Flat (Spec.map f) ∧ Surjective (Spec.map f) ↔ f.hom.FaithfullyFlat := by rw [HasRingHomProperty.Spec_iff (P := @Flat), diff --git a/Mathlib/AlgebraicGeometry/Morphisms/FlatRank.lean b/Mathlib/AlgebraicGeometry/Morphisms/FlatRank.lean new file mode 100644 index 0000000000..a56323f6ca --- /dev/null +++ b/Mathlib/AlgebraicGeometry/Morphisms/FlatRank.lean @@ -0,0 +1,299 @@ +/- +Copyright (c) 2025 Christian Merten. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Merten +-/ +module + +public import Mathlib.CategoryTheory.Limits.Shapes.Countable +public import Mathlib.RingTheory.Finiteness.ModuleFinitePresentation +public import Mathlib.AlgebraicGeometry.Morphisms.Flat +public import Mathlib.AlgebraicGeometry.Morphisms.Finite +public import Mathlib.AlgebraicGeometry.Morphisms.FinitePresentation +public import Mathlib.RingTheory.Flat.Rank + +/-! +# Rank of a finite flat morphism of schemes + +In this file we define the rank `AlgebraicGeometry.Scheme.Hom.finrank` of a finite flat morphism of +schemes `f : X ⟶ Y`. It is locally constant and is characterized by the condition that the rank of +`Spec S ⟶ Spec R` at some prime `p` of `R` is the rank of `S` as an `R`-algebra at `p`. + +## Main definitions + +- `AlgebraicGeometry.Scheme.Hom.finrank`: For a morphism `f : X ⟶ Y` of schemes, the function + `Y → ℕ` sending `y` to the rank of `f_* 𝒪_X` over `𝒪_Y` at `y`. Instead of talking about + sheaves, we define it by choosing an open neighbourhood of `y`. + This is sometimes also called the degree of a morphism in the literature. + +## Main results + +- `AlgebraicGeometry.Scheme.Hom.isLocallyConstant_finrank`: The rank function of a finite flat + locally finitely presented morphism is locally constant. +- `AlgebraicGeometry.Scheme.Hom.one_le_finrank_iff_surjective`: The rank function is at least `1` + everywhere if and only if the morphism is surjective. +- `AlgebraicGeometry.Scheme.Hom.isIso_iff_finrank_eq`: A finite flat locally finitely presented + morphism is an isomorphism if and only if its rank is constant equal to `1`. + +## TODO + +- Relate `Hom.finrank f y` to the rank of `f_* 𝒪_X` over `𝒪_Y` at `y` when the API for + locally free sheaves of modules is developed. +-/ + +public section + +open CategoryTheory Limits TopologicalSpace TensorProduct + +universe u + +namespace AlgebraicGeometry + +noncomputable section + +variable {X S Y T : Scheme.{u}} (f : X ⟶ S) + +/-- The rank of a morphism `f : X ⟶ S` of schemes at a point `s : S`, when `S` is affine. +This is used as an auxiliary definition to define `AlgebraicGeometry.finrank`. -/ +private def IsAffine.finrank [IsAffine S] (f : X ⟶ S) (s : S) : ℕ := + f.appTop.hom.finrank (S.isoSpec.hom s) + +private lemma IsAffine.finrank_of_isPullback [IsAffine S] [IsAffine T] + (f' : Y ⟶ T) (g' : Y ⟶ X) (g : T ⟶ S) (h : IsPullback g' f' f g) [Flat f] [IsFinite f] + (s : S) (t : T) (hs : g t = s) : + IsAffine.finrank f' t = IsAffine.finrank f s := by + subst hs + have : IsAffine X := isAffine_of_isAffineHom f + have : IsPushout f.appTop g.appTop g'.appTop f'.appTop := isPushout_appTop_of_isPullback h + dsimp [finrank] + rw [CommRingCat.finrank_eq_of_isPushout this f.flat_appTop f.finite_appTop (T.isoSpec.hom t), + ← Scheme.Hom.comp_apply, ← Scheme.isoSpec_hom_naturality] + rfl + +private lemma IsAffine.finrank_snd [IsAffine S] [IsAffine T] + (g : T ⟶ S) [Flat f] [IsFinite f] (x : T) : + IsAffine.finrank (pullback.snd f g) x = IsAffine.finrank f (g x) := + finrank_of_isPullback f _ _ _ (.of_hasPullback _ _) _ _ rfl + +private lemma IsAffine.finrank_comp_left_of_isIso [IsAffine S] + (f : X ⟶ Y) (g : Y ⟶ S) [IsIso f] [IsFinite g] [Flat g] : + IsAffine.finrank (f ≫ g) = IsAffine.finrank g := by + ext z + apply finrank_of_isPullback g (f ≫ g) f (𝟙 _) _ _ _ rfl + exact IsPullback.of_horiz_isIso (by simp) + +/-- The rank of a morphism `f : X ⟶ S` of schemes at a point `s : S`. When `f` is finite, +flat and locally of finite presentation, this is a locally constant function (see +`AlgebraicGeometry.isLocallyConstant_finrank`). -/ +@[stacks 02KA "second part"] +def Scheme.Hom.finrank {X S : Scheme.{u}} (f : X ⟶ S) (s : S) : ℕ := + IsAffine.finrank (pullback.snd f (S.affineOpenCover.f <| S.affineOpenCover.idx s)) + (S.affineOpenCover.covers s).choose + +set_option backward.isDefEq.respectTransparency false in +private lemma Scheme.Hom.finrank_eq_finrank_snd_of_isAffine (g : T ⟶ S) [IsAffine T] (t : T) + [Flat f] [IsFinite f] : + f.finrank (g t) = IsAffine.finrank (pullback.snd f g) t := by + let i := S.affineOpenCover.f (S.affineOpenCover.idx (g t)) + obtain ⟨y, hyl, hyr⟩ := Scheme.Pullback.exists_preimage_pullback + (S.affineOpenCover.covers <| g t).choose t (S.affineOpenCover.covers <| g t).choose_spec + obtain ⟨R, u, hu, z, rfl⟩ := (pullback i g).exists_Spec_apply_eq y + trans IsAffine.finrank (pullback.snd (pullback.snd f g) (u ≫ pullback.snd _ _)) z + · refine (IsAffine.finrank_of_isPullback _ _ ?_ ?_ ?_ _ _ ?_).symm + · exact pullback.map _ _ _ _ (pullback.fst f g) (u ≫ pullback.fst _ _) g + pullback.condition.symm (by simp [← pullback.condition]; rfl) + · exact u ≫ pullback.fst _ _ + · apply IsPullback.map_fst_comp_fst_snd_comp_fst + · exact hyl + · simp_rw [← hyr] + exact IsAffine.finrank_snd (pullback.snd f g) (u ≫ pullback.snd _ _) z + +private lemma Scheme.Hom.finrank_eq_of_isAffine [IsAffine S] [Flat f] [IsFinite f] (s : S) : + f.finrank s = IsAffine.finrank f s := by + rw [show s = (𝟙 S : S ⟶ S) s from rfl, finrank_eq_finrank_snd_of_isAffine, + IsAffine.finrank_snd] + +@[simp] +lemma Scheme.Hom.finrank_SpecMap_eq_finrank {R S : CommRingCat.{u}} {f : R ⟶ S} (hf₁ : f.hom.Finite) + (hf₂ : f.hom.Flat) : + finrank (Spec.map f) = f.hom.finrank := by + simp only [← IsFinite.SpecMap_iff, ← Flat.SpecMap_iff] at hf₁ hf₂ + have hf₁ : (Spec.map f).appTop.hom.Finite := (Spec.map f).finite_appTop + have hf₂ : (Spec.map f).appTop.hom.Flat := (Spec.map f).flat_appTop + ext + rw [finrank_eq_of_isAffine, IsAffine.finrank] + have : f = (Scheme.ΓSpecIso R).inv ≫ (Spec.map f).appTop ≫ (Scheme.ΓSpecIso S).hom := by simp + conv_rhs => rw [this] + dsimp + rw [RingHom.finrank_comp_right_of_bijective _ _ (ConcreteCategory.bijective_of_isIso _)] + · rw [RingHom.finrank_comp_left_of_bijective _ _ (ConcreteCategory.bijective_of_isIso _) hf₁ hf₂] + · exact .comp (.of_surjective _ (ConcreteCategory.bijective_of_isIso _).surjective) hf₁ + · exact .comp hf₂ (.of_bijective (ConcreteCategory.bijective_of_isIso _)) + · simp [isoSpec_Spec_hom, SpecMap_ΓSpecIso_hom, ← AlgebraicGeometry.Spec.map_apply, + ← Scheme.Hom.comp_apply, toSpecΓ_SpecMap_ΓSpecIso_inv] + +lemma Scheme.Hom.finrank_SpecMap_algebraMap (R S : Type u) [CommRing R] [CommRing S] [Algebra R S] + [Module.Finite R S] [Module.Flat R S] (x : PrimeSpectrum R) : + finrank (Spec.map (CommRingCat.ofHom <| algebraMap R S)) x = Module.rankAtStalk S x := by + rw [finrank_SpecMap_eq_finrank] + · simp + · simpa [RingHom.finite_algebraMap] + · simpa [RingHom.flat_algebraMap_iff] + +variable (f : X ⟶ Y) [Flat f] [IsFinite f] + +@[simp] +lemma Scheme.Hom.finrank_comp_left_of_isIso (f : X ⟶ Y) (g : Y ⟶ S) + [IsIso f] [Flat g] [IsFinite g] : + finrank (f ≫ g) = finrank g := by + ext z + let e : pullback (f ≫ g) (S.affineOpenCover.f (S.affineOpenCover.idx z)) ≅ + pullback g (S.affineOpenCover.f (S.affineOpenCover.idx z)) := + (pullbackRightPullbackFstIso g (S.affineOpenCover.f (S.affineOpenCover.idx z)) f).symm ≪≫ + asIso (pullback.snd f (pullback.fst g (S.affineOpenCover.f _))) + have : e.hom ≫ pullback.snd _ _ = pullback.snd _ _ := by simp [e] + rw [finrank, finrank, ← this, IsAffine.finrank_comp_left_of_isIso] + +lemma Scheme.Hom.finrank_pullback_snd {Z : Scheme.{u}} (f : X ⟶ Z) (g : Y ⟶ Z) + [Flat f] [IsFinite f] (y : Y) : + finrank (pullback.snd f g) y = finrank f (g y) := by + obtain ⟨R, i, _, y', rfl⟩ := Y.exists_Spec_apply_eq y + rw [← Scheme.Hom.comp_apply, finrank_eq_finrank_snd_of_isAffine, + finrank_eq_finrank_snd_of_isAffine, ← pullbackLeftPullbackSndIso_hom_snd f g i, + ← finrank_eq_of_isAffine, ← finrank_eq_of_isAffine, finrank_comp_left_of_isIso] + +lemma Scheme.Hom.finrank_of_isPullback {P X Y Z : Scheme.{u}} (fst : P ⟶ X) (snd : P ⟶ Y) + (f : X ⟶ Z) (g : Y ⟶ Z) (h : IsPullback fst snd f g) [Flat f] [IsFinite f] (y : Y) : + finrank snd y = finrank f (g y) := by + rw [← h.isoPullback_hom_snd, finrank_comp_left_of_isIso, finrank_pullback_snd] + +lemma Scheme.Hom.finrank_pullback_fst {Z : Scheme.{u}} (f : X ⟶ Z) (g : Y ⟶ Z) + [Flat f] [IsFinite f] (y : Y) : + finrank (pullback.fst g f) y = finrank f (g y) := + finrank_of_isPullback (pullback.snd g f) _ _ _ (.flip <| .of_hasPullback _ _) y + +nonrec lemma Scheme.Hom.one_le_finrank_map (x : X) : 1 ≤ finrank f (f x) := by + wlog hY : ∃ R, Y = Spec R + · obtain ⟨R, g, hg, y, hy⟩ := Y.exists_Spec_apply_eq (f x) + rw [← hy, ← finrank_pullback_snd] + obtain ⟨z, hzl, hzr⟩ := Scheme.Pullback.exists_preimage_pullback (f := f) (g := g) x y hy.symm + rw [hzr.symm] + refine this _ _ ⟨_, rfl⟩ + obtain ⟨R, rfl⟩ := hY + wlog hX : ∃ S, X = Spec S + · have _ : IsAffine X := isAffine_of_isAffineHom f + have heq : f x = (X.isoSpec.inv ≫ f) (X.isoSpec.hom x) := by simp + rw [← finrank_comp_left_of_isIso X.isoSpec.inv, heq] + exact this _ _ _ ⟨_, rfl⟩ + obtain ⟨S, rfl⟩ := hX + obtain ⟨φ, rfl⟩ := Spec.map_surjective f + simp only [IsFinite.SpecMap_iff, Flat.SpecMap_iff] at * + rw [finrank_SpecMap_eq_finrank ‹_› ‹_›] + algebraize [φ.hom] + rw [← RingHom.algebraMap_toAlgebra φ.hom, RingHom.finrank_algebraMap, Nat.add_one_le_iff, + PrimeSpectrum.rankAtStalk_pos_iff_mem_range_comap] + use x + rfl + +set_option backward.isDefEq.respectTransparency false in +/-- A finite flat locally finitely presented morphism is surjective if and only if its rank +function is at least `1` everywhere. -/ +nonrec lemma Scheme.Hom.one_le_finrank_iff_surjective : 1 ≤ finrank f ↔ Surjective f := by + refine ⟨fun h ↦ ?_, fun _ ↦ ?_⟩ + · wlog hY : ∃ R, Y = Spec R + · rw [IsZariskiLocalAtTarget.iff_of_openCover (P := @Surjective) Y.affineCover] + intro i + dsimp only [Scheme.Cover.pullbackHom] + refine this _ (fun y ↦ ?_) ⟨_, rfl⟩ + rw [finrank_pullback_snd] + exact h _ + obtain ⟨R, rfl⟩ := hY + wlog hX : ∃ S, X = Spec S + · have _ : IsAffine X := isAffine_of_isAffineHom f + rw [← MorphismProperty.cancel_left_of_respectsIso @Surjective X.isoSpec.inv] + refine this _ _ (fun x ↦ ?_) ⟨_, rfl⟩ + rw [finrank_comp_left_of_isIso] + exact h x + obtain ⟨S, rfl⟩ := hX + obtain ⟨φ, rfl⟩ := Spec.map_surjective f + constructor + intro x + specialize h x + simp only [IsFinite.SpecMap_iff, Flat.SpecMap_iff] at * + rw [finrank_SpecMap_eq_finrank ‹_› ‹_›] at h + algebraize [φ.hom] + exact (PrimeSpectrum.rankAtStalk_pos_iff_mem_range_comap _).mp h + · intro y + obtain ⟨x, rfl⟩ := f.surjective y + exact one_le_finrank_map f x + +/-- The rank of a finite flat locally finitely presented morphism is locally constant. -/ +nonrec lemma Scheme.Hom.isLocallyConstant_finrank [LocallyOfFinitePresentation f] : + IsLocallyConstant (finrank f) := by + wlog hY : ∃ R, Y = Spec R + · rw [IsLocallyConstant.iff_exists_open] + intro y + obtain ⟨R, g, _, x, rfl⟩ := Y.exists_Spec_apply_eq y + simp_rw [IsLocallyConstant.iff_exists_open] at this + obtain ⟨U, hU, hxU, H⟩ := this (pullback.snd f g) ⟨_, rfl⟩ x + refine ⟨g ''ᵁ ⟨U, hU⟩, (g ''ᵁ ⟨U, hU⟩).2, ⟨x, hxU, rfl⟩, fun y ↦ ?_⟩ + rintro ⟨y', (hyU : y' ∈ U), (rfl : g y' = y)⟩ + rw [← finrank_pullback_snd _ g, ← finrank_pullback_snd _ g] + exact H y' hyU + obtain ⟨R, rfl⟩ := hY + wlog hX : ∃ S, X = Spec S + · have _ : IsAffine X := isAffine_of_isAffineHom f + rw [← finrank_comp_left_of_isIso X.isoSpec.inv] + exact this _ _ ⟨_, rfl⟩ + obtain ⟨S, rfl⟩ := hX + obtain ⟨φ, rfl⟩ := Spec.map_surjective f + simp only [Flat.SpecMap_iff, IsFinite.SpecMap_iff, LocallyOfFinitePresentation.SpecMap_iff] at * + rw [finrank_SpecMap_eq_finrank ‹_› ‹_›] + algebraize [φ.hom] + have := Module.FinitePresentation.of_finite_of_finitePresentation + exact Module.isLocallyConstant_rankAtStalk + +set_option backward.isDefEq.respectTransparency false in +/-- The rank of an isomorphism is `1`. -/ +lemma Scheme.Hom.finrank_eq_one_of_isIso (f : X ⟶ Y) [IsIso f] : finrank f = 1 := by + ext y + obtain ⟨R, g, _, y, rfl⟩ := Y.exists_Spec_apply_eq y + have : Nontrivial R := y.nontrivial + rw [← finrank_pullback_snd, ← Category.comp_id (pullback.snd f g), finrank_comp_left_of_isIso, + ← Spec.map_id, finrank_SpecMap_eq_finrank, CommRingCat.hom_id, Pi.one_apply, + ← Algebra.algebraMap_self, RingHom.finrank_algebraMap] + · simp + · exact RingHom.Finite.id R + · exact RingHom.Flat.id ↑R + +/-- A finite flat locally finitely presented morphism is an isomorphism if and only if +its rank is constant equal to `1`. -/ +nonrec lemma Scheme.Hom.isIso_iff_finrank_eq : IsIso f ↔ finrank f = 1 := by + refine ⟨fun h ↦ finrank_eq_one_of_isIso f, fun h ↦ ?_⟩ + wlog hY : ∃ R, Y = Spec R + · rw [← MorphismProperty.isomorphisms.iff, + IsZariskiLocalAtTarget.iff_of_openCover (P := .isomorphisms Scheme) Y.affineCover] + intro i + dsimp [Scheme.Cover.pullbackHom] + refine this _ ?_ ⟨_, rfl⟩ + ext y + rw [finrank_pullback_snd, h, Pi.one_apply, Pi.one_apply] + obtain ⟨R, rfl⟩ := hY + wlog hX : ∃ S, X = Spec S + · have _ : IsAffine X := isAffine_of_isAffineHom f + rw [← isIso_comp_left_iff X.isoSpec.inv] + refine this _ _ ?_ ⟨_, rfl⟩ + rw [finrank_comp_left_of_isIso, h] + obtain ⟨S, rfl⟩ := hX + obtain ⟨φ, rfl⟩ := Spec.map_surjective f + simp only [IsFinite.SpecMap_iff, Flat.SpecMap_iff] at * + algebraize [φ.hom] + have : IsIso φ := by + rw [ConcreteCategory.isIso_iff_bijective] + apply Module.algebraMap_bijective_of_rankAtStalk + rwa [finrank_SpecMap_eq_finrank ‹_› ‹_›] at h + infer_instance + +end + +end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/StructureSheaf.lean b/Mathlib/AlgebraicGeometry/StructureSheaf.lean index c1655ed34a..f425433310 100644 --- a/Mathlib/AlgebraicGeometry/StructureSheaf.lean +++ b/Mathlib/AlgebraicGeometry/StructureSheaf.lean @@ -403,7 +403,7 @@ variable (R M) in /-- The canonical linear map interpreting `s ∈ M_f` as a section of the structure sheaf on the basic open defined by `f ∈ R`. -/ def toBasicOpenₗ (f : R) : - LocalizedModule (.powers f) M →ₗ[R] Γ(M, PrimeSpectrum.basicOpen f) := + LocalizedModule.Away f M →ₗ[R] Γ(M, PrimeSpectrum.basicOpen f) := IsLocalizedModule.lift (.powers f) (LocalizedModule.mkLinearMap ..) (toOpenₗ R M _) <| by simp only [Subtype.forall] exact Submonoid.powers_le (P := (IsUnit.submonoid _).comap (algebraMap R _)).mpr @@ -511,7 +511,7 @@ theorem toBasicOpenₗ_surjective (f : R) : Function.Surjective (toBasicOpenₗ simp_rw [one_smul, Finset.smul_sum, Submonoid.smul_def, smul_comm (b i), hab _ i, ← smul_assoc, ← Finset.sum_smul, hc] -public instance (f : R) : IsLocalizedModule (.powers f) (toOpenₗ R M (basicOpen f)) := by +public instance (f : R) : IsLocalizedModule.Away f (toOpenₗ R M (basicOpen f)) := by convert IsLocalizedModule.of_linearEquiv (.powers f) (LocalizedModule.mkLinearMap (.powers f) M) (.ofBijective _ ⟨toBasicOpenₗ_injective _, toBasicOpenₗ_surjective _⟩) ext x @@ -537,7 +537,7 @@ public lemma algebraMap_obj_top_bijective : set_option backward.isDefEq.respectTransparency false in public instance (f : R) : IsLocalization.Away f Γ(R, basicOpen f) := (isLocalizedModule_iff_isLocalization' _ _).mp <| - inferInstanceAs (IsLocalizedModule (.powers f) (toOpenₗ R R (basicOpen f))) + inferInstanceAs (IsLocalizedModule.Away f (toOpenₗ R R (basicOpen f))) end basicOpen diff --git a/Mathlib/AlgebraicTopology/DoldKan/Degeneracies.lean b/Mathlib/AlgebraicTopology/DoldKan/Degeneracies.lean index da88b2e9ec..5601ba9c94 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/Degeneracies.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/Degeneracies.lean @@ -136,7 +136,7 @@ theorem degeneracy_comp_PInfty (X : SimplicialObject C) (n : ℕ) {Δ' : Simplex fin_cases y rfl · obtain ⟨i, α, h⟩ := SimplexCategory.eq_σ_comp_of_not_injective θ hθ - rw [h, op_comp, X.map_comp, assoc, show X.map (SimplexCategory.σ i).op = X.σ i by rfl, + rw [h, op_comp, X.map_comp, assoc, ← SimplicialObject.σ_def, σ_comp_PInfty, comp_zero] section diff --git a/Mathlib/AlgebraicTopology/DoldKan/SplitSimplicialObject.lean b/Mathlib/AlgebraicTopology/DoldKan/SplitSimplicialObject.lean index df1580324d..fcc989fb6f 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/SplitSimplicialObject.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/SplitSimplicialObject.lean @@ -5,9 +5,9 @@ Authors: Joël Riou -/ module -public import Mathlib.AlgebraicTopology.SimplicialObject.Split public import Mathlib.AlgebraicTopology.DoldKan.Degeneracies -public import Mathlib.AlgebraicTopology.DoldKan.FunctorN +public import Mathlib.AlgebraicTopology.DoldKan.HomotopyEquivalence +public import Mathlib.AlgebraicTopology.SimplicialObject.Split /-! @@ -157,7 +157,9 @@ theorem ιSummand_comp_d_comp_πSummand_eq_zero (j k : ℕ) (A : IndexSet (op set_option backward.isDefEq.respectTransparency false in /-- If `s` is a splitting of a simplicial object `X` in a preadditive category, `s.nondegComplex` is a chain complex which is given in degree `n` by -the nondegenerate `n`-simplices of `X`. -/ +the nondegenerate `n`-simplices of `X`. This chain complex should be thought +as the normalized chain complex of `X` because of the isomorphism +`toKaroubiNondegComplexIsoN₁`. -/ @[simps] noncomputable def nondegComplex : ChainComplex C ℕ where X := s.N @@ -222,6 +224,77 @@ noncomputable def toKaroubiNondegComplexIsoN₁ : simp only [πSummand_comp_cofan_inj_id_comp_PInfty_eq_PInfty, Karoubi.comp_f, HomologicalComplex.comp_f, N₁_obj_p, Karoubi.id_f] +@[reassoc (attr := simp)] +lemma toKaroubiNondegComplexIsoN₁_hom_f_PInfty : + dsimp% s.toKaroubiNondegComplexIsoN₁.hom.f ≫ PInfty = + s.toKaroubiNondegComplexIsoN₁.hom.f := by + simpa using s.toKaroubiNondegComplexIsoN₁.hom.comm + +@[reassoc (attr := simp)] +lemma toKaroubiNondegComplexIsoN₁_hom_inv_id_f : + dsimp% s.toKaroubiNondegComplexIsoN₁.hom.f ≫ s.toKaroubiNondegComplexIsoN₁.inv.f = 𝟙 _ := by + rw [← dsimp% [-Karoubi.comp_f] Karoubi.comp_f s.toKaroubiNondegComplexIsoN₁.hom + s.toKaroubiNondegComplexIsoN₁.inv, Iso.hom_inv_id] + simp + +/-- Given a splitting `s` of a simplicial object `X` in a preadditive category, +this is the split epimorphism from the alternating face map complex of `X` to the chain +complex `s.nondegComplex`. -/ +@[no_expose] +noncomputable def toNondegComplex : K[X] ⟶ s.nondegComplex := + (fullyFaithfulToKaroubi _).preimage + ({ f := by exact PInfty } ≫ s.toKaroubiNondegComplexIsoN₁.inv) + +/-- Given a splitting `s` of a simplicial object `X` in a preadditive category, +this is the split monomormphism from the chain complex `s.nondegComplex` to +the alternating face map complex fo `X`. -/ +@[no_expose] +noncomputable def fromNondegComplex : s.nondegComplex ⟶ K[X] := + (fullyFaithfulToKaroubi _).preimage + (s.toKaroubiNondegComplexIsoN₁.hom ≫ { f := PInfty }) + +@[reassoc (attr := simp)] +lemma PInfty_toNondegComplex : PInfty ≫ s.toNondegComplex = s.toNondegComplex := + (toKaroubi _).map_injective (by simp [toNondegComplex]) + +@[reassoc (attr := simp)] +lemma fromNondegComplex_toNondegComplex : + s.fromNondegComplex ≫ s.toNondegComplex = 𝟙 _ := + (toKaroubi _).map_injective (by simp [toNondegComplex, fromNondegComplex]) + +@[reassoc] +lemma toNondegComplex_f (n : ℕ) : + s.toNondegComplex.f n = PInfty.f n ≫ s.toKaroubiNondegComplexIsoN₁.inv.f.f n := by + simp [toNondegComplex, fullyFaithfulToKaroubi] + +@[reassoc] +lemma fromNondegComplex_f (n : ℕ) : + s.fromNondegComplex.f n = s.ι n ≫ PInfty.f n := by + simp [fromNondegComplex, fullyFaithfulToKaroubi, + cofan, IndexSet.id, IndexSet.e] + +instance isSplitEpi_toNondegComplex : IsSplitEpi s.toNondegComplex where + exists_splitEpi := ⟨⟨s.fromNondegComplex, by simp⟩⟩ + +instance isSplitMono_fromNondegComplex : IsSplitMono s.fromNondegComplex where + exists_splitMono := ⟨⟨s.toNondegComplex, by simp⟩⟩ + +@[reassoc (attr := simp)] +lemma toNondegComplex_fromNondegComplex : + s.toNondegComplex ≫ s.fromNondegComplex = PInfty := + (toKaroubi _).map_injective (by simp [toNondegComplex, fromNondegComplex]) + +/-- Given a splitting `s` of a simplicial object `X` in a preadditive category, +this is the homotopy equivalence from the alternating face map complex of `X` +to the chain complex `s.nondegComplex`. -/ +@[simps hom inv] +noncomputable def homotopyEquivNondegComplex : + HomotopyEquiv K[X] s.nondegComplex where + hom := s.toNondegComplex + inv := s.fromNondegComplex + homotopyHomInvId := .trans (.ofEq (by simp)) (homotopyPInftyToId X) + homotopyInvHomId := .ofEq (by simp) + end Splitting namespace Split diff --git a/Mathlib/AlgebraicTopology/ModelCategory/Cylinder.lean b/Mathlib/AlgebraicTopology/ModelCategory/Cylinder.lean index ca2f02a37d..9f681a5f76 100644 --- a/Mathlib/AlgebraicTopology/ModelCategory/Cylinder.lean +++ b/Mathlib/AlgebraicTopology/ModelCategory/Cylinder.lean @@ -106,6 +106,28 @@ end @[simp, reassoc] lemma symm_i [HasBinaryCoproducts C] : P.symm.i = (coprod.braiding A A).hom ≫ P.i := by cat_disch +/-- The precylinder in a full subcategory of `C` induced by a precylinder +in the category `C`. -/ +@[simps] +def toFullSubcategory {P : ObjectProperty C} {X : P.FullSubcategory} (Q : Precylinder X.obj) + (hQ : P Q.I) : + Precylinder X where + I := ⟨Q.I, hQ⟩ + i₀ := P.homMk Q.i₀ + i₁ := P.homMk Q.i₁ + π := P.homMk Q.π + +/-- The image of a precylinder by a functor. -/ +@[simps] +def map {X : C} (P : Precylinder X) {D : Type*} [Category* D] (F : C ⥤ D) : + Precylinder (F.obj X) where + I := F.obj P.I + i₀ := F.map P.i₀ + i₁ := F.map P.i₁ + π := F.map P.π + i₀_π := by simp [← F.map_comp] + i₁_π := by simp [← F.map_comp] + end Precylinder /-- In a category with weak equivalences, a cylinder is the diff --git a/Mathlib/AlgebraicTopology/ModelCategory/LeftHomotopy.lean b/Mathlib/AlgebraicTopology/ModelCategory/LeftHomotopy.lean index 99cebcb639..896925077c 100644 --- a/Mathlib/AlgebraicTopology/ModelCategory/LeftHomotopy.lean +++ b/Mathlib/AlgebraicTopology/ModelCategory/LeftHomotopy.lean @@ -82,6 +82,24 @@ def postcomp {f g : X ⟶ Y} (h : P.LeftHomotopy f g) {Z : C} (p : Y ⟶ Z) : P.LeftHomotopy (f ≫ p) (g ≫ p) where h := h.h ≫ p +/-- Left homotopies in a full subcategory identify to left homotopies in the +ambient category. -/ +noncomputable def fullSubcategoryEquiv {P : ObjectProperty C} {X Y : P.FullSubcategory} + {Q : Precylinder X} {f g : X ⟶ Y} : + Q.LeftHomotopy f g ≃ (Q.map P.ι).LeftHomotopy f.hom g.hom where + toFun h := + { h := h.h.hom + h₀ := by + dsimp + simp only [← h.h₀, ObjectProperty.FullSubcategory.comp_hom] + h₁ := by + dsimp + simp only [← h.h₁, ObjectProperty.FullSubcategory.comp_hom] } + invFun h := + { h := P.homMk h.h + h₀ := by ext; exact h.h₀ + h₁ := by ext; exact h.h₁ } + end LeftHomotopy end Precylinder diff --git a/Mathlib/AlgebraicTopology/ModelCategory/PathObject.lean b/Mathlib/AlgebraicTopology/ModelCategory/PathObject.lean index cfc9aa99a5..74e775549e 100644 --- a/Mathlib/AlgebraicTopology/ModelCategory/PathObject.lean +++ b/Mathlib/AlgebraicTopology/ModelCategory/PathObject.lean @@ -111,6 +111,28 @@ end lemma symm_p [HasBinaryProducts C] : P.symm.p = P.p ≫ (prod.braiding A A).hom := by aesop_cat +/-- The pre-path object in a full subcategory of `C` induced by a pre-path object +in the category `C`. -/ +@[simps] +def toFullSubcategory {P : ObjectProperty C} {X : P.FullSubcategory} (Q : PrepathObject X.obj) + (hQ : P Q.P) : + PrepathObject X where + P := ⟨Q.P, hQ⟩ + p₀ := P.homMk Q.p₀ + p₁ := P.homMk Q.p₁ + ι := P.homMk Q.ι + +/-- The image of a pre-path object by a functor. -/ +@[simps] +def map {X : C} (P : PrepathObject X) {D : Type*} [Category* D] (F : C ⥤ D) : + PrepathObject (F.obj X) where + P := F.obj P.P + p₀ := F.map P.p₀ + p₁ := F.map P.p₁ + ι := F.map P.ι + ι_p₀ := by simp [← F.map_comp] + ι_p₁ := by simp [← F.map_comp] + end PrepathObject /-- In a category with weak equivalences, a path object is the diff --git a/Mathlib/AlgebraicTopology/ModelCategory/RightHomotopy.lean b/Mathlib/AlgebraicTopology/ModelCategory/RightHomotopy.lean index 4850c25c86..51b005600e 100644 --- a/Mathlib/AlgebraicTopology/ModelCategory/RightHomotopy.lean +++ b/Mathlib/AlgebraicTopology/ModelCategory/RightHomotopy.lean @@ -85,6 +85,24 @@ def precomp {f g : X ⟶ Y} (h : P.RightHomotopy f g) {Z : C} (i : Z ⟶ X) : P.RightHomotopy (i ≫ f) (i ≫ g) where h := i ≫ h.h +/-- Right homotopies in a full subcategory identify to right homotopies in the +ambient category. -/ +noncomputable def fullSubcategoryEquiv {P : ObjectProperty C} {X Y : P.FullSubcategory} + {Q : PrepathObject Y} {f g : X ⟶ Y} : + Q.RightHomotopy f g ≃ (Q.map P.ι).RightHomotopy f.hom g.hom where + toFun h := + { h := h.h.hom + h₀ := by + dsimp + simp only [← h.h₀, ObjectProperty.FullSubcategory.comp_hom] + h₁ := by + dsimp + simp only [← h.h₁, ObjectProperty.FullSubcategory.comp_hom] } + invFun h := + { h := P.homMk h.h + h₀ := by ext; exact h.h₀ + h₁ := by ext; exact h.h₁ } + end RightHomotopy end PrepathObject diff --git a/Mathlib/AlgebraicTopology/Quasicategory/Basic.lean b/Mathlib/AlgebraicTopology/Quasicategory/Basic.lean index ae3fd9152a..3b21f50c23 100644 --- a/Mathlib/AlgebraicTopology/Quasicategory/Basic.lean +++ b/Mathlib/AlgebraicTopology/Quasicategory/Basic.lean @@ -71,4 +71,23 @@ lemma quasicategory_of_filler (S : SSet) rw [← h j hj, NatTrans.comp_app] rfl +lemma quasicategory_of_hasLiftingProperty (S : SSet) {X : SSet} (t : Limits.IsTerminal X) + (h : ∀ {n : ℕ} {i : Fin (n + 1)} (_ : 0 < i) (_ : i < Fin.last n), + HasLiftingProperty Λ[n, i].ι (t.from S)) : + Quasicategory S where + hornFilling' n i σ₀ h0 hn := + let := h h0 hn + ⟨(CommSq.mk (t.hom_ext (σ₀ ≫ t.from S) (Λ[n + 2, i].ι ≫ t.from Δ[n + 2]))).lift, by simp⟩ + +lemma Quasicategory.hasLiftingProperty (S : SSet) [Quasicategory S] {X : SSet} + (t : Limits.IsTerminal X) {n : ℕ} {i : Fin (n + 1)} (h0 : 0 < i) (hn : i < Fin.last n) : + HasLiftingProperty Λ[n, i].ι (t.from S) where + sq_hasLift _ := + ⟨(hornFilling h0 hn _).choose, (hornFilling h0 hn _).choose_spec.symm, t.hom_ext _ _⟩ + +lemma quasicategory_iff_hasLiftingProperty (S : SSet) {X : SSet} (t : Limits.IsTerminal X) : + Quasicategory S ↔ ∀ {n : ℕ} {i : Fin (n + 1)} (_ : 0 < i) (_ : i < Fin.last n), + HasLiftingProperty Λ[n, i].ι (t.from S) := + ⟨fun _ ↦ Quasicategory.hasLiftingProperty S t, quasicategory_of_hasLiftingProperty S t⟩ + end SSet diff --git a/Mathlib/AlgebraicTopology/Quasicategory/InnerFibration.lean b/Mathlib/AlgebraicTopology/Quasicategory/InnerFibration.lean new file mode 100644 index 0000000000..bea12c034d --- /dev/null +++ b/Mathlib/AlgebraicTopology/Quasicategory/InnerFibration.lean @@ -0,0 +1,99 @@ +/- +Copyright (c) 2026 Jack McKoen. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jack McKoen +-/ +module + +public import Mathlib.AlgebraicTopology.Quasicategory.Basic + +/-! +# Inner fibrations + +Inner fibrations of simplicial sets are the morphisms in `SSet` which have the right lifting +property with respect to all inner horn inclusions. + +Basic consequences of inner fibrations with respect to the definition of quasi-categories are +formalized. + +-/ + +public section + +open CategoryTheory MorphismProperty Simplicial + +universe u + +namespace SSet + +/-- The family of morphisms in `SSet` which consists of inner horn inclusions +`Λ[n, i].ι : Λ[n, i] ⟶ Δ[n]` (for `0 < i < n`). -/ +inductive innerHornInclusions : MorphismProperty SSet.{u} where + | intro {n : ℕ} (i : Fin (n + 3)) (h0 : 0 < i) (hn : i < Fin.last (n + 2)) : + innerHornInclusions Λ[n + 2, i].ι + +lemma horn_ι_mem_innerHornInclusions {n : ℕ} {i : Fin (n + 1)} + (h0 : 0 < i) (hn : i < Fin.last n) : innerHornInclusions (horn.{u} n i).ι := by + obtain _ | _ | k := n + · grind + · grind + · exact ⟨i, h0, hn⟩ + +lemma innerHornInclusions_eq_iSup : + innerHornInclusions.{u} = + ⨆ n, .ofHoms (fun p : {p : Fin (n + 3) // 0 < p ∧ p < Fin.last (n + 2)} ↦ Λ[n + 2, p].ι) := by + ext + refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ + · obtain @⟨n, i, h0, hn⟩ := h + simp only [iSup_iff, ofHoms_iff, Subtype.exists, exists_prop] + use n, i + · simp only [iSup_iff, ofHoms_iff] at h + obtain ⟨n, ⟨i, h0, hn⟩, _, _⟩ := h + exact horn_ι_mem_innerHornInclusions h0 hn + +lemma innerHornInclusions_le_J : innerHornInclusions.{u} ≤ modelCategoryQuillen.J := + fun _ _ _ ⟨_, _, _⟩ ↦ modelCategoryQuillen.horn_ι_mem_J .. + +lemma innerHornInclusions_le_monomorphisms : + innerHornInclusions.{u} ≤ monomorphisms SSet := + innerHornInclusions_le_J.trans modelCategoryQuillen.J_le_monomorphisms + +/-- The inner fibrations are the morphisms which have the right lifting property +with respect to inner horn inclusions. -/ +@[expose, kerodon 01BA] +def innerFibrations : MorphismProperty SSet.{u} := innerHornInclusions.rlp +deriving IsMultiplicative, RespectsIso, IsStableUnderBaseChange, + IsStableUnderRetracts + +/-- A morphism `q` satisfies `[InnerFibration q]` if it belongs to `innerFibrations`. -/ +@[mk_iff] +class InnerFibration {X Y : SSet} (q : X ⟶ Y) : Prop where + mem : innerFibrations q + +lemma mem_innerFibrations {X Y : SSet} (q : X ⟶ Y) [InnerFibration q] : innerFibrations q := + InnerFibration.mem + +lemma quasicategory_of_from_innerFibrations (S : SSet) {X : SSet} (t : Limits.IsTerminal X) + (h : innerFibrations (t.from S)) : Quasicategory S := + quasicategory_of_hasLiftingProperty S t (fun h0 hn ↦ h _ (horn_ι_mem_innerHornInclusions h0 hn)) + +lemma Quasicategory.from_innerFibrations (S : SSet) [Quasicategory S] + {X : SSet} (t : Limits.IsTerminal X) : innerFibrations (t.from S) := + fun _ _ _ ⟨_, h0, hn⟩ ↦ hasLiftingProperty S t h0 hn + +@[kerodon 01BB] +lemma quasicategory_iff_from_innerFibration (S : SSet) {X : SSet} (t : Limits.IsTerminal X) : + Quasicategory S ↔ InnerFibration (t.from S) := + ⟨fun _ ↦ ⟨Quasicategory.from_innerFibrations S t⟩, + fun ⟨h⟩ ↦ quasicategory_of_from_innerFibrations S t h⟩ + +@[kerodon 01BJ] +lemma quasicategory_of_innerFibration_quasicategory {X Y : SSet} {q : X ⟶ Y} [Quasicategory Y] + [InnerFibration q] : Quasicategory X := by + rw [quasicategory_iff_from_innerFibration] + constructor + rw [Limits.terminalIsTerminal.hom_ext (Limits.terminalIsTerminal.from X) + (q ≫ Limits.terminalIsTerminal.from Y)] + exact comp_mem _ _ _ (mem_innerFibrations q) (Quasicategory.from_innerFibrations Y _) + +end SSet diff --git a/Mathlib/AlgebraicTopology/SimplicialObject/DeltaZeroIter.lean b/Mathlib/AlgebraicTopology/SimplicialObject/DeltaZeroIter.lean new file mode 100644 index 0000000000..e4c73113ad --- /dev/null +++ b/Mathlib/AlgebraicTopology/SimplicialObject/DeltaZeroIter.lean @@ -0,0 +1,148 @@ +/- +Copyright (c) 2026 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ +module + +public import Mathlib.AlgebraicTopology.SimplexCategory.DeltaZeroIter +public import Mathlib.AlgebraicTopology.SimplicialObject.Basic + +/-! +# Iterations of `δ 0` and `σ 0` + +This file introduces morphisms `δ₀Iter i` and `σ₀Iter i` for simplicial objects: +they are obtained as the `i`th iteration of `δ 0` or `σ 0`. + +-/ + +@[expose] public section + +open Simplicial + +namespace CategoryTheory.SimplicialObject + +variable {C : Type*} [Category* C] (X : SimplicialObject C) + +/-- If `X` is a simplicial object and `n + i = m`, this is the morphism +`X _⦋m⦌ ⟶ X _⦋n⦌` obtained by iterating `i` times the face map `X.δ 0`. -/ +def δ₀Iter {n m : ℕ} (i : ℕ) (hi : n + i = m := by lia) : + X _⦋m⦌ ⟶ X _⦋n⦌ := + X.map (SimplexCategory.δ₀Iter i hi).op + +@[simp] +lemma δ₀Iter_zero (n : ℕ) : X.δ₀Iter 0 (add_zero n) = 𝟙 _ := by + simp [δ₀Iter] + +@[simp] +lemma δ₀Iter_one (n : ℕ) : X.δ₀Iter 1 (n := n) rfl = X.δ 0 := rfl + +@[reassoc] +lemma δ₀Iter_succ (i : ℕ) {n m : ℕ} (h : n + i = m := by lia) : + X.δ₀Iter (i + 1) = X.δ 0 ≫ X.δ₀Iter i h := by + simp [δ₀Iter, SimplexCategory.δ₀Iter_succ _ h, δ_def] + +@[reassoc] +lemma δ₀Iter_succ' (i : ℕ) {n m : ℕ} (h : n + (i + 1) = m := by lia) : + X.δ₀Iter (i + 1) h = X.δ₀Iter i ≫ X.δ 0 := by + dsimp [δ, δ₀Iter] + rw [← Functor.map_comp, ← op_comp, SimplexCategory.δ₀Iter_succ' _ h] + +@[reassoc] +lemma δ_δ₀Iter (i : ℕ) {n m : ℕ} (j : Fin (m + 2)) + (hi : n + i = m := by lia) (hj : j.val ≤ i := by grind) : + X.δ j ≫ X.δ₀Iter i hi = X.δ₀Iter (i + 1) := by + dsimp [δ, δ₀Iter] + rw [← Functor.map_comp, ← op_comp, SimplexCategory.δ₀Iter_δ ..] + +@[reassoc] +lemma δ_δ₀Iter' {n : ℕ} (i : Fin (n + 2)) (j : ℕ) {m : ℕ} + (i' : Fin (m + 2)) (h : n + j = m := by lia) + (hi'' : i'.val = i.val + j := by grind) : + X.δ i' ≫ X.δ₀Iter j = X.δ₀Iter j ≫ X.δ i := by + dsimp [δ, δ₀Iter] + simp only [← Functor.map_comp, ← op_comp, SimplexCategory.δ₀Iter_δ' _ _ _ _ hi''] + +@[reassoc] +lemma σ_δ₀Iter (i : ℕ) {n m : ℕ} (j : Fin (m + 1)) + (hi : n + (i + 1) = m + 1 := by lia) + (hj : j.val ≤ i := by grind) : + X.σ j ≫ X.δ₀Iter (i + 1) hi = X.δ₀Iter i := by + dsimp [σ, δ₀Iter] + rw [← Functor.map_comp, ← op_comp, SimplexCategory.δ₀Iter_σ ..] + +@[reassoc] +lemma σ_δ₀Iter' (i : ℕ) {n m : ℕ} (j : Fin (m + 1)) (j' : Fin (n + 1)) + (hi' : n + i = m := by lia) + (hj' : j.val = j'.val + i := by grind) : + X.σ j ≫ X.δ₀Iter i = X.δ₀Iter i hi' ≫ X.σ j' := by + simp [σ, δ₀Iter, ← Functor.map_comp, ← op_comp, + SimplexCategory.δ₀Iter_σ' i j j'] + +/-- If `X` is a simplicial object and `n + i = m`, this is the morphism +`X _⦋n⦌ ⟶ X _⦋m⦌` obtained by iterating `i` times the degeneracy map `X.σ 0`. -/ +def σ₀Iter {n m : ℕ} (i : ℕ) (hi : n + i = m := by lia) : + X _⦋n⦌ ⟶ X _⦋m⦌ := + X.map (SimplexCategory.σ₀Iter i hi).op + +@[simp] +lemma σ₀Iter_zero (n : ℕ) : X.σ₀Iter 0 (add_zero n) = 𝟙 _ := by + simp [σ₀Iter] + +@[simp] +lemma σ₀Iter_one (n : ℕ) : X.σ₀Iter 1 (n := n) rfl = X.σ 0 := by + simp [σ₀Iter, σ_def] + +@[reassoc] +lemma σ₀Iter_succ (i : ℕ) {n m : ℕ} (h : n + (i + 1) = m := by lia) : + X.σ₀Iter (i + 1) h = X.σ 0 ≫ X.σ₀Iter i := by + dsimp [σ, σ₀Iter] + rw [← Functor.map_comp, ← op_comp, SimplexCategory.σ₀Iter_succ ..] + +@[reassoc] +lemma σ₀Iter_succ' (i : ℕ) {n m : ℕ} (h : n + i = m := by lia) : + X.σ₀Iter (i + 1) = X.σ₀Iter i h ≫ X.σ 0 := by + simp [σ₀Iter, SimplexCategory.σ₀Iter_succ' _ h, σ_def] + +@[reassoc] +lemma σ₀Iter_δ {n : ℕ} (i : Fin (n + 2)) (j : ℕ) {m : ℕ} (h : m + (j + 1) = n + 1 := by lia) + (hi' : i.val ≤ j + 1 := by grind) : + X.σ₀Iter (n := m) (j + 1) h ≫ X.δ i = X.σ₀Iter j := by + simp only [σ₀Iter, δ, ← Functor.map_comp, ← op_comp, SimplexCategory.δ_σ₀Iter i j h] + +@[reassoc] +lemma σ₀Iter_δ' {n : ℕ} (i : Fin (n + 2)) (j : ℕ) {m : ℕ} + (i' : Fin (m + 2)) (h : m + j = n := by lia) + (hi' : j < i.val := by grind) + (hi'' : i.val = i'.val + j := by grind) : + X.σ₀Iter (n := m + 1) j ≫ X.δ i = X.δ i' ≫ X.σ₀Iter j := by + simp only [σ₀Iter, δ, ← Functor.map_comp, ← op_comp, + SimplexCategory.δ_σ₀Iter' i j i'] + +@[reassoc] +lemma σ₀Iter_σ (i : ℕ) {n m : ℕ} (j : Fin (m + 1)) (hi : n + i = m := by lia) + (hj : j.val ≤ i := by grind) : + X.σ₀Iter i hi ≫ X.σ j = X.σ₀Iter (i + 1) := by + dsimp [σ, σ₀Iter] + rw [← Functor.map_comp, ← op_comp, SimplexCategory.σ_σ₀Iter ..] + +@[reassoc] +lemma σ₀Iter_σ' (i : ℕ) {n m : ℕ} (j : Fin (m + 1)) (j' : Fin (n + 1)) + (hi : n + i = m := by lia) + (hj : j.val = j'.val + i := by grind) : + X.σ₀Iter i hi ≫ X.σ j = X.σ j' ≫ X.σ₀Iter i := by + simp [σ, σ₀Iter, ← Functor.map_comp, ← op_comp, + SimplexCategory.σ_σ₀Iter' i j j'] + +@[reassoc (attr := simp)] +lemma σ₀Iter_δ₀Iter (i : ℕ) {n m : ℕ} (hi : n + i = m := by lia) : + X.σ₀Iter i hi ≫ X.δ₀Iter i hi = 𝟙 _ := by + simp [σ₀Iter, δ₀Iter, ← Functor.map_comp, ← op_comp] + +instance (i : ℕ) {n m : ℕ} (hi : n + i = m) : Mono (X.σ₀Iter i hi) := + mono_of_mono_fac (X.σ₀Iter_δ₀Iter i hi) + +instance (i : ℕ) {n m : ℕ} (hi : n + i = m) : Epi (X.δ₀Iter i hi) := + epi_of_epi_fac (X.σ₀Iter_δ₀Iter i hi) + +end CategoryTheory.SimplicialObject diff --git a/Mathlib/AlgebraicTopology/SimplicialSet/AnodyneExtensions/Inner/Basic.lean b/Mathlib/AlgebraicTopology/SimplicialSet/AnodyneExtensions/Inner/Basic.lean new file mode 100644 index 0000000000..3d7a60bba3 --- /dev/null +++ b/Mathlib/AlgebraicTopology/SimplicialSet/AnodyneExtensions/Inner/Basic.lean @@ -0,0 +1,100 @@ +/- +Copyright (c) 2026 Jack McKoen. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jack McKoen +-/ +module + +public import Mathlib.AlgebraicTopology.Quasicategory.InnerFibration +public import Mathlib.AlgebraicTopology.SimplicialSet.AnodyneExtensions.Basic +public import Mathlib.AlgebraicTopology.SimplicialSet.Presentable +public import Mathlib.CategoryTheory.SmallObject.Basic + +/-! +# Inner anodyne extensions + +Much of this file is mirrored from +`Mathlib.AlgebraicTopology.SimplicialSet.AnodyneExtensions.Basic`. + +*Inner* anodyne extensions form a property of morphisms in the category of simplicial +sets. It contains *inner* horn inclusions and it is closed under coproducts, pushouts, +transfinite compositions and retracts. Equivalently, using the small +object argument, inner anodyne extensions can be defined (and are defined here) +as the class of morphisms that satisfy the left lifting property with respect +to the class of inner fibrations. + +-/ + +public section + +universe u + +open CategoryTheory HomotopicalAlgebra Simplicial + +namespace SSet + +open MorphismProperty + +/-- In the category of simplicial sets, an *inner* anodyne extension is a morphism +that has the left lifting property with respect to *inner* fibrations, where +an inner fibration is a morphism that has the right lifting property with respect +to inner horn inclusions. -/ +@[expose, kerodon 01BR] +def innerAnodyneExtensions : MorphismProperty SSet.{u} := innerFibrations.llp +deriving IsMultiplicative, RespectsIso, IsStableUnderCobaseChange, + IsStableUnderRetracts, IsStableUnderTransfiniteComposition, + IsStableUnderCoproducts + +lemma innerAnodyneExtensions.of_isIso {X Y : SSet.{u}} (f : X ⟶ Y) [IsIso f] : + innerAnodyneExtensions f := + MorphismProperty.of_isIso innerAnodyneExtensions f + +lemma innerAnodyneExtensions_eq_llp_rlp : + innerAnodyneExtensions.{u} = innerHornInclusions.rlp.llp := + rfl + +lemma innerAnodyneExtensions.horn_ι {n : ℕ} {i : Fin (n + 1)} + (h0 : 0 < i) (hn : i < Fin.last n) : + innerAnodyneExtensions.{u} Λ[n, i].ι := by + rw [innerAnodyneExtensions_eq_llp_rlp] + exact le_llp_rlp _ _ (horn_ι_mem_innerHornInclusions h0 hn) + +lemma innerAnodyneExtensions_le : innerAnodyneExtensions ≤ anodyneExtensions.{u} := by + rw [anodyneExtensions_eq_llp_rlp, innerAnodyneExtensions_eq_llp_rlp, le_llp_iff_le_rlp, + rlp_llp_rlp] + exact antitone_rlp innerHornInclusions_le_J + +attribute [local instance] Cardinal.fact_isRegular_aleph0 + Cardinal.orderBotAleph0OrdToType + +instance : MorphismProperty.IsSmall.{u} innerHornInclusions.{u} := by + rw [innerHornInclusions_eq_iSup] + have (n : ℕ) : MorphismProperty.IsSmall.{u} + (MorphismProperty.ofHoms.{u} + fun p : {p : Fin (n + 3) // 0 < p ∧ p < Fin.last (n + 2)} ↦ Λ[n + 2, p].ι) := + isSmall_ofHoms .. + exact isSmall_iSup _ + +instance : IsCardinalForSmallObjectArgument innerHornInclusions.{u} Cardinal.aleph0.{u} where + preservesColimit {A B X Y} i hi f hf := by + have : IsFinitelyPresentable.{u} A := by + simp only [innerHornInclusions_eq_iSup, iSup_iff] at hi + obtain ⟨n, ⟨i⟩⟩ := hi + infer_instance + infer_instance + +instance : HasSmallObjectArgument.{u} innerHornInclusions.{u} where + exists_cardinal := ⟨.aleph0, inferInstance, inferInstance, inferInstance⟩ + +lemma innerAnodyneExtensions_eq_retracts_transfiniteCompositions : + innerAnodyneExtensions = (transfiniteCompositions.{u} + (coproducts.{u} innerHornInclusions.{u}).pushouts).retracts := by + rw [innerAnodyneExtensions_eq_llp_rlp, llp_rlp_of_hasSmallObjectArgument] + +lemma innerAnodyneExtensions_eq_retracts_transfiniteCompositionsOfShape : + innerAnodyneExtensions = (transfiniteCompositionsOfShape + (coproducts.{u} innerHornInclusions.{u}).pushouts ℕ).retracts := by + rw [innerAnodyneExtensions_eq_llp_rlp, + SmallObject.llp_rlp_of_isCardinalForSmallObjectArgument_aleph0] + +end SSet diff --git a/Mathlib/AlgebraicTopology/SimplicialSet/Boundary.lean b/Mathlib/AlgebraicTopology/SimplicialSet/Boundary.lean index 3233f05c3d..4c091d92f1 100644 --- a/Mathlib/AlgebraicTopology/SimplicialSet/Boundary.lean +++ b/Mathlib/AlgebraicTopology/SimplicialSet/Boundary.lean @@ -88,6 +88,14 @@ lemma boundary_obj_eq_univ (m n : ℕ) (h : m < n := by lia) : ← Subcomplex.ofSimplex_le_iff] apply Subcomplex.ofSimplex_map_le +@[simp] +lemma boundary_zero : boundary.{u} 0 = ⊥ := by + ext m x + simp only [boundary, Nat.reduceAdd, Set.mem_setOf_eq, Subfunctor.bot_obj, Set.bot_eq_empty, + Set.mem_empty_iff_false, iff_false, Decidable.not_not] + intro x + exact ⟨0, by subsingleton⟩ + lemma op_boundary (n : ℕ) : ∂Δ[n].op.preimage (stdSimplex.opIso.{u} ⦋n⦌).inv = ∂Δ[n] := by ext ⟨⟨d⟩⟩ j @@ -141,4 +149,63 @@ lemma eq_boundary_iff : end stdSimplex +namespace boundary + +/-- The inclusion of a face of `∂Δ[n]`. -/ +def faceι {n : ℕ} (i : Fin (n + 1)) : + (stdSimplex.face {i}ᶜ : SSet.{u}) ⟶ ∂Δ[n] := + Subcomplex.homOfLE (face_singleton_compl_le_boundary i) + +instance {n : ℕ} (i : Fin (n + 1)) : Mono (faceι.{u} i) := by + dsimp [faceι]; infer_instance + +@[reassoc (attr := simp)] +lemma faceι_ι {n : ℕ} (i : Fin (n + 2)) : + faceι i ≫ (boundary.{u} (n + 1)).ι = (stdSimplex.face {i}ᶜ).ι := by + simp [faceι] + +/-- The morphism `Δ[n] ⟶ ∂Δ[n + 1]` corresponding to face +the face `i : Fin (n + 2)`. -/ +def ι {n : ℕ} (i : Fin (n + 2)) : + Δ[n] ⟶ (∂Δ[n + 1] : SSet.{u}) := + Subcomplex.lift ((stdSimplex.{u}.map (SimplexCategory.δ i))) (by + simp only [Subcomplex.range_eq_ofSimplex] + refine le_trans ?_ (face_singleton_compl_le_boundary i) + rw [stdSimplex.face_singleton_compl, yonedaEquiv_map]) + +@[reassoc (attr := simp)] +lemma ι_ι {n : ℕ} (i : Fin (n + 2)) : + ι.{u} i ≫ ∂Δ[n + 1].ι = stdSimplex.δ i := rfl + +@[reassoc (attr := simp)] +lemma faceSingletonComplIso_inv_ι {n : ℕ} (i : Fin (n + 2)) : + (stdSimplex.faceSingletonComplIso i).inv ≫ ι i = boundary.faceι i := by + rw [← cancel_epi (stdSimplex.faceSingletonComplIso i).hom, Iso.hom_inv_id_assoc] + rfl + +instance {n : ℕ} (i : Fin (n + 2)) : Mono (ι.{u} i) := by + rw [← mono_comp_iff_of_isIso (stdSimplex.faceSingletonComplIso i).inv, + faceSingletonComplIso_inv_ι] + infer_instance + +instance {n : ℕ} (i : Fin (n + 2)) : Mono (stdSimplex.{u}.δ i) := by + rw [← ι_ι] + infer_instance + +lemma hom_ext {n : ℕ} {X : SSet.{u}} {f g : (∂Δ[n + 1] : SSet) ⟶ X} + (h : ∀ (i : Fin (n + 2)), ι i ≫ f = ι i ≫ g) : + f = g := by + ext m ⟨x, hx⟩ + simp only [boundary_eq_iSup, stdSimplex.face_singleton_compl, Subfunctor.iSup_obj, + Set.mem_iUnion, Subcomplex.mem_ofSimplex_obj_iff, op_unop] at hx + obtain ⟨i, ⟨y, rfl⟩⟩ := hx + exact ConcreteCategory.congr_hom (congr_app (h i) _) _ + +@[ext] +lemma hom_ext₀ {X : SSet.{u}} {f g : (∂Δ[0] : SSet) ⟶ X} : f = g := by + ext _ ⟨x, hx⟩ + simp at hx + +end boundary + end SSet diff --git a/Mathlib/AlgebraicTopology/SimplicialSet/CategoryWithFibrations.lean b/Mathlib/AlgebraicTopology/SimplicialSet/CategoryWithFibrations.lean index 5b55870981..f0b22c83c1 100644 --- a/Mathlib/AlgebraicTopology/SimplicialSet/CategoryWithFibrations.lean +++ b/Mathlib/AlgebraicTopology/SimplicialSet/CategoryWithFibrations.lean @@ -7,7 +7,7 @@ module public import Mathlib.AlgebraicTopology.ModelCategory.CategoryWithCofibrations public import Mathlib.AlgebraicTopology.SimplicialSet.Boundary -public import Mathlib.AlgebraicTopology.SimplicialSet.Horn +public import Mathlib.AlgebraicTopology.SimplicialSet.HornColimits public import Mathlib.CategoryTheory.MorphismProperty.LiftingProperty /-! @@ -103,4 +103,41 @@ end end modelCategoryQuillen +namespace horn.IsCompatible + +open modelCategoryQuillen + +variable {X : SSet.{u}} {n : ℕ} + {i : Fin (n + 2)} {f : ∀ (j : Fin (n + 2)) (_ : j ≠ i), Δ[n] ⟶ X} + (hf : horn.IsCompatible f) {Y : SSet.{u}} (p : X ⟶ Y) [Fibration p] + (b : Δ[n + 1] ⟶ Y) + (comm : ∀ (j : Fin (n + 2)) (hj : j ≠ i), f j hj ≫ p = stdSimplex.δ j ≫ b) + +include hf comm in +lemma exists_lift : + ∃ (φ : Δ[n + 1] ⟶ X), + (∀ (j : Fin (n + 2)) (hj : j ≠ i), stdSimplex.δ j ≫ φ = f j hj) ∧ + φ ≫ p = b := by + have sq : CommSq hf.desc Λ[n + 1, i].ι p b := + ⟨horn.hom_ext' (fun j hj ↦ by simpa using comm j hj)⟩ + exact ⟨sq.lift, fun j hj ↦ by simp [← ι_ι_assoc i j hj], by simp⟩ + +/-- If `f : ∀ (j : Fin (n + 2)) (_ : j ≠ i), Δ[n] ⟶ X` is a compatible family +of morphisms (which defines a morphism `Λ[n + 1, i] ⟶ X`), `p : X ⟶ Y` a Kan fibration +and `b : Δ[n + 1] ⟶ Y` such that for all `j ≠ i`, `f j _ ≫ p = stdSimplex.δ j ≫ b`, +then this is a lifting `Δ[n + 1] ⟶ X`. -/ +@[no_expose] +noncomputable def lift : Δ[n + 1] ⟶ X := (hf.exists_lift p b comm).choose + +@[reassoc] +lemma δ_lift (j : Fin (n + 2)) (hj : j ≠ i := by grind) : + stdSimplex.δ j ≫ hf.lift p b comm = f j hj := + ((hf.exists_lift p b comm).choose_spec).1 j hj + +@[reassoc (attr := simp)] +lemma lift_comp : hf.lift p b comm ≫ p = b := + ((hf.exists_lift p b comm).choose_spec).2 + +end horn.IsCompatible + end SSet diff --git a/Mathlib/AlgebraicTopology/SimplicialSet/KanComplex.lean b/Mathlib/AlgebraicTopology/SimplicialSet/KanComplex.lean index b17a458bee..202e392a62 100644 --- a/Mathlib/AlgebraicTopology/SimplicialSet/KanComplex.lean +++ b/Mathlib/AlgebraicTopology/SimplicialSet/KanComplex.lean @@ -31,7 +31,7 @@ universe u namespace SSet -open CategoryTheory Simplicial Limits +open CategoryTheory Simplicial Limits HomotopicalAlgebra open modelCategoryQuillen in /-- A simplicial set `S` is a Kan complex if it is fibrant, which means that @@ -47,4 +47,57 @@ lemma KanComplex.hornFilling {S : SSet.{u}} [KanComplex S] have sq' : CommSq σ₀ Λ[n + 1, i].ι (terminal.from S) (terminal.from _) := ⟨by simp⟩ exact ⟨sq'.lift, by simp⟩ +namespace horn.IsCompatible + +variable {X : SSet.{u}} {n : ℕ} + {i : Fin (n + 2)} {f : ∀ (j : Fin (n + 2)) (_ : j ≠ i), Δ[n] ⟶ X} + +lemma exists_lift_of_kanComplex [KanComplex X] + (hf : horn.IsCompatible f) : + ∃ (φ : Δ[n + 1] ⟶ X), + ∀ (j : Fin (n + 2)) (hj : j ≠ i), stdSimplex.δ j ≫ φ = f j hj := by + obtain ⟨φ, hφ, _⟩ := hf.exists_lift (terminal.from _) (terminal.from _) (by simp) + exact ⟨φ, hφ⟩ + +/-- If `X` is a Kan complex and `f : ∀ (j : Fin (n + 2)) (_ : j ≠ i), Δ[n] ⟶ X` +is a compatible family of morphisms (which defines a morphism `Λ[n + 1, i] ⟶ X`), +then this is a lifting `Δ[n + 1] ⟶ X`. -/ +@[no_expose] +noncomputable def liftOfKanComplex [KanComplex X] (hf : horn.IsCompatible f) : + Δ[n + 1] ⟶ X := + hf.exists_lift_of_kanComplex.choose + +@[reassoc] +lemma δ_liftOfKanComplex [KanComplex X] (hf : horn.IsCompatible f) + (j : Fin (n + 2)) (hj : j ≠ i := by grind) : + stdSimplex.δ j ≫ hf.liftOfKanComplex = f j hj := + hf.exists_lift_of_kanComplex.choose_spec j hj + +end horn.IsCompatible + +open modelCategoryQuillen in +/-- A simplicial set `X` is a Kan complex iff for any `n : ℕ`, `i : Fin (n + 2)`, +and any family of morphisms `Δ[n] ⟶ Z` for all `j ≠ i` that is compatible +(in the sense that it extends to a morphism `Λ[n + 1, i] ⟶ X`), there +exists a morphism `Δ[n + 1] ⟶ Z` which induces the given family of morphisms +on the faces `j ≠ i`. -/ +lemma KanComplex.iff {Z : SSet.{u}} : + KanComplex Z ↔ + ∀ ⦃n : ℕ⦄ ⦃i : Fin (n + 2)⦄ (f : ∀ (j : Fin (n + 2)) (_ : j ≠ i), Δ[n] ⟶ Z) + (_ : horn.IsCompatible f), + ∃ (φ : Δ[n + 1] ⟶ Z), + ∀ (j : Fin (n + 2)) (hj : j ≠ i), stdSimplex.δ j ≫ φ = f j hj := by + refine ⟨fun _ n i f hf ↦ hf.exists_lift_of_kanComplex, + fun h ↦ (isFibrant_iff _).2 ⟨?_⟩⟩ + rw [fibrations_eq] + intro _ _ _ hf + simp only [J, MorphismProperty.iSup_iff] at hf + obtain ⟨n, ⟨i⟩⟩ := hf + refine ⟨fun {t _} _ ↦ ?_⟩ + obtain ⟨φ, hφ⟩ := h _ (horn.IsCompatible.of_hom t) + exact ⟨⟨{ + l := φ + fac_left := horn.hom_ext' (by simpa using hφ) + fac_right := by subsingleton }⟩⟩ + end SSet diff --git a/Mathlib/Analysis/Analytic/Composition.lean b/Mathlib/Analysis/Analytic/Composition.lean index 57015f27b5..e67f66be85 100644 --- a/Mathlib/Analysis/Analytic/Composition.lean +++ b/Mathlib/Analysis/Analytic/Composition.lean @@ -115,7 +115,6 @@ theorem applyComposition_ones (p : FormalMultilinearSeries 𝕜 E F) (n : ℕ) : refine congr_arg v ?_ rw [Fin.ext_iff, Fin.val_castLE, Composition.ones_embedding, Fin.val_mk] -set_option backward.isDefEq.respectTransparency false in theorem applyComposition_single (p : FormalMultilinearSeries 𝕜 E F) {n : ℕ} (hn : 0 < n) (v : Fin n → E) : p.applyComposition (Composition.single n hn) v = fun _j => p n v := by ext j @@ -125,8 +124,8 @@ theorem applyComposition_single (p : FormalMultilinearSeries 𝕜 E F) {n : ℕ} convert Composition.single_embedding hn ⟨i, hi2⟩ using 1 obtain ⟨j_val, j_property⟩ := j have : j_val = 0 := le_bot_iff.1 (Nat.lt_succ_iff.1 j_property) - congr! - simp + rw! [this] + rfl @[simp] theorem removeZero_applyComposition (p : FormalMultilinearSeries 𝕜 E F) {n : ℕ} @@ -1253,7 +1252,6 @@ namespace FormalMultilinearSeries open Composition -set_option backward.isDefEq.respectTransparency false in theorem comp_assoc (r : FormalMultilinearSeries 𝕜 G H) (q : FormalMultilinearSeries 𝕜 F G) (p : FormalMultilinearSeries 𝕜 E F) : (r.comp q).comp p = r.comp (q.comp p) := by ext n v @@ -1292,6 +1290,7 @@ theorem comp_assoc (r : FormalMultilinearSeries 𝕜 G H) (q : FormalMultilinear -- `sizeUpTo_sizeUpTo_add`. refine congr_arg v (Fin.ext ?_) dsimp [Composition.embedding] - rw [sizeUpTo_sizeUpTo_add _ _ hi1 hj1, add_assoc] + rw [← add_assoc, ← sizeUpTo_sizeUpTo_add _ _ hi1 hj1] + rfl end FormalMultilinearSeries diff --git a/Mathlib/Analysis/InnerProductSpace/Defs.lean b/Mathlib/Analysis/InnerProductSpace/Defs.lean index 87c6f5bb54..7048d51799 100644 --- a/Mathlib/Analysis/InnerProductSpace/Defs.lean +++ b/Mathlib/Analysis/InnerProductSpace/Defs.lean @@ -600,4 +600,17 @@ def InnerProductSpace.ofCoreOfTopology [AddCommGroup F] [hF : Module 𝕜 F] [To structure HilbertSpace (𝕜 E : Type*) [RCLike 𝕜] [NormedAddCommGroup E] [InnerProductSpace 𝕜 E] [CompleteSpace E] +namespace PUnit + +instance : InnerProductSpace 𝕜 PUnit where + inner _ _ := 0 + norm_sq_eq_re_inner := by simp + conj_inner_symm := by simp + add_left := by simp + smul_left := by simp + +@[simp] lemma inner_eq_zero (x y : PUnit) : inner 𝕜 x y = 0 := rfl + +end PUnit + end diff --git a/Mathlib/Analysis/Meromorphic/IsolatedZeros.lean b/Mathlib/Analysis/Meromorphic/IsolatedZeros.lean index ba8b7c5d57..db23b63136 100644 --- a/Mathlib/Analysis/Meromorphic/IsolatedZeros.lean +++ b/Mathlib/Analysis/Meromorphic/IsolatedZeros.lean @@ -60,13 +60,9 @@ theorem eventuallyEq_zero_nhdsNE_of_eventuallyEq_zero_codiscreteWithin (hf : Mer (h₁x : x ∈ U) (h₂x : AccPt x (𝓟 U)) (h : f =ᶠ[codiscreteWithin U] 0) : f =ᶠ[𝓝[≠] x] 0 := by rw [← hf.frequently_zero_iff_eventuallyEq_zero] - apply ((accPt_iff_frequently_nhdsNE.1 h₂x).and_eventually - (mem_codiscreteWithin_iff_forall_mem_nhdsNE.1 h x h₁x)).mp - filter_upwards - intro a - simp_rw [Pi.zero_apply] - rw [(by rfl : ({x | f x = 0} ∪ Uᶜ) a ↔ a ∈ {x | f x = 0} ∪ Uᶜ)] - simp_all + apply ((accPt_iff_frequently_nhdsNE.1 h₂x).and_eventually <| eventually_mem_set.2 + (mem_codiscreteWithin_iff_forall_mem_nhdsNE.1 h x h₁x)).mono + simp +contextual /-! ## Identity Principles diff --git a/Mathlib/Analysis/Polynomial/MahlerMeasure.lean b/Mathlib/Analysis/Polynomial/MahlerMeasure.lean index 2f08b67f2d..4c67349ac2 100644 --- a/Mathlib/Analysis/Polynomial/MahlerMeasure.lean +++ b/Mathlib/Analysis/Polynomial/MahlerMeasure.lean @@ -319,7 +319,7 @@ theorem mahlerMeasure_le_sqrt_sum_sq_norm_coeff (p : Polynomial ℂ) : refine Finite.of_finite_image (f := circleMap 0 1) (p.roots.finite_toSet.subset ?_) ?_ · rintro z ⟨θ, ⟨_, heval⟩, rfl⟩ exact (mem_roots hp).mpr heval - · apply InjOn.mono fun _ h ↦ h.1 + · grw [setOf_and, inter_subset_left] exact injOn_circleMap_of_abs_sub_le one_ne_zero (by simp [abs_of_pos pi_pos]) have hlogAe : ∀ᵐ (θ : ℝ) ∂volume.restrict (uIoc 0 (2 * π)), exp (log ‖p.eval (circleMap 0 1 θ)‖) = ‖p.eval (circleMap 0 1 θ)‖ := by diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean index e50ab60658..0175e7acf4 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean @@ -49,12 +49,8 @@ theorem cpow_eq_nhds {a b : ℂ} (ha : a ≠ 0) : theorem cpow_eq_nhds' {p : ℂ × ℂ} (hp_fst : p.fst ≠ 0) : (fun x => x.1 ^ x.2) =ᶠ[𝓝 p] fun x => exp (log x.1 * x.2) := by - suffices ∀ᶠ x : ℂ × ℂ in 𝓝 p, x.1 ≠ 0 from - this.mono fun x hx ↦ by - dsimp only - rw [cpow_def_of_ne_zero hx] - refine IsOpen.eventually_mem ?_ hp_fst - change IsOpen { x : ℂ × ℂ | x.1 = 0 }ᶜ + suffices IsOpen {x : ℂ × ℂ | x.1 = 0}ᶜ from + mem_nhds_iff.mpr ⟨_, fun x hx ↦ by simp_all [cpow_def_of_ne_zero], this, hp_fst⟩ rw [isOpen_compl_iff] exact isClosed_eq continuous_fst continuous_const @@ -247,6 +243,11 @@ theorem Filter.Tendsto.rpow_const {l : Filter α} {f : α → ℝ} {x p : ℝ} ( if h0 : 0 = p then h0 ▸ by simp [tendsto_const_nhds] else hf.rpow tendsto_const_nhds (h.imp id fun h' => h'.lt_of_ne h0) +theorem Filter.Tendsto.rpow_const_nhds_zero {l : Filter α} {f : α → ℝ} {p : ℝ} + (hf : Tendsto f l (𝓝 0)) (hp : 0 < p) : + Tendsto (fun t ↦ f t ^ p) l (𝓝 0) := + Real.zero_rpow hp.ne' ▸ hf.rpow_const (.inr hp.le) + variable [TopologicalSpace α] {f g : α → ℝ} {s : Set α} {x : α} {p : ℝ} nonrec theorem ContinuousAt.rpow (hf : ContinuousAt f x) (hg : ContinuousAt g x) diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Basic.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Basic.lean index 405837e403..ad33732b70 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Basic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Basic.lean @@ -1260,4 +1260,45 @@ theorem norm_exp_mul_exp_add_exp_neg_le_of_abs_im_le {a b : ℝ} (ha : a ≤ 0) · refine Real.cos_nonneg_of_mem_Icc ⟨?_, hb⟩ exact (neg_nonpos.2 <| Real.pi_div_two_pos.le).trans ((_root_.abs_nonneg _).trans hz) +theorem sinh_antiperiodic : Function.Antiperiodic sinh (π * I) := by + simp [Complex.sinh_add, sinh_mul_I, cosh_mul_I] + +@[simp] +theorem sinh_add_pi_mul_I (z : ℂ) : sinh (z + π * I) = -sinh z := + sinh_antiperiodic z + +theorem sinh_periodic : Function.Periodic sinh (2 * π * I) := by + convert sinh_antiperiodic.periodic_two_mul using 1 + ring + +@[simp] +theorem sinh_sub_pi_mul_I (z : ℂ) : sinh (z - π * I) = -sinh z := + sinh_antiperiodic.sub_eq z + +theorem cosh_antiperiodic : Function.Antiperiodic cosh (π * I) := by + simp [Complex.cosh_add, cosh_mul_I, sinh_mul_I] + +@[simp] +theorem cosh_add_pi_mul_I (z : ℂ) : cosh (z + π * I) = -cosh z := + cosh_antiperiodic z + +theorem cosh_periodic : Function.Periodic cosh (2 * π * I) := by + convert cosh_antiperiodic.periodic_two_mul using 1 + ring + +@[simp] +theorem cosh_sub_pi_mul_I (z : ℂ) : cosh (z - π * I) = -cosh z := + cosh_antiperiodic.sub_eq z + +theorem tanh_periodic : Function.Periodic tanh (π * I) := by + simp [tanh_eq_sinh_div_cosh] + +@[simp] +theorem tanh_add_pi_mul_I (z : ℂ) : tanh (z + π * I) = tanh z := + tanh_periodic z + +@[simp] +theorem tanh_sub_pi_mul_I (z : ℂ) : tanh (z - π * I) = tanh z := + tanh_periodic.sub_eq z + end Complex diff --git a/Mathlib/CategoryTheory/Equivalence.lean b/Mathlib/CategoryTheory/Equivalence.lean index 9f222687af..3fcdd28e9a 100644 --- a/Mathlib/CategoryTheory/Equivalence.lean +++ b/Mathlib/CategoryTheory/Equivalence.lean @@ -641,7 +641,8 @@ noncomputable def inv (F : C ⥤ D) [F.IsEquivalence] : D ⥤ C where set_option backward.isDefEq.respectTransparency false in /-- Interpret a functor that is an equivalence as an equivalence. -/ -@[simps functor, stacks 02C3] +@[simps functor, simps -isSimp inverse, simps! -isSimp unitIso_hom_app unitIso_inv_app + counitIso_hom_app counitIso_inv_app, stacks 02C3] noncomputable def asEquivalence (F : C ⥤ D) [F.IsEquivalence] : C ≌ D where functor := F inverse := F.inv diff --git a/Mathlib/CategoryTheory/GuitartExact/Basic.lean b/Mathlib/CategoryTheory/GuitartExact/Basic.lean index 414b891b5a..641501555b 100644 --- a/Mathlib/CategoryTheory/GuitartExact/Basic.lean +++ b/Mathlib/CategoryTheory/GuitartExact/Basic.lean @@ -241,6 +241,14 @@ instance [hw : w.GuitartExact] {X₂ : C₂} (g : StructuredArrow (R.obj X₂) B rw [guitartExact_iff_isConnected_downwards] at hw apply hw +lemma costructuredArrowRightwards_final_iff_of_iso {X₃ X₃' : C₃} (e : X₃ ≅ X₃') : + (w.costructuredArrowRightwards X₃).Final ↔ + (w.costructuredArrowRightwards X₃').Final := by + rw [Functor.final_iff_comp_equivalence _ (CostructuredArrow.mapIso (B.mapIso e)).functor, + Functor.final_iff_equivalence_comp (CostructuredArrow.mapIso e).functor] + exact Functor.final_natIso_iff + (NatIso.ofComponents (fun _ ↦ CostructuredArrow.isoMk (Iso.refl _))) + lemma guitartExact_iff_final : w.GuitartExact ↔ ∀ (X₃ : C₃), (w.costructuredArrowRightwards X₃).Final := ⟨fun _ _ => ⟨fun _ => inferInstance⟩, fun _ => ⟨fun _ => inferInstance⟩⟩ @@ -250,6 +258,14 @@ instance [hw : w.GuitartExact] (X₃ : C₃) : rw [guitartExact_iff_final] at hw apply hw +lemma structuredArrowDownwards_initial_iff_of_iso {X₂ X₂' : C₂} (e : X₂ ≅ X₂') : + (w.structuredArrowDownwards X₂).Initial ↔ + (w.structuredArrowDownwards X₂').Initial := by + rw [Functor.initial_iff_comp_equivalence _ (StructuredArrow.mapIso (R.mapIso e)).functor, + Functor.initial_iff_equivalence_comp (StructuredArrow.mapIso e).functor] + exact Functor.initial_natIso_iff + (NatIso.ofComponents (fun _ ↦ StructuredArrow.isoMk (Iso.refl _))) + lemma guitartExact_iff_initial : w.GuitartExact ↔ ∀ (X₂ : C₂), (w.structuredArrowDownwards X₂).Initial := ⟨fun _ _ => ⟨fun _ => inferInstance⟩, by diff --git a/Mathlib/CategoryTheory/GuitartExact/HorizontalComposition.lean b/Mathlib/CategoryTheory/GuitartExact/HorizontalComposition.lean new file mode 100644 index 0000000000..7511dae8c6 --- /dev/null +++ b/Mathlib/CategoryTheory/GuitartExact/HorizontalComposition.lean @@ -0,0 +1,158 @@ +/- +Copyright (c) 2026 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ +module + +public import Mathlib.CategoryTheory.GuitartExact.Opposite + +/-! +# Horizontal composition of Guitart exact squares + +In this file, we show that the horizontal composition of Guitart exact squares +is Guitart exact. + +-/ + +@[expose] public section + +namespace CategoryTheory + +open Category + +variable {C₁ C₂ C₃ D₁ D₂ D₃ : Type*} [Category* C₁] [Category* C₂] [Category* C₃] + [Category* D₁] [Category* D₂] [Category* D₃] + +namespace TwoSquare + +section WhiskerHorizontal + +variable {T : C₁ ⥤ D₁} {L : C₁ ⥤ C₂} {R : D₁ ⥤ D₂} {B : C₂ ⥤ D₂} (w : TwoSquare T L R B) + {T' : C₁ ⥤ D₁} {B' : C₂ ⥤ D₂} + +/-- Given `w : TwoSquare T L R B`, one may obtain a 2-square `TwoSquare T' L R B'` if we +provide natural transformations `α : T ⟶ T'` and `β : B' ⟶ B`. -/ +@[simps!] +def whiskerHorizontal (α : T' ⟶ T) (β : B ⟶ B') : + TwoSquare T' L R B' := + (w.whiskerTop α).whiskerBottom β + +namespace GuitartExact + +/-- A 2-square stays Guitart exact if we replace the top and bottom functors +by isomorphic functors. See also `whiskerHorizontal_iff`. -/ +lemma whiskerHorizontal [w.GuitartExact] (α : T ≅ T') (β : B ≅ B') : + (w.whiskerHorizontal α.inv β.hom).GuitartExact := by + rw [guitartExact_iff_final] + intro X₂ + let e : costructuredArrowRightwards (w.whiskerHorizontal α.inv β.hom) X₂ ≅ + w.costructuredArrowRightwards X₂ ⋙ (CostructuredArrow.mapIso (β.app X₂)).functor := + NatIso.ofComponents (fun f ↦ CostructuredArrow.isoMk (α.symm.app f.left)) + rw [Functor.final_natIso_iff e] + infer_instance + +/-- A 2-square is Guitart exact iff it is so after replacing the top and bottom functors by +isomorphic functors. -/ +@[simp] +lemma whiskerHorizontal_iff (α : T ≅ T') (β : B ≅ B') : + (w.whiskerHorizontal α.inv β.hom).GuitartExact ↔ w.GuitartExact := by + rw [← guitartExact_op_iff, ← w.guitartExact_op_iff, + ← whiskerVertical_iff w.op (NatIso.op α.symm) (NatIso.op β.symm)] + rfl + +instance [w.GuitartExact] (α : T' ⟶ T) (β : B ⟶ B') + [IsIso α] [IsIso β] : (w.whiskerHorizontal α β).GuitartExact := + whiskerHorizontal w (asIso α).symm (asIso β) + +end GuitartExact + +end WhiskerHorizontal + +section HorizontalComposition + +variable {V₁ : C₁ ⥤ D₁} {T₁ : C₁ ⥤ C₂} {B₁ : D₁ ⥤ D₂} {V₂ : C₂ ⥤ D₂} + (w : TwoSquare T₁ V₁ V₂ B₁) + {T₂ : C₂ ⥤ C₃} {B₂ : D₂ ⥤ D₃} {V₃ : C₃ ⥤ D₃} + (w' : TwoSquare T₂ V₂ V₃ B₂) + +/-- The horizontal composition of 2-squares. (Variant where we allow the replacement of +the horizontal compositions by isomorphic functors.) -/ +@[simps!] +def hComp' {T₁₂ : C₁ ⥤ C₃} {B₁₂ : D₁ ⥤ D₃} (eT : T₁ ⋙ T₂ ≅ T₁₂) (eB : B₁ ⋙ B₂ ≅ B₁₂) : + TwoSquare T₁₂ V₁ V₃ B₁₂ := + (w ≫ₕ w').whiskerHorizontal eT.inv eB.hom + +namespace GuitartExact + +instance hComp [w.GuitartExact] [w'.GuitartExact] : + (w ≫ₕ w').GuitartExact := by + rw [← guitartExact_op_iff] + have : (w ≫ₕ w').op = w.op ≫ᵥ w'.op := by ext; simp + rw [this] + exact inferInstanceAs (w.op ≫ᵥ w'.op).GuitartExact + +instance hComp' {T₁₂ : C₁ ⥤ C₃} {B₁₂ : D₁ ⥤ D₃} (eT : T₁ ⋙ T₂ ≅ T₁₂) (eB : B₁ ⋙ B₂ ≅ B₁₂) + [w.GuitartExact] [w'.GuitartExact] : + (w.hComp' w' eT eB).GuitartExact := by + dsimp only [TwoSquare.hComp'] + infer_instance + +/-- The canonical isomorphism between +`w.costructuredArrowRightwards Y₁ ⋙ w'.costructuredArrowRightwards (B₁.obj Y₁)` and +`(w ≫ₕ w').costructuredArrowRightwards Y₁`. -/ +def costructuredArrowRightwardsComp (Y₁ : D₁) : + w.costructuredArrowRightwards Y₁ ⋙ w'.costructuredArrowRightwards (B₁.obj Y₁) ≅ + (w ≫ₕ w').costructuredArrowRightwards Y₁ := + NatIso.ofComponents (fun _ => CostructuredArrow.isoMk (Iso.refl _)) + +lemma of_hComp [B₁.EssSurj] [w.GuitartExact] [(w ≫ₕ w').GuitartExact] : + w'.GuitartExact := by + rw [guitartExact_iff_final] + intro Y₂ + rw [costructuredArrowRightwards_final_iff_of_iso _ (B₁.objObjPreimageIso Y₂).symm] + have : (w.costructuredArrowRightwards (B₁.objPreimage Y₂) ⋙ + w'.costructuredArrowRightwards (B₁.obj (B₁.objPreimage Y₂))).Final := + (Functor.final_of_natIso (costructuredArrowRightwardsComp w w' _).symm :) + exact Functor.final_of_final_comp (w.costructuredArrowRightwards (B₁.objPreimage Y₂)) _ + +lemma of_hComp' {T₁₂ : C₁ ⥤ C₃} {B₁₂ : D₁ ⥤ D₃} (eT : T₁ ⋙ T₂ ≅ T₁₂) (eB : B₁ ⋙ B₂ ≅ B₁₂) + [B₁.EssSurj] [w.GuitartExact] [h : (w.hComp' w' eT eB).GuitartExact] : + w'.GuitartExact := by + dsimp [TwoSquare.hComp'] at h + rw [whiskerHorizontal_iff] at h + exact of_hComp w w' + +lemma hComp_iff_of_essSurj [B₁.EssSurj] [w.GuitartExact] : + (w ≫ₕ w').GuitartExact ↔ w'.GuitartExact := + ⟨fun _ ↦ of_hComp w w', fun _ ↦ inferInstance⟩ + +lemma hComp'_iff_of_essSurj + {T₁₂ : C₁ ⥤ C₃} {B₁₂ : D₁ ⥤ D₃} (eT : T₁ ⋙ T₂ ≅ T₁₂) (eB : B₁ ⋙ B₂ ≅ B₁₂) + [B₁.EssSurj] [w.GuitartExact] : + (w.hComp' w' eT eB).GuitartExact ↔ w'.GuitartExact := + ⟨fun _ ↦ of_hComp' w w' eT eB, fun _ ↦ inferInstance⟩ + +lemma hComp_iff_of_equivalences (eT : C₂ ≌ C₃) (eB : D₂ ≌ D₃) + (w' : eT.functor ⋙ V₃ ≅ V₂ ⋙ eB.functor) : + (w ≫ₕ w'.hom).GuitartExact ↔ w.GuitartExact := by + let w'' : V₂.op ⋙ eB.op.functor ≅ eT.op.functor ⋙ V₃.op := NatIso.op w' + have : (w ≫ₕ w'.hom).op = (w.op ≫ᵥ w''.hom) := by ext; simp [w''] + rw [← guitartExact_op_iff, ← guitartExact_op_iff w, + ← vComp_iff_of_equivalences _ _ _ w'', this] + rfl + +lemma hComp'_iff_of_equivalences (E : C₂ ≌ C₃) (E' : D₂ ≌ D₃) + (w' : E.functor ⋙ V₃ ≅ V₂ ⋙ E'.functor) + {T₁₂ : C₁ ⥤ C₃} {B₁₂ : D₁ ⥤ D₃} (eT : T₁ ⋙ E.functor ≅ T₁₂) + (eB : B₁ ⋙ E'.functor ≅ B₁₂) : + (w.hComp' w'.hom eT eB).GuitartExact ↔ w.GuitartExact := by + rw [← hComp_iff_of_equivalences w E E' w', TwoSquare.hComp', whiskerHorizontal_iff] + +end GuitartExact + +end HorizontalComposition + +end TwoSquare + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/GuitartExact/VerticalComposition.lean b/Mathlib/CategoryTheory/GuitartExact/VerticalComposition.lean index 0bee9f0a31..ca29743e2e 100644 --- a/Mathlib/CategoryTheory/GuitartExact/VerticalComposition.lean +++ b/Mathlib/CategoryTheory/GuitartExact/VerticalComposition.lean @@ -118,6 +118,32 @@ instance vComp' [GuitartExact w] [GuitartExact w'] {L₁₂ : C₁ ⥤ C₃} dsimp only [TwoSquare.vComp'] infer_instance +set_option backward.isDefEq.respectTransparency false in +lemma of_vComp [R₁.EssSurj] [w.GuitartExact] [(w ≫ᵥ w').GuitartExact] : + w'.GuitartExact := by + rw [guitartExact_iff_initial] + intro Y₂ + rw [structuredArrowDownwards_initial_iff_of_iso _ (R₁.objObjPreimageIso Y₂).symm] + have := Functor.initial_of_natIso (structuredArrowDownwardsComp w w' (R₁.objPreimage Y₂)).symm + exact Functor.initial_of_initial_comp (w.structuredArrowDownwards (R₁.objPreimage Y₂)) _ + +lemma of_vComp' {L₁₂ : C₁ ⥤ C₃} {R₁₂ : D₁ ⥤ D₃} (eL : L₁ ⋙ L₂ ≅ L₁₂) (eR : R₁ ⋙ R₂ ≅ R₁₂) + [R₁.EssSurj] [w.GuitartExact] [h : (w.vComp' w' eL eR).GuitartExact] : + w'.GuitartExact := by + dsimp [TwoSquare.vComp'] at h + rw [whiskerVertical_iff] at h + exact of_vComp w w' + +lemma vComp_iff_of_essSurj [R₁.EssSurj] [w.GuitartExact] : + (w ≫ᵥ w').GuitartExact ↔ w'.GuitartExact := + ⟨fun _ ↦ of_vComp w w', fun _ ↦ inferInstance⟩ + +lemma vComp'_iff_of_essSurj + {L₁₂ : C₁ ⥤ C₃} {R₁₂ : D₁ ⥤ D₃} (eL : L₁ ⋙ L₂ ≅ L₁₂) (eR : R₁ ⋙ R₂ ≅ R₁₂) + [R₁.EssSurj] [w.GuitartExact] : + (w.vComp' w' eL eR).GuitartExact ↔ w'.GuitartExact := + ⟨fun _ ↦ of_vComp' w w' eL eR, fun _ ↦ inferInstance⟩ + set_option backward.isDefEq.respectTransparency false in lemma vComp_iff_of_equivalences (eL : C₂ ≌ C₃) (eR : D₂ ≌ D₃) (w' : H₂ ⋙ eR.functor ≅ eL.functor ⋙ H₃) : diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/IsPullback/Basic.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/IsPullback/Basic.lean index a464ce8856..b278fd7e86 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/IsPullback/Basic.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/IsPullback/Basic.lean @@ -385,6 +385,50 @@ lemma mk' {P X Y Z : C} {fst : P ⟶ X} {snd : P ⟶ Y} {f : X ⟶ Z} {g : Y ⟶ (h₁.trans (l s).choose_spec.1.symm) (h₂.trans (l s).choose_spec.2.symm))⟩ +/-- +The main objects in this lemma fit in the following commutative diagram: +``` +Pfg -------> X <------- Pfi + | | | + | f | + ↓ ↓ ↓ + Y --- g --> S <-- i --- Z + \ / + -- -- + \ / + -- R -- +``` +Suppose the two squares are cartesian, then `Pfg ×[Y] R` is the pullback of +`Pfi ⟶ Z` and `R ⟶ Z`. +-/ +lemma paste_twist_right {X Y Z S : C} {f : X ⟶ S} {g : Y ⟶ S} {i : Z ⟶ S} + {Pfg : C} {fstfg : Pfg ⟶ X} {sndfg : Pfg ⟶ Y} (hfg : IsPullback fstfg sndfg f g) + {Pfi : C} {fstfi : Pfi ⟶ X} {sndfi : Pfi ⟶ Z} (hfi : IsPullback fstfi sndfi f i) + {R : C} (rY : R ⟶ Y) (rZ : R ⟶ Z) (hrw : rY ≫ g = rZ ≫ i) + {Psndfgr : C} (fstsndfgr : Psndfgr ⟶ Pfg) (sndsndfgr : Psndfgr ⟶ R) + (hsndfgr : IsPullback fstsndfgr sndsndfgr sndfg rY) + {t : Psndfgr ⟶ Pfi} (ht₁ : t ≫ fstfi = fstsndfgr ≫ fstfg) (ht₂ : t ≫ sndfi = sndsndfgr ≫ rZ) : + IsPullback t sndsndfgr sndfi rZ := by + refine .of_right ?_ ht₂ hfi + rw [← hrw, ht₁] + exact .paste_horiz hsndfgr hfg + +set_option backward.isDefEq.respectTransparency false in +/-- This is a `HasPullback` variant of `CategoryTheory.IsPullback.paste_twist_right` -/ +lemma map_fst_comp_fst_snd_comp_fst {X Y Z U S : C} (f : X ⟶ S) (g : Y ⟶ S) (i : Z ⟶ S) + [HasPullback i g] (h : U ⟶ pullback i g) [HasPullback f g] [HasPullback (pullback.snd f g) + (h ≫ pullback.snd i g)] [HasPullback f i] : + IsPullback + (pullback.map (pullback.snd f g) (h ≫ pullback.snd i g) f i (pullback.fst f g) + (h ≫ pullback.fst i g) g + pullback.condition.symm (by simp [pullback.condition])) + (pullback.snd (pullback.snd f g) (h ≫ pullback.snd i g)) + (pullback.snd f i) + (h ≫ pullback.fst i g) := + paste_twist_right (.of_hasPullback f g) (.of_hasPullback f i) (h ≫ pullback.snd _ _) + (h ≫ pullback.fst _ _) (by simp [pullback.condition]) _ _ (.of_hasPullback _ _) (by simp) + (by simp) + end IsPullback namespace IsPushout diff --git a/Mathlib/CategoryTheory/Localization/LocalizerMorphism.lean b/Mathlib/CategoryTheory/Localization/LocalizerMorphism.lean index a4188466d2..56ace99ee6 100644 --- a/Mathlib/CategoryTheory/Localization/LocalizerMorphism.lean +++ b/Mathlib/CategoryTheory/Localization/LocalizerMorphism.lean @@ -355,6 +355,71 @@ def arrow : LocalizerMorphism W₁.arrow W₂.arrow where functor := Φ.functor.mapArrow map _ _ _ hf := ⟨Φ.map _ hf.1, Φ.map _ hf.2⟩ +/-- If `Φ : LocalizerMorphism W₁ W₂`, the typeclass `Φ.IsInduced` +says that `W₂.inverseImage Φ.functor = W₁`. -/ +class IsInduced (Φ : LocalizerMorphism W₁ W₂) : Prop where + inverseImage_eq (Φ) : W₂.inverseImage Φ.functor = W₁ + +export IsInduced (inverseImage_eq) + +instance [Φ.IsInduced] : Φ.op.IsInduced where + inverseImage_eq := by + simp [← Φ.inverseImage_eq] + +instance : (id W₁).IsInduced where + inverseImage_eq := rfl + +instance (Ψ : LocalizerMorphism W₂ W₃) [Φ.IsInduced] [Ψ.IsInduced] : + (Φ.comp Ψ).IsInduced where + inverseImage_eq := by + simp [← Φ.inverseImage_eq, ← Ψ.inverseImage_eq] + +section + +variable [Φ.functor.IsEquivalence] [Φ.IsInduced] [W₂.RespectsIso] + +attribute [local simp] Functor.asEquivalence_counitIso_hom_app + Functor.asEquivalence_counitIso_inv_app in +/-- The inverse of a localizer morphism `Φ : LocalizerMorphism W₁ W₂`, +when `Φ.functor` is an equivalence, `W₁` is induced by `W₂` +and `W₂` respects isomorphisms. -/ +@[simps] +noncomputable def inv : LocalizerMorphism W₂ W₁ where + functor := Φ.functor.inv + map := by + simp only [← Φ.inverseImage_eq] + intro X Y f hf + exact (W₂.arrow_mk_iso_iff + (Arrow.isoMk (Φ.functor.asEquivalence.counitIso.app _) + (Φ.functor.asEquivalence.counitIso.app _))).2 hf + +instance : Φ.inv.functor.IsEquivalence := by + dsimp + infer_instance + +attribute [local simp] Functor.asEquivalence_inverse + Functor.asEquivalence_counitIso_hom_app Functor.asEquivalence_counitIso_inv_app in +instance : Φ.inv.IsInduced where + inverseImage_eq := by + ext X Y f + simp only [← Φ.inverseImage_eq] + exact W₂.arrow_mk_iso_iff + (Arrow.isoMk (Φ.functor.asEquivalence.counitIso.app _) + (Φ.functor.asEquivalence.counitIso.app _)) + +lemma isLocalizedEquivalence_of_isInduced : + Φ.IsLocalizedEquivalence := by + refine IsLocalizedEquivalence.of_equivalence _ (fun X Y f hf ↦ ?_) + let e : + Arrow.mk (Φ.functor.map (Φ.functor.preimage + ((Φ.functor.objObjPreimageIso X).hom ≫ f ≫ (Φ.functor.objObjPreimageIso Y).inv))) ≅ + Arrow.mk f := + Arrow.isoMk (Φ.functor.objObjPreimageIso X) (Φ.functor.objObjPreimageIso Y) + simp only [← Φ.inverseImage_eq] + exact ⟨_, _, _, (W₂.arrow_mk_iso_iff e).2 hf, ⟨e⟩⟩ + +end + end LocalizerMorphism end CategoryTheory diff --git a/Mathlib/CategoryTheory/Monoidal/Braided/Basic.lean b/Mathlib/CategoryTheory/Monoidal/Braided/Basic.lean index 735c177d7f..3066c10a85 100644 --- a/Mathlib/CategoryTheory/Monoidal/Braided/Basic.lean +++ b/Mathlib/CategoryTheory/Monoidal/Braided/Basic.lean @@ -779,6 +779,14 @@ end Tensor end MonoidalCategory +@[reassoc] +theorem SymmetricCategory.tensorμ_braid_swap + {C : Type*} [Category* C] [MonoidalCategory C] [SymmetricCategory C] + (X Y : C) : + tensorμ X X Y Y ≫ (β_ (X ⊗ Y) (X ⊗ Y)).hom = + ((β_ X X).hom ⊗ₘ (β_ Y Y).hom) ≫ tensorμ X X Y Y := by + simp [tensorμ, SymmetricCategory.braiding_swap_eq_inv_braiding Y X, tensorHom_def] + instance : BraidedCategory Cᵒᵖ where braiding X Y := (β_ Y.unop X.unop).op braiding_naturality_right X {_ _} f := Quiver.Hom.unop_inj <| by simp diff --git a/Mathlib/CategoryTheory/Monoidal/Cartesian/Ring.lean b/Mathlib/CategoryTheory/Monoidal/Cartesian/Ring.lean new file mode 100644 index 0000000000..252ae59a45 --- /dev/null +++ b/Mathlib/CategoryTheory/Monoidal/Cartesian/Ring.lean @@ -0,0 +1,83 @@ +/- +Copyright (c) 2026 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ +module + +public import Mathlib.Algebra.Category.Ring.Basic +public import Mathlib.CategoryTheory.Monoidal.Ring + +/-! +# Yoneda embedding of `RingCatObj C` + +-/ + +@[expose] public section + +open CategoryTheory MonObj + +universe v u + +namespace CategoryTheory + +variable {C : Type u} [Category.{v} C] [CartesianMonoidalCategory C] [BraidedCategory C] + +open scoped CommRingObj RingObj + +/-- If `R` is a ring object, then `Hom(-, R)` is a presheaf of rings. -/ +@[simps! obj] +def yonedaRingObj (R : C) [RingObj R] : Cᵒᵖ ⥤ RingCat.{v} where + obj X := .of (X.unop ⟶ R) + map f := RingCat.ofHom + { toFun x := f.unop ≫ x + map_one' := by simp + map_zero' := by simp + map_mul' _ _ := MonObj.comp_mul _ _ _ + map_add' _ _ := AddMonObj.comp_add _ _ _ } + +@[simp] +lemma yonedaRingObj_map_apply {R : C} [RingObj R] {X Y : Cᵒᵖ} (f : X ⟶ Y) (x : X.unop ⟶ R) : + dsimp% (yonedaRingObj R).map f x = f.unop ≫ x := rfl + +set_option backward.isDefEq.respectTransparency false in +/-- The yoneda embedding of `RingObjCat C` into presheaves of rings. -/ +def yonedaRing : RingObjCat C ⥤ Cᵒᵖ ⥤ RingCat.{v} where + obj R := yonedaRingObj R.X + map f := + { app X := RingCat.ofHom + { toFun x := x ≫ f.hom + map_one' := by simp + map_zero' := by simp + map_mul' _ _ := MonObj.mul_comp _ _ _ + map_add' _ _ := AddMonObj.add_comp _ _ _ } } + +/-- If `R` is a commutative ring object, then `Hom(-, R)` is a presheaf of commutative rings. -/ +@[simps obj] +def yonedaCommRingObj (R : C) [CommRingObj R] : Cᵒᵖ ⥤ CommRingCat.{v} where + obj X := .of (X.unop ⟶ R) + map f := CommRingCat.ofHom ((yonedaRingObj R).map f).hom + +@[simp] +lemma yonedaCommRingObj_map_apply {R : C} [CommRingObj R] {X Y : Cᵒᵖ} (f : X ⟶ Y) (x : X.unop ⟶ R) : + dsimp% (yonedaCommRingObj R).map f x = f.unop ≫ x := rfl + +set_option backward.isDefEq.respectTransparency false in +/-- The yoneda embedding of `CommRingObjCat C` into presheaves of commutative rings. -/ +@[simps obj] +def yonedaCommRing : CommRingObjCat C ⥤ Cᵒᵖ ⥤ CommRingCat.{v} where + obj R := yonedaCommRingObj R.X + map f := + { app X := CommRingCat.ofHom + { toFun x := x ≫ f.hom + map_one' := by simp + map_zero' := by simp + map_mul' _ _ := MonObj.mul_comp _ _ _ + map_add' _ _ := AddMonObj.add_comp _ _ _ } } + +@[simp] +lemma yonedaCommRing_map_app_apply {R₁ R₂ : CommRingObjCat C} (f : R₁ ⟶ R₂) + {X : C} (x : X ⟶ R₁.X) : + dsimp% (yonedaCommRing.map f).app _ x = x ≫ f.hom := rfl + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Monoidal/CommComon_.lean b/Mathlib/CategoryTheory/Monoidal/CommComon_.lean index 3969d39b1d..7df8792ebb 100644 --- a/Mathlib/CategoryTheory/Monoidal/CommComon_.lean +++ b/Mathlib/CategoryTheory/Monoidal/CommComon_.lean @@ -98,4 +98,11 @@ end end CommComon +instance {C : Type*} [Category* C] [MonoidalCategory C] [SymmetricCategory C] + (A B : C) [ComonObj A] [ComonObj B] + [IsCommComonObj A] [IsCommComonObj B] : IsCommComonObj (A ⊗ B) where + comul_comm := by + rw [Comon.tensorObj_comul, Category.assoc, SymmetricCategory.tensorμ_braid_swap] + simp + end CategoryTheory diff --git a/Mathlib/CategoryTheory/ObjectProperty/Ind.lean b/Mathlib/CategoryTheory/ObjectProperty/Ind.lean index 15da34ca25..fe2ef48884 100644 --- a/Mathlib/CategoryTheory/ObjectProperty/Ind.lean +++ b/Mathlib/CategoryTheory/ObjectProperty/Ind.lean @@ -7,6 +7,7 @@ module public import Mathlib.CategoryTheory.Presentable.ColimitPresentation public import Mathlib.CategoryTheory.Presentable.Dense +public import Mathlib.CategoryTheory.Limits.FilteredColimitCommutesProduct /-! # Ind and pro-properties @@ -102,4 +103,58 @@ lemma ind_iff_exists (H : P ≤ isFinitelyPresentable.{w} C) (CostructuredArrow.pre incl (isFinitelyPresentable.{w} C).ι X) exact of_essentiallySmall_index ⟨_, _, hc⟩ fun Y ↦ Y.left.2 +section + +variable {D : Type*} [Category D] (P : ObjectProperty D) (F : C ⥤ D) + +lemma ind_inverseImage_le [PreservesFilteredColimitsOfSize.{w, w} F] : + ind.{w} (P.inverseImage F) ≤ (ind.{w} P).inverseImage F := by + intro X ⟨J, _, _, pres, h⟩ + simp only [prop_inverseImage_iff] + use J, inferInstance, inferInstance, pres.map F, h + +lemma ind_inverseImage_eq_of_isEquivalence [P.IsClosedUnderIsomorphisms] [F.IsEquivalence] : + ind.{w} (P.inverseImage F) = (ind.{w} P).inverseImage F := by + refine le_antisymm (ind_inverseImage_le _ _) fun X ⟨J, _, _, pres, h⟩ ↦ ?_ + refine ⟨J, ‹_›, ‹_›, .ofIso (pres.map F.asEquivalence.inverse) ?_, fun j ↦ ?_⟩ + · exact (F.asEquivalence.unitIso.app X).symm + · exact P.prop_of_iso ((F.asEquivalence.counitIso.app _).symm) (h j) + +lemma ind_iff_of_equivalence (e : C ≌ D) [P.IsClosedUnderIsomorphisms] (X : D) : + ind.{w} (P.inverseImage e.functor) (e.inverse.obj X) ↔ ind.{w} P X := by + dsimp only [ObjectProperty.ind] + congr! + refine ⟨fun ⟨pres, h⟩ ↦ ?_, fun ⟨pres, h⟩ ↦ ?_⟩ + · exact ⟨.ofIso (pres.map e.functor) (e.counitIso.app X), fun i ↦ h i⟩ + · exact ⟨pres.map e.inverse, fun i ↦ P.prop_of_iso ((e.counitIso.app _).symm) (h i)⟩ + +end + +section Products + +private lemma ind_pi_of_ind {ι : Type w} [P.IsClosedUnderLimitsOfShape (Discrete ι)] + [HasProductsOfShape ι C] [IsIPCOfShape.{w} ι C] {X : ι → C} (hc : ∀ i, ind.{w} P (X i)) : + ind.{w} P (∏ᶜ X) := by + choose J _ _ pres hpres using hc + obtain ⟨hc⟩ := IsIPCOfShape.nonempty_isColimit fun i ↦ (pres i).isColimit + exact ⟨∀ j, J j, inferInstance, inferInstance, + { diag := _, ι := _, isColimit := hc }, fun i ↦ P.prop_limit _ fun a ↦ hpres a.1 _⟩ + +instance isClosedUnderLimitsOfShape_ind_discrete {ι : Type*} [Small.{w} ι] + [P.IsClosedUnderLimitsOfShape (Discrete ι)] [HasProductsOfShape ι C] [IsIPCOfShape.{w} ι C] : + (ind.{w} P).IsClosedUnderLimitsOfShape (Discrete ι) := by + refine .mk' fun X ⟨Y, h⟩ ↦ ?_ + let e := equivShrink ι + have : HasProductsOfShape (Shrink.{w} ι) C := + hasLimitsOfShape_of_equivalence (Discrete.equivalence e) + have : IsIPCOfShape.{w} (Shrink.{w} ι) C := .of_equiv e + have : P.IsClosedUnderLimitsOfShape (Discrete (Shrink.{w} ι)) := + .of_equivalence (Discrete.equivalence e) + let iso : limit Y ≅ ∏ᶜ fun i ↦ Y.obj ⟨e.symm i⟩ := + (Pi.isoLimit _).symm ≪≫ (Pi.reindex e.symm _).symm + rw [(ind.{w} P).prop_iff_of_iso iso] + exact ind_pi_of_ind fun i ↦ h _ + +end Products + end CategoryTheory.ObjectProperty diff --git a/Mathlib/CategoryTheory/Presentable/IsCardinalFiltered.lean b/Mathlib/CategoryTheory/Presentable/IsCardinalFiltered.lean index 0f4a06aa09..1bf553db88 100644 --- a/Mathlib/CategoryTheory/Presentable/IsCardinalFiltered.lean +++ b/Mathlib/CategoryTheory/Presentable/IsCardinalFiltered.lean @@ -8,7 +8,7 @@ module public import Mathlib.CategoryTheory.Filtered.Final public import Mathlib.CategoryTheory.Limits.Shapes.WideEqualizers public import Mathlib.CategoryTheory.Comma.CardinalArrow -public import Mathlib.SetTheory.Cardinal.Cofinality +public import Mathlib.SetTheory.Cardinal.Cofinality.Ordinal public import Mathlib.SetTheory.Cardinal.HasCardinalLT public import Mathlib.SetTheory.Cardinal.Arithmetic diff --git a/Mathlib/CategoryTheory/Triangulated/LocalizingSubcategory.lean b/Mathlib/CategoryTheory/Triangulated/LocalizingSubcategory.lean index 05308db5f8..9c8d3d42ec 100644 --- a/Mathlib/CategoryTheory/Triangulated/LocalizingSubcategory.lean +++ b/Mathlib/CategoryTheory/Triangulated/LocalizingSubcategory.lean @@ -15,9 +15,9 @@ Let `C` be a pretriangulated category. If `A` and `B` are triangulated subcategories of `C`, we define predicates (typeclasses `IsVerdierRightLocalizing` and `IsVerdierLeftLocalizing`) saying that `A` is right `B`-localizing (or left `B`-localizing). -When `B` is closed under isomorphisms, we shall show that this implies that +When `B` is closed under isomorphisms, we show that this implies that the functor from the Verdier quotient `A/(A ⊓ B)` to `C/B` is fully -faithful (TODO @joelriou). +faithful. ## References * [Jean-Louis Verdier, *Des catégories dérivées des catégories abéliennes*, @@ -33,7 +33,7 @@ open Category Limits Pretriangulated Opposite namespace ObjectProperty -variable {C D D' : Type*} [Category* C] [Category* D] [Category* D'] +variable {C D D₁ D₂ : Type*} [Category* C] [Category* D] [Category* D₁] [Category* D₂] /-- If `A` and `B` are triangulated subcategories of a (pre)triangulated category `C` (with `B` closed under isomorphisms), we say that `A` is @@ -151,6 +151,197 @@ lemma IsVerdierLeftLocalizing.fac' ∃ (Z : C) (s' : Z ⟶ Y) (a : Z ⟶ X), A Z ∧ (A ⊓ B).trW s' ∧ a ≫ s = s' := (isVerdierLeftLocalizing_iff A B).1 inferInstance s hY hs +/-- If `A` is a triangulated subcategory of a pretriangulated category `C`, +and `B : ObjectProperty C`, this is the inclusion functor +`A.ι : A.FullSubcategory ⥤ C`, considered as a localizer morphism, +where `C` is equipped with the property of morphisms `B.trW` +and `A.FullSubcategory` with the property of morphisms `(B.inverseImage A.ι).trW`. -/ +@[implicit_reducible] +def triangulatedLocalizerMorphism [A.IsTriangulated] : + LocalizerMorphism (B.inverseImage A.ι).trW B.trW where + functor := A.ι + map X Y f hf := by + simp only [MorphismProperty.inverseImage_iff, trW_iff] at hf ⊢ + obtain ⟨Z, a, b, hT, hZ⟩ := hf + exact ⟨_, _, _, A.ι.map_distinguished _ hT, hZ⟩ + +instance [A.IsTriangulated] : + (triangulatedLocalizerMorphism A B).functor.CommShift ℤ := + inferInstanceAs (A.ι.CommShift ℤ) + +instance [A.IsTriangulated] : + (triangulatedLocalizerMorphism A B).functor.IsTriangulated := + inferInstanceAs A.ι.IsTriangulated + +lemma trW_inverseImage_ι_iff [A.IsTriangulated] {X Y : A.FullSubcategory} (f : X ⟶ Y) : + (B.inverseImage A.ι).trW f ↔ (A ⊓ B).trW f.hom := by + simp only [trW_iff] + constructor + · rintro ⟨Z, a, b, h, hZ⟩ + exact ⟨_, _, _, A.ι.map_distinguished _ h, Z.property, hZ⟩ + · rintro ⟨Z, a, b, h, hZ⟩ + refine ⟨⟨Z, hZ.1⟩, A.homMk a, A.homMk (b ≫ (A.ι.commShiftIso 1).inv.app _), ?_, hZ.2⟩ + rw [← A.ι.map_distinguished_iff] + refine isomorphic_distinguished _ h _ + (Triangle.isoMk _ _ (Iso.refl _) (Iso.refl _) (Iso.refl _) ?_ ?_ ?_) + · cat_disch + · cat_disch + · simp [dsimp% (A.ι.commShiftIso (1 : ℤ)).inv_hom_id_app X] + +lemma inverseImage_opEquivalence_inverse_trW_inverseImage_ι_op [A.IsTriangulated] + [B.IsTriangulated] [B.IsClosedUnderIsomorphisms] : + (B.op.inverseImage A.op.ι).trW.inverseImage A.opEquivalence.inverse = + (B.inverseImage A.ι).op.trW := by + ext ⟨X₁⟩ ⟨X₂⟩ a + simp [trW_op, trW_inverseImage_ι_iff, ← op_inf] + +variable [IsTriangulated C] [A.IsTriangulated] [B.IsTriangulated] [B.IsClosedUnderIsomorphisms] + +section + +variable [A.IsVerdierRightLocalizing B] + (L₁ : A.FullSubcategory ⥤ D₁) (L₂ : C ⥤ D₂) + [L₁.IsLocalization (B.inverseImage A.ι).trW] [L₂.IsLocalization B.trW] + +instance : ((A.triangulatedLocalizerMorphism B).localizedFunctor L₁ L₂).Full := by + let F := (A.triangulatedLocalizerMorphism B).localizedFunctor L₁ L₂ + have : L₁.EssSurj := Localization.essSurj L₁ (B.inverseImage A.ι).trW + let e : A.ι ⋙ L₂ ≅ L₁ ⋙ F := CatCommSq.iso + (A.triangulatedLocalizerMorphism B).functor L₁ L₂ F + refine F.full_of_comp_essSurj L₁ (fun X₁ X₂ φ ↦ ?_) + obtain ⟨φ', hφ'⟩ : ∃ φ', φ = e.inv.app X₁ ≫ φ' ≫ e.hom.app X₂ := + ⟨e.hom.app X₁ ≫ φ ≫ e.inv.app X₂, by + simp [dsimp% e.inv_hom_id_app_assoc, dsimp% e.inv_hom_id_app]⟩ + obtain ⟨f, hf⟩ := Localization.exists_leftFraction L₂ B.trW φ' + obtain ⟨X₃, s', a, hX₃, hs', fac⟩ := + IsVerdierRightLocalizing.fac' f.s X₂.property f.hs + let g : (B.inverseImage A.ι).trW.LeftFraction X₁ X₂ := + { Y' := ⟨X₃, hX₃⟩ + f := A.homMk (f.f ≫ a) + s := A.homMk s' + hs := by rwa [trW_inverseImage_ι_iff] } + have := Localization.inverts L₁ _ _ g.hs + refine ⟨g.map L₁ (Localization.inverts _ _), ?_⟩ + rw [← cancel_mono (F.map (L₁.map g.s)), ← Functor.map_comp, + MorphismProperty.LeftFraction.map_comp_map_s] + simp [g, ← fac, hφ', hf, ← dsimp% NatIso.naturality_1 e, + dsimp% e.hom_inv_id_app_assoc] + +instance [Preadditive D₁] [Preadditive D₂] [L₁.Additive] [L₂.Additive] : + ((A.triangulatedLocalizerMorphism B).localizedFunctor L₁ L₂).Additive := by + let F := (A.triangulatedLocalizerMorphism B).localizedFunctor L₁ L₂ + rw [Localization.functor_additive_iff L₁ (B.inverseImage A.ι).trW] + let e : A.ι ⋙ L₂ ≅ L₁ ⋙ F := CatCommSq.iso + (A.triangulatedLocalizerMorphism B).functor L₁ L₂ F + exact Functor.additive_of_iso e + +instance : ((A.triangulatedLocalizerMorphism B).localizedFunctor L₁ L₂).Faithful := by + letI := Localization.preadditive L₁ (B.inverseImage A.ι).trW + letI := Localization.preadditive L₂ B.trW + have := Localization.functor_additive L₁ (B.inverseImage A.ι).trW + have := Localization.functor_additive L₂ B.trW + let F := (A.triangulatedLocalizerMorphism B).localizedFunctor L₁ L₂ + let e : A.ι ⋙ L₂ ≅ L₁ ⋙ F := + CatCommSq.iso (A.triangulatedLocalizerMorphism B).functor L₁ L₂ F + refine Functor.faithful_of_comp_cancel_zero_of_hasLeftCalculusOfFractions L₁ + (B.inverseImage A.ι).trW F (fun X₁ X₂ f hf ↦ ?_) + replace hf : L₂.map f.hom = L₂.map 0 := by + simp [← dsimp% NatIso.naturality_2 e f, hf] + rw [MorphismProperty.map_eq_iff_postcomp L₂ B.trW] at hf + obtain ⟨X₃, s, hs, fac⟩ := hf + obtain ⟨X₄, t, a, hX₄, ht, fac'⟩ := + IsVerdierRightLocalizing.fac' s X₂.property hs + let t' : X₂ ⟶ ⟨X₄, hX₄⟩ := A.homMk t + have := Localization.inverts L₁ (B.inverseImage A.ι).trW t' + (by rwa [trW_inverseImage_ι_iff]) + rw [← cancel_mono (L₁.map t'), zero_comp, ← L₁.map_comp, ← L₁.map_zero] + congr 1 + ext + simp [t', ← fac', reassoc_of% fac] + +end + +instance [A.IsVerdierRightLocalizing B] : + (A.triangulatedLocalizerMorphism B).IsLocalizedFullyFaithful where + nonempty_fullyFaithful := ⟨.ofFullyFaithful _⟩ + +instance [A.IsVerdierLeftLocalizing B] : + (A.triangulatedLocalizerMorphism B).IsLocalizedFullyFaithful := by + let L₁ := (B.inverseImage A.ι).trW.Q + let L₂ := B.trW.Q + let F : (B.inverseImage A.ι).trW.Localization ⥤ B.trW.Localization := + (A.triangulatedLocalizerMorphism B).localizedFunctor L₁ L₂ + letI : CatCommSq (A.op.triangulatedLocalizerMorphism B.op).functor + (A.opEquivalence.functor ⋙ L₁.op) L₂.op F.op := + ⟨Functor.isoWhiskerLeft A.opEquivalence.functor + (NatIso.op (CatCommSq.iso (A.triangulatedLocalizerMorphism B).functor L₁ L₂ F).symm)⟩ + have : L₂.op.IsLocalization B.op.trW := by rw [trW_op]; infer_instance + have : (A.opEquivalence.functor ⋙ L₁.op).IsLocalization (B.op.inverseImage A.op.ι).trW := by + refine Functor.IsLocalization.of_equivalence_source L₁.op (B.inverseImage A.ι).trW.op + _ _ A.opEquivalence.symm ?_ ?_ + ((Functor.associator _ _ _).symm ≪≫ + Functor.isoWhiskerRight A.opEquivalence.counitIso _ ≪≫ Functor.leftUnitor _) + · rw [← trW_op, ← inverseImage_opEquivalence_inverse_trW_inverseImage_ι_op] + intro _ _ f hf + simp only [MorphismProperty.inverseImage_iff, Equivalence.symm_functor] at hf ⊢ + exact MorphismProperty.le_isoClosure _ _ hf + · refine fun _ _ _ hf ↦ Localization.inverts L₁.op (B.inverseImage A.ι).trW.op _ ?_ + simpa [trW_inverseImage_ι_iff, ← op_inf, trW_op] using hf + exact LocalizerMorphism.IsLocalizedFullyFaithful.mk' (A.triangulatedLocalizerMorphism B) + L₁ L₂ F (((A.op.triangulatedLocalizerMorphism B.op).fullyFaithful + (A.opEquivalence.functor ⋙ L₁.op) L₂.op F.op).unop) + +section + +variable [A.IsVerdierLeftLocalizing B] (L₁ : A.FullSubcategory ⥤ D₁) (L₂ : C ⥤ D₂) + [L₁.IsLocalization (B.inverseImage A.ι).trW] + [L₂.IsLocalization B.trW] + +example : ((A.triangulatedLocalizerMorphism B).localizedFunctor L₁ L₂).Full := by + infer_instance + +example : ((A.triangulatedLocalizerMorphism B).localizedFunctor L₁ L₂).Faithful := by + infer_instance + +instance [A.IsVerdierLeftLocalizing B] [Preadditive D₁] [Preadditive D₂] + [L₁.Additive] [L₂.Additive] : + ((A.triangulatedLocalizerMorphism B).localizedFunctor L₁ L₂).Additive := by + let F := (A.triangulatedLocalizerMorphism B).localizedFunctor L₁ L₂ + rw [Localization.functor_additive_iff L₁ (B.inverseImage A.ι).trW] + let e : A.ι ⋙ L₂ ≅ L₁ ⋙ F := CatCommSq.iso + (A.triangulatedLocalizerMorphism B).functor L₁ L₂ F + exact Functor.additive_of_iso e + +/-- If `A` is a left `B`-localizing triangulated subcategory in the sense of Verdier, +then the induced functor between the localizations with respect to `(B.inverseImage A.ι).trW` +and `B.trW` is fully faithful. -/ +@[no_expose] +noncomputable def IsVerdierLeftLocalizing.fullyFaithful [A.IsVerdierLeftLocalizing B] + {L₁ : A.FullSubcategory ⥤ D₁} {L₂ : C ⥤ D₂} {F : D₁ ⥤ D₂} + [L₁.IsLocalization (B.inverseImage A.ι).trW] [L₂.IsLocalization B.trW] + (e : L₁ ⋙ F ≅ A.ι ⋙ L₂) : + F.FullyFaithful := + Functor.FullyFaithful.ofIso (.ofFullyFaithful + ((A.triangulatedLocalizerMorphism B).localizedFunctor L₁ L₂)) + (Localization.liftNatIso L₁ (B.inverseImage A.ι).trW + ((A.triangulatedLocalizerMorphism B).functor ⋙ L₂) (L₁ ⋙ F) _ _ e.symm) + +/-- If `A` is a right `B`-localizing triangulated subcategory in the sense of Verdier, +then the induced functor between the localizations with respect to `(B.inverseImage A.ι).trW` +and `B.trW` is fully faithful. -/ +@[no_expose] +noncomputable def IsVerdierRightLocalizing.fullyFaithful [A.IsVerdierRightLocalizing B] + {L₁ : A.FullSubcategory ⥤ D₁} {L₂ : C ⥤ D₂} {F : D₁ ⥤ D₂} + [L₁.IsLocalization (B.inverseImage A.ι).trW] [L₂.IsLocalization B.trW] + (e : L₁ ⋙ F ≅ A.ι ⋙ L₂) : + F.FullyFaithful := + Functor.FullyFaithful.ofIso (.ofFullyFaithful + ((A.triangulatedLocalizerMorphism B).localizedFunctor L₁ L₂)) + (Localization.liftNatIso L₁ (B.inverseImage A.ι).trW + ((A.triangulatedLocalizerMorphism B).functor ⋙ L₂) (L₁ ⋙ F) _ _ e.symm) + +end + end ObjectProperty end CategoryTheory diff --git a/Mathlib/Combinatorics/Nullstellensatz.lean b/Mathlib/Combinatorics/Nullstellensatz.lean index 59fee42216..12ebec3ddb 100644 --- a/Mathlib/Combinatorics/Nullstellensatz.lean +++ b/Mathlib/Combinatorics/Nullstellensatz.lean @@ -174,7 +174,7 @@ private lemma Alon.of_mem_P_support {ι : Type*} (i : ι) (S : Finset R) (m : ι (hm : m ∈ (Alon.P S i).support) : ∃ e ≤ S.card, m = single i e := by classical - have hP : Alon.P S i = .rename (fun _ ↦ i) (Alon.P S ()) := by simp [Alon.P, map_prod] + have hP : Alon.P S i = .rename (fun _ ↦ i) (Alon.P S ()) := by simp [Alon.P] rw [hP, support_rename_of_injective (Function.injective_of_subsingleton _)] at hm simp only [Finset.mem_image, mem_support_iff, ne_eq] at hm obtain ⟨e, he, hm⟩ := hm @@ -228,7 +228,7 @@ theorem combinatorial_nullstellensatz_exists_linearCombination intro i _ rw [smul_eq_mul, map_mul] convert mul_zero _ - rw [Alon.P, map_prod] + rw [Alon.P, _root_.map_prod] apply Finset.prod_eq_zero (hx i) simp diff --git a/Mathlib/Data/Finset/BooleanAlgebra.lean b/Mathlib/Data/Finset/BooleanAlgebra.lean index 5719a71861..19e63b5c40 100644 --- a/Mathlib/Data/Finset/BooleanAlgebra.lean +++ b/Mathlib/Data/Finset/BooleanAlgebra.lean @@ -273,8 +273,7 @@ section DecEq variable [Fintype α] [DecidableEq α] -@[simp] -lemma filter_univ_mem (s : Finset α) : univ.filter (· ∈ s) = s := by simp [filter_mem_eq_inter] +lemma filter_univ_mem (s : Finset α) : univ.filter (· ∈ s) = s := by simp instance decidableCodisjoint : Decidable (Codisjoint s t) := decidable_of_iff _ codisjoint_left.symm diff --git a/Mathlib/Data/Finset/Filter.lean b/Mathlib/Data/Finset/Filter.lean index 205857319a..2efe5f0ac3 100644 --- a/Mathlib/Data/Finset/Filter.lean +++ b/Mathlib/Data/Finset/Filter.lean @@ -226,6 +226,11 @@ lemma filter_inj : s.filter p = t.filter p ↔ ∀ ⦃a⦄, p a → (a ∈ s ↔ lemma filter_inj' : s.filter p = s.filter q ↔ ∀ ⦃a⦄, a ∈ s → (p a ↔ q a) := by simp [Finset.ext_iff] +@[simp] +lemma filter_mem_eq_of_subset [DecidablePred (· ∈ s)] (hst : s ⊆ t) : + t.filter (· ∈ s) = s := by + grind + end Filter end Finset diff --git a/Mathlib/Data/Finset/Powerset.lean b/Mathlib/Data/Finset/Powerset.lean index d37121600e..2a9df10393 100644 --- a/Mathlib/Data/Finset/Powerset.lean +++ b/Mathlib/Data/Finset/Powerset.lean @@ -201,6 +201,36 @@ theorem card_powersetCard (n : ℕ) (s : Finset α) : card (powersetCard n s) = Nat.choose (card s) n := (card_pmap _ _ _).trans (Multiset.card_powersetCard n s.1) +/-- The `n`-element subsets of `t` containing `s` are exactly the `(n - s.card)`-element +subsets of `t \ s`, unioned with `s`. -/ +theorem filter_powersetCard_subset [DecidableEq α] (s t : Finset α) (n : ℕ) + (hst : s ⊆ t) (hsn : #s ≤ n) : + (t.powersetCard n).filter (s ⊆ ·) = ((t \ s).powersetCard (n - #s)).image (· ∪ s) := by + ext x + simp only [mem_filter, mem_powersetCard, mem_image] + constructor + · intro ⟨⟨hxt, hxn⟩, hsx⟩ + exact ⟨x \ s, ⟨fun y hy => mem_sdiff.mpr ⟨hxt (mem_sdiff.mp hy).1, (mem_sdiff.mp hy).2⟩, + by rw [card_sdiff_of_subset hsx, hxn]⟩, sdiff_union_of_subset hsx⟩ + · rintro ⟨y, ⟨hyt, hyn⟩, rfl⟩ + refine ⟨⟨union_subset (hyt.trans sdiff_subset) hst, ?_⟩, subset_union_right⟩ + rw [card_union_of_disjoint (disjoint_of_subset_left hyt disjoint_sdiff_self_left), hyn] + omega + +/-- The number of `n`-element subsets of `t` containing `s` equals +`Nat.choose (#t - #s) (n - #s)`. -/ +lemma card_filter_powersetCard_subset [DecidableEq α] (s t : Finset α) (n : ℕ) + (hst : s ⊆ t) (hsn : #s ≤ n) : + #((t.powersetCard n).filter (s ⊆ ·)) = Nat.choose (#t - #s) (n - #s) := by + have hinj : Set.InjOn (· ∪ s) ↑((t \ s).powersetCard (n - #s)) := fun a ha b hb hab => + (union_sdiff_cancel_right + (disjoint_of_subset_left (mem_powersetCard.mp ha).1 disjoint_sdiff_self_left)).symm.trans + ((congrArg (· \ s) hab).trans + (union_sdiff_cancel_right + (disjoint_of_subset_left (mem_powersetCard.mp hb).1 disjoint_sdiff_self_left))) + simp only [filter_powersetCard_subset s t n hst hsn, card_image_of_injOn hinj, + card_powersetCard, card_sdiff_of_subset hst] + @[simp] theorem powersetCard_zero (s : Finset α) : s.powersetCard 0 = {∅} := by grind diff --git a/Mathlib/Data/Finset/Preimage.lean b/Mathlib/Data/Finset/Preimage.lean index ff7918d1c9..d1a8a1b76b 100644 --- a/Mathlib/Data/Finset/Preimage.lean +++ b/Mathlib/Data/Finset/Preimage.lean @@ -191,6 +191,14 @@ def restrictPreimageFinset (e : α ≃ β) (s : Finset β) : (s.preimage e e.inj left_inv _ := by simp right_inv _ := by simp +lemma image_symm_eq_preimage_of_finset [DecidableEq α] (e : α ≃ β) (s : Finset β) : + s.image e.symm = s.preimage e e.injective.injOn := by + grind [Finset.mem_preimage] + +lemma image_eq_preimage_symm_of_finset [DecidableEq β] (e : α ≃ β) (s : Finset α) : + s.image e = s.preimage e.symm e.symm.injective.injOn := + e.symm.image_symm_eq_preimage_of_finset s + end Equiv set_option backward.isDefEq.respectTransparency false in diff --git a/Mathlib/Data/Finsupp/Weight.lean b/Mathlib/Data/Finsupp/Weight.lean index cf9b669dd6..d6cc5fd6d7 100644 --- a/Mathlib/Data/Finsupp/Weight.lean +++ b/Mathlib/Data/Finsupp/Weight.lean @@ -265,13 +265,14 @@ lemma range_single_one : obtain ⟨a, rfl⟩ := (Finsupp.sum_eq_one_iff _).mp hp use a -theorem degree_mapDomain_eq_of_subsingletonAddUnits {τ : Type*} (f : σ → τ) [AddCommMonoid M] - [Subsingleton (AddUnits M)] (x : σ →₀ M) : degree (x.mapDomain f) = degree x := by - classical - trans (x.mapDomain f).sum (fun _ ↦ id) - · simp [degree, sum] - · simpa [sum, mapDomain_support_of_subsingletonAddUnits, degree] using Finset.sum_image' _ - (fun _ _ ↦ mapDomain_apply_eq_sum ..) +@[simp] +theorem degree_mapDomain {τ : Type*} (f : σ → τ) [AddCommMonoid M] (x : σ →₀ M) : + degree (x.mapDomain f) = degree x := by + simp [mapDomain, sum] + dsimp [degree_apply] + +@[deprecated (since := "2026-04-27")] +alias degree_mapDomain_eq_of_subsingletonAddUnits := degree_mapDomain theorem degree_comapDomain_le_of_canonicallyOrderedAdd {τ : Type*} {f : σ → τ} [AddCommMonoid M] [PartialOrder M] [CanonicallyOrderedAdd M] {x : τ →₀ M} (hf : Set.InjOn f (f ⁻¹' x.support)) : diff --git a/Mathlib/Data/Int/Basic.lean b/Mathlib/Data/Int/Basic.lean index 0e3d1925f9..fe3824cdc1 100644 --- a/Mathlib/Data/Int/Basic.lean +++ b/Mathlib/Data/Int/Basic.lean @@ -33,25 +33,6 @@ instance instNontrivial : Nontrivial ℤ := ⟨⟨0, 1, Int.zero_ne_one⟩⟩ @[simp] lemma ofNat_injective : Function.Injective ofNat := @Int.ofNat.inj -section inductionOn' - -variable {C : ℤ → Sort*} (z b : ℤ) - (H0 : C b) (Hs : ∀ k, b ≤ k → C k → C (k + 1)) (Hp : ∀ k ≤ b, C k → C (k - 1)) - -variable {z b H0 Hs Hp} - -lemma inductionOn'_add_one (hz : b ≤ z) : - (z + 1).inductionOn' b H0 Hs Hp = Hs z hz (z.inductionOn' b H0 Hs Hp) := by - apply cast_eq_iff_heq.mpr - lift z - b to ℕ using Int.sub_nonneg.mpr hz with zb hzb - rw [show z + 1 - b = zb + 1 by lia] - have : b + zb = z := by lia - subst this - convert cast_heq _ _ - rw [Int.inductionOn', cast_eq_iff_heq, ← hzb] - -end inductionOn' - section strongRec variable {P : ℤ → Sort*} {lt : ∀ n < m, P n} {ge : ∀ n ≥ m, (∀ k < n, P k) → P n} diff --git a/Mathlib/Data/Int/Init.lean b/Mathlib/Data/Int/Init.lean index 9ad427ad2b..d06ffbf364 100644 --- a/Mathlib/Data/Int/Init.lean +++ b/Mathlib/Data/Int/Init.lean @@ -8,6 +8,7 @@ module public import Batteries.Logic public import Mathlib.Data.Int.Notation public import Mathlib.Data.Nat.Notation +public import Mathlib.Tactic.DepRewrite /-! # Basic operations on the integers @@ -92,7 +93,7 @@ variable {motive : ℤ → Sort*} (z b : ℤ) (zero : motive b) /-- Inductively define a function on `ℤ` by defining it at `b`, for the `succ` of a number greater than `b`, and the `pred` of a number less than `b`. -/ @[elab_as_elim] protected def inductionOn' : motive z := - cast (congrArg motive <| show b + (z - b) = z by rw [Int.add_comm, z.sub_add_cancel b]) <| + cast (congrArg motive <| show b + (z - b) = z by lia) <| match z - b with | .ofNat n => pos n | .negSucc n => neg n @@ -100,35 +101,32 @@ where /-- The positive case of `Int.inductionOn'`. -/ pos : ∀ n : ℕ, motive (b + n) | 0 => cast (by simp) zero - | n + 1 => cast (by rw [Int.add_assoc]; rfl) <| - succ _ (Int.le_add_of_nonneg_right (natCast_nonneg _)) (pos n) + | n + 1 => cast (by lia) <| succ _ (Int.le_add_of_nonneg_right (natCast_nonneg _)) (pos n) /-- The negative case of `Int.inductionOn'`. -/ neg : ∀ n : ℕ, motive (b + -[n+1]) | 0 => pred _ Int.le_rfl zero - | n + 1 => by - refine cast (by lia) (pred _ (Int.le_of_lt ?_) (neg n)) - lia + | n + 1 => cast (by lia) <| pred _ (by lia) (neg n) variable {z b zero succ pred} lemma inductionOn'_self : b.inductionOn' b zero succ pred = zero := cast_eq_iff_heq.mpr <| .symm <| by rw [b.sub_self, ← cast_eq_iff_heq]; rfl -lemma inductionOn'_sub_one (hz : z ≤ b) : +theorem inductionOn'_add_one (hz : b ≤ z) : + (z + 1).inductionOn' b zero succ pred = succ z hz (z.inductionOn' b zero succ pred) := by + unfold Int.inductionOn' + rw! [show z - b = (z - b).toNat by lia, show z + 1 - b = ((z - b).toNat + 1 : ℕ) by lia] + grind [inductionOn'.pos, show b + (z - b).toNat = z by lia] + +theorem inductionOn'_sub_one (hz : z ≤ b) : (z - 1).inductionOn' b zero succ pred = pred z hz (z.inductionOn' b zero succ pred) := by - apply cast_eq_iff_heq.mpr - obtain ⟨n, hn⟩ := Int.eq_negSucc_of_lt_zero (show z - 1 - b < 0 by lia) - rw [hn] - obtain _ | n := n - · change _ = -1 at hn - have : z = b := by lia - subst this; rw [inductionOn'_self]; exact heq_of_eq rfl - · have : z = b + -[n+1] := by rw [Int.negSucc_eq] at hn ⊢; lia - subst this - refine (cast_heq _ _).trans ?_ - congr - symm - rw [Int.inductionOn', cast_eq_iff_heq, show b + -[n+1] - b = -[n+1] by lia] + unfold Int.inductionOn' + conv => lhs; unfold inductionOn'.neg + by_cases z = b + · rw! [show z - 1 - b = -[(b - z).toNat+1] by lia, show z - b = 0 by lia] + grind [inductionOn'.pos] + rw! [show z - 1 - b = -[(b - z).toNat+1] by lia, show z - b = -[(b - z - 1).toNat+1] by lia] + grind end inductionOn' @@ -140,16 +138,45 @@ end inductionOn' /-- See `Int.inductionOn'` for an induction in both directions. -/ @[elab_as_elim] -protected lemma le_induction {m : ℤ} {motive : ∀ n, m ≤ n → Prop} (base : motive m m.le_refl) - (succ : ∀ n hmn, motive n hmn → motive (n + 1) (le_add_one hmn)) : ∀ n hmn, motive n hmn := by - refine fun n ↦ Int.inductionOn' n m ?_ ?_ ?_ <;> grind +protected def leInduction {m : ℤ} {motive : ∀ n, m ≤ n → Sort*} (base : motive m m.le_refl) + (succ : ∀ n hmn, motive n hmn → motive (n + 1) (le_add_one hmn)) : ∀ n hmn, motive n hmn := + fun n ↦ n.inductionOn' m + (fun _ ↦ base) (fun k hle ih _ ↦ succ k hle <| ih hle) (fun _ _ _ _ ↦ False.elim <| by lia) + +@[deprecated (since := "2026-03-25")] protected alias le_induction := Int.leInduction + +theorem leInduction_base {m : ℤ} {motive : ∀ n, m ≤ n → Sort*} (base : motive m m.le_refl) + (succ : ∀ n hmn, motive n hmn → motive (n + 1) (le_add_one hmn)) : + Int.leInduction (motive := motive) base succ m m.le_refl = base := by + rw [Int.leInduction, inductionOn'_self] + +theorem leInduction_add_one {m : ℤ} {motive : ∀ n, m ≤ n → Sort*} (base : motive m m.le_refl) + (succ : ∀ n hmn, motive n hmn → motive (n + 1) (le_add_one hmn)) (n : ℤ) (hmn : m ≤ n) : + Int.leInduction (motive := motive) base succ (n + 1) (by lia) = + succ n hmn (Int.leInduction (motive := motive) base succ n hmn) := by + rw [Int.leInduction, inductionOn'_add_one hmn] + rfl /-- See `Int.inductionOn'` for an induction in both directions. -/ @[elab_as_elim] -protected lemma le_induction_down {m : ℤ} {motive : ∀ n, n ≤ m → Prop} (base : motive m m.le_refl) - (pred : ∀ n hmn, motive n hmn → motive (n - 1) (by lia)) : ∀ n hmn, motive n hmn := fun n ↦ - Int.inductionOn' n m (fun _ ↦ base) (fun k hle _ hle' ↦ by lia) - fun k hle hi _ ↦ pred k hle (hi hle) +protected def leInductionDown {m : ℤ} {motive : ∀ n, n ≤ m → Sort*} (base : motive m m.le_refl) + (pred : ∀ n hnm, motive n hnm → motive (n - 1) (by lia)) : ∀ n hnm, motive n hnm := + fun n ↦ n.inductionOn' m + (fun _ ↦ base) (fun _ _ _ _ ↦ False.elim <| by lia) (fun k hle ih _ ↦ pred k hle <| ih hle) + +theorem leInductionDown_base {m : ℤ} {motive : ∀ n, n ≤ m → Sort*} (base : motive m m.le_refl) + (pred : ∀ n hnm, motive n hnm → motive (n - 1) (by lia)) : + Int.leInductionDown (motive := motive) base pred m m.le_refl = base := by + rw [Int.leInductionDown, inductionOn'_self] + +theorem leInductionDown_sub_one {m : ℤ} {motive : ∀ n, n ≤ m → Sort*} (base : motive m m.le_refl) + (pred : ∀ n hnm, motive n hnm → motive (n - 1) (by lia)) (n : ℤ) (hnm : n ≤ m) : + Int.leInductionDown (motive := motive) base pred (n - 1) (by lia) = + pred n hnm (Int.leInductionDown (motive := motive) base pred n hnm) := by + rw [Int.leInductionDown, inductionOn'_sub_one hnm] + rfl + +@[deprecated (since := "2026-03-25")] protected alias le_induction_down := Int.leInductionDown section strongRec diff --git a/Mathlib/Data/List/Basic.lean b/Mathlib/Data/List/Basic.lean index 576b199501..433d9cb936 100644 --- a/Mathlib/Data/List/Basic.lean +++ b/Mathlib/Data/List/Basic.lean @@ -186,6 +186,8 @@ theorem map_subset_iff {l₁ l₂ : List α} (f : α → β) (h : Injective f) : rcases mem_map.1 (h2 (mem_map_of_mem hx)) with ⟨x', hx', hxx'⟩ cases h hxx'; exact hx' +lemma notMem_of_subset (h : l ⊆ l₁) {a : α} (ha : a ∉ l₁) : a ∉ l := (ha <| h ·) + /-! ### append -/ theorem append_eq_has_append {L₁ L₂ : List α} : List.append L₁ L₂ = L₁ ++ L₂ := diff --git a/Mathlib/Data/List/TakeDrop.lean b/Mathlib/Data/List/TakeDrop.lean index a297cc1411..897b733c06 100644 --- a/Mathlib/Data/List/TakeDrop.lean +++ b/Mathlib/Data/List/TakeDrop.lean @@ -88,6 +88,28 @@ theorem tail_iterate (l : List α) (n : ℕ) : (List.tail^[n]) l = l.drop n := b | zero => rfl | succ n ih => cases l <;> simp [*] +section TailDropLast + +variable (l : List α) (n : ℕ) + +theorem tail_take_eq_take_tail : (l.take n).tail = l.tail.take (n - 1) := by + ext + grind + +theorem dropLast_take_eq_take_dropLast : (l.take n).dropLast = l.dropLast.take (n - 1) := by + ext + grind + +theorem tail_drop_eq_drop_tail : (l.drop n).tail = l.tail.drop n := by + ext + grind + +theorem dropLast_drop_eq_drop_dropLast : (l.drop n).dropLast = l.dropLast.drop n := by + ext + grind + +end TailDropLast + section TakeI variable [Inhabited α] diff --git a/Mathlib/Data/Nat/Count.lean b/Mathlib/Data/Nat/Count.lean index 929beea262..3e7c42de14 100644 --- a/Mathlib/Data/Nat/Count.lean +++ b/Mathlib/Data/Nat/Count.lean @@ -71,10 +71,7 @@ theorem count_monotone : Monotone (count p) := monotone_nat_of_le_succ (by grind) theorem count_add (a b : ℕ) : count p (a + b) = count p a + count (fun k ↦ p (a + k)) b := by - have : Disjoint {x ∈ range a | p x} {x ∈ (range b).map <| addLeftEmbedding a | p x} := by - grind [Finset.disjoint_left] - simp_rw [count_eq_card_filter_range, range_add, filter_union, card_union_of_disjoint this, - filter_map, addLeftEmbedding, card_map, Function.Embedding.coeFn_mk, Function.comp_def] + simp [count, List.range_add, Function.comp_def] theorem count_add' (a b : ℕ) : count p (a + b) = count (fun k ↦ p (k + b)) a + count p b := by rw [add_comm, count_add, add_comm] diff --git a/Mathlib/Data/Nat/Init.lean b/Mathlib/Data/Nat/Init.lean index 5cd32bff81..83c1987137 100644 --- a/Mathlib/Data/Nat/Init.lean +++ b/Mathlib/Data/Nat/Init.lean @@ -271,12 +271,25 @@ lemma le_induction {m : ℕ} {P : ∀ n, m ≤ n → Prop} (base : P m m.le_refl @Nat.leRec (motive := P) _ base succ /-- Induction principle deriving the next case from the two previous ones. -/ -def twoStepInduction {P : ℕ → Sort*} (zero : P 0) (one : P 1) - (more : ∀ n, P n → P (n + 1) → P (n + 2)) : ∀ a, P a +@[elab_as_elim] +def twoStepInduction {motive : ℕ → Sort*} (zero : motive 0) (one : motive 1) + (more : ∀ n, motive n → motive (n + 1) → motive (n + 2)) : ∀ a, motive a | 0 => zero | 1 => one | _ + 2 => more _ (twoStepInduction zero one more _) (twoStepInduction zero one more _) +/-- Induction principle deriving the next case from the `k` previous ones. Use as +``` +induction n using stepInduction 3 with +| base n hn => ... +| step n ih => ... +``` -/ +@[elab_as_elim] +def stepInduction {motive : ℕ → Sort*} (k : ℕ) (base : ∀ i < k, motive i) + (step : ∀ n, (∀ i < k, motive (n + i)) → motive (n + k)) (a : ℕ) : motive a := + if h : a < k then base _ h else + (show a - k + k = a by lia) ▸ step (a - k) fun _ _ ↦ stepInduction k base step _ + @[elab_as_elim] protected theorem strong_induction_on {p : ℕ → Prop} (n : ℕ) (h : ∀ n, (∀ m < n, p m) → p n) : p n := diff --git a/Mathlib/Data/Set/Function.lean b/Mathlib/Data/Set/Function.lean index 89c6138a67..bbc6970df9 100644 --- a/Mathlib/Data/Set/Function.lean +++ b/Mathlib/Data/Set/Function.lean @@ -167,6 +167,7 @@ lemma mapsTo_of_subsingleton' [Subsingleton β] (f : α → β) (h : s.Nonempty lemma mapsTo_of_subsingleton [Subsingleton α] (f : α → α) (s : Set α) : MapsTo f s s := mapsTo_of_subsingleton' _ id +@[gcongr] theorem MapsTo.mono (hf : MapsTo f s₁ t₁) (hs : s₂ ⊆ s₁) (ht : t₁ ⊆ t₂) : MapsTo f s₂ t₂ := fun _ hx => ht (hf <| hs hx) @@ -270,6 +271,7 @@ theorem InjOn.congr (h₁ : InjOn f₁ s) (h : EqOn f₁ f₂ s) : InjOn f₂ s theorem EqOn.injOn_iff (H : EqOn f₁ f₂ s) : InjOn f₁ s ↔ InjOn f₂ s := ⟨fun h => h.congr H, fun h => h.congr H.symm⟩ +@[gcongr] theorem InjOn.mono (h : s₁ ⊆ s₂) (ht : InjOn f s₂) : InjOn f s₁ := fun _ hx _ hy H => ht (h hx) (h hy) H @@ -485,6 +487,7 @@ theorem SurjOn.congr (h : SurjOn f₁ s t) (H : EqOn f₁ f₂ s) : SurjOn f₂ theorem EqOn.surjOn_iff (h : EqOn f₁ f₂ s) : SurjOn f₁ s t ↔ SurjOn f₂ s t := ⟨fun H => H.congr h, fun H => H.congr h.symm⟩ +@[gcongr] theorem SurjOn.mono (hs : s₁ ⊆ s₂) (ht : t₁ ⊆ t₂) (hf : SurjOn f s₁ t₂) : SurjOn f s₂ t₁ := Subset.trans ht <| Subset.trans hf <| image_mono hs diff --git a/Mathlib/FieldTheory/Galois/IsGaloisGroup.lean b/Mathlib/FieldTheory/Galois/IsGaloisGroup.lean index f86dbc4416..f75a19b0b7 100644 --- a/Mathlib/FieldTheory/Galois/IsGaloisGroup.lean +++ b/Mathlib/FieldTheory/Galois/IsGaloisGroup.lean @@ -65,6 +65,21 @@ theorem IsGaloisGroup.of_mulEquiv [hG : IsGaloisGroup G A B] {H : Type*} [Group have he' : ∀ (g : G) (x : B), e.symm g • x = g • x := fun g x ↦ by simp [← he] hG.isInvariant.isInvariant b (fun g ↦ by simpa [he'] using h (e.symm g))⟩ +variable {G A B} in +theorem IsGaloisGroup.iff_of_mulEquiv {H : Type*} [Group H] [MulSemiringAction H B] + (e : H ≃* G) (he : ∀ h (x : B), e h • x = h • x) : + IsGaloisGroup H A B ↔ IsGaloisGroup G A B := by + refine ⟨fun h ↦ h.of_mulEquiv e.symm fun g x ↦ ?_, fun h ↦ h.of_mulEquiv e he⟩ + rw [← he, e.apply_symm_apply] + +variable {G A B} in +@[simp] +theorem IsGaloisGroup.top_iff : IsGaloisGroup (⊤ : Subgroup G) A B ↔ IsGaloisGroup G A B := + iff_of_mulEquiv Subgroup.topEquiv fun _ _ ↦ rfl + +instance [IsGaloisGroup G A B] : IsGaloisGroup (⊤ : Subgroup G) A B := + IsGaloisGroup.top_iff.mpr ‹_› + attribute [instance low] IsGaloisGroup.commutes IsGaloisGroup.isInvariant variable [FaithfulSMul A B] [hA : IsGaloisGroup G A B] diff --git a/Mathlib/GroupTheory/Congruence/Defs.lean b/Mathlib/GroupTheory/Congruence/Defs.lean index 831df828db..bccc972653 100644 --- a/Mathlib/GroupTheory/Congruence/Defs.lean +++ b/Mathlib/GroupTheory/Congruence/Defs.lean @@ -98,7 +98,7 @@ inductive ConGen.Rel [Mul M] (r : M → M → Prop) : M → M → Prop /-- The inductively defined smallest multiplicative congruence relation containing a given binary relation. -/ -@[to_additive addConGen /-- The inductively defined smallest additive congruence relation containing +@[to_additive /-- The inductively defined smallest additive congruence relation containing a given binary relation. -/] def conGen [Mul M] (r : M → M → Prop) : Con M := ⟨⟨ConGen.Rel r, ⟨ConGen.Rel.refl, ConGen.Rel.symm, ConGen.Rel.trans⟩⟩, ConGen.Rel.mul⟩ @@ -394,7 +394,7 @@ theorem inf_iff_and {c d : Con M} {x y} : (c ⊓ d) x y ↔ c x y ∧ d x y := /-- The inductively defined smallest congruence relation containing a binary relation `r` equals the infimum of the set of congruence relations containing `r`. -/ -@[to_additive addConGen_eq /-- The inductively defined smallest additive congruence relation +@[to_additive /-- The inductively defined smallest additive congruence relation containing a binary relation `r` equals the infimum of the set of additive congruence relations containing `r`. -/] theorem conGen_eq (r : M → M → Prop) : conGen r = sInf { s : Con M | ∀ x y, r x y → s x y } := @@ -411,14 +411,14 @@ theorem conGen_eq (r : M → M → Prop) : conGen r = sInf { s : Con M | ∀ x y /-- The smallest congruence relation containing a binary relation `r` is contained in any congruence relation containing `r`. -/ -@[to_additive addConGen_le /-- The smallest additive congruence relation containing a binary +@[to_additive /-- The smallest additive congruence relation containing a binary relation `r` is contained in any additive congruence relation containing `r`. -/] theorem conGen_le {r : M → M → Prop} {c : Con M} (h : ∀ x y, r x y → c x y) : conGen r ≤ c := by rw [conGen_eq]; exact sInf_le h /-- Given binary relations `r, s` with `r` contained in `s`, the smallest congruence relation containing `s` contains the smallest congruence relation containing `r`. -/ -@[to_additive addConGen_mono /-- Given binary relations `r, s` with `r` contained in `s`, the +@[to_additive /-- Given binary relations `r, s` with `r` contained in `s`, the smallest additive congruence relation containing `s` contains the smallest additive congruence relation containing `r`. -/] theorem conGen_mono {r s : M → M → Prop} (h : ∀ x y, r x y → s x y) : conGen r ≤ conGen s := @@ -432,13 +432,13 @@ theorem conGen_of_con (c : Con M) : conGen c = c := /-- The map sending a binary relation to the smallest congruence relation in which it is contained is idempotent. -/ -@[to_additive addConGen_idem /-- The map sending a binary relation to the smallest additive +@[to_additive /-- The map sending a binary relation to the smallest additive congruence relation in which it is contained is idempotent. -/] theorem conGen_idem (r : M → M → Prop) : conGen (conGen r) = conGen r := by simp /-- The supremum of congruence relations `c, d` equals the smallest congruence relation containing the binary relation '`x` is related to `y` by `c` or `d`'. -/ -@[to_additive sup_eq_addConGen /-- The supremum of additive congruence relations `c, d` equals the +@[to_additive /-- The supremum of additive congruence relations `c, d` equals the smallest additive congruence relation containing the binary relation '`x` is related to `y` by `c` or `d`'. -/] theorem sup_eq_conGen (c d : Con M) : c ⊔ d = conGen fun x y => c x y ∨ d x y := by @@ -454,7 +454,7 @@ theorem sup_def {c d : Con M} : c ⊔ d = conGen (⇑c ⊔ ⇑d) := by rw [sup_e /-- The supremum of a set of congruence relations `S` equals the smallest congruence relation containing the binary relation 'there exists `c ∈ S` such that `x` is related to `y` by `c`'. -/ -@[to_additive sSup_eq_addConGen /-- The supremum of a set of additive congruence relations `S` +@[to_additive /-- The supremum of a set of additive congruence relations `S` equals the smallest additive congruence relation containing the binary relation 'there exists `c ∈ S` such that `x` is related to `y` by `c`'. -/] theorem sSup_eq_conGen (S : Set (Con M)) : diff --git a/Mathlib/GroupTheory/CoprodI.lean b/Mathlib/GroupTheory/CoprodI.lean index 13b16cd3e4..fb66081c6a 100644 --- a/Mathlib/GroupTheory/CoprodI.lean +++ b/Mathlib/GroupTheory/CoprodI.lean @@ -1017,7 +1017,7 @@ theorem _root_.FreeGroup.injective_lift_of_ping_pong : Function.Injective (FreeG smul_set_mono ((hXYdisj j i).union_left <| hYdisj hij.symm).subset_compl_right _ ⊆ X i := by clear hnne0 hlt - induction n, h1n using Int.le_induction with + induction n, h1n using Int.leInduction with | base => rw [zpow_one]; exact hX i | succ n _hle hi => calc @@ -1035,7 +1035,7 @@ theorem _root_.FreeGroup.injective_lift_of_ping_pong : Function.Injective (FreeG smul_set_mono ((hXdisj hij.symm).union_left (hXYdisj i j).symm).subset_compl_right _ ⊆ Y i := by clear hnne0 hgt - induction n, h1n using Int.le_induction_down with + induction n, h1n using Int.leInductionDown with | base => rw [zpow_neg, zpow_one]; exact hY i | pred n hle hi => calc diff --git a/Mathlib/GroupTheory/Perm/Cycle/Type.lean b/Mathlib/GroupTheory/Perm/Cycle/Type.lean index aeed8b9e53..353e548c29 100644 --- a/Mathlib/GroupTheory/Perm/Cycle/Type.lean +++ b/Mathlib/GroupTheory/Perm/Cycle/Type.lean @@ -627,6 +627,10 @@ variable [DecidableEq α] {σ : Perm α} theorem cycleType (h : IsThreeCycle σ) : σ.cycleType = {3} := h +theorem ne_one (h : IsThreeCycle σ) : σ ≠ 1 := by + rintro rfl + simpa using h.cycleType + theorem card_support (h : IsThreeCycle σ) : #σ.support = 3 := by rw [← sum_cycleType, h.cycleType, Multiset.sum_singleton] diff --git a/Mathlib/GroupTheory/SpecificGroups/Alternating.lean b/Mathlib/GroupTheory/SpecificGroups/Alternating.lean index d062750359..c0119c006c 100644 --- a/Mathlib/GroupTheory/SpecificGroups/Alternating.lean +++ b/Mathlib/GroupTheory/SpecificGroups/Alternating.lean @@ -273,19 +273,6 @@ theorem _root_.alternatingGroup.closure_cycleType_eq_two_two_eq_top (h5 : 5 ≤ have := closure_cycleType_eq_two_two_eq_alternatingGroup h5 aesop -/-- A key lemma to prove $A_5$ is simple. Shows that any normal subgroup of an alternating group on - at least 5 elements is the entire alternating group if it contains a 3-cycle. -/ -theorem IsThreeCycle.alternating_normalClosure (h5 : 5 ≤ Nat.card α) {f : Perm α} - (hf : IsThreeCycle f) : - normalClosure ({⟨f, hf.mem_alternatingGroup⟩} : Set (alternatingGroup α)) = ⊤ := by - rw [eq_top_iff, ← map_subtype_le_map_subtype, ← MonoidHom.range_eq_map, range_subtype, - normalClosure, MonoidHom.map_closure] - refine (le_of_eq closure_three_cycles_eq_alternating.symm).trans (closure_mono fun g h ↦ ?_) - obtain ⟨c, rfl⟩ := isConj_iff.mp (isConj_iff_cycleType_eq.mpr (hf.trans h.symm)) - refine ⟨⟨c * f * c⁻¹, h.mem_alternatingGroup⟩, ?_, rfl⟩ - rw [Group.mem_conjugatesOfSet_iff] - exact ⟨⟨f, hf.mem_alternatingGroup⟩, Set.mem_singleton _, isThreeCycle_isConj h5 hf h⟩ - /-- Part of proving $A_5$ is simple. Shows that the square of any element of $A_5$ with a 3-cycle in its cycle decomposition is a 3-cycle, so the normal closure of the original element must be $A_5$. -/ @@ -330,52 +317,12 @@ theorem nontrivial_of_three_le_card (h3 : 3 ≤ Nat.card α) : Nontrivial (alter instance {n : ℕ} : Nontrivial (alternatingGroup (Fin (n + 3))) := nontrivial_of_three_le_card (by simp) -/-- The normal closure of the 5-cycle `finRotate 5` within $A_5$ is the whole group. This will be - used to show that the normal closure of any 5-cycle within $A_5$ is the whole group. -/ -theorem normalClosure_finRotate_five : normalClosure ({⟨finRotate 5, - finRotate_bit1_mem_alternatingGroup (n := 2)⟩} : Set (alternatingGroup (Fin 5))) = ⊤ := - eq_top_iff.2 - (by - have h3 : - IsThreeCycle (Fin.cycleRange 2 * finRotate 5 * (Fin.cycleRange 2)⁻¹ * (finRotate 5)⁻¹) := - card_support_eq_three_iff.1 (by decide) - rw [← h3.alternating_normalClosure (by rw [Nat.card_fin])] - refine normalClosure_le_normal ?_ - rw [Set.singleton_subset_iff, SetLike.mem_coe] - have h : - (⟨finRotate 5, finRotate_bit1_mem_alternatingGroup (n := 2)⟩ : alternatingGroup (Fin 5)) ∈ - normalClosure _ := - SetLike.mem_coe.1 (subset_normalClosure (Set.mem_singleton _)) - -- Porting note: added `:` to help the elaborator (otherwise we get a timeout) - exact (mul_mem (Subgroup.normalClosure_normal.conj_mem _ h - ⟨Fin.cycleRange 2, Fin.isThreeCycle_cycleRange_two.mem_alternatingGroup⟩) (inv_mem h) :)) - -/-- The normal closure of $(04)(13)$ within $A_5$ is the whole group. This will be -used to show that the normal closure of any permutation of cycle type $(2,2)$ is the whole group. --/ -theorem normalClosure_swap_mul_swap_five : - normalClosure - ({⟨swap 0 4 * swap 1 3, mem_alternatingGroup.2 (by decide)⟩} : - Set (alternatingGroup (Fin 5))) = - ⊤ := by - let g1 := (⟨swap 0 2 * swap 0 1, mem_alternatingGroup.2 (by decide)⟩ : alternatingGroup (Fin 5)) - let g2 := (⟨swap 0 4 * swap 1 3, mem_alternatingGroup.2 (by decide)⟩ : alternatingGroup (Fin 5)) - have h5 : g1 * g2 * g1⁻¹ * g2⁻¹ = - ⟨finRotate 5, finRotate_bit1_mem_alternatingGroup (n := 2)⟩ := by - rw [Subtype.ext_iff] - simp only [Subgroup.coe_mul, Subgroup.coe_inv] - decide - rw [eq_top_iff, ← normalClosure_finRotate_five] - refine normalClosure_le_normal ?_ - rw [Set.singleton_subset_iff, SetLike.mem_coe, ← h5] - have h : g2 ∈ normalClosure {g2} := - SetLike.mem_coe.1 (subset_normalClosure (Set.mem_singleton _)) - exact mul_mem (Subgroup.normalClosure_normal.conj_mem _ h g1) (inv_mem h) - set_option linter.flexible false in -- TODO: fix non-terminal simp /-- Shows that any non-identity element of $A_5$ whose cycle decomposition consists only of swaps is conjugate to $(04)(13)$. This is used to show that the normal closure of such a permutation in $A_5$ is $A_5$. -/ +@[deprecated "This was an auxilliary lemma for the proof of simplicity of A_5 which has now been +superceded by `alternatingGroup.isSimpleGroup`." (since := "2026-04-28")] theorem isConj_swap_mul_swap_of_cycleType_two {g : Perm (Fin 5)} (ha : g ∈ alternatingGroup (Fin 5)) (h1 : g ≠ 1) (h2 : ∀ n, n ∈ cycleType (g : Perm (Fin 5)) → n = 2) : IsConj (swap 0 4 * swap 1 3) g := by @@ -401,56 +348,6 @@ theorem isConj_swap_mul_swap_of_cycleType_two {g : Perm (Fin 5)} (ha : g ∈ alt decide · contradiction -/-- Shows that $A_5$ is simple by taking an arbitrary non-identity element and showing by casework - on its cycle type that its normal closure is all of $A_5$. -/ -instance isSimpleGroup_five : IsSimpleGroup (alternatingGroup (Fin 5)) := - ⟨fun H => by - intro Hn - refine or_not.imp id fun Hb => ?_ - rw [eq_bot_iff_forall] at Hb - push Not at Hb - obtain ⟨⟨g, gA⟩, gH, g1⟩ : ∃ x : ↥(alternatingGroup (Fin 5)), x ∈ H ∧ x ≠ 1 := Hb - -- `g` is a non-identity alternating permutation in a normal subgroup `H` of $A_5$. - rw [← SetLike.mem_coe, ← Set.singleton_subset_iff] at gH - refine eq_top_iff.2 (le_trans (ge_of_eq ?_) (normalClosure_le_normal gH)) - -- It suffices to show that the normal closure of `g` in $A_5$ is $A_5$. - by_cases h2 : ∀ n ∈ g.cycleType, n = 2 - -- If the cycle decomposition of `g` consists entirely of swaps, then the cycle type is $(2,2)$. - -- This means that it is conjugate to $(04)(13)$, whose normal closure is $A_5$. - · rw [Ne, Subtype.ext_iff] at g1 - exact - (isConj_swap_mul_swap_of_cycleType_two gA g1 h2).normalClosure_eq_top_of - normalClosure_swap_mul_swap_five - push Not at h2 - obtain ⟨n, ng, n2⟩ : ∃ n : ℕ, n ∈ g.cycleType ∧ n ≠ 2 := h2 - -- `n` is the size of a non-swap cycle in the decomposition of `g`. - have n2' : 2 < n := lt_of_le_of_ne (two_le_of_mem_cycleType ng) n2.symm - have n5 : n ≤ 5 := le_trans ?_ g.support.card_le_univ - -- We check that `2 < n ≤ 5`, so that `interval_cases` has a precise range to check. - swap - · obtain ⟨m, hm⟩ := Multiset.exists_cons_of_mem ng - rw [← sum_cycleType, hm, Multiset.sum_cons] - exact le_add_right le_rfl - interval_cases n - -- This breaks into cases `n = 3`, `n = 4`, `n = 5`. - -- If `n = 3`, then `g` has a 3-cycle in its decomposition, so `g^2` is a 3-cycle. - -- `g^2` is in the normal closure of `g`, so that normal closure must be $A_5$. - · rw [eq_top_iff, ← (isThreeCycle_sq_of_three_mem_cycleType_five ng).alternating_normalClosure - (by rw [Nat.card_fin])] - refine normalClosure_le_normal ?_ - rw [Set.singleton_subset_iff, SetLike.mem_coe] - have h := SetLike.mem_coe.1 (subset_normalClosure - (G := alternatingGroup (Fin 5)) (Set.mem_singleton ⟨g, gA⟩)) - exact mul_mem h h - · -- The case `n = 4` leads to contradiction, as no element of $A_5$ includes a 4-cycle. - have con := mem_alternatingGroup.1 gA - rw [sign_of_cycleType, cycleType_of_card_le_mem_cycleType_add_two (by decide) ng] at con - have : Odd 5 := by decide - simp [this] at con - · -- If `n = 5`, then `g` is itself a 5-cycle, conjugate to `finRotate 5`. - refine (isConj_iff_cycleType_eq.2 ?_).normalClosure_eq_top_of normalClosure_finRotate_five - rw [cycleType_of_card_le_mem_cycleType_add_two (by decide) ng, cycleType_finRotate]⟩ - theorem center_eq_bot (hα4 : 4 ≤ Nat.card α) : Subgroup.center (alternatingGroup α) = ⊥ := by rw [eq_bot_iff] diff --git a/Mathlib/GroupTheory/SpecificGroups/Alternating/Simple.lean b/Mathlib/GroupTheory/SpecificGroups/Alternating/Simple.lean index f373dc3cfb..a17e8afefd 100644 --- a/Mathlib/GroupTheory/SpecificGroups/Alternating/Simple.lean +++ b/Mathlib/GroupTheory/SpecificGroups/Alternating/Simple.lean @@ -64,7 +64,7 @@ This file contains two uncomfortable uses of `convert`: open scoped Pointwise -open MulAction Equiv.Perm Equiv Set.powersetCard +open MulAction Equiv.Perm Equiv Set.powersetCard Subgroup namespace Equiv.Perm @@ -212,4 +212,30 @@ public theorem isSimpleGroup (hα : 5 ≤ Nat.card α) : simpa using le_trans (by norm_num) hα eq_bot_or_eq_top_of_normal H _ := normal_subgroup_eq_bot_or_eq_top hα +@[deprecated "Use `alternatingGroup.isSimpleGroup` instead." (since := "2026-04-28")] +theorem _root_.Equiv.Perm.IsThreeCycle.alternating_normalClosure + (h5 : 5 ≤ Nat.card α) {f : Perm α} (hf : IsThreeCycle f) : + normalClosure ({⟨f, hf.mem_alternatingGroup⟩} : Set (alternatingGroup α)) = ⊤ := by + have : IsSimpleGroup (alternatingGroup α) := isSimpleGroup h5 + apply normalClosure_normal.eq_bot_or_eq_top.resolve_left + simp [hf.ne_one] + +@[deprecated "Use `alternatingGroup.isSimpleGroup` instead." (since := "2026-04-28")] +theorem normalClosure_finRotate_five : normalClosure ({⟨finRotate 5, + finRotate_bit1_mem_alternatingGroup (n := 2)⟩} : Set (alternatingGroup (Fin 5))) = ⊤ := by + have : IsSimpleGroup (alternatingGroup (Fin 5)) := isSimpleGroup (by simp) + apply normalClosure_normal.eq_bot_or_eq_top.resolve_left + simp +decide + +@[deprecated "Use `alternatingGroup.isSimpleGroup` instead." (since := "2026-04-28")] +theorem normalClosure_swap_mul_swap_five : normalClosure ({⟨swap 0 4 * swap 1 3, + mem_alternatingGroup.2 (by decide)⟩} : Set (alternatingGroup (Fin 5))) = ⊤ := by + have : IsSimpleGroup (alternatingGroup (Fin 5)) := isSimpleGroup (by simp) + apply normalClosure_normal.eq_bot_or_eq_top.resolve_left + simp +decide + +@[deprecated "Use `alternatingGroup.isSimpleGroup` instead." (since := "2026-04-28")] +instance isSimpleGroup_five : IsSimpleGroup (alternatingGroup (Fin 5)) := + isSimpleGroup (by simp) + end alternatingGroup diff --git a/Mathlib/GroupTheory/Torsion.lean b/Mathlib/GroupTheory/Torsion.lean index 72dc27723d..d35e92dddc 100644 --- a/Mathlib/GroupTheory/Torsion.lean +++ b/Mathlib/GroupTheory/Torsion.lean @@ -299,6 +299,10 @@ theorem torsion_eq_torsion_submonoid : CommMonoid.torsion G = (torsion G).toSubm @[to_additive] theorem mem_torsion (g : G) : g ∈ torsion G ↔ IsOfFinOrder g := Iff.rfl +@[to_additive] +lemma torsion_eq_top_iff : torsion G = ⊤ ↔ IsTorsion G := + (torsion G).eq_top_iff' + @[to_additive] lemma isMulTorsionFree_iff_torsion_eq_bot : IsMulTorsionFree G ↔ CommGroup.torsion G = ⊥ := by rw [isMulTorsionFree_iff_not_isOfFinOrder, eq_bot_iff, SetLike.le_def] diff --git a/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean b/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean index bb6718dfd5..63be48109f 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean @@ -451,11 +451,11 @@ theorem image_vsub_image {s t : Set P1} (f : P1 →ᵃ[k] P2) : /-- The product of two affine maps is an affine map. -/ @[simps linear] def prod (f : P1 →ᵃ[k] P2) (g : P1 →ᵃ[k] P3) : P1 →ᵃ[k] P2 × P3 where - toFun := Pi.prod f g + toFun := Function.prod f g linear := f.linear.prod g.linear map_vadd' := by simp -theorem coe_prod (f : P1 →ᵃ[k] P2) (g : P1 →ᵃ[k] P3) : prod f g = Pi.prod f g := +theorem coe_prod (f : P1 →ᵃ[k] P2) (g : P1 →ᵃ[k] P3) : prod f g = Function.prod f g := rfl @[simp] diff --git a/Mathlib/LinearAlgebra/Dimension/Basic.lean b/Mathlib/LinearAlgebra/Dimension/Basic.lean index b8a9406870..4efb57fcd9 100644 --- a/Mathlib/LinearAlgebra/Dimension/Basic.lean +++ b/Mathlib/LinearAlgebra/Dimension/Basic.lean @@ -189,7 +189,7 @@ theorem lift_rank_le_of_injective_injectiveₛ (i : R' → R) (j : M →+ M') (hc : ∀ (r : R') (m : M), j (i r • m) = r • j m) : lift.{v'} (Module.rank R M) ≤ lift.{v} (Module.rank R' M') := by simp_rw [Module.rank, lift_iSup bddAbove_of_small] - exact ciSup_mono' bddAbove_of_small fun ⟨s, h⟩ ↦ ⟨⟨j '' s, + exact ciSup_mono_of_forall_exists' bddAbove_of_small fun ⟨s, h⟩ ↦ ⟨⟨j '' s, LinearIndepOn.id_image (h.linearIndependent.map_of_injective_injectiveₛ i j hi hj hc)⟩, lift_mk_le'.mpr ⟨(Equiv.Set.image j s hj).toEmbedding⟩⟩ @@ -273,7 +273,7 @@ theorem lift_rank_le_of_injective_injective [AddCommGroup M'] [Module R' M'] (hc : ∀ (r : R') (m : M), j (i r • m) = r • j m) : lift.{v'} (Module.rank R M) ≤ lift.{v} (Module.rank R' M') := by simp_rw [Module.rank, lift_iSup bddAbove_of_small] - exact ciSup_mono' bddAbove_of_small fun ⟨s, h⟩ ↦ + exact ciSup_mono_of_forall_exists' bddAbove_of_small fun ⟨s, h⟩ ↦ ⟨⟨j '' s, LinearIndepOn.id_image <| h.linearIndependent.map_of_injective_injective i j hi (fun _ _ ↦ hj <| by rwa [j.map_zero]) hc⟩, lift_mk_le'.mpr ⟨(Equiv.Set.image j s hj).toEmbedding⟩⟩ diff --git a/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean b/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean index b37b76bb2f..b01b9a2073 100644 --- a/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean +++ b/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean @@ -97,7 +97,8 @@ theorem rank_add_rank_split (db : V₂ →ₗ[K] V) (eb : V₃ →ₗ[K] V) (cd rintro ⟨d, e⟩ have h := eq₂ d (-e) simp only [add_eq_zero_iff_eq_neg, LinearMap.prod_apply, mem_ker, - Prod.mk_inj, coprod_apply, map_neg, neg_apply, LinearMap.mem_range, Pi.prod] at h ⊢ + Prod.mk_inj, coprod_apply, map_neg, neg_apply, LinearMap.mem_range, + Function.prod_apply] at h ⊢ grind end diff --git a/Mathlib/LinearAlgebra/Dimension/Finite.lean b/Mathlib/LinearAlgebra/Dimension/Finite.lean index fd04e5a7ed..0ffa7cd3a8 100644 --- a/Mathlib/LinearAlgebra/Dimension/Finite.lean +++ b/Mathlib/LinearAlgebra/Dimension/Finite.lean @@ -9,7 +9,7 @@ public import Mathlib.LinearAlgebra.Dimension.Constructions public import Mathlib.LinearAlgebra.Dimension.StrongRankCondition public import Mathlib.LinearAlgebra.Dimension.Subsingleton public import Mathlib.LinearAlgebra.FreeModule.Finite.Basic -public import Mathlib.SetTheory.Cardinal.Cofinality +public import Mathlib.SetTheory.Cardinal.Cofinality.Ordinal /-! # Conditions for rank to be finite diff --git a/Mathlib/LinearAlgebra/Goursat.lean b/Mathlib/LinearAlgebra/Goursat.lean index 4090de1ada..b39c302ba9 100644 --- a/Mathlib/LinearAlgebra/Goursat.lean +++ b/Mathlib/LinearAlgebra/Goursat.lean @@ -119,24 +119,20 @@ lemma goursat : ∃ (M' : Submodule R M) (N' : Submodule R N) (M'' : Submodule R obtain ⟨e, he⟩ := goursat_surjective hL₁' hL₂' use M', N', L'.goursatFst, L'.goursatSnd, e rw [← he] - simp only [LinearMap.range_comp, Submodule.range_subtype, L'] + simp only [LinearMap.range_comp, Submodule.range_subtype, L', M', N', P, Q] rw [comap_map_eq_self] · ext ⟨m, n⟩ constructor - · intro hmn - simp only [mem_map, LinearMap.mem_range, prod_apply, Subtype.exists, Prod.exists, coe_prodMap, - coe_subtype, Prod.map_apply, Prod.mk.injEq, exists_and_right, exists_eq_right_right, - exists_eq_right, M', N', fst_apply, snd_apply] - exact ⟨⟨n, hmn⟩, ⟨m, hmn⟩, ⟨m, n, hmn, rfl⟩⟩ - · simp only [mem_map, LinearMap.mem_range, prod_apply, Subtype.exists, Prod.exists, - coe_prodMap, coe_subtype, Prod.map_apply, Prod.mk.injEq, exists_and_right, - exists_eq_right_right, exists_eq_right, forall_exists_index, Pi.prod] - rintro hm hn m₁ n₁ hm₁n₁ ⟨hP, hQ⟩ - simp only [Subtype.ext_iff] at hP hQ - rwa [← hP, ← hQ] + · simp only [mem_map, LinearMap.mem_range, LinearMap.prod_apply, Function.prod_apply, + Subtype.exists, Prod.exists, LinearMap.prodMap_apply, subtype_apply, Prod.mk.injEq, + Subtype.ext_iff, submoduleMap_coe_apply, fst_apply, snd_apply] + grind + · simp only [mem_map, LinearMap.mem_range, LinearMap.prod_apply, Function.prod_apply, + Subtype.exists, Prod.exists, LinearMap.prodMap_apply, subtype_apply, Prod.mk.injEq, + snd_apply, fst_apply, Subtype.ext_iff, submoduleMap_coe_apply] + grind · convert goursatFst_prod_goursatSnd_le (range <| P.prod Q) - ext ⟨m, n⟩ - simp_rw [mem_ker, coe_prodMap, Prod.map_apply, Submodule.mem_prod, Prod.zero_eq_mk, - Prod.ext_iff, ← mem_ker, ker_mkQ] + simp only [ker_prodMap, ker_mkQ, Submodule.ext_iff] + grind end Submodule diff --git a/Mathlib/LinearAlgebra/Prod.lean b/Mathlib/LinearAlgebra/Prod.lean index 6416808409..21f532a1db 100644 --- a/Mathlib/LinearAlgebra/Prod.lean +++ b/Mathlib/LinearAlgebra/Prod.lean @@ -93,11 +93,11 @@ theorem snd_surjective : Function.Surjective (snd R M M₂) := fun x => ⟨(0, x /-- The prod of two linear maps is a linear map. -/ @[simps] def prod (f : M →ₗ[R] M₂) (g : M →ₗ[R] M₃) : M →ₗ[R] M₂ × M₃ where - toFun := Pi.prod f g - map_add' x y := by simp only [Pi.prod, Prod.mk_add_mk, map_add] - map_smul' c x := by simp only [Pi.prod, Prod.smul_mk, map_smul, RingHom.id_apply] + toFun := Function.prod f g + map_add' x y := by simp only [Function.prod_apply, Prod.mk_add_mk, map_add] + map_smul' c x := by simp only [Function.prod_apply, Prod.smul_mk, map_smul, RingHom.id_apply] -theorem coe_prod (f : M →ₗ[R] M₂) (g : M →ₗ[R] M₃) : ⇑(f.prod g) = Pi.prod f g := +theorem coe_prod (f : M →ₗ[R] M₂) (g : M →ₗ[R] M₃) : ⇑(f.prod g) = Function.prod f g := rfl @[simp] @@ -850,7 +850,7 @@ theorem range_prod_eq {f : M →ₗ[R] M₂} {g : M →ₗ[R] M₃} (h : ker f range (prod f g) = (range f).prod (range g) := by refine le_antisymm (f.range_prod_le g) ?_ simp only [SetLike.le_def, prod_apply, mem_range, mem_prod, exists_imp, and_imp, - Prod.forall, Pi.prod] + Prod.forall, Function.prod_apply] rintro _ _ x rfl y rfl -- Note: https://github.com/leanprover-community/mathlib4/pull/8386 had to specify `(f := f)` simp only [Prod.mk_inj, ← sub_mem_ker_iff (f := f)] diff --git a/Mathlib/LinearAlgebra/QuadraticForm/Dual.lean b/Mathlib/LinearAlgebra/QuadraticForm/Dual.lean index e607498ea3..f4f8519a9a 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/Dual.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/Dual.lean @@ -140,7 +140,7 @@ def toDualProd (Q : QuadraticForm R M) [Invertible (2 : R)] : map_app' x := by dsimp only [associated, associatedHom] dsimp only [LinearMap.smul_apply, LinearMap.coe_mk, AddHom.coe_mk, AddHom.toFun_eq_coe, - LinearMap.coe_toAddHom, LinearMap.prod_apply, Pi.prod, LinearMap.add_apply, + LinearMap.coe_toAddHom, LinearMap.prod_apply, Function.prod_apply, LinearMap.add_apply, LinearMap.coe_comp, Function.comp_apply, LinearMap.fst_apply, LinearMap.snd_apply, LinearMap.sub_apply, dualProd_apply, polarBilin_apply_apply, prod_apply, neg_apply] simp only [polar_sub_right, polar_self, nsmul_eq_mul, Nat.cast_ofNat, polar_comm _ x.1 x.2, diff --git a/Mathlib/Logic/Function/Defs.lean b/Mathlib/Logic/Function/Defs.lean index 2d7cf78fb0..04b9b63554 100644 --- a/Mathlib/Logic/Function/Defs.lean +++ b/Mathlib/Logic/Function/Defs.lean @@ -31,6 +31,19 @@ def dcomp {β : α → Sort u₂} {φ : ∀ {x : α}, β x → Sort u₃} (f : @[inherit_doc] infixr:80 " ∘' " => Function.dcomp +/-- Product of functions: `Function.prod f g i = (f i, g i)`, where the types of `f i` and +`g i` may depend on `i`. -/ +protected def prod {ι} {α β : ι → Type*} (f : ∀ i, α i) (g : ∀ i, β i) (i : ι) : + α i × β i := (f i, g i) + +@[simp] lemma prod_apply {ι} {α β : ι → Type*} (f : ∀ i, α i) (g : ∀ i, β i) (i : ι) : + Function.prod f g i = (f i , g i) := rfl + +lemma prod_fst_snd {α β} : Function.prod (Prod.fst : α × β → α) (Prod.snd : α × β → β) = id := + rfl +lemma prod_snd_fst {α β} : Function.prod (Prod.snd : α × β → β) (Prod.fst : α × β → α) = .swap := + rfl + /-- Given functions `f : β → β → φ` and `g : α → β`, produce a function `α → α → φ` that evaluates `g` on each argument, then applies `f` to the results. Can be used, e.g., to transfer a relation from `β` to `α`. -/ diff --git a/Mathlib/MeasureTheory/Integral/Prod.lean b/Mathlib/MeasureTheory/Integral/Prod.lean index 6c872f1d9a..7f3f98fb7f 100644 --- a/Mathlib/MeasureTheory/Integral/Prod.lean +++ b/Mathlib/MeasureTheory/Integral/Prod.lean @@ -502,7 +502,7 @@ theorem integral_prod (f : α × β → E) (hf : Integrable f (μ.prod ν)) : measureReal_def, integral_toReal (measurable_measure_prodMk_left hs).aemeasurable (ae_measure_lt_top hs h2s.ne)] - rw [prod_apply hs] + rw [Measure.prod_apply hs] · rintro f g - i_f i_g hf hg simp_rw [integral_add' i_f i_g, integral_integral_add' i_f i_g, hf, hg] · exact isClosed_eq continuous_integral continuous_integral_integral diff --git a/Mathlib/MeasureTheory/Measure/Prod.lean b/Mathlib/MeasureTheory/Measure/Prod.lean index 6ccbdf61d6..e14709c68e 100644 --- a/Mathlib/MeasureTheory/Measure/Prod.lean +++ b/Mathlib/MeasureTheory/Measure/Prod.lean @@ -837,7 +837,7 @@ theorem map_prod_map {δ} [MeasurableSpace δ] {f : α → β} {g : γ → δ} ( -- hence it is placed in the `WithDensity` file, where the instance is defined. lemma prod_smul_left {μ : Measure α} (c : ℝ≥0∞) : (c • μ).prod ν = c • (μ.prod ν) := by ext s hs - rw [Measure.prod_apply hs, Measure.smul_apply, Measure.prod_apply hs] + rw [prod_apply hs, Measure.smul_apply, prod_apply hs] simp end Measure @@ -873,7 +873,7 @@ theorem skew_product [SFinite μa] [SFinite μc] {f : α → β} (hf : MeasurePr infer_instance -- Thus we can use the integral formula for the product measure, and compute things explicitly ext s hs - rw [map_apply this hs, prod_apply (this hs), prod_apply hs, + rw [map_apply this hs, Measure.prod_apply (this hs), Measure.prod_apply hs, ← hf.lintegral_comp (measurable_measure_prodMk_left hs)] apply lintegral_congr_ae filter_upwards [hg] with a ha @@ -898,7 +898,7 @@ theorem prod_of_right {f : α × β → γ} {μ : Measure α} {ν : Measure β} QuasiMeasurePreserving f (μ.prod ν) τ := by refine ⟨hf, ?_⟩ refine AbsolutelyContinuous.mk fun s hs h2s => ?_ - rw [map_apply hf hs, prod_apply (hf hs)]; simp_rw [preimage_preimage] + rw [map_apply hf hs, Measure.prod_apply (hf hs)]; simp_rw [preimage_preimage] rw [lintegral_congr_ae (h2f.mono fun x hx => hx.preimage_null h2s), lintegral_zero] theorem prod_of_left {α β γ} [MeasurableSpace α] [MeasurableSpace β] [MeasurableSpace γ] @@ -1222,8 +1222,9 @@ theorem _root_.MeasureTheory.measurePreserving_prodAssoc (μa : Measure α) (μb have A (x : α) : MeasurableSet (Prod.mk x ⁻¹' s) := measurable_prodMk_left hs have B : MeasurableSet (MeasurableEquiv.prodAssoc ⁻¹' s) := MeasurableEquiv.prodAssoc.measurable hs - simp_rw [map_apply MeasurableEquiv.prodAssoc.measurable hs, prod_apply hs, prod_apply (A _), - prod_apply B, lintegral_prod _ (measurable_measure_prodMk_left B).aemeasurable] + simp_rw [map_apply MeasurableEquiv.prodAssoc.measurable hs, Measure.prod_apply hs, + Measure.prod_apply (A _), Measure.prod_apply B, + lintegral_prod _ (measurable_measure_prodMk_left B).aemeasurable] rfl theorem _root_.MeasureTheory.volume_preserving_prodAssoc {α₁ β₁ γ₁ : Type*} [MeasureSpace α₁] diff --git a/Mathlib/NumberTheory/Dioph.lean b/Mathlib/NumberTheory/Dioph.lean index 3e2135a239..bdbe351279 100644 --- a/Mathlib/NumberTheory/Dioph.lean +++ b/Mathlib/NumberTheory/Dioph.lean @@ -243,7 +243,7 @@ end Polynomials /-- A set `S ⊆ ℕ^α` is Diophantine if there exists a polynomial on `α ⊕ β` such that `v ∈ S` iff there exists `t : ℕ^β` with `p (v, t) = 0`. -/ def Dioph {α : Type u} (S : Set (α → ℕ)) : Prop := - ∃ (β : Type u) (p : Poly (α ⊕ β)), ∀ v, S v ↔ ∃ t, p (v ⊗ t) = 0 + ∃ (β : Type u) (p : Poly (α ⊕ β)), ∀ v, v ∈ S ↔ ∃ t, p (v ⊗ t) = 0 namespace Dioph @@ -253,7 +253,7 @@ variable {α β γ : Type u} {S S' : Set (α → ℕ)} theorem ext (d : Dioph S) (H : ∀ v, v ∈ S ↔ v ∈ S') : Dioph S' := by rwa [← Set.ext H] -theorem of_no_dummies (S : Set (α → ℕ)) (p : Poly α) (h : ∀ v, S v ↔ p v = 0) : Dioph S := +theorem of_no_dummies (S : Set (α → ℕ)) (p : Poly α) (h : ∀ v, v ∈ S ↔ p v = 0) : Dioph S := ⟨PEmpty, ⟨p.map inl, fun v => (h v).trans ⟨fun h => ⟨PEmpty.elim, h⟩, fun ⟨_, ht⟩ => ht⟩⟩⟩ theorem inject_dummies_lem (f : β → γ) (g : γ → Option β) (inv : ∀ x, g (f x) = some x) @@ -267,8 +267,8 @@ theorem inject_dummies_lem (f : β → γ) (g : γ → Option β) (inv : ∀ x, exact ⟨t ∘ f, by rwa [this]⟩ theorem inject_dummies (f : β → γ) (g : γ → Option β) (inv : ∀ x, g (f x) = some x) - (p : Poly (α ⊕ β)) (h : ∀ v, S v ↔ ∃ t, p (v ⊗ t) = 0) : - ∃ q : Poly (α ⊕ γ), ∀ v, S v ↔ ∃ t, q (v ⊗ t) = 0 := + (p : Poly (α ⊕ β)) (h : ∀ v, v ∈ S ↔ ∃ t, p (v ⊗ t) = 0) : + ∃ q : Poly (α ⊕ γ), ∀ v, v ∈ S ↔ ∃ t, q (v ⊗ t) = 0 := ⟨p.map (inl ⊗ inr ∘ f), fun v => (h v).trans <| inject_dummies_lem f g inv _ _⟩ variable (β) in @@ -281,7 +281,7 @@ theorem reindex_dioph (f : α → β) : Dioph S → Dioph {v | v ∘ f ∈ S} theorem DiophList.forall (l : List (Set <| α → ℕ)) (d : l.Forall Dioph) : Dioph {v | l.Forall fun S : Set (α → ℕ) => v ∈ S} := by - suffices ∃ (β : _) (pl : List (Poly (α ⊕ β))), ∀ v, List.Forall (fun S : Set _ => S v) l ↔ + suffices ∃ (β : _) (pl : List (Poly (α ⊕ β))), ∀ v, List.Forall (fun S : Set _ => v ∈ S) l ↔ ∃ t, List.Forall (fun p : Poly (α ⊕ β) => p (v ⊗ t) = 0) pl from let ⟨β, pl, h⟩ := this @@ -335,7 +335,7 @@ theorem union : ∀ (_ : Dioph S) (_ : Dioph S'), Dioph (S ∪ S') /-- A partial function is Diophantine if its graph is Diophantine. -/ def DiophPFun (f : (α → ℕ) →. ℕ) : Prop := - Dioph {v : Option α → ℕ | f.graph (v ∘ some, v none)} + Dioph {v : Option α → ℕ | (v ∘ some, v none) ∈ f.graph} /-- A function is Diophantine if its graph is Diophantine. -/ def DiophFn (f : (α → ℕ) → ℕ) : Prop := @@ -419,7 +419,7 @@ open Vector3 open scoped Vector3 theorem diophFn_vec_comp1 {S : Set (Vector3 ℕ (succ n))} (d : Dioph S) {f : Vector3 ℕ n → ℕ} - (df : DiophFn f) : Dioph {v : Vector3 ℕ n | (f v::v) ∈ S} := + (df : DiophFn f) : Dioph {v : Vector3 ℕ n | (f v :: v) ∈ S} := Dioph.ext (diophFn_comp1 (reindex_dioph _ (none :: some) d) df) (fun v => by dsimp -- TODO: `apply iff_of_eq` is required here, even though `congr!` works on iff below. @@ -430,7 +430,7 @@ theorem diophFn_vec_comp1 {S : Set (Vector3 ℕ (succ n))} (d : Dioph S) {f : Ve set_option backward.isDefEq.respectTransparency false in /-- Deleting the first component preserves the Diophantine property. -/ theorem vec_ex1_dioph (n) {S : Set (Vector3 ℕ (succ n))} (d : Dioph S) : - Dioph {v : Fin2 n → ℕ | ∃ x, (x::v) ∈ S} := + Dioph {v : Fin2 n → ℕ | ∃ x, (x :: v) ∈ S} := ext (ex1_dioph <| reindex_dioph _ (none :: some) d) fun v => exists_congr fun x => by dsimp @@ -440,7 +440,7 @@ theorem vec_ex1_dioph (n) {S : Set (Vector3 ℕ (succ n))} (d : Dioph S) : theorem diophFn_vec (f : Vector3 ℕ n → ℕ) : DiophFn f ↔ Dioph {v | f (v ∘ fs) = v fz} := ⟨reindex_dioph _ (fz ::ₒ fs), reindex_dioph _ (none::some)⟩ -theorem diophPFun_vec (f : Vector3 ℕ n →. ℕ) : DiophPFun f ↔ Dioph {v | f.graph (v ∘ fs, v fz)} := +theorem diophPFun_vec (f : Vector3 ℕ n →. ℕ) : DiophPFun f ↔ Dioph {v | (v ∘ fs, v fz) ∈ f.graph} := ⟨reindex_dioph _ (fz ::ₒ fs), reindex_dioph _ (none::some)⟩ theorem diophFn_compn : @@ -466,7 +466,7 @@ theorem diophFn_compn : congr! 1 ext x; obtain _ | _ | _ := x <;> rfl have : Dioph {v | (v ⊗ f v::fun i : Fin2 n => fl i v) ∈ S} := - @diophFn_compn n (fun v => S (v ∘ inl ⊗ f (v ∘ inl) :: v ∘ inr)) this _ dfl + @diophFn_compn n (fun v => (v ∘ inl ⊗ f (v ∘ inl) :: v ∘ inr) ∈ S) this _ dfl ext this fun v => by dsimp congr! 3 with x @@ -511,14 +511,14 @@ section variable {f g : (α → ℕ) → ℕ} (df : DiophFn f) (dg : DiophFn g) include df dg -theorem dioph_comp2 {S : ℕ → ℕ → Prop} (d : Dioph fun v : Vector3 ℕ 2 => S (v &0) (v &1)) : - Dioph fun v => S (f v) (g v) := dioph_comp d [f, g] ⟨df, dg⟩ +theorem dioph_comp2 {S : ℕ → ℕ → Prop} (d : Dioph {v : Vector3 ℕ 2 | S (v &0) (v &1)}) : + Dioph {v | S (f v) (g v)} := dioph_comp d [f, g] ⟨df, dg⟩ theorem diophFn_comp2 {h : ℕ → ℕ → ℕ} (d : DiophFn fun v : Vector3 ℕ 2 => h (v &0) (v &1)) : DiophFn fun v => h (f v) (g v) := diophFn_comp d [f, g] ⟨df, dg⟩ /-- The set of places where two Diophantine functions are equal is Diophantine. -/ -theorem eq_dioph : Dioph fun v => f v = g v := +theorem eq_dioph : Dioph {v | f v = g v} := dioph_comp2 df dg <| of_no_dummies _ (Poly.proj &0 - Poly.proj &1) fun v => by exact Int.ofNat_inj.symm.trans ⟨@sub_eq_zero_of_eq ℤ _ (v &0) (v &1), eq_of_sub_eq_zero⟩ @@ -573,7 +573,7 @@ theorem sub_dioph : DiophFn fun v ↦ f v - g v := scoped infixl:80 " D- " => Dioph.sub_dioph /-- The set of places where one Diophantine function divides another is Diophantine. -/ -theorem dvd_dioph : Dioph fun v => f v ∣ g v := +theorem dvd_dioph : Dioph {v | f v ∣ g v} := dioph_comp ((D∃) 2 <| D&2 D= D&1 D* D&0) [f, g] ⟨df, dg⟩ @[inherit_doc] @@ -581,7 +581,7 @@ scoped infixl:50 " D∣ " => Dioph.dvd_dioph /-- Diophantine functions are closed under the modulo operation. -/ theorem mod_dioph : DiophFn fun v => f v % g v := - have : Dioph fun v : Vector3 ℕ 3 => (v &2 = 0 ∨ v &0 < v &2) ∧ ∃ x : ℕ, v &0 + v &2 * x = v &1 := + have : Dioph {v : Vector3 ℕ 3 | (v &2 = 0 ∨ v &0 < v &2) ∧ ∃ x : ℕ, v &0 + v &2 * x = v &1} := (D&2 D= D.0 D∨ D&0 D< D&2) D∧ (D∃) 3 <| D&1 D+ D&3 D* D&0 D= D&2 diophFn_comp2 df dg <| (diophFn_vec _).2 <| @@ -601,7 +601,7 @@ scoped infixl:80 " D% " => Dioph.mod_dioph /-- The set of places where two Diophantine functions are congruent modulo a third is Diophantine. -/ -theorem modEq_dioph {h : (α → ℕ) → ℕ} (dh : DiophFn h) : Dioph fun v => f v ≡ g v [MOD h v] := +theorem modEq_dioph {h : (α → ℕ) → ℕ} (dh : DiophFn h) : Dioph {v | f v ≡ g v [MOD h v]} := df D% dh D= dg D% dh @[inherit_doc] @@ -610,8 +610,7 @@ scoped notation "D≡ " => Dioph.modEq_dioph /-- Diophantine functions are closed under integer division. -/ theorem div_dioph : DiophFn fun v => f v / g v := have : - Dioph fun v : Vector3 ℕ 3 => - v &2 = 0 ∧ v &0 = 0 ∨ v &0 * v &2 ≤ v &1 ∧ v &1 < (v &0 + 1) * v &2 := + Dioph {v : Vector3 ℕ 3 | v &2 = 0 ∧ v &0 = 0 ∨ v &0 * v &2 ≤ v &1 ∧ v &1 < (v &0 + 1) * v &2} := (D&2 D= D.0 D∧ D&0 D= D.0) D∨ D&0 D* D&2 D≤ D&1 D∧ D&1 D< (D&0 D+ D.1) D* D&2 diophFn_comp2 df dg <| (diophFn_vec _).2 <| @@ -631,7 +630,7 @@ scoped infixl:80 " D/ " => Dioph.div_dioph open Pell theorem pell_dioph : - Dioph fun v : Vector3 ℕ 4 => ∃ h : 1 < v &0, xn h (v &1) = v &2 ∧ yn h (v &1) = v &3 := by + Dioph {v : Vector3 ℕ 4 | ∃ h : 1 < v &0, xn h (v &1) = v &2 ∧ yn h (v &1) = v &3} := by have : Dioph {v : Vector3 ℕ 4 | 1 < v &0 ∧ v &1 ≤ v &3 ∧ (v &2 = 1 ∧ v &3 = 0 ∨ @@ -656,7 +655,7 @@ theorem pell_dioph : exact Dioph.ext this fun v => matiyasevic.symm theorem xn_dioph : DiophPFun fun v : Vector3 ℕ 2 => ⟨1 < v &0, fun h => xn h (v &1)⟩ := - have : Dioph fun v : Vector3 ℕ 3 => ∃ y, ∃ h : 1 < v &1, xn h (v &2) = v &0 ∧ yn h (v &2) = y := + have : Dioph {v : Vector3 ℕ 3 | ∃ y, ∃ h : 1 < v &1, xn h (v &2) = v &0 ∧ yn h (v &2) = y} := let D_pell := pell_dioph.reindex_dioph (Fin2 4) [&2, &3, &1, &0] (D∃) 3 D_pell (diophPFun_vec _).2 <| diff --git a/Mathlib/NumberTheory/Divisors.lean b/Mathlib/NumberTheory/Divisors.lean index 964d4299a3..f618c25539 100644 --- a/Mathlib/NumberTheory/Divisors.lean +++ b/Mathlib/NumberTheory/Divisors.lean @@ -692,44 +692,15 @@ lemma mem_divisors_self (hz : z ≠ 0) : z ∈ divisors z := simp @[simp] -lemma mem_divisorsAntidiag : - ∀ {z} {xy : ℤ × ℤ}, xy ∈ divisorsAntidiag z ↔ xy.fst * xy.snd = z ∧ z ≠ 0 - | (n : ℕ), ((x : ℕ), (y : ℕ)) => by +lemma mem_divisorsAntidiag : xy ∈ divisorsAntidiag z ↔ xy.fst * xy.snd = z ∧ z ≠ 0 := by + rcases z, xy with ⟨_ | _, ⟨_ | _, _ | _⟩⟩ + -- splitting this case saves about 1770 heartbeats i.e. 12.5% faster + case ofNat.negSucc.negSucc => simp [divisorsAntidiag] - norm_cast - simp +contextual [eq_comm] - | (n : ℕ), (negSucc x, negSucc y) => by - simp [divisorsAntidiag, negSucc_eq, -neg_add_rev] - norm_cast - simp +contextual [eq_comm] - | (n : ℕ), ((x : ℕ), negSucc y) => by - simp [divisorsAntidiag, negSucc_eq, -neg_add_rev] - norm_cast - aesop - | (n : ℕ), (negSucc x, (y : ℕ)) => by - suffices - (∃ a, (n = a * y ∧ ¬n = 0) ∧ (a : ℤ) = -1 + -↑x) ↔ (n : ℤ) = (-1 + -↑x) * ↑y ∧ ¬n = 0 by - simpa [divisorsAntidiag, eq_comm, negSucc_eq] - simp only [← Int.neg_add, Int.add_comm 1, Int.neg_mul, Int.add_mul] - norm_cast - match n with - | 0 => simp - | n + 1 => simp - | .negSucc n, ((x : ℕ), (y : ℕ)) => by + grind [Nat.cast_inj] + all_goals simp [divisorsAntidiag] - norm_cast - | .negSucc n, (negSucc x, negSucc y) => by - simp [divisorsAntidiag, negSucc_eq, -neg_add_rev] - norm_cast - simp +contextual - | .negSucc n, ((x : ℕ), negSucc y) => by - simp [divisorsAntidiag, negSucc_eq, -neg_add_rev] - norm_cast - aesop - | .negSucc n, (negSucc x, (y : ℕ)) => by - simp [divisorsAntidiag, negSucc_eq, -neg_add_rev] - norm_cast - simp +contextual [eq_comm] + grind theorem image_fst_divisorsAntidiag : z.divisorsAntidiag.image Prod.fst = z.divisors := by ext diff --git a/Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean b/Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean index 45989e41e3..92452a06dc 100644 --- a/Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean +++ b/Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean @@ -215,9 +215,8 @@ lemma term_tsum_of_lt {s : ℝ} (hs : 1 < s) : · exact_mod_cast (summable_nat_add_iff 1).mpr (summable_one_div_nat_rpow.mpr hs) · apply tendsto_of_tendsto_of_tendsto_of_le_of_le tendsto_const_nhds · change Tendsto (fun n : ℕ ↦ (1 / ↑(n + 1) : ℝ) ^ (s - 1)) .. - rw [show 𝓝 (0 : ℝ) = 𝓝 (0 ^ (s - 1)) by rw [zero_rpow]; linarith] - refine Tendsto.rpow_const ?_ (Or.inr <| by linarith) - exact (tendsto_const_div_atTop_nhds_zero_nat _).comp (tendsto_add_atTop_nat _) + exact ((tendsto_const_div_atTop_nhds_zero_nat _).comp + (tendsto_add_atTop_nat _)).rpow_const_nhds_zero (by linarith) · intro n positivity · intro n diff --git a/Mathlib/NumberTheory/Height/Basic.lean b/Mathlib/NumberTheory/Height/Basic.lean index f8e6f016da..3e1eb2e95a 100644 --- a/Mathlib/NumberTheory/Height/Basic.lean +++ b/Mathlib/NumberTheory/Height/Basic.lean @@ -667,7 +667,7 @@ lemma mulHeight_fun_prod_eq {x : (a : α) → ι a → K} (hx : ∀ a, x a ≠ 0 simp_rw [ne_iff, Pi.zero_def] at hx ⊢ choose f hf using hx exact ⟨f, prod_ne_zero_iff.mpr fun a _ ↦ hf a⟩ - simp_rw [map_prod, Real.iSup_prod_eq_prod_iSup_of_nonnegHomClass] + simp_rw [_root_.map_prod, Real.iSup_prod_eq_prod_iSup_of_nonnegHomClass] rw [Multiset.prod_map_prod, finprod_prod_comm _ _ fun b _ ↦ hasFiniteMulSupport_iSup_nonarchAbsVal (hx b), ← prod_mul_distrib] diff --git a/Mathlib/NumberTheory/ModularForms/Basic.lean b/Mathlib/NumberTheory/ModularForms/Basic.lean index cfb4abba9e..c1ab072b34 100644 --- a/Mathlib/NumberTheory/ModularForms/Basic.lean +++ b/Mathlib/NumberTheory/ModularForms/Basic.lean @@ -557,6 +557,7 @@ section GradedRing /-- Cast for modular forms, which is useful for avoiding `Heq`s. Optionally transports along an equality of subgroups. -/ +@[simps -fullyApplied coe] def mcast {a b : ℤ} {Γ Γ' : Subgroup (GL (Fin 2) ℝ)} (h : a = b) (f : ModularForm Γ a) (hΓ : Γ' = Γ := by rfl) : ModularForm Γ' b where toFun := (f : ℍ → ℂ) @@ -571,6 +572,18 @@ theorem gradedMonoid_eq_of_cast {Γ : Subgroup (GL (Fin 2) ℝ)} {a b : GradedMo cases h exact congr_arg _ h2 +/-- The `n`-th power of a modular form, as a modular form of weight `n * k`. -/ +def pow {Γ : Subgroup (GL (Fin 2) ℝ)} [Γ.HasDetPlusMinusOne] {k : ℤ} (f : ModularForm Γ k) + (n : ℕ) : ModularForm Γ (n * k) := + n.rec (mcast (by simp) (1 : ModularForm Γ 0)) (fun n g ↦ (g.mul f).mcast (by grind)) + +@[simp] +lemma coe_pow {Γ : Subgroup (GL (Fin 2) ℝ)} [Γ.HasDetPlusMinusOne] {k : ℤ} + (f : ModularForm Γ k) (n : ℕ) : ⇑(f.pow n) = (⇑f) ^ n := by + induction n with + | zero => simp [pow] + | succ n ih => simp_all only [pow, coe_mcast, coe_mul, pow_succ] + instance (Γ : Subgroup (GL (Fin 2) ℝ)) [Γ.HasDetPlusMinusOne] : GradedMonoid.GOne (ModularForm Γ) where one := 1 @@ -608,6 +621,29 @@ open scoped DirectSum in example (Γ : Subgroup (GL (Fin 2) ℝ)) [Γ.HasDetOne] : Algebra ℂ (⨁ i, ModularForm Γ i) := inferInstance +/-- Bridge between the auto-derived graded-monoid power `GradedMonoid.GMonoid.gnpow` and the +bespoke `ModularForm.pow`: as elements of `GradedMonoid (ModularForm Γ)`, the pair +`⟨n • k, gnpow n f⟩` agrees with `⟨n * k, f.pow n⟩`. -/ +theorem gnpow_eq_pow {Γ : Subgroup (GL (Fin 2) ℝ)} [Γ.HasDetPlusMinusOne] + {k : ℤ} (f : ModularForm Γ k) (n : ℕ) : + (⟨n • k, GradedMonoid.GMonoid.gnpow n f⟩ : GradedMonoid (ModularForm Γ)) = + ⟨(n : ℤ) * k, f.pow n⟩ := by + induction n with + | zero => + refine (GradedMonoid.GMonoid.gnpow_zero' ⟨k, f⟩).trans ?_ + exact gradedMonoid_eq_of_cast (zero_mul k).symm (ModularForm.ext fun _ ↦ rfl) + | succ n ih => + refine (GradedMonoid.GMonoid.gnpow_succ' n ⟨k, f⟩).trans ?_ + refine (congrArg (fun x : GradedMonoid (ModularForm Γ) ↦ x * ⟨k, f⟩) ih).trans ?_ + exact gradedMonoid_eq_of_cast (show ((n : ℤ) * k + k = (n + 1) * k) by ring) + (ModularForm.ext fun _ ↦ rfl) + +/-- The `n`-th power of `DirectSum.of _ k f` lands in grade `n * k` and is given by `f.pow n`. -/ +lemma directSum_of_pow {Γ : Subgroup (GL (Fin 2) ℝ)} [Γ.HasDetPlusMinusOne] + {k : ℤ} (f : ModularForm Γ k) (n : ℕ) : + (DirectSum.of (ModularForm Γ) k f) ^ n = .of (ModularForm Γ) ((n : ℤ) * k) (f.pow n) := by + grind [DirectSum.ofPow, DirectSum.of_eq_of_gradedMonoid_eq (gnpow_eq_pow f n)] + open Filter SlashInvariantForm /-- Given `ModularForm`'s `F i` of weight `k i` for `i : ι`, define the form which as a diff --git a/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean b/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean index 5d38f28dbe..dcd9a8cd69 100644 --- a/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean +++ b/Mathlib/NumberTheory/ModularForms/CuspFormSubmodule.lean @@ -6,7 +6,7 @@ Authors: Chris Birkbeck module public import Mathlib.NumberTheory.ModularForms.QExpansion -public import Mathlib.NumberTheory.ModularForms.LevelOne +public import Mathlib.NumberTheory.ModularForms.LevelOne.Basic public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.QExpansion /-! diff --git a/Mathlib/NumberTheory/ModularForms/Discriminant.lean b/Mathlib/NumberTheory/ModularForms/Discriminant.lean index 582d40a8fe..a489b589c9 100644 --- a/Mathlib/NumberTheory/ModularForms/Discriminant.lean +++ b/Mathlib/NumberTheory/ModularForms/Discriminant.lean @@ -10,7 +10,7 @@ public import Mathlib.Analysis.Normed.Ring.InfiniteProd public import Mathlib.NumberTheory.ModularForms.DedekindEta public import Mathlib.NumberTheory.ModularForms.Basic public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.E2.Transform -public import Mathlib.NumberTheory.ModularForms.LevelOne +public import Mathlib.NumberTheory.ModularForms.LevelOne.Basic public import Mathlib.NumberTheory.ModularForms.QExpansion /-! @@ -192,6 +192,33 @@ lemma exp_isBigO_discriminant : (fun τ ↦ Real.exp (-2 * π * τ.im)) =O[atImI grind [norm_one, norm_sub_rev] linarith [norm_nonneg (𝕢 1 τ), mul_le_mul_of_nonneg_left hprod_bound (norm_nonneg (𝕢 1 τ))] +/-- The cusp function of the discriminant equals `q * ∏' n, (1 - q^(n+1))^24` +on the open unit disc. -/ +lemma discriminant_cuspFunction_eqOn : Set.EqOn (cuspFunction 1 Δ) + (fun q ↦ q * ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 1) := by + intro q hq + by_cases hq0 : q = 0 + · simpa [hq0] using Periodic.cuspFunction_zero_of_zero_at_inf one_pos + discriminant_isZeroAtImInfty.zero_at_infty_comp_ofComplex + · have him := Periodic.im_invQParam_pos_of_norm_lt_one one_pos + (by simpa [dist_zero_right] using hq) hq0 + simp [cuspFunction, Periodic.cuspFunction_eq_of_nonzero 1 _ hq0, + ofComplex_apply_of_im_pos him, discriminant_eq_q_prod ⟨_, him⟩, + Periodic.qParam_right_inv one_ne_zero hq0, eta_q] + +/-- The first q-expansion coefficient of the modular discriminant is 1. -/ +lemma discriminant_qExpansion_coeff_one : (qExpansion 1 Δ).coeff 1 = 1 := by + have hmem : (0 : ℂ) ∈ Metric.ball (0 : ℂ) 1 := Metric.mem_ball_self one_pos + calc (qExpansion 1 Δ).coeff 1 + = derivWithin (cuspFunction 1 Δ) (Metric.ball 0 1) 0 := by + simp [qExpansion_coeff, ← derivWithin_of_isOpen Metric.isOpen_ball hmem] + _ = derivWithin (fun q ↦ q * ∏' i, (1 - q ^ (i + 1)) ^ 24) (Metric.ball 0 1) 0 := + derivWithin_congr discriminant_cuspFunction_eqOn (discriminant_cuspFunction_eqOn hmem) + _ = 1 := by + simp [derivWithin_fun_mul differentiableWithinAt_id' + (differentiableOn_tprod_one_sub_pow_pow 24 _ hmem), + derivWithin_id' _ _ (Metric.isOpen_ball.uniqueDiffWithinAt hmem)] + end end ModularForm diff --git a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean index dd08d30f3e..b6d65d4acf 100644 --- a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean +++ b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean @@ -10,7 +10,7 @@ public import Mathlib.Analysis.SpecialFunctions.Trigonometric.Cotangent public import Mathlib.NumberTheory.LSeries.Dirichlet public import Mathlib.NumberTheory.LSeries.HurwitzZetaValues public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.Basic -public import Mathlib.NumberTheory.ModularForms.LevelOne +public import Mathlib.NumberTheory.ModularForms.LevelOne.Basic public import Mathlib.NumberTheory.TsumDivisorsAntidiagonal import Mathlib.Topology.EMetricSpace.Paracompact diff --git a/Mathlib/NumberTheory/ModularForms/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/LevelOne/Basic.lean similarity index 100% rename from Mathlib/NumberTheory/ModularForms/LevelOne.lean rename to Mathlib/NumberTheory/ModularForms/LevelOne/Basic.lean diff --git a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/LevelOne/DimensionFormula.lean similarity index 97% rename from Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean rename to Mathlib/NumberTheory/ModularForms/LevelOne/DimensionFormula.lean index 0ddf7a000f..dd37aa7f69 100644 --- a/Mathlib/NumberTheory/ModularForms/DimensionFormulas/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/LevelOne/DimensionFormula.lean @@ -136,8 +136,8 @@ lemma ModularForm.rank_eq_one_add_rank_cuspForm {k : ℕ} (hk : 3 ≤ k) (hk2 : exact one_ne_zero <| hE.symm.trans <| (isCuspForm_iff_coeffZero_eq_zero _).mp h · refine (Submodule.Quotient.forall _).mpr fun f ↦ ⟨(qExpansion 1 f).coeff 0, ?_⟩ rw [← Submodule.Quotient.mk_smul, Submodule.Quotient.eq, mem_cuspFormSubmodule_iff, - isCuspForm_iff_coeffZero_eq_zero, ModularForm.coe_sub, ModularFormClass.qExpansion_sub, - IsGLPos.coe_smul, ModularFormClass.qExpansion_smul, map_sub, + isCuspForm_iff_coeffZero_eq_zero, ModularForm.coe_sub, ModularForm.qExpansion_sub, + IsGLPos.coe_smul, ModularForm.qExpansion_smul, map_sub, PowerSeries.coeff_smul, E_qExpansion_coeff_zero hk hk2, smul_eq_mul, mul_one, sub_self] all_goals simp @@ -187,12 +187,12 @@ private lemma weight_two_qExpansion_eq_zero (f : ModularForm 𝒮ℒ 2) : qExpan (Module.rank_eq_one_iff_finrank_eq_one.mp levelOne_weight_six_rank_one) _ have hqc4 : c4 • qExpansion 1 (E₄ : ℍ → ℂ) = qExpansion 1 (f : ℍ → ℂ) ^ 2 := by rw [pow_two, ← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f, - ← ModularFormClass.qExpansion_smul one_pos one_mem_strictPeriods_SL c4 E₄, + ← ModularForm.qExpansion_smul one_pos one_mem_strictPeriods_SL c4 E₄, show (c4 • E₄ : ℍ → ℂ) = (f.mul f) from congrArg DFunLike.coe hc4] have hqc6 : c6 • qExpansion 1 E₆ = qExpansion 1 (f : ℍ → ℂ) ^ 3 := by rw [pow_succ, pow_two, ← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL f f, ← ModularForm.qExpansion_mul one_pos one_mem_strictPeriods_SL (f.mul f) f, - ← ModularFormClass.qExpansion_smul one_pos one_mem_strictPeriods_SL c6 E₆, + ← ModularForm.qExpansion_smul one_pos one_mem_strictPeriods_SL c6 E₆, show (c6 • E₆ : ℍ → ℂ) = (f.mul f).mul f from congrArg DFunLike.coe hc6] exact eq_zero_of_pow_eq_smul (E_qExpansion_coeff_zero _ ⟨2, rfl⟩) (E_qExpansion_coeff_zero _ ⟨3, rfl⟩) E₄_qExpansion_coeff_one E₆_qExpansion_coeff_one hqc4 hqc6 diff --git a/Mathlib/NumberTheory/ModularForms/LevelOne/GradedRing.lean b/Mathlib/NumberTheory/ModularForms/LevelOne/GradedRing.lean new file mode 100644 index 0000000000..6fba210898 --- /dev/null +++ b/Mathlib/NumberTheory/ModularForms/LevelOne/GradedRing.lean @@ -0,0 +1,92 @@ +/- +Copyright (c) 2026 Chris Birkbeck. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Birkbeck +-/ +module + +public import Mathlib.NumberTheory.ModularForms.LevelOne.DimensionFormula + +/-! +# The graded ring of level-1 modular forms + +This file collects structural results about the graded ring `⨁ k, ModularForm 𝒮ℒ k` of +level-1 modular forms, beyond those that fall out of the dimension formula directly. + +## Main results + +* `ModularForm.discriminant_eq_E₄_cube_sub_E₆_sq`: the pointwise identity + `Δ = (E₄³ - E₆²) / 1728`. +* `ModularForm.discriminant_eq_E₄_cube_sub_E₆_sq_graded`: the same identity in the graded + ring `⨁ k, ModularForm 𝒮ℒ k`. +-/ + +public noncomputable section + +open UpperHalfPlane ModularForm ModularFormClass MatrixGroups EisensteinSeries + +namespace ModularForm + +/-- The combination `E₄³ - E₆²` viewed as a level-1 modular form of weight 12. -/ +private noncomputable def E₄CubeSubE₆SqForm : ModularForm 𝒮ℒ 12 := + ModularForm.mcast (by decide) (E₄.pow 3) - ModularForm.mcast (by decide) (E₆.pow 2) + +private lemma E₄CubeSubE₆SqForm_apply (z : ℍ) : + E₄CubeSubE₆SqForm z = E₄ z ^ 3 - E₆ z ^ 2 := by + simp only [E₄CubeSubE₆SqForm, coe_mcast, coe_pow, sub_apply, Pi.pow_apply] + +private lemma E₄CubeSubE₆SqForm_qExpansion_eq : + qExpansion 1 E₄CubeSubE₆SqForm = qExpansion 1 E₄ * qExpansion 1 E₄ * qExpansion 1 E₄ - + qExpansion 1 E₆ * qExpansion 1 E₆ := by + simp only [E₄CubeSubE₆SqForm, coe_sub, coe_mcast, + ModularForm.qExpansion_sub one_pos one_mem_strictPeriods_SL, + ModularForm.qExpansion_pow one_pos one_mem_strictPeriods_SL] + ring + +private lemma E₄CubeSubE₆SqForm_isCuspForm : IsCuspForm E₄CubeSubE₆SqForm := by + simp [isCuspForm_iff_coeffZero_eq_zero, E₄CubeSubE₆SqForm_qExpansion_eq, + PowerSeries.coeff_mul, -PowerSeries.coeff_zero_eq_constantCoeff, + E_qExpansion_coeff_zero _ ⟨2, rfl⟩, E_qExpansion_coeff_zero _ ⟨3, rfl⟩] + +private lemma E₄CubeSubE₆SqForm_qExpansion_coeff_one : + (qExpansion 1 E₄CubeSubE₆SqForm).coeff 1 = 1728 := by + rw [E₄CubeSubE₆SqForm_qExpansion_eq] + norm_num [PowerSeries.coeff_mul, Finset.Nat.antidiagonal_succ, E₄_qExpansion_coeff_one, + E₆_qExpansion_coeff_one, E_qExpansion_coeff_zero _ ⟨2, rfl⟩, + E_qExpansion_coeff_zero _ ⟨3, rfl⟩] + +/-- The modular discriminant equals `(E₄³ - E₆²) / 1728`. -/ +theorem discriminant_eq_E₄_cube_sub_E₆_sq (z : ℍ) : + discriminant z = (E₄ z ^ 3 - E₆ z ^ 2) / 1728 := by + obtain ⟨g, hg⟩ := E₄CubeSubE₆SqForm_isCuspForm + obtain ⟨c, hc⟩ := CuspForm.exists_smul_discriminant_of_weight_eq_twelve g + have hgE : (g : ℍ → ℂ) = E₄CubeSubE₆SqForm := congrArg DFunLike.coe hg + have hc_eq : c = 1728 := by + have hcΔ : (c • CuspForm.discriminant : ℍ → ℂ) = g := congrArg DFunLike.coe hc + have hgΔ := ModularForm.qExpansion_smul one_pos one_mem_strictPeriods_SL c + CuspForm.discriminant + rw [hcΔ, hgE] at hgΔ + simpa [PowerSeries.coeff_smul, discriminant_qExpansion_coeff_one, + E₄CubeSubE₆SqForm_qExpansion_coeff_one] using (congr_arg (·.coeff 1) hgΔ).symm + have h1728 : (1728 : ℂ) * discriminant z = E₄ z ^ 3 - E₆ z ^ 2 := by + rw [← hc_eq, show c * discriminant z = (c • CuspForm.discriminant) z from rfl, hc, + congr_fun hgE z, E₄CubeSubE₆SqForm_apply] + linear_combination h1728 / 1728 + +/-- The modular discriminant equals `(E₄³ - E₆²) / 1728` in the graded ring +`⨁ k, ModularForm 𝒮ℒ k`. -/ +theorem discriminant_eq_E₄_cube_sub_E₆_sq_graded : + DirectSum.of (ModularForm 𝒮ℒ) 12 CuspForm.discriminant = + (1 / 1728 : ℂ) • (.of (ModularForm 𝒮ℒ) 4 E₄ ^ 3 - .of (ModularForm 𝒮ℒ) 6 E₆ ^ 2) := by + simp only [ModularForm.directSum_of_pow] + change DirectSum.of (ModularForm 𝒮ℒ) 12 CuspForm.discriminant = (1 / 1728 : ℂ) • + (DirectSum.of (ModularForm 𝒮ℒ) 12 (E₄.pow 3) - DirectSum.of (ModularForm 𝒮ℒ) 12 (E₆.pow 2)) + rw [← map_sub (DirectSum.of (ModularForm 𝒮ℒ) 12), ← DirectSum.of_smul] + congr 1 + ext z + change ModularForm.discriminant z = (1 / 1728 : ℂ) * (E₄ z ^ 3 - E₆ z ^ 2) + grind [discriminant_eq_E₄_cube_sub_E₆_sq z] + +end ModularForm + +end diff --git a/Mathlib/NumberTheory/ModularForms/NormTrace.lean b/Mathlib/NumberTheory/ModularForms/NormTrace.lean index 33837fc1a7..b1e0731fd3 100644 --- a/Mathlib/NumberTheory/ModularForms/NormTrace.lean +++ b/Mathlib/NumberTheory/ModularForms/NormTrace.lean @@ -5,7 +5,7 @@ Authors: David Loeffler -/ module -public import Mathlib.NumberTheory.ModularForms.LevelOne +public import Mathlib.NumberTheory.ModularForms.LevelOne.Basic /-! # Norm and trace maps diff --git a/Mathlib/NumberTheory/ModularForms/QExpansion.lean b/Mathlib/NumberTheory/ModularForms/QExpansion.lean index 87d52a7155..cd17cb79e0 100644 --- a/Mathlib/NumberTheory/ModularForms/QExpansion.lean +++ b/Mathlib/NumberTheory/ModularForms/QExpansion.lean @@ -520,7 +520,7 @@ lemma qExpansion_one (h) : qExpansion h (1 : ℍ → ℂ) = 1 := by end UpperHalfPlane -namespace ModularFormClass +namespace ModularForm protected lemma cuspFunction_smul (hh : 0 < h) (hΓ : h ∈ Γ.strictPeriods) (a : ℂ) (f : F) [ModularFormClass F Γ k] : cuspFunction h (a • f) = a • cuspFunction h f := @@ -542,6 +542,12 @@ protected lemma cuspFunction_sub {G : Type*} [FunLike G ℍ ℂ] (hh : 0 < h) cuspFunction_sub (ModularFormClass.analyticAt_cuspFunction_zero f hh hΓ).continuousAt (ModularFormClass.analyticAt_cuspFunction_zero g hh hΓ).continuousAt +protected lemma cuspFunction_mul [Γ.HasDetPlusMinusOne] (hh : 0 < h) + (hΓ : h ∈ Γ.strictPeriods) {a b : ℤ} (f : ModularForm Γ a) (g : ModularForm Γ b) : + cuspFunction h (f.mul g) = cuspFunction h f * cuspFunction h g := + cuspFunction_mul (ModularFormClass.analyticAt_cuspFunction_zero f hh hΓ).continuousAt + (ModularFormClass.analyticAt_cuspFunction_zero g hh hΓ).continuousAt + protected lemma qExpansion_smul (hh : 0 < h) (hΓ : h ∈ Γ.strictPeriods) (a : ℂ) (f : F) [ModularFormClass F Γ k] : qExpansion h (a • f) = a • qExpansion h f := qExpansion_smul (ModularFormClass.analyticAt_cuspFunction_zero f hh hΓ) a @@ -562,16 +568,6 @@ protected lemma qExpansion_sub {G : Type*} [FunLike G ℍ ℂ] (hh : 0 < h) qExpansion_sub (ModularFormClass.analyticAt_cuspFunction_zero f hh hΓ) (ModularFormClass.analyticAt_cuspFunction_zero g hh hΓ) -end ModularFormClass - -namespace ModularForm - -protected lemma cuspFunction_mul [Γ.HasDetPlusMinusOne] (hh : 0 < h) - (hΓ : h ∈ Γ.strictPeriods) {a b : ℤ} (f : ModularForm Γ a) (g : ModularForm Γ b) : - cuspFunction h (f.mul g) = cuspFunction h f * cuspFunction h g := - cuspFunction_mul (ModularFormClass.analyticAt_cuspFunction_zero f hh hΓ).continuousAt - (ModularFormClass.analyticAt_cuspFunction_zero g hh hΓ).continuousAt - protected lemma qExpansion_mul [Γ.HasDetPlusMinusOne] (hh : 0 < h) (hΓ : h ∈ Γ.strictPeriods) {a b : ℤ} (f : ModularForm Γ a) (g : ModularForm Γ b) : qExpansion h (f.mul g) = qExpansion h f * qExpansion h g := @@ -587,12 +583,21 @@ protected lemma qExpansion_one [Γ.HasDetPlusMinusOne] : qExpansion h (1 : ModularForm Γ 0) = 1 := by simp [qExpansion_one] +protected lemma qExpansion_pow [Γ.HasDetPlusMinusOne] (hh : 0 < h) + (hΓ : h ∈ Γ.strictPeriods) (f : ModularForm Γ k) (n : ℕ) : + qExpansion h (f.pow n) = (qExpansion h f) ^ n := by + induction n with + | zero => simp only [coe_pow, pow_zero, qExpansion_one] + | succ n ih => + rw [coe_pow, pow_succ, ← coe_pow, ← coe_mul, ModularForm.qExpansion_mul hh hΓ, ih, + pow_succ] + /-- The qExpansion map as an additive group hom. to power series over `ℂ`. -/ def qExpansionAddHom (hh : 0 < h) (hΓ : h ∈ Γ.strictPeriods) (k : ℤ) : ModularForm Γ k →+ PowerSeries ℂ where toFun f := qExpansion h f map_zero' := qExpansion_zero h - map_add' f g := ModularFormClass.qExpansion_add hh hΓ f g + map_add' f g := ModularForm.qExpansion_add hh hΓ f g open scoped DirectSum in /-- The qExpansion map as a map from the graded ring of modular forms to power series over `ℂ`. -/ @@ -621,6 +626,34 @@ lemma qExpansion_of_pow [Γ.HasDetPlusMinusOne] (hh : 0 < h) end ModularForm +namespace ModularFormClass + +@[deprecated (since := "2026-05-05")] +protected alias cuspFunction_smul := ModularForm.cuspFunction_smul + +@[deprecated (since := "2026-05-05")] +protected alias cuspFunction_neg := ModularForm.cuspFunction_neg + +@[deprecated (since := "2026-05-05")] +protected alias cuspFunction_add := ModularForm.cuspFunction_add + +@[deprecated (since := "2026-05-05")] +protected alias cuspFunction_sub := ModularForm.cuspFunction_sub + +@[deprecated (since := "2026-05-05")] +protected alias qExpansion_smul := ModularForm.qExpansion_smul + +@[deprecated (since := "2026-05-05")] +protected alias qExpansion_neg := ModularForm.qExpansion_neg + +@[deprecated (since := "2026-05-05")] +protected alias qExpansion_add := ModularForm.qExpansion_add + +@[deprecated (since := "2026-05-05")] +protected alias qExpansion_sub := ModularForm.qExpansion_sub + +end ModularFormClass + end ring section uniqueness diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean b/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean index 34aedc3509..fecde492ec 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean @@ -471,6 +471,14 @@ theorem csInf_eq_csInf_of_forall_exists_le {s t : Set α} sInf s = sInf t := csSup_eq_csSup_of_forall_exists_le (α := αᵒᵈ) hs ht +theorem csSup_union_le (s t : Set α) : sSup (s ∪ t) ≤ sSup s ⊔ sSup t := by + rcases s.eq_empty_or_nonempty with (rfl | hs) + · simp + rcases t.eq_empty_or_nonempty with (rfl | ht) + · simp + by_cases BddAbove (s ∪ t) <;> + grind [csSup_union, bddAbove_union, csSup_of_not_bddAbove] + lemma sSup_iUnion_Iic (f : ι → α) : sSup (⋃ (i : ι), Iic (f i)) = ⨆ i, f i := by apply csSup_eq_csSup_of_forall_exists_le · rintro x ⟨-, ⟨i, rfl⟩, hi⟩ @@ -588,6 +596,21 @@ theorem csSup_le_csSup' {s t : Set α} (h₁ : BddAbove t) (h₂ : s ⊆ t) : sS exact bot_le · exact csSup_le_csSup h₁ h h₂ +variable {t : Set α} + +theorem csSup_union' (hs : BddAbove s := by bddDefault) (ht : BddAbove t := by bddDefault) : + sSup (s ∪ t) = sSup s ⊔ sSup t := by + rcases s.eq_empty_or_nonempty with (rfl | hne) + · simp + exact (isLUB_csSup' hs |>.union <| isLUB_csSup' ht).csSup_eq hne.inl + +theorem csSup_inter_le' (hs : BddAbove s := by bddDefault) (ht : BddAbove t := by bddDefault) : + sSup (s ∩ t) ≤ sSup s ⊓ sSup t := + csSup_le' fun _ hx ↦ le_inf (le_csSup hs hx.left) (le_csSup ht hx.right) + +theorem csSup_insert' (hs : BddAbove s := by bddDefault) : sSup (insert a s) = a ⊔ sSup s := + isLUB_csSup' hs |>.insert a |>.csSup_eq <| insert_nonempty a s + end ConditionallyCompleteLinearOrderBot namespace WithTop diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Indexed.lean b/Mathlib/Order/ConditionallyCompleteLattice/Indexed.lean index 317cf77e48..53552821c5 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Indexed.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Indexed.lean @@ -188,6 +188,14 @@ theorem ciInf_le {f : ι → α} (H : BddBelow (range f)) (c : ι) : iInf f ≤ theorem ciInf_le_of_le {f : ι → α} (H : BddBelow (range f)) (c : ι) (h : f c ≤ a) : iInf f ≤ a := le_ciSup_of_le (α := αᵒᵈ) H c h +theorem ciSup_mono_of_forall_exists {ι'} [Nonempty ι] {f : ι → α} {g : ι' → α} + (hg : BddAbove <| range g) (h : ∀ i, ∃ i', f i ≤ g i') : ⨆ i, f i ≤ ⨆ i', g i' := + ciSup_le fun i ↦ h i |>.elim <| le_ciSup_of_le hg + +theorem ciInf_mono_of_forall_exists {ι'} [Nonempty ι'] {f : ι → α} {g : ι' → α} + (hf : BddBelow <| range f) (h : ∀ i', ∃ i, f i ≤ g i') : ⨅ i, f i ≤ ⨅ i', g i' := + ciSup_mono_of_forall_exists (α := αᵒᵈ) hf h + /-- If the set of all `f i j` is bounded below, then so is the set of the infimums of every row -/ theorem BddBelow.range_iInf_of_iUnion_range {κ : ι → Sort*} {f : ∀ i, κ i → α} (H : BddBelow <| ⋃ i, range (f i)) : BddBelow <| range fun i ↦ ⨅ j, f i j := by @@ -360,6 +368,26 @@ lemma ciInf_image {ι ι' : Type*} {s : Set ι} {f : ι → ι'} {g : ι' → α ⨅ i ∈ (f '' s), g i = ⨅ x ∈ s, g (f x) := ciSup_image (α := αᵒᵈ) hf hg' +/-- Note that equality need not hold: consider `ι := Bool, p := (·), α := ℤ, f := fun _ ↦ -1`, +then the LHS is `-1` but the RHS is `-1 ⊔ sSup ∅ = -1 ⊔ 0 = 0`. -/ +theorem ciSup_exists_le {p : ι → Prop} {f : Exists p → α} : ⨆ ih, f ih ≤ ⨆ (i) (h), f ⟨i, h⟩ := by + by_cases! h : Exists p + · have : Nonempty <| Exists p := ⟨h⟩ + refine ciSup_le fun ⟨i, hi⟩ ↦ le_ciSup₂ (f := fun _ _ ↦ _) ⟨f ⟨i, hi⟩, ?_⟩ i hi + rintro _ ⟨_, ⟨j, rfl⟩, ⟨hj, rfl⟩⟩ + rfl + · cases isEmpty_or_nonempty ι <;> + simp [h, iSup_of_empty', ciSup_const] + +theorem le_ciInf_exists {p : ι → Prop} {f : Exists p → α} : ⨅ (i) (h), f ⟨i, h⟩ ≤ ⨅ ih, f ih := + ciSup_exists_le (α := αᵒᵈ) + +theorem ciSup_and {p q : Prop} {f : p ∧ q → α} : ⨆ ih, f ih = ⨆ (h₁) (h₂), f ⟨h₁, h₂⟩ := by + by_cases hp : p <;> by_cases hq : q <;> simp [hp, hq, iSup_of_empty'] + +theorem ciInf_and {p q : Prop} {f : p ∧ q → α} : ⨅ ih, f ih = ⨅ (h₁) (h₂), f ⟨h₁, h₂⟩ := + ciSup_and (α := αᵒᵈ) + end ConditionallyCompleteLattice section ConditionallyCompleteLinearOrder @@ -491,9 +519,15 @@ theorem exists_lt_of_lt_ciSup' {f : ι → α} {a : α} (h : a < ⨆ i, f i) : contrapose! h exact ciSup_le' h -theorem ciSup_mono' {ι'} {f : ι → α} {g : ι' → α} (hg : BddAbove (range g)) - (h : ∀ i, ∃ i', f i ≤ g i') : iSup f ≤ iSup g := - ciSup_le' fun i => Exists.elim (h i) (le_ciSup_of_le hg) +theorem ciSup_mono_of_forall_exists' {ι'} {f : ι → α} {g : ι' → α} (hg : BddAbove <| range g) + (h : ∀ i, ∃ i', f i ≤ g i') : ⨆ i, f i ≤ ⨆ i', g i' := + ciSup_le' fun i ↦ h i |>.elim <| le_ciSup_of_le hg + +@[deprecated (since := "2026-05-03")] alias ciSup_mono' := ciSup_mono_of_forall_exists' + +theorem ciSup_exists {p : ι → Prop} {f : Exists p → α} : ⨆ ih, f ih = ⨆ (i) (h), f ⟨i, h⟩ := by + refine le_antisymm ciSup_exists_le <| ciSup_le' fun i ↦ ciSup_le' fun hi ↦ ?_ + simp [show Exists p from ⟨i, hi⟩] lemma ciSup_or' (p q : Prop) (f : p ∨ q → α) : ⨆ (h : p ∨ q), f h = (⨆ h : p, f (.inl h)) ⊔ ⨆ h : q, f (.inr h) := by diff --git a/Mathlib/Order/Defs/Unbundled.lean b/Mathlib/Order/Defs/Unbundled.lean index ae6748e0e4..b45f12284f 100644 --- a/Mathlib/Order/Defs/Unbundled.lean +++ b/Mathlib/Order/Defs/Unbundled.lean @@ -97,6 +97,16 @@ that is, `Std.Trichotomous lt` and `IsStrictOrder X lt`. -/ class IsStrictTotalOrder (α : Sort*) (lt : α → α → Prop) : Prop extends Std.Trichotomous lt, IsStrictOrder α lt +theorem Equivalence.of_isEquiv {α : Sort*} (lt : α → α → Prop) [IsEquiv α lt] : Equivalence lt where + refl := Std.Refl.refl; symm := Std.Symm.symm _ _; trans := IsTrans.trans _ _ _ + +theorem IsEquiv.of_equivalence {α : Sort*} {lt : α → α → Prop} (h : Equivalence lt) : + IsEquiv α lt where + refl := h.refl; symm _ _ := h.symm; trans _ _ _ := h.trans + +theorem equivalence_iff_isEquiv {α : Sort*} (lt : α → α → Prop) : Equivalence lt ↔ IsEquiv α lt := + ⟨.of_equivalence, fun _ => .of_isEquiv lt⟩ + /-- Equality is an equivalence relation. -/ instance eq_isEquiv (α : Sort*) : IsEquiv α (· = ·) where symm := @Eq.symm _ diff --git a/Mathlib/Order/DirSupClosed.lean b/Mathlib/Order/DirSupClosed.lean index 56faba3e38..e1cb895c7c 100644 --- a/Mathlib/Order/DirSupClosed.lean +++ b/Mathlib/Order/DirSupClosed.lean @@ -167,6 +167,87 @@ lemma DirSupInaccOn.union (hs : DirSupInaccOn D s) (ht : DirSupInaccOn D t) : lemma DirSupInacc.union (hs : DirSupInacc s) (ht : DirSupInacc t) : DirSupInacc (s ∪ t) := by simpa using hs.dirSupInaccOn.union ht.dirSupInaccOn (D := .univ) +theorem DirSupClosedOn.union (hDL : IsLowerSet D) + (hs : DirSupClosedOn D s) (ht : DirSupClosedOn D t) : DirSupClosedOn D (s ∪ t) := by + intro d hD hdu hd₀ hd₁ a ha + have hdst : d ∩ s ∪ d ∩ t = d := by grind + rw [← hdst] at hd₀ hd₁ + wlog h : DirectedOn (· ≤ ·) (d ∩ s) ∧ (d ∩ s).Nonempty + · rw [union_comm] at hdu hd₀ hd₁ hdst ⊢ + exact this hDL ht hs hD hdu hd₀ hd₁ ha hdst <| + (directedOn_or_directedOn_of_union' hd₀ hd₁).resolve_right h + obtain ⟨hds, hn⟩ := h + by_cases had : a ∈ lowerBounds (upperBounds (d ∩ s)) + · exact .inl <| hs (hDL inter_subset_left hD) inter_subset_right hn hds + ⟨fun b hb ↦ ha.1 hb.1, had⟩ + · simp only [lowerBounds, mem_setOf_eq, not_forall] at had + obtain ⟨b, hb, hb'⟩ := had + have key : {x ∈ d | ¬ x ≤ b} ⊆ d ∩ t := fun a ⟨had, hab⟩ ↦ + ⟨had, (hdu had).resolve_left fun has ↦ hab <| hb ⟨had, has⟩⟩ + obtain ⟨w, hw⟩ : {x ∈ d | ¬ x ≤ b}.Nonempty := by + contrapose! hb' + apply ha.2 + aesop + refine Or.inr <| ht (hDL inter_subset_left hD) (key.trans inter_subset_right) + ⟨w, hw⟩ (fun x hx y hy ↦ ?_) ?_ + · obtain ⟨z, hz, hz'⟩ := hd₁ _ (.inr (key hx)) _ (.inr (key hy)) + exact ⟨z, ⟨⟨hdst ▸ hz, mt hz'.1.trans hx.2⟩, hz'⟩⟩ + · refine ⟨fun x hx ↦ ha.1 hx.1, fun x hx ↦ ha.2 fun y hy ↦ ?_⟩ + by_cases hyb : y ≤ b + · obtain ⟨z, hz, hxz, hyz⟩ := hd₁ _ (hdst ▸ hy) _ (.inr (key hw)) + exact hxz.trans (hx ⟨hdst ▸ hz, fun hzb ↦ hw.2 (hyz.trans hzb)⟩) + exact hx ⟨hy, hyb⟩ + +theorem DirSupInaccOn.inter (hDL : IsLowerSet D) + (hs : DirSupInaccOn D s) (ht : DirSupInaccOn D t) : DirSupInaccOn D (s ∩ t) := by + rw [← dirSupClosedOn_compl, compl_inter]; exact hs.compl.union hDL ht.compl + +theorem DirSupClosed.union (hs : DirSupClosed s) (ht : DirSupClosed t) : DirSupClosed (s ∪ t) := by + simpa using hs.dirSupClosedOn.union isLowerSet_univ ht.dirSupClosedOn + +theorem DirSupInacc.inter (hs : DirSupInacc s) (ht : DirSupInacc t) : DirSupInacc (s ∩ t) := by + simpa using hs.dirSupInaccOn.inter isLowerSet_univ ht.dirSupInaccOn + +theorem DirSupInaccOn.of_inter_subset + (h : ∀ ⦃d : Set α⦄, d ∈ D → d.Nonempty → DirectedOn (· ≤ ·) d → + ∀ ⦃a : α⦄, IsLUB d a → a ∈ s → ∃ b ∈ d, Ici b ∩ d ⊆ s) : DirSupInaccOn D s := by + intro d hd₀ hd₁ hd₂ a hda hd₃ + obtain ⟨b, hbd, hb⟩ := h hd₀ hd₁ hd₂ hda hd₃ + exact ⟨b, hbd, hb ⟨le_rfl, hbd⟩⟩ + +theorem DirSupInacc.of_inter_subset + (h : ∀ ⦃d : Set α⦄, d.Nonempty → DirectedOn (· ≤ ·) d → + ∀ ⦃a : α⦄, IsLUB d a → a ∈ s → ∃ b ∈ d, Ici b ∩ d ⊆ s) : DirSupInacc s := + dirSupInaccOn_univ.1 (.of_inter_subset (by simpa)) + +/-- The condition `(d ∩ s).Nonempty` in `DirSupInaccOn` can be replaced with the stronger +`∃ b ∈ d, Ici b ∩ d ⊆ s` (under mild assumptions on `D`). -/ +theorem dirSupInaccOn_iff_inter_subset (hDL : IsLowerSet D) : + DirSupInaccOn D s ↔ ∀ ⦃d : Set α⦄, d ∈ D → d.Nonempty → DirectedOn (· ≤ ·) d → + ∀ ⦃a : α⦄, IsLUB d a → a ∈ s → ∃ b ∈ d, Ici b ∩ d ⊆ s where + mpr := .of_inter_subset + mp h t hD ht₀ ht₁ a ha has := by + by_contra! H + have H : ∀ b : t, ∃ c, b.1 ≤ c ∧ c ∈ t ∧ c ∉ s := by simpa [not_subset, and_assoc] using H + choose f hf using H + have := ht₀.to_subtype + have hft : range f ⊆ t := by grind + apply (h (hDL hft hD) (range_nonempty f) _ _ has).ne_empty + · aesop + · intro a ha b hb + obtain ⟨c, hc, _, _⟩ := ht₁ _ (hft ha) _ (hft hb) + have := hf ⟨c, hc⟩ + grind + · exact ⟨upperBounds_mono_set hft ha.1, + fun b hb ↦ ha.2 fun c hc ↦ (hf ⟨c, hc⟩).1.trans (hb <| by simp)⟩ + +/-- The condition `(d ∩ s).Nonempty` in `DirSupInacc` can be replaced with the stronger +`∃ b ∈ d, Ici b ∩ d ⊆ s`. -/ +theorem dirSupInacc_iff_inter_subset : + DirSupInacc s ↔ ∀ ⦃d : Set α⦄, d.Nonempty → DirectedOn (· ≤ ·) d → + ∀ ⦃a : α⦄, IsLUB d a → a ∈ s → ∃ b ∈ d, Ici b ∩ d ⊆ s := by + simpa using dirSupInaccOn_iff_inter_subset isLowerSet_univ + lemma IsUpperSet.dirSupClosed (hs : IsUpperSet s) : DirSupClosed s := fun _d hds ⟨_b, hb⟩ _ _a ha ↦ hs (ha.1 hb) <| hds hb @@ -221,7 +302,7 @@ theorem dirSupClosedOn_singleton (a : α) : DirSupClosedOn D {a} := end PartialOrder -namespace LinearOrder +section LinearOrder variable [LinearOrder α] theorem dirSupClosedOn_iff_of_linearOrder : diff --git a/Mathlib/Order/Filter/Cocardinal.lean b/Mathlib/Order/Filter/Cocardinal.lean index abb0f750c1..c783b9c7c5 100644 --- a/Mathlib/Order/Filter/Cocardinal.lean +++ b/Mathlib/Order/Filter/Cocardinal.lean @@ -9,7 +9,7 @@ public import Mathlib.Order.Filter.Cofinite public import Mathlib.Order.Filter.CountableInter public import Mathlib.Order.Filter.CardinalInter public import Mathlib.SetTheory.Cardinal.Arithmetic -public import Mathlib.SetTheory.Cardinal.Cofinality +public import Mathlib.SetTheory.Cardinal.Cofinality.Ordinal /-! # The cocardinal filter diff --git a/Mathlib/Order/Filter/TendstoCofinite.lean b/Mathlib/Order/Filter/TendstoCofinite.lean index 9027389dfc..b056263b12 100644 --- a/Mathlib/Order/Filter/TendstoCofinite.lean +++ b/Mathlib/Order/Filter/TendstoCofinite.lean @@ -117,7 +117,7 @@ theorem Finsupp.mapDomain_tendstoCofinite [TendstoCofinite f] : simp only [Set.subset_def, Set.mem_preimage, Set.mem_singleton_iff, Set.mem_image, Set.mem_setOf_eq] refine fun y hy ↦ ⟨y.comapDomain e e.injective.injOn, ?_, embDomain_comapDomain ?_⟩ - · rw [← hy, degree_mapDomain_eq_of_subsingletonAddUnits] + · rw [← hy, degree_mapDomain] exact degree_comapDomain_le_of_canonicallyOrderedAdd .. · suffices y.support ⊆ s by simpa [e] simpa [← hy, mapDomain, sum, Finset.subset_iff, single_apply, s] using diff --git a/Mathlib/Order/GaloisConnection/Basic.lean b/Mathlib/Order/GaloisConnection/Basic.lean index 58add68efc..d02d327044 100644 --- a/Mathlib/Order/GaloisConnection/Basic.lean +++ b/Mathlib/Order/GaloisConnection/Basic.lean @@ -57,6 +57,8 @@ variable [Preorder α] [Preorder β] {l : α → β} {u : β → α} variable (gc : GaloisConnection l u) include gc +to_dual_name_hint U L + @[to_dual] theorem upperBounds_l_image (s : Set α) : upperBounds (l '' s) = u ⁻¹' upperBounds s := diff --git a/Mathlib/Order/GaloisConnection/Defs.lean b/Mathlib/Order/GaloisConnection/Defs.lean index 66ff7d7d02..41dc65626f 100644 --- a/Mathlib/Order/GaloisConnection/Defs.lean +++ b/Mathlib/Order/GaloisConnection/Defs.lean @@ -44,6 +44,8 @@ def GaloisConnection [Preorder α] [Preorder β] (l : α → β) (u : β → α) to_dual_insert_cast GaloisConnection := by rw [forall_comm]; simp only [Iff.comm] +to_dual_name_hint U L + namespace GaloisConnection section diff --git a/Mathlib/Order/Interval/Set/Basic.lean b/Mathlib/Order/Interval/Set/Basic.lean index 4e55aaea10..98c6874023 100644 --- a/Mathlib/Order/Interval/Set/Basic.lean +++ b/Mathlib/Order/Interval/Set/Basic.lean @@ -285,7 +285,9 @@ theorem Iio_ssubset_Iic_self : Iio a ⊂ Iic a := theorem Ioo_subset_Ioo (ha : a₂ ≤ a₁) (hb : b₁ ≤ b₂) : Ioo a₁ b₁ ⊆ Ioo a₂ b₂ := fun _ ⟨hx₁, hx₂⟩ => ⟨ha.trans_lt hx₁, hx₂.trans_le hb⟩ -@[to_dual Ioo_subset_Ioo_right] +to_dual_name_hint Left Right + +@[to_dual] theorem Ioo_subset_Ioo_left (h : a₁ ≤ a₂) : Ioo a₂ b ⊆ Ioo a₁ b := Ioo_subset_Ioo h le_rfl @@ -293,11 +295,11 @@ theorem Ioo_subset_Ioo_left (h : a₁ ≤ a₂) : Ioo a₂ b ⊆ Ioo a₁ b := theorem Ico_subset_Ico (ha : a₂ ≤ a₁) (hb : b₁ ≤ b₂) : Ico a₁ b₁ ⊆ Ico a₂ b₂ := fun _ hx => ⟨ha.trans hx.1, hx.2.trans_le hb⟩ -@[to_dual Ioc_subset_Ioc_right] +@[to_dual] theorem Ico_subset_Ico_left (h : a₁ ≤ a₂) : Ico a₂ b ⊆ Ico a₁ b := Ico_subset_Ico h le_rfl -@[to_dual Ico_subset_Ico_right] +@[to_dual] theorem Ioc_subset_Ioc_left (h : a₁ ≤ a₂) : Ioc a₂ b ⊆ Ioc a₁ b := Ioc_subset_Ioc h le_rfl @@ -305,11 +307,11 @@ theorem Ioc_subset_Ioc_left (h : a₁ ≤ a₂) : Ioc a₂ b ⊆ Ioc a₁ b := theorem Icc_subset_Icc (ha : a₂ ≤ a₁) (hb : b₁ ≤ b₂) : Icc a₁ b₁ ⊆ Icc a₂ b₂ := fun _ ⟨hx₁, hx₂⟩ => ⟨ha.trans hx₁, le_trans hx₂ hb⟩ -@[to_dual Icc_subset_Icc_right] +@[to_dual] theorem Icc_subset_Icc_left (h : a₁ ≤ a₂) : Icc a₂ b ⊆ Icc a₁ b := Icc_subset_Icc h le_rfl -@[to_dual (reorder := ha hb) Icc_ssubset_Icc_right] +@[to_dual (reorder := ha hb)] theorem Icc_ssubset_Icc_left (h₂ : a₂ ≤ b₂) (ha : a₂ < a₁) (hb : b₁ ≤ b₂) : Icc a₁ b₁ ⊂ Icc a₂ b₂ := (ssubset_iff_of_subset (Icc_subset_Icc (le_of_lt ha) hb)).mpr ⟨a₂, left_mem_Icc.mpr h₂, not_and.mpr fun f _ => lt_irrefl a₂ (ha.trans_le f)⟩ @@ -318,7 +320,7 @@ theorem Icc_ssubset_Icc_left (h₂ : a₂ ≤ b₂) (ha : a₂ < a₁) (hb : b theorem Ico_subset_Ioo (ha : a₂ < a₁) (hb : b₁ ≤ b₂) : Ico a₁ b₁ ⊆ Ioo a₂ b₂ := fun _ hx ↦ ⟨ha.trans_le hx.1, hx.2.trans_le hb⟩ -@[to_dual Ioc_subset_Ioo_right] +@[to_dual] theorem Ico_subset_Ioo_left (h : a₁ < a₂) : Ico a₂ b ⊆ Ioo a₁ b := Ico_subset_Ioo h le_rfl @@ -326,7 +328,7 @@ theorem Ico_subset_Ioo_left (h : a₁ < a₂) : Ico a₂ b ⊆ Ioo a₁ b := theorem Icc_subset_Ioc (ha : a₂ < a₁) (hb : b₁ ≤ b₂) : Icc a₁ b₁ ⊆ Ioc a₂ b₂ := fun _ hx ↦ ⟨ha.trans_le hx.1, hx.2.trans hb⟩ -@[to_dual Icc_subset_Ico_right] +@[to_dual] theorem Icc_subset_Ioc_left (h : a₁ < a₂) : Icc a₂ b ⊆ Ioc a₁ b := Icc_subset_Ioc h le_rfl @@ -494,11 +496,11 @@ lemma subsingleton_Icc_iff {α : Type*} [LinearOrder α] {a b : α} : contrapose! h exact ⟨a, ⟨le_refl _, h.le⟩, b, ⟨h.le, le_refl _⟩, h.ne⟩ -@[to_dual (attr := simp) Icc_diff_right] +@[to_dual (attr := simp)] theorem Icc_diff_left : Icc a b \ {a} = Ioc a b := ext fun x => by simp [lt_iff_le_and_ne, eq_comm, and_right_comm] -@[to_dual (attr := simp) Ioc_diff_right] +@[to_dual (attr := simp)] theorem Ico_diff_left : Ico a b \ {a} = Ioo a b := ext fun x => by simp [and_right_comm, ← lt_iff_le_and_ne, eq_comm] @@ -506,7 +508,7 @@ theorem Ico_diff_left : Ico a b \ {a} = Ioo a b := theorem Icc_diff_both : Icc a b \ {a, b} = Ioo a b := by rw [insert_eq, ← diff_diff, Icc_diff_left, Ioc_diff_right] -@[to_dual (attr := simp) Ici_diff_left] +@[to_dual (attr := simp)] theorem Iic_diff_right : Iic a \ {a} = Iio a := ext fun x => by simp [lt_iff_le_and_ne] @@ -527,11 +529,11 @@ theorem Icc_diff_Ioo_same (h : a ≤ b) : Icc a b \ Ioo a b = {a, b} := by theorem Iic_diff_Iio_same : Iic a \ Iio a = {a} := by rw [← Iic_diff_right, diff_diff_cancel_left (singleton_subset_iff.2 self_mem_Iic)] -@[to_dual Ioi_union_left] +@[to_dual] theorem Iio_union_right : Iio a ∪ {a} = Iic a := ext fun _ => le_iff_lt_or_eq.symm -@[to_dual Ioo_union_right] +@[to_dual] theorem Ioo_union_left (hab : a < b) : Ioo a b ∪ {a} = Ico a b := by rw [← Ico_diff_left, diff_union_self, union_eq_self_of_subset_right (singleton_subset_iff.2 <| left_mem_Ico.2 hab)] @@ -543,16 +545,16 @@ theorem Ioo_union_both (h : a ≤ b) : Ioo a b ∪ {a, b} = Icc a b := by | x, .inr rfl => right_mem_Icc.mpr h rw [← this, Icc_diff_both] -@[to_dual Ico_union_right] +@[to_dual] theorem Ioc_union_left (hab : a ≤ b) : Ioc a b ∪ {a} = Icc a b := by rw [← Icc_diff_left, diff_union_self, union_eq_self_of_subset_right (singleton_subset_iff.2 <| left_mem_Icc.2 hab)] -@[to_dual (attr := simp) Ioc_insert_left] +@[to_dual (attr := simp)] theorem Ico_insert_right (h : a ≤ b) : insert b (Ico a b) = Icc a b := by rw [insert_eq, union_comm, Ico_union_right h] -@[to_dual (attr := simp) Ioo_insert_right] +@[to_dual (attr := simp)] theorem Ioo_insert_left (h : a < b) : insert a (Ioo a b) = Ico a b := by rw [insert_eq, union_comm, Ioo_union_left h] @@ -588,7 +590,7 @@ theorem mem_Icc_Ico_Ioc_Ioo_of_subset_of_subset {s : Set α} (ho : Ioo a b ⊆ s rw [← Ico_diff_left, ← Icc_diff_right] apply_rules [subset_diff_singleton] -@[to_dual eq_right_or_mem_Ioo_of_mem_Ioc] +@[to_dual] theorem eq_left_or_mem_Ioo_of_mem_Ico {x : α} (hmem : x ∈ Ico a b) : x = a ∨ x ∈ Ioo a b := hmem.1.eq_or_lt'.imp_right fun h => ⟨h, hmem.2⟩ diff --git a/Mathlib/Order/Interval/Set/Disjoint.lean b/Mathlib/Order/Interval/Set/Disjoint.lean index 04675dbb38..e8640977be 100644 --- a/Mathlib/Order/Interval/Set/Disjoint.lean +++ b/Mathlib/Order/Interval/Set/Disjoint.lean @@ -36,11 +36,14 @@ section Preorder variable [Preorder α] {a b c : α} -@[to_dual (attr := simp) Ici_disjoint_Iio] +to_dual_name_hint Disjoint Disjoint +to_dual_name_hint Left Right + +@[to_dual (attr := simp)] theorem Iic_disjoint_Ioi (h : a ≤ b) : Disjoint (Iic a) (Ioi b) := disjoint_left.mpr fun _ ha hb => (h.trans_lt hb).not_ge ha -@[to_dual (attr := simp) Ioi_disjoint_Iic] +@[to_dual (attr := simp)] theorem Iio_disjoint_Ici (h : a ≤ b) : Disjoint (Iio a) (Ici b) := disjoint_left.mpr fun _ ha hb => (h.trans_lt' ha).not_ge hb @@ -56,7 +59,7 @@ theorem Ioc_disjoint_Ioc_of_le {d : α} (h : b ≤ c) : Disjoint (Ioc a b) (Ioc theorem Ico_disjoint_Ico_same : Disjoint (Ico a b) (Ico b c) := disjoint_left.mpr fun _ hab hbc => hab.2.not_ge hbc.1 -@[to_dual (attr := simp) Iic_disjoint_Ici] +@[to_dual (attr := simp)] theorem Ici_disjoint_Iic : Disjoint (Ici a) (Iic b) ↔ ¬a ≤ b := by rw [Set.disjoint_iff_inter_eq_empty, Ici_inter_Iic, Icc_eq_empty_iff] @@ -67,19 +70,19 @@ theorem Ioc_disjoint_Ioi (h : b ≤ c) : Disjoint (Ioc a b) (Ioi c) := theorem Ioc_disjoint_Ioi_same : Disjoint (Ioc a b) (Ioi b) := Ioc_disjoint_Ioi le_rfl -@[to_dual Iio_disjoint_Ioi_of_not_lt] +@[to_dual] theorem Ioi_disjoint_Iio_of_not_lt (h : ¬a < b) : Disjoint (Ioi a) (Iio b) := disjoint_left.mpr fun _ hx hy ↦ h (hx.trans hy) -@[to_dual Iio_disjoint_Ioi_of_le] +@[to_dual] theorem Ioi_disjoint_Iio_of_le (h : a ≤ b) : Disjoint (Ioi b) (Iio a) := Ioi_disjoint_Iio_of_not_lt (not_lt_of_ge h) -@[to_dual Iio_disjoint_Ioi_same] +@[to_dual] theorem Ioi_disjoint_Iio_same : Disjoint (Ioi a) (Iio a) := Ioi_disjoint_Iio_of_le le_rfl -@[to_dual (attr := simp) Iio_disjoint_Ioi_iff] +@[to_dual (attr := simp)] theorem Ioi_disjoint_Iio_iff [DenselyOrdered α] : Disjoint (Ioi a) (Iio b) ↔ ¬a < b := ⟨fun h hab ↦ (exists_between hab).elim fun _ hc ↦ h.notMem_of_mem_left hc.left hc.right, @@ -89,11 +92,11 @@ theorem Ioi_disjoint_Iio_iff [DenselyOrdered α] : Disjoint (Ioi a) (Iio b) ↔ theorem iUnion_Iic : ⋃ a : α, Iic a = univ := iUnion_eq_univ_iff.2 fun x => ⟨x, self_mem_Iic⟩ -@[to_dual (attr := simp) iUnion_Icc_left] +@[to_dual (attr := simp)] theorem iUnion_Icc_right (a : α) : ⋃ b, Icc a b = Ici a := by simp only [← Ici_inter_Iic, ← inter_iUnion, iUnion_Iic, inter_univ] -@[to_dual (attr := simp) iUnion_Ico_left] +@[to_dual (attr := simp)] theorem iUnion_Ioc_right (a : α) : ⋃ b, Ioc a b = Ioi a := by simp only [← Ioi_inter_Iic, ← inter_iUnion, iUnion_Iic, inter_univ] @@ -101,11 +104,11 @@ theorem iUnion_Ioc_right (a : α) : ⋃ b, Ioc a b = Ioi a := by theorem iUnion_Iio [NoMaxOrder α] : ⋃ a : α, Iio a = univ := iUnion_eq_univ_iff.2 exists_gt -@[to_dual (attr := simp) iUnion_Ioc_left] +@[to_dual (attr := simp)] theorem iUnion_Ico_right [NoMaxOrder α] (a : α) : ⋃ b, Ico a b = Ici a := by simp only [← Ici_inter_Iio, ← inter_iUnion, iUnion_Iio, inter_univ] -@[to_dual (attr := simp) iUnion_Ioo_left] +@[to_dual (attr := simp)] theorem iUnion_Ioo_right [NoMaxOrder α] (a : α) : ⋃ b, Ioo a b = Ioi a := by simp only [← Ioi_inter_Iio, ← inter_iUnion, iUnion_Iio, inter_univ] diff --git a/Mathlib/Order/SuccPred/Limit.lean b/Mathlib/Order/SuccPred/Limit.lean index db9acec0c4..b39c005fbd 100644 --- a/Mathlib/Order/SuccPred/Limit.lean +++ b/Mathlib/Order/SuccPred/Limit.lean @@ -164,6 +164,13 @@ theorem IsSuccLimit.bot_lt [OrderBot α] (h : IsSuccLimit a) : ⊥ < a := theorem IsSuccLimit.ne_bot [OrderBot α] (h : IsSuccLimit a) : a ≠ ⊥ := h.bot_lt.ne' +theorem IsSuccLimit.pos [Zero α] [IsBotZeroClass α] (h : IsSuccLimit a) : 0 < a := + let := IsBotZeroClass.toOrderBot α + h.bot_lt + +theorem IsSuccLimit.ne_zero [Zero α] [IsBotZeroClass α] (h : IsSuccLimit a) : a ≠ 0 := + h.pos.ne' + @[to_dual] theorem not_isSuccLimit_iff : ¬ IsSuccLimit a ↔ IsMin a ∨ ¬ IsSuccPrelimit a := by rw [IsSuccLimit, not_and_or, not_not] diff --git a/Mathlib/Order/SuccPred/LinearLocallyFinite.lean b/Mathlib/Order/SuccPred/LinearLocallyFinite.lean index eb6e8f5d04..c4ff141f24 100644 --- a/Mathlib/Order/SuccPred/LinearLocallyFinite.lean +++ b/Mathlib/Order/SuccPred/LinearLocallyFinite.lean @@ -55,8 +55,7 @@ About `toZ`: -/ -@[expose] public section - +public section open Order @@ -292,7 +291,9 @@ theorem toZ_iterate_pred_of_not_isMin (n : ℕ) (hn : ¬IsMin (pred^[n] i0)) : · suffices IsMin (pred^[n.succ] i0) from absurd this hn exact isMin_iterate_pred_of_eq_of_ne h_eq.symm (Ne.symm hmn) -theorem le_of_toZ_le {j : ι} (h_le : toZ i0 i ≤ toZ i0 j) : i ≤ j := by +theorem toZ_strictMono : StrictMono (toZ i0) := by + intro j i h_le + contrapose! h_le rcases le_or_gt i0 i with hi | hi <;> rcases le_or_gt i0 j with hj | hj · rw [← iterate_succ_toZ i hi, ← iterate_succ_toZ j hj] exact Monotone.monotone_iterate_of_le_map succ_mono (le_succ _) (Int.toNat_le_toNat h_le) @@ -302,54 +303,29 @@ theorem le_of_toZ_le {j : ι} (h_le : toZ i0 i ≤ toZ i0 j) : i ≤ j := by refine Monotone.antitone_iterate_of_map_le pred_mono (pred_le _) (Int.toNat_le_toNat ?_) exact Int.neg_le_neg h_le -theorem toZ_mono {i j : ι} (h_le : i ≤ j) : toZ i0 i ≤ toZ i0 j := by - by_cases hi_max : IsMax i - · rw [le_antisymm h_le (hi_max h_le)] - by_cases hj_min : IsMin j - · rw [le_antisymm h_le (hj_min h_le)] - rcases le_or_gt i0 i with hi | hi <;> rcases le_or_gt i0 j with hj | hj - · let m := Nat.find (exists_succ_iterate_of_le h_le) - have hm : succ^[m] i = j := Nat.find_spec (exists_succ_iterate_of_le h_le) - have hj_eq : j = succ^[(toZ i0 i).toNat + m] i0 := by - rw [← hm, add_comm] - nth_rw 1 [← iterate_succ_toZ i hi] - rw [Function.iterate_add] - rfl - by_contra h - obtain hm0 | hm0 : m = 0 ∨ 1 ≤ m := by lia - · rw [hm0, Function.iterate_zero, id] at hm - rw [hm] at h - exact h (le_of_eq rfl) - refine hi_max (max_of_succ_le (le_trans ?_ (@le_of_toZ_le _ _ _ _ _ i0 j i ?_))) - · have h_succ_le : succ^[(toZ i0 i).toNat + 1] i0 ≤ j := by - rw [hj_eq] - exact Monotone.monotone_iterate_of_le_map succ_mono (le_succ i0) (by gcongr) - rwa [Function.iterate_succ', Function.comp_apply, iterate_succ_toZ i hi] at h_succ_le - · exact le_of_not_ge h - · exact absurd h_le (not_le.mpr (hj.trans_le hi)) - · exact (toZ_neg hi).le.trans (toZ_nonneg hj) - · let m := Nat.find (exists_pred_iterate_of_le (α := ι) h_le) - have hm : pred^[m] j = i := Nat.find_spec (exists_pred_iterate_of_le (α := ι) h_le) - have hj_eq : i = pred^[(-toZ i0 j).toNat + m] i0 := by - rw [← hm, add_comm] - nth_rw 1 [← iterate_pred_toZ j hj] - rw [Function.iterate_add] - rfl - by_contra h - obtain hm0 | hm0 : m = 0 ∨ 1 ≤ m := by lia - · rw [hm0, Function.iterate_zero, id] at hm - rw [hm] at h - exact h (le_of_eq rfl) - refine hj_min (min_of_le_pred ?_) - refine (@le_of_toZ_le _ _ _ _ _ i0 j i ?_).trans ?_ - · exact le_of_not_ge h - · have h_le_pred : i ≤ pred^[(-toZ i0 j).toNat + 1] i0 := by - rw [hj_eq] - exact Monotone.antitone_iterate_of_map_le pred_mono (pred_le i0) (by gcongr) - rwa [Function.iterate_succ', Function.comp_apply, iterate_pred_toZ j hj] at h_le_pred - -theorem toZ_le_iff (i j : ι) : toZ i0 i ≤ toZ i0 j ↔ i ≤ j := - ⟨le_of_toZ_le, toZ_mono⟩ +theorem injective_toZ : Function.Injective (toZ i0) := + toZ_strictMono.injective + +@[simp] +theorem toZ_le_toZ {i j : ι} : toZ i0 i ≤ toZ i0 j ↔ i ≤ j := + toZ_strictMono.le_iff_le + +@[deprecated (since := "2026-05-07")] +alias toZ_le_iff := toZ_le_toZ + +@[deprecated toZ_le_toZ (since := "2026-05-06")] +alias ⟨le_of_toZ_le, toZ_mono⟩ := toZ_le_toZ + +@[simp] +theorem toZ_lt_toZ {i j : ι} : toZ i0 i < toZ i0 j ↔ i < j := + toZ_strictMono.lt_iff_lt + +@[deprecated (since := "2026-05-07")] +alias toZ_lt_iff := toZ_lt_toZ + +@[simp] +theorem toZ_inj {i j : ι} : toZ i0 i = toZ i0 j ↔ i = j := + injective_toZ.eq_iff theorem toZ_iterate_succ [NoMaxOrder ι] (n : ℕ) : toZ i0 (succ^[n] i0) = n := toZ_iterate_succ_of_not_isMax n (not_isMax _) @@ -357,9 +333,6 @@ theorem toZ_iterate_succ [NoMaxOrder ι] (n : ℕ) : toZ i0 (succ^[n] i0) = n := theorem toZ_iterate_pred [NoMinOrder ι] (n : ℕ) : toZ i0 (pred^[n] i0) = -n := toZ_iterate_pred_of_not_isMin n (not_isMin _) -theorem injective_toZ : Function.Injective (toZ i0) := - fun _ _ h ↦ le_antisymm (le_of_toZ_le h.le) (le_of_toZ_le h.symm.le) - end toZ section OrderIso @@ -370,7 +343,7 @@ variable [SuccOrder ι] [PredOrder ι] [IsSuccArchimedean ι] noncomputable def orderIsoRangeToZOfLinearSuccPredArch [hι : Nonempty ι] : ι ≃o Set.range (toZ hι.some) where toEquiv := Equiv.ofInjective _ injective_toZ - map_rel_iff' := by intro i j; exact toZ_le_iff i j + map_rel_iff' := by simp instance (priority := 100) countable_of_linear_succ_pred_arch : Countable ι := by rcases isEmpty_or_nonempty ι with _ | hι @@ -398,7 +371,7 @@ noncomputable def orderIsoIntOfLinearSuccPredArch [NoMaxOrder ι] [NoMinOrder ι · simp_rw [if_neg (not_le.mpr hn)] rw [toZ_iterate_pred] simp only [hn.le, Int.toNat_of_nonneg, Int.neg_nonneg_of_nonpos, Int.neg_neg] - map_rel_iff' := by intro i j; exact toZ_le_iff i j + map_rel_iff' := by simp /-- If the order has a bot but no top, `toZ` defines an `OrderIso` between `ι` and `ℕ`. -/ def orderIsoNatOfLinearSuccPredArch [NoMaxOrder ι] [OrderBot ι] : ι ≃o ℕ where @@ -414,7 +387,7 @@ def orderIsoNatOfLinearSuccPredArch [NoMaxOrder ι] [OrderBot ι] : ι ≃o ℕ map_rel_iff' := by intro i j simp only [Equiv.coe_fn_mk, Int.toNat_le] - rw [← @toZ_le_iff ι _ _ _ _ ⊥, Int.toNat_of_nonneg (toZ_nonneg bot_le)] + rw [← toZ_le_toZ (i0 := (⊥ : ι)), Int.toNat_of_nonneg (toZ_nonneg bot_le)] /-- If the order has both a bot and a top, `toZ` gives an `OrderIso` between `ι` and `Finset.range n` for some `n`. -/ @@ -422,7 +395,7 @@ def orderIsoRangeOfLinearSuccPredArch [OrderBot ι] [OrderTop ι] : ι ≃o Finset.range ((toZ ⊥ (⊤ : ι)).toNat + 1) where toFun i := ⟨(toZ ⊥ i).toNat, - Finset.mem_range_succ_iff.mpr (Int.toNat_le_toNat ((toZ_le_iff _ _).mpr le_top))⟩ + Finset.mem_range_succ_iff.mpr (Int.toNat_le_toNat (toZ_le_toZ.mpr le_top))⟩ invFun n := succ^[n] ⊥ left_inv i := iterate_succ_toZ i bot_le right_inv n := by @@ -440,7 +413,7 @@ def orderIsoRangeOfLinearSuccPredArch [OrderBot ι] [OrderTop ι] : map_rel_iff' := by intro i j simp only [Equiv.coe_fn_mk, Subtype.mk_le_mk, Int.toNat_le] - rw [← @toZ_le_iff ι _ _ _ _ ⊥, Int.toNat_of_nonneg (toZ_nonneg bot_le)] + rw [← toZ_le_toZ (i0 := (⊥ : ι)), Int.toNat_of_nonneg (toZ_nonneg bot_le)] end OrderIso diff --git a/Mathlib/Order/Types/Arithmetic.lean b/Mathlib/Order/Types/Arithmetic.lean index e186231372..fd560d56d1 100644 --- a/Mathlib/Order/Types/Arithmetic.lean +++ b/Mathlib/Order/Types/Arithmetic.lean @@ -6,11 +6,8 @@ Authors: Yan Yablonovskiy module public import Mathlib.Data.Real.Basic -public import Mathlib.Order.CompleteBooleanAlgebra -public import Mathlib.Order.Fin.Basic -public import Mathlib.Order.Hom.Lex -public import Mathlib.Order.OmegaCompletePartialOrder public import Mathlib.Order.Types.Defs +public import Mathlib.SetTheory.Cardinal.Order /-! @@ -101,6 +98,33 @@ instance : Monoid OrderType.{u} where simp only [show 1 = type PUnit by rfl, ← type_lex_prod] exact (Prod.Lex.uniqueProd PUnit α).type_congr) +section Cardinal + +open Cardinal + +/-- The cardinal of an `OrderType` is the cardinality of any type on which a relation +with that order type is defined. -/ +def card (o : OrderType) : Cardinal := + o.liftOn (fun α _ ↦ #α) + fun _ _ _ _ hab ↦ mk_congr (type_eq_type.mp hab).some.toEquiv + +@[simp] +theorem card_type {α : Type u} [LinearOrder α] : card (type α) = #α := by + rw [card, liftOn_type] + +@[gcongr] +theorem card_mono {o₁ o₂ : OrderType} : o₁ ≤ o₂ → card o₁ ≤ card o₂ := + inductionOn₂ o₁ o₂ fun _ _ _ _ hle ↦ by + simp [card, (type_le_type_iff.mp hle).some.cardinal_le] + +theorem card_monotone : Monotone card := @card_mono + +@[simp] theorem card_zero : card 0 = 0 := by simpa using card_type (α := PEmpty) + +@[simp] theorem card_one : card 1 = 1 := by simpa using card_type (α := PUnit) + +end Cardinal + instance (n : Nat) : OfNat OrderType n where ofNat := Fin n |> type diff --git a/Mathlib/RepresentationTheory/Character.lean b/Mathlib/RepresentationTheory/Character.lean index 5a4bb405d6..d9173aa051 100644 --- a/Mathlib/RepresentationTheory/Character.lean +++ b/Mathlib/RepresentationTheory/Character.lean @@ -37,7 +37,7 @@ defined in `Mathlib/CategoryTheory/Simple.lean` noncomputable section -universe u +universe u v open CategoryTheory LinearMap CategoryTheory.MonoidalCategory Representation Module @@ -47,7 +47,7 @@ namespace FDRep section Monoid -variable {G : Type u} [Monoid G] +variable {G : Type v} [Monoid G] /-- The character of a representation `V : FDRep k G` is the function associating to `g : G` the trace of the linear map `V.ρ g`. -/ @@ -76,7 +76,7 @@ end Monoid section Group -variable {G : Type u} [Group G] +variable {G : Type v} [Group G] /-- The character of a representation is constant on conjugacy classes. -/ @[simp] @@ -119,7 +119,7 @@ end Group section Orthogonality -variable {G : Type u} [Group G] [IsAlgClosed k] +variable {G : Type v} [Group G] [IsAlgClosed k] variable [Fintype G] [Invertible (Fintype.card G : k)] diff --git a/Mathlib/RepresentationTheory/FDRep.lean b/Mathlib/RepresentationTheory/FDRep.lean index 4b94c3c460..bdfcace5ec 100644 --- a/Mathlib/RepresentationTheory/FDRep.lean +++ b/Mathlib/RepresentationTheory/FDRep.lean @@ -50,7 +50,7 @@ and this is reflected in the documentation. suppress_compilation -universe u +universe u v open CategoryTheory @@ -61,14 +61,14 @@ open CategoryTheory.Limits Note that `R` can be any ring, but the main case of interest is when `R = k` is a field and `G` is a group. -/ -abbrev FDRep (R G : Type u) [Ring R] [Monoid G] := +abbrev FDRep (R : Type u) (G : Type v) [Ring R] [Monoid G] := Action (FGModuleCat.{u} R) G namespace FDRep -variable {R k G : Type u} [CommRing R] [Field k] [Monoid G] +variable {R k : Type u} {G : Type v} [CommRing R] [Field k] [Monoid G] -example : LargeCategory (FDRep R G) := by infer_instance +example {G : Type u} [Monoid G] : LargeCategory (FDRep R G) := by infer_instance example : ConcreteCategory (FDRep R G) (Action.HomSubtype _ _) := by infer_instance example : Preadditive (FDRep R G) := by infer_instance example : HasFiniteLimits (FDRep k G) := by infer_instance @@ -195,7 +195,7 @@ namespace FDRep -- below should then just be obtained from general results about rigid categories. open Representation -variable {k G V : Type u} [Field k] [Group G] +variable {k : Type u} {G : Type v} {V : Type u} [Field k] [Group G] variable [AddCommGroup V] [Module k V] variable [FiniteDimensional k V] variable (ρV : Representation k G V) (W : FDRep k G) diff --git a/Mathlib/RepresentationTheory/Invariants.lean b/Mathlib/RepresentationTheory/Invariants.lean index d499a56240..73f0aa71d5 100644 --- a/Mathlib/RepresentationTheory/Invariants.lean +++ b/Mathlib/RepresentationTheory/Invariants.lean @@ -211,7 +211,7 @@ end Rep section FDRep -variable {k : Type u} [Field k] {G : Type u} [Group G] +variable {k : Type u} [Field k] {G : Type v} [Group G] /-- The invariants of the representation `linHom X.ρ Y.ρ` correspond to the representation homomorphisms from `X` to `Y`. -/ diff --git a/Mathlib/RingTheory/Flat/Rank.lean b/Mathlib/RingTheory/Flat/Rank.lean index 43401ac19c..7d35764a59 100644 --- a/Mathlib/RingTheory/Flat/Rank.lean +++ b/Mathlib/RingTheory/Flat/Rank.lean @@ -7,6 +7,7 @@ module public import Mathlib.LinearAlgebra.Trace public import Mathlib.RingTheory.Spectrum.Prime.FreeLocus +public import Mathlib.RingTheory.RingHom.Flat /-! @@ -34,7 +35,11 @@ open TensorProduct attribute [local instance] Module.free_of_flat_of_isLocalRing -variable {R S : Type*} [CommRing R] [CommRing S] [Algebra R S] [Module.Flat R S] [Module.Finite R S] +variable {R S : Type*} [CommRing R] [CommRing S] [Algebra R S] + +section + +variable [Module.Flat R S] [Module.Finite R S] lemma PrimeSpectrum.rankAtStalk_pos_iff_mem_range_comap (p : PrimeSpectrum R) : 0 < Module.rankAtStalk (R := R) S p ↔ p ∈ Set.range (PrimeSpectrum.comap (algebraMap R S)) := by @@ -122,3 +127,62 @@ lemma Module.algebraMap_bijective_iff_rankAtStalk : grind alias ⟨Module.algebraMap_bijective_of_rankAtStalk, _⟩ := Module.algebraMap_bijective_iff_rankAtStalk + +end + +section + +/-- The rank of a ring homomorphism `f : R →+* S` at a prime `x` of `R` is the rank of +`S` as an `R`-module at the stalk of `x`. -/ +@[expose] +noncomputable def RingHom.finrank {R S : Type*} [CommRing R] [CommRing S] (f : R →+* S) + (x : PrimeSpectrum R) : ℕ := + letI : Algebra R S := f.toAlgebra + Module.rankAtStalk S x + +@[simp] +lemma RingHom.finrank_algebraMap : + (algebraMap R S).finrank = Module.rankAtStalk (R := R) S := by + ext + rw [RingHom.finrank, toAlgebra_algebraMap] + +lemma Algebra.rankAtStalk_eq_of_isPushout (R S : Type*) [CommRing R] [CommRing S] [Algebra R S] + (R' S' : Type*) [CommRing R'] [CommRing S'] [Algebra R R'] [Algebra S S'] [Algebra R' S'] + [Algebra R S'] [IsScalarTower R R' S'] [IsScalarTower R S S'] + [Algebra.IsPushout R S R' S'] [Module.Flat R S] [Module.Finite R S] (x : PrimeSpectrum R') : + Module.rankAtStalk S' x = Module.rankAtStalk S (PrimeSpectrum.comap (algebraMap R R') x) := by + have : IsPushout R R' S S' := Algebra.IsPushout.symm inferInstance + have := Module.rankAtStalk_eq_of_equiv (Algebra.IsPushout.equiv R R' S S').symm.toLinearEquiv + rw [Module.rankAtStalk_eq_of_equiv (Algebra.IsPushout.equiv R R' S S').symm.toLinearEquiv, + Module.rankAtStalk_baseChange] + +lemma RingHom.finrank_comp_left_of_bijective {R S T : Type*} [CommRing R] [CommRing S] [CommRing T] + (f : R →+* S) (g : S →+* T) (hf : Function.Bijective g) (h1 : f.Finite) (h2 : f.Flat) + (x : PrimeSpectrum R) : (g.comp f).finrank x = f.finrank x := by + algebraize [f, g, (g.comp f)] + have : Algebra.IsPushout R S R T := .of_bijective_right _ _ hf + apply Algebra.rankAtStalk_eq_of_isPushout + +attribute [local instance] Algebra.TensorProduct.rightAlgebra in +lemma RingHom.finrank_comp_right_of_bijective {R S T : Type*} [CommRing R] [CommRing S] + [CommRing T] (f : R →+* S) (g : S →+* T) (hg : Function.Bijective f) (h1 : g.Finite) + (h2 : g.Flat) (y : PrimeSpectrum R) (x : PrimeSpectrum S) + (hy : y = PrimeSpectrum.comap f x) : + (g.comp f).finrank y = g.finrank x := by + subst hy + algebraize [f, g, (g.comp f)] + have : Module.Finite R T := h1.comp <| .of_surjective _ hg.2 + have : Module.Flat R T := (RingHom.Flat.of_bijective hg).comp h2 + have : Algebra.IsPushout R T S T := .of_bijective_left _ _ hg + exact (Algebra.rankAtStalk_eq_of_isPushout _ _ _ _ _).symm + +lemma CommRingCat.finrank_eq_of_isPushout {R S T P : CommRingCat.{u}} {f : R ⟶ S} {g : R ⟶ T} + {inl : S ⟶ P} {inr : T ⟶ P} (h : CategoryTheory.IsPushout f g inl inr) (hf : f.hom.Flat) + (hfin : f.hom.Finite) (x : PrimeSpectrum T) : + inr.hom.finrank x = f.hom.finrank (PrimeSpectrum.comap g.hom x) := by + algebraize [f.hom, g.hom, inl.hom, inr.hom, inl.hom.comp f.hom] + have : IsScalarTower R T P := .of_algebraMap_eq' <| congr($(h.1.1).hom) + have : Algebra.IsPushout R S T P := CommRingCat.isPushout_iff_isPushout.mp h + exact Algebra.rankAtStalk_eq_of_isPushout R S T P x + +end diff --git a/Mathlib/RingTheory/LocalIso.lean b/Mathlib/RingTheory/LocalIso.lean new file mode 100644 index 0000000000..ac833ffa20 --- /dev/null +++ b/Mathlib/RingTheory/LocalIso.lean @@ -0,0 +1,183 @@ +/- +Copyright (c) 2026 Christian Merten. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jiedong Jiang, Christian Merten +-/ +module + +public import Mathlib.RingTheory.RingHom.OpenImmersion +public import Mathlib.RingTheory.Spectrum.Prime.Topology + +/-! +# Local isomorphisms + +A ring homomorphism is a local isomorphism if source locally (in the geometric sense) +it is a standard open immersion. + +## Main declarations + +- `Algebra.IsLocalIso`: The class of algebras that are locally standard open immersions. + +We show that local isomorphisms are local, stable under composition and base change. + +## Implementation note + +Most results in this file follow purely formally from the corresponding property of +standard open immersion. We could use the `RingHom.Locally` API to obtain them, but +it would yield results with less universe generality and we would have to replace +`CommSemiring` by `CommRing`. In the future, we may consider refactoring the API +for `RingHom` properties to allow for also treating properties of `CommSemiring`s +and then simplify the proofs in this file. +-/ + +universe w v u + +public section + +open TensorProduct + +/-- An `R`-algebra `S` is a local isomorphism if source locally (in the geometric sense), +it is a standard open immersion. -/ +@[stacks 096E "(1) in the algebra formulation", mk_iff] +class Algebra.IsLocalIso (R S : Type*) [CommSemiring R] [CommSemiring S] [Algebra R S] : Prop where + exists_notMem_isStandardOpenImmersion (q : Ideal S) [q.IsPrime] : + ∃ g ∉ q, IsStandardOpenImmersion R (Localization.Away g) + +namespace Algebra.IsLocalIso + +variable {R S : Type*} [CommSemiring R] [CommSemiring S] [Algebra R S] + +variable (R S) in +lemma span_isStandardOpenImmersion_eq_top [Algebra.IsLocalIso R S] : + Ideal.span {g : S | Algebra.IsStandardOpenImmersion R (Localization.Away g)} = ⊤ := by + by_contra hne + obtain ⟨m, hm, hms⟩ := Ideal.exists_le_maximal _ hne + obtain ⟨g, hgm, hstd⟩ := + Algebra.IsLocalIso.exists_notMem_isStandardOpenImmersion (R := R) m + exact hgm (hms (Ideal.subset_span hstd)) + +lemma iff_span_isStandardOpenImmersion_eq_top : + IsLocalIso R S ↔ + Ideal.span {g : S | IsStandardOpenImmersion R (Localization.Away g)} = ⊤ := by + refine ⟨fun _ ↦ span_isStandardOpenImmersion_eq_top R S, fun h ↦ ⟨fun q hq ↦ ?_⟩⟩ + grind [Ideal.IsPrime.ne_top, Ideal.span_le, SetLike.mem_coe] + +instance (priority := 100) [IsStandardOpenImmersion R S] : IsLocalIso R S where + exists_notMem_isStandardOpenImmersion q hq := by + use 1, hq.one_notMem + exact IsStandardOpenImmersion.trans _ S _ + +lemma of_span_range_eq_top {ι : Type*} (f : ι → S) (h : Ideal.span (Set.range f) = ⊤) + (T : ι → Type*) [∀ i, CommSemiring (T i)] [∀ i, Algebra R (T i)] [∀ i, Algebra S (T i)] + [∀ i, IsScalarTower R S (T i)] [∀ i, IsLocalization.Away (f i) (T i)] + [∀ i, IsLocalIso R (T i)] : IsLocalIso R S := by + refine ⟨fun q hq ↦ ?_⟩ + obtain ⟨i, hi⟩ : ∃ i, f i ∉ q := by + rw [← PrimeSpectrum.iSup_basicOpen_eq_top_iff] at h + have : ⟨q, hq⟩ ∈ ⨆ i, PrimeSpectrum.basicOpen (f i) := by simp [h] + simpa using this + have : ⟨q, hq⟩ ∈ PrimeSpectrum.basicOpen (f i) := hi + rw [← SetLike.mem_coe, ← PrimeSpectrum.localization_away_comap_range (T i)] at this + obtain ⟨q', hq'⟩ := this + obtain ⟨g', hg', h⟩ := exists_notMem_isStandardOpenImmersion (R := R) q'.1 + obtain ⟨n, g, hg⟩ := IsLocalization.Away.surj (f i) g' + refine ⟨g * (f i), ?_, ?_⟩ + · refine Ideal.IsPrime.mul_notMem hq ?_ hi + simp only [PrimeSpectrum.ext_iff, PrimeSpectrum.comap_asIdeal] at hq' + rwa [← hq', Ideal.mem_comap, ← hg, Ideal.mul_unit_mem_iff_mem] + exact (IsLocalization.Away.algebraMap_isUnit (f i)).pow n + · have : IsLocalization.Away g' (Localization.Away (algebraMap S (T i) g)) := by + rw [← hg] + exact .of_associated + (associated_mul_unit_right _ _ ((IsLocalization.Away.algebraMap_isUnit (f i)).pow n)).symm + let e₁ : Localization.Away (algebraMap S (T i) g) ≃ₐ[S] Localization.Away (g * f i) := + IsLocalization.algEquiv (.powers (g * f i)) _ _ + let e₂ : Localization.Away g' ≃ₐ[R] Localization.Away (g * f i) := + ((IsLocalization.algEquiv (.powers g') _ _).restrictScalars R).trans (e₁.restrictScalars R) + exact .of_algEquiv e₂ + +lemma of_span_eq_top {s : Set S} (h : Ideal.span s = ⊤) + (h : ∀ x ∈ s, IsLocalIso R (Localization.Away x)) : IsLocalIso R S := by + have heq : Ideal.span (Set.range fun i : s ↦ i.1) = ⊤ := by simpa + have (i : s) : IsLocalIso R (Localization.Away i.1) := h _ i.property + exact .of_span_range_eq_top _ heq fun i ↦ Localization.Away i.1 + +lemma pi_of_finite {ι : Type*} (R : Type*) (S : ι → Type*) [CommSemiring R] + [∀ i, CommRing (S i)] [∀ i, Algebra R (S i)] [Finite ι] [∀ i, IsLocalIso R (S i)] : + IsLocalIso R (∀ i, S i) := by + classical + let (i : ι) : Algebra (∀ i, S i) (S i) := (Pi.evalAlgHom R S i).toAlgebra + have (i : ι) : IsLocalization.Away (Pi.single i (1 : S i)) (S i) := by + apply IsLocalization.away_of_isIdempotentElem + · simp [IsIdempotentElem, ← Pi.single_mul_left] + · apply RingHom.ker_evalRingHom + · apply (Pi.evalRingHom S i).surjective + apply of_span_range_eq_top (fun i ↦ Pi.single i (1 : S i)) _ fun i ↦ S i + exact Ideal.span_single_eq_top _ + +variable (T : Type*) [CommSemiring T] + +attribute [local instance] isScalarTower_localizationAlgebra in +variable (R S) in +/-- Local isomorphisms are stable under composition. -/ +lemma trans [Algebra S T] [Algebra R T] [IsScalarTower R S T] + [IsLocalIso R S] [IsLocalIso S T] : IsLocalIso R T := by + -- The proof is purely formal given that open immersions are stable under composition. + let s : Set S := {g : S | IsStandardOpenImmersion R (Localization.Away g)} + let T' (g : S) := Localization.Away (algebraMap S T g) + let (g : S) : Algebra (Localization.Away g) (T' g) := localizationAlgebra (.powers g) T + let T'' (g : S) (x : T) := Localization.Away (algebraMap _ (T' g) x) + let t (g : S) : Set T := {x : T | IsStandardOpenImmersion (Localization.Away g) (T'' g x)} + let ι : Type _ := Σ i : s, t i.1 + have (i : ι) : IsStandardOpenImmersion (Localization.Away i.1.1) (T'' i.1 i.2) := i.2.2 + suffices h : Ideal.span (Set.range fun i : ι ↦ algebraMap S T i.1 * i.2) = ⊤ by + have (i : ι) : IsStandardOpenImmersion R (T'' i.1 i.2) := + have : IsScalarTower R (Localization.Away i.1.1) (T' i.1.1) := + IsScalarTower.to₁₃₄ _ S _ _ + have : IsStandardOpenImmersion (Localization.Away i.1.1) (T'' i.1.1 i.2.1) := i.2.2 + have : IsStandardOpenImmersion R (Localization.Away i.1.1) := i.1.2 + .trans _ (Localization.Away i.1.1) _ + exact .of_span_range_eq_top _ h fun i : ι ↦ T'' i.1 i.2 + have h1 := congr(Ideal.map (algebraMap S T) $(span_isStandardOpenImmersion_eq_top R S)) + rw [Ideal.map_top, Ideal.map_span] at h1 + nth_rw 1 [_root_.eq_top_iff, ← Ideal.top_mul ⊤, ← h1, ← span_isStandardOpenImmersion_eq_top S T, + Ideal.span_mul_span, Ideal.span_le, Set.mul_subset_iff] + simp only [Set.mem_image, Set.mem_setOf_eq, SetLike.mem_coe, forall_exists_index, and_imp, + forall_apply_eq_imp_iff₂] + intro g hg x hx + refine Ideal.subset_span ⟨⟨⟨g, hg⟩, ⟨x, ?_⟩⟩, rfl⟩ + simp only [Set.mem_setOf_eq, t] + let : Algebra (Localization.Away x) (T'' g x) := + localizationAlgebra (.powers x) (T' g) + have : IsScalarTower S (Localization.Away x) (T'' g x) := + IsScalarTower.to₁₃₄ _ T _ _ + have : IsLocalization (algebraMapSubmonoid (Localization.Away x) (.powers g)) (T'' g x) := by + have : algebraMapSubmonoid (Localization.Away x) (.powers g) = + algebraMapSubmonoid (Localization.Away x) (.powers (algebraMap S T g)) := by + simp [IsScalarTower.algebraMap_apply S T (Localization.Away x)] + rw [this] + exact .commutes _ (T' g) _ (.powers x) (.powers (algebraMap S T g)) + have : IsPushout S (Localization.Away x) (Localization.Away g) (T'' g x) := + Algebra.isPushout_of_isLocalization (.powers g) _ _ _ + exact .of_isPushout S (Localization.Away x) _ _ + +variable {T} in +lemma of_algEquiv [Algebra R T] (e : S ≃ₐ[R] T) [IsLocalIso R S] : IsLocalIso R T := by + algebraize [e.toAlgHom.toRingHom] + have : IsStandardOpenImmersion S T := .of_bijective e.bijective + exact .trans _ S _ + +variable {T} in +lemma iff_of_algEquiv [Algebra R T] (e : S ≃ₐ[R] T) : IsLocalIso R S ↔ IsLocalIso R T := + ⟨fun _ ↦ .of_algEquiv e, fun _ ↦ .of_algEquiv e.symm⟩ + +instance [Algebra R T] [IsLocalIso R S] : IsLocalIso T (T ⊗[R] S) := by + rw [iff_span_isStandardOpenImmersion_eq_top, _root_.eq_top_iff, + ← Ideal.map_top Algebra.TensorProduct.includeRight, ← span_isStandardOpenImmersion_eq_top R S, + Ideal.map_le_iff_le_comap, Ideal.span_le] + intro g hg + apply Ideal.subset_span + simp only [Set.mem_setOf_eq] at hg ⊢ + exact .of_algEquiv <| IsLocalization.Away.tensorProductEquivTMulRight R T g (Localization.Away g) + +end Algebra.IsLocalIso diff --git a/Mathlib/RingTheory/LocalProperties/Exactness.lean b/Mathlib/RingTheory/LocalProperties/Exactness.lean index fa8cd9d6e9..50336a5d8a 100644 --- a/Mathlib/RingTheory/LocalProperties/Exactness.lean +++ b/Mathlib/RingTheory/LocalProperties/Exactness.lean @@ -10,7 +10,6 @@ public import Mathlib.RingTheory.LocalProperties.Submodule public import Mathlib.RingTheory.Localization.Algebra public import Mathlib.RingTheory.Localization.Away.Basic public import Mathlib.Algebra.Module.LocalizedModule.AtPrime -public import Mathlib.Algebra.Module.LocalizedModule.Away /-! # Local properties about linear maps diff --git a/Mathlib/RingTheory/LocalProperties/Submodule.lean b/Mathlib/RingTheory/LocalProperties/Submodule.lean index 38b71c21cb..014c000986 100644 --- a/Mathlib/RingTheory/LocalProperties/Submodule.lean +++ b/Mathlib/RingTheory/LocalProperties/Submodule.lean @@ -148,7 +148,7 @@ variable [∀ r : s, Module (Rₚ r) (Mₚ r)] [∀ r : s, IsScalarTower R (Rₚ r) (Mₚ r)] (f : ∀ r : s, M →ₗ[R] Mₚ r) - [∀ r : s, IsLocalizedModule (.powers r.1) (f r)] + [∀ r : s, IsLocalizedModule.Away r.1 (f r)] theorem Module.eq_of_isLocalized_span (x y : M) (h : ∀ r : s, f r x = f r y) : x = y := by suffices Module.eqIdeal R x y = ⊤ by simpa [Module.eqIdeal] using (eq_top_iff_one _).mp this diff --git a/Mathlib/RingTheory/LocalRing/ResidueField/Fiber.lean b/Mathlib/RingTheory/LocalRing/ResidueField/Fiber.lean index 21c2586192..dae55a28f2 100644 --- a/Mathlib/RingTheory/LocalRing/ResidueField/Fiber.lean +++ b/Mathlib/RingTheory/LocalRing/ResidueField/Fiber.lean @@ -72,6 +72,22 @@ lemma Ideal.Fiber.exists_smul_eq_one_tmul (x : p.Fiber S) : ∃ r ∉ p, ∃ s, (Algebra.TensorProduct.comm _ _ _ x) refine ⟨r, hr, s, by simpa using congr((Algebra.TensorProduct.comm _ _ _).symm $e)⟩ +attribute [local instance] Algebra.TensorProduct.rightAlgebra in +/-- `p.Fiber S` is isomorphic to the quotient `Sₚ ⧸ pSₚ`. -/ +noncomputable def Fiber.algEquivQuotient : + letI Rp := Localization p.primeCompl + letI pRp := IsLocalRing.maximalIdeal Rp + letI Sp := Localization (Algebra.algebraMapSubmonoid S p.primeCompl) + letI pSp := pRp.map (algebraMap Rp Sp) + p.Fiber S ≃ₐ[S] Sp ⧸ pSp := + (commRight R S p.ResidueField).symm.trans <| (tensorQuotientEquiv S _ S _).trans <| + { __ := Ideal.quotientEquiv _ _ (Localization.tensorLeftAlgEquiv p.primeCompl S) (by + rw [← Ideal.map_coe includeRight, Ideal.map_map] + congr + ext + simp [Localization.tensorLeftAlgEquiv_apply_one_tmul p.primeCompl]) + commutes' := by simp } + set_option backward.isDefEq.respectTransparency false in variable (R S) in /-- The fiber `PrimeSpectrum S → PrimeSpectrum R` at a prime ideal diff --git a/Mathlib/RingTheory/Localization/BaseChange.lean b/Mathlib/RingTheory/Localization/BaseChange.lean index b308f049b6..fd34209bf8 100644 --- a/Mathlib/RingTheory/Localization/BaseChange.lean +++ b/Mathlib/RingTheory/Localization/BaseChange.lean @@ -165,6 +165,37 @@ lemma Algebra.isPushout_of_isLocalization [IsLocalization (Algebra.algebraMapSub Algebra.IsPushout R T A B := (Algebra.isLocalization_iff_isPushout S _).mp inferInstance +lemma Submonoid.map_isUnit_le_isUnit {M N : Type*} [Monoid M] [Monoid N] + {F : Type*} [FunLike F M N] [MonoidHomClass F M N] (f : F) : + Submonoid.map f (IsUnit.submonoid M) ≤ IsUnit.submonoid N := by + rintro x ⟨y, hy, rfl⟩ + exact hy.map _ + +lemma Algebra.algebraMapSubmonoid_isUnit_le_isUnit {R S : Type*} [CommSemiring R] [Semiring S] + [Algebra R S] : + Algebra.algebraMapSubmonoid S (IsUnit.submonoid R) ≤ IsUnit.submonoid S := by + rintro x ⟨y, hy, rfl⟩ + exact hy.map _ + +instance {R S : Type*} [CommSemiring R] [CommSemiring S] [Algebra R S] : + IsLocalization (Algebra.algebraMapSubmonoid S (IsUnit.submonoid R)) S := + IsLocalization.of_le_isUnit Algebra.algebraMapSubmonoid_isUnit_le_isUnit + +lemma Algebra.IsPushout.of_bijective_left [Algebra A T] [IsScalarTower R A T] + (H : Function.Bijective (algebraMap R A)) : + IsPushout R T A T := by + have : IsLocalization (IsUnit.submonoid R) A := + IsLocalization.of_le_isUnit_of_bijective Algebra.algebraMapSubmonoid_isUnit_le_isUnit H + apply isPushout_of_isLocalization (IsUnit.submonoid R) + +lemma Algebra.IsPushout.of_bijective_right [Algebra A T] [IsScalarTower R A T] + (H : Function.Bijective (algebraMap A T)) : + IsPushout R A R T := by + have : IsLocalization (algebraMapSubmonoid A (IsUnit.submonoid R)) T := by + apply IsLocalization.of_le_isUnit_of_bijective _ H + simpa using Algebra.algebraMapSubmonoid_isUnit_le + apply Algebra.isPushout_of_isLocalization (IsUnit.submonoid R) + variable (R M) in open TensorProduct in instance {α} [IsLocalizedModule S f] : diff --git a/Mathlib/RingTheory/Localization/Finiteness.lean b/Mathlib/RingTheory/Localization/Finiteness.lean index 90a08641dc..84ac4fc6d6 100644 --- a/Mathlib/RingTheory/Localization/Finiteness.lean +++ b/Mathlib/RingTheory/Localization/Finiteness.lean @@ -35,8 +35,8 @@ section open scoped Pointwise -variable {R S : Type*} [CommRing R] [CommRing S] (M : Submonoid R) (f : R →+* S) -variable (R' S' : Type*) [CommRing R'] [CommRing S'] +variable {R S : Type*} [CommSemiring R] [CommSemiring S] (M : Submonoid R) (f : R →+* S) +variable (R' S' : Type*) [CommSemiring R'] [CommSemiring S'] variable [Algebra R R'] [Algebra S S'] open scoped Classical in @@ -146,7 +146,7 @@ lemma of_isLocalization (R S) {Rₚ Sₚ : Type*} [CommSemiring R] [CommSemiring use T.image (algebraMap S Sₚ) simpa using span_eq_top_localization_localization Rₚ M Sₚ hT -instance {R S : Type*} [CommRing R] {P : Ideal R} [CommRing S] [Algebra R S] +instance {R S : Type*} [CommSemiring R] {P : Ideal R} [CommSemiring S] [Algebra R S] [Module.Finite R S] [P.IsPrime] : Module.Finite (Localization.AtPrime P) (Localization (Algebra.algebraMapSubmonoid S P.primeCompl)) := @@ -169,7 +169,7 @@ instance [Module.Finite R M] : Module.Finite (Localization S) (LocalizedModule S end -variable {R : Type u} [CommRing R] {M : Type w} [AddCommMonoid M] [Module R M] +variable {R : Type u} [CommSemiring R] {M : Type w} [AddCommMonoid M] [Module R M] /-- If there exists a finite set `{ r }` of `R` such that `Mᵣ` is `Rᵣ`-finite for each `r`, @@ -182,10 +182,10 @@ See `of_localizationSpan'` for a version without the finite set assumption. -/ theorem of_localizationSpan_finite' (t : Finset R) (ht : Ideal.span (t : Set R) = ⊤) {Mₚ : ∀ (_ : t), Type*} [∀ (g : t), AddCommMonoid (Mₚ g)] [∀ (g : t), Module R (Mₚ g)] - {Rₚ : ∀ (_ : t), Type u} [∀ (g : t), CommRing (Rₚ g)] [∀ (g : t), Algebra R (Rₚ g)] + {Rₚ : ∀ (_ : t), Type*} [∀ (g : t), CommSemiring (Rₚ g)] [∀ (g : t), Algebra R (Rₚ g)] [∀ (g : t), IsLocalization.Away g.val (Rₚ g)] [∀ (g : t), Module (Rₚ g) (Mₚ g)] [∀ (g : t), IsScalarTower R (Rₚ g) (Mₚ g)] - (f : ∀ (g : t), M →ₗ[R] Mₚ g) [∀ (g : t), IsLocalizedModule (Submonoid.powers g.val) (f g)] + (f : ∀ (g : t), M →ₗ[R] Mₚ g) [∀ (g : t), IsLocalizedModule.Away g.val (f g)] (H : ∀ (g : t), Module.Finite (Rₚ g) (Mₚ g)) : Module.Finite R M := by classical @@ -218,17 +218,17 @@ See `Module.Finite.of_localizationSpan_finite` for the specialized version. -/ theorem of_localizationSpan' (t : Set R) (ht : Ideal.span t = ⊤) {Mₚ : ∀ (_ : t), Type*} [∀ (g : t), AddCommMonoid (Mₚ g)] [∀ (g : t), Module R (Mₚ g)] - {Rₚ : ∀ (_ : t), Type u} [∀ (g : t), CommRing (Rₚ g)] [∀ (g : t), Algebra R (Rₚ g)] + {Rₚ : ∀ (_ : t), Type*} [∀ (g : t), CommSemiring (Rₚ g)] [∀ (g : t), Algebra R (Rₚ g)] [h₁ : ∀ (g : t), IsLocalization.Away g.val (Rₚ g)] [∀ (g : t), Module (Rₚ g) (Mₚ g)] [∀ (g : t), IsScalarTower R (Rₚ g) (Mₚ g)] - (f : ∀ (g : t), M →ₗ[R] Mₚ g) [h₂ : ∀ (g : t), IsLocalizedModule (Submonoid.powers g.val) (f g)] + (f : ∀ (g : t), M →ₗ[R] Mₚ g) [h₂ : ∀ (g : t), IsLocalizedModule.Away g.val (f g)] (H : ∀ (g : t), Module.Finite (Rₚ g) (Mₚ g)) : Module.Finite R M := by rw [Ideal.span_eq_top_iff_finite] at ht obtain ⟨t', hc, ht'⟩ := ht have (g : t') : IsLocalization.Away g.val (Rₚ ⟨g.val, hc g.property⟩) := h₁ ⟨g.val, hc g.property⟩ - have (g : t') : IsLocalizedModule (Submonoid.powers g.val) + have (g : t') : IsLocalizedModule.Away g.val ((fun g ↦ f ⟨g.val, hc g.property⟩) g) := h₂ ⟨g.val, hc g.property⟩ apply of_localizationSpan_finite' t' ht' (fun g ↦ f ⟨g.val, hc g.property⟩) (fun g ↦ H ⟨g.val, hc g.property⟩) @@ -241,9 +241,9 @@ See `of_localizationSpan` for a version without the finite set assumption. -/ theorem of_localizationSpan_finite (t : Finset R) (ht : Ideal.span (t : Set R) = ⊤) (H : ∀ (g : t), Module.Finite (Localization.Away g.val) - (LocalizedModule (Submonoid.powers g.val) M)) : + (LocalizedModule.Away g.val M)) : Module.Finite R M := - let f (g : t) : M →ₗ[R] LocalizedModule (Submonoid.powers g.val) M := + let f (g : t) : M →ₗ[R] LocalizedModule.Away g.val M := LocalizedModule.mkLinearMap (Submonoid.powers g.val) M of_localizationSpan_finite' t ht f H @@ -251,9 +251,9 @@ theorem of_localizationSpan_finite (t : Finset R) (ht : Ideal.span (t : Set R) = then `M` is a finite `R`-module. -/ theorem of_localizationSpan (t : Set R) (ht : Ideal.span t = ⊤) (H : ∀ (g : t), Module.Finite (Localization.Away g.val) - (LocalizedModule (Submonoid.powers g.val) M)) : + (LocalizedModule.Away g.val M)) : Module.Finite R M := - let f (g : t) : M →ₗ[R] LocalizedModule (Submonoid.powers g.val) M := + let f (g : t) : M →ₗ[R] LocalizedModule.Away g.val M := LocalizedModule.mkLinearMap (Submonoid.powers g.val) M of_localizationSpan' t ht f H @@ -263,7 +263,7 @@ end Module namespace Ideal -variable {R : Type u} [CommRing R] +variable {R : Type u} [CommSemiring R] /-- If `I` is an ideal such that there exists a set `{ r }` of `R` such that the image of `I` in `Rᵣ` is finitely generated for each `r`, then `I` is finitely @@ -277,7 +277,7 @@ lemma fg_of_localizationSpan {I : Ideal R} (t : Set R) (ht : Ideal.span t = ⊤) end Ideal -variable {R : Type u} [CommRing R] {S : Type v} [CommRing S] {f : R →+* S} +variable {R : Type u} [CommSemiring R] {S : Type v} [CommSemiring S] {f : R →+* S} /-- To check that the kernel of a ring homomorphism is finitely generated, diff --git a/Mathlib/RingTheory/Localization/Free.lean b/Mathlib/RingTheory/Localization/Free.lean index 92f8594566..af9e0e7b7f 100644 --- a/Mathlib/RingTheory/Localization/Free.lean +++ b/Mathlib/RingTheory/Localization/Free.lean @@ -43,7 +43,7 @@ lemma Module.FinitePresentation.exists_basis_localizedModule_powers [IsLocalization S Rₛ] [Module.FinitePresentation R M] {I} [Finite I] (b : Basis I Rₛ M') : ∃ (r : R) (hr : r ∈ S) - (b' : Basis I (Localization (.powers r)) (LocalizedModule (.powers r) M)), + (b' : Basis I (Localization (.powers r)) (LocalizedModule.Away r M)), ∀ i, (LocalizedModule.lift (.powers r) f fun s ↦ IsLocalizedModule.map_units f ⟨s.1, SetLike.le_def.mp (Submonoid.powers_le.mpr hr) s.2⟩) (b' i) = b i := by have : Module.FinitePresentation R (I →₀ R) := Module.finitePresentation_of_projective _ _ @@ -79,8 +79,8 @@ lemma Module.FinitePresentation.exists_free_localizedModule_powers (Rₛ) [CommRing Rₛ] [Algebra R Rₛ] [Module Rₛ M'] [IsScalarTower R Rₛ M'] [Nontrivial Rₛ] [IsLocalization S Rₛ] [Module.FinitePresentation R M] [Module.Free Rₛ M'] : ∃ r, r ∈ S ∧ - Module.Free (Localization (.powers r)) (LocalizedModule (.powers r) M) ∧ - Module.finrank (Localization (.powers r)) (LocalizedModule (.powers r) M) = + Module.Free (Localization (.powers r)) (LocalizedModule.Away r M) ∧ + Module.finrank (Localization (.powers r)) (LocalizedModule.Away r M) = Module.finrank Rₛ M' := by let I := Module.Free.ChooseBasisIndex Rₛ M' let b : Basis I Rₛ M' := Module.Free.chooseBasis Rₛ M' diff --git a/Mathlib/RingTheory/Regular/Category.lean b/Mathlib/RingTheory/Regular/Category.lean index e27bfc5440..f81fe48953 100644 --- a/Mathlib/RingTheory/Regular/Category.lean +++ b/Mathlib/RingTheory/Regular/Category.lean @@ -6,7 +6,7 @@ Authors: Jingting Wang, Wanyi He, Nailin Guan module public import Mathlib.Algebra.Homology.ShortComplex.ModuleCat -public import Mathlib.RingTheory.QuotSMulTop +public import Mathlib.Algebra.Module.Submodule.Pointwise /-! # Categorical constructions for `IsSMulRegular` @@ -18,32 +18,29 @@ universe u v w variable {R : Type u} [CommRing R] (M : ModuleCat.{v} R) -open CategoryTheory Ideal Pointwise +open CategoryTheory Abelian Pointwise -lemma LinearMap.exact_smul_id_smul_top_mkQ (M : Type v) [AddCommGroup M] [Module R M] (r : R) : - Function.Exact (r • LinearMap.id : M →ₗ[R] M) (r • (⊤ : Submodule R M)).mkQ := by +lemma LinearMap.exact_lsmul_mkQ_smul_top (M : Type v) [AddCommGroup M] [Module R M] (r : R) : + Function.Exact (LinearMap.lsmul _ M r) (r • (⊤ : Submodule R M)).mkQ := by intro x - simp [Submodule.mem_smul_pointwise_iff_exists, - Submodule.mem_smul_pointwise_iff_exists] + simp [Submodule.mem_smul_pointwise_iff_exists, Submodule.mem_smul_pointwise_iff_exists] + +@[deprecated (since := "2026-04-13")] +alias LinearMap.exact_smul_id_smul_top_mkQ := LinearMap.exact_lsmul_mkQ_smul_top namespace ModuleCat /-- The short (exact) complex `M → M → M⧸xM` obtain from the scalar multiple of `x : R` on `M`. -/ -@[simps] -def smulShortComplex (r : R) : - ShortComplex (ModuleCat R) where - X₁ := M - X₂ := M - X₃ := ModuleCat.of R (QuotSMulTop r M) - f := ModuleCat.ofHom (r • LinearMap.id) - g := ModuleCat.ofHom (r • (⊤ : Submodule R M)).mkQ - zero := by - ext x - exact (LinearMap.exact_smul_id_smul_top_mkQ M r).apply_apply_eq_zero x - -lemma smulShortComplex_exact (r : R) : (smulShortComplex M r).Exact := by - simp [smulShortComplex, ShortComplex.ShortExact.moduleCat_exact_iff_function_exact, - LinearMap.exact_smul_id_smul_top_mkQ, -LinearMap.coe_smul] +@[simps!] +def smulShortComplex (r : R) : ShortComplex (ModuleCat R) := + ModuleCat.shortComplexOfCompEqZero (LinearMap.lsmul _ M r) (r • (⊤ : Submodule R M)).mkQ + (LinearMap.exact_lsmul_mkQ_smul_top M r).linearMap_comp_eq_zero + +@[simp] +lemma smulShortComplex_f_eq_smul_id (r : R) : (M.smulShortComplex r).f = r • 𝟙 M := rfl + +lemma smulShortComplex_exact (r : R) : (smulShortComplex M r).Exact := + ModuleCat.shortComplex_exact _ (LinearMap.exact_lsmul_mkQ_smul_top M r) instance smulShortComplex_g_epi (r : R) : Epi (smulShortComplex M r).g := by simpa [smulShortComplex, ModuleCat.epi_iff_surjective] using Submodule.mkQ_surjective _ diff --git a/Mathlib/RingTheory/RingHom/OpenImmersion.lean b/Mathlib/RingTheory/RingHom/OpenImmersion.lean index 45d7eb59fd..0d8177217f 100644 --- a/Mathlib/RingTheory/RingHom/OpenImmersion.lean +++ b/Mathlib/RingTheory/RingHom/OpenImmersion.lean @@ -30,13 +30,13 @@ variable {R S T : Type*} [CommSemiring R] [CommSemiring S] [CommSemiring T] [Algebra R S] : Prop where exists_away (R S) : ∃ r : R, IsLocalization.Away r S -open IsStandardOpenImmersion +namespace IsStandardOpenImmersion instance (r : R) : IsStandardOpenImmersion R (Localization.Away r) := ⟨r, inferInstance⟩ variable (R S T) in -@[trans] theorem IsStandardOpenImmersion.trans [Algebra S T] [IsScalarTower R S T] +@[trans] theorem trans [Algebra S T] [IsScalarTower R S T] [IsStandardOpenImmersion R S] [IsStandardOpenImmersion S T] : IsStandardOpenImmersion R T := let ⟨r, _⟩ := exists_away R S @@ -50,7 +50,37 @@ instance [IsStandardOpenImmersion R T] : IsStandardOpenImmersion S (S ⊗[R] T) let ⟨r, _⟩ := exists_away R T ⟨algebraMap R S r, inferInstance⟩ -end Algebra +instance : IsStandardOpenImmersion R R := + ⟨1, IsLocalization.away_of_isUnit_of_bijective R isUnit_one Function.bijective_id⟩ + +lemma of_bijective (h : Function.Bijective (algebraMap R S)) : + IsStandardOpenImmersion R S := by + rw [Algebra.isStandardOpenImmersion_iff] + use 1 + apply IsLocalization.away_of_isUnit_of_bijective _ isUnit_one h + +lemma of_algEquiv {T : Type*} [CommSemiring T] [Algebra R T] (e : S ≃ₐ[R] T) + [h : IsStandardOpenImmersion R S] : + IsStandardOpenImmersion R T := by + rw [Algebra.isStandardOpenImmersion_iff] at * + obtain ⟨r, hr⟩ := h + use r + exact IsLocalization.isLocalization_of_algEquiv _ e + +lemma iff_of_algEquiv {T : Type*} [CommSemiring T] [Algebra R T] + (e : S ≃ₐ[R] T) : + IsStandardOpenImmersion R S ↔ IsStandardOpenImmersion R T := + ⟨fun _ ↦ .of_algEquiv e, fun _ ↦ .of_algEquiv e.symm⟩ + +variable (R S) in +lemma of_isPushout (R' S' : Type*) [CommSemiring R'] [CommSemiring S'] + [Algebra R R'] [Algebra S S'] [Algebra R' S'] [Algebra R S'] [IsScalarTower R R' S'] + [IsScalarTower R S S'] [IsPushout R S R' S'] [IsStandardOpenImmersion R S] : + IsStandardOpenImmersion R' S' := + have : IsPushout R R' S S' := by rwa [IsPushout.comm] + .of_algEquiv (IsPushout.equiv R _ S _) + +end Algebra.IsStandardOpenImmersion namespace RingHom diff --git a/Mathlib/RingTheory/Spectrum/Prime/FreeLocus.lean b/Mathlib/RingTheory/Spectrum/Prime/FreeLocus.lean index 11c5b02be3..0e2381c60c 100644 --- a/Mathlib/RingTheory/Spectrum/Prime/FreeLocus.lean +++ b/Mathlib/RingTheory/Spectrum/Prime/FreeLocus.lean @@ -168,7 +168,7 @@ lemma freeLocus_eq_univ [Module.Finite R M] [Module.Flat R M] : lemma basicOpen_subset_freeLocus_iff [Module.FinitePresentation R M] {f : R} : (basicOpen f : Set (PrimeSpectrum R)) ⊆ freeLocus R M ↔ - Module.Projective (Localization.Away f) (LocalizedModule (.powers f) M) := by + Module.Projective (Localization.Away f) (LocalizedModule.Away f M) := by rw [← freeLocus_eq_univ_iff, freeLocus_localization, Set.preimage_eq_univ_iff, localization_away_comap_range _ f] diff --git a/Mathlib/RingTheory/Spectrum/Prime/Module.lean b/Mathlib/RingTheory/Spectrum/Prime/Module.lean index e5022d65de..97da996481 100644 --- a/Mathlib/RingTheory/Spectrum/Prime/Module.lean +++ b/Mathlib/RingTheory/Spectrum/Prime/Module.lean @@ -35,7 +35,7 @@ lemma IsLocalRing.closedPoint_mem_support [IsLocalRing R] [Nontrivial M] : /-- `M[1/f] = 0` if and only if `D(f) ∩ Supp M = 0`. -/ lemma LocalizedModule.subsingleton_iff_disjoint {f : R} : - Subsingleton (LocalizedModule (.powers f) M) ↔ + Subsingleton (LocalizedModule.Away 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, Set.le_iff_subset] diff --git a/Mathlib/RingTheory/Support.lean b/Mathlib/RingTheory/Support.lean index 508da5dff7..f6dfd25967 100644 --- a/Mathlib/RingTheory/Support.lean +++ b/Mathlib/RingTheory/Support.lean @@ -97,7 +97,7 @@ lemma Module.annihilator_le_of_mem_support (hp : p ∈ Module.support R M) : exact le_trans ((Submodule.subtype _).annihilator_le_of_injective Subtype.val_injective) hm lemma LocalizedModule.subsingleton_iff_support_subset {f : R} : - Subsingleton (LocalizedModule (.powers f) M) ↔ + Subsingleton (LocalizedModule.Away f M) ↔ Module.support R M ⊆ PrimeSpectrum.zeroLocus {f} := by rw [LocalizedModule.subsingleton_iff] constructor @@ -221,7 +221,7 @@ lemma Module.support_eq_zeroLocus : then `M[1/f] = 0` for some `p ∈ D(f)`. -/ lemma LocalizedModule.exists_subsingleton_away (p : Ideal R) [p.IsPrime] [Subsingleton (LocalizedModule p.primeCompl M)] : - ∃ f ∉ p, Subsingleton (LocalizedModule (.powers f) M) := by + ∃ f ∉ p, Subsingleton (LocalizedModule.Away f M) := by have : ⟨p, inferInstance⟩ ∈ (Module.support R M)ᶜ := by simpa [Module.notMem_support_iff] rw [Module.support_eq_zeroLocus, ← Set.biUnion_of_singleton (Module.annihilator R M : Set R), @@ -233,7 +233,7 @@ lemma LocalizedModule.exists_subsingleton_away (p : Ideal R) [p.IsPrime] lemma IsLocalizedModule.exists_subsingleton_away {M' : Type*} [AddCommMonoid M'] [Module R M'] (l : M →ₗ[R] M') (p : Ideal R) [p.IsPrime] [IsLocalizedModule p.primeCompl l] [Subsingleton M'] : - ∃ f ∉ p, Subsingleton (LocalizedModule (.powers f) M) := by + ∃ f ∉ p, Subsingleton (LocalizedModule.Away f M) := by let e := IsLocalizedModule.iso p.primeCompl l have : Subsingleton (LocalizedModule p.primeCompl M) := e.subsingleton exact LocalizedModule.exists_subsingleton_away p diff --git a/Mathlib/SetTheory/Cardinal/Basic.lean b/Mathlib/SetTheory/Cardinal/Basic.lean index 0447a2c18a..b45d98e570 100644 --- a/Mathlib/SetTheory/Cardinal/Basic.lean +++ b/Mathlib/SetTheory/Cardinal/Basic.lean @@ -247,7 +247,7 @@ theorem lift_iSup_le_lift_iSup {ι : Type v} {ι' : Type v'} {f : ι → Cardina {f' : ι' → Cardinal.{w'}} (hf : BddAbove (range f)) (hf' : BddAbove (range f')) {g : ι → ι'} (h : ∀ i, lift.{w'} (f i) ≤ lift.{w} (f' (g i))) : lift.{w'} (iSup f) ≤ lift.{w} (iSup f') := by rw [lift_iSup hf, lift_iSup hf'] - exact ciSup_mono' (bddAbove_range_comp.{_, _, w} hf' _) fun i => ⟨_, h i⟩ + exact ciSup_mono_of_forall_exists' (bddAbove_range_comp.{_, _, w} hf' _) fun i => ⟨_, h i⟩ /-- A variant of `lift_iSup_le_lift_iSup` with universes specialized via `w = v` and `w' = v'`. This is sometimes necessary to avoid universe unification issues. -/ diff --git a/Mathlib/SetTheory/Cardinal/Cofinality/Basic.lean b/Mathlib/SetTheory/Cardinal/Cofinality/Basic.lean new file mode 100644 index 0000000000..020b1a98d7 --- /dev/null +++ b/Mathlib/SetTheory/Cardinal/Cofinality/Basic.lean @@ -0,0 +1,203 @@ +/- +Copyright (c) 2017 Mario Carneiro. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mario Carneiro, Floris van Doorn, Violeta Hernández Palacios +-/ +module + +public import Mathlib.Order.Cofinal +public import Mathlib.SetTheory.Cardinal.Basic + +/-! +# Cofinality of an order + +This file contains the definition of the cofinality `Order.cof α` of an order. This is the smallest +cardinality of a cofinal subset. +-/ + +public noncomputable section + +open Function Cardinal Set Order + +universe u v w + +variable {α γ : Type u} {β : Type v} + +/-! ### Cofinality of orders -/ + +namespace Order +section Preorder +variable [Preorder α] + +variable (α) in +/-- The cofinality of a preorder is the smallest cardinality of a cofinal subset. -/ +def cof : Cardinal := + ⨅ s : {s : Set α // IsCofinal s}, #s + +theorem cof_le {s : Set α} (h : IsCofinal s) : cof α ≤ #s := + ciInf_le' (ι := {s : Set α // IsCofinal s}) _ ⟨s, h⟩ + +theorem le_lift_cof_iff {c : Cardinal.{max u v}} : + c ≤ lift.{v} (cof α) ↔ ∀ s : Set α, IsCofinal s → c ≤ lift.{v} #s := by + rw [cof, lift_iInf, le_ciInf_iff'] + simp + +theorem le_cof_iff {c : Cardinal} : c ≤ cof α ↔ ∀ s : Set α, IsCofinal s → c ≤ #s := by + simpa using @le_lift_cof_iff.{u, u} α _ c + +@[deprecated (since := "2026-02-18")] alias le_cof := le_cof_iff + +variable (α) in +theorem cof_eq : ∃ s : Set α, IsCofinal s ∧ #s = cof α := by + obtain ⟨s, hs⟩ := ciInf_mem fun s : {s : Set α // IsCofinal s} ↦ #s + exact ⟨s.1, s.2, hs⟩ + +variable (α) in +theorem cof_le_cardinalMk : cof α ≤ #α := + cof_le .univ |>.trans_eq mk_univ + +theorem cof_eq_zero_iff : cof α = 0 ↔ IsEmpty α := by + refine ⟨fun _ ↦ ?_, fun _ ↦ by simp [cof]⟩ + obtain ⟨s, hs, hs'⟩ := cof_eq α + simp_all [mk_eq_zero_iff, isCofinal_empty_iff] + +@[simp] +theorem cof_eq_zero [h : IsEmpty α] : cof α = 0 := + cof_eq_zero_iff.2 h + +theorem cof_ne_zero_iff : cof α ≠ 0 ↔ Nonempty α := by + simpa using cof_eq_zero_iff.not + +@[simp] +theorem cof_ne_zero [h : Nonempty α] : cof α ≠ 0 := + cof_ne_zero_iff.2 h + +theorem cof_eq_one_iff : cof α = 1 ↔ ∃ x : α, IsTop x := by + refine ⟨fun h ↦ ?_, fun ⟨t, ht⟩ ↦ ?_⟩ + · obtain ⟨s, hs, hs'⟩ := cof_eq α + rw [h, mk_set_eq_one_iff] at hs' + obtain ⟨t, rfl⟩ := hs' + use t + rwa [isCofinal_singleton_iff] at hs + · apply le_antisymm + · apply (cof_le (s := {t}) _).trans_eq (mk_singleton _) + rwa [isCofinal_singleton_iff] + · rw [Cardinal.one_le_iff_ne_zero, cof_ne_zero_iff] + use t + +@[simp] +theorem cof_eq_one [OrderTop α] : cof α = 1 := + cof_eq_one_iff.2 ⟨⊤, isTop_top⟩ + +theorem cof_ne_one_iff : cof α ≠ 1 ↔ NoTopOrder α := by + rw [← not_iff_not, not_not, noTopOrder_iff, cof_eq_one_iff] + simp + +@[simp] +theorem cof_ne_one [h : NoTopOrder α] : cof α ≠ 1 := + cof_ne_one_iff.2 h + +theorem cof_le_one_iff [Nonempty α] : cof α ≤ 1 ↔ ∃ x : α, IsTop x := by + rw [le_iff_lt_or_eq, Cardinal.lt_one_iff, cof_eq_one_iff] + simp + +theorem one_lt_cof_iff [Nonempty α] : 1 < cof α ↔ NoTopOrder α := by + rw [← not_iff_not, not_lt, noTopOrder_iff, cof_le_one_iff] + simp + +@[simp] +theorem one_lt_cof [Nonempty α] [h : NoTopOrder α] : 1 < cof α := + one_lt_cof_iff.2 h + +end Preorder + +section LinearOrder +variable [LinearOrder α] [LinearOrder β] [LinearOrder γ] + +theorem lift_cof_congr_of_strictMono {f : α → β} (hf : StrictMono f) (hf' : IsCofinal (range f)) : + lift.{v} (cof α) = lift.{u} (cof β) := by + apply le_antisymm <;> rw [le_lift_cof_iff] <;> intro s hs + · have H (x : s) : ∃ y : α, x ≤ f y := by simpa using hf' x + choose g hg using H + refine (lift_le.2 <| cof_le (s := range g) fun a ↦ ?_).trans mk_range_le_lift + obtain ⟨_, ⟨b, rfl⟩, hb⟩ := hf' (f a) + obtain ⟨c, hc, hc'⟩ := hs (f b) + refine ⟨_, Set.mem_range_self ⟨c, hc⟩, ?_⟩ + rw [← hf.le_iff_le] + exact hb.trans (hc'.trans (hg ⟨c, hc⟩)) + · exact (lift_le.2 <| cof_le (hs.image hf.monotone hf')).trans mk_image_le_lift + +theorem cof_congr_of_strictMono {f : α → γ} (hf : StrictMono f) (hf' : IsCofinal (range f)) : + cof α = cof γ := by + simpa using lift_cof_congr_of_strictMono hf hf' + +@[simp] +theorem cof_lt_aleph0_iff : Order.cof α < ℵ₀ ↔ Order.cof α ≤ 1 := by + refine ⟨fun h ↦ ?_, (lt_of_le_of_lt · one_lt_aleph0)⟩ + obtain ⟨s, hs, hs'⟩ := Order.cof_eq α + have hf : s.Finite := by + rw [Set.Finite, ← mk_lt_aleph0_iff] + exact hs'.trans_lt h + obtain ⟨t, ht, ht'⟩ := hf.exists_subsingleton_isCofinal hs + apply (cof_le ht').trans + simpa + +@[simp] +theorem aleph0_le_cof_iff : ℵ₀ ≤ Order.cof α ↔ 1 < Order.cof α := by + simp [← not_lt] + +@[simp] +theorem cof_eq_aleph0 [NoMaxOrder α] [Nonempty α] [Countable α] : cof α = ℵ₀ := + ((cof_le_cardinalMk _).trans mk_le_aleph0).antisymm (by simp) + +theorem cof_nat : cof ℕ = ℵ₀ := by simp + +end LinearOrder +end Order + +section Congr +variable [Preorder α] [Preorder β] [Preorder γ] + +theorem GaloisConnection.cof_le_lift {f : β → α} {g : α → β} (h : GaloisConnection f g) : + Cardinal.lift.{u} (Order.cof β) ≤ Cardinal.lift.{v} (Order.cof α) := by + rw [le_lift_cof_iff] + exact fun s hs ↦ (lift_le.2 <| cof_le (h.map_isCofinal hs)).trans mk_image_le_lift + +theorem GaloisConnection.cof_le {f : γ → α} {g : α → γ} (h : GaloisConnection f g) : + Order.cof γ ≤ Order.cof α := by + simpa using h.cof_le_lift + +theorem OrderIso.lift_cof_congr (f : α ≃o β) : + Cardinal.lift.{v} (Order.cof α) = Cardinal.lift.{u} (Order.cof β) := + f.to_galoisConnection.cof_le_lift.antisymm (f.symm.to_galoisConnection.cof_le_lift) + +@[deprecated (since := "2026-03-20")] alias OrderIso.lift_cof_eq := OrderIso.lift_cof_congr + +theorem OrderIso.cof_congr (f : α ≃o γ) : Order.cof α = Order.cof γ := by + simpa using f.lift_cof_congr + +@[deprecated (since := "2026-03-20")] alias OrderIso.cof_eq := OrderIso.cof_congr + +@[deprecated (since := "2026-02-18")] alias RelIso.cof_eq_lift := OrderIso.lift_cof_congr +@[deprecated (since := "2026-02-18")] alias RelIso.cof_eq := OrderIso.cof_congr + +end Congr + +/-- If the union of `s` is cofinal and `s` is smaller than the cofinality, then `s` has a cofinal +member. -/ +theorem isCofinal_of_isCofinal_sUnion {α : Type*} [LinearOrder α] {s : Set (Set α)} + (h₁ : IsCofinal (⋃₀ s)) (h₂ : #s < Order.cof α) : ∃ x ∈ s, IsCofinal x := by + contrapose! h₂ + simp_rw [not_isCofinal_iff] at h₂ + choose f hf using h₂ + refine (cof_le (s := range fun x ↦ f x.1 x.2) fun a ↦ ?_).trans mk_range_le + obtain ⟨b, ⟨t, ht, hb⟩, hab⟩ := h₁ a + simpa using ⟨t, ht, hab.trans (hf t ht b hb).le⟩ + +/-- If the union of the `ι`-indexed family `s` is cofinal and `ι` is smaller than the cofinality, +then `s` has a cofinal member. -/ +theorem isCofinal_of_isCofinal_iUnion {α : Type*} {ι} [LinearOrder α] {s : ι → Set α} + (h₁ : IsCofinal (⋃ i, s i)) (h₂ : #ι < Order.cof α) : ∃ i, IsCofinal (s i) := by + rw [← sUnion_range] at h₁ + obtain ⟨_, ⟨i, rfl⟩, h⟩ := isCofinal_of_isCofinal_sUnion h₁ (mk_range_le.trans_lt h₂) + exact ⟨i, h⟩ diff --git a/Mathlib/SetTheory/Cardinal/Cofinality.lean b/Mathlib/SetTheory/Cardinal/Cofinality/Ordinal.lean similarity index 78% rename from Mathlib/SetTheory/Cardinal/Cofinality.lean rename to Mathlib/SetTheory/Cardinal/Cofinality/Ordinal.lean index 2c6f9e25f3..84be4fadcd 100644 --- a/Mathlib/SetTheory/Cardinal/Cofinality.lean +++ b/Mathlib/SetTheory/Cardinal/Cofinality/Ordinal.lean @@ -5,30 +5,25 @@ Authors: Mario Carneiro, Floris van Doorn, Violeta Hernández Palacios -/ module -public import Mathlib.Order.Cofinal public import Mathlib.SetTheory.Cardinal.Arithmetic +public import Mathlib.SetTheory.Cardinal.Cofinality.Basic public import Mathlib.SetTheory.Ordinal.FixedPoint /-! -# Cofinality +# Cofinality of an ordinal -This file contains the definition of cofinality of an order and an ordinal number. +This file contains the definition of the cofinality `Ordinal.cof o` of an ordinal. This is the +cofinality of the ordinal `o` when viewed as a linear order. -## Main Definitions - -* `Order.cof α` is the cofinality of a preorder. This is the smallest cardinality of a cofinal - subset. -* `Ordinal.cof o` is the cofinality of the ordinal `o` when viewed as a linear order. - -## Main Statements +## Main statements * `Cardinal.lt_power_cof_ord`: A consequence of König's theorem stating that `c < c ^ c.ord.cof` for `c ≥ ℵ₀`. -## Implementation Notes +## Implementation notes -* The cofinality is defined for ordinals. - If `c` is a cardinal number, its cofinality is `c.ord.cof`. +* We do not separately define the cofinality of a cardinal. If `c` is a cardinal number, you can + write its cofinality as `c.ord.cof`. -/ public noncomputable section @@ -40,185 +35,7 @@ universe u v w variable {α γ : Type u} {β : Type v} -/-! ### Cofinality of orders -/ - -namespace Order -section Preorder -variable [Preorder α] - -variable (α) in -/-- The cofinality of a preorder is the smallest cardinality of a cofinal subset. -/ -def cof : Cardinal := - ⨅ s : {s : Set α // IsCofinal s}, #s - -theorem cof_le {s : Set α} (h : IsCofinal s) : cof α ≤ #s := - ciInf_le' (ι := {s : Set α // IsCofinal s}) _ ⟨s, h⟩ - -theorem le_lift_cof_iff {c : Cardinal.{max u v}} : - c ≤ lift.{v} (cof α) ↔ ∀ s : Set α, IsCofinal s → c ≤ lift.{v} #s := by - rw [cof, lift_iInf, le_ciInf_iff'] - simp - -theorem le_cof_iff {c : Cardinal} : c ≤ cof α ↔ ∀ s : Set α, IsCofinal s → c ≤ #s := by - simpa using @le_lift_cof_iff.{u, u} α _ c - -@[deprecated (since := "2026-02-18")] alias le_cof := le_cof_iff - -variable (α) in -theorem cof_eq : ∃ s : Set α, IsCofinal s ∧ #s = cof α := by - obtain ⟨s, hs⟩ := ciInf_mem fun s : {s : Set α // IsCofinal s} ↦ #s - exact ⟨s.1, s.2, hs⟩ - -variable (α) in -theorem cof_le_cardinalMk : cof α ≤ #α := - cof_le .univ |>.trans_eq mk_univ - -theorem cof_eq_zero_iff : cof α = 0 ↔ IsEmpty α := by - refine ⟨fun _ ↦ ?_, fun _ ↦ by simp [cof]⟩ - obtain ⟨s, hs, hs'⟩ := cof_eq α - simp_all [mk_eq_zero_iff, isCofinal_empty_iff] - -@[simp] -theorem cof_eq_zero [h : IsEmpty α] : cof α = 0 := - cof_eq_zero_iff.2 h - -theorem cof_ne_zero_iff : cof α ≠ 0 ↔ Nonempty α := by - simpa using cof_eq_zero_iff.not - -@[simp] -theorem cof_ne_zero [h : Nonempty α] : cof α ≠ 0 := - cof_ne_zero_iff.2 h - -theorem cof_eq_one_iff : cof α = 1 ↔ ∃ x : α, IsTop x := by - refine ⟨fun h ↦ ?_, fun ⟨t, ht⟩ ↦ ?_⟩ - · obtain ⟨s, hs, hs'⟩ := cof_eq α - rw [h, mk_set_eq_one_iff] at hs' - obtain ⟨t, rfl⟩ := hs' - use t - rwa [isCofinal_singleton_iff] at hs - · apply le_antisymm - · apply (cof_le (s := {t}) _).trans_eq (mk_singleton _) - rwa [isCofinal_singleton_iff] - · rw [Cardinal.one_le_iff_ne_zero, cof_ne_zero_iff] - use t - -@[simp] -theorem cof_eq_one [OrderTop α] : cof α = 1 := - cof_eq_one_iff.2 ⟨⊤, isTop_top⟩ - -theorem cof_ne_one_iff : cof α ≠ 1 ↔ NoTopOrder α := by - rw [← not_iff_not, not_not, noTopOrder_iff, cof_eq_one_iff] - simp - -@[simp] -theorem cof_ne_one [h : NoTopOrder α] : cof α ≠ 1 := - cof_ne_one_iff.2 h - -theorem cof_le_one_iff [Nonempty α] : cof α ≤ 1 ↔ ∃ x : α, IsTop x := by - rw [le_iff_lt_or_eq, Cardinal.lt_one_iff, cof_eq_one_iff] - simp - -theorem one_lt_cof_iff [Nonempty α] : 1 < cof α ↔ NoTopOrder α := by - rw [← not_iff_not, not_lt, noTopOrder_iff, cof_le_one_iff] - simp - -@[simp] -theorem one_lt_cof [Nonempty α] [h : NoTopOrder α] : 1 < cof α := - one_lt_cof_iff.2 h - -end Preorder - -section LinearOrder -variable [LinearOrder α] [LinearOrder β] [LinearOrder γ] - -theorem lift_cof_congr_of_strictMono {f : α → β} (hf : StrictMono f) (hf' : IsCofinal (range f)) : - lift.{v} (cof α) = lift.{u} (cof β) := by - apply le_antisymm <;> rw [le_lift_cof_iff] <;> intro s hs - · have H (x : s) : ∃ y : α, x ≤ f y := by simpa using hf' x - choose g hg using H - refine (lift_le.2 <| cof_le (s := range g) fun a ↦ ?_).trans mk_range_le_lift - obtain ⟨_, ⟨b, rfl⟩, hb⟩ := hf' (f a) - obtain ⟨c, hc, hc'⟩ := hs (f b) - refine ⟨_, Set.mem_range_self ⟨c, hc⟩, ?_⟩ - rw [← hf.le_iff_le] - exact hb.trans (hc'.trans (hg ⟨c, hc⟩)) - · exact (lift_le.2 <| cof_le (hs.image hf.monotone hf')).trans mk_image_le_lift - -theorem cof_congr_of_strictMono {f : α → γ} (hf : StrictMono f) (hf' : IsCofinal (range f)) : - cof α = cof γ := by - simpa using lift_cof_congr_of_strictMono hf hf' - -@[simp] -theorem cof_lt_aleph0_iff : Order.cof α < ℵ₀ ↔ Order.cof α ≤ 1 := by - refine ⟨fun h ↦ ?_, (lt_of_le_of_lt · one_lt_aleph0)⟩ - obtain ⟨s, hs, hs'⟩ := Order.cof_eq α - have hf : s.Finite := by - rw [Set.Finite, ← mk_lt_aleph0_iff] - exact hs'.trans_lt h - obtain ⟨t, ht, ht'⟩ := hf.exists_subsingleton_isCofinal hs - apply (cof_le ht').trans - simpa - -@[simp] -theorem aleph0_le_cof_iff : ℵ₀ ≤ Order.cof α ↔ 1 < Order.cof α := by - simp [← not_lt] - -@[simp] -theorem cof_eq_aleph0 [NoMaxOrder α] [Nonempty α] [Countable α] : cof α = ℵ₀ := - ((cof_le_cardinalMk _).trans mk_le_aleph0).antisymm (by simp) - -theorem cof_nat : cof ℕ = ℵ₀ := by simp -theorem cof_int : cof ℤ = ℵ₀ := by simp - -end LinearOrder -end Order - -section Congr -variable [Preorder α] [Preorder β] [Preorder γ] - -theorem GaloisConnection.cof_le_lift {f : β → α} {g : α → β} (h : GaloisConnection f g) : - Cardinal.lift.{u} (Order.cof β) ≤ Cardinal.lift.{v} (Order.cof α) := by - rw [le_lift_cof_iff] - exact fun s hs ↦ (lift_le.2 <| cof_le (h.map_isCofinal hs)).trans mk_image_le_lift - -theorem GaloisConnection.cof_le {f : γ → α} {g : α → γ} (h : GaloisConnection f g) : - Order.cof γ ≤ Order.cof α := by - simpa using h.cof_le_lift - -theorem OrderIso.lift_cof_congr (f : α ≃o β) : - Cardinal.lift.{v} (Order.cof α) = Cardinal.lift.{u} (Order.cof β) := - f.to_galoisConnection.cof_le_lift.antisymm (f.symm.to_galoisConnection.cof_le_lift) - -@[deprecated (since := "2026-03-20")] alias OrderIso.lift_cof_eq := OrderIso.lift_cof_congr - -theorem OrderIso.cof_congr (f : α ≃o γ) : Order.cof α = Order.cof γ := by - simpa using f.lift_cof_congr - -@[deprecated (since := "2026-03-20")] alias OrderIso.cof_eq := OrderIso.cof_congr - -@[deprecated (since := "2026-02-18")] alias RelIso.cof_eq_lift := OrderIso.lift_cof_congr -@[deprecated (since := "2026-02-18")] alias RelIso.cof_eq := OrderIso.cof_congr - -end Congr - -/-- If the union of `s` is cofinal and `s` is smaller than the cofinality, then `s` has a cofinal -member. -/ -theorem isCofinal_of_isCofinal_sUnion {α : Type*} [LinearOrder α] {s : Set (Set α)} - (h₁ : IsCofinal (⋃₀ s)) (h₂ : #s < Order.cof α) : ∃ x ∈ s, IsCofinal x := by - contrapose! h₂ - simp_rw [not_isCofinal_iff] at h₂ - choose f hf using h₂ - refine (cof_le (s := range fun x ↦ f x.1 x.2) fun a ↦ ?_).trans mk_range_le - obtain ⟨b, ⟨t, ht, hb⟩, hab⟩ := h₁ a - simpa using ⟨t, ht, hab.trans (hf t ht b hb).le⟩ - -/-- If the union of the `ι`-indexed family `s` is cofinal and `ι` is smaller than the cofinality, -then `s` has a cofinal member. -/ -theorem isCofinal_of_isCofinal_iUnion {α : Type*} {ι} [LinearOrder α] {s : ι → Set α} - (h₁ : IsCofinal (⋃ i, s i)) (h₂ : #ι < Order.cof α) : ∃ i, IsCofinal (s i) := by - rw [← sUnion_range] at h₁ - obtain ⟨_, ⟨i, rfl⟩, h⟩ := isCofinal_of_isCofinal_sUnion h₁ (mk_range_le.trans_lt h₂) - exact ⟨i, h⟩ +theorem Order.cof_int : cof ℤ = ℵ₀ := by simp /-! ### Cofinality of ordinals -/ diff --git a/Mathlib/SetTheory/Cardinal/Finite.lean b/Mathlib/SetTheory/Cardinal/Finite.lean index a5a8ff1613..9a618a494b 100644 --- a/Mathlib/SetTheory/Cardinal/Finite.lean +++ b/Mathlib/SetTheory/Cardinal/Finite.lean @@ -237,7 +237,7 @@ theorem card_sigma {β : α → Type*} [Fintype α] [∀ a, Finite (β a)] : simp_rw [Nat.card_eq_fintype_card, Fintype.card_sigma] theorem card_pi {β : α → Type*} [Fintype α] : Nat.card (∀ a, β a) = ∏ a, Nat.card (β a) := by - simp_rw [Nat.card, mk_pi, prod_eq_of_fintype, toNat_lift, map_prod] + simp_rw [Nat.card, mk_pi, prod_eq_of_fintype, toNat_lift, _root_.map_prod] theorem card_fun [Finite α] : Nat.card (α → β) = Nat.card β ^ Nat.card α := by haveI := Fintype.ofFinite α diff --git a/Mathlib/SetTheory/Cardinal/Ordinal.lean b/Mathlib/SetTheory/Cardinal/Ordinal.lean index a005c37126..bc8955f159 100644 --- a/Mathlib/SetTheory/Cardinal/Ordinal.lean +++ b/Mathlib/SetTheory/Cardinal/Ordinal.lean @@ -53,19 +53,21 @@ end Cardinal namespace Ordinal -theorem lift_card_iSup_le_sum_card {ι : Type u} [Small.{v} ι] (f : ι → Ordinal.{v}) : +theorem lift_card_iSup_le_sum_card {ι : Type u} (f : ι → Ordinal.{v}) : Cardinal.lift.{u} (⨆ i, f i).card ≤ Cardinal.sum fun i ↦ (f i).card := by + by_cases! hf : ¬ BddAbove (range f) + · simp [ciSup_of_not_bddAbove hf] simp_rw [← mk_toType] rw [← mk_sigma, ← Cardinal.lift_id'.{v} #(Σ _, _), ← Cardinal.lift_umax.{v, u}] apply lift_mk_le_lift_mk_of_surjective (f := .mk ∘ (⟨·.2.toOrd, - (mem_Iio.mp (ToType.toOrd _).2).trans_le (Ordinal.le_iSup _ _)⟩)) + (mem_Iio.mp (ToType.toOrd _).2).trans_le (le_ciSup hf _)⟩)) rw [EquivLike.comp_surjective] rintro ⟨x, hx⟩ - obtain ⟨i, hi⟩ := Ordinal.lt_iSup_iff.mp hx + obtain ⟨i, hi⟩ := (lt_ciSup_iff' hf).mp hx exact ⟨⟨i, .mk ⟨x, hi⟩⟩, by simp⟩ theorem card_iSup_le_sum_card {ι : Type u} (f : ι → Ordinal.{max u v}) : - (⨆ i, f i).card ≤ Cardinal.sum (fun i ↦ (f i).card) := by + (⨆ i, f i).card ≤ Cardinal.sum fun i ↦ (f i).card := by have := lift_card_iSup_le_sum_card f rwa [Cardinal.lift_id'] at this @@ -81,6 +83,45 @@ theorem card_iSup_Iio_le_card_mul_iSup {o : Ordinal.{u}} (f : Iio o → Ordinal. · exact mk_toType o · exact ToType.mk.symm.iSup_comp (g := fun x ↦ (f x).card) +theorem card_iSup_le_lift {ι : Type u} {c : Cardinal} {f : ι → Ordinal.{v}} + (hι : Cardinal.lift.{v} #ι ≤ Cardinal.lift.{u} c) (hf : ∀ i, (f i).card ≤ c) : + (⨆ i, f i).card ≤ c := by + by_cases! hc : c < ℵ₀ + · obtain ⟨n, rfl⟩ := lt_aleph0.1 hc + rw [card_le_nat] + refine ciSup_le' fun i ↦ ?_ + simpa using hf i + · rw [← Cardinal.lift_le.{u}] + apply (lift_card_iSup_le_sum_card ..).trans ((sum_le_lift_mk_mul_iSup_lift _).trans _) + rw [← mul_eq_self hc, Cardinal.lift_mul] + apply mul_le_mul' hι (ciSup_le' _) + simpa [← lift_card] + +theorem card_iSup_le {ι : Type*} {c : Cardinal} {f : ι → Ordinal} + (hι : #ι ≤ c) (hf : ∀ i, (f i).card ≤ c) : (⨆ i, f i).card ≤ c := by + rw [← Cardinal.lift_le] at hι + simpa using card_iSup_le_lift hι hf + +theorem card_iSup_Iio_le_of_lift {o : Ordinal.{u}} {c : Cardinal} {f : Iio o → Ordinal.{v}} + (hι : Cardinal.lift.{v} o.card ≤ Cardinal.lift.{u} c) (hf : ∀ i, (f i).card ≤ c) : + (⨆ i, f i).card ≤ c := by + apply card_iSup_le_lift _ hf + conv_rhs => rw [← Cardinal.lift_lift.{u, u + 1}] + rwa [Cardinal.mk_Iio_ordinal, Cardinal.lift_lift, ← Cardinal.lift_lift.{v, u + 1}, + Cardinal.lift_le] + +theorem card_iSup_Iio_le {o : Ordinal} {c : Cardinal} {f : Iio o → Ordinal} + (hι : o.card ≤ c) (hf : ∀ i, (f i).card ≤ c) : (⨆ i, f i).card ≤ c := by + rw [← Cardinal.lift_le] at hι + simpa using card_iSup_Iio_le_of_lift hι hf + +theorem card_sSup_le {c : Cardinal} {s : Set Ordinal.{u}} + (hs : #s ≤ Cardinal.lift.{u + 1} c) (hs' : ∀ x ∈ s, x.card ≤ c) : (sSup s).card ≤ c := by + rw [sSup_eq_iSup'] + apply card_iSup_le_lift + · rwa [Cardinal.lift_id'.{u, u + 1}] + · simpa + theorem card_opow_le_of_omega0_le_left {a : Ordinal} (ha : ω ≤ a) (b : Ordinal) : (a ^ b).card ≤ max a.card b.card := by refine limitRecOn b ?_ ?_ ?_ @@ -97,15 +138,8 @@ theorem card_opow_le_of_omega0_le_left {a : Ordinal} (ha : ω ≤ a) (b : Ordina · rwa [aleph0_le_card] · intro b hb IH rw [(isNormal_opow (one_lt_omega0.trans_le ha)).apply_of_isSuccLimit hb] - apply (card_iSup_Iio_le_card_mul_iSup _).trans - rw [Cardinal.lift_id, Cardinal.mul_eq_max_of_aleph0_le_right, max_comm] - · apply max_le _ (le_max_right _ _) - apply ciSup_le' - rintro ⟨c, (hcb : c < b)⟩ - grw [IH c hcb, hcb] - · simpa using hb.ne_bot - · exact le_ciSup_of_le Cardinal.bddAbove_of_small - ⟨1, one_lt_omega0.trans_le <| omega0_le_of_isSuccLimit hb⟩ (by simpa) + exact card_iSup_Iio_le (le_max_right ..) fun i ↦ + (IH i i.2).trans (max_le_max_left _ (card_le_card i.2.le)) theorem card_opow_le_of_omega0_le_right (a : Ordinal) {b : Ordinal} (hb : ω ≤ b) : (a ^ b).card ≤ max a.card b.card := by diff --git a/Mathlib/SetTheory/Cardinal/Regular.lean b/Mathlib/SetTheory/Cardinal/Regular.lean index a217f53550..d552b46b5e 100644 --- a/Mathlib/SetTheory/Cardinal/Regular.lean +++ b/Mathlib/SetTheory/Cardinal/Regular.lean @@ -5,7 +5,7 @@ Authors: Mario Carneiro, Floris van Doorn, Violeta Hernández Palacios, Nir Paz -/ module -public import Mathlib.SetTheory.Cardinal.Cofinality +public import Mathlib.SetTheory.Cardinal.Cofinality.Ordinal public import Mathlib.SetTheory.Ordinal.FixedPoint /-! diff --git a/Mathlib/SetTheory/Ordinal/FundamentalSequence.lean b/Mathlib/SetTheory/Ordinal/FundamentalSequence.lean index f76ca692f4..dac122e01d 100644 --- a/Mathlib/SetTheory/Ordinal/FundamentalSequence.lean +++ b/Mathlib/SetTheory/Ordinal/FundamentalSequence.lean @@ -5,7 +5,7 @@ Authors: Violeta Hernández Palacios, Mario Carneiro -/ module -public import Mathlib.SetTheory.Cardinal.Cofinality +public import Mathlib.SetTheory.Cardinal.Cofinality.Ordinal /-! # Fundamental sequences diff --git a/Mathlib/SetTheory/Ordinal/Univ.lean b/Mathlib/SetTheory/Ordinal/Univ.lean index 3b881c094b..fdb00da8c7 100644 --- a/Mathlib/SetTheory/Ordinal/Univ.lean +++ b/Mathlib/SetTheory/Ordinal/Univ.lean @@ -114,6 +114,11 @@ end Ordinal namespace Cardinal +@[simp] +theorem mk_ordinal : #Ordinal = univ.{u, u + 1} := + (lift_id _).symm + +@[deprecated mk_ordinal (since := "2026-04-22")] theorem univ_id : univ.{u, u + 1} = #Ordinal := lift_id _ @@ -168,7 +173,7 @@ theorem lt_univ {c} : c < univ.{u, u + 1} ↔ ∃ c', c = lift.{u + 1, u} c' := theorem lt_univ' {c} : c < univ.{u, v} ↔ ∃ c', c = lift.{max (u + 1) v, u} c' := ⟨fun h => by let ⟨a, h', e⟩ := lt_lift_iff.1 h - rw [← univ_id] at h' + rw [mk_ordinal] at h' rcases lt_univ.{u}.1 h' with ⟨c', rfl⟩ exact ⟨c', by simp only [e.symm, lift_lift]⟩, fun ⟨_, e⟩ => e.symm ▸ lift_lt_univ' _⟩ diff --git a/Mathlib/Tactic/FunProp/Core.lean b/Mathlib/Tactic/FunProp/Core.lean index 53d2456624..d49e135fa7 100644 --- a/Mathlib/Tactic/FunProp/Core.lean +++ b/Mathlib/Tactic/FunProp/Core.lean @@ -322,6 +322,17 @@ def applyMorRules (funPropDecl : FunPropDecl) (e : Expr) (fData : FunctionData) (funProp : Expr → FunPropM (Option Result)) : FunPropM (Option Result) := do trace[Debug.Meta.Tactic.fun_prop] "applying morphism theorems to {← ppExpr e}" + -- get theorems + let candidates ← getMorphismTheorems e + trace[Meta.Tactic.fun_prop] + "candidate morphism theorems: {← candidates.mapM fun c => ppOrigin (.decl c.thmName)}" + + -- try theorems + for c in candidates do + if let some r ← tryTheorem? e (.decl c.thmName) funProp then + return r + + -- if all failed try to add/remove arguments match ← fData.isMorApplication with | .none => throwError "fun_prop bug: invalid use of mor rules on {← ppExpr e}" | .underApplied => @@ -330,16 +341,6 @@ def applyMorRules (funPropDecl : FunPropDecl) (e : Expr) (fData : FunctionData) let some (f, g) ← fData.peeloffArgDecomposition | return none applyCompRule funPropDecl e f g funProp | .exact => - - let candidates ← getMorphismTheorems e - - trace[Meta.Tactic.fun_prop] - "candidate morphism theorems: {← candidates.mapM fun c => ppOrigin (.decl c.thmName)}" - - for c in candidates do - if let some r ← tryTheorem? e (.decl c.thmName) funProp then - return r - trace[Debug.Meta.Tactic.fun_prop] "no theorem matched" return none diff --git a/Mathlib/Tactic/FunProp/Theorems.lean b/Mathlib/Tactic/FunProp/Theorems.lean index ae0b183c48..a6dc7dcff9 100644 --- a/Mathlib/Tactic/FunProp/Theorems.lean +++ b/Mathlib/Tactic/FunProp/Theorems.lean @@ -358,8 +358,8 @@ def getTheoremFromConst (declName : Name) (prio : Nat := eval_prio default) : Me } -- todo: maybe do a little bit more careful detection of morphism and transition theorems match (← fData.isMorApplication) with - | .exact => return .mor thm - | .underApplied | .overApplied => + | .exact | .overApplied => return .mor thm + | .underApplied => throwError "fun_prop theorem about morphism coercion has to be in fully applied form" | .none => if fData.fn.isFVar && (fData.args.size == 1) && diff --git a/Mathlib/Tactic/GCongr/Core.lean b/Mathlib/Tactic/GCongr/Core.lean index 725b16cfbb..419d3b8035 100644 --- a/Mathlib/Tactic/GCongr/Core.lean +++ b/Mathlib/Tactic/GCongr/Core.lean @@ -228,7 +228,7 @@ def getRel (e : Expr) : Option (Name × Expr × Expr) := none | _ => none -/-- If `e` is of the form `r a b`, replace either `a` or `b` with `e`. -/ +/-- If `r` is of the form `rel a b`, replace either `a` or `b` with `e`. -/ def updateRel (r e : Expr) (isLhs : Bool) : Expr := match r with | .forallE _ d b _ => if isLhs then r.updateForallE! e b else r.updateForallE! d e @@ -517,7 +517,7 @@ lemma rel_imp_rel (h₁ : r c a) (h₂ : r b d) : r a b → r c d := Construct a `GCongrLemma` for `gcongr` goals of the form `a ≺ b → c ≺ d`. This will be tried if there is no other available `@[gcongr]` lemma. For example, the relation `a ≡ b [ZMOD n]` has an instance of `IsTrans`, so a congruence of the form -`a ≡ b [ZMOD n] → c ≡ d [ZMOD n]` can be solved with `rel_imp_rel`, `rel_trans` or `rel_trans'`. +`a ≡ b [ZMOD n] → c ≡ d [ZMOD n]` can be solved with `rel_imp_rel`. -/ def relImpRelLemma (arity : Nat) : List GCongrLemma := if arity < 2 then [] else [{ diff --git a/Mathlib/Tactic/Translate/Core.lean b/Mathlib/Tactic/Translate/Core.lean index 5857d6b791..d4bf5141cf 100644 --- a/Mathlib/Tactic/Translate/Core.lean +++ b/Mathlib/Tactic/Translate/Core.lean @@ -224,9 +224,9 @@ structure TranslateData : Type where changeNumeral : Bool /-- When `isDual := true`, every translation `A → B` will also give a translation `B → A`. -/ isDual : Bool - guessNameData : GuessName.GuessNameData + guessNameExt : GuessName.GuessNameExt -attribute [inherit_doc GuessName.GuessNameData] TranslateData.guessNameData +attribute [inherit_doc GuessName.GuessNameExt] TranslateData.guessNameExt /-- Get the translation for the given name. -/ def findTranslation? (env : Environment) (t : TranslateData) : Name → Option TranslationInfo := @@ -302,7 +302,7 @@ where Unless the original translation was wrong, please remove this `{t.attrName}` attribute." modifyEnv (t.translations.addEntry · (src, info)) trace[translate] "Added translation {src} ↦ {tgt}\ - {if info.reorder.reorder.isEmpty then "" else s!" (reorder := {info.reorder.reorder})}"} \ + {if info.reorder.reorder.isEmpty then "" else s!" (reorder := {info.reorder.reorder})"} \ (relevant_arg := {info.relevantArg})" /-- `Config` is the type of the arguments that can be provided to `to_additive`. -/ @@ -557,15 +557,16 @@ where return tmpLCtx.mkLambda (usedLetOnly := false) fvars e /-- Rename binder names in pi type. -/ -def renameBinderNames (t : TranslateData) (rename : NameMap Name) (src : Expr) : Expr := +def renameBinderNames (data : GuessName.GuessNameData) (rename : NameMap Name) + (src : Expr) : Expr := src.mapForallBinderNames fun n => (rename.get? n).getD <| match n with | .str p s => .str p <| - let s' := GuessName.guessName t.guessNameData s + let s' := GuessName.guessName data s if s' != s then s' else -- If the name starts with `h`, translate the rest of the name, e.g. `hmax` ↦ `hmin`. if let some suffix := s.dropPrefix? 'h' then - "h" ++ GuessName.guessName t.guessNameData suffix.toString + "h" ++ GuessName.guessName data suffix.toString else s | n => n @@ -633,7 +634,8 @@ def updateDecl (t : TranslateData) (tgt : Name) (srcDecl : ConstantInfo) let mut type := decl.type if let some b := unfoldBoundaries? then type ← b.insertBoundaries decl.type t.attrName - let (type', relevantArg₂) ← applyReplacementForall t dont <| renameBinderNames t rename type + let (type', relevantArg₂) ← applyReplacementForall t dont <| + renameBinderNames (t.guessNameExt.getState (← getEnv)) rename type type ← reorderForall reorder.reorder type' if let some b := unfoldBoundaries? then type ← b.unfoldInsertions type @@ -911,7 +913,7 @@ def targetName (t : TranslateData) (cfg : Config) (src : Name) : CoreM Name := d return tgt let .str pre s := src | throwError "{t.attrName}: can't transport {src}" trace[translate_detail] "The name {s} splits as {open GuessName in s.splitCase}" - let tgt_auto := GuessName.guessName t.guessNameData s + let tgt_auto := GuessName.guessName (t.guessNameExt.getState (← getEnv)) s let depth := cfg.tgt.getNumParts let pre := translateNamespace (← getEnv) pre let (pre1, pre2) := pre.splitAt (depth - 1) diff --git a/Mathlib/Tactic/Translate/GuessName.lean b/Mathlib/Tactic/Translate/GuessName.lean index f3b8355f8c..5f466e2572 100644 --- a/Mathlib/Tactic/Translate/GuessName.lean +++ b/Mathlib/Tactic/Translate/GuessName.lean @@ -15,7 +15,7 @@ public import Mathlib.Init public meta section -open Std +open Lean Std namespace Mathlib.Tactic.GuessName open GuessName -- currently needed to enable projection notation @@ -40,6 +40,7 @@ structure GuessNameData where When applying the dictionary, we lower-case the output if the input was also given in lower-case. -/ abbreviationDict : Std.HashMap String String + deriving Inhabited /-- A set of strings of names that end in a capital letter. * If the string contains a lowercase letter, the string should be split between the first occurrence @@ -176,4 +177,27 @@ def guessName (g : GuessNameData) : String → String := applyNameDict g <| s.splitCase +/-- Environment extension used for guessing the translation of a name. -/ +abbrev GuessNameExt := EnvExtension GuessNameData + +/-- Register a new `GuessNameExt`. -/ +def registerGuessNameExt (data : GuessNameData) : IO GuessNameExt := do + registerEnvExtension (pure data) + +/-- Add the translation `src ↦ tgt` to the `GuessNameExt`. +Both `src` and `tgt` should be capitalized. +This change persists until the end of the current file, but it does not persist through imports. -/ +def GuessNameExt.addTranslation (ext : GuessNameExt) (srcId tgtId : Ident) : + Elab.Command.CommandElabM Unit := do + let src := srcId.getId.toString + let tgt := tgtId.getId.toString + unless src.front.isUpper do throwErrorAt srcId "`{src}` should be capitalized" + unless tgt.front.isUpper do throwErrorAt tgtId "`{tgt}` should be capitalized" + modifyEnv fun env ↦ ext.modifyState env fun data ↦ + let src := src.decapitalizeSeq + if src.splitCase matches [_] then + { data with nameDict := data.nameDict.insert src tgt.splitCase } + else + { data with abbreviationDict := data.abbreviationDict.insert src tgt } + end Mathlib.Tactic.GuessName diff --git a/Mathlib/Tactic/Translate/ToAdditive.lean b/Mathlib/Tactic/Translate/ToAdditive.lean index 4c5243baec..fa0829532e 100644 --- a/Mathlib/Tactic/Translate/ToAdditive.lean +++ b/Mathlib/Tactic/Translate/ToAdditive.lean @@ -378,14 +378,19 @@ def abbreviationDict : Std.HashMap String String := .ofList [ ("subNegZeroAddMonoid", "SubNegZeroMonoid"), ("modularCharacter", "AddModularCharacter"), ("isQuotientCoveringMap", "IsAddQuotientCoveringMap"), - ("addExact", "exact"), + ("addExact", "Exact"), ("isMonHom", "IsAddMonHom"), ("mapMon", "MapAddMon"), ("monObj", "AddMonObj"), ("isModHom", "IsAddModHom"), ("mapMod", "MapAddMod"), ("modObj", "AddModObj"), - ("yonedaMon", "yonedaAddMon")] + ("yonedaMon", "YonedaAddMon"), + ("conGen", "AddConGen")] + +@[inherit_doc GuessName.GuessNameExt] +initialize guessNameExt : GuessName.GuessNameExt ← + GuessName.registerGuessNameExt { nameDict, abbreviationDict } /-- The bundle of environment extensions for `to_additive` -/ def data : TranslateData where @@ -393,7 +398,7 @@ def data : TranslateData where attrName := `to_additive changeNumeral := true isDual := false - guessNameData := { nameDict, abbreviationDict } + guessNameExt initialize registerBuiltinAttribute { name := `to_additive @@ -411,4 +416,9 @@ have a corresponding translated declaration. -/ elab "insert_to_additive_translation" src:ident tgt:ident : command => do translations.add src.getId { translation := tgt.getId } +/-- `to_additive_name_hint src tgt` lets `to_additive` translate the name segment `src` to `tgt` +for the rest of the file current. `src` and `tgt` should both be capitalized. -/ +elab "to_additive_name_hint" src:ident tgt:ident : command => do + guessNameExt.addTranslation src tgt + end Mathlib.Tactic.ToAdditive diff --git a/Mathlib/Tactic/Translate/ToDual.lean b/Mathlib/Tactic/Translate/ToDual.lean index 223911f2cd..cca3403ebd 100644 --- a/Mathlib/Tactic/Translate/ToDual.lean +++ b/Mathlib/Tactic/Translate/ToDual.lean @@ -181,8 +181,6 @@ def nameDict : Std.HashMap String (List String) := .ofList [ ("iic", ["Ici"]), ("ioc", ["Ico"]), ("ico", ["Ioc"]), - ("u", ["L"]), - ("l", ["U"]), ("next", ["Prev"]), ("prev", ["Next"]), ("heyting", ["Coheyting"]), @@ -256,6 +254,11 @@ def abbreviationDict : Std.HashMap String String := .ofList [ ("decidableSucc", "DecidablePred"), ] +@[inherit_doc GuessName.GuessNameExt] +initialize guessNameExt : GuessName.GuessNameExt ← + GuessName.registerGuessNameExt { nameDict, abbreviationDict } + + /-- The bundle of environment extensions for `to_dual` -/ def data : TranslateData where ignoreArgsAttr; doTranslateAttr; translations @@ -263,7 +266,7 @@ def data : TranslateData where attrName := `to_dual changeNumeral := false isDual := true - guessNameData := { nameDict, abbreviationDict } + guessNameExt /-- The `to_dual_insert_cast` attribute is used to tag declarations `foo` that should not be unfolded in a proof that is translated. Instead, a rewrite with an equality theorem is inserted. @@ -286,4 +289,10 @@ initialize registerBuiltinAttribute { applicationTime := .afterCompilation } +/-- `to_dual_name_hint src tgt` lets `to_dual` translate between the name segments `src` and `tgt` +for the rest of the file current. `src` and `tgt` should both be capitalized. -/ +elab "to_dual_name_hint" src:ident tgt:ident : command => do + guessNameExt.addTranslation src tgt + guessNameExt.addTranslation tgt src + end Mathlib.Tactic.ToDual diff --git a/Mathlib/Topology/Algebra/ContinuousAffineMap.lean b/Mathlib/Topology/Algebra/ContinuousAffineMap.lean index 8d123a7660..901f4bf7b5 100644 --- a/Mathlib/Topology/Algebra/ContinuousAffineMap.lean +++ b/Mathlib/Topology/Algebra/ContinuousAffineMap.lean @@ -400,7 +400,7 @@ def prod (f : P₁ →ᴬ[k] P₂) (g : P₁ →ᴬ[k] P₃) : P₁ →ᴬ[k] P __ := AffineMap.prod f g cont := by eta_expand; dsimp; fun_prop -theorem coe_prod (f : P₁ →ᴬ[k] P₂) (g : P₁ →ᴬ[k] P₃) : prod f g = Pi.prod f g := +theorem coe_prod (f : P₁ →ᴬ[k] P₂) (g : P₁ →ᴬ[k] P₃) : prod f g = Function.prod f g := rfl @[simp] diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean b/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean index 9062eda5f0..c680957af6 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean @@ -221,7 +221,7 @@ protected theorem HasProd.map [CommMonoid γ] [TopologicalSpace γ] (hf : HasPro protected theorem Topology.IsInducing.hasProd_iff [CommMonoid γ] [TopologicalSpace γ] {G} [FunLike G α γ] [MonoidHomClass G α γ] {g : G} (hg : IsInducing g) (f : β → α) (a : α) : HasProd (g ∘ f) (g a) L ↔ HasProd f a L := by - simp_rw [HasProd, comp_apply, ← map_prod] + simp_rw [HasProd, comp_apply, ← _root_.map_prod] exact hg.tendsto_nhds_iff.symm @[to_additive] @@ -261,7 +261,7 @@ lemma Topology.IsClosedEmbedding.map_tprod {ι α α' G : Type*} simp only [Multipliable, HasProd] at h ⊢ obtain ⟨b, hb⟩ := h obtain ⟨a, ha⟩ : b ∈ Set.range g := - hge.isClosed_range.mem_of_tendsto hb (.of_forall <| by simp [← map_prod]) + hge.isClosed_range.mem_of_tendsto hb (.of_forall <| by simp [← _root_.map_prod]) use a simp [hge.tendsto_nhds_iff, Function.comp_def, ha, hb] · simpa [tprod_bot hL] using @@ -288,7 +288,7 @@ lemma Topology.IsInducing.multipliable_iff_tprod_comp_mem_range [CommMonoid γ] · by_cases hL : L.NeBot · exact ⟨_, hf.map_tprod g hg.continuous⟩ · by_cases hfs : (mulSupport fun x ↦ g (f x)).Finite - · simp [tprod_bot hL, finprod_eq_prod _ hfs, ← map_prod] + · simp [tprod_bot hL, finprod_eq_prod _ hfs, ← _root_.map_prod] · exact ⟨1, by simp [tprod_bot hL, finprod_of_infinite_mulSupport hfs]⟩ · rintro ⟨hgf, a, ha⟩ use a diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Constructions.lean b/Mathlib/Topology/Algebra/InfiniteSum/Constructions.lean index 1be2234cb6..0f29cf7e43 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Constructions.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Constructions.lean @@ -274,7 +274,7 @@ variable {ι : Type*} {X : α → Type*} [∀ x, CommMonoid (X x)] [∀ x, Topol @[to_additive] theorem Pi.hasProd {f : ι → ∀ x, X x} {g : ∀ x, X x} : HasProd f g L ↔ ∀ x, HasProd (fun i ↦ f i x) (g x) L := by - simp only [HasProd, tendsto_pi_nhds, prod_apply] + simp only [HasProd, tendsto_pi_nhds, Finset.prod_apply] @[to_additive] theorem Pi.multipliable {f : ι → ∀ x, X x} : diff --git a/Mathlib/Topology/Inseparable.lean b/Mathlib/Topology/Inseparable.lean index 956b0bfc78..ec597005b3 100644 --- a/Mathlib/Topology/Inseparable.lean +++ b/Mathlib/Topology/Inseparable.lean @@ -483,7 +483,7 @@ theorem subtype_inseparable_iff {p : X → Prop} (x y : Subtype p) : (x ~ᵢ y) @[simp] theorem inseparable_prod {x₁ x₂ : X} {y₁ y₂ : Y} : ((x₁, y₁) ~ᵢ (x₂, y₂)) ↔ (x₁ ~ᵢ x₂) ∧ (y₁ ~ᵢ y₂) := by - simp only [Inseparable, nhds_prod_eq, prod_inj] + simp only [Inseparable, nhds_prod_eq, Filter.prod_inj] theorem Inseparable.prod {x₁ x₂ : X} {y₁ y₂ : Y} (hx : x₁ ~ᵢ x₂) (hy : y₁ ~ᵢ y₂) : (x₁, y₁) ~ᵢ (x₂, y₂) := diff --git a/Mathlib/Topology/Instances/ENNReal/ENatENNReal.lean b/Mathlib/Topology/Instances/ENNReal/ENatENNReal.lean new file mode 100644 index 0000000000..c8bfca567f --- /dev/null +++ b/Mathlib/Topology/Instances/ENNReal/ENatENNReal.lean @@ -0,0 +1,32 @@ +/- +Copyright (c) 2026 Weiyi Wang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Weiyi Wang +-/ +module + +public import Mathlib.Data.Real.ENatENNReal +public import Mathlib.Topology.Instances.ENat +public import Mathlib.Topology.Instances.ENNReal.Lemmas +import Mathlib.Algebra.Order.Floor.Extended + +/-! +# Topology lemma for `ENat.toENNReal` + +This file shows `ENat.toENNReal` is a closed embedding. +-/ + +public section + +namespace ENat + +@[continuity] +theorem continuous_toENNReal : Continuous toENNReal := by + refine OrderTopology.continuous_iff.mpr fun a ↦ ⟨?_, ?_⟩ + · simpa using isOpen_Ioi + · simpa using isOpen_Iio + +theorem isClosedEmbedding_toENNReal : Topology.IsClosedEmbedding toENNReal := + continuous_toENNReal.isClosedEmbedding toENNReal_strictMono.injective + +end ENat diff --git a/Mathlib/Topology/Sets/VietorisTopology.lean b/Mathlib/Topology/Sets/VietorisTopology.lean index b865f743cf..5f6df6e1a3 100644 --- a/Mathlib/Topology/Sets/VietorisTopology.lean +++ b/Mathlib/Topology/Sets/VietorisTopology.lean @@ -281,18 +281,40 @@ theorem _root_.IsCompact.powerset_vietoris {K : Set α} (hK : IsCompact K) : instance [CompactSpace α] : CompactSpace (Set α) := ⟨powerset_univ ▸ isCompact_univ.powerset_vietoris⟩ +theorem subset_closure_of_specializes {s t : Set α} (h : s ⤳ t) : t ⊆ closure s := + h.mem_closed isClosed_closure.powerset_vietoris subset_closure + +theorem specializes_iff {s t : Set α} : s ⤳ t ↔ (∀ x ∈ s, ∃ y ∈ t, x ⤳ y) ∧ t ⊆ closure s := by + refine ⟨fun h => ⟨fun x hx => ?_, subset_closure_of_specializes h⟩, fun ⟨hst, hts⟩ => ?_⟩ + · obtain ⟨y, hyt, hxy⟩ := h.mem_closed (s := {u | (u ∩ closure {x}).Nonempty}) + (isClosed_inter_nonempty_of_isClosed isClosed_closure) ⟨x, hx, subset_closure rfl⟩ + exact ⟨y, hyt, specializes_iff_mem_closure.mpr hxy⟩ + · simp_rw [Specializes, nhds_generateFrom, le_iInf₂_iff] + rintro _ ⟨hs, ⟨U, hU, rfl⟩ | ⟨U, hU, rfl⟩⟩ + · refine iInf₂_le U.powerset ⟨fun x hx => ?_, .inl <| mem_image_of_mem _ hU⟩ + obtain ⟨y, hyt, hxy⟩ := hst x hx + exact hxy.mem_open hU <| hs hyt + · obtain ⟨x, hxt, hxU⟩ := hs + obtain ⟨y, hyU, hys⟩ := mem_closure_iff.mp (hts hxt) U hU hxU + exact iInf₂_le {t | (t ∩ U).Nonempty} ⟨⟨y, hys, hyU⟩, .inr <| mem_image_of_mem _ hU⟩ + +theorem specializes_iff_of_t1Space {s t : Set α} [T1Space α] : s ⤳ t ↔ s ⊆ t ∧ t ⊆ closure s := by + simp_rw [specializes_iff, specializes_iff_eq, existsAndEq, and_true, ← subset_def] + +theorem subset_of_specializes {s t : Set α} [T1Space α] (h : s ⤳ t) : s ⊆ t := + (specializes_iff_of_t1Space.mp h).1 + theorem specializes_of_subset_closure {s t : Set α} (hst : s ⊆ t) (hts : t ⊆ closure s) : s ⤳ t := by - simp_rw [Specializes, nhds_generateFrom, le_iInf₂_iff] - rintro _ ⟨hs, ⟨U, hU, rfl⟩ | ⟨U, hU, rfl⟩⟩ - · exact iInf₂_le U.powerset ⟨hst.trans hs, .inl <| mem_image_of_mem _ hU⟩ - · obtain ⟨x, hxt, hxU⟩ := hs - obtain ⟨y, hyU, hys⟩ := mem_closure_iff.mp (hts hxt) U hU hxU - exact iInf₂_le {t | (t ∩ U).Nonempty} ⟨⟨y, hys, hyU⟩, .inr <| mem_image_of_mem _ hU⟩ + aesop (add simp specializes_iff) theorem specializes_closure {s : Set α} : s ⤳ closure s := specializes_of_subset_closure subset_closure .rfl +instance [T1Space α] : T0Space (Set α) where + t0 _ _ h := + subset_antisymm (subset_of_specializes h.specializes) (subset_of_specializes h.specializes') + end vietoris namespace Compacts @@ -456,6 +478,54 @@ instance [DiscreteTopology α] : DiscreteTopology (Compacts α) := by theorem discreteTopology_iff : DiscreteTopology (Compacts α) ↔ DiscreteTopology α := ⟨fun _ => isEmbedding_singleton.discreteTopology, fun _ => inferInstance⟩ +instance [T1Space α] : T0Space (Compacts α) := + isEmbedding_coe.t0Space + +instance [T2Space α] : T2Space (Compacts α) where + t2 K₁ K₂ h := by + wlog h' : ¬(K₁ ≤ K₂) generalizing K₁ K₂ + · grind [Disjoint.symm, le_antisymm] + rw [SetLike.not_le_iff_exists] at h' + obtain ⟨x, hx₁, hx₂⟩ := h' + obtain ⟨U, V, hU, hV, hU', hV', hUV⟩ := K₂.isCompact.separation_of_notMem hx₂ + exact ⟨_, _, isOpen_inter_nonempty_of_isOpen hV, isOpen_subsets_of_isOpen hU, ⟨x, hx₁, hV'⟩, + hU', by grind [Set.Nonempty]⟩ + +@[simp] +theorem t2Space_iff : T2Space (Compacts α) ↔ T2Space α := + ⟨fun _ => isEmbedding_singleton.t2Space, fun _ => inferInstance⟩ + +instance [RegularSpace α] : RegularSpace (Compacts α) := by + simp_rw [regularSpace_generateFrom induced_generateFrom_eq, image_union, image_image, powerset, + preimage_setOf_eq, Filter.disjoint_iff] + rintro _ (⟨U, hU, rfl⟩ | ⟨U, hU, rfl⟩) K hK + · obtain ⟨V, W, hV, hW, hKV, hUW, hVW⟩ := + SeparatedNhds.of_isCompact_isClosed K.isCompact hU.isClosed_compl + (disjoint_compl_right_iff_subset.mpr hK) + refine ⟨{K | (↑K ∩ W).Nonempty}, ?_, {K | ↑K ⊆ V}, + (isOpen_subsets_of_isOpen hV).mem_nhds_iff.mpr hKV, by grind [Set.Nonempty]⟩ + simp_rw [(isOpen_inter_nonempty_of_isOpen hW).mem_nhdsSet, compl_setOf, + ← inter_compl_nonempty_iff] + grw [hUW] + · obtain ⟨x, hx₁, hx₂⟩ := hK + obtain ⟨V, W, hV, hW, hxV, hUW, hVW⟩ := + SeparatedNhds.of_isCompact_isClosed (isCompact_singleton (x := x)) hU.isClosed_compl + (by simpa) + refine ⟨{K | ↑K ⊆ W}, ?_, {K | (↑K ∩ V).Nonempty}, ?_, by grind [Set.Nonempty]⟩ + · simp_rw [(isOpen_subsets_of_isOpen hW).mem_nhdsSet, compl_setOf, not_nonempty_iff_eq_empty, + ← disjoint_iff_inter_eq_empty, ← subset_compl_iff_disjoint_right] + gcongr + · rw [(isOpen_inter_nonempty_of_isOpen hV).mem_nhds_iff] + exact ⟨x, hx₁, hxV <| Set.mem_singleton x⟩ + +@[simp] +theorem regularSpace_iff : RegularSpace (Compacts α) ↔ RegularSpace α := + ⟨fun _ => isEmbedding_singleton.regularSpace, fun _ => inferInstance⟩ + +@[simp] +theorem t3Space_iff : T3Space (Compacts α) ↔ T3Space α := + ⟨fun _ => isEmbedding_singleton.t3Space, fun _ => inferInstance⟩ + theorem isCompact_subsets_of_isCompact {K : Set α} (hK : IsCompact K) : IsCompact {L : Compacts α | ↑L ⊆ K} := by rw [isEmbedding_coe.isCompact_iff] @@ -679,6 +749,27 @@ instance [DiscreteTopology α] : DiscreteTopology (NonemptyCompacts α) := theorem discreteTopology_iff : DiscreteTopology (NonemptyCompacts α) ↔ DiscreteTopology α := ⟨fun _ => isEmbedding_singleton.discreteTopology, fun _ => inferInstance⟩ +instance [T1Space α] : T0Space (NonemptyCompacts α) := + isEmbedding_toCompacts.t0Space + +instance [T2Space α] : T2Space (NonemptyCompacts α) := + isEmbedding_toCompacts.t2Space + +@[simp] +theorem t2Space_iff : T2Space (NonemptyCompacts α) ↔ T2Space α := + ⟨fun _ => isEmbedding_singleton.t2Space, fun _ => inferInstance⟩ + +instance [RegularSpace α] : RegularSpace (NonemptyCompacts α) := + isEmbedding_toCompacts.regularSpace + +@[simp] +theorem regularSpace_iff : RegularSpace (NonemptyCompacts α) ↔ RegularSpace α := + ⟨fun _ => isEmbedding_singleton.regularSpace, fun _ => inferInstance⟩ + +@[simp] +theorem t3Space_iff : T3Space (NonemptyCompacts α) ↔ T3Space α := + ⟨fun _ => isEmbedding_singleton.t3Space, fun _ => inferInstance⟩ + instance [CompactSpace α] : CompactSpace (NonemptyCompacts α) := isClosedEmbedding_toCompacts.compactSpace diff --git a/Mathlib/Topology/UniformSpace/LocallyUniformConvergence.lean b/Mathlib/Topology/UniformSpace/LocallyUniformConvergence.lean index 2170661fd4..c86814c50b 100644 --- a/Mathlib/Topology/UniformSpace/LocallyUniformConvergence.lean +++ b/Mathlib/Topology/UniformSpace/LocallyUniformConvergence.lean @@ -208,7 +208,7 @@ theorem TendstoLocallyUniformlyOn.prodMk [UniformSpace γ] {G : ι → α → γ theorem TendstoLocallyUniformlyOn.piProd [UniformSpace γ] {G : ι → α → γ} {g : α → γ} (hF : TendstoLocallyUniformlyOn F f p s) (hG : TendstoLocallyUniformlyOn G g p s) : - TendstoLocallyUniformlyOn (fun n ↦ Pi.prod (F n) (G n)) (Pi.prod f g) p s := + TendstoLocallyUniformlyOn (fun n ↦ Function.prod (F n) (G n)) (Function.prod f g) p s := hF.prodMk hG theorem TendstoLocallyUniformly.prodMk [UniformSpace γ] {G : ι → α → γ} {g : α → γ} @@ -219,7 +219,7 @@ theorem TendstoLocallyUniformly.prodMk [UniformSpace γ] {G : ι → α → γ} theorem TendstoLocallyUniformly.piProd [UniformSpace γ] {G : ι → α → γ} {g : α → γ} (hF : TendstoLocallyUniformly F f p) (hG : TendstoLocallyUniformly G g p) : - TendstoLocallyUniformly (fun n ↦ Pi.prod (F n) (G n)) (Pi.prod f g) p := + TendstoLocallyUniformly (fun n ↦ Function.prod (F n) (G n)) (Function.prod f g) p := hF.prodMk hG /-- If every `x ∈ s` has a neighbourhood within `s` on which `F i` tends uniformly to `f`, then diff --git a/MathlibTest/StepInduction.lean b/MathlibTest/StepInduction.lean new file mode 100644 index 0000000000..3c3b7d7cfd --- /dev/null +++ b/MathlibTest/StepInduction.lean @@ -0,0 +1,46 @@ +module + +import Mathlib.Data.Nat.Fib.Basic + +/-! +The examples below are ported from the [Rocq supplementary material](https://zenodo.org/records/13855491) +accompanying Olivier Danvy's "[Nested Summations](https://doi.org/10.1145/3694848.3694858)". +-/ + +open Nat Finset + +def fibf (f : ℕ → ℕ) : ℕ → ℕ + | 0 => f 0 + | 1 => f 1 + | n + 2 => fibf f (n + 1) + fibf f n + +example {f : ℕ → ℕ} {n : ℕ} : fibf f (n + 1) = f 1 * fib (n + 1) + f 0 * fib n := by + induction n using stepInduction 2 with + | base n hn => + obtain rfl | rfl : n = 0 ∨ n = 1 := by lia + all_goals simp [fibf] + | step n ih => grind [fibf, fib_add_two, ih 0 (by decide)] + +def a6356 : ℕ → ℕ + | 0 => 1 + | 1 => 3 + | 2 => 6 + | n + 3 => 2 * a6356 (n + 2) + a6356 (n + 1) - a6356 n + +def a6356Sum (f : ℕ → ℕ) : ℕ → ℕ → ℕ + | 0, i => f (2 - i) + | n + 1, i => ∑ j ∈ range (3 - i), a6356Sum f n j + +lemma strictMono_a6356 : StrictMono a6356 := by + refine strictMono_nat_of_lt_succ fun n ↦ ?_ + induction n using stepInduction 3 with + | base n hn => decide +revert + | step n ih => grind [a6356] + +example {n : ℕ} : a6356Sum (· - 1) (n + 1) 0 = a6356 n := by + induction n using stepInduction 3 with + | base n hn => decide +revert + | step n ih => + have := strictMono_a6356 (lt_add_one n) + rw [← add_left_inj (a6356 n), a6356, Nat.sub_add_cancel (by lia)] + grind [sum_range_succ, sum_range_one, a6356Sum, ih 0 (by decide)] diff --git a/MathlibTest/ToDual.lean b/MathlibTest/ToDual.lean index b22bc4eba8..64d779c246 100644 --- a/MathlibTest/ToDual.lean +++ b/MathlibTest/ToDual.lean @@ -418,3 +418,22 @@ class Category.{v,u} (c : Type u) where @[to_dual self (reorder := A B, 2 4)] structure Comma {A : Type u} [Category.{v} A] {B : Type u'} [Category.{v'} B] where + +open Mathlib.Tactic Translate ToDual + +/-- info: "leftMono" -/ +#guard_msgs in +#eval return GuessName.guessName (data.guessNameExt.getState (← getEnv)) "leftMono" + +to_dual_name_hint LeftMono FooBar + +/-- info: "fooBar" -/ +#guard_msgs in +#eval return GuessName.guessName (data.guessNameExt.getState (← getEnv)) "leftMono" + +to_dual_name_hint Left Right +to_dual_name_hint Epi Mono + +/-- info: "right_epi" -/ +#guard_msgs in +#eval return GuessName.guessName (data.guessNameExt.getState (← getEnv)) "left_mono" diff --git a/MathlibTest/fun_prop_dev.lean b/MathlibTest/fun_prop_dev.lean index 0b2d0e95fa..a2c6252f06 100644 --- a/MathlibTest/fun_prop_dev.lean +++ b/MathlibTest/fun_prop_dev.lean @@ -699,3 +699,36 @@ example (hX : ∀ i, Lin' (X i)) : Lin (fun ω i ↦ X i ω) := by -- failed in https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/Weird.20behavior.20of.20fun_prop end MVarBug + +section BundledMorphismWithFunctionValues + +structure FooHom (α : Type*) where + toFun : α → α → α + cont' : Con (Function.uncurry toFun) + +instance : FunLike (FooHom α) α (α → α) where + coe f := f.toFun + coe_injective' f g h := by cases f; cases g; congr + +@[fun_prop] +theorem con_foohom' {β : Type*} {f : β → FooHom α} (hf : Con f) {g₁ : β → α} (hg₁ : Con g₁) + {g₂ : β → α} (hg₂ : Con g₂) : Con fun x ↦ (f x) (g₁ x) (g₂ x) := silentSorry + +example {f : FooHom α} : Con fun x => f x x := by fun_prop + +example {f : FooHom α} (y : α) : Con fun x => f x y := by fun_prop + +example {f : FooHom α} : Con fun x => f (f x x) x := by fun_prop + +example {f : FooHom (Fin 2 → α)} : Con fun x i => f (f (fun _ => x 0) x) x i := by fun_prop + +example {f : FooHom (Fin 2 → α)} (i) : Con fun x => f (f (fun _ => x 0) x) x i := by fun_prop + +example {f : α → FooHom α} (hf : Con (fun x : α × α × α => f x.1 x.2.1 x.2.2)) : + Con fun x ↦ f x x x := by + fun_prop + +example {f : α → FooHom α} (hf : Con f) : Con fun x ↦ f x (f x x x) x := by + fun_prop + +end BundledMorphismWithFunctionValues