diff --git a/Archive/Wiedijk100Theorems/AbelRuffini.lean b/Archive/Wiedijk100Theorems/AbelRuffini.lean index 23333e7ac08fff..9e686d91399255 100644 --- a/Archive/Wiedijk100Theorems/AbelRuffini.lean +++ b/Archive/Wiedijk100Theorems/AbelRuffini.lean @@ -11,29 +11,25 @@ import Mathlib.RingTheory.Int.Basic import Mathlib.RingTheory.RootsOfUnity.Minpoly /-! -# Construction of an algebraic number that is not solvable by radicals. +# Construction of an algebraic number that is not solvable by radicals The main ingredients are: -* `solvableByRad.isSolvable'` in `Mathlib/FieldTheory/AbelRuffini.lean` : - an irreducible polynomial with an `IsSolvableByRad` root has solvable Galois group + +* `isSolvable_gal_of_irreducible` in `Mathlib/FieldTheory/AbelRuffini.lean`: + an irreducible polynomial with an `IsSolvableByRad` root has solvable Galois group. * `galActionHom_bijective_of_prime_degree'` in `Mathlib/FieldTheory/PolynomialGaloisGroup.lean` : - an irreducible polynomial of prime degree with 1-3 non-real roots has full Galois group + an irreducible polynomial of prime degree with 1-3 non-real roots has full Galois group. * `Equiv.Perm.not_solvable` in `Mathlib/GroupTheory/Solvable.lean` : the symmetric group is not - solvable + solvable. Then all that remains is the construction of a specific polynomial satisfying the conditions of `galActionHom_bijective_of_prime_degree'`, which is done in this file. - -/ - namespace AbelRuffini - open Function Polynomial Polynomial.Gal Ideal -open scoped Polynomial - attribute [local instance] splits_ℚ_ℂ variable (R : Type*) [CommRing R] (a b : ℕ) @@ -155,19 +151,19 @@ theorem gal_Phi (hab : b < a) (h_irred : Irreducible (Φ ℚ a b)) : exact real_roots_Phi_ge a b hab theorem not_solvable_by_rad (p : ℕ) (x : ℂ) (hx : aeval x (Φ ℚ a b) = 0) (hab : b < a) - (hp : p.Prime) (hpa : p ∣ a) (hpb : p ∣ b) (hp2b : ¬p ^ 2 ∣ b) : ¬IsSolvableByRad ℚ x := by + (hp : p.Prime) (hpa : p ∣ a) (hpb : p ∣ b) (hp2b : ¬p ^ 2 ∣ b) : x ∉ solvableByRad ℚ ℂ := by have h_irred := irreducible_Phi a b p hp hpa hpb hp2b - apply mt (solvableByRad.isSolvable' h_irred hx) + apply mt (isSolvable_gal_of_irreducible · h_irred hx) intro h refine Equiv.Perm.not_solvable _ (le_of_eq ?_) (solvable_of_surjective (gal_Phi a b hab h_irred).2) rw_mod_cast [Cardinal.mk_fintype, complex_roots_Phi a b h_irred.separable] -theorem not_solvable_by_rad' (x : ℂ) (hx : aeval x (Φ ℚ 4 2) = 0) : ¬IsSolvableByRad ℚ x := by +theorem not_solvable_by_rad' (x : ℂ) (hx : aeval x (Φ ℚ 4 2) = 0) : x ∉ solvableByRad ℚ ℂ := by apply not_solvable_by_rad 4 2 2 x hx <;> decide /-- **Abel-Ruffini Theorem** -/ -theorem exists_not_solvable_by_rad : ∃ x : ℂ, IsAlgebraic ℚ x ∧ ¬IsSolvableByRad ℚ x := by +theorem exists_not_solvable_by_rad : ∃ x : ℂ, IsAlgebraic ℚ x ∧ x ∉ solvableByRad ℚ ℂ := by obtain ⟨x, hx⟩ := (IsAlgClosed.splits (Φ ℂ 4 2)).exists_eval_eq_zero (by simp [degree_Phi]) rw [← map_Phi 4 2 (algebraMap ℚ ℂ), eval_map] at hx exact ⟨x, ⟨Φ ℚ 4 2, (monic_Phi 4 2).ne_zero, hx⟩, not_solvable_by_rad' x hx⟩ diff --git a/Archive/Wiedijk100Theorems/CubingACube.lean b/Archive/Wiedijk100Theorems/CubingACube.lean index f494d1ff16ba03..31c9c0f26df100 100644 --- a/Archive/Wiedijk100Theorems/CubingACube.lean +++ b/Archive/Wiedijk100Theorems/CubingACube.lean @@ -9,6 +9,8 @@ import Mathlib.Data.Set.Finite.Lemmas import Mathlib.Order.Interval.Set.Disjoint /-! +# Dissection of Cubes + Proof that a cube (in dimension n ≥ 3) cannot be cubed: There does not exist a partition of a cube into finitely many smaller cubes (at least two) of different sizes. diff --git a/Counterexamples/CanonicallyOrderedCommSemiringTwoMul.lean b/Counterexamples/CanonicallyOrderedCommSemiringTwoMul.lean index f29bf9a07628ab..16029d0bd999c6 100644 --- a/Counterexamples/CanonicallyOrderedCommSemiringTwoMul.lean +++ b/Counterexamples/CanonicallyOrderedCommSemiringTwoMul.lean @@ -7,6 +7,7 @@ import Mathlib.Algebra.Ring.Subsemiring.Order import Mathlib.Data.ZMod.Basic /-! +# A canonically ordered commutative semiring where multiplication by 2 is not injective A canonically ordered commutative semiring with two different elements `a` and `b` such that `a ≠ b` and `2 * a = 2 * b`. Thus, multiplication by a fixed non-zero element of a canonically diff --git a/Counterexamples/IrrationalPowerOfIrrational.lean b/Counterexamples/IrrationalPowerOfIrrational.lean index 4ee3facae0cc1c..a2b082d116c102 100644 --- a/Counterexamples/IrrationalPowerOfIrrational.lean +++ b/Counterexamples/IrrationalPowerOfIrrational.lean @@ -6,10 +6,10 @@ Authors: Seewoo Lee import Mathlib.Analysis.SpecialFunctions.Pow.NNReal import Mathlib.NumberTheory.Real.Irrational -/- -# Irrational power of irrational numbers are not necessarily irrational. +/-! +# An irrational power of an irrational number need not be irrational -Prove that there exist irrational numbers `a`, `b` such that `a^b` is rational. +This file proves that there exist irrational numbers `a`, `b` such that `a^b` is rational. We use the following famous argument (based on the law of excluded middle and irrationality of √2). Consider `c = √2^√2`. If `c` is rational, we are done. diff --git a/Mathlib.lean b/Mathlib.lean index 41601b19cd1486..d1544b3ecdbb2c 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -171,6 +171,7 @@ public import Mathlib.Algebra.Category.ModuleCat.Kernels public import Mathlib.Algebra.Category.ModuleCat.LeftResolution public import Mathlib.Algebra.Category.ModuleCat.Limits public import Mathlib.Algebra.Category.ModuleCat.Localization +public import Mathlib.Algebra.Category.ModuleCat.Monoidal.Adjunction public import Mathlib.Algebra.Category.ModuleCat.Monoidal.Basic public import Mathlib.Algebra.Category.ModuleCat.Monoidal.Closed public import Mathlib.Algebra.Category.ModuleCat.Monoidal.Symmetric @@ -602,6 +603,7 @@ public import Mathlib.Algebra.Homology.EulerCharacteristic public import Mathlib.Algebra.Homology.ExactSequence public import Mathlib.Algebra.Homology.ExactSequenceFour public import Mathlib.Algebra.Homology.Factorizations.Basic +public import Mathlib.Algebra.Homology.Factorizations.CM5a public import Mathlib.Algebra.Homology.Factorizations.CM5b public import Mathlib.Algebra.Homology.Functor public import Mathlib.Algebra.Homology.GrothendieckAbelian @@ -677,6 +679,7 @@ public import Mathlib.Algebra.Homology.SpectralObject.EpiMono public import Mathlib.Algebra.Homology.SpectralObject.HasSpectralSequence public import Mathlib.Algebra.Homology.SpectralObject.Homology public import Mathlib.Algebra.Homology.SpectralObject.Page +public import Mathlib.Algebra.Homology.SpectralObject.SpectralSequence public import Mathlib.Algebra.Homology.SpectralSequence.Basic public import Mathlib.Algebra.Homology.SpectralSequence.ComplexShape public import Mathlib.Algebra.Homology.Square @@ -696,6 +699,7 @@ public import Mathlib.Algebra.Lie.CartanSubalgebra public import Mathlib.Algebra.Lie.Character public import Mathlib.Algebra.Lie.Classical public import Mathlib.Algebra.Lie.Cochain +public import Mathlib.Algebra.Lie.Derivation.BaseChange public import Mathlib.Algebra.Lie.Derivation.Basic public import Mathlib.Algebra.Lie.Derivation.Killing public import Mathlib.Algebra.Lie.DirectSum @@ -794,6 +798,7 @@ public import Mathlib.Algebra.Module.RingHom public import Mathlib.Algebra.Module.Shrink public import Mathlib.Algebra.Module.SnakeLemma public import Mathlib.Algebra.Module.SpanRank +public import Mathlib.Algebra.Module.SpanRankOperations public import Mathlib.Algebra.Module.Submodule.Basic public import Mathlib.Algebra.Module.Submodule.Bilinear public import Mathlib.Algebra.Module.Submodule.Defs @@ -1485,7 +1490,9 @@ public import Mathlib.AlgebraicTopology.SimplicialCategory.SimplicialObject public import Mathlib.AlgebraicTopology.SimplicialComplex.Basic 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.Homotopy public import Mathlib.AlgebraicTopology.SimplicialObject.II public import Mathlib.AlgebraicTopology.SimplicialObject.Op public import Mathlib.AlgebraicTopology.SimplicialObject.Split @@ -1531,6 +1538,7 @@ public import Mathlib.AlgebraicTopology.SimplicialSet.StrictSegal public import Mathlib.AlgebraicTopology.SimplicialSet.Subcomplex public import Mathlib.AlgebraicTopology.SimplicialSet.SubcomplexColimits public import Mathlib.AlgebraicTopology.SingularHomology.Basic +public import Mathlib.AlgebraicTopology.SingularHomology.HomotopyInvariance public import Mathlib.AlgebraicTopology.SingularSet public import Mathlib.AlgebraicTopology.TopologicalSimplex public import Mathlib.Analysis.AbsoluteValue.Equivalence @@ -1700,6 +1708,7 @@ public import Mathlib.Analysis.Calculus.FormalMultilinearSeries public import Mathlib.Analysis.Calculus.Gradient.Basic public import Mathlib.Analysis.Calculus.Implicit public import Mathlib.Analysis.Calculus.ImplicitContDiff +public import Mathlib.Analysis.Calculus.ImplicitFunction.ProdDomain public import Mathlib.Analysis.Calculus.InverseFunctionTheorem.Analytic public import Mathlib.Analysis.Calculus.InverseFunctionTheorem.ApproximatesLinearOn public import Mathlib.Analysis.Calculus.InverseFunctionTheorem.ContDiff @@ -1748,6 +1757,7 @@ public import Mathlib.Analysis.Complex.Arg public import Mathlib.Analysis.Complex.Asymptotics public import Mathlib.Analysis.Complex.Basic public import Mathlib.Analysis.Complex.BorelCaratheodory +public import Mathlib.Analysis.Complex.CanonicalDecomposition public import Mathlib.Analysis.Complex.Cardinality public import Mathlib.Analysis.Complex.CauchyIntegral public import Mathlib.Analysis.Complex.Circle @@ -1761,6 +1771,7 @@ public import Mathlib.Analysis.Complex.HalfPlane public import Mathlib.Analysis.Complex.Harmonic.Analytic public import Mathlib.Analysis.Complex.Harmonic.Liouville public import Mathlib.Analysis.Complex.Harmonic.MeanValue +public import Mathlib.Analysis.Complex.Harmonic.Poisson public import Mathlib.Analysis.Complex.HasPrimitives public import Mathlib.Analysis.Complex.IntegerCompl public import Mathlib.Analysis.Complex.IsIntegral @@ -1941,6 +1952,7 @@ public import Mathlib.Analysis.InnerProductSpace.Rayleigh public import Mathlib.Analysis.InnerProductSpace.Reproducing public import Mathlib.Analysis.InnerProductSpace.Semisimple public import Mathlib.Analysis.InnerProductSpace.Spectrum +public import Mathlib.Analysis.InnerProductSpace.StandardSubspace public import Mathlib.Analysis.InnerProductSpace.StarOrder public import Mathlib.Analysis.InnerProductSpace.Subspace public import Mathlib.Analysis.InnerProductSpace.Symmetric @@ -2069,6 +2081,7 @@ public import Mathlib.Analysis.Normed.Module.Ball.Action public import Mathlib.Analysis.Normed.Module.Ball.Homeomorph public import Mathlib.Analysis.Normed.Module.Ball.Pointwise public import Mathlib.Analysis.Normed.Module.Ball.RadialEquiv +public import Mathlib.Analysis.Normed.Module.Bases public import Mathlib.Analysis.Normed.Module.Basic public import Mathlib.Analysis.Normed.Module.Complemented public import Mathlib.Analysis.Normed.Module.Completion @@ -2384,6 +2397,7 @@ public import Mathlib.CategoryTheory.Adjunction.Comma public import Mathlib.CategoryTheory.Adjunction.CompositionIso public import Mathlib.CategoryTheory.Adjunction.Evaluation public import Mathlib.CategoryTheory.Adjunction.FullyFaithful +public import Mathlib.CategoryTheory.Adjunction.FullyFaithfulLimits public import Mathlib.CategoryTheory.Adjunction.Lifting.Left public import Mathlib.CategoryTheory.Adjunction.Lifting.Right public import Mathlib.CategoryTheory.Adjunction.Limits @@ -2751,6 +2765,7 @@ public import Mathlib.CategoryTheory.Limits.Preorder public import Mathlib.CategoryTheory.Limits.Presentation public import Mathlib.CategoryTheory.Limits.Preserves.Basic public import Mathlib.CategoryTheory.Limits.Preserves.Bifunctor +public import Mathlib.CategoryTheory.Limits.Preserves.BifunctorCokernel public import Mathlib.CategoryTheory.Limits.Preserves.Creates.Finite public import Mathlib.CategoryTheory.Limits.Preserves.Creates.Pullbacks public import Mathlib.CategoryTheory.Limits.Preserves.Filtered @@ -3064,6 +3079,7 @@ public import Mathlib.CategoryTheory.ObjectProperty.FunctorCategory.PreservesLim public import Mathlib.CategoryTheory.ObjectProperty.HasCardinalLT public import Mathlib.CategoryTheory.ObjectProperty.Ind public import Mathlib.CategoryTheory.ObjectProperty.InheritedFromHom +public import Mathlib.CategoryTheory.ObjectProperty.Kernels public import Mathlib.CategoryTheory.ObjectProperty.LimitsClosure public import Mathlib.CategoryTheory.ObjectProperty.LimitsOfShape public import Mathlib.CategoryTheory.ObjectProperty.Local @@ -3306,6 +3322,7 @@ public import Mathlib.CategoryTheory.Sums.Basic public import Mathlib.CategoryTheory.Sums.Products public import Mathlib.CategoryTheory.Thin public import Mathlib.CategoryTheory.Topos.Classifier +public import Mathlib.CategoryTheory.Topos.Sheaf public import Mathlib.CategoryTheory.Triangulated.Adjunction public import Mathlib.CategoryTheory.Triangulated.Basic public import Mathlib.CategoryTheory.Triangulated.Functor @@ -3450,10 +3467,9 @@ public import Mathlib.Combinatorics.SimpleGraph.CompleteMultipartite public import Mathlib.Combinatorics.SimpleGraph.ConcreteColorings public import Mathlib.Combinatorics.SimpleGraph.Connectivity.Connected public import Mathlib.Combinatorics.SimpleGraph.Connectivity.EdgeConnectivity +public import Mathlib.Combinatorics.SimpleGraph.Connectivity.Finite public import Mathlib.Combinatorics.SimpleGraph.Connectivity.Represents public import Mathlib.Combinatorics.SimpleGraph.Connectivity.Subgraph -public import Mathlib.Combinatorics.SimpleGraph.Connectivity.WalkCounting -public import Mathlib.Combinatorics.SimpleGraph.Connectivity.WalkDecomp public import Mathlib.Combinatorics.SimpleGraph.Copy public import Mathlib.Combinatorics.SimpleGraph.Dart public import Mathlib.Combinatorics.SimpleGraph.DegreeSum @@ -3505,6 +3521,8 @@ public import Mathlib.Combinatorics.SimpleGraph.UniversalVerts public import Mathlib.Combinatorics.SimpleGraph.VertexCover public import Mathlib.Combinatorics.SimpleGraph.Walk public import Mathlib.Combinatorics.SimpleGraph.Walks.Basic +public import Mathlib.Combinatorics.SimpleGraph.Walks.Counting +public import Mathlib.Combinatorics.SimpleGraph.Walks.Decomp public import Mathlib.Combinatorics.SimpleGraph.Walks.Maps public import Mathlib.Combinatorics.SimpleGraph.Walks.Operations public import Mathlib.Combinatorics.SimpleGraph.Walks.Subwalks @@ -3951,6 +3969,7 @@ public import Mathlib.Data.Multiset.UnionInter public import Mathlib.Data.Multiset.ZeroCons public import Mathlib.Data.NNRat.BigOperators public import Mathlib.Data.NNRat.Defs +public import Mathlib.Data.NNRat.Encodable public import Mathlib.Data.NNRat.Floor public import Mathlib.Data.NNRat.Lemmas public import Mathlib.Data.NNRat.Order @@ -4000,6 +4019,7 @@ public import Mathlib.Data.Nat.Factorial.NatCast public import Mathlib.Data.Nat.Factorial.SuperFactorial public import Mathlib.Data.Nat.Factorization.Basic public import Mathlib.Data.Nat.Factorization.Defs +public import Mathlib.Data.Nat.Factorization.Divisors public import Mathlib.Data.Nat.Factorization.Induction public import Mathlib.Data.Nat.Factorization.LCM public import Mathlib.Data.Nat.Factorization.PrimePow @@ -4461,6 +4481,7 @@ public import Mathlib.Geometry.Manifold.SmoothEmbedding public import Mathlib.Geometry.Manifold.StructureGroupoid public import Mathlib.Geometry.Manifold.VectorBundle.Basic public import Mathlib.Geometry.Manifold.VectorBundle.CovariantDerivative.Basic +public import Mathlib.Geometry.Manifold.VectorBundle.CovariantDerivative.Torsion public import Mathlib.Geometry.Manifold.VectorBundle.FiberwiseLinear public import Mathlib.Geometry.Manifold.VectorBundle.Hom public import Mathlib.Geometry.Manifold.VectorBundle.LocalFrame @@ -4616,6 +4637,7 @@ public import Mathlib.GroupTheory.QuotientGroup.Finite public import Mathlib.GroupTheory.QuotientGroup.ModEq public import Mathlib.GroupTheory.Rank public import Mathlib.GroupTheory.RegularWreathProduct +public import Mathlib.GroupTheory.ResiduallyFinite public import Mathlib.GroupTheory.Schreier public import Mathlib.GroupTheory.SchurZassenhaus public import Mathlib.GroupTheory.SemidirectProduct @@ -4809,6 +4831,7 @@ public import Mathlib.LinearAlgebra.Finsupp.Span public import Mathlib.LinearAlgebra.Finsupp.SumProd public import Mathlib.LinearAlgebra.Finsupp.Supported public import Mathlib.LinearAlgebra.Finsupp.VectorSpace +public import Mathlib.LinearAlgebra.FixedSubmodule public import Mathlib.LinearAlgebra.FreeAlgebra public import Mathlib.LinearAlgebra.FreeModule.Basic public import Mathlib.LinearAlgebra.FreeModule.Determinant @@ -5127,6 +5150,7 @@ public import Mathlib.MeasureTheory.Function.AEMeasurableSequence public import Mathlib.MeasureTheory.Function.AbsolutelyContinuous public import Mathlib.MeasureTheory.Function.ConditionalExpectation.AEMeasurable public import Mathlib.MeasureTheory.Function.ConditionalExpectation.Basic +public import Mathlib.MeasureTheory.Function.ConditionalExpectation.CondJensen public import Mathlib.MeasureTheory.Function.ConditionalExpectation.CondexpL1 public import Mathlib.MeasureTheory.Function.ConditionalExpectation.CondexpL2 public import Mathlib.MeasureTheory.Function.ConditionalExpectation.Indicator @@ -5529,6 +5553,7 @@ public import Mathlib.NumberTheory.ModularForms.CongruenceSubgroups 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.EisensteinSeries.Basic public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.Defs public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.E2.Defs @@ -5622,6 +5647,7 @@ public import Mathlib.NumberTheory.RamificationInertia.Basic public import Mathlib.NumberTheory.RamificationInertia.Galois public import Mathlib.NumberTheory.RamificationInertia.HilbertTheory public import Mathlib.NumberTheory.RamificationInertia.Unramified +public import Mathlib.NumberTheory.RatFunc.Ostrowski public import Mathlib.NumberTheory.Rayleigh public import Mathlib.NumberTheory.Real.GoldenRatio public import Mathlib.NumberTheory.Real.Irrational @@ -5959,6 +5985,7 @@ public import Mathlib.Probability.Decision.Risk.Basic public import Mathlib.Probability.Decision.Risk.Defs public import Mathlib.Probability.Density public import Mathlib.Probability.Distributions.Beta +public import Mathlib.Probability.Distributions.Binomial public import Mathlib.Probability.Distributions.Cauchy public import Mathlib.Probability.Distributions.Exponential public import Mathlib.Probability.Distributions.Fernique @@ -5979,6 +6006,7 @@ public import Mathlib.Probability.Distributions.Pareto public import Mathlib.Probability.Distributions.Poisson.Basic public import Mathlib.Probability.Distributions.Poisson.PoissonLimitThm public import Mathlib.Probability.Distributions.SetBernoulli +public import Mathlib.Probability.Distributions.TwoValued public import Mathlib.Probability.Distributions.Uniform public import Mathlib.Probability.HasLaw public import Mathlib.Probability.HasLawExists @@ -5994,7 +6022,8 @@ public import Mathlib.Probability.Independence.Integration public import Mathlib.Probability.Independence.Kernel public import Mathlib.Probability.Independence.Kernel.Indep public import Mathlib.Probability.Independence.Kernel.IndepFun -public import Mathlib.Probability.Independence.Process +public import Mathlib.Probability.Independence.Process.Basic +public import Mathlib.Probability.Independence.Process.HasIndepIncrements public import Mathlib.Probability.Independence.ZeroOne public import Mathlib.Probability.Kernel.Basic public import Mathlib.Probability.Kernel.CompProdEqIff @@ -6122,6 +6151,7 @@ public import Mathlib.RingTheory.Adjoin.FGBaseChange public import Mathlib.RingTheory.Adjoin.Field public import Mathlib.RingTheory.Adjoin.Polynomial public import Mathlib.RingTheory.Adjoin.Polynomial.Basic +public import Mathlib.RingTheory.Adjoin.Polynomial.Bivariate public import Mathlib.RingTheory.Adjoin.PowerBasis public import Mathlib.RingTheory.Adjoin.Singleton public import Mathlib.RingTheory.Adjoin.Tower @@ -6395,6 +6425,7 @@ public import Mathlib.RingTheory.LittleWedderburn public import Mathlib.RingTheory.LocalProperties.Basic public import Mathlib.RingTheory.LocalProperties.Exactness public import Mathlib.RingTheory.LocalProperties.Injective +public import Mathlib.RingTheory.LocalProperties.InjectiveDimension public import Mathlib.RingTheory.LocalProperties.IntegrallyClosed public import Mathlib.RingTheory.LocalProperties.Projective public import Mathlib.RingTheory.LocalProperties.ProjectiveDimension diff --git a/Mathlib/Algebra/Algebra/Epi.lean b/Mathlib/Algebra/Algebra/Epi.lean index 4eaed9cb2db9d2..f27f1e60d934be 100644 --- a/Mathlib/Algebra/Algebra/Epi.lean +++ b/Mathlib/Algebra/Algebra/Epi.lean @@ -62,7 +62,7 @@ end Semiring instance (R A : Type*) [CommRing R] [IsDomain R] [Field A] [Algebra R A] [IsFractionRing R A] : Algebra.IsEpi R A := by refine (isEpi_iff_forall_one_tmul_eq R A).mpr fun x ↦ ?_ - obtain ⟨a, b, hb, rfl⟩ := IsFractionRing.div_surjective (A := R) x + obtain ⟨a, b, hb, rfl⟩ := IsFractionRing.div_surjective R x set f := algebraMap R A with hf replace hb : f b ≠ 0 := by aesop calc 1 ⊗ₜ[R] (f a / f b) diff --git a/Mathlib/Algebra/Algebra/Hom.lean b/Mathlib/Algebra/Algebra/Hom.lean index a0d8568b93f4cf..40abf78853a5ad 100644 --- a/Mathlib/Algebra/Algebra/Hom.lean +++ b/Mathlib/Algebra/Algebra/Hom.lean @@ -126,7 +126,7 @@ protected theorem coe_coe {F : Type*} [FunLike F A B] [AlgHomClass F R A B] (f : theorem toFun_eq_coe (f : A →ₐ[R] B) : f.toFun = f := rfl -/-- Turn an algebra homomorpism into the corresponding multiplicative monoid homomorphism. -/ +/-- Turn an algebra homomorphism into the corresponding multiplicative monoid homomorphism. -/ @[coe] def toMonoidHom' (f : A →ₐ[R] B) : A →* B := (f : A →+* B) diff --git a/Mathlib/Algebra/Algebra/StrictPositivity.lean b/Mathlib/Algebra/Algebra/StrictPositivity.lean index fa8be79323c2a1..a02d554e1c3461 100644 --- a/Mathlib/Algebra/Algebra/StrictPositivity.lean +++ b/Mathlib/Algebra/Algebra/StrictPositivity.lean @@ -67,6 +67,15 @@ lemma isSelfAdjoint [Semiring A] [PartialOrder A] [StarRing A] [StarOrderedRing lemma _root_.isStrictlyPositive_one [LE A] [Monoid A] [Zero A] [ZeroLEOneClass A] : IsStrictlyPositive (1 : A) := iff_of_unital.mpr ⟨zero_le_one, isUnit_one⟩ +@[grind =] +lemma _root_.Units.isStrictlyPositive_iff [LE A] [Monoid A] [Zero A] {a : Aˣ} : + IsStrictlyPositive (a : A) ↔ (0 : A) ≤ a := + ⟨fun h => h.nonneg, fun h => iff_of_unital.mp ⟨h, a.isUnit⟩⟩ + +@[aesop safe apply] +lemma _root_.Units.isStrictlyPositive_of_le [LE A] [Monoid A] [Zero A] {a : Aˣ} + (h : (0 : A) ≤ a) : IsStrictlyPositive (a : A) := a.isStrictlyPositive_iff.mpr h + end basic section StarOrderedRing diff --git a/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean b/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean index 6eb7fdda650b74..29121326006f86 100644 --- a/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean +++ b/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean @@ -240,17 +240,15 @@ def toAddSubmonoid {R : Type u} {A : Type v} [CommSemiring R] [Semiring A] [Alge S.toSubsemiring.toAddSubmonoid /-- A subalgebra over a ring is also a `Subring`. -/ -@[simps toSubsemiring] +@[reducible] def toSubring {R : Type u} {A : Type v} [CommRing R] [Ring A] [Algebra R A] (S : Subalgebra R A) : Subring A := { S.toSubsemiring with neg_mem' := S.neg_mem } -@[simp] theorem mem_toSubring {R : Type u} {A : Type v} [CommRing R] [Ring A] [Algebra R A] {S : Subalgebra R A} {x} : x ∈ S.toSubring ↔ x ∈ S := Iff.rfl -@[simp] theorem coe_toSubring {R : Type u} {A : Type v} [CommRing R] [Ring A] [Algebra R A] (S : Subalgebra R A) : (↑S.toSubring : Set A) = S := rfl @@ -289,6 +287,7 @@ instance toCommRing {R A} [CommRing R] [CommRing A] [Algebra R A] (S : Subalgebr end /-- The forgetful map from `Subalgebra` to `Submodule` as an `OrderEmbedding` -/ +@[implicit_reducible] -- Not `@[reducible]` because it is an order embedding rather than a function. def toSubmodule : Subalgebra R A ↪o Submodule R A where toEmbedding := { toFun := fun S => @@ -710,7 +709,6 @@ theorem coe_inclusion (s : S) : (inclusion h s : A) = s := namespace inclusion -set_option backward.isDefEq.respectTransparency false in scoped instance isScalarTower_left (X) [SMul X R] [SMul X A] [IsScalarTower X R A] : letI := (inclusion h).toModule; IsScalarTower X S T := letI := (inclusion h).toModule @@ -878,7 +876,6 @@ theorem rangeS_algebraMap {R A : Type*} [CommSemiring R] [CommSemiring A] [Algeb rw [algebraMap_eq, Algebra.algebraMap_self, RingHom.id_comp, ← toSubsemiring_subtype, Subsemiring.rangeS_subtype] -set_option backward.isDefEq.respectTransparency false in @[simp] theorem range_algebraMap {R A : Type*} [CommRing R] [CommRing A] [Algebra R A] (S : Subalgebra R A) : (algebraMap S A).range = S.toSubring := by diff --git a/Mathlib/Algebra/Algebra/Subalgebra/IsSimpleOrder.lean b/Mathlib/Algebra/Algebra/Subalgebra/IsSimpleOrder.lean index 65c794ed74ea9a..176d9f6b6125ee 100644 --- a/Mathlib/Algebra/Algebra/Subalgebra/IsSimpleOrder.lean +++ b/Mathlib/Algebra/Algebra/Subalgebra/IsSimpleOrder.lean @@ -18,7 +18,6 @@ public section open Module Submodule -set_option backward.isDefEq.respectTransparency false in theorem Subalgebra.isSimpleOrder_of_finrank_prime (F A) [Field F] [Ring A] [IsDomain A] [Algebra F A] (hp : (finrank F A).Prime) : IsSimpleOrder (Subalgebra F A) := { toNontrivial := diff --git a/Mathlib/Algebra/Algebra/Subalgebra/Lattice.lean b/Mathlib/Algebra/Algebra/Subalgebra/Lattice.lean index fc97ff470920c1..4c73f2d9acbb2a 100644 --- a/Mathlib/Algebra/Algebra/Subalgebra/Lattice.lean +++ b/Mathlib/Algebra/Algebra/Subalgebra/Lattice.lean @@ -28,7 +28,7 @@ variable (R : Type u) {A : Type v} {B : Type w} variable [CommSemiring R] [Semiring A] [Algebra R A] [Semiring B] [Algebra R B] /-- The minimal subalgebra that includes `s`. -/ -@[simps toSubsemiring] +@[simps -isSimp toSubsemiring] def adjoin (s : Set A) : Subalgebra R A := { Subsemiring.closure (Set.range (algebraMap R A) ∪ s) with algebraMap_mem' := fun r => Subsemiring.subset_closure <| Or.inl ⟨r, rfl⟩ } diff --git a/Mathlib/Algebra/Algebra/Subalgebra/Rank.lean b/Mathlib/Algebra/Algebra/Subalgebra/Rank.lean index 4b1366526b3965..f8eb33eca32c9f 100644 --- a/Mathlib/Algebra/Algebra/Subalgebra/Rank.lean +++ b/Mathlib/Algebra/Algebra/Subalgebra/Rank.lean @@ -29,7 +29,6 @@ namespace Subalgebra variable {R S : Type*} [CommRing R] [CommRing S] [Algebra R S] (A B : Subalgebra R S) -set_option backward.isDefEq.respectTransparency false in section variable [Module.Free R A] [Module.Free A (Algebra.adjoin A (B : Set S))] @@ -55,7 +54,6 @@ theorem finrank_left_dvd_finrank_sup_of_free : end -set_option backward.isDefEq.respectTransparency false in section variable [Module.Free R B] [Module.Free B (Algebra.adjoin B (A : Set S))] diff --git a/Mathlib/Algebra/BigOperators/Finprod.lean b/Mathlib/Algebra/BigOperators/Finprod.lean index a35c3ba8df5f61..7945e7f8c79545 100644 --- a/Mathlib/Algebra/BigOperators/Finprod.lean +++ b/Mathlib/Algebra/BigOperators/Finprod.lean @@ -602,6 +602,15 @@ lemma finprod_le_finprod {M : Type*} [CommMonoidWithZero M] [PartialOrder M] [Ze finprod_eq_finset_prod_of_mulSupport_subset g (show g.mulSupport ⊆ s by grind)] exact Finset.prod_le_prod (fun i _ ↦ hf₀ i) fun i _ ↦ h i +lemma finprod_zero_le_one {M α : Type*} [CommMonoidWithZero M] [PartialOrder M] + [ZeroLEOneClass M] [PosMulMono M] : + ∏ᶠ _ : α, (0 : M) ≤ 1 := by + rw [← finprod_one (α := α)] + by_cases H : (fun _ : α ↦ (0 : M)).HasFiniteMulSupport + · exact finprod_le_finprod H (fun _ ↦ le_rfl) (by fun_prop) fun _ ↦ zero_le_one + · rw [finprod_of_not_hasFiniteMulSupport H] + exact finprod_one.symm.le + /-! ### Distributivity w.r.t. addition, subtraction, and (scalar) multiplication -/ diff --git a/Mathlib/Algebra/Category/ModuleCat/ChangeOfRings.lean b/Mathlib/Algebra/Category/ModuleCat/ChangeOfRings.lean index 4bd0fed5029979..912fcc260c46a3 100644 --- a/Mathlib/Algebra/Category/ModuleCat/ChangeOfRings.lean +++ b/Mathlib/Algebra/Category/ModuleCat/ChangeOfRings.lean @@ -837,6 +837,11 @@ def Counit.map {Y} : (restrictScalars f ⋙ extendScalars f).obj Y ⟶ Y := rw [mul_smul] | add _ _ ih1 ih2 => rw [smul_add, map_add, map_add, ih1, ih2, smul_add] } +lemma Counit.map_apply_one_tmul {Y : ModuleCat S} (y : Y) : + Counit.map f ((1 : S) ⊗ₜ[R] y) = y := by + change (1 : S) • y = y + simp + set_option backward.isDefEq.respectTransparency false in /-- The natural transformation from the composition of restriction and extension of scalars to the identity functor on `S`-module. @@ -900,6 +905,11 @@ lemma extendRestrictScalarsAdj_unit_app_apply (extendRestrictScalarsAdj f).unit.app M m = (1 : S) ⊗ₜ[R,f] m := rfl +@[simp] +lemma extendRestrictScalarsAdj_counit_app_apply_one_tmul (M : ModuleCat S) (m : M) : + dsimp% (extendRestrictScalarsAdj f).counit.app M ((1 : S) ⊗ₜ[R] m) = m := by + apply ExtendRestrictScalarsAdj.Counit.map_apply_one_tmul + instance {R : Type u₁} {S : Type u₂} [CommRing R] [CommRing S] (f : R →+* S) : (extendScalars.{u₁, u₂, max u₂ w} f).IsLeftAdjoint := (extendRestrictScalarsAdj f).isLeftAdjoint diff --git a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Adjunction.lean b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Adjunction.lean new file mode 100644 index 00000000000000..4d6b58c955b116 --- /dev/null +++ b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Adjunction.lean @@ -0,0 +1,125 @@ +/- +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.ModuleCat.ChangeOfRings +public import Mathlib.Algebra.Category.ModuleCat.Monoidal.Basic + +/-! +# The monoidal adjunction between the extension and the restriction of scalars + +Let `f : R →+* S` be a morphism of commutative rings. We show that the functor +`extendsScalars f : ModuleCat R ⥤ ModuleCat S` is monoidal, and deduce that +`restrictScalars f : ModuleCat S ⥤ ModuleCat R` is lax monoidal. + +-/ + +@[expose] public section + +universe u + +open CategoryTheory ModuleCat MonoidalCategory Limits + Functor.LaxMonoidal Functor.OplaxMonoidal TensorProduct + +namespace ModuleCat + +variable {R S : Type u} [CommRing R] [CommRing S] (f : R →+* S) + +@[simp] +lemma extendsScalars_map_leftUnitor_inv_one_tmul (M : ModuleCat R) (m : M) : + letI := f.toAlgebra + (extendScalars f).map (λ_ M).inv ((1 : S) ⊗ₜ[R] m) = (1 : S) ⊗ₜ[R] (1 ⊗ₜ m) := rfl + +@[simp] +lemma extendsScalars_map_rightUnitor_inv_one_tmul (M : ModuleCat R) (m : M) : + letI := f.toAlgebra + (extendScalars f).map (ρ_ M).inv ((1 : S) ⊗ₜ[R] m) = (1 : S) ⊗ₜ[R] (m ⊗ₜ 1) := rfl + +open ModuleCat.MonoidalCategory in +noncomputable instance : (extendScalars f).Monoidal := + letI : Algebra R S := f.toAlgebra + Functor.CoreMonoidal.toMonoidal + (.mk' + (εIso := (AlgebraTensorModule.rid R S S).symm.toModuleIso) + (μIso := fun M₁ M₂ ↦ (AlgebraTensorModule.distribBaseChange R S M₁ M₂).symm.toModuleIso) + (μIso_inv_natural_left := fun {M₁ M₁'} g M₂ ↦ + ((extendRestrictScalarsAdj f).homEquiv _ _).injective + (tensor_ext (fun _ _ ↦ rfl))) + (μIso_inv_natural_right := fun {M₂ M₂'} M₁ g ↦ + ((extendRestrictScalarsAdj f).homEquiv _ _).injective + (tensor_ext (fun _ _ ↦ rfl))) + (oplax_associativity := fun M₁ M₂ M₃ ↦ + ((extendRestrictScalarsAdj f).homEquiv _ _).injective + (tensor_ext₃' (fun _ _ _ ↦ rfl))) + (oplax_left_unitality := fun M ↦ by + ext m + dsimp + rw [MonoidalCategory.leftUnitor_inv_apply] + erw [AlgebraTensorModule.distribBaseChange_tmul, + MonoidalCategory.whiskerRight_apply, + AlgebraTensorModule.rid_tmul] + rw [one_smul] + rfl) + (oplax_right_unitality := fun M ↦ by + ext m + dsimp + rw [MonoidalCategory.rightUnitor_inv_apply] + erw [AlgebraTensorModule.distribBaseChange_tmul, + MonoidalCategory.whiskerLeft_apply, + AlgebraTensorModule.rid_tmul] + rw [one_smul] + rfl)) + +lemma extendScalars_ε : + letI := f.toAlgebra + dsimp% ε (extendScalars f) = (AlgebraTensorModule.rid R S S).toModuleIso.inv := rfl + +lemma extendScalars_η : + letI := f.toAlgebra + dsimp% η (extendScalars f) = (AlgebraTensorModule.rid R S S).toModuleIso.hom := rfl + +lemma extendScalars_μ (M₁ M₂ : ModuleCat R) : + letI := f.toAlgebra + dsimp% μ (extendScalars f) M₁ M₂ = + (AlgebraTensorModule.distribBaseChange R S M₁ M₂).toModuleIso.inv := + rfl + +lemma extendScalars_δ (M₁ M₂ : ModuleCat R) : + letI := f.toAlgebra + dsimp% δ (extendScalars f) M₁ M₂ = + (AlgebraTensorModule.distribBaseChange R S M₁ M₂).toModuleIso.hom := + rfl + +@[simp] +lemma extendScalars_δ_tmul (M₁ M₂ : ModuleCat R) (m₁ : M₁) (m₂ : M₂) : + letI := f.toAlgebra + dsimp% δ (extendScalars f) M₁ M₂ (((1 : S) ⊗ₜ[R] (m₁ ⊗ₜ[R] m₂) :)) = + ((1 : S) ⊗ₜ[R] m₁) ⊗ₜ[S] ((1 : S) ⊗ₜ[R] m₂) := rfl + +noncomputable instance : (restrictScalars f).LaxMonoidal := + (extendRestrictScalarsAdj f).rightAdjointLaxMonoidal + +@[simp] +lemma restrictScalars_η (r : R) : + ε (restrictScalars f) r = f r := by + letI := f.toAlgebra + dsimp [Adjunction.rightAdjointLaxMonoidal_ε] + rw [extendRestrictScalarsAdj_homEquiv_apply, extendScalars_η] + erw [AlgebraTensorModule.rid_tmul] + rw [RingHom.smul_toAlgebra, mul_one] + +set_option backward.isDefEq.respectTransparency false in +@[simp] +lemma restrictScalars_μ_tmul (M₁ M₂ : ModuleCat S) (m₁ : M₁) (m₂ : M₂) : + dsimp% μ (restrictScalars f) M₁ M₂ (m₁ ⊗ₜ m₂) = m₁ ⊗ₜ m₂ := by + dsimp [Adjunction.rightAdjointLaxMonoidal_μ] + rw [extendRestrictScalarsAdj_homEquiv_apply] + dsimp + rw [extendScalars_δ_tmul, tensorHom_tmul, + extendRestrictScalarsAdj_counit_app_apply_one_tmul, + extendRestrictScalarsAdj_counit_app_apply_one_tmul] + +end ModuleCat diff --git a/Mathlib/Algebra/Category/ModuleCat/Sheaf/Free.lean b/Mathlib/Algebra/Category/ModuleCat/Sheaf/Free.lean index 63090837f132bf..35ae621f0f8243 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Sheaf/Free.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Sheaf/Free.lean @@ -80,6 +80,11 @@ lemma freeHomEquiv_symm_comp {M N : SheafOfModules.{u} R} {I : Type u} (s : I noncomputable abbrev freeSection {I : Type u} (i : I) : (free (R := R) I).sections := (free (R := R) I).freeHomEquiv (𝟙 (free I)) i +lemma freeHomEquiv_apply {M : SheafOfModules.{u} R} {I : Type u} + (f : free I ⟶ M) (i : I) : + freeHomEquiv M f i = sectionsMap f (freeSection i) := + rfl + lemma unitHomEquiv_symm_freeHomEquiv_apply {I : Type u} {M : SheafOfModules.{u} R} (f : free I ⟶ M) (i : I) : M.unitHomEquiv.symm (M.freeHomEquiv f i) = ιFree i ≫ f := by @@ -104,6 +109,12 @@ lemma sectionMap_freeMap_freeSection (i : I) : sectionsMap (freeMap (R := R) f) (freeSection i) = freeSection (f i) := by simp [← freeHomEquiv_comp_apply] +lemma sectionsMap_freeHomEquiv_symm_freeSection + {M : SheafOfModules.{u} R} (f : I → M.sections) (i : I) : + sectionsMap ((freeHomEquiv M).symm f) (freeSection i) = f i := by + obtain ⟨f, rfl⟩ := (freeHomEquiv M).surjective f + cat_disch + @[reassoc (attr := simp)] lemma ιFree_freeMap (i : I) : ιFree (R := R) i ≫ freeMap f = ιFree (f i) := by @@ -123,6 +134,70 @@ noncomputable def freeFunctor : Type u ⥤ SheafOfModules.{u} R where map_id X := (freeHomEquiv _).injective (by ext1 i; simp) map_comp {I J K} f g := (freeHomEquiv _).injective (by ext1; simp [freeHomEquiv_comp_apply]) +/- If `C` was in `Type u`, we could show that `freeFunctor` is a left adjoint, and +deduce that `freeFunctor` preserves all colimits. Instead, we use +the natural bijection `freeHomEquiv`, which is as close as an adjunction we can get. -/ +instance : PreservesColimitsOfSize.{v₂, u₂} (freeFunctor (R := R)) where + preservesColimitsOfShape {J} _ := ⟨fun {K} ↦ ⟨fun {c} hc ↦ ⟨by + replace hc := (Types.isColimit_iff_coconeTypesIsColimit c).1 ⟨hc⟩ + let coconeTypes (s : Cocone (K ⋙ freeFunctor (R := R))) : + K.CoconeTypes := + { pt := s.pt.sections + ι j := freeHomEquiv _ (s.ι.app j) + ι_naturality {j j'} f := by + funext x + dsimp + rw [← s.w f] + dsimp + rw [freeHomEquiv_comp_apply, freeHomEquiv_freeMap, + Function.comp_apply, freeHomEquiv_apply] } + exact { + desc s := (freeHomEquiv _).symm (hc.desc (coconeTypes s)) + fac s j := (freeHomEquiv _).injective (by + funext x + dsimp + rw [freeHomEquiv_comp_apply, freeHomEquiv_freeMap, Function.comp_apply, + sectionsMap_freeHomEquiv_symm_freeSection, + dsimp% hc.fac_apply (coconeTypes s) j x]) + uniq s m hm := (freeHomEquiv _).injective (by + funext x + obtain ⟨j, x, rfl⟩ := Functor.CoconeTypes.IsColimit.ι_jointly_surjective hc x + replace hm := congr_fun ((freeHomEquiv _).congr_arg (hm j)) x + dsimp at hm + rw [freeHomEquiv_comp_apply, freeHomEquiv_freeMap, + Function.comp_apply] at hm + rw [freeHomEquiv_apply, freeHomEquiv_apply, + sectionsMap_freeHomEquiv_symm_freeSection, + Functor.coconeTypesEquiv_symm_apply_ι, + dsimp% hc.fac_apply (coconeTypes s) j x, hm]) }⟩⟩⟩ + + +section + +variable (I J : Type u) + +/-- A binary coproduct of free sheaves of modules is the free sheaf +of modules on the sum type. -/ +noncomputable def freeSumIso : free I ⨿ free J ≅ free (R := R) (I ⊕ J) := + IsColimit.coconePointUniqueUpToIso + (coprodIsCoprod (free (R := R) I) (free J)) + (mapIsColimitOfPreservesOfIsColimit (freeFunctor (R := R)) _ _ + (Types.binaryCoproductColimit I J)) + +@[reassoc (attr := simp)] +lemma inl_freeSumIso_hom : + coprod.inl ≫ (freeSumIso (R := R) I J).hom = freeMap Sum.inl := + IsColimit.comp_coconePointUniqueUpToIso_hom + (coprodIsCoprod (free (R := R) I) (free J)) _ (.mk .left) + +@[reassoc (attr := simp)] +lemma inr_freeSumIso_hom : + coprod.inr ≫ (freeSumIso (R := R) I J).hom = freeMap Sum.inr := + IsColimit.comp_coconePointUniqueUpToIso_hom + (coprodIsCoprod (free (R := R) I) (free J)) _ (.mk .right) + +end + section variable {C' : Type u₂} [Category.{v₂} C'] {J' : GrothendieckTopology C'} {S : Sheaf J' RingCat.{u}} diff --git a/Mathlib/Algebra/Category/ModuleCat/Ulift.lean b/Mathlib/Algebra/Category/ModuleCat/Ulift.lean index 18c286b0a1759c..870f6641c0abb6 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Ulift.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Ulift.lean @@ -17,7 +17,7 @@ public import Mathlib.CategoryTheory.Preadditive.Projective.Preserves # Ulift functor for ModuleCat In this file, we define the obvious functor `ModuleCat.{v} R ⥤ ModuleCat.{max v v'} R` and prove -it is exact, fully faithful and preverves projective and injective objects. +it is exact, fully faithful and preserves projective and injective objects. -/ diff --git a/Mathlib/Algebra/Category/MonCat/FilteredColimits.lean b/Mathlib/Algebra/Category/MonCat/FilteredColimits.lean index f7ae3409f92206..136732d55717e8 100644 --- a/Mathlib/Algebra/Category/MonCat/FilteredColimits.lean +++ b/Mathlib/Algebra/Category/MonCat/FilteredColimits.lean @@ -232,7 +232,6 @@ noncomputable def colimitCocone : Cocone F where pt := colimit.{v, u} F ι := { app := coconeMorphism F } -set_option backward.isDefEq.respectTransparency false in /-- Given a cocone `t` of `F`, the induced monoid homomorphism from the colimit to the cocone point. As a function, this is simply given by the induced map of the corresponding cocone in `Type`. The only thing left to see is that it is a monoid homomorphism. diff --git a/Mathlib/Algebra/Category/Ring/Under/Limits.lean b/Mathlib/Algebra/Category/Ring/Under/Limits.lean index 2a7dea27fdd0fc..588849e1158a7e 100644 --- a/Mathlib/Algebra/Category/Ring/Under/Limits.lean +++ b/Mathlib/Algebra/Category/Ring/Under/Limits.lean @@ -107,7 +107,6 @@ end Pi section Equalizer -set_option backward.isDefEq.respectTransparency false in lemma equalizer_comp {A B : Under R} (f g : A ⟶ B) : (AlgHom.equalizer (toAlgHom f) (toAlgHom g)).val.toUnder ≫ f = (AlgHom.equalizer (toAlgHom f) (toAlgHom g)).val.toUnder ≫ g := by @@ -121,12 +120,10 @@ def equalizerFork {A B : Under R} (f g : A ⟶ B) : Fork.ofι ((AlgHom.equalizer (toAlgHom f) (toAlgHom g)).val.toUnder) (by rw [equalizer_comp]) -set_option backward.isDefEq.respectTransparency false in @[simp] lemma equalizerFork_ι {A B : Under R} (f g : A ⟶ B) : (Under.equalizerFork f g).ι = (AlgHom.equalizer (toAlgHom f) (toAlgHom g)).val.toUnder := rfl -set_option backward.isDefEq.respectTransparency false in /-- Variant of `Under.equalizerFork'` for algebra maps. This is definitionally equal to `Under.equalizerFork` but this is costly in applications. -/ def equalizerFork' {A B : Type u} [CommRing A] [CommRing B] [Algebra R A] [Algebra R B] @@ -134,7 +131,6 @@ def equalizerFork' {A B : Type u} [CommRing A] [CommRing B] [Algebra R A] [Algeb Fork f.toUnder g.toUnder := Fork.ofι ((AlgHom.equalizer f g).val.toUnder) <| by ext a; exact a.property -set_option backward.isDefEq.respectTransparency false in @[simp] lemma equalizerFork'_ι {A B : Type u} [CommRing A] [CommRing B] [Algebra R A] [Algebra R B] (f g : A →ₐ[R] B) : @@ -162,14 +158,12 @@ def tensorProdEqualizer {A B : Under R} (f g : A ⟶ B) : ((tensorProd R S).map ((AlgHom.equalizer (toAlgHom f) (toAlgHom g)).val.toUnder)) <| by rw [← Functor.map_comp, equalizer_comp, Functor.map_comp] -set_option backward.isDefEq.respectTransparency false in @[simp] lemma tensorProdEqualizer_ι {A B : Under R} (f g : A ⟶ B) : (tensorProdEqualizer f g).ι = (tensorProd R S).map ((AlgHom.equalizer (toAlgHom f) (toAlgHom g)).val.toUnder) := rfl -set_option backward.isDefEq.respectTransparency false in /-- If `S` is `R`-flat, `S ⊗[R] eq(f, g)` is isomorphic to `eq(𝟙 ⊗[R] f, 𝟙 ⊗[R] g)`. -/ -- marked noncomputable for performance (only) noncomputable def equalizerForkTensorProdIso [Module.Flat R S] {A B : Under R} (f g : A ⟶ B) : diff --git a/Mathlib/Algebra/CharP/MixedCharZero.lean b/Mathlib/Algebra/CharP/MixedCharZero.lean index d2998f61d06100..ea5ee389a6dcdd 100644 --- a/Mathlib/Algebra/CharP/MixedCharZero.lean +++ b/Mathlib/Algebra/CharP/MixedCharZero.lean @@ -5,8 +5,13 @@ Authors: Jon Eugster -/ module -public import Mathlib.Algebra.CharP.LocalRing -public import Mathlib.RingTheory.Ideal.Quotient.Basic +public import Mathlib.Algebra.Algebra.Defs +public import Mathlib.Algebra.CharP.Defs +public import Mathlib.Algebra.IsPrimePow +public import Mathlib.RingTheory.Ideal.Maximal +public import Mathlib.RingTheory.Ideal.Quotient.Defs +public import Mathlib.RingTheory.LocalRing.Defs +import Mathlib.Algebra.CharP.LocalRing /-! # Equal and mixed characteristic @@ -44,7 +49,8 @@ characteristic case for convenience: ## Implementation Notes -We use the terms `EqualCharZero` and `AlgebraRat` despite not being such definitions in mathlib. +We use the terms `EqualCharZero` and `AlgebraRat` despite there not being any such definitions +in mathlib. The former refers to the statement `∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ I)`, the latter refers to the existence of an instance `[Algebra ℚ R]`. The two are shown to be equivalent conditions. @@ -54,7 +60,7 @@ equivalent conditions. - Relate mixed characteristic in a local ring to p-adic numbers [NumberTheory.PAdics]. -/ -@[expose] public section +public section variable (R : Type*) [CommRing R] @@ -82,7 +88,7 @@ namespace MixedCharZero Reduction to `p` prime: When proving any statement `P` about mixed characteristic rings we can always assume that `p` is prime. -/ -theorem reduce_to_p_prime {P : Prop} : +lemma reduce_to_p_prime {P : Prop} : (∀ p > 0, MixedCharZero R p → P) ↔ ∀ p : ℕ, p.Prime → MixedCharZero R p → P := by constructor · intro h q q_prime q_mixedChar @@ -108,7 +114,7 @@ theorem reduce_to_p_prime {P : Prop} : Reduction to `I` prime ideal: When proving statements about mixed characteristic rings, after we reduced to `p` prime, we can assume that the ideal `I` in the definition is maximal. -/ -theorem reduce_to_maximal_ideal {p : ℕ} (hp : Nat.Prime p) : +lemma reduce_to_maximal_ideal {p : ℕ} (hp : Nat.Prime p) : (∃ I : Ideal R, I ≠ ⊤ ∧ CharP (R ⧸ I) p) ↔ ∃ I : Ideal R, I.IsMaximal ∧ CharP (R ⧸ I) p := by constructor · intro g @@ -154,7 +160,7 @@ namespace EqualCharZero set_option backward.isDefEq.respectTransparency false in /-- `ℚ`-algebra implies equal characteristic. -/ -theorem of_algebraRat [Algebra ℚ R] : ∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ I) := by +private lemma of_algebraRat [Algebra ℚ R] : ∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ I) := by intro I hI constructor intro a b h_ab @@ -164,13 +170,16 @@ theorem of_algebraRat [Algebra ℚ R] : ∀ I : Ideal R, I ≠ ⊤ → CharZero · simpa only [← Ideal.Quotient.eq_zero_iff_mem, map_sub, sub_eq_zero, map_natCast] simpa only [Ne, sub_eq_zero] using (@Nat.cast_injective ℚ _ _).ne hI +/-! +The construction of the algebra map `ℚ →+* R` (given by `x ↦ (x.num : R) /ₚ ↑x.pnatDen`) +is marked `private` as it is considered an implementation detail. +-/ section ConstructionAlgebraRat variable {R} set_option backward.isDefEq.respectTransparency false in -/-- Internal: Not intended to be used outside this local construction. -/ -theorem PNat.isUnit_natCast [h : Fact (∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ I))] +private lemma PNat.isUnit_natCast [h : Fact (∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ I))] (n : ℕ+) : IsUnit (n : R) := by -- `n : R` is a unit iff `(n)` is not a proper ideal in `R`. rw [← Ideal.span_singleton_eq_top] @@ -184,33 +193,31 @@ theorem PNat.isUnit_natCast [h : Fact (∀ I : Ideal R, I ≠ ⊤ → CharZero ( exact Ideal.subset_span (Set.mem_singleton _) @[coe] -noncomputable def pnatCast [Fact (∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ I))] : ℕ+ → Rˣ := +private noncomputable def pnatCast [Fact (∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ I))] : ℕ+ → Rˣ := fun n => (PNat.isUnit_natCast n).unit -/-- Internal: Not intended to be used outside this local construction. -/ -noncomputable instance coePNatUnits +private noncomputable instance coePNatUnits [Fact (∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ I))] : Coe ℕ+ Rˣ := ⟨EqualCharZero.pnatCast⟩ -/-- Internal: Not intended to be used outside this local construction. -/ @[simp] -theorem pnatCast_one [Fact (∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ I))] : ((1 : ℕ+) : Rˣ) = 1 := by +private lemma pnatCast_one [Fact (∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ I))] : + ((1 : ℕ+) : Rˣ) = 1 := by apply Units.ext rw [Units.val_one] change ((PNat.isUnit_natCast (R := R) 1).unit : R) = 1 rw [IsUnit.unit_spec (PNat.isUnit_natCast 1)] rw [PNat.one_coe, Nat.cast_one] -/-- Internal: Not intended to be used outside this local construction. -/ @[simp] -theorem pnatCast_eq_natCast [Fact (∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ I))] (n : ℕ+) : +private lemma pnatCast_eq_natCast [Fact (∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ I))] (n : ℕ+) : ((n : Rˣ) : R) = ↑n := by change ((PNat.isUnit_natCast (R := R) n).unit : R) = ↑n simp only [IsUnit.unit_spec] /-- Equal characteristic implies `ℚ`-algebra. -/ @[implicit_reducible] -noncomputable def algebraRat (h : ∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ I)) : +private noncomputable def algebraRat (h : ∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ I)) : Algebra ℚ R := haveI : Fact (∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ I)) := ⟨h⟩ RingHom.toAlgebra @@ -239,7 +246,7 @@ noncomputable def algebraRat (h : ∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ end ConstructionAlgebraRat /-- Not mixed characteristic implies equal characteristic. -/ -theorem of_not_mixedCharZero [CharZero R] (h : ∀ p > 0, ¬MixedCharZero R p) : +private lemma of_not_mixedCharZero [CharZero R] (h : ∀ p > 0, ¬MixedCharZero R p) : ∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ I) := by intro I hI_ne_top suffices CharP (R ⧸ I) 0 from CharP.charP_to_charZero _ @@ -252,7 +259,7 @@ theorem of_not_mixedCharZero [CharZero R] (h : ∀ p > 0, ¬MixedCharZero R p) : exact absurd h_mixed (h p.succ p.succ_pos) /-- Equal characteristic implies not mixed characteristic. -/ -theorem to_not_mixedCharZero (h : ∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ I)) : +private lemma to_not_mixedCharZero (h : ∀ I : Ideal R, I ≠ ⊤ → CharZero (R ⧸ I)) : ∀ p > 0, ¬MixedCharZero R p := by intro p p_pos by_contra hp_mixedChar @@ -284,7 +291,7 @@ end EqualCharZero /-- A ring of characteristic zero is not a `ℚ`-algebra iff it has mixed characteristic for some `p`. -/ -theorem isEmpty_algebraRat_iff_mixedCharZero [CharZero R] : +lemma isEmpty_algebraRat_iff_mixedCharZero [CharZero R] : IsEmpty (Algebra ℚ R) ↔ ∃ p > 0, MixedCharZero R p := by contrapose! rw [← EqualCharZero.iff_not_mixedCharZero] @@ -315,16 +322,14 @@ theorem split_equalCharZero_mixedCharZero [CharZero R] (h_equal : Algebra ℚ R rw [← isEmpty_algebraRat_iff_mixedCharZero, not_isEmpty_iff] at h exact h.some -example (n : ℕ) (h : n ≠ 0) : 0 < n := - zero_lt_iff.mpr h - /-- Split any `Prop` over `R` into the three cases: - positive characteristic. - equal characteristic zero. - mixed characteristic `(0, p)`. -/ -theorem split_by_characteristic (h_pos : ∀ p : ℕ, p ≠ 0 → CharP R p → P) (h_equal : Algebra ℚ R → P) +theorem split_by_characteristic (h_pos : ∀ p : ℕ, p ≠ 0 → CharP R p → P) + (h_equal : Algebra ℚ R → P) (h_mixed : ∀ p : ℕ, Nat.Prime p → MixedCharZero R p → P) : P := by cases CharP.exists R with | intro p p_charP => @@ -340,7 +345,8 @@ In an `IsDomain R`, split any `Prop` over `R` into the three cases: - equal characteristic zero. - mixed characteristic `(0, p)`. -/ -theorem split_by_characteristic_domain [IsDomain R] (h_pos : ∀ p : ℕ, Nat.Prime p → CharP R p → P) +theorem split_by_characteristic_domain [IsDomain R] + (h_pos : ∀ p : ℕ, Nat.Prime p → CharP R p → P) (h_equal : Algebra ℚ R → P) (h_mixed : ∀ p : ℕ, Nat.Prime p → MixedCharZero R p → P) : P := by refine split_by_characteristic R ?_ h_equal h_mixed intro p p_pos p_char diff --git a/Mathlib/Algebra/CharP/Two.lean b/Mathlib/Algebra/CharP/Two.lean index 4bb268cbe23927..19803221084e16 100644 --- a/Mathlib/Algebra/CharP/Two.lean +++ b/Mathlib/Algebra/CharP/Two.lean @@ -33,9 +33,6 @@ section AddMonoidWithOne variable [AddMonoidWithOne R] -theorem two_eq_zero [CharP R 2] : (2 : R) = 0 := by - rw [← Nat.cast_two, CharP.cast_eq_zero] - /-- The only hypotheses required to build a `CharP R 2` instance are `1 ≠ 0` and `2 = 0`. -/ theorem of_one_ne_zero_of_two_eq_zero (h₁ : (1 : R) ≠ 0) (h₂ : (2 : R) = 0) : CharP R 2 where cast_eq_zero_iff n := by @@ -45,6 +42,34 @@ theorem of_one_ne_zero_of_two_eq_zero (h₁ : (1 : R) ≠ 0) (h₂ : (2 : R) = 0 · simp_rw [hn.not_two_dvd_nat, iff_false] rwa [natCast_eq_one_of_odd_of_two_eq_zero hn h₂] +variable [CharP R 2] + +@[scoped simp] +theorem two_eq_zero : (2 : R) = 0 := by + rw [← Nat.cast_two, CharP.cast_eq_zero] + +theorem natCast_eq_ite (n : ℕ) : (n : R) = if Even n then 0 else 1 := by + induction n <;> aesop (add simp [one_add_one_eq_two]) + +@[simp] +theorem range_natCast : Set.range ((↑) : ℕ → R) = {0, 1} := by + rw [funext natCast_eq_ite, Set.range_ite_const] + · use 0; simp + · use 1; simp + +variable (R) in +theorem natCast_cases (n : ℕ) : (n : R) = 0 ∨ (n : R) = 1 := + range_natCast.le (Set.mem_range_self _) + +theorem natCast_eq_mod (n : ℕ) : (n : R) = (n % 2 : ℕ) := by + simp [natCast_eq_ite, Nat.even_iff] + +@[scoped simp] +theorem ofNat_eq_mod (n : ℕ) [n.AtLeastTwo] : (ofNat(n) : R) = (ofNat(n) % 2 : ℕ) := + natCast_eq_mod n + +example : (37 : R) = 1 := by simp + end AddMonoidWithOne section Semiring @@ -94,6 +119,22 @@ protected theorem two_zsmul (x : R) : (2 : ℤ) • x = 0 := by protected theorem add_eq_zero {a b : R} : a + b = 0 ↔ a = b := by rw [← CharTwo.sub_eq_add, sub_eq_iff_eq_add, zero_add] +theorem intCast_eq_ite (n : ℤ) : (n : R) = if Even n then 0 else 1 := by + obtain ⟨n, rfl | rfl⟩ := n.eq_nat_or_neg <;> simpa using natCast_eq_ite n + +@[simp] +theorem range_intCast : Set.range ((↑) : ℤ → R) = {0, 1} := by + rw [funext intCast_eq_ite, Set.range_ite_const] + · use 0; simp + · use 1; simp + +variable (R) in +theorem intCast_cases (n : ℤ) : (n : R) = 0 ∨ (n : R) = 1 := + (Set.ext_iff.1 range_intCast _).1 (Set.mem_range_self _) + +theorem intCast_eq_mod (n : ℤ) : (n : R) = (n % 2 : ℤ) := by + simp [intCast_eq_ite, Int.even_iff] + end Ring section CommSemiring @@ -101,7 +142,7 @@ section CommSemiring variable [CommSemiring R] [CharP R 2] theorem add_sq (x y : R) : (x + y) ^ 2 = x ^ 2 + y ^ 2 := by - simp [add_pow_two, two_eq_zero (R := R)] + simp [add_pow_two] theorem add_mul_self (x y : R) : (x + y) * (x + y) = x * x + y * y := by rw [← pow_two, ← pow_two, ← pow_two, add_sq] diff --git a/Mathlib/Algebra/Field/Subfield/Basic.lean b/Mathlib/Algebra/Field/Subfield/Basic.lean index ac0471f961eb41..f71d10ed60d7c4 100644 --- a/Mathlib/Algebra/Field/Subfield/Basic.lean +++ b/Mathlib/Algebra/Field/Subfield/Basic.lean @@ -252,13 +252,11 @@ instance : InfSet (Subfield K) := @[simp, norm_cast] theorem coe_sInf (S : Set (Subfield K)) : ((sInf S : Subfield K) : Set K) = ⋂ s ∈ S, ↑s := - show ((sInf (Subfield.toSubring '' S) : Subring K) : Set K) = ⋂ s ∈ S, ↑s by - simp + show ((sInf (Subfield.toSubring '' S) : Subring K) : Set K) = ⋂ s ∈ S, ↑s by simp @[simp] -theorem mem_sInf {S : Set (Subfield K)} {x : K} : x ∈ sInf S ↔ ∀ p ∈ S, x ∈ p := - Subring.mem_sInf.trans - ⟨fun h p hp => h p.toSubring ⟨p, hp, rfl⟩, fun h _ ⟨p', hp', p_eq⟩ => p_eq ▸ h p' hp'⟩ +theorem mem_sInf {S : Set (Subfield K)} {x : K} : x ∈ sInf S ↔ ∀ p ∈ S, x ∈ p := by + simpa only [Set.mem_iInter] using Set.ext_iff.1 (coe_sInf S) x @[simp, norm_cast] theorem coe_iInf {ι : Sort*} {S : ι → Subfield K} : (↑(⨅ i, S i) : Set K) = ⋂ i, S i := by diff --git a/Mathlib/Algebra/FiniteSupport/Basic.lean b/Mathlib/Algebra/FiniteSupport/Basic.lean index 4f140a6b091094..66b51c3f410ed6 100644 --- a/Mathlib/Algebra/FiniteSupport/Basic.lean +++ b/Mathlib/Algebra/FiniteSupport/Basic.lean @@ -13,7 +13,7 @@ public import Mathlib.Data.Set.Finite.Lattice import Mathlib.Algebra.Group.Support /-! -# Make fun_prop work for finite (mulitplicative) support +# Make fun_prop work for finite (multiplicative) support We provide API lemmas for the predicate `HasFiniteMulSupport` (and its additivized version `HasFiniteSupport`) on functions so that `fun_prop` can prove it for functions that are diff --git a/Mathlib/Algebra/FiniteSupport/Defs.lean b/Mathlib/Algebra/FiniteSupport/Defs.lean index 9a0240621edcf5..45f4c9bd1d54f2 100644 --- a/Mathlib/Algebra/FiniteSupport/Defs.lean +++ b/Mathlib/Algebra/FiniteSupport/Defs.lean @@ -9,7 +9,7 @@ public import Mathlib.Algebra.Notation.Support public import Mathlib.Data.Set.Finite.Basic /-! -# Make fun_prop work for finite (mulitplicative) support +# Make fun_prop work for finite (multiplicative) support We define a new predicate `HasFiniteMulSupport` (and its additivized version) on functions and provide the infrastructure so that `fun_prop` can prove it for functions that are diff --git a/Mathlib/Algebra/Group/Action/End.lean b/Mathlib/Algebra/Group/Action/End.lean index 125afea7ea9bf8..8fde4399617920 100644 --- a/Mathlib/Algebra/Group/Action/End.lean +++ b/Mathlib/Algebra/Group/Action/End.lean @@ -63,10 +63,10 @@ instance applyAddAction : AddAction (Additive (Function.End α)) α := inferInst @[simp] lemma smul_def (f : Function.End α) (a : α) : f • a = f a := rfl ---TODO - This statement should be somethting like `toFun (f * g) = toFun f ∘ toFun g` +--TODO - This statement should be something like `toFun (f * g) = toFun f ∘ toFun g` lemma mul_def (f g : Function.End α) : (f * g) = f ∘ g := rfl ---TODO - This statement should be somethting like `toFun 1 = id` +--TODO - This statement should be something like `toFun 1 = id` lemma one_def : (1 : Function.End α) = id := rfl /-- `Function.End.applyMulAction` is faithful. -/ diff --git a/Mathlib/Algebra/Group/Defs.lean b/Mathlib/Algebra/Group/Defs.lean index 9906f33dc6aa9e..fa571650f02d71 100644 --- a/Mathlib/Algebra/Group/Defs.lean +++ b/Mathlib/Algebra/Group/Defs.lean @@ -6,13 +6,13 @@ Authors: Jeremy Avigad, Leonardo de Moura, Simon Hudon, Mario Carneiro module public import Batteries.Logic +public import Batteries.Util.LibraryNote public import Mathlib.Algebra.Notation.Defs public import Mathlib.Algebra.Regular.Defs public import Mathlib.Data.Int.Notation public import Mathlib.Data.Nat.BinaryRec public import Mathlib.Tactic.MkIffOfInductiveProp public import Mathlib.Tactic.OfNat -public import Mathlib.Tactic.Basic public import Mathlib.Data.Nat.Notation public import Mathlib.Tactic.Simps.Basic diff --git a/Mathlib/Algebra/Group/Fin/Basic.lean b/Mathlib/Algebra/Group/Fin/Basic.lean index a8e9d3067e1ffc..8598d0beb5711e 100644 --- a/Mathlib/Algebra/Group/Fin/Basic.lean +++ b/Mathlib/Algebra/Group/Fin/Basic.lean @@ -110,24 +110,7 @@ lemma coe_sub_one (a : Fin (n + 1)) : ↑(a - 1) = if a = 0 then n else a - 1 := @[simp] lemma lt_sub_iff {n : ℕ} {a b : Fin n} : a < a - b ↔ a < b := by - rcases n with - | n - · exact a.elim0 - constructor - · contrapose - intro h - obtain ⟨l, hl⟩ := Nat.exists_eq_add_of_le (Fin.not_lt.mp h) - simpa only [Fin.not_lt, le_iff_val_le_val, sub_def, hl, ← Nat.add_assoc, Nat.add_mod_left, - Nat.mod_eq_of_lt, Nat.sub_add_cancel b.is_lt.le] using - (le_trans (mod_le _ _) (le_add_left _ _)) - · intro h - rw [lt_def, sub_def] - simp only - obtain ⟨k, hk⟩ := Nat.exists_eq_add_of_lt b.is_lt - have : n + 1 - b = k + 1 := by - simp_rw [hk, Nat.add_assoc, Nat.add_sub_cancel_left] - -- simp_rw because, otherwise, rw tries to rewrite inside `b : Fin (n + 1)` - rw [this, Nat.mod_eq_of_lt (hk.ge.trans_lt' ?_), Nat.lt_add_left_iff_pos] <;> - lia + fin_omega @[simp] lemma sub_le_iff {n : ℕ} {a b : Fin n} : a - b ≤ a ↔ b ≤ a := by diff --git a/Mathlib/Algebra/Group/Hom/Defs.lean b/Mathlib/Algebra/Group/Hom/Defs.lean index 7385be05cb5c17..1c6ae90b130af3 100644 --- a/Mathlib/Algebra/Group/Hom/Defs.lean +++ b/Mathlib/Algebra/Group/Hom/Defs.lean @@ -212,7 +212,7 @@ the entirety of the `FunLike` hierarchy in order to determine this because so ma `OneHomClass` instance (in fact, this problem is likely worse for `ZeroHomClass`). This can lead to a significant performance hit when `map_one` fails to apply. -To avoid this problem, we mark these widely applicable simp lemmas with key discimination tree keys +To avoid this problem, we mark these widely applicable simp lemmas with key discrimination tree keys with `mid` priority in order to ensure that they are not tried first. We do not use `low`, to allow bundled morphisms to unfold themselves with `low` priority such that diff --git a/Mathlib/Algebra/Group/Idempotent.lean b/Mathlib/Algebra/Group/Idempotent.lean index eb272f5d58523a..b906c879422f18 100644 --- a/Mathlib/Algebra/Group/Idempotent.lean +++ b/Mathlib/Algebra/Group/Idempotent.lean @@ -37,6 +37,8 @@ variable {M N S : Type*} /-- An element `a` is said to be idempotent if `a * a = a`. -/ def IsIdempotentElem [Mul M] (a : M) : Prop := a * a = a +lemma isIdempotentElem_iff [Mul M] {a : M} : IsIdempotentElem a ↔ a * a = a := Iff.rfl + namespace IsIdempotentElem section Mul variable [Mul M] {a : M} diff --git a/Mathlib/Algebra/Group/InjSurj.lean b/Mathlib/Algebra/Group/InjSurj.lean index af7a1b2aef7e35..b5526f91462958 100644 --- a/Mathlib/Algebra/Group/InjSurj.lean +++ b/Mathlib/Algebra/Group/InjSurj.lean @@ -49,8 +49,8 @@ a semigroup. See note [reducible non-instances]. -/ @[to_additive /-- A type endowed with `+` is an additive semigroup, if it admits an injective map that preserves `+` to an additive semigroup. -/] protected abbrev semigroup [Semigroup M₂] (f : M₁ → M₂) (hf : Injective f) - (mul : ∀ x y, f (x * y) = f x * f y) : Semigroup M₁ := - { ‹Mul M₁› with mul_assoc := fun x y z => hf <| by rw [mul, mul, mul, mul, mul_assoc] } + (mul : ∀ x y, f (x * y) = f x * f y) : Semigroup M₁ where + mul_assoc := fun x y z => hf <| by rw [mul, mul, mul, mul, mul_assoc] /-- A type endowed with `*` is a commutative magma, if it admits a surjective map that preserves `*` from a commutative magma. -/ @@ -121,10 +121,9 @@ preserves `1` and `*` to a `MulOneClass`. See note [reducible non-instances]. - /-- A type endowed with `0` and `+` is an `AddZeroClass`, if it admits an injective map that preserves `0` and `+` to an `AddZeroClass`. -/] protected abbrev mulOneClass [MulOneClass M₂] (f : M₁ → M₂) (hf : Injective f) (one : f 1 = 1) - (mul : ∀ x y, f (x * y) = f x * f y) : MulOneClass M₁ := - { ‹One M₁›, ‹Mul M₁› with - one_mul := fun x => hf <| by rw [mul, one, one_mul], - mul_one := fun x => hf <| by rw [mul, one, mul_one] } + (mul : ∀ x y, f (x * y) = f x * f y) : MulOneClass M₁ where + one_mul := fun x => hf <| by rw [mul, one, one_mul] + mul_one := fun x => hf <| by rw [mul, one, mul_one] variable [Pow M₁ ℕ] @@ -136,7 +135,7 @@ injective map that preserves `0` and `+` to an additive monoid. See note [reducible non-instances]. -/] protected abbrev monoid [Monoid M₂] (f : M₁ → M₂) (hf : Injective f) (one : f 1 = 1) (mul : ∀ x y, f (x * y) = f x * f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) : Monoid M₁ := - { hf.mulOneClass f one mul, hf.semigroup f mul with + { hf.semigroup f mul, hf.mulOneClass f one mul with npow := fun n x => x ^ n, npow_zero := fun x => hf <| by rw [npow, one, pow_zero], npow_succ := fun n x => hf <| by rw [npow, pow_succ, mul, npow] } @@ -149,7 +148,7 @@ admits an injective map that preserves `0` and `+` to an additive left cancel mo protected abbrev leftCancelMonoid [LeftCancelMonoid M₂] (f : M₁ → M₂) (hf : Injective f) (one : f 1 = 1) (mul : ∀ x y, f (x * y) = f x * f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) : LeftCancelMonoid M₁ := - { hf.leftCancelSemigroup f mul, hf.monoid f one mul npow with } + { hf.monoid f one mul npow, hf.leftCancelSemigroup f mul with } /-- A type endowed with `1` and `*` is a right cancel monoid, if it admits an injective map that preserves `1` and `*` to a right cancel monoid. See note [reducible non-instances]. -/ @@ -159,7 +158,7 @@ admits an injective map that preserves `0` and `+` to an additive left cancel mo protected abbrev rightCancelMonoid [RightCancelMonoid M₂] (f : M₁ → M₂) (hf : Injective f) (one : f 1 = 1) (mul : ∀ x y, f (x * y) = f x * f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) : RightCancelMonoid M₁ := - { hf.rightCancelSemigroup f mul, hf.monoid f one mul npow with } + { hf.monoid f one mul npow, hf.rightCancelSemigroup f mul with } /-- A type endowed with `1` and `*` is a cancel monoid, if it admits an injective map that preserves `1` and `*` to a cancel monoid. See note [reducible non-instances]. -/ @@ -188,7 +187,7 @@ admits an injective map that preserves `0` and `+` to an additive cancel commuta protected abbrev cancelCommMonoid [CancelCommMonoid M₂] (f : M₁ → M₂) (hf : Injective f) (one : f 1 = 1) (mul : ∀ x y, f (x * y) = f x * f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) : CancelCommMonoid M₁ := - { hf.leftCancelSemigroup f mul, hf.commMonoid f one mul npow with } + { hf.commMonoid f one mul npow, hf.leftCancelSemigroup f mul with } /-- A type has an involutive inversion if it admits a surjective map that preserves `⁻¹` to a type which has an involutive inversion. See note [reducible non-instances] -/ @@ -207,9 +206,8 @@ preserves `1` and `⁻¹` to a `InvOneClass`. See note [reducible non-instances /-- A type endowed with `0` and unary `-` is an `NegZeroClass`, if it admits an injective map that preserves `0` and unary `-` to an `NegZeroClass`. -/] protected abbrev invOneClass [InvOneClass M₂] (f : M₁ → M₂) (hf : Injective f) (one : f 1 = 1) - (inv : ∀ x, f (x⁻¹) = (f x)⁻¹) : InvOneClass M₁ := - { ‹One M₁›, ‹Inv M₁› with - inv_one := hf <| by rw [inv, one, inv_one] } + (inv : ∀ x, f (x⁻¹) = (f x)⁻¹) : InvOneClass M₁ where + inv_one := hf <| by rw [inv, one, inv_one] variable [Div M₁] [Pow M₁ ℤ] @@ -224,7 +222,7 @@ protected abbrev divInvMonoid [DivInvMonoid M₂] (f : M₁ → M₂) (hf : Inje (mul : ∀ x y, f (x * y) = f x * f y) (inv : ∀ x, f x⁻¹ = (f x)⁻¹) (div : ∀ x y, f (x / y) = f x / f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n) : DivInvMonoid M₁ := - { hf.monoid f one mul npow, ‹Inv M₁›, ‹Div M₁› with + { hf.monoid f one mul npow with zpow := fun n x => x ^ n, zpow_zero' := fun x => hf <| by rw [zpow, zpow_zero, one], zpow_succ' := fun n x => hf <| by rw [zpow, mul, zpow_natCast, pow_succ, zpow, zpow_natCast], @@ -297,7 +295,7 @@ protected abbrev commGroup [CommGroup M₂] (f : M₁ → M₂) (hf : Injective (mul : ∀ x y, f (x * y) = f x * f y) (inv : ∀ x, f x⁻¹ = (f x)⁻¹) (div : ∀ x y, f (x / y) = f x / f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n) : CommGroup M₁ := - { hf.commMonoid f one mul npow, hf.group f one mul inv div npow zpow with } + { hf.group f one mul inv div npow zpow, hf.commMonoid f one mul npow with } end Injective @@ -316,8 +314,8 @@ semigroup. See note [reducible non-instances]. -/ /-- A type endowed with `+` is an additive semigroup, if it admits a surjective map that preserves `+` from an additive semigroup. -/] protected abbrev semigroup [Semigroup M₁] (f : M₁ → M₂) (hf : Surjective f) - (mul : ∀ x y, f (x * y) = f x * f y) : Semigroup M₂ := - { ‹Mul M₂› with mul_assoc := hf.forall₃.2 fun x y z => by simp only [← mul, mul_assoc] } + (mul : ∀ x y, f (x * y) = f x * f y) : Semigroup M₂ where + mul_assoc := hf.forall₃.2 fun x y z => by simp only [← mul, mul_assoc] /-- A type endowed with `*` is a commutative semigroup, if it admits a surjective map that preserves `*` from a commutative semigroup. See note [reducible non-instances]. -/ @@ -346,10 +344,9 @@ variable [One M₂] /-- A type endowed with `0` and `+` is an `AddZeroClass`, if it admits a surjective map that preserves `0` and `+` to an `AddZeroClass`. -/] protected abbrev mulOneClass [MulOneClass M₁] (f : M₁ → M₂) (hf : Surjective f) (one : f 1 = 1) - (mul : ∀ x y, f (x * y) = f x * f y) : MulOneClass M₂ := - { ‹One M₂›, ‹Mul M₂› with - one_mul := hf.forall.2 fun x => by rw [← one, ← mul, one_mul], - mul_one := hf.forall.2 fun x => by rw [← one, ← mul, mul_one] } + (mul : ∀ x y, f (x * y) = f x * f y) : MulOneClass M₂ where + one_mul := hf.forall.2 fun x => by rw [← one, ← mul, one_mul] + mul_one := hf.forall.2 fun x => by rw [← one, ← mul, mul_one] variable [Pow M₂ ℕ] @@ -376,7 +373,7 @@ admits a surjective map that preserves `0` and `+` to an additive commutative mo protected abbrev commMonoid [CommMonoid M₁] (f : M₁ → M₂) (hf : Surjective f) (one : f 1 = 1) (mul : ∀ x y, f (x * y) = f x * f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) : CommMonoid M₂ := - { hf.commSemigroup f mul, hf.monoid f one mul npow with } + { hf.monoid f one mul npow, hf.commSemigroup f mul with } /-- A type has an involutive inversion if it admits a surjective map that preserves `⁻¹` to a type which has an involutive inversion. See note [reducible non-instances] -/ @@ -399,7 +396,7 @@ protected abbrev divInvMonoid [DivInvMonoid M₁] (f : M₁ → M₂) (hf : Surj (mul : ∀ x y, f (x * y) = f x * f y) (inv : ∀ x, f x⁻¹ = (f x)⁻¹) (div : ∀ x y, f (x / y) = f x / f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n) : DivInvMonoid M₂ := - { hf.monoid f one mul npow, ‹Div M₂›, ‹Inv M₂› with + { hf.monoid f one mul npow with zpow := fun n x => x ^ n, zpow_zero' := hf.forall.2 fun x => by rw [← zpow, zpow_zero, ← one], zpow_succ' := fun n => hf.forall.2 fun x => by @@ -430,7 +427,7 @@ protected abbrev commGroup [CommGroup M₁] (f : M₁ → M₂) (hf : Surjective (mul : ∀ x y, f (x * y) = f x * f y) (inv : ∀ x, f x⁻¹ = (f x)⁻¹) (div : ∀ x y, f (x / y) = f x / f y) (npow : ∀ (x) (n : ℕ), f (x ^ n) = f x ^ n) (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n) : CommGroup M₂ := - { hf.commMonoid f one mul npow, hf.group f one mul inv div npow zpow with } + { hf.group f one mul inv div npow zpow, hf.commMonoid f one mul npow with } end Surjective diff --git a/Mathlib/Algebra/Group/Irreducible/Indecomposable.lean b/Mathlib/Algebra/Group/Irreducible/Indecomposable.lean index 674dff3d487665..ef97f0b2b4d67a 100644 --- a/Mathlib/Algebra/Group/Irreducible/Indecomposable.lean +++ b/Mathlib/Algebra/Group/Irreducible/Indecomposable.lean @@ -199,7 +199,7 @@ lemma Submonoid.mem_closure_image_one_lt_iff [CommMonoid S] [IsOrderedCancelMono v i ∈ closure (v '' {i | 1 < f (v i)}) ↔ 1 < f (v i) := by refine ⟨fun hi ↦ ?_, fun hi ↦ subset_closure <| mem_image_of_mem v hi⟩ suffices v i = 1 ∨ 1 < f (v i) from this.resolve_left hv_one - refine closure_induction (by aesop) (by simp) (fun x y _ _ hx hy ↦ ?_) hi + refine closure_induction (by grind) (by simp) (fun x y _ _ hx hy ↦ ?_) hi rcases hx with rfl | hx; · simpa rcases hy with rfl | hy; · right; simpa right diff --git a/Mathlib/Algebra/GroupWithZero/Associated.lean b/Mathlib/Algebra/GroupWithZero/Associated.lean index 5541ca3930d967..3a3cf67f419dca 100644 --- a/Mathlib/Algebra/GroupWithZero/Associated.lean +++ b/Mathlib/Algebra/GroupWithZero/Associated.lean @@ -497,9 +497,8 @@ theorem dvd_eq_le : ((· ∣ ·) : Associates M → Associates M → Prop) = (· instance uniqueUnits : Unique (Associates M)ˣ where uniq := by rintro ⟨a, b, hab, hba⟩ - revert hab hba - exact Quotient.inductionOn₂ a b <| fun a b hab hba ↦ Units.ext <| Quotient.sound <| - associated_one_of_associated_mul_one <| Quotient.exact hab + induction a, b using Quotient.inductionOn₂ with | _ a b + exact Units.ext <| Quotient.sound <| associated_one_of_associated_mul_one <| Quotient.exact hab @[simp] theorem coe_unit_eq_one (u : (Associates M)ˣ) : (u : Associates M) = 1 := by diff --git a/Mathlib/Algebra/HierarchyDesign.lean b/Mathlib/Algebra/HierarchyDesign.lean index 30362429da56ba..5bbae9e02f3c27 100644 --- a/Mathlib/Algebra/HierarchyDesign.lean +++ b/Mathlib/Algebra/HierarchyDesign.lean @@ -6,7 +6,7 @@ Authors: Kim Morrison, Eric Wieser module public import Mathlib.Init -public import Mathlib.Tactic.Basic +public import Batteries.Util.LibraryNote /-! # Documentation of the algebraic hierarchy diff --git a/Mathlib/Algebra/Homology/Additive.lean b/Mathlib/Algebra/Homology/Additive.lean index 808dd43d6f90ec..3cf5b40f00e0c0 100644 --- a/Mathlib/Algebra/Homology/Additive.lean +++ b/Mathlib/Algebra/Homology/Additive.lean @@ -186,7 +186,6 @@ def NatIso.mapHomologicalComplex {F G : W₁ ⥤ W₂} [F.PreservesZeroMorphisms inv_hom_id := by simp only [← NatTrans.mapHomologicalComplex_comp, α.inv_hom_id, NatTrans.mapHomologicalComplex_id] -set_option backward.isDefEq.respectTransparency false in /-- An equivalence of categories induces an equivalences between the respective categories of homological complex. -/ diff --git a/Mathlib/Algebra/Homology/BifunctorShift.lean b/Mathlib/Algebra/Homology/BifunctorShift.lean index ed92cbf6d7a206..da4118e427b380 100644 --- a/Mathlib/Algebra/Homology/BifunctorShift.lean +++ b/Mathlib/Algebra/Homology/BifunctorShift.lean @@ -24,7 +24,7 @@ that the two ways to deduce an isomorphism `mapBifunctor (K₁⟦x⟧) (K₂⟦y⟧) F ≅ (mapBifunctor K₁ K₂ F)⟦x + y⟧` differ by the sign `(x * y).negOnePow`. -These definitions and properties can be summarised by saysing that the bifunctor +These definitions and properties can be summarised by saying that the bifunctor `F.map₂CochainComplex : CochainComplex C₁ ℤ ⥤ CochainComplex C₂ ℤ ⥤ CochainComplex D ℤ` commutes with shifts by `ℤ`. diff --git a/Mathlib/Algebra/Homology/CochainComplexPlus.lean b/Mathlib/Algebra/Homology/CochainComplexPlus.lean index fb0cea062682ab..17a95eb227a14c 100644 --- a/Mathlib/Algebra/Homology/CochainComplexPlus.lean +++ b/Mathlib/Algebra/Homology/CochainComplexPlus.lean @@ -13,7 +13,7 @@ public import Mathlib.CategoryTheory.ObjectProperty.Shift # Bounded below cochain complexes In this file, we consider the full subcategory `CochainComplex.Plus C` -of `CochainComplex C ℤ` consisting of bounded below cocahin complexes +of `CochainComplex C ℤ` consisting of bounded below cochain complexes in a category `C`. -/ diff --git a/Mathlib/Algebra/Homology/DerivedCategory/Ext/Map.lean b/Mathlib/Algebra/Homology/DerivedCategory/Ext/Map.lean index 42613503389404..6fbaaab78f14e2 100644 --- a/Mathlib/Algebra/Homology/DerivedCategory/Ext/Map.lean +++ b/Mathlib/Algebra/Homology/DerivedCategory/Ext/Map.lean @@ -11,7 +11,7 @@ public import Mathlib.Algebra.Homology.DerivedCategory.ExactFunctor /-! # Map Between Ext Induced by Exact Functor -In this file, we develope the map `Ext^k (M, N) → Ext^k (F(M), F(N))`, +In this file, we develop the map `Ext^k (M, N) → Ext^k (F(M), F(N))`, where `F` is an exact functor between abelian categories. -/ diff --git a/Mathlib/Algebra/Homology/Embedding/ExtendHomotopy.lean b/Mathlib/Algebra/Homology/Embedding/ExtendHomotopy.lean index 10dc6b95068315..56111f6e6de25e 100644 --- a/Mathlib/Algebra/Homology/Embedding/ExtendHomotopy.lean +++ b/Mathlib/Algebra/Homology/Embedding/ExtendHomotopy.lean @@ -46,7 +46,7 @@ lemma homAux_eq (i' j' : Option ι) (i j : ι) (hi : i' = some i) (hj : j' = som subst hi hj simp [homAux, extend.XIso, extend.X] -/-- Auxiliary defnition for `Homotopy.extend`. -/ +/-- Auxiliary definition for `Homotopy.extend`. -/ noncomputable def hom (i' j' : ι') : (K.extend e).X i' ⟶ (L.extend e).X j' := extend.homAux φ (e.r i') (e.r j') diff --git a/Mathlib/Algebra/Homology/Factorizations/CM5a.lean b/Mathlib/Algebra/Homology/Factorizations/CM5a.lean new file mode 100644 index 00000000000000..71a16734f371a0 --- /dev/null +++ b/Mathlib/Algebra/Homology/Factorizations/CM5a.lean @@ -0,0 +1,231 @@ +/- +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.Homology.DerivedCategory.HomologySequence +public import Mathlib.Algebra.Homology.Factorizations.CM5b +public import Mathlib.Algebra.Homology.HomologicalComplexLimitsEventuallyConstant +public import Mathlib.Algebra.Homology.Refinements +public import Mathlib.Algebra.Homology.SingleHomology +public import Mathlib.CategoryTheory.Category.Factorisation +public import Mathlib.CategoryTheory.Functor.OfSequence + +/-! +# Factorization lemma + +In this file, we shall show that if `f : K ⟶ L` is a morphism between bounded below +cochain complexes in an abelian category with enough injectives, +there exists a factorization `ι ≫ π = f` with `ι : K ⟶ K'` a monomorphism that is also +a quasimorphism and `π : K' ⟶ L` a morphism which degreewise is an epimorphism with +an injective kernel, while `K'` is also bounded below (with precise bounds depending +on the available bounds for `K` and `L`): this is +`CochainComplex.Plus.modelCategoryQuillen.cm5a` (TODO). Using the factorization +obtained in the file `Mathlib/Algebra/Homology/Factorizations/CM5b.lean`, +we may assume `f : K ⇨ L` is a monomorphism (a case which appears as +the lemma `CochainComplex.Plus.modelCategoryQuillen.cm5a_cof` (TODO)). + +In the proof, the key (private) lemma shall be +`CochainComplex.Plus.modelCategoryQuillen.cm5a_cof.step` which shows that +if `f` is a monomorphism which is a quasi-isomorphism in degrees `≤ n₀` and +`n₀ + 1 = n₁`, then `f` has a factorisation `ι ≫ π = f` +where `ι` is a monomorphism that is a quasi-isomorphism in degrees `≤ n₁`, +and `π` is an isomorphism in degrees `≤ n₀` that is also a degreewise +epimorphism with an injective kernel. The proof of `step` decomposes +a two separate lemmas `step₁` and `step₂` (TODO): we first ensure that `ι` +induces a monomorphism in homology in degree `n₁`, and we proceed further +in `step₂`. + +As we assume that both `K` and `L` are bounded below, we may find `n₀ : ℤ` +such that `K` and `L` are striclty `≥ n₀ + 1`: in particular, `f` induces +an isomorphism in degrees `≤ n₀`. Iterating the lemma `step`, we construct +a projective system `ℕᵒᵖ ⥤ CochainComplex C ℤ` +(see `CochainComplex.Plus.modelCategoryQuillen.cm5a_cof.cochainComplexFunctor`). +Degreewise, this projective system is essentially constant, which allows +to take its limit, which shall be the intermediate object in the +lemma `cm5a_cof` (TODO). + +-/ + +open CategoryTheory Limits Opposite Abelian HomologicalComplex Pretriangulated + +variable {C : Type*} [Category* C] [Abelian C] + +namespace CochainComplex.Plus.modelCategoryQuillen + +variable {K L : CochainComplex C ℤ} (f : K ⟶ L) + +namespace cm5a_cof + +/-- Given a morphism `f : K ⟶ L`, this is the property of factorisations +of `f` consisting of a monomorphism followed by a degreewise epimorphism +with injective kernel. -/ +public def cofFib : ObjectProperty (Factorisation f) := + fun F ↦ Mono F.ι ∧ degreewiseEpiWithInjectiveKernel F.π + +instance (F : (cofFib f).FullSubcategory) : Mono F.obj.ι := + F.property.1 + +variable {f} in +/-- The property that the first morphism of a factorisation is +a quasi-isomorphisms in degrees `≤ n`. -/ +public def quasiIsoLE (n : ℤ) : ObjectProperty (cofFib f).FullSubcategory := + fun F ↦ ∀ i ≤ n, QuasiIsoAt F.obj.ι i + +variable {f} in +/-- The property that the second morphism of a factorisation is +an isomorphism in degrees `≤ n`. -/ +public def isIsoLE (n : ℤ) : ObjectProperty (cofFib f).FullSubcategory := + fun F ↦ ∀ i ≤ n, IsIso (F.obj.π.f i) + +namespace step₁ + +variable [EnoughInjectives C] + +/-! +This section provides the material in order to prove the lemma `step₁` below. +Given a monomorphism `f : K ⟶ L` in `CochainComplex C ℤ` which is +a quasi-isomorphism in degrees `≤ n₀` (with `n₀ + 1 = n₁`), we construct +a factorization `ι f n₁ ≫ π K L n₁ = f` where the intermediate object +`mid K L n₁` is `S K n₁ ⊞ L`, with `S K n₁` the single complex in degree `n₁` +given by an injective object containing `K.opcycles n₁` (which is a cokernel of +the differential `K.X n₀ ⟶ K.X n₁`). +We obtain that `ι f n₁` is a quasi-isomorphism in degrees `≤ n₀` and +induces a monomorphism in homology in degree `n₀`, +and that `π K L n₁` is an isomorphism in degrees `≤ n₀` that is +also a degreewise epimorphism with an injective kernel. -/ + +variable (n₀ n₁ : ℤ) (hn₁ : n₀ + 1 = n₁) + +variable (K) in +/-- The single complex in degree `n₁` that is given by an injective +object containing `K.opcycles n₁`. -/ +noncomputable abbrev S : CochainComplex C ℤ := + ((single C _ n₁).obj (Injective.under (K.opcycles n₁))) + +variable (K L) in +/-- The intermediate object in the factorization. -/ +noncomputable abbrev mid := S K n₁ ⊞ L + +variable (K) in +/-- The morphim `K ⟶ S K n₁` which in degree `n₁` corresponds to +the composition `K.X n₁ ⟶ K.opcycles n₁ ⟶ Injective.under (K.opcycles n₁)`. -/ +noncomputable def i : K ⟶ S K n₁ := mkHomToSingle (K.pOpcycles n₁ ≫ Injective.ι _) (by simp) + +/-- The first morphism in the factorization. -/ +noncomputable abbrev ι : K ⟶ mid K L n₁ := biprod.lift (i K n₁) f + +variable (K L) in +/-- The second morphism in the factorization. -/ +noncomputable abbrev π : mid K L n₁ ⟶ L := biprod.snd + +variable (K L) in +/-- A section of `π K L n₁` -/ +noncomputable abbrev σ : L ⟶ mid K L n₁ := biprod.inr + +@[reassoc] +lemma ι_π : ι f n₁ ≫ π K L n₁ = f := by simp + +instance [Mono f] : Mono (ι f n₁) := mono_of_mono_fac (ι_π f n₁) + +variable (K L) in +lemma degreewiseEpiWithInjectiveKernel_π : + degreewiseEpiWithInjectiveKernel (π K L n₁) := by + intro q + rw [Abelian.epiWithInjectiveKernel_iff] + exact ⟨(S K n₁).X q, inferInstance, (biprod.inl : _ ⟶ mid K L n₁).f q, by simp, + ⟨{ r := (biprod.fst : mid K L n₁ ⟶ _).f q, s := (biprod.inr : _ ⟶ mid K L n₁).f q }⟩⟩ + +variable (K L) in +lemma isIso_π_f (i : ℤ) (hi : i ≠ n₁ := by lia) : + IsIso ((π K L n₁).f i) := by + refine ⟨(biprod.inr : _ ⟶ mid K L n₁).f i, ?_, by simp⟩ + rw [biprodX_ext_to_iff] + constructor + · apply (isZero_single_obj_X (.up ℤ) _ _ _ hi).eq_of_tgt + · simp + +include hn₁ in +variable (K L) in +lemma quasiIsoAt_π (i : ℤ) (hi : i ≤ n₀ := by lia) : + QuasiIsoAt (π K L n₁) i := by + obtain (hi | rfl) := hi.lt_or_eq + · rw [quasiIsoAt_iff' _ (i - 1) i (i + 1) (by simp) (by simp)] + let φ := (shortComplexFunctor' C _ (i - 1) i (i + 1)).map (π K L n₁) + have : IsIso φ.τ₁ := isIso_π_f .. + have : IsIso φ.τ₂ := isIso_π_f .. + have : IsIso φ.τ₃ := isIso_π_f .. + exact ShortComplex.quasiIso_of_epi_of_isIso_of_mono φ + · rw [quasiIsoAt_iff_isIso_homologyMap] + have : homologyMap (biprod.inl : _ ⟶ mid K L n₁) i = 0 := + (ShortComplex.isZero_homology_of_isZero_X₂ _ + (isZero_single_obj_X (.up ℤ) _ _ _ (by lia))).eq_of_src _ _ + refine ⟨homologyMap (σ K L n₁) i, ?_, ?_⟩ + · simp [← homologyMap_id, ← biprod.total, homologyMap_comp, this] + · simp [← homologyMap_comp, homologyMap_id] + +variable (hf : ∀ i ≤ n₀, QuasiIsoAt f i) + +include hn₁ hf in +lemma quasiIsoAt_ι (i : ℤ) (hi : i ≤ n₀) : + QuasiIsoAt (ι f n₁) i := by + have := quasiIsoAt_π K L n₀ n₁ hn₁ i hi + rw [← quasiIsoAt_iff_comp_right _ (π K L n₁), ι_π] + exact hf i hi + +instance : Mono (homologyMap (ι f n₁) n₁) := by + let n₀ := n₁ - 1 + rw [mono_homologyMap_iff_up_to_refinements _ n₀ n₁ (n₁ + 1) (by simp; lia) (by simp)] + intro A x₁ _ y₀ hy₀ + obtain ⟨y₀, rfl⟩ : ∃ (z₁ : A ⟶ L.X n₀), z₁ ≫ (σ K L n₁).f n₀ = y₀ := by + refine ⟨y₀ ≫ (π K L n₁).f n₀, Eq.trans ?_ (Category.comp_id _)⟩ + have : (biprod.inl : _ ⟶ mid K L n₁).f n₀ = 0 := + (isZero_single_obj_X (.up ℤ) _ _ _ (by lia)).eq_of_src _ _ + simp [this, ← biprod_total_f] + simp only [Category.assoc, Hom.comm, biprodX_ext_to_iff, biprod_lift_fst_f, + biprod_inr_fst_f, comp_zero, biprod_lift_snd_f, biprod_inr_snd_f, + Category.comp_id] at hy₀ + obtain ⟨h₁, h₂⟩ := hy₀ + replace h₁ : x₁ ≫ K.pOpcycles n₁ = 0 := by + rw [← cancel_mono (Injective.ι _)] + simpa [i, ← cancel_mono (singleObjXSelf (.up ℤ) n₁ _).hom] using h₁ + obtain ⟨A₁, π, _, x₀, hx₀⟩ := + (K.comp_pOpcycles_eq_zero_iff_up_to_refinements x₁ n₀ (by simp; lia)).1 h₁ + exact ⟨A₁, π, inferInstance, x₀, hx₀⟩ + +end step₁ + +-- This lemma and a few definitions above are made public only in order to please CI. +-- They will be made private again when the proofs of `cm5a_cof` and `cm5a` are added. +open step₁ in +public lemma step₁ [EnoughInjectives C] [Mono f] (n₀ n₁ : ℤ) + (hf : ∀ i ≤ n₀, QuasiIsoAt f i) (hn₁ : n₀ + 1 = n₁ := by lia) : + ∃ (F : (cofFib f).FullSubcategory), quasiIsoLE n₀ F ∧ isIsoLE n₀ F ∧ + Mono (homologyMap F.obj.ι n₁) := + ⟨.mk { mid := mid K L n₁, ι := ι f n₁, π := π K L n₁ } + ⟨inferInstance, degreewiseEpiWithInjectiveKernel_π K L n₁⟩, + fun i hi ↦ quasiIsoAt_ι f n₀ n₁ hn₁ hf i hi, + fun i hi ↦ isIso_π_f K L n₁ i (by lia), + inferInstance⟩ + +proof_wanted step₂ [EnoughInjectives C] [Mono f] (n₀ n₁ : ℤ) + (hf : ∀ i ≤ n₀, QuasiIsoAt f i) [Mono (homologyMap f n₁)] (hn₁ : n₀ + 1 = n₁ := by lia) : + ∃ (F : (cofFib f).FullSubcategory), quasiIsoLE n₁ F ∧ isIsoLE n₁ F + +proof_wanted step [EnoughInjectives C] [Mono f] (n₀ n₁ : ℤ) (hn₁ : n₀ + 1 = n₁) + (hf : ∀ i ≤ n₀, QuasiIsoAt f i) (hn₁ : n₀ + 1 = n₁ := by lia) : + ∃ (F : (cofFib f).FullSubcategory), quasiIsoLE n₁ F ∧ isIsoLE n₀ F + +end cm5a_cof + +proof_wanted cm5a_cof (n : ℤ) [K.IsStrictlyGE n] [L.IsStrictlyGE n] [Mono f] [EnoughInjectives C] : + ∃ (K' : CochainComplex C ℤ) (_hK' : K'.IsStrictlyGE n) (ι : K ⟶ K') (π : K' ⟶ L), + Mono ι ∧ QuasiIso ι ∧ degreewiseEpiWithInjectiveKernel π ∧ ι ≫ π = f + +proof_wanted cm5a (n : ℤ) [K.IsStrictlyGE (n + 1)] [L.IsStrictlyGE n] [EnoughInjectives C] : + ∃ (K' : CochainComplex C ℤ) (_hK' : K'.IsStrictlyGE n) (ι : K ⟶ K') (π : K' ⟶ L), + Mono ι ∧ QuasiIso ι ∧ degreewiseEpiWithInjectiveKernel π ∧ ι ≫ π = f + +end CochainComplex.Plus.modelCategoryQuillen diff --git a/Mathlib/Algebra/Homology/HomologicalBicomplex.lean b/Mathlib/Algebra/Homology/HomologicalBicomplex.lean index 695d7f7325f545..08c47437808ef4 100644 --- a/Mathlib/Algebra/Homology/HomologicalBicomplex.lean +++ b/Mathlib/Algebra/Homology/HomologicalBicomplex.lean @@ -110,7 +110,7 @@ end OfGradedObject /-- Constructor for a morphism `K ⟶ L` in the category `HomologicalComplex₂ C c₁ c₂` which takes as inputs a morphism `f : K.toGradedObject ⟶ L.toGradedObject` and -the compatibilites with both horizontal and vertical differentials. -/ +the compatibilities with both horizontal and vertical differentials. -/ @[simps!] def homMk {K L : HomologicalComplex₂ C c₁ c₂} (f : K.toGradedObject ⟶ L.toGradedObject) diff --git a/Mathlib/Algebra/Homology/HomologicalComplexAbelian.lean b/Mathlib/Algebra/Homology/HomologicalComplexAbelian.lean index 7202dc660a510d..2a32f76a3aa9e0 100644 --- a/Mathlib/Algebra/Homology/HomologicalComplexAbelian.lean +++ b/Mathlib/Algebra/Homology/HomologicalComplexAbelian.lean @@ -25,7 +25,11 @@ open CategoryTheory Category Limits namespace HomologicalComplex -variable {C ι : Type*} {c : ComplexShape ι} [Category* C] [Abelian C] +variable {C ι : Type*} {c : ComplexShape ι} [Category* C] + +section + +variable [Abelian C] noncomputable instance : IsNormalEpiCategory (HomologicalComplex C c) := ⟨fun p _ => ⟨NormalEpi.mk _ (kernel.ι p) (kernel.condition _) @@ -71,4 +75,28 @@ lemma shortExact_iff_degreewise_shortExact : exact hS.map (eval C c i) · exact shortExact_of_degreewise_shortExact S +end + +section + +variable [HasZeroMorphisms C] [HasZeroObject C] [DecidableEq ι] + +instance (i j : ι) (I : C) [Injective I] : + Injective (((single C c i).obj I).X j) := by + by_cases hij : j = i + · subst hij + simp only [single_obj_X_self] + infer_instance + · exact (isZero_single_obj_X _ _ _ _ hij).injective + +instance (i j : ι) (P : C) [Projective P] : + Projective (((single C c i).obj P).X j) := by + by_cases hij : j = i + · subst hij + simp only [single_obj_X_self] + infer_instance + · exact (isZero_single_obj_X _ _ _ _ hij).projective + +end + end HomologicalComplex diff --git a/Mathlib/Algebra/Homology/HomotopyCategory/HomComplexSingle.lean b/Mathlib/Algebra/Homology/HomotopyCategory/HomComplexSingle.lean index c3d357fd893fcb..bb849621c08d52 100644 --- a/Mathlib/Algebra/Homology/HomotopyCategory/HomComplexSingle.lean +++ b/Mathlib/Algebra/Homology/HomotopyCategory/HomComplexSingle.lean @@ -13,7 +13,7 @@ public import Mathlib.Algebra.Homology.HomotopyCategory.SingleFunctors We introduce constructors `Cochain.fromSingleMk` and `Cocycle.fromSingleMk` for cochains and cocycles from a single complex. We also introduce similar -definitions for cochains and cocyles to a single complex. +definitions for cochains and cocycles to a single complex. -/ diff --git a/Mathlib/Algebra/Homology/HomotopyCategory/Pretriangulated.lean b/Mathlib/Algebra/Homology/HomotopyCategory/Pretriangulated.lean index ffe8c0b311e222..2440de6b25e9ac 100644 --- a/Mathlib/Algebra/Homology/HomotopyCategory/Pretriangulated.lean +++ b/Mathlib/Algebra/Homology/HomotopyCategory/Pretriangulated.lean @@ -21,7 +21,7 @@ cochain complexes `φ : K ⟶ L`. This result first appeared in the Liquid Tensor Experiment. In the LTE, the formalization followed the Stacks Project: in particular, the distinguished triangles were defined using degreewise-split short exact sequences of cochain -complexes. Here, we follow the original definitions in [Verdiers's thesis, I.3][verdier1996] +complexes. Here, we follow the original definitions in [Verdier's thesis, I.3][verdier1996] (with the better sign conventions from the introduction of [Brian Conrad's book *Grothendieck duality and base change*][conrad2000]). diff --git a/Mathlib/Algebra/Homology/HomotopyCategory/SingleFunctors.lean b/Mathlib/Algebra/Homology/HomotopyCategory/SingleFunctors.lean index be9065b984f985..8a62dc6e083cfb 100644 --- a/Mathlib/Algebra/Homology/HomotopyCategory/SingleFunctors.lean +++ b/Mathlib/Algebra/Homology/HomotopyCategory/SingleFunctors.lean @@ -35,7 +35,7 @@ namespace CochainComplex open HomologicalComplex /-- The collection of all single functors `C ⥤ CochainComplex C ℤ` along with -their compatibilites with shifts. (This definition has purposely no `simps` +their compatibilities with shifts. (This definition has purposely no `simps` attribute, as the generated lemmas would not be very useful.) -/ noncomputable def singleFunctors : SingleFunctors C (CochainComplex C ℤ) ℤ where functor n := single _ _ n diff --git a/Mathlib/Algebra/Homology/ModelCategory/Lifting.lean b/Mathlib/Algebra/Homology/ModelCategory/Lifting.lean index 861d197ebd8915..ca2fc428f6150a 100644 --- a/Mathlib/Algebra/Homology/ModelCategory/Lifting.lean +++ b/Mathlib/Algebra/Homology/ModelCategory/Lifting.lean @@ -96,7 +96,7 @@ lemma π_f_cochain₁_v_ι_f (n m : ℤ) (hnm : n + 1 = m) : (exists_hom sq hsq hQ hK n m hnm).choose_spec /-- A `1`-cocycle from a cokernel `Q` of `i : A ⟶ B` to a kernel `K` of -`p : X ⟶ Y`. If this is a coboundary, then the square in `CochainCompplex C ℤ` +`p : X ⟶ Y`. If this is a coboundary, then the square in `CochainComplex C ℤ` has a lifting, see the lemma `hasLift` below. -/ noncomputable def cocycle₁ : Cocycle Q K 1 := Cocycle.mk (cochain₁ sq hsq hQ hK) 2 (by simp) (by diff --git a/Mathlib/Algebra/Homology/Single.lean b/Mathlib/Algebra/Homology/Single.lean index 7258ee68e4fae0..4ab1e05842a022 100644 --- a/Mathlib/Algebra/Homology/Single.lean +++ b/Mathlib/Algebra/Homology/Single.lean @@ -248,7 +248,7 @@ noncomputable def fromSingle₀Equiv (C : ChainComplex V ℕ) (X : V) : @[simp] lemma fromSingle₀Equiv_symm_apply_f_zero {C : ChainComplex V ℕ} {X : V} (f : X ⟶ C.X 0) : - ((fromSingle₀Equiv C X).symm f).f 0 = f := by + dsimp% ((fromSingle₀Equiv C X).symm f).f 0 = f := by simp [fromSingle₀Equiv] @[simp] diff --git a/Mathlib/Algebra/Homology/SpectralObject/Homology.lean b/Mathlib/Algebra/Homology/SpectralObject/Homology.lean index e345f9fc9c2948..c9c8b219e28c6b 100644 --- a/Mathlib/Algebra/Homology/SpectralObject/Homology.lean +++ b/Mathlib/Algebra/Homology/SpectralObject/Homology.lean @@ -120,7 +120,6 @@ noncomputable def dShortComplex ShortComplex C := ShortComplex.mk _ _ (X.d_d f₁ f₂ f₃ f₄ f₅ f₆ f₇ n₀ n₁ n₂ n₃ n₄) -set_option backward.isDefEq.respectTransparency false in @[reassoc] lemma map_fourδ₁Toδ₀_EMap_fourδ₄Toδ₃ (hn₂ : n₁ + 1 = n₂ := by lia) (hn₃ : n₂ + 1 = n₃ := by lia) : diff --git a/Mathlib/Algebra/Homology/SpectralObject/SpectralSequence.lean b/Mathlib/Algebra/Homology/SpectralObject/SpectralSequence.lean new file mode 100644 index 00000000000000..42e8d1ab62d434 --- /dev/null +++ b/Mathlib/Algebra/Homology/SpectralObject/SpectralSequence.lean @@ -0,0 +1,318 @@ +/- +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.Homology.SpectralObject.Homology +public import Mathlib.Algebra.Homology.SpectralObject.HasSpectralSequence +public import Mathlib.Algebra.Homology.SpectralSequence.Basic +public import Mathlib.Order.WithBotTop + +/-! +# The spectral sequence of a spectral object + +The main definition in this file is `Abelian.SpectralObject.spectralSequence` (TODO). +Assume that `X` is a spectral object indexed by `ι` in an abelian category `C`, +and that we have `data : SpectralSequenceDataCore ι c r₀` for a family +of complex shapes `c : ℤ → ComplexShape κ` for a type `κ` and `r₀ : ℤ`. +Then, under the assumption `X.HasSpectralSequence data` (see the file +`Mathlib/Algebra/Homology/SpectralObject/HasSpectralSequence.lean`), +we obtain `X.spectralSequence data` (TODO) which is a spectral sequence starting +on page `r₀`, such that the `r`th page (for `r₀ ≤ r`) is a homological +complex of shape `c r`. + +## Outline of the construction + +The construction of the spectral sequence is as follows. If `r₀ ≤ r` +and `pq : κ`, we define the object of the spectral sequence in position `pq` +on the `r`th page as `E^d(i₀ r pq ≤ i₁ pq ≤ i₂ pq ≤ i₃ r pq)` +where `d := data.deg pq` and the indices `i₀`, `i₁`, `i₂`, `i₃` are given +by `data` (they all depend on `pq`, and `i₀` and `i₃` also depend on the page `r`), +see `spectralSequencePageXIso`. + +When `(c r).Rel pq pq'`, the differential from the object in position `pq` +to the object in position `pq'` on the `r`th page can be related to +the differential `X.d` of the spectral object (see the lemma +`spectralSequence_page_d_eq`). Indeed, the assumptions that +are part of `data` give equalities of indices `i₂ r pq' = i₀ r pq` +and `i₃ pq' = i₁ pq`, so that we have a chain of inequalities +`i₀ r pq' ≤ i₁ pq' ≤ i₂ pq' ≤ i₃ r pq' ≤ i₂ pq ≤ i₃ r pq` for which +the API of spectral objects provides a differential +`X.d : E^n(i₀ r pq ≤ i₁ pq ≤ i₂ pq ≤ i₃ r pq) ⟶ E^{n + 1}(i₀ r pq' ≤ i₁ pq' ≤ i₂ pq' ≤ i₃ r pq')`. + +Now, fix `r` and three positions `pq`, `pq'` and `pq''` such that +`pq` is the previous object of `pq'` for `c r` and `pq''` is the next +object of `pq'`. (Note that in case there are no nontrivial differentials +to the object `pq'` for the complex shape `c r`, according to the homological +complex API, we have `pq = pq'` and the differential is zero. Similarly, +when there are no nontrivial differentials from the object in position `pq'`, +we have `pq'' = pq` and the corresponding differential is zero.) +In the favourable case where both `(c r).Rel pq pq'` and `(c r).Rel pq' pq''` +hold, the definition `SpectralObject.SpectralSequence.shortComplexIso` +in this file can be used in combination to `SpectralObject.SpectralSequence.dHomologyIso` +in order to compute the homology of the differentials.) + +In the general case, using the assumptions in `X.HasSpectralSequence data`, +we provide a limit kernel fork `kf` and +a limit cokernel cofork `cc` of the differentials on the `r`th page, +together with an epi-mono factorization `fac` which allows +to obtain that the homology of the `r`th page identifies to the next page (see the definitions +`SpectralObject.SpectralSequence.homologyData` (TODO) and +`SpectralObject.spectralSequenceHomologyData` (TODO)). + +-/ + +@[expose] public section + +namespace CategoryTheory + +open Limits ComposableArrows + +namespace Abelian + +namespace SpectralObject + +variable {C ι κ : Type*} [Category* C] [Abelian C] [Preorder ι] + (X : SpectralObject C ι) + {c : ℤ → ComplexShape κ} {r₀ : ℤ} + +variable (data : SpectralSequenceDataCore ι c r₀) + +namespace SpectralSequence + +/-- The object on position `pq` on the `r`th page of the spectral sequence. -/ +noncomputable def pageX (r : ℤ) (pq : κ) (hr : r₀ ≤ r := by lia) : C := + X.E (homOfLE (data.le₀₁ r pq)) (homOfLE (data.le₁₂ pq)) (homOfLE (data.le₂₃ r pq)) + (data.deg pq - 1) (data.deg pq) (data.deg pq + 1) + +/-- The object on position `pq` on the `r`th page of the spectral sequence identifies +to `E^{deg pq}(i₀ ≤ i₁ ≤ i₂ ≤ i₃)`. -/ +noncomputable def pageXIso (r : ℤ) (hr : r₀ ≤ r) (pq : κ) + (i₀ i₁ i₂ i₃ : ι) (h₀ : i₀ = data.i₀ r pq) (h₁ : i₁ = data.i₁ pq) + (h₂ : i₂ = data.i₂ pq) (h₃ : i₃ = data.i₃ r pq) + (n₀ n₁ n₂ : ℤ) (h : n₁ = data.deg pq) + (hn₁ : n₀ + 1 = n₁ := by lia) (hn₂ : n₁ + 1 = n₂ := by lia) : + pageX X data r pq hr ≅ X.E + (homOfLE (data.le₀₁' r hr pq h₀ h₁)) + (homOfLE (data.le₁₂' pq h₁ h₂)) + (homOfLE (data.le₂₃' r hr pq h₂ h₃)) + n₀ n₁ n₂ hn₁ hn₂ := + eqToIso (by + obtain rfl : n₀ = n₁ - 1 := by lia + subst h hn₂ h₀ h₁ h₂ h₃ + rfl) + +open Classical in +/-- The differential on the `r`th page of the spectral sequence. -/ +noncomputable def pageD (r : ℤ) (pq pq' : κ) (hr : r₀ ≤ r := by lia) : + pageX X data r pq hr ⟶ pageX X data r pq' hr := + if hpq : (c r).Rel pq pq' + then + X.d (homOfLE (data.le₀₁ r pq')) + (homOfLE (data.le₁₂' pq' rfl (data.hc₀₂ r pq pq' hpq))) + (homOfLE (data.le₀₁ r pq)) (homOfLE (data.le₁₂ pq)) (homOfLE (data.le₂₃ r pq)) + (data.deg pq - 1) (data.deg pq) (data.deg pq + 1) (data.deg pq + 2) ≫ + (pageXIso _ _ _ _ _ _ _ _ _ rfl rfl + (data.hc₀₂ r pq pq' hpq) (data.hc₁₃ r pq pq' hpq) _ _ _ (data.hc r pq pq' hpq) rfl _).inv + else 0 + +set_option backward.isDefEq.respectTransparency false in +lemma pageD_eq (r : ℤ) (hr : r₀ ≤ r) (pq pq' : κ) (hpq : (c r).Rel pq pq') + {i₀ i₁ i₂ i₃ i₄ i₅ : ι} (f₁ : i₀ ⟶ i₁) (f₂ : i₁ ⟶ i₂) (f₃ : i₂ ⟶ i₃) + (f₄ : i₃ ⟶ i₄) (f₅ : i₄ ⟶ i₅) + (h₀ : i₀ = data.i₀ r pq') (h₁ : i₁ = data.i₁ pq') (h₂ : i₂ = data.i₀ r pq) + (h₃ : i₃ = data.i₁ pq) (h₄ : i₄ = data.i₂ pq) (h₅ : i₅ = data.i₃ r pq) + (n₀ n₁ n₂ n₃ : ℤ) (hn₁' : n₁ = data.deg pq) + (hn₁ : n₀ + 1 = n₁ := by lia) (hn₂ : n₁ + 1 = n₂ := by lia) (hn₃ : n₂ + 1 = n₃ := by lia) : + pageD X data r pq pq' = + (pageXIso _ _ _ _ _ _ _ _ _ h₂ h₃ h₄ h₅ _ _ _ hn₁' _ _).hom ≫ + X.d f₁ f₂ f₃ f₄ f₅ n₀ n₁ n₂ n₃ hn₁ hn₂ hn₃ ≫ + (pageXIso _ _ _ _ _ _ _ _ _ h₀ h₁ (by rw [h₂, data.hc₀₂ r pq pq' hpq]) + (by rw [h₃, data.hc₁₃ r pq pq' hpq]) _ _ _ + (by simpa only [← hn₂, hn₁'] using data.hc r pq pq' hpq) _ _).inv := by + subst hn₁' h₀ h₁ h₂ h₃ h₄ h₅ + obtain rfl : n₀ = data.deg pq - 1 := by lia + obtain rfl : n₂ = data.deg pq + 1 := by lia + obtain rfl : n₃ = data.deg pq + 2 := by lia + dsimp [pageD, pageXIso] + rw [dif_pos hpq, Category.id_comp] + rfl + +@[reassoc (attr := simp)] +lemma pageD_pageD (r : ℤ) (hr : r₀ ≤ r) (pq pq' pq'' : κ) : + pageD X data r pq pq' hr ≫ pageD X data r pq' pq'' hr = 0 := by + by_cases hpq : (c r).Rel pq pq' + · by_cases hpq' : (c r).Rel pq' pq'' + · rw [pageD_eq X data r hr pq pq' hpq (homOfLE (data.le₂₃ r pq'')) + (homOfLE (data.le₁₂' pq' (data.hc₁₃ r pq' pq'' hpq').symm + (data.hc₀₂ r pq pq' hpq))) (homOfLE (data.le₀₁ r pq)) (homOfLE (data.le₁₂ pq)) + (homOfLE (data.le₂₃ r pq)) + (data.hc₀₂ r pq' pq'' hpq').symm (data.hc₁₃ r pq' pq'' hpq').symm rfl rfl rfl rfl + (data.deg pq - 1) (data.deg pq) (data.deg pq + 1) (data.deg pq + 2) rfl, + pageD_eq X data r hr pq' pq'' hpq' _ _ _ _ _ rfl rfl + (data.hc₀₂ r pq' pq'' hpq').symm (data.hc₁₃ r pq' pq'' hpq').symm + (data.hc₀₂ r pq pq' hpq) (data.hc₁₃ r pq pq' hpq) + _ _ (data.deg pq + 2) _ (data.hc r pq pq' hpq) rfl (by lia) rfl, + Category.assoc, Category.assoc, Iso.inv_hom_id_assoc, + d_d_assoc .., zero_comp, comp_zero] + · dsimp only [pageD] + rw [dif_neg hpq', comp_zero] + · dsimp only [pageD] + rw [dif_neg hpq, zero_comp] + +/-- The `r`th page of the spectral sequence. -/ +@[simps] +noncomputable def page (r : ℤ) (hr : r₀ ≤ r) : + HomologicalComplex C (c r) where + X pq := pageX X data r pq + d := pageD X data r + shape pq pq' hpq := dif_neg hpq + +/-- The short complex of the `r`th page of the spectral sequence on position `pq'` +identifies to the short complex given by the differentials of the spectral object. +Then, the homology of this short complex can be computed using +`SpectralSequence.dHomologyIso`. +(This only applies in the favourable case when there are `pq` and `pq''` such +that `(c r).Rel pq pq'` and `(c r).Rel pq' pq''` hold.) -/ +noncomputable def shortComplexIso (r : ℤ) (hr : r₀ ≤ r) (pq pq' pq'' : κ) + (hpq : (c r).Rel pq pq') (hpq' : (c r).Rel pq' pq'') + (n₀ n₁ n₂ n₃ n₄ : ℤ) + (hn₁ : n₀ + 1 = n₁) (hn₂ : n₁ + 1 = n₂) (hn₃ : n₂ + 1 = n₃) (hn₄ : n₃ + 1 = n₄) + (hn₂' : n₂ = data.deg pq') : + (page X data r hr).sc' pq pq' pq'' ≅ + X.dShortComplex (homOfLE (data.le₀₁ r pq'')) + (homOfLE (data.le₁₂ pq'')) (homOfLE (data.le₂₃ r pq'')) + (homOfLE (by simpa only [← data.hc₁₃ r pq' pq'' hpq', data.hc₀₂ r pq pq' hpq] + using data.le₁₂ pq')) (homOfLE (data.le₀₁ r pq)) + (homOfLE (data.le₁₂ pq)) (homOfLE (data.le₂₃ r pq)) n₀ n₁ n₂ n₃ n₄ hn₁ hn₂ hn₃ hn₄ := by + refine ShortComplex.isoMk + (pageXIso _ _ _ hr _ _ _ _ _ rfl rfl rfl rfl _ _ _ (by have := data.hc r pq pq' hpq; lia)) + (pageXIso _ _ _ hr _ _ _ _ _ (by rw [data.hc₀₂ r pq' pq'' hpq']) + (by rw [data.hc₁₃ r pq' pq'' hpq']) + (by rw [data.hc₀₂ r pq pq' hpq]) (by rw [data.hc₁₃ r pq pq' hpq]) _ _ _ hn₂') + (pageXIso _ _ _ hr _ _ _ _ _ rfl rfl rfl rfl _ _ _ (by have := data.hc r pq' pq'' hpq'; lia)) + ?_ ?_ + · simp only [← Iso.comp_inv_eq, Category.assoc] + exact (pageD_eq X data r hr pq pq' hpq _ _ _ _ _ (data.hc₀₂ r pq' pq'' hpq').symm + (data.hc₁₃ r pq' pq'' hpq').symm ..).symm + · simp only [← Iso.comp_inv_eq, Category.assoc] + exact (pageD_eq X data r hr pq' pq'' hpq' _ _ _ _ _ rfl rfl ..).symm + +section + +variable (r r' : ℤ) (hrr' : r + 1 = r') (hr : r₀ ≤ r) + (pq pq' pq'' : κ) (hpq : (c r).prev pq' = pq) (hpq' : (c r).next pq' = pq'') + (i₀' i₀ i₁ i₂ i₃ i₃' : ι) + (hi₀' : i₀' = data.i₀ r' pq') + (hi₀ : i₀ = data.i₀ r pq') + (hi₁ : i₁ = data.i₁ pq') + (hi₂ : i₂ = data.i₂ pq') + (hi₃ : i₃ = data.i₃ r pq') + (hi₃' : i₃' = data.i₃ r' pq') + (n₀ n₁ n₂ : ℤ) + (hn₁' : n₁ = data.deg pq') + +namespace HomologyData + +set_option backward.isDefEq.respectTransparency false in +lemma kf_w (hn₁ : n₀ + 1 = n₁ := by lia) (hn₂ : n₁ + 1 = n₂ := by lia) : + (X.mapFourδ₁Toδ₀' i₀' i₀ i₁ i₂ i₃ (data.i₀_le' hrr' hr pq' hi₀' hi₀) + (data.le₀₁' r hr pq' hi₀ hi₁) (data.le₁₂' pq' hi₁ hi₂) (data.le₂₃' r hr pq' hi₂ hi₃) + n₀ n₁ n₂ hn₁ hn₂ ≫ + (pageXIso X data _ hr _ _ _ _ _ hi₀ hi₁ hi₂ hi₃ _ _ _ hn₁' _ _ ).inv) ≫ + (page X data r hr).d pq' pq'' = 0 := by + by_cases h : (c r).Rel pq' pq'' + · dsimp + rw [pageD_eq X data r hr pq' pq'' h + (homOfLE (by simpa only [hi₀', data.i₀_prev r r' _ _ h] using data.le₀₁ r pq'')) + (homOfLE (data.i₀_le' hrr' hr pq' hi₀' hi₀)) _ _ _ rfl + (by rw [hi₀', data.i₀_prev r r' pq' pq'' h]) hi₀ hi₁ hi₂ hi₃ _ _ _ _ hn₁' hn₁ hn₂ rfl, + Category.assoc, Iso.inv_hom_id_assoc, map_fourδ₁Toδ₀_d_assoc .., zero_comp] + · rw [HomologicalComplex.shape _ _ _ h, comp_zero] + +/-- A (limit) kernel fork of the differential on the `r`th page whose point +identifies to an object `X.E` -/ +noncomputable abbrev kf (hn₁ : n₀ + 1 = n₁ := by lia) (hn₂ : n₁ + 1 = n₂ := by lia) : + KernelFork ((page X data r hr).d pq' pq'') := + KernelFork.ofι _ (kf_w X data r r' hrr' hr pq' pq'' + i₀' i₀ i₁ i₂ i₃ hi₀' hi₀ hi₁ hi₂ hi₃ n₀ n₁ n₂ hn₁') + +/-- The (exact) short complex attached to the kernel fork `kf`. -/ +@[simps!] +noncomputable def kfSc (hn₁ : n₀ + 1 = n₁ := by lia) (hn₂ : n₁ + 1 = n₂ := by lia) : + ShortComplex C := + ShortComplex.mk _ _ (kf_w X data r r' hrr' hr pq' pq'' + i₀' i₀ i₁ i₂ i₃ hi₀' hi₀ hi₁ hi₂ hi₃ n₀ n₁ n₂ hn₁' hn₁) + +instance (hn₁ : n₀ + 1 = n₁) (hn₂ : n₁ + 1 = n₂) : + Mono (kfSc X data r r' hrr' hr pq' pq'' i₀' i₀ i₁ i₂ i₃ + hi₀' hi₀ hi₁ hi₂ hi₃ n₀ n₁ n₂ hn₁' hn₁ hn₂).f := by + dsimp + infer_instance + +variable [X.HasSpectralSequence data] in +include hpq' hn₁' in +lemma isIso_mapFourδ₁Toδ₀' (h : ¬ (c r).Rel pq' pq'') + (hn₁ : n₀ + 1 = n₁ := by lia) (hn₂ : n₁ + 1 = n₂ := by lia) : + IsIso (X.mapFourδ₁Toδ₀' + i₀' i₀ i₁ i₂ i₃ (data.i₀_le' hrr' hr pq' hi₀' hi₀) (data.le₀₁' r hr pq' hi₀ hi₁) + (data.le₁₂' pq' hi₁ hi₂) (data.le₂₃' r hr pq' hi₂ hi₃) n₀ n₁ n₂ hn₁ hn₂) := by + apply X.isIso_map_fourδ₁Toδ₀_of_isZero .. + refine X.isZero_H_obj_mk₁_i₀_le' data r r' hrr' hr pq' (fun k hk ↦ ?_) _ (by lia) _ _ hi₀' hi₀ + obtain rfl := (c r).next_eq' hk + subst hpq' + exact h hk + +variable [X.HasSpectralSequence data] in +include hpq' in +lemma kfSc_exact (hn₁ : n₀ + 1 = n₁ := by lia) (hn₂ : n₁ + 1 = n₂ := by lia) : + (kfSc X data r r' hrr' hr pq' pq'' i₀' i₀ i₁ i₂ i₃ hi₀' hi₀ hi₁ hi₂ hi₃ + n₀ n₁ n₂ hn₁' hn₁ hn₂).Exact := by + by_cases h : (c r).Rel pq' pq'' + · refine ShortComplex.exact_of_iso (Iso.symm ?_) + (X.dKernelSequence_exact + (homOfLE (show data.i₀ r pq'' ≤ i₀' by + simpa only [hi₀', data.i₀_prev r r' _ _ h] using data.le₀₁ r pq'')) + (homOfLE (data.i₀_le' hrr' hr pq' hi₀' hi₀)) (homOfLE (data.le₀₁' r hr pq' hi₀ hi₁)) + (homOfLE (data.le₁₂' pq' hi₁ hi₂)) (homOfLE (data.le₂₃' r hr pq' hi₂ hi₃)) _ rfl + n₀ n₁ n₂ (n₂ + 1) hn₁ hn₂ rfl) + refine ShortComplex.isoMk (Iso.refl _) + (pageXIso X data _ hr _ _ _ _ _ hi₀ hi₁ hi₂ hi₃ _ _ _ hn₁') + (pageXIso X data _ hr _ _ _ _ _ rfl (by rw [hi₀', data.i₀_prev r r' _ _ h]) + (by rw [hi₀, data.hc₀₂ r _ _ h]) (by rw [hi₁, data.hc₁₃ r _ _ h]) _ _ _ + (by have := data.hc r _ _ h; lia)) ?_ ?_ + · simp + · dsimp + rw [pageD_eq X data r hr pq' pq'' h + (homOfLE (show data.i₀ r pq'' ≤ i₀' by + simpa only [hi₀', data.i₀_prev r r' _ _ h] using data.le₀₁ r pq'')) + _ _ _ _ rfl _ _ _ _ _ n₀ n₁ n₂ (n₂ + 1), + Category.assoc, Category.assoc, Iso.inv_hom_id, Category.comp_id] + rw [hi₀', data.i₀_prev r r' _ _ h] + · rw [ShortComplex.exact_iff_epi _ ((page X data r hr).shape _ _ h)] + have := isIso_mapFourδ₁Toδ₀' X data r r' hrr' hr pq' pq'' hpq' + i₀' i₀ i₁ i₂ i₃ hi₀' hi₀ hi₁ hi₂ hi₃ n₀ n₁ n₂ hn₁' h + dsimp + infer_instance + +variable [X.HasSpectralSequence data] in +/-- The kernel fork `kf` is a limit. -/ +noncomputable def isLimitKf (hn₁ : n₀ + 1 = n₁ := by lia) (hn₂ : n₁ + 1 = n₂ := by lia) : + IsLimit (kf X data r r' hrr' hr pq' pq'' + i₀' i₀ i₁ i₂ i₃ hi₀' hi₀ hi₁ hi₂ hi₃ n₀ n₁ n₂ hn₁' hn₁ hn₂) := + (kfSc_exact X data r r' hrr' hr pq' pq'' hpq' + i₀' i₀ i₁ i₂ i₃ hi₀' hi₀ hi₁ hi₂ hi₃ n₀ n₁ n₂ hn₁' hn₁ hn₂).fIsKernel + +end HomologyData + +end + +end SpectralSequence + +end SpectralObject + +end Abelian + +end CategoryTheory diff --git a/Mathlib/Algebra/InstantTheorem.lean b/Mathlib/Algebra/InstantTheorem.lean new file mode 100644 index 00000000000000..c7d4c00f1cf35c --- /dev/null +++ b/Mathlib/Algebra/InstantTheorem.lean @@ -0,0 +1 @@ +Nat.add_comm a b diff --git a/Mathlib/Algebra/Lie/CartanExists.lean b/Mathlib/Algebra/Lie/CartanExists.lean index cdd38bb553a734..266f79f139084a 100644 --- a/Mathlib/Algebra/Lie/CartanExists.lean +++ b/Mathlib/Algebra/Lie/CartanExists.lean @@ -198,7 +198,7 @@ lemma engel_isBot_of_isMin (hLK : finrank K L ≤ #K) (U : LieSubalgebra K L) -- We separately consider the case `i = 0`. obtain rfl | hi0 := eq_or_ne i 0 · -- `The polynomial `coeff χ 0` is zero if it evaluates to zero on all elements of `K`, - -- provided that its degree is stictly less than `#K`. + -- provided that its degree is strictly less than `#K`. apply eq_zero_of_forall_eval_zero_of_natDegree_lt_card _ _ ?deg case deg => -- We need to show `(natDegree (coeff χ 0)) < #K` and know that `finrank K L ≤ #K` diff --git a/Mathlib/Algebra/Lie/Derivation/BaseChange.lean b/Mathlib/Algebra/Lie/Derivation/BaseChange.lean new file mode 100644 index 00000000000000..f9dcaaee4ef1e2 --- /dev/null +++ b/Mathlib/Algebra/Lie/Derivation/BaseChange.lean @@ -0,0 +1,97 @@ +/- +Copyright (c) 2026 Leonid Ryvkin. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Leonid Ryvkin +-/ +module + +public import Mathlib.Algebra.Lie.BaseChange +public import Mathlib.Algebra.Lie.Derivation.Basic +public import Mathlib.RingTheory.Derivation.Lie + +/-! +# LieDerivations of a Lie algebra created through BaseChange + +When, given an `R`-algebra `A` and an `R`-Lie algebra `L` the (Lie algebra) basechange `A ⊗[R] L`, +both derivations of `A` and Lie derivations of `L` induce Lie derivations of `A ⊗[R] L`. Moreover, +both these procedures are Lie algebra homomorphisms themselves. + + +## Tags + +lie algebra, extension of scalars, base change, derivation + +-/ + +@[expose] public section +namespace Lie.Derivation + +open TensorProduct +variable {R : Type*} [CommRing R] +variable {A : Type*} [CommRing A] [Algebra R A] +variable {L : Type*} [LieRing L] [LieAlgebra R L] + +variable (L) in +/-- A derivation of an associative `R`-algebra `A`, induces a Lie derivation of `A ⊗[R] L` for any +Lie algebra `L` over `R`. -/ +def ofDerivation : Derivation R A A →ₗ⁅R⁆ LieDerivation R (A ⊗[R] L) (A ⊗[R] L) where + toFun d := + { toFun := d.rTensor L + map_add' := by simp + map_smul' := by simp + leibniz' x y := by + simp only [LinearMap.coe_mk, AddHom.coe_mk] + refine x.induction_on (by simp) (fun _ l ↦ ?_) (fun _ _ h1 h2 ↦ ?_) + · refine y.induction_on (by simp) (fun _ l' ↦ ?_) (fun _ _ h1 h2 ↦ ?_) + · simp [← lie_skew l' l, -lie_skew, add_tmul, tmul_neg] + · simp [h1, h2, sub_add_sub_comm] + · simp [h1, h2, sub_add_sub_comm] } + map_add' _ _ := by ext; simp + map_smul' _ _ := by ext; simp + map_lie' {_ _} := by + ext z + refine z.induction_on (by simp) (by simp [sub_tmul]) (fun _ _ hx hy ↦ ?_) + simp_all + abel + +@[simp] +lemma ofDerivation_apply (d : Derivation R A A) (x : A ⊗[R] L) : + ofDerivation L d x = d.toLinearMap.rTensor L x := + rfl + +variable (A) in +/-- A Lie derivation of an `R-`Lie algebra `L`, induces a Lie derivation of `A ⊗[R] L` for any +Algebra `A` over `R`. -/ +def ofLieDerivation : (LieDerivation R L L) →ₗ⁅R⁆ (LieDerivation R (A ⊗[R] L) (A ⊗[R] L)) where + toFun d := + { toFun := d.toLinearMap.lTensor A + map_add' := by simp + map_smul' := by simp + leibniz' x y:= by + simp only [LinearMap.coe_mk, AddHom.coe_mk] + refine x.induction_on (by simp) ?_ ?_ + · intros _ _ + refine y.induction_on (by simp) ?_ ?_ + · intros _ _ + simp [LieAlgebra.ExtendScalars.bracket_tmul, tmul_sub, mul_comm] + · intros _ _ h1 h2 + simp [h1, h2] + abel_nf + · intros _ _ h1 h2 + simp [h1, h2] + abel_nf } + map_add' _ _ := by ext _; simp + map_smul' _ _ := by ext _; simp + map_lie' {_ _} := by + ext z + refine z.induction_on (by simp) (fun a l ↦ ?_) (fun _ _ hx hy ↦ ?_) + · simp [tmul_sub] + · simp_all [sub_add_sub_comm] + +@[simp] +lemma ofLieDerivation_apply (d : LieDerivation R L L) (x : A ⊗[R] L) : + ofLieDerivation A d x = d.toLinearMap.lTensor A x := + rfl + +end Lie.Derivation +end diff --git a/Mathlib/Algebra/Lie/Derivation/Basic.lean b/Mathlib/Algebra/Lie/Derivation/Basic.lean index 47eeac256c4de9..629e1d93c7275a 100644 --- a/Mathlib/Algebra/Lie/Derivation/Basic.lean +++ b/Mathlib/Algebra/Lie/Derivation/Basic.lean @@ -333,14 +333,14 @@ section variable (R L : Type*) [CommRing R] [LieRing L] [LieAlgebra R L] set_option backward.isDefEq.respectTransparency false in -/-- The Lie algebra morphism from Lie derivations into linear endormophisms. -/ +/-- The Lie algebra morphism from Lie derivations into linear endomorphisms. -/ def toLinearMapLieHom : LieDerivation R L L →ₗ⁅R⁆ L →ₗ[R] L where toFun := toLinearMap map_add' := by intro D1 D2; dsimp map_smul' := by intro D1 D2; dsimp map_lie' := by intro D1 D2; dsimp -/-- The map from Lie derivations to linear endormophisms is injective. -/ +/-- The map from Lie derivations to linear endomorphisms is injective. -/ lemma toLinearMapLieHom_injective : Function.Injective (toLinearMapLieHom R L) := fun _ _ h ↦ ext fun a ↦ congrFun (congrArg DFunLike.coe h) a diff --git a/Mathlib/Algebra/Lie/EngelSubalgebra.lean b/Mathlib/Algebra/Lie/EngelSubalgebra.lean index 922d324bdb3637..77c52aedbc4bfe 100644 --- a/Mathlib/Algebra/Lie/EngelSubalgebra.lean +++ b/Mathlib/Algebra/Lie/EngelSubalgebra.lean @@ -82,7 +82,7 @@ lemma engel_zero : engel R (0 : L) = ⊤ := by /-- Engel subalgebras are self-normalizing. See `LieSubalgebra.normalizer_eq_self_of_engel_le` for a proof that Lie-subalgebras containing an Engel subalgebra are also self-normalizing, -provided that the ambient Lie algebra is artinina. -/ +provided that the ambient Lie algebra is Artinian. -/ @[simp] lemma normalizer_engel (x : L) : normalizer (engel R x) = engel R x := by apply le_antisymm _ (le_normalizer _) diff --git a/Mathlib/Algebra/Lie/Quotient.lean b/Mathlib/Algebra/Lie/Quotient.lean index d63988d4fdb2ea..4bc4ed7e81a994 100644 --- a/Mathlib/Algebra/Lie/Quotient.lean +++ b/Mathlib/Algebra/Lie/Quotient.lean @@ -128,28 +128,28 @@ theorem mk_bracket (x y : L) : mk ⁅x, y⁆ = ⁅(mk x : L ⧸ I), (mk y : L rfl instance lieQuotientLieRing : LieRing (L ⧸ I) where - add_lie := by - intro x' y' z'; refine Quotient.inductionOn₃' x' y' z' ?_; intro x y z + add_lie x' y' z' := by + induction x', y', z' using Quotient.inductionOn₃' with | _ x y z repeat' first | rw [is_quotient_mk] | rw [← mk_bracket] | rw [← Submodule.Quotient.mk_add (R := R) (M := L)] apply congr_arg; apply add_lie - lie_add := by - intro x' y' z'; refine Quotient.inductionOn₃' x' y' z' ?_; intro x y z + lie_add x' y' z' := by + induction x', y', z' using Quotient.inductionOn₃' with | _ x y z repeat' first | rw [is_quotient_mk] | rw [← mk_bracket] | rw [← Submodule.Quotient.mk_add (R := R) (M := L)] apply congr_arg; apply lie_add - lie_self := by - intro x'; refine Quotient.inductionOn' x' ?_; intro x + lie_self x' := by + induction x' using Quotient.inductionOn' with | _ x rw [is_quotient_mk, ← mk_bracket] apply congr_arg; apply lie_self - leibniz_lie := by - intro x' y' z'; refine Quotient.inductionOn₃' x' y' z' ?_; intro x y z + leibniz_lie x' y' z' := by + induction x', y', z' using Quotient.inductionOn₃' with | _ x y z repeat' first | rw [is_quotient_mk] @@ -158,8 +158,8 @@ instance lieQuotientLieRing : LieRing (L ⧸ I) where apply congr_arg; apply leibniz_lie instance lieQuotientLieAlgebra : LieAlgebra R (L ⧸ I) where - lie_smul := by - intro t x' y'; refine Quotient.inductionOn₂' x' y' ?_; intro x y + lie_smul t x' y' := by + induction x', y' using Quotient.inductionOn₂' with | _ x y repeat' first | rw [is_quotient_mk] diff --git a/Mathlib/Algebra/Lie/Weights/IsSimple.lean b/Mathlib/Algebra/Lie/Weights/IsSimple.lean index 95acdf35ba4375..1103149b58ed3b 100644 --- a/Mathlib/Algebra/Lie/Weights/IsSimple.lean +++ b/Mathlib/Algebra/Lie/Weights/IsSimple.lean @@ -9,11 +9,20 @@ public import Mathlib.Algebra.Lie.Weights.RootSystem public import Mathlib.LinearAlgebra.RootSystem.Finite.Lemmas /-! -# Simple Lie algebras +# Lie ideals, invariant root submodules, and simple Lie algebras -We show the irreducibility of root systems of simple Lie algebras. +Given a semisimple Lie algebra, the lattice of ideals is order isomorphic to the lattice of +Weyl-group-invariant submodules of the corresponding root system. In this file we provide +`LieIdeal.toInvtRootSubmodule`, which constructs the invariant submodule associated to an ideal, +and `LieAlgebra.IsKilling.invtSubmoduleToLieIdeal`, which constructs the ideal associated to an +invariant submodule. + +As of Mar 2026, the proofs that these maps are part of an order isomorphism is still pending. ## Main definitions +* `LieIdeal.rootSet`: the set of roots whose root space is contained in a given Lie ideal. +* `LieIdeal.rootSpan`: the submodule of `Dual K H` spanned by `LieIdeal.rootSet`. +* `LieIdeal.toInvtRootSubmodule`: the invariant root submodule associated to an ideal. * `LieAlgebra.IsKilling.invtSubmoduleToLieIdeal`: constructs a Lie ideal from an invariant submodule of the dual space @@ -23,6 +32,89 @@ We show the irreducibility of root systems of simple Lie algebras. @[expose] public section +namespace LieIdeal + +open LieAlgebra LieAlgebra.IsKilling LieModule Module + +variable {K L : Type*} [Field K] [LieRing L] [LieAlgebra K L] [FiniteDimensional K L] + {H : LieSubalgebra K L} [H.IsCartanSubalgebra] + +lemma corootSubmodule_le (I : LieIdeal K L) {α : Weight K H L} + (hα : rootSpace H α ≤ I.restr H) : + corootSubmodule α ≤ I.restr H := by + intro x hx + obtain ⟨a, ha, rfl⟩ := (LieSubmodule.mem_map _).mp hx + have : (⟨a.val, a.property⟩ : H) ∈ corootSpace α := ha + rw [mem_corootSpace] at this + refine (Submodule.span_le.mpr ?_) this + rintro _ ⟨y, hy, _, -, rfl⟩ + exact lie_mem_left K L I y _ (hα hy) + +/-- The set of roots whose root space is contained in a given Lie ideal. -/ +def rootSet (I : LieIdeal K L) : Set H.root := { α | rootSpace H α.1 ≤ I.restr H } + +@[simp] +lemma mem_rootSet {I : LieIdeal K L} {α : H.root} : + α ∈ I.rootSet ↔ rootSpace H α.1 ≤ I.restr H := Iff.rfl + +variable [CharZero K] [IsKilling K L] [IsTriangularizable K H L] + +/-- The submodule of `Dual K H` spanned by the roots associated to a Lie ideal. -/ +noncomputable def rootSpan (I : LieIdeal K L) : Submodule K (Dual K H) := + Submodule.span K ((rootSystem H).root '' I.rootSet) + +lemma rootSpace_le_of_apply_coroot_ne_zero (I : LieIdeal K L) + {α : Weight K H L} (hα : rootSpace H α ≤ I.restr H) + {γ : H → K} (hγ_ne : γ (coroot α) ≠ 0) : + rootSpace H γ ≤ I.restr H := by + intro y hy + have : γ (coroot α) • y ∈ I.toSubmodule := by + rw [← lie_eq_smul_of_mem_rootSpace hy (coroot α)] + exact lie_mem_left K L I _ y + (I.corootSubmodule_le hα (coe_coroot_mem_corootSubmodule α)) + exact I.toSubmodule.smul_mem_iff hγ_ne |>.mp this + +lemma reflectionPerm_mem_rootSet_iff (I : LieIdeal K L) (α β : H.root) : + (rootSystem H).reflectionPerm β α ∈ I.rootSet ↔ α ∈ I.rootSet := by + let S := rootSystem H + suffices h : ∀ γ δ : H.root, δ ∈ I.rootSet → S.reflectionPerm γ δ ∈ I.rootSet by + exact ⟨fun hα => S.reflectionPerm_self β α ▸ h β _ hα, h β α⟩ + intro γ δ hδ + simp only [mem_rootSet] at hδ ⊢ + by_cases hp : S.pairing δ γ = 0 + · rwa [S.reflectionPerm_eq_of_pairing_eq_zero hp] + · have hγ := I.rootSpace_le_of_apply_coroot_ne_zero hδ + (mt S.pairing_eq_zero_iff.mpr hp) + have h_neg : S.pairing (S.reflectionPerm γ δ) γ ≠ 0 := by + rwa [← S.pairing_reflectionPerm γ δ γ, S.pairing_reflectionPerm_self_right, neg_ne_zero] + exact I.rootSpace_le_of_apply_coroot_ne_zero hγ h_neg + +/-- The submodule spanned by roots of a Lie ideal is invariant under all root reflections. -/ +lemma rootSpan_mem_invtRootSubmodule (I : LieIdeal K L) : + I.rootSpan ∈ (rootSystem H).invtRootSubmodule := by + rw [RootPairing.mem_invtRootSubmodule_iff] + intro β + rw [Module.End.mem_invtSubmodule, rootSpan, Submodule.span_le] + rintro - ⟨α, hα, rfl⟩ + rw [SetLike.mem_coe, Submodule.mem_comap, LinearEquiv.coe_coe, ← RootPairing.root_reflectionPerm] + exact Submodule.subset_span ⟨_, (I.reflectionPerm_mem_rootSet_iff α β).mpr hα, rfl⟩ + +/-- The invariant root submodule corresponding to a Lie ideal. + +Given a Lie ideal `I`, this produces an invariant root submodule by taking the span of all +roots whose root spaces are contained in `I`. -/ +noncomputable def toInvtRootSubmodule (I : LieIdeal K L) : + (rootSystem H).invtRootSubmodule := + ⟨I.rootSpan, I.rootSpan_mem_invtRootSubmodule⟩ + +@[gcongr] +lemma toInvtRootSubmodule_mono {I J : LieIdeal K L} (h : I ≤ J) : + I.toInvtRootSubmodule (H := H) ≤ J.toInvtRootSubmodule := + Submodule.span_mono (Set.image_mono + fun α (hα : rootSpace H α.1 ≤ I.restr H) ↦ hα.trans (show I.restr H ≤ J.restr H from h)) + +end LieIdeal + namespace LieAlgebra.IsKilling variable {K L : Type*} [Field K] [CharZero K] [LieRing L] [LieAlgebra K L] [FiniteDimensional K L] diff --git a/Mathlib/Algebra/Lie/Weights/Killing.lean b/Mathlib/Algebra/Lie/Weights/Killing.lean index 83700390f61e93..e9b52edadfb495 100644 --- a/Mathlib/Algebra/Lie/Weights/Killing.lean +++ b/Mathlib/Algebra/Lie/Weights/Killing.lean @@ -686,6 +686,12 @@ This represents the image of the coroot space under the inclusion `H ↪ L`. -/ noncomputable abbrev corootSubmodule (α : Weight K H L) : LieSubmodule K H L := LieSubmodule.map H.toLieSubmodule.incl (corootSpace α) +omit [CharZero K] in +lemma coe_coroot_mem_corootSubmodule (α : Weight K H L) : + (coroot α : L) ∈ corootSubmodule α := + (LieSubmodule.mem_map _).mpr + ⟨⟨coroot α, (coroot α).property⟩, coroot_mem_corootSpace α, rfl⟩ + open Submodule in lemma sl2SubmoduleOfRoot_eq_sup (α : Weight K H L) (hα : α.IsNonZero) : sl2SubmoduleOfRoot hα = genWeightSpace L α ⊔ genWeightSpace L (-α) ⊔ corootSubmodule α := by diff --git a/Mathlib/Algebra/LieRinehartAlgebra/Defs.lean b/Mathlib/Algebra/LieRinehartAlgebra/Defs.lean index 54101a796129ad..f02ef102ddfe4d 100644 --- a/Mathlib/Algebra/LieRinehartAlgebra/Defs.lean +++ b/Mathlib/Algebra/LieRinehartAlgebra/Defs.lean @@ -25,15 +25,15 @@ terms of the Chevalley-Eilenberg algebra of a Lie-Rinehart algebra. @[expose] public section -/-- A Lie-Reinhart ring is a pair consisting of a commutative ring `A` and a Lie ring `L` such that +/-- A Lie-Rinehart ring is a pair consisting of a commutative ring `A` and a Lie ring `L` such that `A` and `L` are each a module over the other, satisfying compatibility conditions. -/ class LieRinehartRing (A L : Type*) [CommRing A] [LieRing L] [Module A L] [LieRingModule L A] : Prop where - lie_smul_eq_mul (a b : A) (x : L) : ⁅a • x, b⁆ = a * ⁅x, b⁆ - leibniz_mul_right (x : L) (a b : A) : ⁅x, a * b⁆ = a • ⁅x, b⁆ + ⁅x, a⁆ * b - leibniz_smul_right (x y : L) (a : A) : ⁅x, a • y⁆ = a • ⁅x, y⁆ + ⁅x, a⁆ • y + lie_smul_eq_mul' (a b : A) (x : L) : ⁅a • x, b⁆ = a * ⁅x, b⁆ + leibniz_mul_right' (x : L) (a b : A) : ⁅x, a * b⁆ = a • ⁅x, b⁆ + ⁅x, a⁆ * b + leibniz_smul_right' (x y : L) (a : A) : ⁅x, a • y⁆ = a • ⁅x, y⁆ + ⁅x, a⁆ • y -/-- A Lie-Reinhart algebra with coefficients in a commutative ring `R`, is a pair consisting of a +/-- A Lie-Rinehart algebra with coefficients in a commutative ring `R`, is a pair consisting of a commutative `R`-algebra `A` and a Lie algebra `L` with coefficients in `R`, such that `A` and `L` are each a module over the other, satisfying compatibility conditions. @@ -55,10 +55,19 @@ variable {R A₁ L₁ A₂ L₂ A₃ L₃ : Type*} [CommRing R] [Algebra R A₃] [LieAlgebra R L₃] {σ₁₂ : A₁ →ₐ[R] A₂} {σ₂₃ : A₂ →ₐ[R] A₃} +@[simp] lemma LieRinehartRing.lie_smul_eq_mul [LieRinehartRing A₁ L₁] (a b : A₁) (x : L₁) : + ⁅a • x, b⁆ = a * ⁅x, b⁆ := LieRinehartRing.lie_smul_eq_mul' a b x + +@[simp] lemma LieRinehartRing.leibniz_mul_right [LieRinehartRing A₁ L₁] (x : L₁) (a b : A₁) : + ⁅x, a * b⁆ = a • ⁅x, b⁆ + ⁅x, a⁆ * b := LieRinehartRing.leibniz_mul_right' x a b + +@[simp] lemma LieRinehartRing.leibniz_smul_right [LieRinehartRing A₁ L₁] (x y : L₁) (a : A₁) : + ⁅x, a • y⁆ = a • ⁅x, y⁆ + ⁅x, a⁆ • y := LieRinehartRing.leibniz_smul_right' x y a + instance : LieRinehartRing A₁ (Derivation R A₁ A₁) where - lie_smul_eq_mul _ _ _ := rfl - leibniz_mul_right _ _ _ := by simp; ring - leibniz_smul_right _ _ _ := by ext; simp [Derivation.commutator_apply]; ring + lie_smul_eq_mul' _ _ _ := rfl + leibniz_mul_right' _ _ _ := by simp; ring + leibniz_smul_right' _ _ _ := by ext; simp [Derivation.commutator_apply]; ring /-- The derivations of a commutative Algebra themselves form a LieRinehart-Algebra. -/ instance : LieRinehartAlgebra R A₁ (Derivation R A₁ A₁) where @@ -78,11 +87,11 @@ structure Hom (σ : A₁ →ₐ[R] A₂) (L₁ L₂ : Type*) map_smul_apply' (a : A₁) (x : L₁) : toLieHom (a • x) = σ a • toLieHom x apply_lie' (a : A₁) (x : L₁) : σ ⁅x, a⁆ = ⁅toLieHom x, σ a⁆ -namespace Hom - @[inherit_doc] scoped notation:25 L " →ₗ⁅" σ:25 "⁆ " L₂:0 => LieRinehartAlgebra.Hom σ L L₂ +namespace Hom + instance : CoeFun (L₁ →ₗ⁅σ₁₂⁆ L₂) (fun _ => L₁ → L₂) := ⟨fun f => f.toLieHom⟩ /-- This is `LieRinehartAlgebra.Hom.map_smul_apply'` restated using the coercion to function rather @@ -118,6 +127,8 @@ protected def id : L₁ →ₗ⁅AlgHom.id R A₁⁆ L₁ where map_smul_apply' _ _ := by simp apply_lie' _ _ := by simp +end Hom + variable [LieRinehartRing A₁ L₁] [LieRinehartAlgebra R A₁ L₁] set_option backward.isDefEq.respectTransparency false in @@ -126,15 +137,16 @@ variable (R A₁ L₁) in to the module of derivations of `A`. -/ def anchor : L₁ →ₗ⁅AlgHom.id R A₁⁆ Derivation R A₁ A₁ where toFun x := .mk' (LieModule.toEnd R L₁ A₁ x) fun a b ↦ by - simp [LieRinehartRing.leibniz_mul_right, mul_comm b] + simp [mul_comm b] map_add' _ _ := by ext; simp map_smul' _ _ := by ext; simp map_lie' {_ _} := by ext; simp [Derivation.commutator_apply] - map_smul_apply' _ _ := by ext; simp [LieRinehartRing.lie_smul_eq_mul] + map_smul_apply' _ _ := by ext; simp apply_lie' _ _ := by simp @[simp] lemma anchor_derivation : anchor R A₁ (Derivation R A₁ A₁) = Hom.id := rfl -end Hom +@[simp] lemma anchor_apply (l : L₁) (a : A₁) : + (LieRinehartAlgebra.anchor R A₁ L₁ l) a = ⁅l, a⁆ := rfl end LieRinehartAlgebra diff --git a/Mathlib/Algebra/MathlibDemo.lean b/Mathlib/Algebra/MathlibDemo.lean new file mode 100644 index 00000000000000..65e734856beb74 --- /dev/null +++ b/Mathlib/Algebra/MathlibDemo.lean @@ -0,0 +1,41 @@ +import Mathlib.Analysis.InnerProductSpace.Basic +import Mathlib.LinearAlgebra.LinearMap + +-- Abstract Hilbert space +variable (H : Type) +variable [NormedAddCommGroup H] +variable [InnerProductSpace ℝ H] +variable [CompleteSpace H] + +-- Continuous linear operator +abbrev EndH := H →L[ℝ] H + +-- Identity +def id_op : EndH H := ContinuousLinearMap.id ℝ H + +-- Composition +def comp (O₁ O₂ : EndH H) : EndH H := O₁.comp O₂ + +-- Scalar multiplication +def O_k (k : ℝ) : EndH H := k • ContinuousLinearMap.id ℝ H + +-- Symmetry / inversion +def S : EndH H := - ContinuousLinearMap.id ℝ H + +-- Iterated operator +def Ω (O : EndH H) : EndH H := O.comp O + +-- Algebra A +inductive A : EndH H → Prop +| id : A id_op +| comp : ∀ {O₁ O₂}, A O₁ → A O₂ → A (comp H O₁ O₂) +| scalar : ∀ k : ℝ, A (O_k H k) +| omega : ∀ O, A O → A (Ω H O) +| symm : A (S H) + +-- Example operator chain +def O_total (k : ℝ) : EndH H := + comp (O_k k) (comp S id_op) + +-- Example ψ +def ψ_example : H := sorry -- user-defined state diff --git a/Mathlib/Algebra/Module/Congruence/Defs.lean b/Mathlib/Algebra/Module/Congruence/Defs.lean index 254feef7b5d4ef..b1110520f7421e 100644 --- a/Mathlib/Algebra/Module/Congruence/Defs.lean +++ b/Mathlib/Algebra/Module/Congruence/Defs.lean @@ -125,12 +125,10 @@ instance [Monoid S] [Add M] [MulAction S M] (c : ModuleCon S M) : MulAction S c. instance [AddZeroClass M] [DistribSMul S M] (c : ModuleCon S M) : DistribSMul S c.Quotient := fast_instance% Quotient.mk''_surjective.distribSMul c.mk' fun _ _ ↦ rfl -set_option backward.isDefEq.respectTransparency false in instance [Monoid S] [AddMonoid M] [DistribMulAction S M] (c : ModuleCon S M) : DistribMulAction S c.Quotient := fast_instance% Quotient.mk''_surjective.distribMulAction c.mk' fun _ _ ↦ rfl -set_option backward.isDefEq.respectTransparency false in instance [Semiring S] [AddCommMonoid M] [Module S M] (c : ModuleCon S M) : Module S c.Quotient := fast_instance% Quotient.mk''_surjective.module _ c.mk' fun _ _ ↦ rfl diff --git a/Mathlib/Algebra/Module/SpanRank.lean b/Mathlib/Algebra/Module/SpanRank.lean index 43fb78fe83fcfe..03c925cae93464 100644 --- a/Mathlib/Algebra/Module/SpanRank.lean +++ b/Mathlib/Algebra/Module/SpanRank.lean @@ -6,6 +6,7 @@ Authors: Wanyi He, Jiedong Jiang, Xuchun Li, Christian Merten, Jingting Wang, An module public import Mathlib.Data.ENat.Lattice +public import Mathlib.LinearAlgebra.Dimension.Free public import Mathlib.LinearAlgebra.Dimension.StrongRankCondition public import Mathlib.RingTheory.Finiteness.Ideal @@ -53,7 +54,7 @@ namespace Submodule section Defs -universe u +universe u v variable {R : Type*} {M : Type u} [Semiring R] [AddCommMonoid M] [Module R M] @@ -128,6 +129,17 @@ lemma fg_iff_spanRank_eq_spanFinrank {p : Submodule R M} : p.spanRank = p.spanFi rw [spanFinrank, ← spanRank_finite_iff_fg, eq_comm] exact cast_toNat_eq_iff_lt_aleph0 +lemma FG.spanRank_eq_spanFinrank {p : Submodule R M} (fg : p.FG) : p.spanRank = p.spanFinrank := + fg_iff_spanRank_eq_spanFinrank.mpr fg + +lemma FG.spanRank_le_iff {p : Submodule R M} (hp : p.FG) (n : ℕ) : + p.spanRank ≤ n ↔ p.spanFinrank ≤ n := + (Cardinal.toNat_le_iff_of_lt_aleph0 n (by simpa)).symm + +lemma FG.spanRank_eq_iff {p : Submodule R M} (hp : p.FG) (n : ℕ) : + p.spanRank = n ↔ p.spanFinrank = n := + (Cardinal.toNat_eq_iff_of_lt_aleph0 n (by simpa)).symm + lemma spanRank_span_le_card (s : Set M) : (Submodule.span R s).spanRank ≤ #s := by rw [spanRank] let s' : {s1 : Set M // span R s1 = span R s} := ⟨s, rfl⟩ @@ -178,15 +190,19 @@ theorem FG.exists_span_set_encard_eq_spanFinrank {p : Submodule R M} (h : p.FG) rw [Set.encard, ENat.card, spanFinrank, hs₁, this] simp -/-- For a finitely generated submodule, its spanRank is less than or equal to a cardinal `a` - if and only if there is a generating subset with cardinality less than or equal to `a`. -/ -lemma FG.spanRank_le_iff_exists_span_set_card_le (p : Submodule R M) {a : Cardinal} : - p.spanRank ≤ a ↔ ∃ s : Set M, #s ≤ a ∧ span R s = p := by +lemma lift_spanRank_le_iff_exists_span_set_card_le (p : Submodule R M) {a : Cardinal.{max u v}} : + Cardinal.lift.{v} p.spanRank ≤ a ↔ ∃ s : Set M, Cardinal.lift.{v} #s ≤ a ∧ span R s = p := by constructor · intro h obtain ⟨s, ⟨hs₁, hs₂⟩⟩ := exists_span_set_card_eq_spanRank p exact ⟨s, ⟨hs₁ ▸ h, hs₂⟩⟩ - · exact (fun ⟨s, ⟨hs₁, hs₂⟩⟩ ↦ hs₂.symm ▸ (le_trans (spanRank_span_le_card s) hs₁)) + · exact fun ⟨s, ⟨h₁, h₂⟩⟩ ↦ h₂.symm ▸ (Cardinal.lift_le.mpr (spanRank_span_le_card s)).trans h₁ + +/-- For a finitely generated submodule, its spanRank is less than or equal to a cardinal `a` + if and only if there is a generating subset with cardinality less than or equal to `a`. -/ +lemma FG.spanRank_le_iff_exists_span_set_card_le (p : Submodule R M) {a : Cardinal} : + p.spanRank ≤ a ↔ ∃ s : Set M, #s ≤ a ∧ span R s = p := by + convert lift_spanRank_le_iff_exists_span_set_card_le p (a := a) <;> simp @[simp] lemma spanRank_eq_zero_iff_eq_bot {I : Submodule R M} : I.spanRank = 0 ↔ I = ⊥ := by @@ -257,33 +273,50 @@ end Submodule section map -universe u +universe u v namespace Submodule section Semilinear variable {R S : Type*} {M N : Type u} [Semiring R] [Semiring S] {σ : R →+* S} [AddCommMonoid M] [Module R M] [AddCommMonoid N] [Module S N] + {L : Type v} [AddCommMonoid L] [Module S L] -lemma spanRank_map_le [RingHomSurjective σ] (f : M →ₛₗ[σ] N) - (p : Submodule R M) : (p.map f).spanRank ≤ p.spanRank := by - rw [← generators_card p, FG.spanRank_le_iff_exists_span_set_card_le] - exact ⟨f '' p.generators, Cardinal.mk_image_le, le_antisymm (span_le.2 (fun n ⟨m, hm, h⟩ ↦ +lemma lift_spanRank_map_le [RingHomSurjective σ] (f : M →ₛₗ[σ] L) (p : Submodule R M) : + Cardinal.lift.{u} (p.map f).spanRank ≤ Cardinal.lift.{v} p.spanRank := by + rw [← generators_card p, lift_spanRank_le_iff_exists_span_set_card_le] + exact ⟨f '' p.generators, Cardinal.mk_image_le_lift, le_antisymm (span_le.2 (fun n ⟨m, hm, h⟩ ↦ ⟨m, span_generators p ▸ subset_span hm, h⟩)) (by simp [span_generators])⟩ -lemma spanFinrank_map_le_of_fg [RingHomSurjective σ] (f : M →ₛₗ[σ] N) - {p : Submodule R M} (hp : p.FG) : (p.map f).spanFinrank ≤ p.spanFinrank := - (Cardinal.toNat_le_iff_le_of_lt_aleph0 (spanRank_finite_iff_fg.mpr (FG.map f hp)) - (spanRank_finite_iff_fg.mpr hp)).2 (p.spanRank_map_le f) +lemma spanRank_map_le [RingHomSurjective σ] (f : M →ₛₗ[σ] N) (p : Submodule R M) : + (p.map f).spanRank ≤ p.spanRank := by + simpa using lift_spanRank_map_le f p -lemma spanRank_map_eq_of_injective [RingHomSurjective σ] (f : M →ₛₗ[σ] N) - (hf : Function.Injective f) (p : Submodule R M) : (p.map f).spanRank = p.spanRank := by - refine (spanRank_map_le f p).antisymm ?_ +lemma spanFinrank_map_le_of_fg [RingHomSurjective σ] (f : M →ₛₗ[σ] L) {p : Submodule R M} + (hp : p.FG) : (p.map f).spanFinrank ≤ p.spanFinrank := by + rw [← (hp.map f).spanRank_le_iff, ← Cardinal.lift_le.{u}, Cardinal.lift_natCast, + ← Cardinal.lift_natCast.{v}, ← hp.spanRank_eq_spanFinrank] + exact p.lift_spanRank_map_le f + +lemma lift_spanRank_map_eq_of_injective [RingHomSurjective σ] (f : M →ₛₗ[σ] L) + (hf : Function.Injective f) (p : Submodule R M) : + Cardinal.lift.{u} (p.map f).spanRank = Cardinal.lift.{v} p.spanRank := by + refine (lift_spanRank_map_le f p).antisymm ?_ obtain ⟨s, hs, e⟩ := (p.map f).exists_span_set_card_eq_spanRank obtain ⟨s, rfl⟩ : ∃ y, f '' y = s := Set.subset_range_iff_exists_image_eq.mp ((subset_span.trans e.le).trans LinearMap.map_le_range) obtain rfl : span R s = p := by simpa [(map_injective_of_injective hf).eq_iff] using e - grw [← hs, spanRank_span_le_card, Cardinal.mk_image_eq hf] + grw [← hs, Cardinal.mk_image_eq_lift _ _ hf, Cardinal.lift_le, spanRank_span_le_card] + +lemma spanRank_map_eq_of_injective [RingHomSurjective σ] (f : M →ₛₗ[σ] N) + (hf : Function.Injective f) (p : Submodule R M) : (p.map f).spanRank = p.spanRank := by + simpa using lift_spanRank_map_eq_of_injective f hf p + +lemma spanFinrank_map_eq_of_injective [RingHomSurjective σ] (f : M →ₛₗ[σ] L) + (hf : Function.Injective f) {p : Submodule R M} : + (p.map f).spanFinrank = p.spanFinrank := by + rw [Submodule.spanFinrank, Submodule.spanFinrank, ← Cardinal.toNat_lift.{u, v}, + ← Cardinal.toNat_lift.{v, u}, lift_spanRank_map_eq_of_injective f hf p] lemma spanRank_range_le [RingHomSurjective σ] (f : M →ₛₗ[σ] N) : (LinearMap.range f).spanRank ≤ (⊤ : Submodule R M).spanRank := by @@ -293,6 +326,9 @@ lemma spanRank_range_le [RingHomSurjective σ] (f : M →ₛₗ[σ] N) : lemma spanRank_top (p : Submodule R M) : (⊤ : Submodule R p).spanRank = p.spanRank := by simpa using (spanRank_map_eq_of_injective _ p.subtype_injective ⊤).symm +lemma spanFinrank_top (p : Submodule R M) : (⊤ : Submodule R p).spanFinrank = p.spanFinrank := by + simp [Submodule.spanFinrank] + lemma spanRank_eq_of_equiv {σ' : S →+* R} [RingHomInvPair σ σ'] [RingHomInvPair σ' σ] (e : M ≃ₛₗ[σ] N) : (⊤ : Submodule R M).spanRank = (⊤ : Submodule S N).spanRank := by @@ -324,23 +360,44 @@ end Submodule section Ideal -variable {R S : Type u} [Semiring R] [Semiring S] (f : R →+* S) (I : Ideal R) +variable {R S : Type u} [Semiring R] [Semiring S] {T : Type v} [Semiring T] open Submodule in -lemma Ideal.spanRank_map_le : (I.map f).spanRank ≤ I.spanRank := by - rw [← generators_card I, FG.spanRank_le_iff_exists_span_set_card_le] - refine ⟨f '' I.generators, Cardinal.mk_image_le, le_antisymm (span_le.2 (fun s ⟨r, hr, hfr⟩ ↦ +lemma Ideal.lift_spanRank_map_le (f : R →+* T) (I : Ideal R) : + Cardinal.lift.{u} (I.map f).spanRank ≤ Cardinal.lift.{v} I.spanRank := by + rw [← generators_card I, lift_spanRank_le_iff_exists_span_set_card_le] + refine ⟨f '' I.generators, Cardinal.mk_image_le_lift, le_antisymm (span_le.2 (fun s ⟨r, hr, hfr⟩ ↦ hfr ▸ mem_map_of_mem _ <| span_generators I ▸ subset_span hr)) ?_⟩ refine map_le_of_le_comap (fun r hr ↦ ?_) simp only [submodule_span_eq, mem_comap] rw [← map_span, ← submodule_span_eq, span_generators] exact mem_map_of_mem f hr -open Submodule in -variable {I} in -lemma Ideal.spanFinrank_map_le_of_fg (hI : I.FG) : (I.map f).spanFinrank ≤ I.spanFinrank := - (Cardinal.toNat_le_iff_le_of_lt_aleph0 (spanRank_finite_iff_fg.mpr (Ideal.FG.map hI f)) - ((spanRank_finite_iff_fg.mpr hI))).2 (spanRank_map_le f I) +lemma Ideal.lift_spanRank_map_eq_of_ringEquiv (f : R ≃+* T) (I : Ideal R) : + Cardinal.lift.{u} (I.map f).spanRank = Cardinal.lift.{v} I.spanRank := by + apply (I.lift_spanRank_map_le (f : R →+* T)).antisymm + nth_rw 1 [← Ideal.map_of_equiv f (I := I)] + exact Ideal.lift_spanRank_map_le (f.symm : T →+* R) _ + +lemma Ideal.spanRank_map_le (f : R →+* S) (I : Ideal R) : (I.map f).spanRank ≤ I.spanRank := by + simpa using I.lift_spanRank_map_le f + +@[simp] +lemma Ideal.spanRank_map_eq_of_ringEquiv (f : R ≃+* S) (I : Ideal R) : + (I.map f).spanRank = I.spanRank := by + simpa using I.lift_spanRank_map_eq_of_ringEquiv f + +lemma Ideal.spanFinrank_map_le_of_fg (f : R →+* T) {I : Ideal R} (hI : I.FG) : + (I.map f).spanFinrank ≤ I.spanFinrank := by + rw [← Submodule.FG.spanRank_le_iff (hI.map f), ← Cardinal.lift_le.{u}, Cardinal.lift_natCast, + ← Cardinal.lift_natCast.{v}, ← Submodule.FG.spanRank_eq_spanFinrank hI] + exact I.lift_spanRank_map_le f + +@[simp] +lemma Ideal.spanFinrank_map_eq_of_ringEquiv (f : R ≃+* T) (I : Ideal R) : + (I.map f).spanFinrank = I.spanFinrank := by + rw [Submodule.spanFinrank, Submodule.spanFinrank, ← Cardinal.toNat_lift.{u, v}, + ← Cardinal.toNat_lift.{v, u}, I.lift_spanRank_map_eq_of_ringEquiv f] end Ideal @@ -364,6 +421,10 @@ theorem Submodule.rank_eq_spanRank_of_free [Module.Free R M] [StrongRankConditio rw [← Basis.mk_eq_rank'' B, ← Basis.mk_eq_spanRank B, ← Cardinal.lift_id #(Set.range B), Cardinal.mk_range_eq_of_injective B.injective, Cardinal.lift_id _] +lemma Module.finrank_eq_spanFinrank_of_free [StrongRankCondition R] [Module.Free R M] : + Module.finrank R M = (⊤ : Submodule R M).spanFinrank := by + simp [Module.finrank, Submodule.spanFinrank, Submodule.rank_eq_spanRank_of_free] + theorem Submodule.rank_le_spanRank [StrongRankCondition R] : Module.rank R M ≤ (⊤ : Submodule R M).spanRank := by rw [Module.rank, Submodule.spanRank] diff --git a/Mathlib/Algebra/Module/SpanRankOperations.lean b/Mathlib/Algebra/Module/SpanRankOperations.lean new file mode 100644 index 00000000000000..41d14eb62cb098 --- /dev/null +++ b/Mathlib/Algebra/Module/SpanRankOperations.lean @@ -0,0 +1,98 @@ +/- +Copyright (c) 2026 Nailin Guan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Nailin Guan +-/ +module + +public import Mathlib.Algebra.Module.SpanRank +public import Mathlib.RingTheory.Ideal.Cotangent +public import Mathlib.RingTheory.LocalRing.Module + +/-! +# Span rank under operations + +In this file we show how operations on submodules interact with `Submodule.spanRank`. + +# Main Results + +* `Submodule.spanRank_baseChange_le`: Base change doesn't increase the span rank. + +* `TensorProduct.spanFinrank_top_eq_of_residueField`: For a finitely generated module over + a local ring, the dimension of the base change to the residue field is equal to its span rank. + +* `IsLocalRing.spanFinrank_maximalIdeal_eq_finrank_cotangentSpace`: The minimal number of + generators of the unique maximal ideal is equal to the dimension of the cotangent space. + +-/ + +@[expose] public section + +open IsLocalRing TensorProduct Submodule + +variable {R A : Type*} [CommRing R] [CommRing A] [Algebra R A] + {M : Type*} [AddCommGroup M] [Module R M] (N : Submodule R M) + +lemma Submodule.spanRank_baseChange_le : (N.baseChange A).spanRank ≤ N.spanRank.lift := by + obtain ⟨s, hs₁, hs₂⟩ := N.exists_span_set_card_eq_spanRank + grw [← hs₁, ← hs₂, baseChange_span, spanRank_span_le_card] + convert Cardinal.mk_image_le_lift (f := TensorProduct.mk R A M 1) (s := s) + · exact (Cardinal.lift_id' _).symm + · exact Cardinal.lift_umax.symm + +lemma Submodule.FG.spanFinrank_baseChange_le (fg : N.FG) : + (N.baseChange A).spanFinrank ≤ N.spanFinrank := by + grw [spanFinrank, spanRank_baseChange_le, Cardinal.toNat_lift, spanFinrank] + simp [Cardinal.lift_lt_aleph0, spanRank_finite_iff_fg.mpr fg] + +lemma TensorProduct.spanRank_top_le : (⊤ : Submodule A (A ⊗[R] N)).spanRank ≤ N.spanRank.lift := by + grw [← Submodule.baseChange_top, ← N.spanRank_top, spanRank_baseChange_le] + +lemma TensorProduct.spanFinrank_top_le_of_fg (fg : N.FG) : + (⊤ : Submodule A (A ⊗[R] N)).spanFinrank ≤ N.spanFinrank := by + grw [← Submodule.baseChange_top, ← N.spanFinrank_top, (N.fg_top.mpr fg).spanFinrank_baseChange_le] + +variable [IsLocalRing R] +local notation "𝓀" => ResidueField R + +set_option backward.isDefEq.respectTransparency false in +lemma TensorProduct.spanFinrank_top_eq_of_residueField (fg : N.FG) : + (⊤ : Submodule 𝓀 (𝓀 ⊗[R] N)).spanFinrank = N.spanFinrank := by + let : Module.Finite R N := Module.Finite.iff_fg.mpr fg + apply (TensorProduct.spanFinrank_top_le_of_fg N fg).antisymm + obtain ⟨s, hs₁, hs₂⟩ := (⊤ : Submodule 𝓀 (𝓀 ⊗[R] N)).exists_span_set_card_eq_spanRank + have hs₃ : s.Finite := Cardinal.mk_lt_aleph0_iff.mp (by simpa [hs₁] using Module.Finite.fg_top) + let t := Function.surjInv (mk_surjective R N 𝓀 residue_surjective) '' s + have ht₁ : mk R 𝓀 N 1 '' t = s := by rw [← Set.image_comp, Function.comp_surjInv, s.image_id] + have ht₂ : span R t = ⊤ := by + rwa [← restrictScalars_eq_top_iff R, restrictScalars_span _ _ (by exact residue_surjective), + ← ht₁, ← map_span, map_tensorProduct_mk_eq_top] at hs₂ + grw [← N.spanFinrank_top, ← ht₂, spanFinrank_span_le_ncard_of_finite (hs₃.image _), spanFinrank, + ← hs₁, Set.ncard_image_le hs₃] + rfl + +namespace IsLocalRing + +set_option backward.isDefEq.respectTransparency false in +lemma spanFinrank_eq_finrank_quotient (N : Submodule R M) (fg : N.FG) : + N.spanFinrank = + Module.finrank (R ⧸ maximalIdeal R) (N ⧸ (maximalIdeal R) • (⊤ : Submodule R N)) := by + let : Module 𝓀 (N ⧸ maximalIdeal R • (⊤ : Submodule R N)) := + inferInstanceAs (Module (R ⧸ maximalIdeal R) _) + let : IsScalarTower R 𝓀 (N ⧸ maximalIdeal R • (⊤ : Submodule R N)) := + inferInstanceAs (IsScalarTower R (R ⧸ maximalIdeal R) _) + rw [← spanFinrank_top_eq_of_residueField N fg, ← Module.finrank_eq_spanFinrank_of_free] + let e : 𝓀 ⊗[R] N ≃ₗ[𝓀] N ⧸ (maximalIdeal R) • (⊤ : Submodule R N) := + (quotTensorEquivQuotSMul N (maximalIdeal R)).extendScalarsOfSurjective residue_surjective + exact e.finrank_eq + +lemma spanFinrank_maximalIdeal_eq_finrank_cotangentSpace_of_fg (fg : (maximalIdeal R).FG) : + (maximalIdeal R).spanFinrank = Module.finrank (ResidueField R) (CotangentSpace R) := + spanFinrank_eq_finrank_quotient _ fg + +variable (R) in +lemma spanFinrank_maximalIdeal_eq_finrank_cotangentSpace [IsNoetherianRing R] : + (maximalIdeal R).spanFinrank = Module.finrank (ResidueField R) (CotangentSpace R) := + spanFinrank_maximalIdeal_eq_finrank_cotangentSpace_of_fg (maximalIdeal R).fg_of_isNoetherianRing + +end IsLocalRing diff --git a/Mathlib/Algebra/Module/Submodule/Pointwise.lean b/Mathlib/Algebra/Module/Submodule/Pointwise.lean index 50f885c5d7ae71..09b44ace8cbf73 100644 --- a/Mathlib/Algebra/Module/Submodule/Pointwise.lean +++ b/Mathlib/Algebra/Module/Submodule/Pointwise.lean @@ -201,6 +201,9 @@ protected def pointwiseDistribMulAction : DistribMulAction α (Submodule R M) wh scoped[Pointwise] attribute [instance] Submodule.pointwiseDistribMulAction +theorem pointwise_smul_def {a : α} {S : Submodule R M} : + a • S = S.map (DistribSMul.toLinearMap R M a) := rfl + open Pointwise @[simp, norm_cast] @@ -563,4 +566,24 @@ lemma sup_set_smul (s t : Set S) : end set_acting_on_submodules +section group + +variable {R G M : Type*} [Semiring R] [AddCommMonoid M] [Module R M] + [Group G] [DistribMulAction G M] [SMulCommClass G R M] + {S : Submodule R M} + +open MulAction + +lemma stabilizer_coe : + stabilizer G S = stabilizer G (S : Set M) := by + ext + rw [mem_stabilizer_iff, SetLike.ext'_iff, coe_pointwise_smul, + ← mem_stabilizer_iff] + +theorem mem_stabilizer_submodule_iff_map_eq {e : G} : + e ∈ stabilizer G S ↔ S.map (DistribSMul.toLinearMap R M e) = S := by + rfl + +end group + end Submodule diff --git a/Mathlib/Algebra/Module/Torsion/Basic.lean b/Mathlib/Algebra/Module/Torsion/Basic.lean index a1d2b60aeedd8c..8a06c1ad2ed4e2 100644 --- a/Mathlib/Algebra/Module/Torsion/Basic.lean +++ b/Mathlib/Algebra/Module/Torsion/Basic.lean @@ -708,6 +708,10 @@ def submodule_torsionBy_orderIso (a : R) : left_inv := by intro; ext; simp [restrictScalarsEmbedding] right_inv := by intro; ext; simp [restrictScalarsEmbedding] } +instance (M : Type*) [AddCommGroup M] [Module R M] [Module.Finite R M] (I : Ideal R) : + Module.Finite (R ⧸ I) (M ⧸ I • (⊤ : Submodule R M)) := + Module.Finite.of_restrictScalars_finite R _ _ + end Submodule end NeedsGroup diff --git a/Mathlib/Algebra/Module/ZLattice/Basic.lean b/Mathlib/Algebra/Module/ZLattice/Basic.lean index 391a256d01e204..4f01cca3921ae1 100644 --- a/Mathlib/Algebra/Module/ZLattice/Basic.lean +++ b/Mathlib/Algebra/Module/ZLattice/Basic.lean @@ -274,7 +274,8 @@ def quotientEquiv [Fintype ι] : · refine fun q => Quotient.liftOn q (fractRestrict b) (fun _ _ h => ?_) rw [Subtype.mk.injEq, fractRestrict_apply, fractRestrict_apply, fract_eq_fract] exact QuotientAddGroup.leftRel_apply.mp h - · refine Quotient.inductionOn₂ x y (fun _ _ hxy => ?_) + · induction x, y using Quotient.inductionOn₂ + intro hxy rw [Quotient.liftOn_mk (s := quotientRel (span ℤ (Set.range b))), fractRestrict, Quotient.liftOn_mk (s := quotientRel (span ℤ (Set.range b))), fractRestrict, Subtype.mk.injEq] at hxy diff --git a/Mathlib/Algebra/MonoidAlgebra/Defs.lean b/Mathlib/Algebra/MonoidAlgebra/Defs.lean index 4b379285108d56..b4b6bbaf368ca6 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Defs.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Defs.lean @@ -5,6 +5,7 @@ Authors: Johannes Hölzl, Yury Kudryashov, Kim Morrison -/ module +public import Mathlib.Algebra.GroupWithZero.Action.TransferInstance public import Mathlib.Algebra.Module.Defs public import Mathlib.Data.Finsupp.Basic public import Mathlib.Data.Finsupp.SMulWithZero @@ -42,6 +43,12 @@ When the domain is multiplicative, e.g. a group, this will be used to define the We introduce the notation `R[M]` for both `MonoidAlgebra R M` and `AddMonoidAlgebra R M`. The notations are scoped to their respective namespaces, and which one `R[M]` resolves to therefore depends on which of the two namespaces is open. + +## TODO + +Use `coeff`/`ofCoeff` more widely. See +https://github.com/leanprover-community/mathlib4/pull/36746 +https://github.com/leanprover-community/mathlib4/pull/25273 -/ @[expose] public section @@ -96,6 +103,46 @@ meta def unexpander : Lean.PrettyPrinter.Unexpander section Semiring variable [Semiring R] {x y : R[M]} {r r₁ r₂ : R} {m m' m₁ m₂ : M} +/-- Construct an element of the monoid algebra `R[M]` from its coefficients `M →₀ R`. -/ +@[to_additive +/-- Construct an element of the additive monoid algebra `R[M]` from its coefficients `M →₀ R`. -/] +def ofCoeff (x : M →₀ R) : R[M] := x + +/-- The coefficients `M →₀ R` of an element of the monoid algebra `R[M]`. -/ +@[to_additive +/-- The coefficients `M →₀ R` of an element of the additive monoid algebra `R[M]`. -/] +def coeff (x : R[M]) : M →₀ R := x + +@[to_additive (attr := simp)] lemma coeff_ofCoeff (x : M →₀ R) : coeff (ofCoeff x) = x := rfl +@[to_additive (attr := simp)] lemma ofCoeff_coeff (x : R[M]) : ofCoeff x.coeff = x := rfl + +/-- `MonoidAlgebra.coeff` as an equiv. -/ +@[to_additive (attr := simps apply symm_apply) +/-- `AddMonoidAlgebra.coeff` as an equiv. -/] +def coeffEquiv : R[M] ≃ (M →₀ R) where + toFun := coeff + invFun := ofCoeff + left_inv _ := rfl + right_inv _ := rfl + +@[to_additive] lemma «forall» {P : R[M] → Prop} : (∀ p, P p) ↔ ∀ q, P (ofCoeff q) := + coeffEquiv.forall_congr_left + +@[to_additive] lemma «exists» {P : R[M] → Prop} : (∃ p, P p) ↔ ∃ q, P (ofCoeff q) := + coeffEquiv.exists_congr_left + +@[to_additive] +lemma coeff_injective : (coeff : R[M] → M →₀ R).Injective := coeffEquiv.injective + +@[to_additive] +lemma ofCoeff_injective : (ofCoeff : (M →₀ R) → R[M]).Injective := coeffEquiv.symm.injective + +@[to_additive (attr := simp)] +lemma coeff_inj : x.coeff = y.coeff ↔ x = y := coeff_injective.eq_iff + +@[to_additive] +lemma ofCoeff_inj {x y : M →₀ R} : ofCoeff x = ofCoeff y ↔ x = y := ofCoeff_injective.eq_iff + @[to_additive] instance inhabited : Inhabited R[M] := inferInstanceAs <| Inhabited <| M →₀ R @@ -111,6 +158,7 @@ variable [Semiring R] {x y : R[M]} {r r₁ r₂ : R} {m m' m₁ m₂ : M} @[to_additive] instance instIsCancelAdd [IsCancelAdd R] : IsCancelAdd R[M] := inferInstanceAs <| IsCancelAdd <| M →₀ R +-- TODO: Replace this with `coeff`. See https://github.com/leanprover-community/mathlib4/pull/36746 @[to_additive] instance instCoeFun : CoeFun R[M] fun _ ↦ M → R := inferInstanceAs <| CoeFun (M →₀ R) fun _ ↦ M → R @@ -118,6 +166,39 @@ variable [Semiring R] {x y : R[M]} {r r₁ r₂ : R} {m m' m₁ m₂ : M} @[to_additive (attr := ext) /-- A copy of `Finsupp.ext` for `AddMonoidAlgebra`. -/] lemma ext ⦃f g : R[M]⦄ (hfg : ∀ m, f m = g m) : f = g := Finsupp.ext hfg +/-- `MonoidAlgebra.coeff` as an `AddEquiv`. -/ +@[to_additive (attr := simps! apply symm_apply) +/-- `AddMonoidAlgebra.coeff` as an `AddEquiv`. -/] +def coeffAddEquiv : R[M] ≃+ (M →₀ R) := coeffEquiv.addEquiv + +@[to_additive (attr := simp)] lemma coeff_zero : coeff (0 : R[M]) = 0 := rfl +@[to_additive (attr := simp)] lemma ofCoeff_zero : (ofCoeff 0 : R[M]) = 0 := rfl +@[to_additive (attr := simp)] lemma coeff_eq_zero : coeff x = 0 ↔ x = 0 := coeff_inj +@[to_additive (attr := simp)] lemma ofCoeff_eq_zero {x : M →₀ R} : ofCoeff x = 0 ↔ x = 0 := + ofCoeff_inj + +@[to_additive (attr := simp)] +lemma coeff_add (x y : R[M]) : coeff (x + y) = coeff x + coeff y := rfl + +@[to_additive (attr := simp)] +lemma ofCoeff_add (x y : M →₀ R) : ofCoeff (x + y) = ofCoeff x + ofCoeff y := rfl + +@[to_additive (attr := simp)] +lemma coeff_sum (s : Finset ι) (f : ι → R[M]) : + coeff (∑ i ∈ s, f i) = ∑ i ∈ s, coeff (f i) := map_sum coeffAddEquiv .. + +@[to_additive (attr := simp)] +lemma ofCoeff_sum (s : Finset ι) (f : ι → M →₀ R) : + ofCoeff (∑ i ∈ s, f i) = ∑ i ∈ s, ofCoeff (f i) := map_sum coeffAddEquiv.symm .. + +@[to_additive (attr := simp)] +lemma coeff_finsuppSum [AddCommMonoid N] (f : ι →₀ N) (g : ι → N → R[M]) : + coeff (f.sum g) = f.sum (fun i n ↦ coeff (g i n)) := map_finsuppSum coeffAddEquiv .. + +@[to_additive (attr := simp)] +lemma ofCoeff_finsuppSum [AddCommMonoid N] (f : ι →₀ N) (g : ι → N → M →₀ R) : + ofCoeff (f.sum g) = f.sum (fun i n ↦ ofCoeff (g i n)) := map_finsuppSum coeffAddEquiv.symm .. + -- TODO: This definition is very leaky, and we later have frequent problems conflating the two -- versions of `single`. Perhaps someone wants to try making this a `def` rather than an `abbrev`? -- In Mathlib 3 this was locally reducible. @@ -142,7 +223,13 @@ variable {A : Type*} [SMulZeroClass A R] instance smulZeroClass : SMulZeroClass A R[M] := Finsupp.smulZeroClass -@[to_additive (attr := simp) (dont_translate := A) coeff_smul] +@[to_additive (dont_translate := A) (attr := simp) coeff_smul] +lemma coeff_smul (a : A) (x : R[M]) : coeff (a • x) = a • coeff x := rfl + +@[to_additive (dont_translate := A) (attr := simp) ofCoeff_smul] +lemma ofCoeff_smul (a : A) (x : M →₀ R) : ofCoeff (a • x) = a • ofCoeff x := rfl + +@[to_additive (attr := simp) (dont_translate := A) smul_apply] lemma smul_apply (a : A) (x : R[M]) (m : M) : (a • x) m = a • x m := rfl @[to_additive (attr := simp) (dont_translate := A) smul_single] @@ -587,6 +674,18 @@ variable [Ring R] instance addCommGroup : AddCommGroup R[M] := inferInstanceAs <| AddCommGroup <| M →₀ R +@[to_additive (attr := simp)] +lemma coeff_neg (x : R[M]) : coeff (-x) = -coeff x := rfl + +@[to_additive (attr := simp)] +lemma ofCoeff_neg (x : M →₀ R) : ofCoeff (-x) = -ofCoeff x := rfl + +@[to_additive (attr := simp)] +lemma coeff_sub (x y : R[M]) : coeff (x - y) = coeff x - coeff y := rfl + +@[to_additive (attr := simp)] +lemma ofCoeff_sub (x y : M →₀ R) : ofCoeff (x - y) = ofCoeff x - ofCoeff y := rfl + @[to_additive (attr := simp) (dont_translate := R)] lemma neg_apply (m : M) (x : R[M]) : (-x) m = -x m := rfl diff --git a/Mathlib/Algebra/MvPolynomial/Basic.lean b/Mathlib/Algebra/MvPolynomial/Basic.lean index 9f51190dc38807..e1e9159070b86b 100644 --- a/Mathlib/Algebra/MvPolynomial/Basic.lean +++ b/Mathlib/Algebra/MvPolynomial/Basic.lean @@ -582,7 +582,7 @@ theorem coeff_add (m : σ →₀ ℕ) (p q : MvPolynomial σ R) : coeff m (p + q @[simp] theorem coeff_smul {S₁ : Type*} [SMulZeroClass S₁ R] (m : σ →₀ ℕ) (C : S₁) (p : MvPolynomial σ R) : coeff m (C • p) = C • coeff m p := - smul_apply C p m + AddMonoidAlgebra.smul_apply C p m @[simp] theorem coeff_zero (m : σ →₀ ℕ) : coeff m (0 : MvPolynomial σ R) = 0 := diff --git a/Mathlib/Algebra/MyNewProofs.lean b/Mathlib/Algebra/MyNewProofs.lean new file mode 100644 index 00000000000000..d259e6fcb35a39 --- /dev/null +++ b/Mathlib/Algebra/MyNewProofs.lean @@ -0,0 +1,5 @@ +import Mathlib.Algebra.Group.Basic +import Mathlib.Algebra.Ring.Basic + +theorem my_add_comm (a b : Nat) : a + b = b + a := + Nat.add_comm a b diff --git a/Mathlib/Algebra/NonAssoc/LieAdmissible/Defs.lean b/Mathlib/Algebra/NonAssoc/LieAdmissible/Defs.lean index 701e566b412087..653b9292bd47b6 100644 --- a/Mathlib/Algebra/NonAssoc/LieAdmissible/Defs.lean +++ b/Mathlib/Algebra/NonAssoc/LieAdmissible/Defs.lean @@ -90,7 +90,7 @@ namespace LeftPreLieRing variable {L : Type*} [LeftPreLieRing L] -/-- `LeftPreLieRings` are examples of `LieAdmissibleRings` by the commutatitvity assumption on the +/-- `LeftPreLieRings` are examples of `LieAdmissibleRings` by the commutativity assumption on the associator. -/ instance instLieAdmissibleRing : LieAdmissibleRing L where assoc_def x y z := by @@ -113,7 +113,7 @@ namespace RightPreLieRing variable {L : Type*} [RightPreLieRing L] -/-- `RightPreLieRings` are examples of `LieAdmissibleRings` by the commutatitvity assumption on +/-- `RightPreLieRings` are examples of `LieAdmissibleRings` by the commutativity assumption on the associator. -/ instance instLieAdmissibleRing : LieAdmissibleRing L where assoc_def x y z := by diff --git a/Mathlib/Algebra/Order/AbsoluteValue/Basic.lean b/Mathlib/Algebra/Order/AbsoluteValue/Basic.lean index b7dfbc8deb7d90..8222c36385042a 100644 --- a/Mathlib/Algebra/Order/AbsoluteValue/Basic.lean +++ b/Mathlib/Algebra/Order/AbsoluteValue/Basic.lean @@ -217,7 +217,6 @@ section OrderedCommRing variable [CommRing S] [PartialOrder S] [IsOrderedRing S] [Ring R] (abv : AbsoluteValue R S) [NoZeroDivisors S] -@[simp] protected theorem map_neg (a : R) : abv (-a) = abv a := by by_cases ha : a = 0; · simp [ha] refine @@ -236,6 +235,11 @@ protected theorem le_add (a b : R) : abv a - abv b ≤ abv (a + b) := by lemma sub_le_add (a b : R) : abv (a - b) ≤ abv a + abv b := by simpa only [← sub_eq_add_neg, AbsoluteValue.map_neg] using abv.add_le a (-b) +instance addGroupSeminormClass : AddGroupSeminormClass (AbsoluteValue R S) R S where + toSubadditiveHomClass := AbsoluteValue.subadditiveHomClass + map_zero := AbsoluteValue.map_zero + map_neg_eq_map f a := AbsoluteValue.map_neg f a + instance [Nontrivial R] [IsDomain S] : MulRingNormClass (AbsoluteValue R S) R S := { AbsoluteValue.subadditiveHomClass, AbsoluteValue.monoidWithZeroHomClass with diff --git a/Mathlib/Algebra/Order/Algebra.lean b/Mathlib/Algebra/Order/Algebra.lean index 1f6a448200a966..d9549f3a215ad3 100644 --- a/Mathlib/Algebra/Order/Algebra.lean +++ b/Mathlib/Algebra/Order/Algebra.lean @@ -37,11 +37,10 @@ ordered algebra public section -variable {α β : Type*} [CommSemiring α] [PartialOrder α] +variable {α β : Type*} [CommSemiring α] [PartialOrder α] [Semiring β] [PartialOrder β] [Algebra α β] section OrderedSemiring -variable (β) -variable [Semiring β] [PartialOrder β] [IsOrderedRing β] [Algebra α β] [SMulPosMono α β] {a : α} +variable (β) [IsOrderedRing β] [SMulPosMono α β] {a : α} @[gcongr, mono] lemma algebraMap_mono : Monotone (algebraMap α β) := fun a₁ a₂ ha ↦ by @@ -52,7 +51,7 @@ lemma algebraMap_nonneg (ha : 0 ≤ a) : 0 ≤ algebraMap α β a := by simpa us end OrderedSemiring section StrictOrderedSemiring -variable [Semiring β] [PartialOrder β] [IsStrictOrderedRing β] [Algebra α β] +variable [IsStrictOrderedRing β] section SMulPosMono variable [SMulPosMono α β] [SMulPosReflectLE α β] {a₁ a₂ : α} @@ -119,15 +118,15 @@ meta def evalAlgebraMap : PositivityExt where eval {u β} _zβ _pβ e := do return .nonnegative q(algebraMap_nonneg $β $pa) | _ => pure .none -example [Semiring β] [PartialOrder β] [IsOrderedRing β] [Algebra α β] [SMulPosMono α β] +example [IsOrderedRing β] [SMulPosMono α β] {a : α} (ha : 0 ≤ a) : 0 ≤ algebraMap α β a := by positivity -example [Semiring β] [PartialOrder β] [IsOrderedRing β] [Algebra α β] [SMulPosMono α β] +example [IsOrderedRing β] [SMulPosMono α β] {a : α} (ha : 0 < a) : 0 ≤ algebraMap α β a := by positivity -example [Semiring β] [PartialOrder β] [IsStrictOrderedRing β] [Algebra α β] [SMulPosStrictMono α β] +example [IsStrictOrderedRing β] [SMulPosStrictMono α β] {a : α} (ha : 0 < a) : 0 < algebraMap α β a := by positivity diff --git a/Mathlib/Algebra/Order/Antidiag/Prod.lean b/Mathlib/Algebra/Order/Antidiag/Prod.lean index f333dc4ac64ea3..b6f97ac1fb2f4e 100644 --- a/Mathlib/Algebra/Order/Antidiag/Prod.lean +++ b/Mathlib/Algebra/Order/Antidiag/Prod.lean @@ -76,7 +76,7 @@ instance [AddMonoid A] : Subsingleton (HasAntidiagonal A) where rw [ha, hb] -- The goal of this lemma is to allow to rewrite antidiagonal --- when the decidability instances obsucate Lean +-- when the decidability instances obfuscate Lean lemma hasAntidiagonal_congr (A : Type*) [AddMonoid A] [H1 : HasAntidiagonal A] [H2 : HasAntidiagonal A] : H1.antidiagonal = H2.antidiagonal := by congr!; subsingleton diff --git a/Mathlib/Algebra/Order/Floor/Ring.lean b/Mathlib/Algebra/Order/Floor/Ring.lean index 520d5130ac73ae..c662cfe50ae9d6 100644 --- a/Mathlib/Algebra/Order/Floor/Ring.lean +++ b/Mathlib/Algebra/Order/Floor/Ring.lean @@ -239,15 +239,15 @@ theorem floor_sub_ofNat (a : R) (n : ℕ) [n.AtLeastTwo] : ⌊a - ofNat(n)⌋ = ⌊a⌋ - ofNat(n) := floor_sub_natCast a n -theorem abs_sub_lt_one_of_floor_eq_floor {R : Type*} - [CommRing R] [LinearOrder R] [IsStrictOrderedRing R] [FloorRing R] - {a b : R} (h : ⌊a⌋ = ⌊b⌋) : |a - b| < 1 := by - have : a < ⌊a⌋ + 1 := lt_floor_add_one a - have : b < ⌊b⌋ + 1 := lt_floor_add_one b - have : (⌊a⌋ : R) = ⌊b⌋ := Int.cast_inj.2 h - have : (⌊a⌋ : R) ≤ a := floor_le a - have : (⌊b⌋ : R) ≤ b := floor_le b - exact abs_sub_lt_iff.2 ⟨by linarith, by linarith⟩ +theorem abs_sub_lt_one_of_floor_eq_floor {a b : R} (h : ⌊a⌋ = ⌊b⌋) : |a - b| < 1 := by + wlog h0 : b ≤ a generalizing a b + · rw [abs_sub_comm] + exact this h.symm (le_of_not_ge h0) + calc |a - b| + _ = a - b := abs_of_nonneg (sub_nonneg_of_le h0) + _ < ⌊a⌋ + 1 - b := sub_lt_sub_right (lt_floor_add_one a) _ + _ ≤ ⌊a⌋ + 1 - ⌊b⌋ := sub_le_sub_left (floor_le b) _ + _ = 1 := by rw [h, add_sub_cancel_left] lemma floor_eq_self_iff_mem (a : R) : ⌊a⌋ = a ↔ a ∈ Set.range Int.cast := by aesop diff --git a/Mathlib/Algebra/Order/Hom/Monoid.lean b/Mathlib/Algebra/Order/Hom/Monoid.lean index 2888a5855889ce..a783837fac5458 100644 --- a/Mathlib/Algebra/Order/Hom/Monoid.lean +++ b/Mathlib/Algebra/Order/Hom/Monoid.lean @@ -515,7 +515,7 @@ theorem mk_coe (f : α ≃*o β) (h) : OrderMonoidIso.mk (f : α ≃* β) h = f /-- Reinterpret an ordered monoid isomorphism as an order isomorphism. -/ @[to_additive -/-- Reinterpret an ordered additive monoid isomomorphism as an order isomomorphism. -/] +/-- Reinterpret an ordered additive monoid isomorphism as an order isomorphism. -/] def toOrderIso (f : α ≃*o β) : α ≃o β := { f with map_rel_iff' := map_le_map_iff f } diff --git a/Mathlib/Algebra/Order/Ring/Archimedean.lean b/Mathlib/Algebra/Order/Ring/Archimedean.lean index d4756fb9a2912f..f85be72d328284 100644 --- a/Mathlib/Algebra/Order/Ring/Archimedean.lean +++ b/Mathlib/Algebra/Order/Ring/Archimedean.lean @@ -243,13 +243,7 @@ variable [IsStrictOrderedRing R] theorem add_left_cancel_of_ne_top {x y z : ArchimedeanClass R} (hx : x ≠ ⊤) (h : x + y = x + z) : y = z := by - induction x with | mk x - induction y with | mk y - induction z with | mk z - simp_rw [← mk_mul, mk_eq_mk] at h - obtain ⟨⟨m, hm⟩, ⟨n, hn⟩⟩ := h - simp_rw [abs_mul, mul_comm |x|, nsmul_eq_mul, ← mul_assoc, ← nsmul_eq_mul] at hm hn - refine mk_eq_mk.2 ⟨⟨m, ?_⟩, ⟨n, ?_⟩⟩ <;> exact le_of_mul_le_mul_right ‹_› (by simpa using hx) + simp_all theorem add_right_cancel_of_ne_top {x y z : ArchimedeanClass R} (hx : x ≠ ⊤) (h : y + x = z + x) : y = z := by diff --git a/Mathlib/Algebra/Order/Ring/IsNonarchimedean.lean b/Mathlib/Algebra/Order/Ring/IsNonarchimedean.lean index f5c699cdb9d5f2..254fa245d5642f 100644 --- a/Mathlib/Algebra/Order/Ring/IsNonarchimedean.lean +++ b/Mathlib/Algebra/Order/Ring/IsNonarchimedean.lean @@ -198,6 +198,23 @@ lemma apply_sum_le_sup_of_isNonarchimedean {α β : Type*} [AddCommMonoid α] {f · exact .inl h₁ · exact .inr <| le_trans h₂ hind +open Finset in +lemma apply_sum_eq_of_lt {α β F : Type*} [AddCommGroup α] [FunLike F α R] + [AddGroupSeminormClass F α R] {f : F} (nonarch : IsNonarchimedean f) {s : Finset β} {l : β → α} + {k : β} (hk : k ∈ s) (hmax : ∀ j ∈ s, j ≠ k → f (l j) < f (l k)) : + f (∑ i ∈ s, l i) = f (l k) := by + have : s.Nonempty := by use k + induction this using Nonempty.cons_induction generalizing k with + | singleton a => simp_all + | cons a s _ hs _ => + by_cases ha : k = a + · rw [sum_cons, ha] + apply add_eq_left_of_lt nonarch + grw [apply_sum_le_sup_of_isNonarchimedean nonarch hs] + grind [sup'_lt_iff] + · simp only [mem_cons, false_or, forall_eq_or_imp, ha] at hk hmax + grind [add_eq_right_of_lt nonarch] + /-- If `f` is a nonarchimedean additive group seminorm on a commutative ring `α`, `n : ℕ`, and `a b : α`, then we can find `m : ℕ` such that `m ≤ n` and `f ((a + b) ^ n) ≤ (f (a ^ m)) * (f (b ^ (n - m)))`. -/ diff --git a/Mathlib/Algebra/Order/SuccPred/TypeTags.lean b/Mathlib/Algebra/Order/SuccPred/TypeTags.lean index 7eaa4b15e847dc..c8aa6651bebc3f 100644 --- a/Mathlib/Algebra/Order/SuccPred/TypeTags.lean +++ b/Mathlib/Algebra/Order/SuccPred/TypeTags.lean @@ -11,7 +11,7 @@ public import Mathlib.Algebra.Order.Monoid.Unbundled.TypeTags /-! # Successor and predecessor on type tags -This file declates successor and predecessor orders on type tags. +This file declares successor and predecessor orders on type tags. -/ diff --git a/Mathlib/Algebra/Polynomial/Bivariate.lean b/Mathlib/Algebra/Polynomial/Bivariate.lean index 2b85e0e851584b..2a74360c15aa81 100644 --- a/Mathlib/Algebra/Polynomial/Bivariate.lean +++ b/Mathlib/Algebra/Polynomial/Bivariate.lean @@ -250,9 +250,10 @@ def Bivariate.swap : R[X][Y] ≃ₐ[R] R[X][Y] := by @[simp] theorem Bivariate.swap_symm : swap.symm = (swap (R := R)) := rfl -@[simp] theorem Bivariate.swap_apply (p : R[X][Y]) : swap p = p.aevalAeval (A := R[X][Y]) Y (C X) := rfl +attribute [local simp] Bivariate.swap_apply + theorem Bivariate.swap_X : swap (R := R) (C X) = Y := by simp theorem Bivariate.swap_Y : swap (R := R) Y = (C X) := by simp diff --git a/Mathlib/Algebra/Polynomial/Laurent.lean b/Mathlib/Algebra/Polynomial/Laurent.lean index 13c1cd9f997d21..46399330962902 100644 --- a/Mathlib/Algebra/Polynomial/Laurent.lean +++ b/Mathlib/Algebra/Polynomial/Laurent.lean @@ -312,7 +312,7 @@ theorem trunc_C_mul_T (n : ℤ) (r : R) : trunc (C r * T n) = ite (0 ≤ n) (mon · rw [toFinsupp_inj] ext a have : a ≠ n := by lia - simp only [coeff_ofFinsupp, comapDomain_apply, Int.ofNat_eq_natCast, coeff_zero, + simp only [coeff_ofFinsupp, comapDomain_apply, Int.ofNat_eq_natCast, Polynomial.coeff_zero, single_eq_of_ne this] @[simp] diff --git a/Mathlib/Algebra/Polynomial/Module/Basic.lean b/Mathlib/Algebra/Polynomial/Module/Basic.lean index b3be05c7c33547..9e2c5eccb1d2f6 100644 --- a/Mathlib/Algebra/Polynomial/Module/Basic.lean +++ b/Mathlib/Algebra/Polynomial/Module/Basic.lean @@ -178,8 +178,8 @@ noncomputable def equivPolynomialSelf : PolynomialModule R R ≃ₗ[R[X]] R[X] : | add _ _ hp hq => rw [smul_add, map_add, map_add, mul_add, hp, hq] | single n a => ext i - simp only [coeff_ofFinsupp, smul_single_apply, toFinsuppIso_symm_apply, coeff_ofFinsupp, - single_apply, smul_eq_mul, Polynomial.coeff_mul, mul_ite, mul_zero] + simp_rw [toFinsuppIso_symm_apply, coeff_ofFinsupp, coeff_mul, smul_single_apply, + smul_eq_mul, coeff_ofFinsupp, single_apply, mul_ite, mul_zero] split_ifs with hn · rw [Finset.sum_eq_single (i - n, n)] · simp only [ite_true] diff --git a/Mathlib/Algebra/Polynomial/PartialFractions.lean b/Mathlib/Algebra/Polynomial/PartialFractions.lean index c538df24a03281..54231e42ec29a6 100644 --- a/Mathlib/Algebra/Polynomial/PartialFractions.lean +++ b/Mathlib/Algebra/Polynomial/PartialFractions.lean @@ -21,7 +21,7 @@ decomposes as `q + ∑ i j, rᵢⱼ / gᵢ ^ (j + 1)`. Since polynomials do not have a division, the main theorem `mul_prod_pow_inverse_eq_quo_add_sum_rem_mul_pow_inverse` is stated in an `R[X]`-algebra `K` -containing inverses `giᵢ` for each polynomial `gᵢ` occuring in the denominator. +containing inverses `giᵢ` for each polynomial `gᵢ` occurring in the denominator. These results were formalised by the Xena Project, at the suggestion @@ -31,15 +31,15 @@ of Patrick Massot. ## Main results * `mul_prod_pow_inverse_eq_quo_add_sum_rem_mul_pow_inverse`: Partial fraction decomposition for - polynomials over a commutative ring `R`, the denomiator is a product of powers of + polynomials over a commutative ring `R`, the denominator is a product of powers of monic pairwise coprime polynomials. Division is done in an `R[X]`-algebra `K` - containing inverses `gi i` for each `g i` occuring in the denomiator. + containing inverses `gi i` for each `g i` occurring in the denominator. * `eq_quo_mul_prod_pow_add_sum_rem_mul_prod_pow`: Partial fraction decomposition for - polynomials over a commutative ring `R`, the denomiator is a product of powers of + polynomials over a commutative ring `R`, the denominator is a product of powers of monic pairwise coprime polynomials. The denominators are multiplied out on both sides and formally cancelled. * `eq_quo_mul_prod_add_sum_rem_mul_prod`: Partial fraction decomposition for - polynomials over a commutative ring `R`, the denomiator is a product of monic + polynomials over a commutative ring `R`, the denominator is a product of monic pairwise coprime polynomials. The denominators are multiplied out on both sides and formally cancelled. * `div_prod_eq_quo_add_sum_rem_div`: Partial fraction decomposition for polynomials over an diff --git a/Mathlib/Algebra/Ring/ULift.lean b/Mathlib/Algebra/Ring/ULift.lean index 024b7c6493cd0b..97e348e52e05a8 100644 --- a/Mathlib/Algebra/Ring/ULift.lean +++ b/Mathlib/Algebra/Ring/ULift.lean @@ -8,6 +8,7 @@ module public import Mathlib.Algebra.Group.ULift public import Mathlib.Algebra.Ring.Equiv public import Mathlib.Data.Int.Cast.Basic +public import Mathlib.Tactic.PPWithUniv /-! # `ULift` instances for ring diff --git a/Mathlib/Algebra/SkewMonoidAlgebra/Basic.lean b/Mathlib/Algebra/SkewMonoidAlgebra/Basic.lean index 86997559cd3266..8199498397b672 100644 --- a/Mathlib/Algebra/SkewMonoidAlgebra/Basic.lean +++ b/Mathlib/Algebra/SkewMonoidAlgebra/Basic.lean @@ -851,9 +851,9 @@ section coeff_mul variable [Semiring k] -section Monoid +section Mul -variable [Monoid G] [MulSemiringAction G k] +variable [Mul G] [SMulZeroClass G k] theorem coeff_mul [DecidableEq G] (f g : SkewMonoidAlgebra k G) (x : G) : (f * g).coeff x = f.sum fun a₁ b₁ ↦ g.sum fun a₂ b₂ ↦ @@ -919,10 +919,6 @@ theorem coeff_mul_single_aux (f : SkewMonoidAlgebra k G) {r : k} {x y z : G} _ = f.coeff y * y • r := by split_ifs with h <;> simp [support] at h <;> simp [h] -theorem coeff_mul_single_one (f : SkewMonoidAlgebra k G) (r : k) (x : G) : - (f * single 1 r).coeff x = f.coeff x * x • r := - f.coeff_mul_single_aux fun a ↦ by rw [mul_one] - theorem coeff_mul_single_of_not_exists_mul (r : k) {g g' : G} (x : SkewMonoidAlgebra k G) (h : ∀ x, ¬g' = x * g) : (x * single g r).coeff g' = 0 := by classical @@ -944,10 +940,6 @@ theorem coeff_single_mul_aux (f : SkewMonoidAlgebra k G) {r : k} {x y z : G} _ = if z ∈ f.support then r * x • f.coeff z else 0 := (f.support.sum_ite_eq' _ _) _ = _ := by split_ifs with h <;> simp [support] at h <;> simp [h] -theorem coeff_single_one_mul (f : SkewMonoidAlgebra k G) (r : k) (x : G) : - (single (1 : G) r * f).coeff x = r * f.coeff x := by - simp [coeff_single_mul_aux, one_smul] - theorem coeff_single_mul_of_not_exists_mul (r : k) {g g' : G} (x : SkewMonoidAlgebra k G) (h : ¬∃ d, g' = g * d) : (single g r * x).coeff g' = 0 := by classical @@ -958,6 +950,20 @@ theorem coeff_single_mul_of_not_exists_mul (r : k) {g g' : G} (x : SkewMonoidAlg exact absurd ⟨_, rfl⟩ h · simp +end Mul + +section Monoid + +variable [Monoid G] [MulSemiringAction G k] + +theorem coeff_mul_single_one (f : SkewMonoidAlgebra k G) (r : k) (x : G) : + (f * single 1 r).coeff x = f.coeff x * x • r := + f.coeff_mul_single_aux fun a ↦ by rw [mul_one] + +theorem coeff_single_one_mul (f : SkewMonoidAlgebra k G) (r : k) (x : G) : + (single (1 : G) r * f).coeff x = r * f.coeff x := by + simp [coeff_single_mul_aux, one_smul] + end Monoid section Group diff --git a/Mathlib/Algebra/WithConv.lean b/Mathlib/Algebra/WithConv.lean index eb74dba8a1b8db..1d7600ee547c31 100644 --- a/Mathlib/Algebra/WithConv.lean +++ b/Mathlib/Algebra/WithConv.lean @@ -87,6 +87,16 @@ instance [Monoid R] [AddCommMonoid A] [DistribMulAction R A] : DistribMulAction instance [Semiring R] [AddCommMonoid A] [Module R A] : Module R (WithConv A) := fast_instance% (WithConv.equiv A).module R +/-- Lift an equivalence between `A` and `B` to `WithConv A` and `WithConv B`. -/ +protected def congr (f : A ≃ B) : WithConv A ≃ WithConv B := + (WithConv.equiv A).trans (f.trans (WithConv.equiv B).symm) + +@[simp] lemma congr_apply (f : A ≃ B) (x : WithConv A) : + WithConv.congr f x = toConv (f x.ofConv) := rfl +@[simp] lemma symm_congr (f : A ≃ B) : (WithConv.congr f).symm = WithConv.congr f.symm := rfl +lemma symm_congr_apply (f : A ≃ B) (x : WithConv B) : + (WithConv.congr f).symm x = toConv (f.symm x.ofConv) := by simp + section AddGroup variable [AddGroup A] @@ -150,4 +160,22 @@ protected def linearEquiv [Semiring R] [Module R A] : WithConv A ≃ₗ[R] A whe @[simp] lemma toConv_multisetSum (s : Multiset A) : toConv s.sum = (s.map toConv).sum := map_multiset_sum (WithConv.addEquiv _).symm _ +section +variable [Semiring R] [Module R A] [AddCommMonoid B] [Module R B] + +/-- Lift a linear equivalence between `A` and `B` to `WithConv A` and `WithConv B`. -/ +def congrLinearEquiv (f : A ≃ₗ[R] B) : WithConv A ≃ₗ[R] WithConv B := + (WithConv.linearEquiv R A).trans (f.trans (WithConv.linearEquiv R B).symm) + +@[simp] lemma congrLinearEquiv_apply (f : A ≃ₗ[R] B) (x : WithConv A) : + congrLinearEquiv f x = toConv (f x.ofConv) := rfl +@[simp] lemma symm_congrLinearEquiv (f : A ≃ₗ[R] B) : + (congrLinearEquiv f).symm = congrLinearEquiv f.symm := rfl +lemma symm_congrLinearEquiv_apply (f : A ≃ₗ[R] B) (x : WithConv B) : + (congrLinearEquiv f).symm x = toConv (f.symm x.ofConv) := by simp +@[simp] theorem toEquiv_congrLinearEquiv (f : A ≃ₗ[R] B) : + (congrLinearEquiv f).toEquiv = WithConv.congr f.toEquiv := rfl + +end + end WithConv diff --git a/Mathlib/AlgebraicGeometry/AffineTransitionLimit.lean b/Mathlib/AlgebraicGeometry/AffineTransitionLimit.lean index f5a2c9a0d22372..f7841b1663c3e0 100644 --- a/Mathlib/AlgebraicGeometry/AffineTransitionLimit.lean +++ b/Mathlib/AlgebraicGeometry/AffineTransitionLimit.lean @@ -325,7 +325,6 @@ lemma isBasis_preimage_isAffineOpen [IsCofiltered I] [∀ {i j} (f : i ⟶ j), I Scheme.Hom.app_eq_appLE, Scheme.Hom.appLE_map, ← this] exact ⟨hxr, hrU⟩ -set_option backward.isDefEq.respectTransparency false in include hc in @[stacks 01Z4 "(1)"] lemma exists_preimage_eq diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/Reduction.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/Reduction.lean index 1e56826ba61027..d7701e24182ac8 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/Reduction.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/Reduction.lean @@ -91,6 +91,61 @@ lemma Δ_integral_of_isIntegral (W : WeierstrassCurve K) [IsIntegral R W] : use W_int.Δ rw [hW_int, map_Δ] +lemma integralModel_a₁_eq (W : WeierstrassCurve K) [hW : IsIntegral R W] : + algebraMap R K (integralModel R W).a₁ = W.a₁ := by + conv_rhs => rw [← baseChange_integralModel_eq R W] + simp [integralModel] + +lemma integralModel_a₂_eq (W : WeierstrassCurve K) [hW : IsIntegral R W] : + algebraMap R K (integralModel R W).a₂ = W.a₂ := by + conv_rhs => rw [← baseChange_integralModel_eq R W] + simp [integralModel] + +lemma integralModel_a₃_eq (W : WeierstrassCurve K) [hW : IsIntegral R W] : + algebraMap R K (integralModel R W).a₃ = W.a₃ := by + conv_rhs => rw [← baseChange_integralModel_eq R W] + simp [integralModel] + +lemma integralModel_a₄_eq (W : WeierstrassCurve K) [hW : IsIntegral R W] : + algebraMap R K (integralModel R W).a₄ = W.a₄ := by + conv_rhs => rw [← baseChange_integralModel_eq R W] + simp [integralModel] + +lemma integralModel_a₆_eq (W : WeierstrassCurve K) [hW : IsIntegral R W] : + algebraMap R K (integralModel R W).a₆ = W.a₆ := by + conv_rhs => rw [← baseChange_integralModel_eq R W] + simp [integralModel] + +lemma integralModel_b₂_eq (W : WeierstrassCurve K) [hW : IsIntegral R W] : + algebraMap R K (integralModel R W).b₂ = W.b₂ := by + conv_rhs => rw [← baseChange_integralModel_eq R W] + simp [integralModel] + +lemma integralModel_b₄_eq (W : WeierstrassCurve K) [hW : IsIntegral R W] : + algebraMap R K (integralModel R W).b₄ = W.b₄ := by + conv_rhs => rw [← baseChange_integralModel_eq R W] + simp [integralModel] + +lemma integralModel_b₆_eq (W : WeierstrassCurve K) [hW : IsIntegral R W] : + algebraMap R K (integralModel R W).b₆ = W.b₆ := by + conv_rhs => rw [← baseChange_integralModel_eq R W] + simp [integralModel] + +lemma integralModel_b₈_eq (W : WeierstrassCurve K) [hW : IsIntegral R W] : + algebraMap R K (integralModel R W).b₈ = W.b₈ := by + conv_rhs => rw [← baseChange_integralModel_eq R W] + simp [integralModel] + +lemma integralModel_c₄_eq (W : WeierstrassCurve K) [hW : IsIntegral R W] : + algebraMap R K (integralModel R W).c₄ = W.c₄ := by + conv_rhs => rw [← baseChange_integralModel_eq R W] + simp [integralModel] + +lemma integralModel_c₆_eq (W : WeierstrassCurve K) [hW : IsIntegral R W] : + algebraMap R K (integralModel R W).c₆ = W.c₆ := by + conv_rhs => rw [← baseChange_integralModel_eq R W] + simp [integralModel] + lemma integralModel_Δ_eq (W : WeierstrassCurve K) [hW : IsIntegral R W] : algebraMap R K (integralModel R W).Δ = W.Δ := by conv_rhs => rw [← baseChange_integralModel_eq R W] @@ -221,19 +276,70 @@ noncomputable def reduction (W : WeierstrassCurve K) [IsMinimal R W] : /-- A minimal Weierstrass equation has good reduction if and only if the valuation of its discriminant is 1. -/ @[mk_iff] -class IsGoodReduction (W : WeierstrassCurve K) [IsMinimal R W] : Prop where +class HasGoodReduction (W : WeierstrassCurve K) : Prop extends IsMinimal R W where goodReduction : valuation K (maximalIdeal R) W.Δ = 1 -lemma isGoodReduction_iff_isElliptic_reduction {W : WeierstrassCurve K} [IsMinimal R W] : - IsGoodReduction R W ↔ (W.reduction R).IsElliptic := by +@[deprecated (since := "2026-03-04")] alias IsGoodReduction := HasGoodReduction + +lemma hasGoodReduction_iff_isElliptic_reduction {W : WeierstrassCurve K} [hW : IsMinimal R W] : + HasGoodReduction R W ↔ (W.reduction R).IsElliptic := by refine Iff.trans ?_ (W.reduction R).isElliptic_iff.symm simp only [reduction, map_Δ, isUnit_iff_ne_zero, ne_eq, residue_eq_zero_iff] have h : ¬(valuation K (maximalIdeal R) (algebraMap R K (integralModel R W).Δ) < 1) ↔ (integralModel R W).Δ ∉ IsLocalRing.maximalIdeal R := not_iff_not.mpr <| valuation_lt_one_iff_mem _ _ - refine ((integralModel_Δ_eq R W ▸ isGoodReduction_iff _ _).trans ?_).trans h - simpa using (valuation_le_one _ _).ge_iff_eq.symm + refine ((integralModel_Δ_eq R W ▸ hasGoodReduction_iff _ _).trans ?_).trans h + simpa [hW] using (valuation_le_one (R := R) (K := K) _ _).ge_iff_eq.symm + +@[deprecated (since := "2026-03-04")] alias isGoodReduction_iff_isElliptic_reduction := + hasGoodReduction_iff_isElliptic_reduction + +/-- A minimal Weierstrass equation has multiplicative reduction if and only if +the valuation of its discriminant is less than 1 and the valuation of `a₄` equals 1. -/ +@[mk_iff] +class HasMultiplicativeReduction (W : WeierstrassCurve K) : Prop extends IsMinimal R W where + badReduction : valuation K (maximalIdeal R) W.Δ < 1 + multiplicativeReduction : valuation K (maximalIdeal R) W.c₄ = 1 + +/-- A minimal Weierstrass equation has additive reduction if and only if +the valuation of its discriminant is less than 1 and the valuation of `a₄` is less than 1. -/ +@[mk_iff] +class HasAdditiveReduction (W : WeierstrassCurve K) : Prop extends IsMinimal R W where + badReduction : valuation K (maximalIdeal R) W.Δ < 1 + additiveReduction : valuation K (maximalIdeal R) W.c₄ < 1 + +variable {W : WeierstrassCurve K} + +theorem hasGoodReduction_or_hasMultiplicativeReduction_or_hasAdditiveReduction [IsMinimal R W] : + W.HasGoodReduction R ∨ W.HasMultiplicativeReduction R ∨ W.HasAdditiveReduction R := by + rw [hasGoodReduction_iff, hasMultiplicativeReduction_iff, hasAdditiveReduction_iff, + ← integralModel_Δ_eq R W, ← integralModel_c₄_eq R W] + grind [valuation_le_one] + +theorem HasGoodReduction.not_hasMultiplicativeReduction (hW : W.HasGoodReduction R) : + ¬ W.HasMultiplicativeReduction R := + fun h ↦ h.badReduction.ne hW.goodReduction + +theorem HasGoodReduction.not_hasAdditiveReduction (hW : W.HasGoodReduction R) : + ¬ W.HasAdditiveReduction R := + fun h ↦ h.badReduction.ne hW.goodReduction + +theorem HasMultiplicativeReduction.not_hasGoodReduction (hW : W.HasMultiplicativeReduction R) : + ¬ W.HasGoodReduction R := + fun h ↦ hW.badReduction.ne h.goodReduction + +theorem HasAdditiveReduction.not_hasGoodReduction (hW : W.HasAdditiveReduction R) : + ¬ W.HasGoodReduction R := + fun h ↦ hW.badReduction.ne h.goodReduction + +theorem HasMultiplicativeReduction.not_hasAdditiveReduction (hW : W.HasMultiplicativeReduction R) : + ¬ W.HasAdditiveReduction R := + fun h ↦ h.additiveReduction.ne hW.multiplicativeReduction + +theorem HasAdditiveReduction.not_hasMultiplicativeReduction (hW : W.HasAdditiveReduction R) : + ¬ W.HasMultiplicativeReduction R := + fun h ↦ hW.additiveReduction.ne h.multiplicativeReduction end Reduction diff --git a/Mathlib/AlgebraicGeometry/Morphisms/UnderlyingMap.lean b/Mathlib/AlgebraicGeometry/Morphisms/UnderlyingMap.lean index 594d2d516c724e..70419635ef35b8 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/UnderlyingMap.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/UnderlyingMap.lean @@ -9,8 +9,7 @@ public import Mathlib.Topology.LocalAtTarget public import Mathlib.AlgebraicGeometry.Morphisms.Constructors /-! - -## Properties on the underlying functions of morphisms of schemes. +# Properties on the underlying functions of morphisms of schemes This file includes various results on properties of morphisms of schemes that come from properties of the underlying map of topological spaces, including diff --git a/Mathlib/AlgebraicGeometry/Properties.lean b/Mathlib/AlgebraicGeometry/Properties.lean index 8f084b7c58aa09..35c57e8db9b0f7 100644 --- a/Mathlib/AlgebraicGeometry/Properties.lean +++ b/Mathlib/AlgebraicGeometry/Properties.lean @@ -249,12 +249,12 @@ instance Scheme.component_nontrivial (X : Scheme.{u}) (U : X.Opens) [Nonempty U] set_option backward.isDefEq.respectTransparency false in instance irreducibleSpace_of_isIntegral [IsIntegral X] : IrreducibleSpace X := by by_contra H - replace H : ¬IsPreirreducible (⊤ : Set X) := fun h => + replace H : ¬IsPreirreducible .univ := fun h => H { toPreirreducibleSpace := ⟨h⟩ toNonempty := inferInstance } simp_rw [isPreirreducible_iff_isClosed_union_isClosed, not_forall, not_or] at H rcases H with ⟨S, T, hS, hT, h₁, h₂, h₃⟩ - rw [Set.not_top_subset] at h₂ h₃ + rw [Set.not_univ_subset] at h₂ h₃ haveI : Nonempty (⟨Sᶜ, hS.1⟩ : X.Opens) := ⟨⟨_, h₂.choose_spec⟩⟩ haveI : Nonempty (⟨Tᶜ, hT.1⟩ : X.Opens) := ⟨⟨_, h₃.choose_spec⟩⟩ haveI : Nonempty (⟨Sᶜ, hS.1⟩ ⊔ ⟨Tᶜ, hT.1⟩ : X.Opens) := ⟨⟨_, Or.inl h₂.choose_spec⟩⟩ diff --git a/Mathlib/AlgebraicTopology/DoldKan/Compatibility.lean b/Mathlib/AlgebraicTopology/DoldKan/Compatibility.lean index a3ea4b2df5ba83..25181e78eaac1b 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/Compatibility.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/Compatibility.lean @@ -13,17 +13,17 @@ The purpose of this file is to introduce tools which will enable the construction of the Dold-Kan equivalence `SimplicialObject C ≌ ChainComplex C ℕ` for a pseudoabelian category `C` from the equivalence `Karoubi (SimplicialObject C) ≌ Karoubi (ChainComplex C ℕ)` and the two -equivalences `simplicial_object C ≅ Karoubi (SimplicialObject C)` and -`ChainComplex C ℕ ≅ Karoubi (ChainComplex C ℕ)`. +equivalences `SimplicialObject C ≌ Karoubi (SimplicialObject C)` and +`ChainComplex C ℕ ≌ Karoubi (ChainComplex C ℕ)`. It is certainly possible to get an equivalence `SimplicialObject C ≌ ChainComplex C ℕ` using a composition of the three equivalences above, but then neither the functor nor the inverse would have good definitional properties. For example, it would be better if the inverse functor of the equivalence was exactly the functor -`Γ₀ : SimplicialObject C ⥤ ChainComplex C ℕ` which was constructed in `FunctorGamma.lean`. +`Γ₀ : ChainComplex C ℕ ⥤ SimplicialObject C` which was constructed in `FunctorGamma.lean`. -In this file, given four categories `A`, `A'`, `B`, `B'`, equivalences `eA : A ≅ A'`, -`eB : B ≅ B'`, `e' : A' ≅ B'`, functors `F : A ⥤ B'`, `G : B ⥤ A` equipped with certain +In this file, given four categories `A`, `A'`, `B`, `B'`, equivalences `eA : A ≌ A'`, +`eB : B ≌ B'`, `e' : A' ≌ B'`, functors `F : A ⥤ B'`, `G : B ⥤ A` equipped with certain compatibilities, we construct successive equivalences: - `equivalence₀` from `A` to `B'`, which is the composition of `eA` and `e'`. - `equivalence₁` from `A` to `B'`, with the same inverse functor as `equivalence₀`, @@ -55,14 +55,14 @@ variable {A A' B B' : Type*} [Category* A] [Category* A'] [Category* B] [Categor (eB : B ≌ B') (e' : A' ≌ B') {F : A ⥤ B'} (hF : eA.functor ⋙ e'.functor ≅ F) {G : B ⥤ A} (hG : eB.functor ⋙ e'.inverse ≅ G ⋙ eA.functor) -/-- A basic equivalence `A ≅ B'` obtained by composing `eA : A ≅ A'` and `e' : A' ≅ B'`. -/ +/-- A basic equivalence `A ≌ B'` obtained by composing `eA : A ≌ A'` and `e' : A' ≌ B'`. -/ @[simps! functor inverse unitIso_hom_app] def equivalence₀ : A ≌ B' := eA.trans e' variable {eA} {e'} -/-- An intermediate equivalence `A ≅ B'` whose functor is `F` and whose inverse is +/-- An intermediate equivalence `A ≌ B'` whose functor is `F` and whose inverse is `e'.inverse ⋙ eA.inverse`. -/ @[simps! functor] def equivalence₁ : A ≌ B' := (equivalence₀ eA e').changeFunctor hF @@ -104,7 +104,7 @@ theorem equivalence₁UnitIso_eq : (equivalence₁ hF).unitIso = equivalence₁U ext X simp [equivalence₁] -/-- An intermediate equivalence `A ≅ B` obtained as the composition of `equivalence₁` and +/-- An intermediate equivalence `A ≌ B` obtained as the composition of `equivalence₁` and the inverse of `eB : B ≌ B'`. -/ @[simps! functor] def equivalence₂ : A ≌ B := @@ -155,8 +155,8 @@ theorem equivalence₂UnitIso_eq : (equivalence₂ eB hF).unitIso = equivalence variable {eB} -/-- The equivalence `A ≅ B` whose functor is `F ⋙ eB.inverse` and -whose inverse is `G : B ≅ A`. -/ +/-- The equivalence `A ≌ B` whose functor is `F ⋙ eB.inverse` and +whose inverse functor is `G : B ⥤ A`. -/ @[simps! inverse] def equivalence : A ≌ B := ((equivalence₂ eB hF).changeInverse diff --git a/Mathlib/AlgebraicTopology/DoldKan/Equivalence.lean b/Mathlib/AlgebraicTopology/DoldKan/Equivalence.lean index 99c18780fb26e3..97716a6dda8fd9 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/Equivalence.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/Equivalence.lean @@ -91,7 +91,7 @@ obtained by composing the previous equivalence with the equivalences `Karoubi (ChainComplex C ℕ) ≌ ChainComplex C ℕ`. Instead, we polish this construction in `Compatibility.lean` by ensuring good definitional properties of the equivalence (e.g. the inverse functor is definitionally equal to -`Γ₀' : ChainComplex C ℕ ⥤ SimplicialObject C`) and +`Γ₀ : ChainComplex C ℕ ⥤ SimplicialObject C`, which is induced by `Γ₀'`) and showing compatibilities for the unit and counit isomorphisms. In this file `Equivalence.lean`, assuming the category `A` is abelian, we obtain diff --git a/Mathlib/AlgebraicTopology/DoldKan/EquivalencePseudoabelian.lean b/Mathlib/AlgebraicTopology/DoldKan/EquivalencePseudoabelian.lean index 15a0be4973b860..783057f7abc920 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/EquivalencePseudoabelian.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/EquivalencePseudoabelian.lean @@ -60,7 +60,7 @@ of the equivalence `ChainComplex C ℕ ≌ Karoubi (ChainComplex C ℕ)`. -/ def N [IsIdempotentComplete C] [HasFiniteCoproducts C] : SimplicialObject C ⥤ ChainComplex C ℕ := N₁ ⋙ (toKaroubiEquivalence _).inverse -/-- The functor `Γ` for the equivalence is `Γ'`. -/ +/-- The functor `Γ` for the equivalence is `Γ₀`. -/ @[simps!, nolint unusedArguments] def Γ [IsIdempotentComplete C] [HasFiniteCoproducts C] : ChainComplex C ℕ ⥤ SimplicialObject C := Γ₀ diff --git a/Mathlib/AlgebraicTopology/ExtraDegeneracy.lean b/Mathlib/AlgebraicTopology/ExtraDegeneracy.lean index 5045c8f5ad0556..8c9bb320f57f96 100644 --- a/Mathlib/AlgebraicTopology/ExtraDegeneracy.lean +++ b/Mathlib/AlgebraicTopology/ExtraDegeneracy.lean @@ -63,11 +63,11 @@ structure formally behave like extra degeneracies `σ (-1)`. -/ @[ext] structure ExtraDegeneracy (X : SimplicialObject.Augmented C) where /-- a section of the augmentation in dimension `0` -/ - s' : point.obj X ⟶ drop.obj X _⦋0⦌ + s' : X.right ⟶ X.left _⦋0⦌ /-- the extra degeneracy -/ - s : ∀ n : ℕ, drop.obj X _⦋n⦌ ⟶ drop.obj X _⦋n + 1⦌ - s'_comp_ε : s' ≫ X.hom.app (op ⦋0⦌) = 𝟙 _ := by cat_disch - s₀_comp_δ₁ : s 0 ≫ X.left.δ 1 = X.hom.app (op ⦋0⦌) ≫ s' := by cat_disch + s : ∀ n : ℕ, X.left _⦋n⦌ ⟶ X.left _⦋n + 1⦌ + s'_comp_ε : dsimp% s' ≫ X.hom.app (op ⦋0⦌) = 𝟙 X.right := by cat_disch + s₀_comp_δ₁ : dsimp% s 0 ≫ X.left.δ 1 = X.hom.app (op ⦋0⦌) ≫ s' := by cat_disch s_comp_δ₀ : ∀ n : ℕ, s n ≫ X.left.δ 0 = 𝟙 _ := by cat_disch s_comp_δ : ∀ (n : ℕ) (i : Fin (n + 2)), s (n + 1) ≫ X.left.δ i.succ = X.left.δ i ≫ s n := by cat_disch @@ -77,10 +77,10 @@ structure ExtraDegeneracy (X : SimplicialObject.Augmented C) where namespace ExtraDegeneracy attribute [reassoc] s₀_comp_δ₁ s_comp_δ s_comp_σ -set_option backward.isDefEq.respectTransparency false in -- This is needed below. attribute [reassoc (attr := simp)] s'_comp_ε s_comp_δ₀ -set_option backward.isDefEq.respectTransparency false in +attribute [local simp←] Functor.map_comp in +attribute [local simp] s₀_comp_δ₁ s_comp_δ s_comp_σ in /-- If `ed` is an extra degeneracy for `X : SimplicialObject.Augmented C` and `F : C ⥤ D` is a functor, then `ed.map F` is an extra degeneracy for the augmented simplicial object in `D` obtained by applying `F` to `X`. -/ @@ -88,35 +88,7 @@ def map {D : Type*} [Category* D] {X : SimplicialObject.Augmented C} (ed : Extra (F : C ⥤ D) : ExtraDegeneracy (((whiskering _ _).obj F).obj X) where s' := F.map ed.s' s n := F.map (ed.s n) - s'_comp_ε := by - dsimp - rw [comp_id, ← F.map_comp, ed.s'_comp_ε] - dsimp only [point_obj] - rw [F.map_id] - s₀_comp_δ₁ := by - dsimp - rw [comp_id, ← F.map_comp] - dsimp [SimplicialObject.whiskering, SimplicialObject.δ] - rw [← F.map_comp] - erw [ed.s₀_comp_δ₁] - s_comp_δ₀ n := by - dsimp [SimplicialObject.δ] - rw [← F.map_comp] - erw [ed.s_comp_δ₀] - dsimp - rw [F.map_id] - s_comp_δ n i := by - dsimp [SimplicialObject.δ] - rw [← F.map_comp, ← F.map_comp] - erw [ed.s_comp_δ] - rfl - s_comp_σ n i := by - dsimp [SimplicialObject.whiskering, SimplicialObject.σ] - rw [← F.map_comp, ← F.map_comp] - erw [ed.s_comp_σ] - rfl -set_option backward.isDefEq.respectTransparency false in /-- If `X` and `Y` are isomorphic augmented simplicial objects, then an extra degeneracy for `X` gives also an extra degeneracy for `Y` -/ def ofIso {X Y : SimplicialObject.Augmented C} (e : X ≅ Y) (ed : ExtraDegeneracy X) : @@ -124,27 +96,46 @@ def ofIso {X Y : SimplicialObject.Augmented C} (e : X ≅ Y) (ed : ExtraDegenera s' := (point.mapIso e).inv ≫ ed.s' ≫ (drop.mapIso e).hom.app (op ⦋0⦌) s n := (drop.mapIso e).inv.app (op ⦋n⦌) ≫ ed.s n ≫ (drop.mapIso e).hom.app (op ⦋n + 1⦌) s'_comp_ε := by - simpa only [Functor.mapIso, assoc, w₀, ed.s'_comp_ε_assoc] using (point.mapIso e).inv_hom_id + simpa [w₀, ed.s'_comp_ε_assoc] using (point.mapIso e).inv_hom_id s₀_comp_δ₁ := by - have h := w₀ e.inv - dsimp at h ⊢ - simp only [assoc, ← SimplicialObject.δ_naturality, ed.s₀_comp_δ₁_assoc, reassoc_of% h] + simp [← SimplicialObject.δ_naturality, s₀_comp_δ₁_assoc, w₀_assoc] s_comp_δ₀ n := by - have h := ed.s_comp_δ₀ - dsimp at h ⊢ - simpa only [assoc, ← SimplicialObject.δ_naturality, reassoc_of% h] using + simpa [← SimplicialObject.δ_naturality] using congr_app (drop.mapIso e).inv_hom_id (op ⦋n⦌) s_comp_δ n i := by - have h := ed.s_comp_δ n i - dsimp at h ⊢ - simp only [assoc, ← SimplicialObject.δ_naturality, reassoc_of% h, + simp [← SimplicialObject.δ_naturality, s_comp_δ_assoc, ← SimplicialObject.δ_naturality_assoc] s_comp_σ n i := by - have h := ed.s_comp_σ n i - dsimp at h ⊢ - simp only [assoc, ← SimplicialObject.σ_naturality, reassoc_of% h, + simp [← SimplicialObject.σ_naturality, s_comp_σ_assoc, ← SimplicialObject.σ_naturality_assoc] +variable {X : SimplicialObject.Augmented C} (ed : ExtraDegeneracy X) + +attribute [local simp←] Functor.map_comp in +/-- The section of the augmentation that is induced by the extradegeneracy. -/ +def section_ : (SimplicialObject.const C).obj X.right ⟶ X.left where + app n := ed.s' ≫ X.left.map (SimplexCategory.isTerminalZero.from _).op + +@[simp] +lemma section_app_op_mk_zero : + ed.section_.app (op ⦋0⦌) = ed.s' := by + simp [section_] + +@[reassoc (attr := simp)] +lemma section_app_comp_hom_app (n : SimplexCategoryᵒᵖ) : + dsimp% ed.section_.app n ≫ X.hom.app n = 𝟙 _ := by + dsimp [section_] + rw [assoc, dsimp% X.hom.naturality, comp_id] + exact ed.s'_comp_ε + +@[simp] +lemma section_comp_hom : ed.section_ ≫ X.hom = 𝟙 _ := by cat_disch + +/-- If an augmented simplicial object has an extradegeneracy, then +then augmentation is a split epimorphism. -/ +def splitEpi : SplitEpi X.hom where + section_ := ed.section_ + end ExtraDegeneracy end Augmented @@ -267,84 +258,51 @@ noncomputable def ExtraDegeneracy.s (n : ℕ) : cases i using Fin.cases <;> simp set_option backward.isDefEq.respectTransparency false in --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11119): @[simp] removed as the linter complains the LHS is not in normal form --- The problem is that the type of `ExtraDegeneracy.s` is not in normal form, this causes the `erw` --- in the proofs below. +@[reassoc (attr := simp)] theorem ExtraDegeneracy.s_comp_π_0 (n : ℕ) : - ExtraDegeneracy.s f S n ≫ WidePullback.π _ 0 = - @WidePullback.base _ _ _ f.right (fun _ : Fin (n + 1) => f.left) (fun _ => f.hom) _ ≫ - S.section_ := by - dsimp [ExtraDegeneracy.s] - simp + dsimp% ExtraDegeneracy.s f S n ≫ WidePullback.π _ 0 = + WidePullback.base (B := f.right) (objs := fun _ ↦ f.left) + (arrows := fun _ ↦ f.hom) ≫ S.section_ := by + simp [ExtraDegeneracy.s] set_option backward.isDefEq.respectTransparency false in --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11119): @[simp] removed as the linter complains the LHS is not in normal form +@[reassoc (attr := simp)] theorem ExtraDegeneracy.s_comp_π_succ (n : ℕ) (i : Fin (n + 1)) : - ExtraDegeneracy.s f S n ≫ WidePullback.π _ i.succ = - @WidePullback.π _ _ _ f.right (fun _ : Fin (n + 1) => f.left) (fun _ => f.hom) _ i := by + dsimp% ExtraDegeneracy.s f S n ≫ WidePullback.π _ i.succ = + WidePullback.π (B := f.right) (objs := fun _ ↦ f.left) + (arrows := fun _ ↦ f.hom) i := by simp [ExtraDegeneracy.s] --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11119): @[simp] removed as the linter complains the LHS is not in normal form +@[reassoc (attr := simp)] theorem ExtraDegeneracy.s_comp_base (n : ℕ) : - ExtraDegeneracy.s f S n ≫ WidePullback.base _ = WidePullback.base _ := by - apply WidePullback.lift_base + dsimp% ExtraDegeneracy.s f S n ≫ WidePullback.base _ = WidePullback.base _ := + WidePullback.lift_base .. set_option backward.isDefEq.respectTransparency false in /-- The augmented Čech nerve associated to a split epimorphism has an extra degeneracy. -/ noncomputable def extraDegeneracy : SimplicialObject.Augmented.ExtraDegeneracy f.augmentedCechNerve where - s' := S.section_ ≫ WidePullback.lift f.hom (fun _ => 𝟙 _) fun i => by rw [id_comp] + s' := S.section_ ≫ WidePullback.lift f.hom (fun _ ↦ 𝟙 _) (by simp) s n := ExtraDegeneracy.s f S n - s'_comp_ε := by - dsimp - simp only [assoc, WidePullback.lift_base, SplitEpi.id] s₀_comp_δ₁ := by - dsimp [cechNerve, SimplicialObject.δ, SimplexCategory.δ] + dsimp [SimplicialObject.δ, SimplexCategory.δ] ext j · fin_cases j - simpa only [assoc, WidePullback.lift_π, comp_id] using ExtraDegeneracy.s_comp_π_0 f S 0 - · simpa only [assoc, WidePullback.lift_base, SplitEpi.id, comp_id] using - ExtraDegeneracy.s_comp_base f S 0 + simp + · simp s_comp_δ₀ n := by - dsimp [cechNerve, SimplicialObject.δ, SimplexCategory.δ] - ext j - · simpa only [assoc, WidePullback.lift_π, id_comp] using ExtraDegeneracy.s_comp_π_succ f S n j - · simpa only [assoc, WidePullback.lift_base, id_comp] using ExtraDegeneracy.s_comp_base f S n + dsimp [SimplicialObject.δ, SimplexCategory.δ] + cat_disch s_comp_δ n i := by dsimp [SimplicialObject.δ, SimplexCategory.δ] ext j - · simp only [assoc, WidePullback.lift_π] - cases j using Fin.cases with - | zero => - rw [Fin.succ_succAbove_zero] - erw [ExtraDegeneracy.s_comp_π_0, ExtraDegeneracy.s_comp_π_0] - dsimp - simp only [WidePullback.lift_base_assoc] - | succ k => - erw [Fin.succ_succAbove_succ, ExtraDegeneracy.s_comp_π_succ, - ExtraDegeneracy.s_comp_π_succ] - simp only [WidePullback.lift_π] - · simp only [assoc, WidePullback.lift_base] - erw [ExtraDegeneracy.s_comp_base, ExtraDegeneracy.s_comp_base] - dsimp - simp only [WidePullback.lift_base] + · induction j using Fin.cases <;> simp + · simp s_comp_σ n i := by - dsimp [cechNerve, SimplicialObject.σ, SimplexCategory.σ] + dsimp [SimplicialObject.σ, SimplexCategory.σ] ext j - · simp only [assoc, WidePullback.lift_π] - cases j using Fin.cases with - | zero => - erw [ExtraDegeneracy.s_comp_π_0, ExtraDegeneracy.s_comp_π_0] - dsimp - simp only [WidePullback.lift_base_assoc] - | succ k => - erw [Fin.succ_predAbove_succ, ExtraDegeneracy.s_comp_π_succ, - ExtraDegeneracy.s_comp_π_succ] - simp only [WidePullback.lift_π] - · simp only [assoc, WidePullback.lift_base] - erw [ExtraDegeneracy.s_comp_base, ExtraDegeneracy.s_comp_base] - dsimp - simp only [WidePullback.lift_base] + · induction j using Fin.cases <;> simp + · simp end AugmentedCechNerve @@ -377,22 +335,17 @@ noncomputable def homotopyEquiv [Preadditive C] [HasZeroObject C] inv := (ChainComplex.fromSingle₀Equiv _ _).symm (by exact ed.s') homotopyInvHomId := Homotopy.ofEq (by ext - dsimp - erw [AlternatingFaceMapComplex.ε_app_f_zero, - ChainComplex.fromSingle₀Equiv_symm_apply_f_zero, s'_comp_ε] - rfl) + simp [dsimp% ChainComplex.fromSingle₀Equiv_symm_apply_f_zero + (C := AlternatingFaceMapComplex.obj X.left)]) homotopyHomInvId := { hom i := Pi.single (i + 1) (-ed.s i) zero i j hij := Pi.single_eq_of_ne (Ne.symm hij) _ comm i := by cases i with | zero => - rw [Homotopy.prevD_chainComplex, Homotopy.dNext_zero_chainComplex, zero_add] - dsimp - erw [ChainComplex.fromSingle₀Equiv_symm_apply_f_zero] - simp only [AlternatingFaceMapComplex.obj_d_eq] - rw [Fin.sum_univ_two] - simp [s_comp_δ₀, s₀_comp_δ₁] + rw [Homotopy.prevD_chainComplex, Homotopy.dNext_zero_chainComplex] + simp [dsimp% ChainComplex.fromSingle₀Equiv_symm_apply_f_zero + (C := AlternatingFaceMapComplex.obj X.left), s_comp_δ₀, s₀_comp_δ₁] | succ i => rw [Homotopy.prevD_chainComplex, Homotopy.dNext_succ_chainComplex] simp [Fin.sum_univ_succ (n := i + 2), s_comp_δ₀, Preadditive.sum_comp, diff --git a/Mathlib/AlgebraicTopology/SimplexCategory/GeneratorsRelations/Basic.lean b/Mathlib/AlgebraicTopology/SimplexCategory/GeneratorsRelations/Basic.lean index 051223ef4b6885..25d20cef5fa220 100644 --- a/Mathlib/AlgebraicTopology/SimplexCategory/GeneratorsRelations/Basic.lean +++ b/Mathlib/AlgebraicTopology/SimplexCategory/GeneratorsRelations/Basic.lean @@ -119,11 +119,12 @@ end generators /-- A property is true for every morphism iff it holds for generators and is multiplicative. -/ lemma multiplicativeClosure_isGenerator_eq_top : generators.multiplicativeClosure = ⊤ := by apply le_antisymm (by simp) - intro x y f _ - apply CategoryTheory.Quotient.induction - apply Paths.induction - · exact generators.multiplicativeClosure.id_mem _ - · rintro _ _ _ _ ⟨⟩ h + rintro x y f - + induction f using CategoryTheory.Quotient.induction with | _ f + induction f using Paths.induction with + | id => exact generators.multiplicativeClosure.id_mem _ + | comp _ k h => + cases k · exact generators.multiplicativeClosure.comp_mem _ _ h <| .of _ <| .δ _ · exact generators.multiplicativeClosure.comp_mem _ _ h <| .of _ <| .σ _ diff --git a/Mathlib/AlgebraicTopology/SimplicialObject/Basic.lean b/Mathlib/AlgebraicTopology/SimplicialObject/Basic.lean index 1523f8d4863a38..3ed59d87f05708 100644 --- a/Mathlib/AlgebraicTopology/SimplicialObject/Basic.lean +++ b/Mathlib/AlgebraicTopology/SimplicialObject/Basic.lean @@ -211,11 +211,26 @@ theorem σ_naturality {X' X : SimplicialObject C} (f : X ⟶ X') {n : ℕ} (i : variable (C) +section + +variable {D : Type*} [Category* D] + +variable (D) in /-- Functor composition induces a functor on simplicial objects. -/ @[simps!] -def whiskering (D : Type*) [Category* D] : (C ⥤ D) ⥤ SimplicialObject C ⥤ SimplicialObject D := +def whiskering : (C ⥤ D) ⥤ SimplicialObject C ⥤ SimplicialObject D := whiskeringRight _ _ _ +@[simp] +lemma whiskering_obj_obj_δ (F : C ⥤ D) (X : SimplicialObject C) {n : ℕ} (i : Fin (n + 2)) : + dsimp% (((whiskering C D).obj F).obj X).δ i = F.map (X.δ i) := rfl + +@[simp] +lemma whiskering_obj_obj_σ (F : C ⥤ D) (X : SimplicialObject C) {n : ℕ} (i : Fin (n + 1)) : + dsimp% (((whiskering C D).obj F).obj X).σ i = F.map (X.σ i) := rfl + +end + /-- Truncated simplicial objects. -/ abbrev Truncated (n : ℕ) := (SimplexCategory.Truncated n)ᵒᵖ ⥤ C @@ -422,9 +437,9 @@ def toArrow : Augmented C ⥤ Arrow C where /-- The compatibility of a morphism with the augmentation, on 0-simplices -/ @[reassoc] theorem w₀ {X Y : Augmented C} (f : X ⟶ Y) : - (Augmented.drop.map f).app (op ⦋0⦌) ≫ Y.hom.app (op ⦋0⦌) = - X.hom.app (op ⦋0⦌) ≫ Augmented.point.map f := by - convert congr_app f.w (op ⦋0⦌) + dsimp% (Augmented.drop.map f).app (op ⦋0⦌) ≫ Y.hom.app (op ⦋0⦌) = + X.hom.app (op ⦋0⦌) ≫ Augmented.point.map f := + congr_app f.w (op ⦋0⦌) variable (C) diff --git a/Mathlib/AlgebraicTopology/SimplicialObject/ChainHomotopy.lean b/Mathlib/AlgebraicTopology/SimplicialObject/ChainHomotopy.lean new file mode 100644 index 00000000000000..b8cefb6ffc9d7b --- /dev/null +++ b/Mathlib/AlgebraicTopology/SimplicialObject/ChainHomotopy.lean @@ -0,0 +1,180 @@ +/- +Copyright (c) 2025 Fabian Odermatt. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Fabian Odermatt +-/ +module + +public import Mathlib.AlgebraicTopology.SimplicialObject.Homotopy +public import Mathlib.AlgebraicTopology.AlternatingFaceMapComplex +public import Mathlib.Algebra.Homology.Homotopy + +/-! +# Simplicial homotopies induce chain homotopies + +Given a simplicial homotopy between morphisms of simplicial objects in a preadditive category, +we construct a chain homotopy between the induced morphisms on the alternating face map complexes. + +Concretely, if `H : Homotopy f g` gives maps +`H.h i : X _⦋n⦌ ⟶ Y _⦋n+1⦌` indexed by `i : Fin (n + 1)`, we define the degree-`n` component +of the chain homotopy as the opposite of alternating sum `∑ i, (-1)^i • H.h i`. +-/ + +@[expose] public section + +universe v u + +open CategoryTheory CategoryTheory.SimplicialObject +open SimplexCategory Simplicial Opposite AlgebraicTopology + +namespace CategoryTheory.SimplicialObject.Homotopy + +variable {C : Type u} [Category.{v} C] [Preadditive C] +variable {X Y : SimplicialObject C} {f g : X ⟶ Y} +variable (H : Homotopy f g) + +namespace ToChainHomotopy + +/-- The family of components of the induced chain homotopy -/ +noncomputable def hom (p q : ℕ) : X _⦋p⦌ ⟶ Y _⦋q⦌ := + if h : p + 1 = q then + -∑ k : Fin (p + 1), ((-1 : ℤ) ^ (k : ℕ)) • H.h k ≫ eqToHom (by simp [h]) + else 0 + +@[simp] +lemma hom_eq (p : ℕ) : + hom H p (p + 1) = -∑ k : Fin (p + 1), ((-1 : ℤ) ^ (k : ℕ)) • H.h k := by + simp [hom] + +@[simp] +lemma hom_eq_zero (p q : ℕ) (hpq : p + 1 ≠ q) : + hom H p q = 0 := + dif_neg hpq + +private lemma comm_zero : + letI d : Y _⦋1⦌ ⟶ Y _⦋0⦌ := ((alternatingFaceMapComplex C).obj Y).d 1 0 + f.app (op ⦋0⦌) = hom H 0 1 ≫ d + g.app (op ⦋0⦌) := by + simp [← H.h_last_comp_δ_last 0] + +private lemma comm_succ (n : ℕ) : + letI α : X _⦋n + 1⦌ ⟶ Y _⦋n + 1⦌ := + ((alternatingFaceMapComplex C).obj X).d (n + 1) n ≫ ToChainHomotopy.hom H n (n + 1) + letI β : X _⦋n + 1⦌ ⟶ Y _⦋n + 1⦌ := hom H (n + 1) (n + 2) ≫ + ((alternatingFaceMapComplex C).obj Y).d (n + 2) (n + 1) + f.app (op ⦋n + 1⦌) = α + β + g.app (op ⦋n + 1⦌) := by + rw [← H.h_zero_comp_δ_zero, ← H.h_last_comp_δ_last] + dsimp + simp only [alternatingFaceMapComplex_obj_d, AlternatingFaceMapComplex.objD, hom_eq, + Preadditive.comp_neg, Preadditive.neg_comp, Preadditive.comp_sum, + Preadditive.sum_comp, Preadditive.comp_zsmul, Preadditive.zsmul_comp, + smul_neg, Finset.sum_neg_distrib, ← Finset.sum_zsmul, smul_smul, ← pow_add] + let α (x : Fin (n + 1) × Fin (n + 2)) := (-1) ^ ((x.1 + x.2 : ℕ)) • X.δ x.2 ≫ H.h x.1 + let β (x : Fin (n + 3) × Fin (n + 2)) := (-1) ^ ((x.1 + x.2 : ℕ)) • H.h x.2 ≫ Y.δ x.1 + have h₂ (x : Fin (n + 1) × Fin (n + 2)) (hx : x.1.castSucc < x.2) : + α x = -β ⟨x.2.succ, x.1.castSucc⟩ := by + dsimp [α, β] + simp only [← H.h_castSucc_comp_δ_succ_of_lt x.2 x.1 hx, + pow_add, pow_one, mul_neg, mul_one, neg_mul, neg_smul, neg_neg] + rw [mul_comm] + rw [← Finset.sum_product .univ .univ α, ← Finset.sum_product .univ .univ β, + Finset.univ_product_univ, Finset.univ_product_univ] + let S : Finset (Fin (n + 1) × Fin (n + 2)) := { x | x.1.castSucc < x.2 } + let γ₁ (x : Fin (n + 1) × Fin (n + 2)) := (x.2.castSucc, x.1.succ) + let γ₂ (x : Fin (n + 1) × Fin (n + 2)) := (x.2.succ, x.1.castSucc) + let γ₃ (i : Fin (n + 1)) := (i.castSucc.succ, i.succ) + let γ₄ (i : Fin (n + 1)) := (i.castSucc.succ, i.castSucc) + have hγ₁ : Function.Injective γ₁ := fun _ _ ↦ by aesop + have hγ₂ : Function.Injective γ₂ := fun _ _ ↦ by aesop + have hγ₃ : Function.Injective γ₃ := fun _ _ ↦ by aesop + have hγ₄ : Function.Injective γ₄ := fun _ _ ↦ by aesop + have eq₁ : H.h 0 ≫ Y.δ 0 = β ⟨0, 0⟩ := by simp [β] + have eq₂ : H.h (Fin.last _) ≫ Y.δ (Fin.last _) = - β ⟨Fin.last _, Fin.last _⟩ := by + dsimp [β] + simp only [pow_add, even_two, Even.neg_pow, one_pow, mul_one, + pow_one, mul_neg, neg_smul, neg_neg] + rw [← pow_add, (Even.add_self n).neg_one_pow, one_smul] + have eq₃ : ∑ x ∈ Sᶜ, α x = - ∑ y ∈ Finset.image γ₁ Sᶜ, β y := by + rw [← Finset.sum_neg_distrib, Finset.sum_image hγ₁.injOn] + refine Finset.sum_congr rfl (fun x hx ↦ ?_) + dsimp [α, β, γ₁] + simp only [← H.h_succ_comp_δ_castSucc_of_lt x.2 x.1 (by simpa [S] using hx), + pow_add, pow_one, mul_neg, mul_one, neg_smul, neg_neg] + rw [mul_comm] + have eq₄ : ∑ x ∈ S, α x = - ∑ y ∈ Finset.image γ₂ S, β y := by + rw [← Finset.sum_neg_distrib, Finset.sum_image hγ₂.injOn] + refine Finset.sum_congr rfl (fun x hx ↦ ?_) + dsimp [α, β, γ₂] + simp only [← H.h_castSucc_comp_δ_succ_of_lt x.2 x.1 (by simpa [S] using hx), + pow_add, pow_one, mul_neg, mul_one, neg_mul, neg_smul, neg_neg] + rw [mul_comm] + have eq₅ : ∑ x, β (γ₄ x) = - ∑ x, β (γ₃ x) := by + rw [← Finset.sum_neg_distrib] + exact Finset.sum_congr rfl (fun x hx ↦ by simp [h_succ_comp_δ_castSucc_succ, β, γ₃, γ₄]) + have h₁ : Disjoint (Finset.image γ₁ Sᶜ) (Finset.image γ₂ S) := by + rw [Finset.disjoint_iff_ne] + simp only [Finset.compl_filter, not_lt, Finset.mem_image, Finset.mem_filter, Finset.mem_univ, + true_and, Prod.exists, ne_eq, forall_exists_index, and_imp, Prod.forall, Prod.mk.injEq, + not_and, γ₁, S, γ₂] + rintro _ _ ⟨a, _⟩ ⟨b, _⟩ h₁ rfl rfl _ _ ⟨a', _⟩ ⟨b', _⟩ h₂ rfl rfl h₃ h₄ + simp only [Fin.castSucc_mk, Fin.mk_le_mk, Fin.mk_lt_mk, + Fin.succ_mk, Fin.mk.injEq] at h₁ h₂ h₃ h₄ + grind + have h₂ : Disjoint (Finset.image γ₃ .univ) (Finset.image γ₄ .univ) := by + rw [Finset.disjoint_iff_ne] + grind + have h₃ : Disjoint (Finset.disjUnion _ _ h₂) {(0, 0), (Fin.last _, Fin.last _)} := by + rw [Finset.disjoint_iff_ne] + grind + have h₄ : Disjoint (Finset.disjUnion _ _ h₁) (Finset.disjUnion _ _ h₃) := by + rw [Finset.disjoint_iff_ne] + simp only [Finset.compl_filter, not_lt, Finset.disjUnion_eq_union, Finset.mem_union, + Finset.mem_image, Finset.mem_filter, Finset.mem_univ, true_and, Prod.exists, ne_eq, + Finset.mem_insert, Finset.mem_singleton, Prod.forall, Prod.mk.injEq, not_and, + S, γ₁, γ₂, γ₃, γ₄] + rintro _ _ (⟨⟨j, _⟩, ⟨k, _⟩, h₁, h₂, h₃⟩ | ⟨⟨j, _⟩, ⟨k, _⟩, h₁, h₂, h₃⟩) _ _ + ((⟨⟨i, _⟩, h₄, h₅⟩ | ⟨⟨i, _⟩, h₄, h₅⟩) | (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩)) <;> + simp at h₁ h₂ h₃ <;> grind + have H : (Finset.disjUnion _ _ h₁)ᶜ = Finset.disjUnion _ _ h₃ := + Finset.compl_eq_of_disjoint_of_card_add_eq h₄ (by + rw [Finset.card_disjUnion, Finset.card_disjUnion, Finset.card_disjUnion, + Finset.card_image_of_injective _ hγ₁, Finset.card_image_of_injective _ hγ₂, + Finset.card_image_of_injective _ hγ₃, Finset.card_image_of_injective _ hγ₄] + simp only [Finset.card_compl_add_card, Fintype.card_prod, Fintype.card_fin, + Finset.card_univ] + grind) + rw [eq₁, eq₂, ← S.sum_add_sum_compl, eq₃, eq₄, + neg_add_rev, neg_neg, neg_neg, ← Finset.sum_disjUnion h₁, + ← (Finset.disjUnion _ _ h₁).sum_add_sum_compl, neg_add, + ← add_assoc, add_neg_cancel, zero_add, H, + Finset.sum_disjUnion, Finset.sum_disjUnion, + Finset.sum_image hγ₃.injOn, Finset.sum_image hγ₄.injOn, + Finset.sum_insert (by simp), Finset.sum_singleton, + neg_add_rev, neg_add_rev, neg_add_rev, eq₅] + simp + +end ToChainHomotopy + +set_option backward.isDefEq.respectTransparency false in +/-- A simplicial homotopy between `f` and `g` induces a chain homotopy +between the induced morphisms on the alternating face map complexes. -/ +noncomputable def toChainHomotopy (H : Homotopy f g) : + _root_.Homotopy + ((alternatingFaceMapComplex C).map f) + ((alternatingFaceMapComplex C).map g) where + hom := ToChainHomotopy.hom H + zero i j hij := ToChainHomotopy.hom_eq_zero _ _ _ hij + comm n := by + cases n with + | zero => + rw [prevD_eq (j' := 1) (w := by simp), dNext_eq_zero _ _ (by simp), zero_add] + simp [ToChainHomotopy.comm_zero H] + | succ n => + rw [dNext_eq (i' := n) (w := by simp), prevD_eq (j' := n + 2) (w := by simp)] + simp [ToChainHomotopy.comm_succ H] + +theorem map_homology_eq [CategoryWithHomology C] (H : Homotopy f g) (n : ℕ) : + (HomologicalComplex.homologyFunctor C _ n).map ((alternatingFaceMapComplex C).map f) = + (HomologicalComplex.homologyFunctor C _ n).map ((alternatingFaceMapComplex C).map g) := by + simpa using (H.toChainHomotopy).homologyMap_eq n + +end CategoryTheory.SimplicialObject.Homotopy diff --git a/Mathlib/AlgebraicTopology/SimplicialObject/Homotopy.lean b/Mathlib/AlgebraicTopology/SimplicialObject/Homotopy.lean new file mode 100644 index 00000000000000..30ae54f07cf520 --- /dev/null +++ b/Mathlib/AlgebraicTopology/SimplicialObject/Homotopy.lean @@ -0,0 +1,168 @@ +/- +Copyright (c) 2025 Fabian Odermatt. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Fabian Odermatt +-/ +module + +public import Mathlib.AlgebraicTopology.SimplicialObject.Basic +public import Mathlib.AlgebraicTopology.SimplexCategory.Basic + +/-! +# Simplicial homotopies of simplicial objects + +This file defines the notion of a combinatorial simplicial homotopy between two morphisms +of simplicial objects. + +## Main definitions + +* `Homotopy f g`: The type of simplicial homotopies between morphisms `f g : X ⟶ Y`. +* `Homotopy.refl f`: The constant homotopy from `f` to `f`. + +## Implementation notes + +The definition follows the combinatorial description of simplicial homotopies. +Given simplicial objects `X Y : SimplicialObject C` and morphisms `f g : X ⟶ Y`, +a simplicial homotopy consists of a family of morphisms `h n i : X _⦋n⦌ ⟶ Y _⦋n+1⦌` +satisfying compatibilities involving the faces and degeneracies. + +## References + +* [nLab, *Simplicial Homotopy*](https://ncatlab.org/nlab/show/simplicial+homotopy) +-/ + +@[expose] public section + +universe v u v' u' + +noncomputable section + +open SimplexCategory Simplicial Opposite + +namespace CategoryTheory.SimplicialObject + +variable {C : Type u} [Category.{v} C] + +/-- A simplicial homotopy between morphisms `f g : X ⟶ Y` of simplicial objects +consists of a family of morphisms `h n i : X _⦋n⦌ ⟶ Y _⦋n + 1⦌` for `i : Fin (n + 1)`, +satisfying compatibility conditions with respect to face and degeneracy maps -/ +@[ext] +structure Homotopy + {X Y : SimplicialObject C} (f g : X ⟶ Y) where + /-- Basic data: `h i : Xₙ ⟶ Yₙ₊₁` for `i : Fin (n + 1)`. -/ + h {n : ℕ} (i : Fin (n + 1)) : X _⦋n⦌ ⟶ Y _⦋n + 1⦌ + h_zero_comp_δ_zero (n : ℕ) : h 0 ≫ Y.δ 0 = g.app (op ⦋n⦌) + h_last_comp_δ_last (n : ℕ) : h (Fin.last n) ≫ Y.δ (Fin.last (n + 1)) = f.app (op ⦋n⦌) + h_succ_comp_δ_castSucc_of_lt {n : ℕ} (i : Fin (n + 2)) (j : Fin (n + 1)) (hij : i ≤ j.castSucc) : + h j.succ ≫ Y.δ i.castSucc = X.δ i ≫ h j + h_succ_comp_δ_castSucc_succ {n : ℕ} (j : Fin (n + 1)) : + h j.succ ≫ Y.δ j.castSucc.succ = h j.castSucc ≫ Y.δ j.castSucc.succ + h_castSucc_comp_δ_succ_of_lt {n : ℕ} (i : Fin (n + 2)) (j : Fin (n + 1)) (hji : j.castSucc < i) : + h j.castSucc ≫ Y.δ i.succ = X.δ i ≫ h j + h_comp_σ_castSucc_of_le {n : ℕ} (i j : Fin (n + 1)) (hij : i ≤ j) : + h j ≫ Y.σ i.castSucc = X.σ i ≫ h j.succ + h_comp_σ_succ_of_lt {n : ℕ} (i j : Fin (n + 1)) (hji : j ≤ i) : + h j ≫ Y.σ i.succ = X.σ i ≫ h j.castSucc + +namespace Homotopy + +variable {X Y : SimplicialObject C} {f g : X ⟶ Y} + +attribute [reassoc (attr := simp)] + h_zero_comp_δ_zero h_last_comp_δ_last h_succ_comp_δ_castSucc_of_lt + h_castSucc_comp_δ_succ_of_lt h_comp_σ_castSucc_of_le h_comp_σ_succ_of_lt + +attribute [reassoc] h_succ_comp_δ_castSucc_succ + +/-- The constant homotopy from `f` to `f`. -/ +@[simps] +def refl (f : X ⟶ Y) : Homotopy f f where + h i := X.σ i ≫ f.app _ + h_zero_comp_δ_zero n := by + have := Y.δ_comp_σ_self (n := n) (i := 0) + dsimp at this + simp only [SimplicialObject.σ_naturality, Category.assoc, this, Category.comp_id] + h_last_comp_δ_last n := by + have := Y.δ_comp_σ_succ (i := Fin.last n) + dsimp at this + simp only [SimplicialObject.σ_naturality, Category.assoc, this, Category.comp_id] + h_succ_comp_δ_castSucc_of_lt i j hij := by simp [Y.δ_comp_σ_of_le hij] + h_succ_comp_δ_castSucc_succ j := by + have h₁ := Y.δ_comp_σ_self (i := j.succ) + have h₂ := Y.δ_comp_σ_succ (i := j.castSucc) + dsimp at h₁ h₂ + simp only [SimplicialObject.σ_naturality, Category.assoc, h₁, Category.comp_id, h₂] + h_castSucc_comp_δ_succ_of_lt i j hji := by simp [Y.δ_comp_σ_of_gt hji] + h_comp_σ_castSucc_of_le i j hij := by simp [Y.σ_comp_σ hij] + h_comp_σ_succ_of_lt i j hji := by simp [Y.σ_comp_σ hji] + +/-- Postcompose a simplicial homotopy with a functor `F : C ⥤ D`. -/ +@[simps] +def whiskerRight (H : Homotopy f g) {D : Type u'} [Category.{v'} D] (F : C ⥤ D) : + Homotopy + (((SimplicialObject.whiskering C D).obj F).map f) + (((SimplicialObject.whiskering C D).obj F).map g) where + h i := F.map (H.h i) + h_zero_comp_δ_zero n := by + simpa [SimplicialObject.δ] using + congrArg (fun k => F.map k) (H.h_zero_comp_δ_zero n) + h_last_comp_δ_last n := by + simpa [SimplicialObject.δ] using + congrArg (fun k => F.map k) (H.h_last_comp_δ_last n) + h_succ_comp_δ_castSucc_of_lt i j hij := by + simpa [SimplicialObject.δ] using + congrArg (fun k => F.map k) (H.h_succ_comp_δ_castSucc_of_lt i j hij) + h_succ_comp_δ_castSucc_succ j := by + simpa [SimplicialObject.δ] using + congrArg (fun k => F.map k) (H.h_succ_comp_δ_castSucc_succ j) + h_castSucc_comp_δ_succ_of_lt i j hji := by + simpa [SimplicialObject.δ] using + congrArg (fun k => F.map k) (H.h_castSucc_comp_δ_succ_of_lt i j hji) + h_comp_σ_castSucc_of_le i j hij := by + simpa [SimplicialObject.σ] using + congrArg (fun k => F.map k) (H.h_comp_σ_castSucc_of_le i j hij) + h_comp_σ_succ_of_lt i j hji := by + simpa [SimplicialObject.σ] using + congrArg (fun k => F.map k) (H.h_comp_σ_succ_of_lt i j hji) + +/-- Postcompose a simplicial homotopy with a morphism of simplicial objects. -/ +@[simps] +def postcomp (H : Homotopy f g) {Y' : SimplicialObject C} (p : Y ⟶ Y') : + Homotopy (f ≫ p) (g ≫ p) where + h i := H.h i ≫ p.app _ + h_zero_comp_δ_zero n := by + simpa [-h_zero_comp_δ_zero] using H.h_zero_comp_δ_zero n =≫ p.app _ + h_last_comp_δ_last n := by + simpa [-h_last_comp_δ_last] using H.h_last_comp_δ_last n =≫ p.app _ + h_succ_comp_δ_castSucc_of_lt i j hij := by + simpa using H.h_succ_comp_δ_castSucc_of_lt i j hij =≫ p.app _ + h_succ_comp_δ_castSucc_succ j := by + simpa using H.h_succ_comp_δ_castSucc_succ j =≫ p.app _ + h_castSucc_comp_δ_succ_of_lt i j hji := by + simpa using H.h_castSucc_comp_δ_succ_of_lt i j hji =≫ p.app _ + h_comp_σ_castSucc_of_le i j hij := by + simpa using H.h_comp_σ_castSucc_of_le i j hij =≫ p.app _ + h_comp_σ_succ_of_lt i j hji := by + simpa using H.h_comp_σ_succ_of_lt i j hji =≫ p.app _ + +/-- Precompose a simplicial homotopy with a morphism of simplicial objects. -/ +@[simps] +def precomp (H : Homotopy f g) {X' : SimplicialObject C} (p : X' ⟶ X) : + Homotopy (p ≫ f) (p ≫ g) where + h i := p.app _ ≫ H.h i + h_zero_comp_δ_zero n := by + simpa [-h_zero_comp_δ_zero] using p.app _ ≫= H.h_zero_comp_δ_zero n + h_last_comp_δ_last n := by + simpa [-h_last_comp_δ_last] using p.app _ ≫= H.h_last_comp_δ_last n + h_succ_comp_δ_castSucc_of_lt i j hij := by + simpa using p.app _ ≫= H.h_succ_comp_δ_castSucc_of_lt i j hij + h_succ_comp_δ_castSucc_succ j := by + simpa using p.app _ ≫= H.h_succ_comp_δ_castSucc_succ j + h_castSucc_comp_δ_succ_of_lt i j hji := by + simpa using p.app _ ≫= H.h_castSucc_comp_δ_succ_of_lt i j hji + h_comp_σ_castSucc_of_le i j hij := by + simpa using p.app _ ≫= H.h_comp_σ_castSucc_of_le i j hij + h_comp_σ_succ_of_lt i j hji := by + simpa using p.app _ ≫= H.h_comp_σ_succ_of_lt i j hji + +end CategoryTheory.SimplicialObject.Homotopy diff --git a/Mathlib/AlgebraicTopology/SingularHomology/HomotopyInvariance.lean b/Mathlib/AlgebraicTopology/SingularHomology/HomotopyInvariance.lean new file mode 100644 index 00000000000000..b1a49b7652ce8b --- /dev/null +++ b/Mathlib/AlgebraicTopology/SingularHomology/HomotopyInvariance.lean @@ -0,0 +1,57 @@ +/- +Copyright (c) 2025 Fabian Odermatt. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Fabian Odermatt +-/ +module + +public import Mathlib.AlgebraicTopology.SingularHomology.Basic +public import Mathlib.AlgebraicTopology.SimplicialObject.Homotopy +public import Mathlib.AlgebraicTopology.SimplicialObject.ChainHomotopy + +/-! +# Homotopy invariance of singular homology (simplicial step) + +This file proves that simplicially homotopic morphisms of simplicial sets induce the same maps +on singular homology (with coefficients in an object of a preadditive category with coproducts). +-/ + +@[expose] public section + +universe v u + +open CategoryTheory SimplicialObject Homotopy +open AlgebraicTopology.SSet + +variable (C : Type u) [Category.{v} C] +variable [CategoryTheory.Preadditive C] [CategoryTheory.Limits.HasCoproducts C] +variable {C} +variable (R : C) +variable {X Y : SSet} (f g : X ⟶ Y) + +/-- +If `f` and `g` are simplicially homotopic maps of simplicial sets, then they induce chain-homotopic +maps on the singular chain complexes with coefficients in `R`. +-/ +noncomputable def singularChainComplexFunctor_mapHomotopy_of_simplicialHomotopy + (H : Homotopy f g) : + Homotopy + (((singularChainComplexFunctor C).obj R).map f) + (((singularChainComplexFunctor C).obj R).map g) := by + simpa using + toChainHomotopy (H.whiskerRight (_ : Type _ ⥤ C)) + +/-- +Simplicially homotopic maps of simplicial sets induce the same map on homology of the singular +chain complex (with coefficients in `R`). +-/ +theorem singularChainComplexFunctor_map_homology_eq_of_simplicialHomotopy + [CategoryWithHomology C] + (H : Homotopy f g) (n : ℕ) : + (HomologicalComplex.homologyFunctor C _ n).map + (((singularChainComplexFunctor C).obj R).map f) = + (HomologicalComplex.homologyFunctor C _ n).map + (((singularChainComplexFunctor C).obj R).map g) := by + simpa using + (singularChainComplexFunctor_mapHomotopy_of_simplicialHomotopy + (C := C) (R := R) (f := f) (g := g) H).homologyMap_eq n diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Note.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Note.lean index 66744ee529ef9f..3fee5194d46efb 100644 --- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Note.lean +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Note.lean @@ -6,7 +6,7 @@ Authors: Jireh Loreaux module public import Mathlib.Init -public import Mathlib.Tactic.Basic +public import Batteries.Util.LibraryNote /-! # Documentation concerning the continuous functional calculus diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean index 002c5a40688006..e6891ef02f0cd3 100644 --- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean @@ -333,7 +333,7 @@ lemma le_iff_norm_sqrt_mul_rpow (a b : A) (ha : 0 ≤ a := by cfc_tac) lemma le_iff_norm_sqrt_mul_sqrt_inv {a : A} {b : Aˣ} (ha : 0 ≤ a) (hb : 0 ≤ (b : A)) : a ≤ b ↔ ‖sqrt a * sqrt (↑b⁻¹ : A)‖ ≤ 1 := by rw [CFC.sqrt_eq_rpow (a := (↑b⁻¹ : A)), ← CFC.rpow_neg_one_eq_inv b, - CFC.rpow_rpow (b : A) _ _ (by simp) (by simp), + CFC.rpow_rpow (b : A) _ _ (by simp), le_iff_norm_sqrt_mul_rpow a (hb := b.isUnit.isStrictlyPositive hb)] simp diff --git a/Mathlib/Analysis/CStarAlgebra/Matrix.lean b/Mathlib/Analysis/CStarAlgebra/Matrix.lean index ba69ee76654763..0ca3e6b49f3436 100644 --- a/Mathlib/Analysis/CStarAlgebra/Matrix.lean +++ b/Mathlib/Analysis/CStarAlgebra/Matrix.lean @@ -129,7 +129,7 @@ lemma inner_toEuclideanCLM (A : Matrix n n ℝ) (x y : EuclideanSpace ℝ n) : toLin_apply, mulVec_eq_sum, OrthonormalBasis.coe_toBasis_repr_apply, EuclideanSpace.basisFun_repr, op_smul_eq_smul, Finset.sum_apply, Pi.smul_apply, transpose_apply, smul_eq_mul, OrthonormalBasis.coe_toBasis, EuclideanSpace.basisFun_apply, PiLp.inner_apply, - ofLp_sum, ofLp_smul, EuclideanSpace.ofLp_single, RCLike.inner_apply, conj_trivial, dotProduct] + ofLp_sum, ofLp_smul, PiLp.ofLp_single, RCLike.inner_apply, conj_trivial, dotProduct] congr with i rw [mul_comm (x.ofLp i)] simp [Pi.single_apply] diff --git a/Mathlib/Analysis/Calculus/ContDiff/Comp.lean b/Mathlib/Analysis/Calculus/ContDiff/Comp.lean index 9abb46526f6ca9..47fca6afcd75c3 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/Comp.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/Comp.lean @@ -333,6 +333,12 @@ theorem contDiffWithinAt_fst {s : Set (E × F)} {p : E × F} : ContDiffWithinAt 𝕜 n (Prod.fst : E × F → E) s p := contDiff_fst.contDiffWithinAt +/-- Postcomposing `f` with `Prod.fst` is `C^n` at `x` -/ +@[fun_prop] +theorem ContDiffWithinAt.fst {f : E → F × G} {x : E} (hf : ContDiffWithinAt 𝕜 n f s x) : + ContDiffWithinAt 𝕜 n (fun x ↦ (f x).1) s x := + contDiffWithinAt_fst.comp x hf (mapsTo_image f s) + /-- The second projection in a product is `C^∞`. -/ @[fun_prop] theorem contDiff_snd : ContDiff 𝕜 n (Prod.snd : E × F → F) := @@ -357,11 +363,23 @@ theorem ContDiffOn.snd {f : E → F × G} {s : Set E} (hf : ContDiffOn 𝕜 n f ContDiffOn 𝕜 n (fun x => (f x).2) s := contDiff_snd.comp_contDiffOn hf +/-- The second projection within a domain at a point in a product is `C^∞`. -/ +@[fun_prop] +theorem contDiffWithinAt_snd {s : Set (E × F)} {p : E × F} : + ContDiffWithinAt 𝕜 n (Prod.snd : E × F → F) s p := + contDiff_snd.contDiffWithinAt + /-- The second projection at a point in a product is `C^∞`. -/ @[fun_prop] theorem contDiffAt_snd {p : E × F} : ContDiffAt 𝕜 n (Prod.snd : E × F → F) p := contDiff_snd.contDiffAt +/-- Postcomposing `f` with `Prod.snd` is `C^n` at `x` -/ +@[fun_prop] +theorem ContDiffWithinAt.snd {f : E → F × G} {x : E} (hf : ContDiffWithinAt 𝕜 n f s x) : + ContDiffWithinAt 𝕜 n (fun x ↦ (f x).2) s x := + contDiffWithinAt_snd.comp x hf (mapsTo_image f s) + /-- Postcomposing `f` with `Prod.snd` is `C^n` at `x` -/ @[fun_prop] theorem ContDiffAt.snd {f : E → F × G} {x : E} (hf : ContDiffAt 𝕜 n f x) : @@ -378,11 +396,25 @@ theorem ContDiffAt.snd'' {f : F → G} {x : E × F} (hf : ContDiffAt 𝕜 n f x. ContDiffAt 𝕜 n (fun x : E × F => f x.2) x := hf.comp x contDiffAt_snd -/-- The second projection within a domain at a point in a product is `C^∞`. -/ -@[fun_prop] -theorem contDiffWithinAt_snd {s : Set (E × F)} {p : E × F} : - ContDiffWithinAt 𝕜 n (Prod.snd : E × F → F) s p := - contDiff_snd.contDiffWithinAt +theorem contDiffWithinAt_prod_iff (f : E → F × G) : + ContDiffWithinAt 𝕜 n f s x ↔ + ContDiffWithinAt 𝕜 n (Prod.fst ∘ f) s x ∧ ContDiffWithinAt 𝕜 n (Prod.snd ∘ f) s x := + ⟨fun h ↦ ⟨h.fst, h.snd⟩, fun h ↦ h.1.prodMk h.2⟩ + +theorem contDiffAt_prod_iff (f : E → F × G) : + ContDiffAt 𝕜 n f x ↔ + ContDiffAt 𝕜 n (Prod.fst ∘ f) x ∧ ContDiffAt 𝕜 n (Prod.snd ∘ f) x := + ⟨fun h ↦ ⟨h.fst, h.snd⟩, fun h ↦ h.1.prodMk h.2⟩ + +theorem contDiffOn_prod_iff (f : E → F × G) : + ContDiffOn 𝕜 n f s ↔ + ContDiffOn 𝕜 n (Prod.fst ∘ f) s ∧ ContDiffOn 𝕜 n (Prod.snd ∘ f) s := + ⟨fun h ↦ ⟨h.fst, h.snd⟩, fun h ↦ h.1.prodMk h.2⟩ + +theorem contDiff_prod_iff (f : E → F × G) : + ContDiff 𝕜 n f ↔ + ContDiff 𝕜 n (Prod.fst ∘ f) ∧ ContDiff 𝕜 n (Prod.snd ∘ f) := + ⟨fun h ↦ ⟨h.fst, h.snd⟩, fun h ↦ h.1.prodMk h.2⟩ section NAry diff --git a/Mathlib/Analysis/Calculus/Implicit.lean b/Mathlib/Analysis/Calculus/Implicit.lean index 3dfa1ff1bac092..abdf64ac05ae8f 100644 --- a/Mathlib/Analysis/Calculus/Implicit.lean +++ b/Mathlib/Analysis/Calculus/Implicit.lean @@ -16,7 +16,7 @@ public import Mathlib.Analysis.Normed.Module.Complemented We prove three versions of the implicit function theorem. First we define a structure `ImplicitFunctionData` that holds arguments for the most general version of the implicit function theorem, see `ImplicitFunctionData.implicitFunction` and -`ImplicitFunctionData.implicitFunction_hasStrictFDerivAt`. This version allows a user to choose a +`ImplicitFunctionData.hasStrictFDerivAt_implicitFunction`. This version allows a user to choose a specific implicit function but provides only a little convenience over the inverse function theorem. Then we define `HasStrictFDerivAt.implicitFunctionDataOfComplemented`: implicit function defined by @@ -28,7 +28,7 @@ that the kernel of `f'` is complemented, hence the only assumptions are `HasStri and `f'.range = ⊤`. This version is named `HasStrictFDerivAt.implicitFunction`. For the version where the implicit equation is defined by a $C^n$ function `f : E × F → G` with an -invertible derivative `∂f/∂y`, see `IsContDiffImplicitAt.implicitFunction`. +invertible derivative `∂f/∂y`, see `ContDiffAt.implicitFunction`. ## TODO @@ -47,8 +47,7 @@ invertible derivative `∂f/∂y`, see `IsContDiffImplicitAt.implicitFunction`. implicit function, inverse function -/ -@[expose] public section - +public section noncomputable section @@ -129,7 +128,7 @@ def prodFun (x : E) : F × G := (φ.leftFun x, φ.rightFun x) @[simp] -theorem prodFun_apply (x : E) : φ.prodFun x = (φ.leftFun x, φ.rightFun x) := +theorem prodFun_apply (x : E) : φ.prodFun x = (φ.leftFun x, φ.rightFun x) := by rfl protected theorem hasStrictFDerivAt : @@ -161,17 +160,22 @@ complementary subspaces of `E`, then `implicitFunction` is the unique (germ of a def implicitFunction : F → G → E := Function.curry <| φ.toOpenPartialHomeomorph.symm +theorem implicitFunction_def : + implicitFunction φ = Function.curry (φ.hasStrictFDerivAt.toOpenPartialHomeomorph _).symm := by + rfl + lemma implicitFunction_apply {x : F} {y : G} : - φ.implicitFunction x y = φ.toOpenPartialHomeomorph.symm (x, y) := rfl + φ.implicitFunction x y = φ.toOpenPartialHomeomorph.symm (x, y) := by + rfl @[simp] -theorem toOpenPartialHomeomorph_coe : ⇑φ.toOpenPartialHomeomorph = φ.prodFun := +theorem toOpenPartialHomeomorph_coe : ⇑φ.toOpenPartialHomeomorph = φ.prodFun := by rfl @[deprecated (since := "2025-08-29")] alias toPartialHomeomorph_coe := toOpenPartialHomeomorph_coe theorem toOpenPartialHomeomorph_apply (x : E) : - φ.toOpenPartialHomeomorph x = (φ.leftFun x, φ.rightFun x) := + φ.toOpenPartialHomeomorph x = (φ.leftFun x, φ.rightFun x) := by rfl @[deprecated (since := "2025-08-29")] alias @@ -190,22 +194,46 @@ theorem map_pt_mem_toOpenPartialHomeomorph_target : @[deprecated (since := "2025-08-29")] alias map_pt_mem_toPartialHomeomorph_target := map_pt_mem_toOpenPartialHomeomorph_target -theorem prod_map_implicitFunction : +theorem prodFun_implicitFunction : ∀ᶠ p : F × G in 𝓝 (φ.prodFun φ.pt), φ.prodFun (φ.implicitFunction p.1 p.2) = p := φ.hasStrictFDerivAt.eventually_right_inverse.mono fun ⟨_, _⟩ h => h -theorem left_map_implicitFunction : +@[deprecated (since := "2026-01-27")] +alias prod_map_implicitFunction := prodFun_implicitFunction + +theorem leftFun_implicitFunction : ∀ᶠ p : F × G in 𝓝 (φ.prodFun φ.pt), φ.leftFun (φ.implicitFunction p.1 p.2) = p.1 := - φ.prod_map_implicitFunction.mono fun _ => congr_arg Prod.fst + φ.prodFun_implicitFunction.mono fun _ => congr_arg Prod.fst + +@[deprecated (since := "2026-01-27")] +alias left_map_implicitFunction := leftFun_implicitFunction -theorem right_map_implicitFunction : +theorem rightFun_implicitFunction : ∀ᶠ p : F × G in 𝓝 (φ.prodFun φ.pt), φ.rightFun (φ.implicitFunction p.1 p.2) = p.2 := - φ.prod_map_implicitFunction.mono fun _ => congr_arg Prod.snd + φ.prodFun_implicitFunction.mono fun _ => congr_arg Prod.snd + +@[deprecated (since := "2026-01-27")] +alias right_map_implicitFunction := rightFun_implicitFunction theorem implicitFunction_apply_image : ∀ᶠ x in 𝓝 φ.pt, φ.implicitFunction (φ.leftFun x) (φ.rightFun x) = x := φ.hasStrictFDerivAt.eventually_left_inverse +theorem leftFun_implicitFunction_eq_leftFun : ∀ᶠ x in 𝓝 φ.pt, + φ.leftFun (φ.implicitFunction (φ.leftFun φ.pt) (φ.rightFun x)) = φ.leftFun φ.pt := by + have := φ.leftFun_implicitFunction.curry_nhds.self_of_nhds.prod_inr_nhds (φ.leftFun φ.pt) + rwa [← prodFun_apply, ← φ.hasStrictFDerivAt.map_nhds_eq_of_equiv, eventually_map] at this + +theorem rightFun_implicitFunction_eq_rightFun : ∀ᶠ x in 𝓝 φ.pt, + φ.rightFun (φ.implicitFunction (φ.leftFun φ.pt) (φ.rightFun x)) = φ.rightFun x := by + have := φ.rightFun_implicitFunction.curry_nhds.self_of_nhds.prod_inr_nhds (φ.leftFun φ.pt) + rwa [← prodFun_apply, ← φ.hasStrictFDerivAt.map_nhds_eq_of_equiv, eventually_map] at this + +theorem leftFun_eq_iff_implicitFunction : ∀ᶠ x in 𝓝 φ.pt, + φ.leftFun x = φ.leftFun φ.pt ↔ φ.implicitFunction (φ.leftFun φ.pt) (φ.rightFun x) = x := by + filter_upwards [φ.implicitFunction_apply_image, φ.leftFun_implicitFunction_eq_leftFun] with x _ _ + constructor <;> exact fun h => by rwa [← h] + theorem map_nhds_eq : map φ.leftFun (𝓝 φ.pt) = 𝓝 (φ.leftFun φ.pt) := show map (Prod.fst ∘ φ.prodFun) (𝓝 φ.pt) = 𝓝 (φ.prodFun φ.pt).1 by rw [← map_map, φ.hasStrictFDerivAt.map_nhds_eq_of_equiv, map_fst_nhds] @@ -243,7 +271,7 @@ theorem rightDeriv_fderiv_implicitFunction (φ : ImplicitFunctionData 𝕜 E F G φ.rightDeriv (fderiv 𝕜 (φ.implicitFunction (φ.leftFun φ.pt)) (φ.rightFun φ.pt) x) = x := by exact φ.fderiv_implicitFunction_apply_eq_iff.mp rfl |>.right -theorem implicitFunction_hasStrictFDerivAt (g'inv : G →L[𝕜] E) +theorem hasStrictFDerivAt_implicitFunction (g'inv : G →L[𝕜] E) (hg'inv : φ.rightDeriv.comp g'inv = ContinuousLinearMap.id 𝕜 G) (hg'invf : φ.leftDeriv.comp g'inv = 0) : HasStrictFDerivAt (φ.implicitFunction (φ.leftFun φ.pt)) g'inv (φ.rightFun φ.pt) := by @@ -252,6 +280,9 @@ theorem implicitFunction_hasStrictFDerivAt (g'inv : G →L[𝕜] E) rw [eq_comm, fderiv_implicitFunction_apply_eq_iff] simp_all [DFunLike.ext_iff] +@[deprecated (since := "2026-01-27")] +alias implicitFunction_hasStrictFDerivAt := hasStrictFDerivAt_implicitFunction + theorem map_implicitFunction_nhdsWithin_preimage (φ : ImplicitFunctionData 𝕜 E F G) (s : Set E) : (𝓝[φ.implicitFunction (φ.leftFun φ.pt) ⁻¹' s] (φ.rightFun φ.pt)).map @@ -348,7 +379,7 @@ end Defs @[simp] theorem implicitToOpenPartialHomeomorphOfComplemented_fst (hf : HasStrictFDerivAt f f' a) (hf' : f'.range = ⊤) (hker : f'.ker.ClosedComplemented) (x : E) : - (hf.implicitToOpenPartialHomeomorphOfComplemented f f' hf' hker x).fst = f x := + (hf.implicitToOpenPartialHomeomorphOfComplemented f f' hf' hker x).fst = f x := by rfl @[deprecated (since := "2025-08-29")] alias @@ -357,7 +388,7 @@ theorem implicitToOpenPartialHomeomorphOfComplemented_fst (hf : HasStrictFDerivA theorem implicitToOpenPartialHomeomorphOfComplemented_apply (hf : HasStrictFDerivAt f f' a) (hf' : f'.range = ⊤) (hker : f'.ker.ClosedComplemented) (y : E) : hf.implicitToOpenPartialHomeomorphOfComplemented f f' hf' hker y = - (f y, Classical.choose hker (y - a)) := + (f y, Classical.choose hker (y - a)) := by rfl @[deprecated (since := "2025-08-29")] alias implicitToPartialHomeomorphOfComplemented_apply := @@ -433,7 +464,7 @@ theorem to_implicitFunctionOfComplemented (hf : HasStrictFDerivAt f f' a) (hf' : (hker : f'.ker.ClosedComplemented) : HasStrictFDerivAt (hf.implicitFunctionOfComplemented f f' hf' hker (f a)) f'.ker.subtypeL 0 := by - convert (implicitFunctionDataOfComplemented f f' hf hf' hker).implicitFunction_hasStrictFDerivAt + convert (implicitFunctionDataOfComplemented f f' hf hf' hker).hasStrictFDerivAt_implicitFunction f'.ker.subtypeL _ _ swap · ext @@ -475,7 +506,7 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] [CompleteSpace 𝕜] {E : returns an open partial homeomorphism between `E` and `F × ker f'`. -/ def implicitToOpenPartialHomeomorph (hf : HasStrictFDerivAt f f' a) (hf' : f'.range = ⊤) : OpenPartialHomeomorph E (F × f'.ker) := - haveI := FiniteDimensional.complete 𝕜 F + have := FiniteDimensional.complete 𝕜 F hf.implicitToOpenPartialHomeomorphOfComplemented f f' hf' f'.ker_closedComplemented_of_finiteDimensional_range @@ -490,7 +521,7 @@ variable {f f'} @[simp] theorem implicitToOpenPartialHomeomorph_fst (hf : HasStrictFDerivAt f f' a) (hf' : f'.range = ⊤) - (x : E) : (hf.implicitToOpenPartialHomeomorph f f' hf' x).fst = f x := + (x : E) : (hf.implicitToOpenPartialHomeomorph f f' hf' x).fst = f x := by rfl @[deprecated (since := "2025-08-29")] alias @@ -500,7 +531,7 @@ theorem implicitToOpenPartialHomeomorph_fst (hf : HasStrictFDerivAt f f' a) (hf' theorem implicitToOpenPartialHomeomorph_apply_ker (hf : HasStrictFDerivAt f f' a) (hf' : f'.range = ⊤) (y : f'.ker) : hf.implicitToOpenPartialHomeomorph f f' hf' (y + a) = (f (y + a), y) := - haveI := FiniteDimensional.complete 𝕜 F + have := FiniteDimensional.complete 𝕜 F implicitToOpenPartialHomeomorphOfComplemented_apply_ker .. @[deprecated (since := "2025-08-29")] alias @@ -509,7 +540,7 @@ theorem implicitToOpenPartialHomeomorph_apply_ker (hf : HasStrictFDerivAt f f' a @[simp] theorem implicitToOpenPartialHomeomorph_self (hf : HasStrictFDerivAt f f' a) (hf' : f'.range = ⊤) : hf.implicitToOpenPartialHomeomorph f f' hf' a = (f a, 0) := - haveI := FiniteDimensional.complete 𝕜 F + have := FiniteDimensional.complete 𝕜 F implicitToOpenPartialHomeomorphOfComplemented_self .. @[deprecated (since := "2025-08-29")] alias @@ -518,7 +549,7 @@ theorem implicitToOpenPartialHomeomorph_self (hf : HasStrictFDerivAt f f' a) (hf set_option backward.isDefEq.respectTransparency false in theorem mem_implicitToOpenPartialHomeomorph_source (hf : HasStrictFDerivAt f f' a) (hf' : f'.range = ⊤) : a ∈ (hf.implicitToOpenPartialHomeomorph f f' hf').source := - haveI := FiniteDimensional.complete 𝕜 F + have := FiniteDimensional.complete 𝕜 F ImplicitFunctionData.pt_mem_toOpenPartialHomeomorph_source _ @[deprecated (since := "2025-08-29")] alias @@ -527,7 +558,7 @@ theorem mem_implicitToOpenPartialHomeomorph_source (hf : HasStrictFDerivAt f f' theorem mem_implicitToOpenPartialHomeomorph_target (hf : HasStrictFDerivAt f f' a) (hf' : f'.range = ⊤) : (f a, (0 : f'.ker)) ∈ (hf.implicitToOpenPartialHomeomorph f f' hf').target := - haveI := FiniteDimensional.complete 𝕜 F + have := FiniteDimensional.complete 𝕜 F mem_implicitToOpenPartialHomeomorphOfComplemented_target .. @[deprecated (since := "2025-08-29")] alias @@ -548,13 +579,13 @@ alias _root_.Filter.Tendsto.implicitFunction := tendsto_implicitFunction /-- `HasStrictFDerivAt.implicitFunction` sends `(z, y)` to a point in `f ⁻¹' z`. -/ theorem map_implicitFunction_eq (hf : HasStrictFDerivAt f f' a) (hf' : f'.range = ⊤) : ∀ᶠ p : F × f'.ker in 𝓝 (f a, 0), f (hf.implicitFunction f f' hf' p.1 p.2) = p.1 := - haveI := FiniteDimensional.complete 𝕜 F + have := FiniteDimensional.complete 𝕜 F map_implicitFunctionOfComplemented_eq .. @[simp] theorem implicitFunction_apply_image (hf : HasStrictFDerivAt f f' a) (hf' : f'.range = ⊤) : hf.implicitFunction f f' hf' (f a) 0 = a := by - haveI := FiniteDimensional.complete 𝕜 F + have := FiniteDimensional.complete 𝕜 F apply implicitFunctionOfComplemented_apply_image /-- Any point in some neighborhood of `a` can be represented as `HasStrictFDerivAt.implicitFunction` @@ -562,14 +593,16 @@ of some point. -/ theorem eq_implicitFunction (hf : HasStrictFDerivAt f f' a) (hf' : f'.range = ⊤) : ∀ᶠ x in 𝓝 a, hf.implicitFunction f f' hf' (f x) (hf.implicitToOpenPartialHomeomorph f f' hf' x).snd = x := - haveI := FiniteDimensional.complete 𝕜 F + have := FiniteDimensional.complete 𝕜 F eq_implicitFunctionOfComplemented .. theorem to_implicitFunction (hf : HasStrictFDerivAt f f' a) (hf' : f'.range = ⊤) : HasStrictFDerivAt (hf.implicitFunction f f' hf' (f a)) f'.ker.subtypeL 0 := - haveI := FiniteDimensional.complete 𝕜 F + have := FiniteDimensional.complete 𝕜 F to_implicitFunctionOfComplemented .. end FiniteDimensional end HasStrictFDerivAt + +end diff --git a/Mathlib/Analysis/Calculus/ImplicitContDiff.lean b/Mathlib/Analysis/Calculus/ImplicitContDiff.lean index f6bedfdc0c9dbe..bb4287f60ddb94 100644 --- a/Mathlib/Analysis/Calculus/ImplicitContDiff.lean +++ b/Mathlib/Analysis/Calculus/ImplicitContDiff.lean @@ -5,7 +5,7 @@ Authors: Winston Yin -/ module -public import Mathlib.Analysis.Calculus.Implicit +public import Mathlib.Analysis.Calculus.ImplicitFunction.ProdDomain public import Mathlib.Analysis.Calculus.InverseFunctionTheorem.ContDiff /-! @@ -14,169 +14,118 @@ public import Mathlib.Analysis.Calculus.InverseFunctionTheorem.ContDiff In this file, we apply the generalised implicit function theorem to the more familiar case and show that the implicit function preserves the smoothness class of the implicit equation. -Let `E`, `F`, and `G` be real or complex Banach spaces. Let `f : E × F → G` be a function that is -$C^n$ at a point `(a, b) : E × F`, where `n ≥ 1`. Let `f'` be the derivative of `f` at `(a, b)`. If -the map `y ↦ f' (0, y)` is a Banach space isomorphism, then there exists a function `φ : E → F` such -that `φ a = b`, and `f x (φ x) = f a b` holds for all `x` in a neighbourhood of `a`. Furthermore, -`φ` is $C^n$ at `a`. - -## TODO -* Local uniqueness of the implicit function -* Derivative of the implicit function +Let `E₁`, `E₂`, and `F` be real or complex Banach spaces. Let `f : E₁ × E₂ → F` be a function that +is $C^n$ at a point `(u₁, u₂) : E₁ × E₂`, where `n ≥ 1`. Let `f'` be the derivative of `f` at +`(u₁, u₂)`. If the map `y ↦ f' (0, y)` is a Banach space isomorphism, then there exists a function +`ψ : E₁ → E₂` such that `ψ u₁ = u₂`, and `f (x, ψ x) = f (u₁, u₂)` holds for all `x` in a +neighbourhood of `u₁`. Furthermore, `ψ` is $C^n$ at `u₁`. ## Tags implicit function, inverse function -/ -@[expose] public section +public section -variable - {𝕜 : Type*} [RCLike 𝕜] - {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] [CompleteSpace E] +variable {𝕜 : Type*} [RCLike 𝕜] + {E₁ : Type*} [NormedAddCommGroup E₁] [NormedSpace 𝕜 E₁] [CompleteSpace E₁] + {E₂ : Type*} [NormedAddCommGroup E₂] [NormedSpace 𝕜 E₂] [CompleteSpace E₂] {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] [CompleteSpace F] - {G : Type*} [NormedAddCommGroup G] [NormedSpace 𝕜 G] [CompleteSpace G] namespace ImplicitFunctionData /-- The implicit function defined by a $C^n$ implicit equation is $C^n$. This applies to the general form of the implicit function theorem. -/ -theorem contDiff_implicitFunction {φ : ImplicitFunctionData 𝕜 E F G} {n : WithTop ℕ∞} - (hl : ContDiffAt 𝕜 n φ.leftFun φ.pt) (hr : ContDiffAt 𝕜 n φ.rightFun φ.pt) (hn : n ≠ 0) : +theorem contDiffAt_implicitFunction {φ : ImplicitFunctionData 𝕜 E₁ E₂ F} {n : WithTop ℕ∞} + (hl : ContDiffAt 𝕜 n φ.leftFun φ.pt) (hr : ContDiffAt 𝕜 n φ.rightFun φ.pt) (pn : n ≠ 0) : ContDiffAt 𝕜 n φ.implicitFunction.uncurry (φ.prodFun φ.pt) := by - rw [implicitFunction, Function.uncurry_curry, toOpenPartialHomeomorph, - ← HasStrictFDerivAt.localInverse_def] - exact (hl.prodMk hr).to_localInverse (φ.hasStrictFDerivAt |>.hasFDerivAt) hn + rw [implicitFunction_def, Function.uncurry_curry, ← HasStrictFDerivAt.localInverse_def] + refine ContDiffAt.to_localInverse ?_ (φ.hasStrictFDerivAt.hasFDerivAt) pn + convert hl.prodMk hr <;> simp end ImplicitFunctionData -open Filter - -open LinearMap (ker range) - open scoped Topology -/-- A predicate stating the sufficient conditions on an implicit equation `f : E × F → G` that will -lead to a $C^n$ implicit function `φ : E → F`. -/ -structure IsContDiffImplicitAt (n : WithTop ℕ∞) (f : E × F → G) (f' : E × F →L[𝕜] G) (a : E × F) : - Prop where - hasFDerivAt : HasFDerivAt f f' a - contDiffAt : ContDiffAt 𝕜 n f a - bijective : Function.Bijective (f'.comp (ContinuousLinearMap.inr 𝕜 E F)) - ne_zero : n ≠ 0 +namespace ContDiffAt -namespace IsContDiffImplicitAt +variable {u : E₁ × E₂} {f : E₁ × E₂ → F} {n : WithTop ℕ∞} -variable - {n : WithTop ℕ∞} {f : E × F → G} {f' : E × F →L[𝕜] G} {a : E × F} - -omit [CompleteSpace E] [CompleteSpace F] [CompleteSpace G] in -@[deprecated IsContDiffImplicitAt.ne_zero (since := "2025-12-22")] -theorem one_le (h : IsContDiffImplicitAt n f f' a) : 1 ≤ n := by - rw [ENat.one_le_iff_ne_zero_withTop] - exact h.ne_zero - -/-- We record the parameters of our specific case in order to apply the general implicit function -theorem. -/ -def implicitFunctionData (h : IsContDiffImplicitAt n f f' a) : - ImplicitFunctionData 𝕜 (E × F) E G where - leftFun := Prod.fst - leftDeriv := ContinuousLinearMap.fst 𝕜 E F - rightFun := f - rightDeriv := f' - pt := a - hasStrictFDerivAt_leftFun := by fun_prop - hasStrictFDerivAt_rightFun := h.contDiffAt.hasStrictFDerivAt' h.hasFDerivAt h.ne_zero - range_leftDeriv := LinearMap.range_eq_top_of_surjective _ fun x ↦ ⟨(x, 0), rfl⟩ - range_rightDeriv := by - apply top_unique - rw [← LinearMap.range_eq_top_of_surjective _ h.bijective.surjective] - exact LinearMap.range_comp_le_range _ _ - isCompl_ker := by - apply IsCompl.of_eq - · ext ⟨x, y⟩ - rw [Submodule.mem_inf, Submodule.mem_bot, LinearMap.mem_ker, ContinuousLinearMap.coe_fst, - LinearMap.coe_fst, LinearMap.mem_ker, Prod.ext_iff, ← h.bijective.injective.eq_iff] - simp +contextual [Prod.mk_zero_zero] - · ext x - simp only [Submodule.mem_sup, Submodule.mem_top, iff_true] - obtain ⟨y, hy⟩ := h.bijective.surjective (f' x) - exact ⟨(0, y), by simp, x - (0, y), by simp [map_sub, ← hy], by abel⟩ - -@[simp] -lemma implicitFunctionData_pt (h : IsContDiffImplicitAt n f f' a) : - h.implicitFunctionData.pt = a := rfl - -@[simp] -lemma implicitFunctionData_leftFun_apply {h : IsContDiffImplicitAt n f f' a} {xy : E × F} : - h.implicitFunctionData.leftFun xy = xy.1 := rfl - -@[deprecated "use simp" (since := "2026-01-08")] -lemma implicitFunctionData_leftFun_pt (h : IsContDiffImplicitAt n f f' a) : - h.implicitFunctionData.leftFun h.implicitFunctionData.pt = a.1 := by - simp - -@[simp] -lemma implicitFunctionData_rightFun_apply {h : IsContDiffImplicitAt n f f' a} {xy : E × F} : - h.implicitFunctionData.rightFun xy = f xy := rfl - -@[deprecated "use simp" (since := "2026-01-08")] -lemma implicitFunctionData_rightFun_pt (h : IsContDiffImplicitAt n f f' a) : - h.implicitFunctionData.rightFun h.implicitFunctionData.pt = f a := by - simp - -/-- The implicit function provided by the general theorem, from which we construct the more useful -form `IsContDiffImplicitAt.implicitFunction`. -/ -noncomputable def implicitFunctionAux (h : IsContDiffImplicitAt n f f' a) : E → G → E × F := - h.implicitFunctionData.implicitFunction - -lemma implicitFunctionAux_fst (h : IsContDiffImplicitAt n f f' a) : - ∀ᶠ p in 𝓝 (a.1, f a), (h.implicitFunctionAux p.1 p.2).1 = p.1 := - h.implicitFunctionData.prod_map_implicitFunction.mono fun _ ↦ congr_arg Prod.fst - -lemma comp_implicitFunctionAux_eq_snd (h : IsContDiffImplicitAt n f f' a) : - ∀ᶠ p in 𝓝 (a.1, f a), f (h.implicitFunctionAux p.1 p.2) = p.2 := - h.implicitFunctionData.prod_map_implicitFunction.mono fun _ ↦ congr_arg Prod.snd - -/-- Implicit function `φ` defined by `f (x, φ x) = f a`. -/ -noncomputable def implicitFunction (h : IsContDiffImplicitAt n f f' a) : E → F := - fun x ↦ (h.implicitFunctionAux x (f a)).2 - -lemma implicitFunction_def (h : IsContDiffImplicitAt n f f' a) : - h.implicitFunction = fun x ↦ (h.implicitFunctionData.implicitFunction.uncurry (x, f a)).2 := +/-- Implicit function `ψ` defined by `f (x, ψ x) = f u`. -/ +noncomputable def implicitFunction + (cdf : ContDiffAt 𝕜 n f u) (pn : n ≠ 0) (if₂ : (fderiv 𝕜 f u ∘L .inr 𝕜 E₁ E₂).IsInvertible) : + E₁ → E₂ := + (cdf.hasStrictFDerivAt pn).implicitFunctionOfProdDomain if₂ + +theorem implicitFunction_def + (cdf : ContDiffAt 𝕜 n f u) (pn : n ≠ 0) (if₂ : (fderiv 𝕜 f u ∘L .inr 𝕜 E₁ E₂).IsInvertible) : + cdf.implicitFunction pn if₂ = (cdf.hasStrictFDerivAt pn).implicitFunctionOfProdDomain if₂ := by rfl -@[simp] -lemma implicitFunction_apply (h : IsContDiffImplicitAt n f f' a) (x : E) : - h.implicitFunction x = (h.implicitFunctionData.implicitFunction x (f a)).2 := rfl +/-- At the base point `u.1`, the implicit function evaluates to `u.2`. -/ +theorem implicitFunction_apply_self + (cdf : ContDiffAt 𝕜 n f u) (pn : n ≠ 0) (if₂ : (fderiv 𝕜 f u ∘L .inr 𝕜 E₁ E₂).IsInvertible) : + cdf.implicitFunction pn if₂ u.1 = u.2 := + eq_of_tendsto_nhds ((cdf.hasStrictFDerivAt pn).tendsto_implicitFunctionOfProdDomain if₂) /-- `implicitFunction` is indeed the (local) implicit function defined by `f`. -/ -lemma apply_implicitFunction (h : IsContDiffImplicitAt n f f' a) : - ∀ᶠ x in 𝓝 a.1, f (x, h.implicitFunction x) = f a := by - have := h.comp_implicitFunctionAux_eq_snd - have hfst := h.implicitFunctionAux_fst - rw [nhds_prod_eq, eventually_swap_iff] at this hfst - apply this.curry.self_of_nhds.mp - apply hfst.curry.self_of_nhds.mono - simp_rw [Prod.swap_prod_mk] - intro x h1 h2 - rw [← h2] - congr 1 - ext - · rw [h1] - · rfl - -theorem eventually_implicitFunction_apply_eq (h : IsContDiffImplicitAt n f f' a) : - ∀ᶠ xy in 𝓝 a, f xy = f a → h.implicitFunction xy.1 = xy.2 := by - refine h.implicitFunctionData.implicitFunction_apply_image.mono fun xy h₁ h₂ ↦ ?_ - simp_all - -/-- If the implicit equation `f` is $C^n$ at `(x, y)`, then its implicit function `φ` around `x` is -also $C^n$ at `x`. -/ -theorem contDiffAt_implicitFunction (h : IsContDiffImplicitAt n f f' a) : - ContDiffAt 𝕜 n h.implicitFunction a.1 := by - have := h.implicitFunctionData.contDiff_implicitFunction contDiffAt_fst h.contDiffAt h.ne_zero - rw [implicitFunction_def] +theorem eventually_apply_implicitFunction + (cdf : ContDiffAt 𝕜 n f u) (pn : n ≠ 0) (if₂ : (fderiv 𝕜 f u ∘L .inr 𝕜 E₁ E₂).IsInvertible) : + ∀ᶠ x in 𝓝 u.1, f (x, cdf.implicitFunction pn if₂ x) = f u := + (cdf.hasStrictFDerivAt pn).eventually_apply_implicitFunctionOfProdDomain if₂ + +theorem eventually_apply_eq_iff_implicitFunction + (cdf : ContDiffAt 𝕜 n f u) (pn : n ≠ 0) (if₂ : (fderiv 𝕜 f u ∘L .inr 𝕜 E₁ E₂).IsInvertible) : + ∀ᶠ v in 𝓝 u, f v = f u ↔ cdf.implicitFunction pn if₂ v.1 = v.2 := + (cdf.hasStrictFDerivAt pn).eventually_apply_eq_iff_implicitFunctionOfProdDomain if₂ + +theorem hasStrictFDerivAt_implicitFunction + (cdf : ContDiffAt 𝕜 n f u) (pn : n ≠ 0) (if₂ : (fderiv 𝕜 f u ∘L .inr 𝕜 E₁ E₂).IsInvertible) : + HasStrictFDerivAt (cdf.implicitFunction pn if₂) + (-(fderiv 𝕜 f u ∘L .inr 𝕜 E₁ E₂).inverse ∘L (fderiv 𝕜 f u ∘L .inl 𝕜 E₁ E₂)) u.1 := + (cdf.hasStrictFDerivAt pn).hasStrictFDerivAt_implicitFunctionOfProdDomain if₂ + +/-- If the implicit equation `f` is $C^n$ at `(u₁, u₂)`, then its implicit function `ψ` around `u₁` +is also $C^n$ at `u₁`. -/ +theorem contDiffAt_implicitFunction + (cdf : ContDiffAt 𝕜 n f u) (pn : n ≠ 0) (if₂ : (fderiv 𝕜 f u ∘L .inr 𝕜 E₁ E₂).IsInvertible) : + ContDiffAt 𝕜 n (cdf.implicitFunction pn if₂) u.1 := by + rw [ContDiffAt.implicitFunction_def, HasStrictFDerivAt.implicitFunctionOfProdDomain_def] + set φ := (cdf.hasStrictFDerivAt pn).implicitFunctionDataOfProdDomain if₂ + have : ContDiffAt 𝕜 n φ.implicitFunction.uncurry (f u, u.1) := by + simpa [φ] using φ.contDiffAt_implicitFunction + (by simpa [φ] using cdf) (by simpa [φ] using contDiffAt_fst) pn fun_prop +end ContDiffAt + +/-- A predicate stating the sufficient conditions on an implicit equation `f : E₁ × E₂ → F` that +will lead to a $C^n$ implicit function `ψ : E₁ → E₂`. -/ +@[deprecated "ContDiffAt.implicitFunction does not require this" (since := "2026-01-27")] +structure IsContDiffImplicitAt (n : WithTop ℕ∞) (f : E₁ × E₂ → F) (f' : E₁ × E₂ →L[𝕜] F) + (u : E₁ × E₂) : Prop where + hasFDerivAt : HasFDerivAt f f' u + contDiffAt : ContDiffAt 𝕜 n f u + bijective : Function.Bijective (f'.comp (ContinuousLinearMap.inr 𝕜 E₁ E₂)) + ne_zero : n ≠ 0 + +namespace IsContDiffImplicitAt + +@[deprecated (since := "2026-01-27")] +alias implicitFunction := ContDiffAt.implicitFunction + +@[deprecated (since := "2026-01-27")] +alias implicitFunction_def := ContDiffAt.implicitFunction_def + +@[deprecated (since := "2026-01-27")] +alias apply_implicitFunction := ContDiffAt.eventually_apply_implicitFunction + +@[deprecated (since := "2026-01-27")] +alias eventually_implicitFunction_apply_eq := ContDiffAt.eventually_apply_eq_iff_implicitFunction + +@[deprecated (since := "2026-01-27")] +alias contDiffAt_implicitFunction := ContDiffAt.contDiffAt_implicitFunction + end IsContDiffImplicitAt + +end diff --git a/Mathlib/Analysis/Calculus/ImplicitFunction/ProdDomain.lean b/Mathlib/Analysis/Calculus/ImplicitFunction/ProdDomain.lean new file mode 100644 index 00000000000000..261746cc9cfb2e --- /dev/null +++ b/Mathlib/Analysis/Calculus/ImplicitFunction/ProdDomain.lean @@ -0,0 +1,133 @@ +/- +Copyright (c) 2025 A Tucker. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: A Tucker +-/ +module + +public import Mathlib.Analysis.Calculus.Implicit + +/-! +# Implicit function theorem — domain a product space + +This specialization of the implicit function theorem applies to an uncurried bivariate function +`f : E₁ × E₂ → F` and assumes strict differentiability of `f` at `u : E₁ × E₂` as well as +invertibility of `f₂u : E₂ →L[𝕜] F` its partial derivative with respect to the second argument. + +It proves the existence of `ψ : E₁ → E₂` such that for `v` in a neighbourhood of `u` we have +`f v = f u ↔ ψ v.1 = v.2`. This is `HasStrictFDerivAt.implicitFunctionOfProdDomain`. A formula for +its first derivative follows. + +## Tags + +implicit function +-/ + +public section + +open Filter +open scoped Topology + +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] + {E₁ : Type*} [NormedAddCommGroup E₁] [NormedSpace 𝕜 E₁] [CompleteSpace E₁] + {E₂ : Type*} [NormedAddCommGroup E₂] [NormedSpace 𝕜 E₂] [CompleteSpace E₂] + {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] [CompleteSpace F] + +namespace HasStrictFDerivAt + +variable {u : E₁ × E₂} {f : E₁ × E₂ → F} {f'u : E₁ × E₂ →L[𝕜] F} + +/-- Given `f : E₁ × E₂ → F` strictly differentiable at `u` with invertible partial derivative +`f₂u : E₂ →L[𝕜] F`, we may construct an `ImplicitFunctionData 𝕜 (E₁ × E₂) F E₁` with `f` as its +`leftFun` and `Prod.fst : E₁ × E₂ → E₁` as its `rightFun` by proving that the kernels of the +associated `leftDeriv` and `rightDeriv` are complementary. -/ +def implicitFunctionDataOfProdDomain + (dfu : HasStrictFDerivAt f f'u u) (if₂u : (f'u ∘L .inr 𝕜 E₁ E₂).IsInvertible) : + ImplicitFunctionData 𝕜 (E₁ × E₂) F E₁ where + leftFun := f + rightFun := Prod.fst + pt := u + leftDeriv := f'u + hasStrictFDerivAt_leftFun := dfu + rightDeriv := .fst 𝕜 E₁ E₂ + hasStrictFDerivAt_rightFun := hasStrictFDerivAt_fst + range_leftDeriv := by + have : (f'u ∘L .inr 𝕜 E₁ E₂).range ≤ f'u.range := LinearMap.range_comp_le_range .. + rwa [LinearMap.range_eq_top.mpr if₂u.surjective, top_le_iff] at this + range_rightDeriv := Submodule.range_fst + isCompl_ker := by + constructor + · rw [LinearMap.disjoint_ker] + intro (_, y) h rfl + simpa using (injective_iff_map_eq_zero _).mp if₂u.injective y h + · rw [Submodule.codisjoint_iff_exists_add_eq] + intro v + have ⟨y, hy⟩ := if₂u.surjective (f'u v) + use v - (0, y), (0, y) + aesop + +@[simp] theorem pt_implicitFunctionDataOfProdDomain + (dfu : HasStrictFDerivAt f f'u u) (if₂u : (f'u ∘L .inr 𝕜 E₁ E₂).IsInvertible) : + (dfu.implicitFunctionDataOfProdDomain if₂u).pt = u := by + rfl + +@[simp] theorem leftFun_implicitFunctionDataOfProdDomain + (dfu : HasStrictFDerivAt f f'u u) (if₂u : (f'u ∘L .inr 𝕜 E₁ E₂).IsInvertible) : + (dfu.implicitFunctionDataOfProdDomain if₂u).leftFun = f := by + rfl + +@[simp] theorem rightFun_implicitFunctionDataOfProdDomain + (dfu : HasStrictFDerivAt f f'u u) (if₂u : (f'u ∘L .inr 𝕜 E₁ E₂).IsInvertible) : + (dfu.implicitFunctionDataOfProdDomain if₂u).rightFun = Prod.fst := by + rfl + +/-- Implicit function `ψ : E₁ → E₂` associated with the (uncurried) bivariate function +`f : E₁ × E₂ → F` at `u : E₁ × E₂`. -/ +noncomputable def implicitFunctionOfProdDomain + (dfu : HasStrictFDerivAt f f'u u) (if₂u : (f'u ∘L .inr 𝕜 E₁ E₂).IsInvertible) : + E₁ → E₂ := + fun x => ((dfu.implicitFunctionDataOfProdDomain if₂u).implicitFunction (f u) x).2 + +theorem implicitFunctionOfProdDomain_def + {dfu : HasStrictFDerivAt f f'u u} {if₂u : (f'u ∘L .inr 𝕜 E₁ E₂).IsInvertible} : + dfu.implicitFunctionOfProdDomain if₂u = + fun x => ((dfu.implicitFunctionDataOfProdDomain if₂u).implicitFunction (f u) x).2 := by + rfl + +theorem eventually_apply_eq_iff_implicitFunctionOfProdDomain + (dfu : HasStrictFDerivAt f f'u u) (if₂u : (f'u ∘L .inr 𝕜 E₁ E₂).IsInvertible) : + ∀ᶠ v in 𝓝 u, f v = f u ↔ dfu.implicitFunctionOfProdDomain if₂u v.1 = v.2 := by + let φ := dfu.implicitFunctionDataOfProdDomain if₂u + filter_upwards [φ.leftFun_eq_iff_implicitFunction, φ.rightFun_implicitFunction_eq_rightFun] + exact fun v h _ => Iff.trans h ⟨congrArg _, by aesop⟩ + +theorem hasStrictFDerivAt_implicitFunctionOfProdDomain + (dfu : HasStrictFDerivAt f f'u u) (if₂u : (f'u ∘L .inr 𝕜 E₁ E₂).IsInvertible) : + HasStrictFDerivAt (dfu.implicitFunctionOfProdDomain if₂u) + (-(f'u ∘L .inr 𝕜 E₁ E₂).inverse ∘L (f'u ∘L .inl 𝕜 E₁ E₂)) u.1 := by + suffices f'u ∘L (.prod (.id ..) (-(f'u ∘L .inr ..).inverse ∘L (f'u ∘L .inl ..))) = 0 from + ((dfu.implicitFunctionDataOfProdDomain if₂u).hasStrictFDerivAt_implicitFunction _ + (ContinuousLinearMap.fst_comp_prod _ _) this).snd + ext + rw [f'u.comp_apply, ← f'u.comp_inl_add_comp_inr] + simp [map_neg, if₂u] + +theorem tendsto_implicitFunctionOfProdDomain + (dfu : HasStrictFDerivAt f f'u u) (if₂u : (f'u ∘L .inr 𝕜 E₁ E₂).IsInvertible) : + Tendsto (dfu.implicitFunctionOfProdDomain if₂u) (𝓝 u.1) (𝓝 u.2) := by + have := (dfu.hasStrictFDerivAt_implicitFunctionOfProdDomain if₂u).continuousAt.tendsto + rwa [(dfu.eventually_apply_eq_iff_implicitFunctionOfProdDomain if₂u).self_of_nhds.mp rfl] at this + +theorem eventually_apply_implicitFunctionOfProdDomain + (dfu : HasStrictFDerivAt f f'u u) (if₂u : (f'u ∘L .inr 𝕜 E₁ E₂).IsInvertible) : + ∀ᶠ x in 𝓝 u.1, f (x, dfu.implicitFunctionOfProdDomain if₂u x) = f u := by + have hψ := dfu.tendsto_implicitFunctionOfProdDomain if₂u + set ψ := dfu.implicitFunctionOfProdDomain if₂u + suffices ∀ᶠ x in 𝓝 u.1, f (x, ψ x) = f u ↔ ψ x = ψ x by simpa using this + apply Eventually.image_of_prod (r := fun x y => f (x, y) = f u ↔ ψ x = y) hψ + rw [← nhds_prod_eq] + exact dfu.eventually_apply_eq_iff_implicitFunctionOfProdDomain if₂u + +end HasStrictFDerivAt + +end diff --git a/Mathlib/Analysis/Complex/CanonicalDecomposition.lean b/Mathlib/Analysis/Complex/CanonicalDecomposition.lean new file mode 100644 index 00000000000000..fc6a8b84c0c6bc --- /dev/null +++ b/Mathlib/Analysis/Complex/CanonicalDecomposition.lean @@ -0,0 +1,154 @@ +/- +Copyright (c) 2026 Stefan Kebekus. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Stefan Kebekus +-/ +module + +public import Mathlib.Analysis.Meromorphic.FactorizedRational + +/-! +# Canonical Decomposition + +If a function `f` is meromorphic on a compact set `U`, then it has only finitely many zeros and +poles on the disk, and the theorem `MeromorphicOn.extract_zeros_poles` can be used to re-write `f` +as `(∏ᶠ u, (· - u) ^ divisor f U u) • g`, where `g` is analytic without zeros on `U`. In case where +`U` is a disk, one consider a similar decomposition, called *Canonical Decomposition* or *Blaschke +Product* that replaces the factors `(· - u)` by canonical factors that take only values of norm +one on the boundary of the circle. This file introduces the canonical factors. + +See Page 160f of [Lang, *Introduction to Complex Hyperbolic Spaces*][MR886677] for a detailed +discussion. + +TODO: Formulate the canonical decomposition. +-/ + +@[expose] public section + +namespace Complex + +open ComplexConjugate Metric Real + +variable {R : ℝ} {w : ℂ} + +/-! +## Canonical Factors + +Given `R : ℝ` and `w : ℂ`, the Blaschke factor `Blaschke R w : ℂ → ℂ` is meromorphic in normal form, +has a single pole at `w`, no zeros, and takes values of norm one on the circle of radius `R`. +-/ + +/-- +Given `R : ℝ` and `w : ℂ`, the canonical factor is the function +`fun z ↦ (R ^ 2 - (conj w) * z) / (R * (z - w))`. In applications, one will typically consider a +setting where `w ∈ ball 0 R`. +-/ +noncomputable def canonicalFactor (R : ℝ) (w : ℂ) : ℂ → ℂ := + fun z ↦ (R ^ 2 - (conj w) * z) / (R * (z - w)) + +lemma canonicalFactor_def (R : ℝ) (w : ℂ) : + canonicalFactor R w = fun z ↦ (R ^ 2 - (conj w) * z) / (R * (z - w)) := + rfl + +lemma canonicalFactor_apply (R : ℝ) (w z : ℂ) : + canonicalFactor R w z = (R ^ 2 - (conj w) * z) / (R * (z - w)) := + rfl + +@[simp] +lemma canonicalFactor_apply_self (R : ℝ) (w : ℂ) : + canonicalFactor R w w = 0 := by + simp [canonicalFactor_apply] + +/-! +### Regularity properties +-/ + +variable (R w) in +/-- +Canonical factors are meromorphic. +-/ +theorem meromorphicOn_canonicalFactor : MeromorphicOn (canonicalFactor R w) Set.univ := by + intro x hx + unfold canonicalFactor + fun_prop + +open scoped ComplexOrder in +variable (R w) in +/-- +The canonical factor `CanonicalFactor R w` is analytic on the complement of `w`. +-/ +theorem analyticOnNhd_canonicalFactor : AnalyticOnNhd ℂ (canonicalFactor R w) {w}ᶜ := by + intro x hx + rw [canonicalFactor_def] + obtain (rfl | h) := eq_or_ne R 0 + · simpa using analyticAt_const + have : x - w ≠ 0 := by grind + fun_prop (disch := positivity) + +/-- +The canonical factor `CanonicalFactor R w` has a simple pole at `z = w`. +-/ +theorem meromorphicOrderAt_canonicalFactor (h : w ∈ ball 0 R) : + meromorphicOrderAt (canonicalFactor R w) w = -1 := by + unfold canonicalFactor + rw [fun_meromorphicOrderAt_div (by fun_prop) (by fun_prop), + fun_meromorphicOrderAt_mul (by fun_prop) (by fun_prop)] + have : meromorphicOrderAt (fun z ↦ ↑R ^ 2 - (starRingEnd ℂ) w * z) w = 0 := by + refine (MeromorphicNFAt.meromorphicOrderAt_eq_zero_iff ?_).2 ?_ + · apply AnalyticAt.meromorphicNFAt + fun_prop + · rw [← normSq_eq_conj_mul_self, normSq_eq_norm_sq w, sub_ne_zero, ne_eq, ← ofReal_pow, + ofReal_inj, sq_eq_sq₀ (pos_of_mem_ball h).le (norm_nonneg w)] + rw [mem_ball_iff_norm, sub_zero] at h + grind + simp [this, meromorphicOrderAt_const, (pos_of_mem_ball h).ne', + meromorphicOrderAt_id_sub_const] + +/-- +Canonical factors are meromorphic in normal form. +-/ +theorem meromorphicNFOn_canonicalFactor (h : w ∈ ball 0 R) : + MeromorphicNFOn (canonicalFactor R w) Set.univ := by + intro z hz + obtain (rfl | h₁) := eq_or_ne z w + · rw [meromorphicNFAt_iff_analyticAt_or] + right + refine ⟨meromorphicOn_canonicalFactor R z z (Set.mem_univ z), ?_, by simp⟩ + simpa [meromorphicOrderAt_canonicalFactor h] using WithTop.coe_lt_zero.mpr (by lia : -1 < 0) + apply (analyticOnNhd_canonicalFactor R w z h₁).meromorphicNFAt + +/-! +### Values of Canonical Factors +-/ + +open scoped ComplexOrder in +/-- +The canonical factor `CanonicalFactor R w` has no zeros inside the ball of radius `R`. +-/ +theorem canonicalFactor_ne_zero {z : ℂ} (hw : w ∈ ball 0 R) (h₁z : z ∈ closedBall 0 R) + (h₂z : z ≠ w) : + canonicalFactor R w z ≠ 0 := by + obtain ⟨hR, hzw⟩ : 0 < R ∧ z - w ≠ 0 := by grind [mem_ball_zero_iff, norm_nonneg] + simp only [mem_ball, dist_zero_right, mem_closedBall] at hw h₁z + have h_num_ne_zero : R ^ 2 - conj w * z ≠ 0 := by + suffices ‖conj w * z‖ < ‖(R : ℂ) ^ 2‖ by grind + suffices ‖w‖ * ‖z‖ < R * R by simpa [sq] + grw [h₁z] + gcongr + rw [canonicalFactor_apply] + positivity + +open scoped ComplexOrder in +/-- +The canonical factor `CanonicalFactor R w` takes values of norm one on `sphere 0 R`. +-/ +theorem norm_canonicalFactor_eval_circle_eq_one {z : ℂ} (hw : w ∈ ball 0 R) (hz : z ∈ sphere 0 R) : + ‖canonicalFactor R w z‖ = 1 := by + obtain ⟨hR, hzw⟩ : 0 < R ∧ z - w ≠ 0 := by + grind [mem_ball_zero_iff, norm_nonneg, mem_sphere_zero_iff_norm] + rw [canonicalFactor, norm_div, div_eq_iff (by rw [ne_eq, norm_eq_zero]; positivity), one_mul] + obtain rfl := by simpa [mem_sphere_zero_iff_norm] using hz + rw [← ofReal_pow, ← normSq_eq_norm_sq, normSq_eq_conj_mul_self, ← sub_mul, mul_comm _ z] + simp [← map_sub] + +end Complex diff --git a/Mathlib/Analysis/Complex/Harmonic/Poisson.lean b/Mathlib/Analysis/Complex/Harmonic/Poisson.lean new file mode 100644 index 00000000000000..dcfd579844bfe8 --- /dev/null +++ b/Mathlib/Analysis/Complex/Harmonic/Poisson.lean @@ -0,0 +1,111 @@ +/- +Copyright (c) 2026 Stefan Kebekus. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mihai Iancu, Stefan Kebekus, Sebastian Schleissinger, Aristotle AI +-/ +module + +public import Mathlib.Analysis.Complex.Harmonic.MeanValue +public import Mathlib.Analysis.Complex.Poisson + +/-! +# Poisson Integral Formula + +This file establishes several versions of the **Poisson Integral Formula** for harmonic functions on +arbitrary disks in the complex plane, formulated with the real part of the Herglotz–Riesz kernel of +integration and with the Poisson kernel, respectively. + +TODO: Extend this formula to vector-valued harmonic functions +-/ + +public section + +open Complex InnerProductSpace Metric Real Topology + +variable + {f : ℂ → ℝ} {c w : ℂ} {R : ℝ} + +namespace InnerProductSpace + +private lemma continuousOn_herglotz_riesz (_ : w ∈ ball c R) : + ContinuousOn (fun x ↦ ((x - c + (w - c)) / (x - c - (w - c))).re) + {z | ‖z - c‖ ∈ Set.Ioc ‖w - c‖ R} := by + have : ∀ x ∈ {z | ‖z - c‖ ∈ Set.Ioc ‖w - c‖ R}, x - c - (w - c) ≠ 0 := by + grind [mem_ball, mem_sphere] + fun_prop (disch := assumption) + +set_option backward.isDefEq.respectTransparency false in +/-- +**Poisson integral formula** for harmonic functions on arbitrary disks in the complex plane, +formulated with the real part of the Herglotz–Riesz kernel of integration. +-/ +theorem HarmonicOnNhd.circleAverage_re_herglotzRieszKernel_smul + (hf : HarmonicOnNhd f (closedBall c R)) (hw : w ∈ ball c R) : + Real.circleAverage ((re ∘ herglotzRieszKernel c w) • f) c R = f w := by + obtain ⟨e, h₁e, h₂e⟩ := (isCompact_closedBall c R).exists_thickening_subset_open + (isOpen_setOf_harmonicAt f) (by aesop) + rw [thickening_closedBall h₁e (pos_of_mem_ball hw).le] at h₂e + obtain ⟨F, h₁F, h₂F⟩ := HarmonicOnNhd.exists_analyticOnNhd_ball_re_eq h₂e + have h₃F : DifferentiableOn ℂ F (closure (ball c R)) := by + intro x hx + apply (h₁F x _).differentiableWithinAt + grind [mem_ball, mem_closedBall.1 (closure_ball_subset_closedBall hx)] + have h₄F : Set.EqOn (re ∘ herglotzRieszKernel c w • f) + (reCLM ∘ (fun z ↦ ((z - c + (w - c)) / (z - c - (w - c))).re • F z)) + (sphere c R) := by + intro x hx + simp [h₂F (sphere_subset_ball (lt_add_of_pos_left R h₁e) hx), herglotzRieszKernel_def] + rw [← abs_of_pos (pos_of_mem_ball hw)] at h₄F + rw [circleAverage_congr_sphere h₄F, reCLM.circleAverage_comp_comm, + h₃F.diffContOnCl.circleAverage_re_herglotzRieszKernel_smul' hw] + · apply h₂F + grind [mem_ball] + -- CircleIntegrable (fun z ↦ ((z - c + (w - c)) / (z - c - (w - c))).re • F z) c R + apply (ContinuousOn.smul _ _).circleIntegrable' + · apply (continuousOn_herglotz_riesz hw).mono + grind [mem_ball, dist_eq_norm, mem_sphere_iff_norm, (pos_of_mem_ball hw)] + · apply (h₁F.mono _).continuousOn (𝕜 := ℂ) + grind [mem_sphere, mem_ball, (pos_of_mem_ball hw)] + +/-- +**Poisson integral formula** for harmonic functions on arbitrary disks in the complex plane, +formulated with the real part of the Herglotz–Riesz kernel of integration. +-/ +theorem HarmonicContOnCl.circleAverage_re_herglotzRieszKernel_smul + (hf : HarmonicContOnCl f (ball c R)) (hw : w ∈ ball c R) : + Real.circleAverage ((re ∘ herglotzRieszKernel c w) • f) c R = f w := by + apply ContinuousOn.eq_of_eqOn_Ioo (r := ‖w - c‖) + · apply ContinuousOn.circleAverage + · rw [herglotzRieszKernel_fun_def] + apply (continuousOn_herglotz_riesz hw).smul (hf.2.mono _) + grind [closure_ball c (pos_of_mem_ball hw).ne', mem_closedBall_iff_norm] + · simp only [Set.mem_Ioc, and_imp] + grind [norm_nonneg (w - c)] + · grind [mem_ball_iff_norm] + · intro r hr + rw [HarmonicOnNhd.circleAverage_re_herglotzRieszKernel_smul + (hf.1.mono (closedBall_subset_ball hr.2)) (by grind [mem_ball_iff_norm])] + +/-- +**Poisson integral formula** for harmonic functions on arbitrary disks in the complex plane, +formulated with the Poisson kernel of integration. +-/ +theorem HarmonicOnNhd.circleAverage_poissonKernel_smul + (hf : HarmonicOnNhd f (closedBall c R)) (hw : w ∈ ball c R) : + Real.circleAverage (poissonKernel c w • f) c R = f w := by + rw [← hf.circleAverage_re_herglotzRieszKernel_smul hw] + apply circleAverage_congr_sphere + (fun _ _ ↦ by simp_rw [← poissonKernel_eq_re_herglotzRieszKernel]) + +/-- +**Poisson integral formula** for harmonic functions on arbitrary disks in the complex plane, +formulated with the Poisson kernel of integration. +-/ +theorem HarmonicContOnCl.circleAverage_poissonKernel_smul + (hf : HarmonicContOnCl f (ball c R)) (hw : w ∈ ball c R) : + Real.circleAverage (poissonKernel c w • f) c R = f w := by + rw [← hf.circleAverage_re_herglotzRieszKernel_smul hw] + apply circleAverage_congr_sphere + (fun _ _ ↦ by simp_rw [← poissonKernel_eq_re_herglotzRieszKernel]) + +end InnerProductSpace diff --git a/Mathlib/Analysis/Complex/Poisson.lean b/Mathlib/Analysis/Complex/Poisson.lean index 672d854f9353fe..bf466a70df2009 100644 --- a/Mathlib/Analysis/Complex/Poisson.lean +++ b/Mathlib/Analysis/Complex/Poisson.lean @@ -39,6 +39,11 @@ noncomputable def herglotzRieszKernel (c w z : ℂ) : ℂ := lemma herglotzRieszKernel_def (c w z : ℂ) : herglotzRieszKernel c w z = ((z - c) + (w - c)) / ((z - c) - (w - c)) := by rfl +lemma herglotzRieszKernel_fun_def (c w : ℂ) : + herglotzRieszKernel c w = fun z ↦ ((z - c) + (w - c)) / ((z - c) - (w - c)) := by + ext z + exact herglotzRieszKernel_def c w z + /-- The Poisson kernel of integration. -/ diff --git a/Mathlib/Analysis/Convex/Approximation.lean b/Mathlib/Analysis/Convex/Approximation.lean index a31077d88be9a7..9f68e0c068603e 100644 --- a/Mathlib/Analysis/Convex/Approximation.lean +++ b/Mathlib/Analysis/Convex/Approximation.lean @@ -111,7 +111,8 @@ theorem sSup_affine_eq (hsc : IsClosed s) theorem sSup_of_countable_affine_eq [HereditarilyLindelofSpace E] (hsc : IsClosed s) (hφc : LowerSemicontinuousOn φ s) (hφcv : ConvexOn ℝ s φ) : ∃ 𝓕' : Set (s → ℝ), 𝓕'.Countable ∧ sSup 𝓕' = s.restrict φ ∧ - ∀ f ∈ 𝓕', ∃ (l : E →L[𝕜] 𝕜) (c : ℝ), f = s.restrict (re ∘ l) + const s c := by + ∀ f ∈ 𝓕', f ≤ s.restrict φ ∧ + ∃ (l : E →L[𝕜] 𝕜) (c : ℝ), f = s.restrict (re ∘ l) + const s c := by by_cases! hs : s.Nonempty · let 𝓕 := {f | f ≤ s.restrict φ ∧ ∃ (l : E →L[𝕜] 𝕜) (c : ℝ), f = s.restrict (re ∘ l) + const s c} @@ -123,9 +124,9 @@ theorem sSup_of_countable_affine_eq [HereditarilyLindelofSpace E] (hsc : IsClose · exact (bddAbove_def.2 ⟨φ ∘ Subtype.val, fun y hy => hy.1⟩) have hr (f) (hf : f ∈ 𝓕) : LowerSemicontinuous f := by obtain ⟨l, c, hlc⟩ := hf.2 - exact Continuous.lowerSemicontinuous (hlc ▸ Continuous.add (by fun_prop) (by fun_prop)) + exact Continuous.lowerSemicontinuous (hlc ▸ by fun_prop) obtain ⟨𝓕', h𝓕'⟩ := exists_countable_lowerSemicontinuous_isLUB hr hl - refine ⟨𝓕', h𝓕'.2.1, h𝓕'.2.2.csSup_eq ?_, fun f hf => (h𝓕'.1 hf).2⟩ + refine ⟨𝓕', h𝓕'.2.1, h𝓕'.2.2.csSup_eq ?_, fun f hf => h𝓕'.1 hf⟩ by_contra! grind [(isLUB_empty_iff.1 (this ▸ h𝓕'.2.2)) (fun x : s => φ x - 1) ⟨hs.some, hs.some_mem⟩] · use ∅; simp [restrict_def]; grind @@ -134,21 +135,22 @@ theorem sSup_of_countable_affine_eq [HereditarilyLindelofSpace E] (hsc : IsClose theorem sSup_of_nat_affine_eq [HereditarilyLindelofSpace E] (hsc : IsClosed s) (hφc : LowerSemicontinuousOn φ s) (hφcv : ConvexOn ℝ s φ) : ∃ (l : ℕ → E →L[𝕜] 𝕜) (c : ℕ → ℝ), + (∀ i, s.restrict (re ∘ (l i)) + const s (c i) ≤ s.restrict φ) ∧ ⨆ i, s.restrict (re ∘ (l i)) + const s (c i) = s.restrict φ := by obtain ⟨𝓕', h𝓕'⟩ := hφcv.sSup_of_countable_affine_eq (𝕜 := 𝕜) hsc hφc by_cases! he : 𝓕'.Nonempty · obtain ⟨f, hf⟩ := h𝓕'.1.exists_eq_range he have (i : ℕ) : ∃ (l : E →L[𝕜] 𝕜) (c : ℝ), f i = s.restrict (re ∘ l) + const s c := by simp_all choose l c hlc using this - refine ⟨l, c, ?_⟩ + refine ⟨l, c, fun i => (hlc i) ▸ (h𝓕'.2.2 (f i) (hf ▸ mem_range_self i)).1, ?_⟩ calc _ = ⨆ i, f i := by congr with i x; exact congrFun (hlc i).symm x _ = _ := by rw [← sSup_range, ← hf, h𝓕'.2.1] · by_cases! hsφ : s.restrict φ = 0 - · refine ⟨fun _ => 0, fun _ => 0, ?_⟩ - ext x - have := congrFun hsφ x - simp_all + · have := congrFun hsφ + refine ⟨fun _ => 0, fun _ => 0, ?_, ?_⟩ + · simp_all [restrict_def] + · ext; simp_all · obtain ⟨x, hx⟩ := Function.ne_iff.1 hsφ have : s = ∅ := by have := congrFun h𝓕'.2.1 x; simp_all grind @@ -180,7 +182,7 @@ theorem univ_sSup_affine_eq (hφc : LowerSemicontinuous φ) (hφcv : ConvexOn theorem univ_sSup_of_countable_affine_eq [HereditarilyLindelofSpace E] (hφc : LowerSemicontinuous φ) (hφcv : ConvexOn ℝ univ φ) : ∃ 𝓕' : Set (E → ℝ), 𝓕'.Countable ∧ sSup 𝓕' = φ ∧ - ∀ f ∈ 𝓕', ∃ (l : E →L[𝕜] 𝕜) (c : ℝ), f = (re ∘ l) + const E c := by + ∀ f ∈ 𝓕', f ≤ φ ∧ ∃ (l : E →L[𝕜] 𝕜) (c : ℝ), f = (re ∘ l) + const E c := by let 𝓕 := {f | f ≤ φ ∧ ∃ (l : E →L[𝕜] 𝕜) (c : ℝ), f = (re ∘ l) + const E c} have hl : IsLUB 𝓕 φ := by refine (hφcv.univ_sSup_affine_eq (𝕜 := 𝕜) hφc) ▸ isLUB_csSup ?_ ?_ @@ -193,26 +195,28 @@ theorem univ_sSup_of_countable_affine_eq [HereditarilyLindelofSpace E] obtain ⟨l, c, hlc⟩ := hf.2 exact Continuous.lowerSemicontinuous (by rw [hlc]; fun_prop) obtain ⟨𝓕', h𝓕'⟩ := exists_countable_lowerSemicontinuous_isLUB hr hl - refine ⟨𝓕', h𝓕'.2.1, h𝓕'.2.2.csSup_eq ?_, fun f hf => (h𝓕'.1 hf).2⟩ + refine ⟨𝓕', h𝓕'.2.1, h𝓕'.2.2.csSup_eq ?_, fun f hf => h𝓕'.1 hf⟩ by_contra! grind [(isLUB_empty_iff.1 (this ▸ h𝓕'.2.2)) (fun x => φ x - 1) 0] /-- The sequential version of `univ_sSup_of_countable_affine_eq`. -/ theorem univ_sSup_of_nat_affine_eq [HereditarilyLindelofSpace E] (hφc : LowerSemicontinuous φ) (hφcv : ConvexOn ℝ univ φ) : - ∃ (l : ℕ → E →L[𝕜] 𝕜) (c : ℕ → ℝ), ⨆ i, re ∘ (l i) + const E (c i) = φ := by + ∃ (l : ℕ → E →L[𝕜] 𝕜) (c : ℕ → ℝ), (∀ i, re ∘ (l i) + const E (c i) ≤ φ) + ∧ ⨆ i, re ∘ (l i) + const E (c i) = φ := by obtain ⟨𝓕', h𝓕'⟩ := hφcv.univ_sSup_of_countable_affine_eq (𝕜 := 𝕜) hφc by_cases! he : 𝓕'.Nonempty · obtain ⟨f, hf⟩ := h𝓕'.1.exists_eq_range he have (i : ℕ) : ∃ (l : E →L[𝕜] 𝕜) (c : ℝ), f i = re ∘ l + const E c := by simp_all choose l c hlc using this - refine ⟨l, c, ?_⟩ + refine ⟨l, c, fun i => (hlc i) ▸ (h𝓕'.2.2 (f i) (hf ▸ mem_range_self i)).1, ?_⟩ calc _ = ⨆ i, f i := by congr with i x; exact congrFun (hlc i).symm x _ = _ := by rw [← sSup_range, ← hf, h𝓕'.2.1] - · refine ⟨fun _ => 0, fun _ => 0, ?_⟩ - ext x - simp_all [← congrFun h𝓕'.2.1 x] + · refine ⟨fun _ => 0, fun _ => 0, fun i x => ?_, ?_⟩ + · simp_all [← congrFun h𝓕'.2.1 x] + · ext x + simp_all [← congrFun h𝓕'.2.1 x] end RCLike @@ -232,13 +236,14 @@ theorem real_sSup_affine_eq (hsc : IsClosed s) theorem real_sSup_of_countable_affine_eq [HereditarilyLindelofSpace E] (hsc : IsClosed s) (hφc : LowerSemicontinuousOn φ s) (hφcv : ConvexOn ℝ s φ) : ∃ 𝓕' : Set (s → ℝ), 𝓕'.Countable ∧ sSup 𝓕' = s.restrict φ ∧ - ∀ f ∈ 𝓕', ∃ (l : E →L[ℝ] ℝ) (c : ℝ), f = s.restrict l + const s c := + ∀ f ∈ 𝓕', f ≤ s.restrict φ ∧ ∃ (l : E →L[ℝ] ℝ) (c : ℝ), f = s.restrict l + const s c := sSup_of_countable_affine_eq (𝕜 := ℝ) hsc hφc hφcv /-- The real version of `sSup_of_nat_affine_eq`. -/ theorem real_sSup_of_nat_affine_eq [HereditarilyLindelofSpace E] (hsc : IsClosed s) (hφc : LowerSemicontinuousOn φ s) (hφcv : ConvexOn ℝ s φ) : ∃ (l : ℕ → E →L[ℝ] ℝ) (c : ℕ → ℝ), + (∀ i, s.restrict (l i) + const s (c i) ≤ s.restrict φ) ∧ ⨆ i, s.restrict (l i) + const s (c i) = s.restrict φ := sSup_of_nat_affine_eq (𝕜 := ℝ) hsc hφc hφcv @@ -251,13 +256,14 @@ theorem real_univ_sSup_affine_eq (hφc : LowerSemicontinuous φ) (hφcv : Convex theorem real_univ_sSup_of_countable_affine_eq [HereditarilyLindelofSpace E] (hφc : LowerSemicontinuous φ) (hφcv : ConvexOn ℝ univ φ) : ∃ 𝓕' : Set (E → ℝ), 𝓕'.Countable ∧ sSup 𝓕' = φ ∧ - ∀ f ∈ 𝓕', ∃ (l : E →L[ℝ] ℝ) (c : ℝ), f = l + const E c := + ∀ f ∈ 𝓕', f ≤ φ ∧ ∃ (l : E →L[ℝ] ℝ) (c : ℝ), f = l + const E c := univ_sSup_of_countable_affine_eq (𝕜 := ℝ) hφc hφcv /-- The real version of `univ_sSup_of_nat_affine_eq`. -/ theorem real_univ_sSup_of_nat_affine_eq [HereditarilyLindelofSpace E] (hφc : LowerSemicontinuous φ) (hφcv : ConvexOn ℝ univ φ) : - ∃ (l : ℕ → E →L[ℝ] ℝ) (c : ℕ → ℝ), ⨆ i, (l i) + const E (c i) = φ := + ∃ (l : ℕ → E →L[ℝ] ℝ) (c : ℕ → ℝ), (∀ i, (l i) + const E (c i) ≤ φ) ∧ + ⨆ i, (l i) + const E (c i) = φ := univ_sSup_of_nat_affine_eq (𝕜 := ℝ) hφc hφcv end Real diff --git a/Mathlib/Analysis/Convex/Extreme.lean b/Mathlib/Analysis/Convex/Extreme.lean index f6dd736b7cec4a..ae6d59e33d3263 100644 --- a/Mathlib/Analysis/Convex/Extreme.lean +++ b/Mathlib/Analysis/Convex/Extreme.lean @@ -174,6 +174,10 @@ theorem IsExtreme.extremePoints_eq (hAB : IsExtreme 𝕜 A B) : Subset.antisymm (fun _ hx ↦ ⟨hx.1, hAB.extremePoints_subset_extremePoints hx⟩) (inter_extremePoints_subset_extremePoints_of_subset hAB.1) +@[nontriviality] +lemma Set.extremePoints_eq_self [Subsingleton E] (A : Set E) : Set.extremePoints 𝕜 A = A := + subset_antisymm extremePoints_subset fun _ h ↦ ⟨h, fun _ _ _ _ _ ↦ Subsingleton.elim ..⟩ + end SMul section OrderedSemiring diff --git a/Mathlib/Analysis/Convex/PathConnected.lean b/Mathlib/Analysis/Convex/PathConnected.lean index eeb3a45808390a..6bf7f083e46a07 100644 --- a/Mathlib/Analysis/Convex/PathConnected.lean +++ b/Mathlib/Analysis/Convex/PathConnected.lean @@ -34,7 +34,7 @@ namespace Path @[simps] protected def segment (a b : E) : Path a b where toFun t := lineMap a b (t : ℝ) - continuous_toFun := by unfold lineMap; continuity + continuous_toFun := by dsimp [lineMap]; fun_prop source' := by simp target' := by simp diff --git a/Mathlib/Analysis/Convex/Strict/Extreme.lean b/Mathlib/Analysis/Convex/Strict/Extreme.lean index 194c8dc5ddede5..cfb52e39e1db4a 100644 --- a/Mathlib/Analysis/Convex/Strict/Extreme.lean +++ b/Mathlib/Analysis/Convex/Strict/Extreme.lean @@ -84,3 +84,8 @@ theorem StrictConvexSpace.extremePoints_closedBall_eq_sphere [Nontrivial A] {x : closedBall_diff_ball] end Normed + +@[simp] lemma Set.extremePoints_Icc {a b : ℝ} (hab : a ≤ b) : + extremePoints ℝ (Icc a b) = {a, b} := by + rw [Real.Icc_eq_closedBall, StrictConvexSpace.extremePoints_closedBall_eq_sphere] + grind [Real.sphere_eq_pair] diff --git a/Mathlib/Analysis/Convex/StrictConvexSpace.lean b/Mathlib/Analysis/Convex/StrictConvexSpace.lean index ebfddc691e2c91..181e5c66a92501 100644 --- a/Mathlib/Analysis/Convex/StrictConvexSpace.lean +++ b/Mathlib/Analysis/Convex/StrictConvexSpace.lean @@ -212,3 +212,6 @@ theorem norm_midpoint_lt_iff (h : ‖x‖ = ‖y‖) : ‖(1 / 2 : ℝ) • (x + rw [norm_smul, Real.norm_of_nonneg (one_div_nonneg.2 zero_le_two), ← inv_eq_one_div, ← div_eq_inv_mul, div_lt_iff₀ (zero_lt_two' ℝ), mul_two, ← not_sameRay_iff_of_norm_eq h, not_sameRay_iff_norm_add_lt, h] + +instance Real.instStrictConvexSpace : StrictConvexSpace ℝ ℝ where + strictConvex_closedBall _ _ := strictConvex_iff_convex.mpr (convex_closedBall _ _) diff --git a/Mathlib/Analysis/Distribution/ContDiffMapSupportedIn.lean b/Mathlib/Analysis/Distribution/ContDiffMapSupportedIn.lean index 1403f4a7347691..8028e8bd6c8e25 100644 --- a/Mathlib/Analysis/Distribution/ContDiffMapSupportedIn.lean +++ b/Mathlib/Analysis/Distribution/ContDiffMapSupportedIn.lean @@ -89,7 +89,7 @@ variable (𝕜 E F F' : Type*) [NontriviallyNormedField 𝕜] [NormedAddCommGroup E] [NormedSpace ℝ E] [NormedAddCommGroup F] [NormedSpace ℝ F] [NormedSpace 𝕜 F] [SMulCommClass ℝ 𝕜 F] [NormedAddCommGroup F'] [NormedSpace ℝ F'] [NormedSpace 𝕜 F'] [SMulCommClass ℝ 𝕜 F'] - {n k : ℕ∞} {K : Compacts E} + {n n₁ n₂ k : ℕ∞} {K K₁ K₂ : Compacts E} /-- The type of bundled `n`-times continuously differentiable maps which vanish outside of a fixed compact set `K`. -/ @@ -321,6 +321,43 @@ lemma postcompLM_apply [LinearMap.CompatibleSMul F F' ℝ 𝕜] (T : F →L[𝕜 postcompLM T f = T ∘ f := rfl +open scoped Classical in +/-- If `n₁ ≥ n₂` and `K₁ ⊆ K₂`, `monoLM 𝕜` is the `𝕜`-linear inclusion of +`𝓓^{n₁}_{K₁}(E, F)` inside `𝓓^{n₂}_{K₂}(E, F)`. Otherwise, this is the zero map. + +This is in fact continuous (see `monoCLM`). Furthermore: +* it is a topological embedding when `n₁ = n₂` and `K₁ ⊆ K₂` (not in Mathlib as of March 2026). +* it maps bounded sets to compact sets when `n₁ ≥ n₂ + 1` and `K₁ ⊆ K₂` (not in Mathlib as of +March 2026). + +The parameters `n₁, n₂, K₁, K₂` are implicit as they can often be inferred from context, or +specified by a type ascription. +-/ +noncomputable def monoLM : + 𝓓^{n₁}_{K₁}(E, F) →ₗ[𝕜] 𝓓^{n₂}_{K₂}(E, F) where + toFun f := + if h : n₂ ≤ n₁ ∧ K₁ ≤ K₂ then + .of_support_subset (f.contDiff.of_le (mod_cast h.1)) (f.support_subset.trans h.2) + else 0 + map_add' f g := by split_ifs <;> ext <;> simp + map_smul' c f := by split_ifs <;> ext <;> simp + +open scoped Classical in +@[simp] +lemma monoLM_apply (f : 𝓓^{n₁}_{K₁}(E, F)) : + ((monoLM 𝕜 f : 𝓓^{n₂}_{K₂}(E, F)) : E → F) = if n₂ ≤ n₁ ∧ K₁ ≤ K₂ then f else 0 := by + rw [monoLM] + split_ifs <;> rfl + +lemma monoLM_eq_zero (H : ¬ (n₂ ≤ n₁ ∧ K₁ ≤ K₂)) : + (monoLM 𝕜 : 𝓓^{n₁}_{K₁}(E, F) →ₗ[𝕜] 𝓓^{n₂}_{K₂}(E, F)) = 0 := by + ext; simp [H] + +lemma monoLM_eq_of_scalars (𝕜' : Type*) + [NontriviallyNormedField 𝕜'] [NormedSpace 𝕜' F] [SMulCommClass ℝ 𝕜' F] : + (monoLM 𝕜 : 𝓓^{n₁}_{K₁}(E, F) → 𝓓^{n₂}_{K₂}(E, F)) = monoLM 𝕜' := + rfl + variable (n k) in /-- `fderivLM 𝕜 n k` is the `𝕜`-linear-map sending `f : 𝓓^{n}_{K}(E, F)` to its derivative as an element of `𝓓^{k}_{K}(E, E →L[ℝ] F)`. @@ -723,6 +760,54 @@ lemma postcompCLM_apply [LinearMap.CompatibleSMul F F' ℝ 𝕜] (T : F →L[ postcompCLM T f = T ∘ f := rfl +theorem seminorm_monoLM_le {i : ℕ} (f : 𝓓^{n₁}_{K₁}(E, F)) : + N[𝕜]_{K₂, n₂, i} (monoLM 𝕜 f) ≤ N[𝕜]_{K₁, n₁, i} f := by + by_cases H : n₂ ≤ n₁ ∧ K₁ ≤ K₂ + · simp (discharger := positivity) only [ContDiffMapSupportedIn.seminorm_le_iff, monoLM_apply, H, + and_self, ↓reduceIte] + intro hik _ _ + exact norm_iteratedFDeriv_apply_le_seminorm _ (hik.trans (mod_cast H.1)) + · simp [monoLM_eq_zero, H] + +theorem seminorm_monoLM_eq {i : ℕ} (h₁ : n₁ = n₂) (h₂ : K₁ ≤ K₂) (f : 𝓓^{n₁}_{K₁}(E, F)) : + N[𝕜]_{K₂, n₂, i} (monoLM 𝕜 f) = N[𝕜]_{K₁, n₁, i} f := by + simp [BoundedContinuousFunction.norm_eq_iSup_norm, ContDiffMapSupportedIn.seminorm_apply, + structureMapCLM_apply, h₁, h₂] + +/-- If `n₁ ≥ n₂` and `K₁ ⊆ K₂`, `monoCLM 𝕜` is the continuous `𝕜`-linear inclusion of +`𝓓^{n₁}_{K₁}(E, F)` inside `𝓓^{n₂}_{K₂}(E, F)`. Otherwise, this is the zero map. + +Furthermore: +* it is a topological embedding when `n₁ = n₂` and `K₁ ⊆ K₂` (not in Mathlib as of March 2026). +* it maps bounded sets to compact sets when `n₁ ≥ n₂ + 1` and `K₁ ⊆ K₂` (not in Mathlib as of +March 2026). + +The parameters `n₁, n₂, K₁, K₂` are implicit as they can often be inferred from context, or +specified by a type ascription. +-/ +noncomputable def monoCLM : + 𝓓^{n₁}_{K₁}(E, F) →L[𝕜] 𝓓^{n₂}_{K₂}(E, F) where + toLinearMap := monoLM 𝕜 + cont := show Continuous (monoLM 𝕜) by + refine continuous_of_isBounded (ContDiffMapSupportedIn.withSeminorms _ _ _ _ _) + (ContDiffMapSupportedIn.withSeminorms _ _ _ _ _) _ (fun i ↦ ⟨{i}, 1, fun f ↦ ?_⟩) + simpa using seminorm_monoLM_le 𝕜 f + +open scoped Classical in +@[simp] +lemma monoCLM_apply (f : 𝓓^{n₁}_{K₁}(E, F)) : + ((monoCLM 𝕜 f : 𝓓^{n₂}_{K₂}(E, F)) : E → F) = if n₂ ≤ n₁ ∧ K₁ ≤ K₂ then f else 0 := + monoLM_apply 𝕜 f + +lemma monoCLM_eq_zero (H : ¬ (n₂ ≤ n₁ ∧ K₁ ≤ K₂)) : + (monoCLM 𝕜 : 𝓓^{n₁}_{K₁}(E, F) →L[𝕜] 𝓓^{n₂}_{K₂}(E, F)) = 0 := by + ext; simp [H] + +lemma monoCLM_eq_of_scalars (𝕜' : Type*) + [NontriviallyNormedField 𝕜'] [NormedSpace 𝕜' F] [SMulCommClass ℝ 𝕜' F] : + (monoCLM 𝕜 : 𝓓^{n₁}_{K₁}(E, F) → 𝓓^{n₂}_{K₂}(E, F)) = monoCLM 𝕜' := + rfl + theorem seminorm_fderivLM_le {i : ℕ} (f : 𝓓^{n}_{K}(E, F)) : N[𝕜]_{K, k, i} (fderivLM 𝕜 n k f) ≤ N[𝕜]_{K, n, i+1} f := by by_cases! hk : k + 1 ≤ n diff --git a/Mathlib/Analysis/Distribution/TestFunction.lean b/Mathlib/Analysis/Distribution/TestFunction.lean index 2d3a867065daaa..c62e71944e88a4 100644 --- a/Mathlib/Analysis/Distribution/TestFunction.lean +++ b/Mathlib/Analysis/Distribution/TestFunction.lean @@ -52,13 +52,13 @@ distributions, test function @[expose] public section open Function Seminorm SeminormFamily Set TopologicalSpace UniformSpace -open scoped BoundedContinuousFunction NNReal Topology +open scoped BoundedContinuousFunction NNReal Topology ContDiff variable {𝕜 𝕂 : Type*} [NontriviallyNormedField 𝕜] - {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] {Ω : Opens E} + {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] {Ω Ω₁ Ω₂ : Opens E} {F : Type*} [NormedAddCommGroup F] [NormedSpace ℝ F] [NormedSpace 𝕜 F] {F' : Type*} [NormedAddCommGroup F'] [NormedSpace ℝ F'] [NormedSpace 𝕜 F'] - {n : ℕ∞} + {n n₁ n₂ k : ℕ∞} variable (Ω F n) in /-- The type of bundled `n`-times continuously differentiable maps with compact support -/ @@ -435,4 +435,98 @@ lemma postcompCLM_apply (T : F →L[𝕜] F') end postcomp +section Monotone + +variable [Algebra ℝ 𝕜] [IsScalarTower ℝ 𝕜 F] + +variable (𝕜) in +/-- If `n₁ ≥ n₂` and `Ω₁ ⊆ Ω₂`, `monoCLM 𝕜` is the continuous `𝕜`-linear inclusion of +`𝓓^{n₁}(Ω₁, F)` inside `𝓓^{n₂}(Ω₂, F)`. Otherwise, this is the zero map. + +This is in fact a topological embedding when `n₁ = n₂` and `Ω₁ ⊆ Ω₂` (not in Mathlib as of +March 2026). + +The parameters `n₁, n₂, Ω₁, Ω₂` are implicit as they can often be inferred from context, or +specified by a type ascription. -/ +noncomputable def monoCLM : + 𝓓^{n₁}(Ω₁, F) →L[𝕜] 𝓓^{n₂}(Ω₂, F) := + open scoped Classical in + letI Φ (f : 𝓓^{n₁}(Ω₁, F)) : 𝓓^{n₂}(Ω₂, F) := + if h : n₂ ≤ n₁ ∧ Ω₁ ≤ Ω₂ then + ⟨f, f.contDiff.of_le (mod_cast h.1), f.hasCompactSupport, f.tsupport_subset.trans h.2⟩ + else 0 + TestFunction.limitCLM 𝕜 Φ + (fun K K_sub_Ω₁ ↦ if h : n₂ ≤ n₁ ∧ Ω₁ ≤ Ω₂ + then ofSupportedInCLM 𝕜 (K_sub_Ω₁.trans h.2) ∘L ContDiffMapSupportedIn.monoCLM 𝕜 + else 0) + (fun _ _ _ ↦ by ext; dsimp [Φ]; split_ifs with h <;> simp [h]) + +open scoped Classical in +@[simp] +lemma monoCLM_apply (f : 𝓓^{n₁}(Ω₁, F)) : + ((monoCLM 𝕜 f : 𝓓^{n₂}(Ω₂, F)) : E → F) = if n₂ ≤ n₁ ∧ Ω₁ ≤ Ω₂ then f else 0 := by + rw [monoCLM] + split_ifs <;> rfl + +lemma monoCLM_eq_zero (H : ¬ (n₂ ≤ n₁ ∧ Ω₁ ≤ Ω₂)) : + (monoCLM 𝕜 : 𝓓^{n₁}(Ω₁, F) →L[𝕜] 𝓓^{n₂}(Ω₂, F)) = 0 := by + ext; simp [H] + +lemma monoCLM_eq_of_scalars (𝕜' : Type*) + [NontriviallyNormedField 𝕜'] [NormedSpace 𝕜' F] [Algebra ℝ 𝕜'] [IsScalarTower ℝ 𝕜' F] : + (monoCLM 𝕜 : 𝓓^{n₁}(Ω₁, F) → 𝓓^{n₂}(Ω₂, F)) = monoCLM 𝕜' := + rfl + +end Monotone + +section FDerivCLM + +variable [Algebra ℝ 𝕜] [IsScalarTower ℝ 𝕜 F] + +variable (𝕜 n k) in +/-- `fderivCLM 𝕜 n k` is the continuous `𝕜`-linear-map sending `f : 𝓓^{n}_{K}(E, F)` to +its derivative as an element of `𝓓^{k}_{K}(E, E →L[ℝ] F)`. +This only makes mathematical sense if `k + 1 ≤ n`, otherwise we define it as the zero map. -/ +noncomputable def fderivCLM : + 𝓓^{n}(Ω, F) →L[𝕜] 𝓓^{k}(Ω, E →L[ℝ] F) := + letI Φ (f : 𝓓^{n}(Ω, F)) : 𝓓^{k}(Ω, E →L[ℝ] F) := + if hk : k + 1 ≤ n then + ⟨fderiv ℝ f, f.contDiff.fderiv_right (mod_cast hk), + f.hasCompactSupport.fderiv ℝ, tsupport_fderiv_subset ℝ |>.trans f.tsupport_subset⟩ + else 0 + TestFunction.limitCLM 𝕜 Φ + (fun K K_sub_Ω ↦ ofSupportedInCLM 𝕜 K_sub_Ω ∘L ContDiffMapSupportedIn.fderivCLM 𝕜 n k) + (fun _ _ _ ↦ by ext; dsimp [Φ]; split_ifs with h <;> simp [h]) + +@[simp] +lemma fderivCLM_apply (f : 𝓓^{n}(Ω, F)) : + fderivCLM 𝕜 n k f = if k + 1 ≤ n then fderiv ℝ f else 0 := by + rw [fderivCLM] + split_ifs <;> rfl + +lemma fderivCLM_apply_of_le (f : 𝓓^{n}(Ω, F)) (hk : k + 1 ≤ n) : + fderivCLM 𝕜 n k f = fderiv ℝ f := by + simp [hk] + +lemma fderivCLM_apply_of_gt (f : 𝓓^{n}(Ω, F)) (hk : n < k + 1) : + fderivCLM 𝕜 n k f = 0 := by + ext : 1 + simp [not_le_of_gt hk] + +variable (𝕜) in +lemma fderivCLM_ofSupportedIn {K : Compacts E} + (K_sub_Ω : (K : Set E) ⊆ Ω) (f : 𝓓^{n}_{K}(E, F)) : + fderivCLM 𝕜 n k (ofSupportedIn K_sub_Ω f) = + ofSupportedIn K_sub_Ω (ContDiffMapSupportedIn.fderivCLM 𝕜 n k f) := by + ext + simp + +variable (𝕜) in +lemma fderivCLM_eq_of_scalars (𝕜' : Type*) + [NontriviallyNormedField 𝕜'] [NormedSpace 𝕜' F] [Algebra ℝ 𝕜'] [IsScalarTower ℝ 𝕜' F] : + (fderivCLM 𝕜 n k : 𝓓^{n}(Ω, F) → _) = fderivCLM 𝕜' n k := + rfl + +end FDerivCLM + end TestFunction diff --git a/Mathlib/Analysis/Fourier/AddCircleMulti.lean b/Mathlib/Analysis/Fourier/AddCircleMulti.lean index bcbf82a8662228..202ee01c093996 100644 --- a/Mathlib/Analysis/Fourier/AddCircleMulti.lean +++ b/Mathlib/Analysis/Fourier/AddCircleMulti.lean @@ -254,7 +254,7 @@ variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] def mFourierCoeff (f : UnitAddTorus d → E) (n : d → ℤ) : E := ∫ t, mFourier (-n) t • f t /-- The Fourier coefficients of a function on `UnitAddTorus d` can be computed as integrals -over `∏ i, (aᵢ, aᵢ + 1]`, for any real `a`. -/ +over `∏ i, (aᵢ, aᵢ + 1]`, for any `a : d → ℝ`. -/ theorem mFourierCoeff_eq_integral (f : UnitAddTorus d → E) (n : d → ℤ) (a : d → ℝ) : mFourierCoeff f n = ∫ (x : d → ℝ) in {x : d → ℝ | ∀ i, x i ∈ Ioc (a i) (a i + 1)}, diff --git a/Mathlib/Analysis/InnerProductSpace/PiL2.lean b/Mathlib/Analysis/InnerProductSpace/PiL2.lean index addcd7aa6b2af2..1809daf0493b8b 100644 --- a/Mathlib/Analysis/InnerProductSpace/PiL2.lean +++ b/Mathlib/Analysis/InnerProductSpace/PiL2.lean @@ -223,6 +223,7 @@ def restrict₂ (hIJ : I ⊆ J) : toFun x := toLp 2 (Finset.restrict₂ («π» := fun _ ↦ 𝕜) hIJ x.ofLp) map_add' x y := by ext; simp map_smul' m x := by ext; simp + cont := Continuous.comp' (by fun_prop) (continuous_pi (by dsimp; fun_prop)) @[simp] lemma restrict₂_apply (hIJ : I ⊆ J) (x : EuclideanSpace 𝕜 J) (i : I) : @@ -288,25 +289,26 @@ section DecEq variable [DecidableEq ι] --- TODO : This should be generalized to `PiLp`. /-- The vector given in Euclidean space by being `a : 𝕜` at coordinate `i : ι` and `0 : 𝕜` at all other coordinates. -/ -def EuclideanSpace.single (i : ι) (a : 𝕜) : EuclideanSpace 𝕜 ι := - toLp _ (Pi.single i a) +abbrev EuclideanSpace.single (i : ι) (a : 𝕜) : EuclideanSpace 𝕜 ι := PiLp.single 2 i a -@[simp] lemma EuclideanSpace.ofLp_single (i : ι) (a : 𝕜) : ofLp (single i a) = Pi.single i a := rfl +@[deprecated PiLp.ofLp_single (since := "2026-03-15")] +lemma EuclideanSpace.ofLp_single (i : ι) (a : 𝕜) : ofLp (single i a) = Pi.single i a := by + simp -@[simp] -lemma EuclideanSpace.toLp_single (i : ι) (a : 𝕜) : toLp _ (Pi.single i a) = single i a := rfl +@[deprecated PiLp.toLp_single (since := "2026-03-15")] +lemma EuclideanSpace.toLp_single (i : ι) (a : 𝕜) : toLp _ (Pi.single i a) = single i a := by + simp -@[simp] +@[deprecated PiLp.single_apply (since := "2026-03-15")] theorem EuclideanSpace.single_apply (i : ι) (a : 𝕜) (j : ι) : (EuclideanSpace.single i a) j = ite (j = i) a 0 := by - rw [EuclideanSpace.single, PiLp.toLp_apply, ← Pi.single_apply i a j] + simp -@[simp] +@[deprecated PiLp.single_eq_zero_iff (since := "2026-03-15")] theorem EuclideanSpace.single_eq_zero_iff {i : ι} {a : 𝕜} : - EuclideanSpace.single i a = 0 ↔ a = 0 := (toLp_eq_zero 2).trans Pi.single_eq_zero_iff + EuclideanSpace.single i a = 0 ↔ a = 0 := by simp variable [Fintype ι] @@ -317,36 +319,34 @@ theorem EuclideanSpace.inner_single_left (i : ι) (a : 𝕜) (v : EuclideanSpace theorem EuclideanSpace.inner_single_right (i : ι) (a : 𝕜) (v : EuclideanSpace 𝕜 ι) : ⟪v, EuclideanSpace.single i (a : 𝕜)⟫ = a * conj (v i) := by simp [PiLp.inner_apply] -@[simp] +@[deprecated PiLp.norm_single (since := "2026-03-15")] theorem EuclideanSpace.norm_single (i : ι) (a : 𝕜) : - ‖EuclideanSpace.single i (a : 𝕜)‖ = ‖a‖ := - PiLp.norm_toLp_single 2 (fun _ => 𝕜) i a + ‖EuclideanSpace.single i (a : 𝕜)‖ = ‖a‖ := by simp -@[simp] +@[deprecated PiLp.nnnorm_single (since := "2026-03-15")] theorem EuclideanSpace.nnnorm_single (i : ι) (a : 𝕜) : - ‖EuclideanSpace.single i (a : 𝕜)‖₊ = ‖a‖₊ := - PiLp.nnnorm_toLp_single 2 (fun _ => 𝕜) i a + ‖EuclideanSpace.single i (a : 𝕜)‖₊ = ‖a‖₊ := by simp -@[simp] +@[deprecated PiLp.dist_single_same (since := "2026-03-15")] theorem EuclideanSpace.dist_single_same (i : ι) (a b : 𝕜) : - dist (EuclideanSpace.single i (a : 𝕜)) (EuclideanSpace.single i (b : 𝕜)) = dist a b := - PiLp.dist_toLp_single_same 2 (fun _ => 𝕜) i a b + dist (EuclideanSpace.single i (a : 𝕜)) (EuclideanSpace.single i (b : 𝕜)) = dist a b := by + simp -@[simp] +@[deprecated PiLp.nndist_single_same (since := "2026-03-15")] theorem EuclideanSpace.nndist_single_same (i : ι) (a b : 𝕜) : - nndist (EuclideanSpace.single i (a : 𝕜)) (EuclideanSpace.single i (b : 𝕜)) = nndist a b := - PiLp.nndist_toLp_single_same 2 (fun _ => 𝕜) i a b + nndist (EuclideanSpace.single i (a : 𝕜)) (EuclideanSpace.single i (b : 𝕜)) = nndist a b := by + simp -@[simp] +@[deprecated PiLp.edist_single_same (since := "2026-03-15")] theorem EuclideanSpace.edist_single_same (i : ι) (a b : 𝕜) : - edist (EuclideanSpace.single i (a : 𝕜)) (EuclideanSpace.single i (b : 𝕜)) = edist a b := - PiLp.edist_toLp_single_same 2 (fun _ => 𝕜) i a b + edist (EuclideanSpace.single i (a : 𝕜)) (EuclideanSpace.single i (b : 𝕜)) = edist a b := by + simp /-- `EuclideanSpace.single` forms an orthonormal family. -/ theorem EuclideanSpace.orthonormal_single : Orthonormal 𝕜 fun i : ι => EuclideanSpace.single i (1 : 𝕜) := by simp_rw [orthonormal_iff_ite, EuclideanSpace.inner_single_left, map_one, one_mul, - EuclideanSpace.single_apply] + PiLp.single_apply] intros trivial @@ -411,7 +411,7 @@ instance instFunLike : FunLike (OrthonormalBasis ι 𝕜 E) ι E where rw [this, Pi.single_smul] replace h := congr_fun h i simp only [LinearEquiv.comp_coe, map_smul, LinearEquiv.coe_coe, LinearEquiv.trans_apply, - coe_symm_linearEquiv, EuclideanSpace.toLp_single, + coe_symm_linearEquiv, PiLp.toLp_single, LinearIsometryEquiv.coe_symm_toLinearEquiv] at h ⊢ rw [h] @@ -445,7 +445,7 @@ protected theorem orthonormal (b : OrthonormalBasis ι 𝕜 E) : Orthonormal rw [orthonormal_iff_ite] intro i j rw [← b.repr.inner_map_map (b i) (b j), b.repr_self i, b.repr_self j, - EuclideanSpace.inner_single_left, EuclideanSpace.single_apply, map_one, one_mul] + EuclideanSpace.inner_single_left, PiLp.single_apply, map_one, one_mul] @[simp] lemma norm_eq_one (b : OrthonormalBasis ι 𝕜 E) (i : ι) : @@ -678,18 +678,18 @@ theorem _root_.Pi.orthonormalBasis_apply {η : Type*} [Fintype η] [DecidableEq [∀ i, Fintype (ι i)] {𝕜 : Type*} [RCLike 𝕜] {E : η → Type*} [∀ i, NormedAddCommGroup (E i)] [∀ i, InnerProductSpace 𝕜 (E i)] (B : ∀ i, OrthonormalBasis (ι i) 𝕜 (E i)) (j : (i : η) × (ι i)) : - Pi.orthonormalBasis B j = toLp _ (Pi.single _ (B j.fst j.snd)) := by + Pi.orthonormalBasis B j = PiLp.single 2 j.fst (B j.fst j.snd) := by classical ext k obtain ⟨i, j⟩ := j simp only [Pi.orthonormalBasis, coe_ofRepr, LinearIsometryEquiv.symm_trans, LinearIsometryEquiv.symm_symm, LinearIsometryEquiv.piLpCongrRight_symm, LinearIsometryEquiv.trans_apply, LinearIsometryEquiv.piLpCongrRight_apply, - LinearIsometryEquiv.piLpCurry_apply, EuclideanSpace.ofLp_single, PiLp.toLp_apply, + LinearIsometryEquiv.piLpCurry_apply, PiLp.ofLp_single, PiLp.toLp_apply, Sigma.curry_single (γ := fun _ _ => 𝕜)] obtain rfl | hi := Decidable.eq_or_ne i k - · simp only [Pi.single_eq_same, EuclideanSpace.toLp_single, OrthonormalBasis.repr_symm_single] - · simp only [Pi.single_eq_of_ne' hi, toLp_zero, map_zero] + · simp + · simp [hi] @[simp] theorem _root_.Pi.orthonormalBasis_repr {η : Type*} [Fintype η] {ι : η → Type*} @@ -841,7 +841,7 @@ lemma equiv_apply_basis (i : ι) : b.equiv b' e (b i) = b' (e i) := by simp only [OrthonormalBasis.equiv, LinearIsometryEquiv.trans_apply, OrthonormalBasis.repr_self] refine DFunLike.congr rfl ?_ ext j - simp [Pi.single_apply, Equiv.symm_apply_eq] + simp @[simp] lemma equiv_self_rfl : b.equiv b (.refl ι) = .refl 𝕜 E := by diff --git a/Mathlib/Analysis/InnerProductSpace/Spectrum.lean b/Mathlib/Analysis/InnerProductSpace/Spectrum.lean index cec178bda387fe..72c7ac84316f8c 100644 --- a/Mathlib/Analysis/InnerProductSpace/Spectrum.lean +++ b/Mathlib/Analysis/InnerProductSpace/Spectrum.lean @@ -6,8 +6,9 @@ Authors: Heather Macbeth module public import Mathlib.Analysis.InnerProductSpace.Rayleigh -public import Mathlib.Analysis.InnerProductSpace.PiL2 -public import Mathlib.Algebra.DirectSum.Decomposition +public import Mathlib.Analysis.Normed.Group.Submodule +public import Mathlib.Analysis.Normed.Operator.FredholmAlternative +public import Mathlib.LinearAlgebra.Eigenspace.ContinuousLinearMap public import Mathlib.LinearAlgebra.Eigenspace.Minpoly public import Mathlib.Data.Fin.Tuple.Sort @@ -47,9 +48,15 @@ Letting `T` be a self-adjoint operator on a finite-dimensional inner product spa These are forms of the *diagonalization theorem* for self-adjoint operators on finite-dimensional inner product spaces. +The third part of the file covers properties of compact self-adjoint operators: +* `orthogonalComplement_iSup_eigenspaces_eq_bot`: the eigenspaces of a compact self-adjoint operator + have trivial orthogonal complement. +* `finite_dimensional_eigenspace`: the eigenspaces of a compact self-adjoint operator are + finite-dimensional. + ## TODO -Spectral theory for compact self-adjoint operators, bounded self-adjoint operators. +Spectral theory for bounded self-adjoint operators. ## Tags @@ -66,7 +73,7 @@ local notation "⟪" x ", " y "⟫" => inner 𝕜 x y open scoped ComplexConjugate -open Module.End WithLp +open Module End WithLp namespace LinearMap @@ -368,3 +375,54 @@ theorem eigenvalue_pos_of_pos {μ : ℝ} {T : E →ₗ[𝕜] E} (hμ : HasEigenv exact (mul_pos_iff_of_pos_right hpos).mp (this ▸ hnn v) end Nonneg + +namespace ContinuousLinearMap + +variable [CompleteSpace E] {T : E →L[𝕜] E} + +theorem eq_zero_of_forall_hasEigenvalue_eq_zero (hT : IsCompactOperator T) (hT' : T.IsSymmetric) : + (∀ μ, HasEigenvalue (T : End 𝕜 E) μ → μ = 0) ↔ T = 0 := by + rw [← nnnorm_eq_zero, ← ENNReal.coe_eq_zero, ← T.spectralRadius_eq_nnnorm hT'.isSelfAdjoint, + spectralRadius, ← not_iff_not, ENNReal.iSup_eq_zero] + push Not + apply exists_congr + simp +contextual [hT.hasEigenvalue_iff_mem_spectrum] + +set_option backward.isDefEq.respectTransparency false in +/-- The **Spectral Theorem** for compact self-adjoint operators: the eigenspaces of a compact +self-adjoint operator have trivial orthogonal complement. -/ +theorem orthogonalComplement_iSup_eigenspaces_eq_bot + (hT : IsCompactOperator T) (hT' : T.IsSymmetric) : + (⨆ μ, eigenspace (T : Module.End 𝕜 E) μ)ᗮ = ⊥ := by + let S : (⨆ μ, eigenspace T μ : Submodule 𝕜 E)ᗮ →L[𝕜] (⨆ μ, eigenspace T μ : Submodule 𝕜 E)ᗮ := + { __ := T.restrict hT'.orthogonalComplement_iSup_eigenspaces_invariant + cont := by fun_prop } + have hS_compact : IsCompactOperator S := + hT.restrict' hT'.orthogonalComplement_iSup_eigenspaces_invariant + have hS_symm : S.IsSymmetric := + hT'.restrict_invariant (hT'.orthogonalComplement_iSup_eigenspaces_invariant) + have hS μ : eigenspace (S : Module.End 𝕜 (⨆ μ, eigenspace T μ : Submodule 𝕜 E)ᗮ) μ = ⊥ := by + rw [Submodule.eq_bot_iff] + intro v hv + rw [Subtype.ext_iff, Submodule.coe_zero, ← Submodule.mem_bot 𝕜, + ← Submodule.inf_orthogonal_eq_bot (⨆ μ, eigenspace T μ : Submodule 𝕜 E)] + refine ⟨Submodule.mem_iSup_of_mem μ ?_, v.2⟩ + rw [mem_eigenspace_iff] at hv ⊢ + exact Subtype.ext_iff.mp hv + have h μ : HasEigenvalue (S : End 𝕜 (⨆ μ, eigenspace T μ : Submodule 𝕜 E)ᗮ) μ → μ = 0 := by + simp_all [hasEigenvalue_iff] + rw [eq_zero_of_forall_hasEigenvalue_eq_zero hS_compact hS_symm] at h + rw [← Submodule.subsingleton_iff_eq_bot] + by_contra! hV + simpa [h] using hS 0 + +/-- The **Spectral Theorem** for compact self-adjoint operators: the eigenspaces of a compact +self-adjoint operator are finite-dimensional. -/ +theorem finite_dimensional_eigenspace (hT : IsCompactOperator T) (μ : 𝕜) (hμ : μ ≠ 0) : + FiniteDimensional 𝕜 (eigenspace T.toLinearMap μ) := by + replace hT := hT.restrict' + ((mem_invtSubmodule_iff_forall_mem_of_mem _).mp (eigenspace_mem_invtSubmodule T.toLinearMap μ)) + rw [restrict_eigenspace, LinearMap.coe_smul, IsCompactOperator.smul_iff₀ hμ] at hT + rwa [← isCompactOperator_id_iff_finiteDimensional] + +end ContinuousLinearMap diff --git a/Mathlib/Analysis/InnerProductSpace/StandardSubspace.lean b/Mathlib/Analysis/InnerProductSpace/StandardSubspace.lean new file mode 100644 index 00000000000000..e5bfde0db34841 --- /dev/null +++ b/Mathlib/Analysis/InnerProductSpace/StandardSubspace.lean @@ -0,0 +1,227 @@ +/- +Copyright (c) 2026 Yoh Tanimoto. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yoh Tanimoto +-/ +module + +public import Mathlib.Analysis.CStarAlgebra.Module.Constructions +public import Mathlib.Analysis.InnerProductSpace.Projection.Submodule + +/-! +# Standard subspaces of a Hilbert space + +This files defines standard subspaces of a complex Hilbert space: a standard subspace `S` of `H` is +a closed real subspace `S` such that `S ⊓ i S = ⊥` and `S ⊔ i S = ⊤`. For a standard subspace, one +can define a closable operator `x + i y ↦ x - i y` and develop an analogue of the Tomita-Takesaki +modular theory for von Neumann algebras. By considering inclusions of standard subspaces, one can +obtain unitary representations of various Lie groups. + +## Main definitions and results + +* `instance : InnerProductSpace ℝ H` for `InnerProductSpace ℂ H`, by restricting the scalar product + to its real part + +* `StandardSubspace` as a structure with a `ClosedSubmodule` for `InnerProductSpace ℝ H` satisfying + `IsCyclic` and `IsSeparating`. Actually the interesting cases need `CompleteSpace H`, but the + definition is given for a general case. + +* `symplComp` as a `StandardSubspace` of the symplectic complement of a standard subspace with + respect to `⟪⬝, ⬝⟫.im` + +* `symplComp_symplComp_eq` the double symplectic complement is equal to itself + +## References + +* [Chap. 2 of Lecture notes by R. Longo](https://www.mat.uniroma2.it/longo/Lecture-Notes_files/LN-Part1.pdf) + +* [Oberwolfach report](https://ems.press/content/serial-article-files/48171) + +## TODO + +Define the Tomita conjugation, prove Tomita's theorem, prove the KMS condition. +-/ + +@[expose] public section + +open Complex ContinuousLinearMap +open scoped ComplexInnerProductSpace + +section ScalarSMulCLE + +variable (H : Type*) [NormedAddCommGroup H] [InnerProductSpace ℂ H] + +set_option backward.isDefEq.respectTransparency false in +/-- the scalar product by a non-zero complex number as a continuous real-linear equivalence. -/ +noncomputable def scalarSMulCLE (c : ℂˣ) : H ≃L[ℝ] H := ContinuousLinearEquiv.smulLeft c + +@[simp] +lemma scalarSMulCLE_apply (c : ℂˣ) (x : H) : scalarSMulCLE H c x = c • x := rfl + +@[simp] +lemma scalarSMulCLE_symm_apply (c : ℂˣ) (x : H) : (scalarSMulCLE H c).symm x = c⁻¹ • x := rfl + +end ScalarSMulCLE + +namespace ClosedSubmodule + +variable {H : Type*} [NormedAddCommGroup H] [ipc : InnerProductSpace ℂ H] + +set_option backward.isDefEq.respectTransparency false in +/-- `H` as a real Hilbert space. This instance is declared inside `ClosedSubmodule` namespace. If +one needs this structure (for example when considering standard subspaces), one should just `open +ClosedSubmodule` and not declare another instance. -/ +noncomputable scoped instance : InnerProductSpace ℝ H where + inner x y := ⟪x, y⟫.re + norm_sq_eq_re_inner := by simp [RCLike.re_to_real, ipc.norm_sq_eq_re_inner] + conj_inner_symm x y := by + simp only [← ipc.conj_inner_symm x y, conj_trivial] + rfl + add_left := by simp + smul_left := by simp + +lemma inner_real_eq_re_inner (x y : H) : inner ℝ x y = ⟪x, y⟫.re := rfl + +/-- The imaginary unit as an invertible element. -/ +@[simps] +def _root_.Complex.UnitI : ℂˣ where + val := I + inv := -I + val_inv := by simp + inv_val := by simp + +/-- The image of a closed submodule by the multiplication by `Complex.I`. -/ +noncomputable abbrev mulI (S : ClosedSubmodule ℝ H) := S.mapEquiv (scalarSMulCLE H UnitI) + +/-- The symplectic complement of a closed submodule with respect to `⟪⬝, ⬝⟫.im`, defined as the +image of `mulI` and `orthogonal`. The proof that this is the symplectic complement is given by +`mem_symplComp_iff`. -/ +noncomputable abbrev symplComp (S : ClosedSubmodule ℝ H) := (S.mulI)ᗮ + +lemma mem_iff (S : ClosedSubmodule ℝ H) {x : H} : x ∈ S ↔ x ∈ S.toSubmodule.carrier := by + exact Eq.to_iff rfl + +lemma mem_symplComp_iff {x : H} {S : ClosedSubmodule ℝ H} : + x ∈ S.symplComp ↔ ∀ y ∈ S, ⟪y, x⟫.im = 0 := by + simp only [mem_orthogonal, mem_mapEquiv_iff, scalarSMulCLE_symm_apply, Units.smul_def, + Units.val_inv_eq_inv_val, val_UnitI, inv_I, neg_smul] + constructor + · intro h y hy + have hiy := h (I • y) + simp only [← smul_assoc, smul_eq_mul, I_mul_I, neg_smul, one_smul, neg_neg] at hiy + simpa [inner_real_eq_re_inner] using hiy hy + · intro h _ hy + have hiy := h _ hy + simpa [inner_smul_left] using hiy + +lemma mulI_orthogonal_eq_symplComp (S : ClosedSubmodule ℝ H) : Sᗮ.mulI = S.symplComp := by + ext x + rw [← mem_iff, ← mem_iff, mem_symplComp_iff, mem_mapEquiv_iff, scalarSMulCLE_symm_apply, + Units.inv_mk, Units.smul_mk_apply] + simp [inner_real_eq_re_inner] + + +lemma mulI_orthogonal (S : ClosedSubmodule ℝ H) : Sᗮ.mulI = S.mulIᗮ := by + rw [mulI_orthogonal_eq_symplComp] + +@[simp] +lemma mulI_symplComp {S : ClosedSubmodule ℝ H} : + S.symplComp.mulI = S.mulI.symplComp := by + rw [symplComp, symplComp, mulI_orthogonal_eq_symplComp] + +@[simp] +lemma mulI_mulI_eq (S : ClosedSubmodule ℝ H) : S.mulI.mulI = S := by + ext x + simp only [Submodule.carrier_eq_coe, coe_toSubmodule, SetLike.mem_coe] + constructor + · intro h + rw [mem_mapEquiv_iff (scalarSMulCLE H UnitI), ← SetLike.forall_smul_mem_iff] at h + simpa [← smul_assoc, Units.smul_def] using (h (-1 : ℝ)) + · intro h + rw [← SetLike.forall_smul_mem_iff] at h + simpa [← smul_assoc, Units.smul_def] using (h (-1 : ℝ)) + +lemma involutive_mulI : + Function.Involutive (mulI : ClosedSubmodule ℝ H → ClosedSubmodule ℝ H) := mulI_mulI_eq + +@[simp] +lemma symplComp_symplComp_eq [CompleteSpace H] {S : ClosedSubmodule ℝ H} : + S.symplComp.symplComp = S := by simp [symplComp] + +lemma mulI_sup (S T : ClosedSubmodule ℝ H) : + (S ⊔ T).mulI = S.mulI ⊔ T.mulI := by + rw [mulI, ← mapEquiv_sup_eq] + +lemma mulI_inf (S T : ClosedSubmodule ℝ H) : + (S ⊓ T).mulI = S.mulI ⊓ T.mulI := by + rw [mulI, ← mapEquiv_inf_eq] + +@[simp] +lemma symplComp_sup (S T : ClosedSubmodule ℝ H) : + (S ⊔ T).symplComp = S.symplComp ⊓ T.symplComp := by + rw [symplComp, symplComp, symplComp, mulI_sup] + exact Eq.symm (inf_orthogonal S.mulI T.mulI) + +@[simp] +lemma symplComp_inf [CompleteSpace H] (S T : ClosedSubmodule ℝ H) : + (S ⊓ T).symplComp = S.symplComp ⊔ T.symplComp := by + rw [symplComp, symplComp, symplComp, mulI_inf] + exact Eq.symm (sup_orthogonal S.mulI T.mulI) + +end ClosedSubmodule + +section Def + +variable (H : Type*) [NormedAddCommGroup H] [InnerProductSpace ℂ H] + +/-- A standard subspace `S` of a complex Hilbert space (or just an inner product space) `H` is a +closed real subspace `S` such that `S ⊓ i S = ⊥` and `S ⊔ i S = ⊤`. -/ +@[ext] +structure StandardSubspace where + /-- A real closed subspace `S`. -/ + toClosedSubmodule : ClosedSubmodule ℝ H + /-- `S` is separating, that is, `S ⊓ i S` is the trivial subspace. -/ + IsSeparating : toClosedSubmodule ⊓ toClosedSubmodule.mulI = ⊥ + /-- `S` is cyclic, that is, `S ⊔ i S` is the whole space. -/ + IsCyclic : toClosedSubmodule ⊔ toClosedSubmodule.mulI = ⊤ + +end Def + +namespace StandardSubspace + +open ClosedSubmodule + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] + +@[simp] +lemma toClosedSubmodule_inj {S T : StandardSubspace H} : + S.toClosedSubmodule = T.toClosedSubmodule ↔ S = T := + StandardSubspace.ext_iff.symm + +lemma toClosedSubmodule_injective : Function.Injective (toClosedSubmodule (H := H)) := + fun _ _ ↦ toClosedSubmodule_inj.mp + +/-- The image of a standard subspace by the multiplication by `Complex.I`, bundled as a +`StandardSubspace`. -/ +noncomputable def mulI (S : StandardSubspace H) : StandardSubspace H where + toClosedSubmodule := S.toClosedSubmodule.mulI + IsSeparating := by simpa [mulI_mulI_eq, inf_comm] using S.IsSeparating + IsCyclic := by simpa [mulI_mulI_eq, sup_comm] using S.IsCyclic + +/-- The symplectic complement of a standard subspace, bundled as a `StandardSubspace`. -/ +noncomputable def symplComp [CompleteSpace H] (S : StandardSubspace H) : StandardSubspace H where + toClosedSubmodule := S.toClosedSubmodule.symplComp + IsSeparating := by + simp [mulI_symplComp, ClosedSubmodule.inf_orthogonal, sup_comm, S.IsCyclic] + IsCyclic := by + simp [mulI_symplComp, ClosedSubmodule.sup_orthogonal, inf_comm, S.IsSeparating] + +@[simp] +theorem symplComp_symplComp_eq [CompleteSpace H] (S : StandardSubspace H) : + S.symplComp.symplComp = S := toClosedSubmodule_inj.mp ClosedSubmodule.symplComp_symplComp_eq + +lemma involutive_symplComp [CompleteSpace H] : + Function.Involutive (symplComp : StandardSubspace H → StandardSubspace H) + := symplComp_symplComp_eq + +end StandardSubspace diff --git a/Mathlib/Analysis/LocallyConvex/WeakSpace.lean b/Mathlib/Analysis/LocallyConvex/WeakSpace.lean index a20819b1f86a82..120985f50ef08c 100644 --- a/Mathlib/Analysis/LocallyConvex/WeakSpace.lean +++ b/Mathlib/Analysis/LocallyConvex/WeakSpace.lean @@ -76,8 +76,9 @@ theorem LinearMap.image_closure_of_convex {s : Set E} (hs : Convex ℝ s) (e : E rw [← Set.image_subset_image_iff (toWeakSpace 𝕜 F).injective, h_convex.toWeakSpace_closure 𝕜] simpa only [Set.image_image, ← hs.toWeakSpace_closure 𝕜, LinearEquiv.symm_apply_apply] using he'.continuousOn.image_closure (s := toWeakSpace 𝕜 E '' s) - exact WeakBilin.continuous_of_continuous_eval _ fun f ↦ - WeakBilin.eval_continuous _ { toLinearMap := e.dualMap f : StrongDual 𝕜 E } + exact WeakBilin.continuous_of_continuous_eval _ fun f ↦ WeakBilin.eval_continuous _ ({ + toLinearMap := e.dualMap f + cont := by dsimp; fun_prop } : StrongDual 𝕜 E) /-- If `e` is a linear isomorphism between two locally convex spaces, and `e` induces (via precomposition) an isomorphism between their continuous duals, then `e` commutes with the closure diff --git a/Mathlib/Analysis/Matrix/Spectrum.lean b/Mathlib/Analysis/Matrix/Spectrum.lean index e84b277a7173f3..1e6809ddfb7d49 100644 --- a/Mathlib/Analysis/Matrix/Spectrum.lean +++ b/Mathlib/Analysis/Matrix/Spectrum.lean @@ -127,13 +127,13 @@ theorem conjStarAlgAut_star_eigenvectorUnitary : diagonal (RCLike.ofReal ∘ hA.eigenvalues) := by apply Matrix.toEuclideanLin.injective <| (EuclideanSpace.basisFun n 𝕜).toBasis.ext fun i ↦ ?_ simp only [conjStarAlgAut_star_apply, toLpLin_apply, OrthonormalBasis.coe_toBasis, - EuclideanSpace.basisFun_apply, EuclideanSpace.ofLp_single, ← mulVec_mulVec, + EuclideanSpace.basisFun_apply, PiLp.ofLp_single, ← mulVec_mulVec, eigenvectorUnitary_mulVec, ← mulVec_mulVec, mulVec_eigenvectorBasis, Matrix.diagonal_mulVec_single, mulVec_smul, star_eigenvectorUnitary_mulVec, - RCLike.real_smul_eq_coe_smul (K := 𝕜), WithLp.toLp_smul, EuclideanSpace.toLp_single, + RCLike.real_smul_eq_coe_smul (K := 𝕜), WithLp.toLp_smul, PiLp.toLp_single, Function.comp_apply, mul_one] apply PiLp.ext fun j ↦ ?_ - simp only [PiLp.smul_apply, EuclideanSpace.single_apply, smul_eq_mul, mul_ite, mul_one, mul_zero] + simp only [PiLp.smul_apply, PiLp.single_apply, smul_eq_mul, mul_ite, mul_one, mul_zero] @[deprecated (since := "2025-11-06")] alias star_mul_self_mul_eq_diagonal := conjStarAlgAut_star_eigenvectorUnitary diff --git a/Mathlib/Analysis/MeanInequalities.lean b/Mathlib/Analysis/MeanInequalities.lean index 0d3a4a039b8427..8fe04d53fd0bb9 100644 --- a/Mathlib/Analysis/MeanInequalities.lean +++ b/Mathlib/Analysis/MeanInequalities.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2019 Yury Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Yury Kudryashov, Sébastien Gouëzel, Rémy Degenne +Authors: Yury Kudryashov, Sébastien Gouëzel, Rémy Degenne, Jireh Loreaux -/ module @@ -495,14 +495,39 @@ theorem inner_le_Lp_mul_Lq (f g : ι → ℝ≥0) {p q : ℝ} (hpq : p.HolderCon suffices (∑ i ∈ s, f' i * g' i) ≤ 1 by simp_rw [f', g', div_mul_div_comm, ← sum_div] at this rwa [div_le_iff₀, one_mul] at this - -- TODO: We are missing a positivity extension here - exact mul_pos (rpow_pos hf) (rpow_pos hg) + positivity refine inner_le_Lp_mul_Lp_of_norm_le_one s f' g' hpq (le_of_eq ?_) (le_of_eq ?_) · simp_rw [f', div_rpow, ← sum_div, ← rpow_mul, one_div, inv_mul_cancel₀ hpq.ne_zero, rpow_one, div_self hf.ne'] · simp_rw [g', div_rpow, ← sum_div, ← rpow_mul, one_div, inv_mul_cancel₀ hpq.symm.ne_zero, rpow_one, div_self hg.ne'] +/-- **Hölder inequality**: The (`r`-power of the) `L^r` norm of the product of two functions is +bounded by the product of (the `r`-powers of) their `L^p` and `L^q` norms when `p`, `q`, and `r` +form a `Real.HolderTriple`. -/ +theorem Lr_rpow_le_Lp_mul_Lq (f g : ι → ℝ≥0) {p q r : ℝ} (hpqr : p.HolderTriple q r) : + ∑ i ∈ s, (f i * g i) ^ r ≤ (∑ i ∈ s, f i ^ p) ^ (r / p) * (∑ i ∈ s, g i ^ q) ^ (r / q) := by + have := hpqr.holderConjugate_div_div + calc ∑ i ∈ s, (f i * g i) ^ r + _ = ∑ i ∈ s, (f i) ^ r * (g i) ^ r := s.sum_congr rfl fun i hi ↦ mul_rpow .. + _ ≤ (∑ i ∈ s, f i ^ p) ^ (r / p) * (∑ i ∈ s, g i ^ q) ^ (r / q) := by + apply inner_le_Lp_mul_Lq s _ _ this |>.trans_eq + congr! 2 + all_goals try simp only [fieldEq] + all_goals + refine s.sum_congr rfl fun i hi ↦ by simp [← rpow_mul, ← mul_div_assoc, hpqr.pos'.ne'] + +/-- **Hölder inequality**: The `L^r` norm of the product of two functions is bounded by the +product of their `L^p` and `L^q` norms when `p`, `q`, and `r` form a `Real.HolderTriple`. -/ +theorem Lr_le_Lp_mul_Lq (f g : ι → ℝ≥0) {p q r : ℝ} (hpqr : p.HolderTriple q r) : + (∑ i ∈ s, (f i * g i) ^ r) ^ (1 / r) ≤ + (∑ i ∈ s, f i ^ p) ^ (1 / p) * (∑ i ∈ s, g i ^ q) ^ (1 / q) := by + convert rpow_le_rpow_iff (inv_eq_one_div r ▸ inv_pos.mpr hpqr.pos' : 0 < 1 / r) |>.mpr <| + Lr_rpow_le_Lp_mul_Lq s f g hpqr using 1 + have hr := hpqr.pos'.ne' + simp only [← rpow_mul, mul_rpow] + field_simp + /-- **Weighted Hölder inequality**. -/ lemma inner_le_weight_mul_Lp (s : Finset ι) {p : ℝ} (hp : 1 ≤ p) (w f : ι → ℝ≥0) : ∑ i ∈ s, w i * f i ≤ (∑ i ∈ s, w i) ^ (1 - p⁻¹) * (∑ i ∈ s, w i * f i ^ p) ^ p⁻¹ := by @@ -521,38 +546,70 @@ lemma inner_le_weight_mul_Lp (s : Finset ι) {p : ℝ} (hp : 1 ≤ p) (w f : ι have hp₁ : 1 - p⁻¹ ≠ 0 := by simp [sub_eq_zero, hp.ne'] simp [mul_rpow, div_inv_eq_mul, one_mul, one_div, hp₀, hp₁] -/-- **Hölder inequality**: the scalar product of two functions is bounded by the product of their -`L^p` and `L^q` norms when `p` and `q` are conjugate exponents. A version for `NNReal`-valued -functions. For an alternative version, convenient if the infinite sums are already expressed as -`p`-th powers, see `inner_le_Lp_mul_Lq_hasSum`. -/ -theorem inner_le_Lp_mul_Lq_tsum {f g : ι → ℝ≥0} {p q : ℝ} (hpq : p.HolderConjugate q) - (hf : Summable fun i => f i ^ p) (hg : Summable fun i => g i ^ q) : - (Summable fun i => f i * g i) ∧ - ∑' i, f i * g i ≤ (∑' i, f i ^ p) ^ (1 / p) * (∑' i, g i ^ q) ^ (1 / q) := by +/-- **Hölder inequality**: The (`r`-power of the) `L^r` norm of the product of two functions is +bounded by the product of (the `r`-powers of) their `L^p` and `L^q` norms when `p`, `q`, and `r` +form a `Real.HolderTriple`. A version for `NNReal`-valued functions. For an alternative version, +convenient if the infinite sums are already expressed as powers, see `inner_le_Lp_mul_Lq_hasSum`. -/ +theorem summable_and_Lr_rpow_le_Lp_mul_Lq_tsum {f g : ι → ℝ≥0} {p q r : ℝ} + (hpqr : p.HolderTriple q r) (hf : Summable fun i => f i ^ p) (hg : Summable fun i => g i ^ q) : + (Summable fun i => (f i * g i) ^ r) ∧ + ∑' i, (f i * g i) ^ r ≤ (∑' i, f i ^ p) ^ (r / p) * (∑' i, g i ^ q) ^ (r / q) := by have H₁ : ∀ s : Finset ι, - ∑ i ∈ s, f i * g i ≤ (∑' i, f i ^ p) ^ (1 / p) * (∑' i, g i ^ q) ^ (1 / q) := by + ∑ i ∈ s, (f i * g i) ^ r ≤ (∑' i, f i ^ p) ^ (r / p) * (∑' i, g i ^ q) ^ (r / q) := by intro s - refine le_trans (inner_le_Lp_mul_Lq s f g hpq) (mul_le_mul ?_ ?_ bot_le bot_le) - · rw [NNReal.rpow_le_rpow_iff (one_div_pos.mpr hpq.pos)] + obtain ⟨hp, hq, hr⟩ := hpqr.all_pos + refine le_trans (Lr_rpow_le_Lp_mul_Lq s f g hpqr) (mul_le_mul ?_ ?_ bot_le bot_le) + · rw [NNReal.rpow_le_rpow_iff (by positivity)] exact hf.sum_le_tsum _ (fun _ _ => zero_le _) - · rw [NNReal.rpow_le_rpow_iff (one_div_pos.mpr hpq.symm.pos)] + · rw [NNReal.rpow_le_rpow_iff (by positivity)] exact hg.sum_le_tsum _ (fun _ _ => zero_le _) - have bdd : BddAbove (Set.range fun s => ∑ i ∈ s, f i * g i) := by - refine ⟨(∑' i, f i ^ p) ^ (1 / p) * (∑' i, g i ^ q) ^ (1 / q), ?_⟩ + have bdd : BddAbove (Set.range fun s => ∑ i ∈ s, (f i * g i) ^ r) := by + refine ⟨(∑' i, f i ^ p) ^ (r / p) * (∑' i, g i ^ q) ^ (r / q), ?_⟩ rintro a ⟨s, rfl⟩ exact H₁ s have H₂ : Summable _ := (hasSum_of_isLUB _ (isLUB_ciSup bdd)).summable exact ⟨H₂, H₂.tsum_le_of_sum_le H₁⟩ +/-- **Hölder inequality**: the scalar product of two functions is bounded by the product of their +`L^p` and `L^q` norms when `p` and `q` are conjugate exponents. A version for `NNReal`-valued +functions. For an alternative version, convenient if the infinite sums are already expressed as +`p`-th powers, see `inner_le_Lp_mul_Lq_hasSum`. -/ +theorem summable_and_inner_le_Lp_mul_Lq_tsum {f g : ι → ℝ≥0} {p q : ℝ} (hpq : p.HolderConjugate q) + (hf : Summable fun i => f i ^ p) (hg : Summable fun i => g i ^ q) : + (Summable fun i => f i * g i) ∧ + ∑' i, f i * g i ≤ (∑' i, f i ^ p) ^ (1 / p) * (∑' i, g i ^ q) ^ (1 / q) := by + simpa using summable_and_Lr_rpow_le_Lp_mul_Lq_tsum hpq hf hg + +theorem summable_mul_rpow_of_Lp_Lq {f g : ι → ℝ≥0} {p q r : ℝ} (hpqr : p.HolderTriple q r) + (hf : Summable fun i => f i ^ p) (hg : Summable fun i => g i ^ q) : + Summable fun i => (f i * g i) ^ r := + (summable_and_Lr_rpow_le_Lp_mul_Lq_tsum hpqr hf hg).1 + theorem summable_mul_of_Lp_Lq {f g : ι → ℝ≥0} {p q : ℝ} (hpq : p.HolderConjugate q) (hf : Summable fun i => f i ^ p) (hg : Summable fun i => g i ^ q) : Summable fun i => f i * g i := - (inner_le_Lp_mul_Lq_tsum hpq hf hg).1 + (summable_and_inner_le_Lp_mul_Lq_tsum hpq hf hg).1 -theorem inner_le_Lp_mul_Lq_tsum' {f g : ι → ℝ≥0} {p q : ℝ} (hpq : p.HolderConjugate q) +theorem Lr_rpow_le_Lp_mul_Lq_tsum {f g : ι → ℝ≥0} {p q r : ℝ} (hpqr : p.HolderTriple q r) + (hf : Summable fun i => f i ^ p) (hg : Summable fun i => g i ^ q) : + ∑' i, (f i * g i) ^ r ≤ (∑' i, f i ^ p) ^ (r / p) * (∑' i, g i ^ q) ^ (r / q) := + (summable_and_Lr_rpow_le_Lp_mul_Lq_tsum hpqr hf hg).2 + +theorem Lr_le_Lp_mul_Lq_tsum {f g : ι → ℝ≥0} {p q r : ℝ} (hpqr : p.HolderTriple q r) + (hf : Summable fun i => f i ^ p) (hg : Summable fun i => g i ^ q) : + (∑' i, (f i * g i) ^ r) ^ (1 / r) ≤ (∑' i, f i ^ p) ^ (1 / p) * (∑' i, g i ^ q) ^ (1 / q) := by + convert rpow_le_rpow_iff (inv_eq_one_div r ▸ inv_pos.mpr hpqr.pos') |>.mpr <| + Lr_rpow_le_Lp_mul_Lq_tsum hpqr hf hg + have hr := hpqr.pos'.ne' + simp only [← rpow_mul, mul_rpow] + field_simp + +theorem inner_le_Lp_mul_Lq_tsum {f g : ι → ℝ≥0} {p q : ℝ} (hpq : p.HolderConjugate q) (hf : Summable fun i => f i ^ p) (hg : Summable fun i => g i ^ q) : ∑' i, f i * g i ≤ (∑' i, f i ^ p) ^ (1 / p) * (∑' i, g i ^ q) ^ (1 / q) := - (inner_le_Lp_mul_Lq_tsum hpq hf hg).2 + (summable_and_inner_le_Lp_mul_Lq_tsum hpq hf hg).2 + +@[deprecated (since := "2026-02-12")] alias inner_le_Lp_mul_Lq_tsum' := inner_le_Lp_mul_Lq_tsum /-- **Hölder inequality**: the scalar product of two functions is bounded by the product of their `L^p` and `L^q` norms when `p` and `q` are conjugate exponents. A version for `NNReal`-valued @@ -561,7 +618,7 @@ functions. For an alternative version, convenient if the infinite sums are not a theorem inner_le_Lp_mul_Lq_hasSum {f g : ι → ℝ≥0} {A B : ℝ≥0} {p q : ℝ} (hpq : p.HolderConjugate q) (hf : HasSum (fun i => f i ^ p) (A ^ p)) (hg : HasSum (fun i => g i ^ q) (B ^ q)) : ∃ C, C ≤ A * B ∧ HasSum (fun i => f i * g i) C := by - obtain ⟨H₁, H₂⟩ := inner_le_Lp_mul_Lq_tsum hpq hf.summable hg.summable + obtain ⟨H₁, H₂⟩ := summable_and_inner_le_Lp_mul_Lq_tsum hpq hf.summable hg.summable have hA : A = (∑' i : ι, f i ^ p) ^ (1 / p) := by rw [hf.tsum_eq, rpow_inv_rpow_self hpq.ne_zero] have hB : B = (∑' i : ι, g i ^ q) ^ (1 / q) := by rw [hg.tsum_eq, rpow_inv_rpow_self hpq.symm.ne_zero] @@ -681,19 +738,22 @@ end NNReal namespace Real -variable (f g : ι → ℝ) {p q : ℝ} +variable (f g : ι → ℝ) {p q r : ℝ} + +/-- **Hölder inequality**: the sum of (the `r`-powers of) the product of two functions is bounded by +the product of their `L^p` and `L^q` norms when `p`, `q` and `r` form a `Real.HolderTriple`. +Version for sums over finite sets, with real-valued functions. -/ +theorem Lr_rpow_le_Lp_mul_Lq (hpqr : HolderTriple p q r) : + ∑ i ∈ s, |f i * g i| ^ r ≤ (∑ i ∈ s, |f i| ^ p) ^ (r / p) * (∑ i ∈ s, |g i| ^ q) ^ (r / q) := by + simpa using NNReal.coe_le_coe.2 <| NNReal.Lr_rpow_le_Lp_mul_Lq s (fun i ↦ ⟨_, abs_nonneg (f i)⟩) + (fun i ↦ ⟨_, abs_nonneg (g i)⟩) hpqr /-- **Hölder inequality**: the scalar product of two functions is bounded by the product of their `L^p` and `L^q` norms when `p` and `q` are conjugate exponents. Version for sums over finite sets, with real-valued functions. -/ theorem inner_le_Lp_mul_Lq (hpq : HolderConjugate p q) : ∑ i ∈ s, f i * g i ≤ (∑ i ∈ s, |f i| ^ p) ^ (1 / p) * (∑ i ∈ s, |g i| ^ q) ^ (1 / q) := by - have := - NNReal.coe_le_coe.2 - (NNReal.inner_le_Lp_mul_Lq s (fun i => ⟨_, abs_nonneg (f i)⟩) (fun i => ⟨_, abs_nonneg (g i)⟩) - hpq) - push_cast at this - refine le_trans (sum_le_sum fun i _ => ?_) this + refine le_trans (sum_le_sum fun i _ ↦ ?_) (by simpa using Lr_rpow_le_Lp_mul_Lq s f g hpq) simp only [← abs_mul, le_abs_self] /-- For `1 ≤ p`, the `p`-th power of the sum of `f i` is bounded above by a constant times the @@ -731,6 +791,18 @@ theorem inner_le_Lp_mul_Lq_of_nonneg (hpq : HolderConjugate p q) (hf : ∀ i ∈ convert inner_le_Lp_mul_Lq s f g hpq using 3 <;> apply sum_congr rfl <;> intro i hi <;> simp only [abs_of_nonneg, hf i hi, hg i hi] +/-- **Hölder inequality**: the sum of (the `r`-power of) the product of two functions is bounded +by (the `r`-power of) the product of their `L^p` and `L^q` norms, when `p`, `q`, `r` form a +`Real.HolderTriple`. -/ +theorem Lr_rpow_le_Lp_mul_Lq_of_nonneg {ι : Type*} (s : Finset ι) {f g : ι → ℝ} {p q r : ℝ} + (hpqr : p.HolderTriple q r) (hf : ∀ i ∈ s, 0 ≤ f i) (hg : ∀ i ∈ s, 0 ≤ g i) : + ∑ i ∈ s, (f i * g i) ^ r ≤ (∑ i ∈ s, f i ^ p) ^ (r / p) * (∑ i ∈ s, g i ^ q) ^ (r / q) := by + convert Lr_rpow_le_Lp_mul_Lq s f g hpqr using 3 with i hi + · rw [abs_of_nonneg (mul_nonneg (hf i hi) (hg i hi))] + all_goals + congr! with i hi + exact Eq.symm (abs_of_nonneg (by grind)) + /-- **Weighted Hölder inequality**. -/ lemma inner_le_weight_mul_Lp_of_nonneg (s : Finset ι) {p : ℝ} (hp : 1 ≤ p) (w f : ι → ℝ) (hw : ∀ i, 0 ≤ w i) (hf : ∀ i, 0 ≤ f i) : @@ -753,30 +825,68 @@ lemma compact_inner_le_weight_mul_Lp_of_nonneg (s : Finset ι) {p : ℝ} (hp : 1 · exact sum_nonneg fun i _ ↦ by have := hw i; have := hf i; positivity · exact sum_nonneg fun i _ ↦ by have := hw i; positivity +/-- **Hölder inequality**: the sum of (the `r`-powers of) two functions is bounded by the product +of (the `r`-powers of) their `L^p` and `L^q` norms when `p`, `q` and `r` form a `Real.HolderTriple`. +A version for `ℝ`-valued functions. -/ +theorem summable_and_Lr_rpow_le_Lp_mul_Lq_tsum_of_nonneg (hpqr : p.HolderTriple q r) + (hf : ∀ i, 0 ≤ f i) (hg : ∀ i, 0 ≤ g i) (hf_sum : Summable fun i => f i ^ p) + (hg_sum : Summable fun i => g i ^ q) : + (Summable fun i => (f i * g i) ^ r) ∧ + ∑' i, (f i * g i) ^ r ≤ (∑' i, f i ^ p) ^ (r / p) * (∑' i, g i ^ q) ^ (r / q) := by + lift f to ι → ℝ≥0 using hf + lift g to ι → ℝ≥0 using hg + -- After https://github.com/leanprover/lean4/pull/2734, `norm_cast` needs help with beta reduction. + beta_reduce at * + norm_cast at * + exact NNReal.summable_and_Lr_rpow_le_Lp_mul_Lq_tsum hpqr hf_sum hg_sum + /-- **Hölder inequality**: the scalar product of two functions is bounded by the product of their `L^p` and `L^q` norms when `p` and `q` are conjugate exponents. A version for `ℝ`-valued functions. For an alternative version, convenient if the infinite sums are already expressed as `p`-th powers, see `inner_le_Lp_mul_Lq_hasSum_of_nonneg`. -/ -theorem inner_le_Lp_mul_Lq_tsum_of_nonneg (hpq : p.HolderConjugate q) (hf : ∀ i, 0 ≤ f i) - (hg : ∀ i, 0 ≤ g i) (hf_sum : Summable fun i => f i ^ p) (hg_sum : Summable fun i => g i ^ q) : +theorem summable_and_inner_le_Lp_mul_Lq_tsum_of_nonneg (hpq : p.HolderConjugate q) + (hf : ∀ i, 0 ≤ f i) (hg : ∀ i, 0 ≤ g i) (hf_sum : Summable fun i => f i ^ p) + (hg_sum : Summable fun i => g i ^ q) : (Summable fun i => f i * g i) ∧ ∑' i, f i * g i ≤ (∑' i, f i ^ p) ^ (1 / p) * (∑' i, g i ^ q) ^ (1 / q) := by - lift f to ι → ℝ≥0 using hf - lift g to ι → ℝ≥0 using hg - -- After https://github.com/leanprover/lean4/pull/2734, `norm_cast` needs help with beta reduction. - beta_reduce at * - norm_cast at * - exact NNReal.inner_le_Lp_mul_Lq_tsum hpq hf_sum hg_sum + simpa using summable_and_Lr_rpow_le_Lp_mul_Lq_tsum_of_nonneg hpq hf hg hf_sum hg_sum + +theorem summable_Lr_of_Lp_Lq_of_nonneg (hpqr : p.HolderTriple q r) (hf : ∀ i, 0 ≤ f i) + (hg : ∀ i, 0 ≤ g i) (hf_sum : Summable fun i => f i ^ p) (hg_sum : Summable fun i => g i ^ q) : + Summable fun i => (f i * g i) ^ r := + (summable_and_Lr_rpow_le_Lp_mul_Lq_tsum_of_nonneg hpqr hf hg hf_sum hg_sum).1 theorem summable_mul_of_Lp_Lq_of_nonneg (hpq : p.HolderConjugate q) (hf : ∀ i, 0 ≤ f i) (hg : ∀ i, 0 ≤ g i) (hf_sum : Summable fun i => f i ^ p) (hg_sum : Summable fun i => g i ^ q) : Summable fun i => f i * g i := - (inner_le_Lp_mul_Lq_tsum_of_nonneg hpq hf hg hf_sum hg_sum).1 + (summable_and_inner_le_Lp_mul_Lq_tsum_of_nonneg hpq hf hg hf_sum hg_sum).1 -theorem inner_le_Lp_mul_Lq_tsum_of_nonneg' (hpq : p.HolderConjugate q) (hf : ∀ i, 0 ≤ f i) +theorem Lr_rpow_le_Lp_mul_Lq_tsum_of_nonneg (hpqr : p.HolderTriple q r) (hf : ∀ i, 0 ≤ f i) + (hg : ∀ i, 0 ≤ g i) (hf_sum : Summable fun i => f i ^ p) (hg_sum : Summable fun i => g i ^ q) : + ∑' i, (f i * g i) ^ r ≤ (∑' i, f i ^ p) ^ (r / p) * (∑' i, g i ^ q) ^ (r / q) := + (summable_and_Lr_rpow_le_Lp_mul_Lq_tsum_of_nonneg hpqr hf hg hf_sum hg_sum).2 + +theorem Lr_le_Lp_mul_Lq_tsum_of_nonneg (hpqr : p.HolderTriple q r) (hf : ∀ i, 0 ≤ f i) + (hg : ∀ i, 0 ≤ g i) (hf_sum : Summable fun i => f i ^ p) (hg_sum : Summable fun i => g i ^ q) : + (∑' i, (f i * g i) ^ r) ^ (1 / r) ≤ (∑' i, f i ^ p) ^ (1 / p) * (∑' i, g i ^ q) ^ (1 / q) := by + -- It's really inconvenient that `positivity` can't use `∀` hypotheses. + have hf' : 0 ≤ ∑' i, f i ^ p := tsum_nonneg fun i ↦ rpow_nonneg (hf i) p + have hg' : 0 ≤ ∑' i, g i ^ q := tsum_nonneg fun i ↦ rpow_nonneg (hg i) q + have hr := hpqr.pos' + convert rpow_le_rpow_iff (tsum_nonneg fun i ↦ rpow_nonneg (mul_nonneg (hf i) (hg i)) r) + (by apply mul_nonneg; all_goals apply rpow_nonneg; assumption) + (inv_eq_one_div r ▸ inv_pos.mpr hr) |>.mpr <| + Lr_rpow_le_Lp_mul_Lq_tsum_of_nonneg hpqr hf hg hf_sum hg_sum using 1 + rw [mul_rpow (rpow_nonneg hf' _) (rpow_nonneg hg' _), ← Real.rpow_mul hg', ← Real.rpow_mul hf'] + field_simp + +theorem inner_le_Lp_mul_Lq_tsum_of_nonneg (hpq : p.HolderConjugate q) (hf : ∀ i, 0 ≤ f i) (hg : ∀ i, 0 ≤ g i) (hf_sum : Summable fun i => f i ^ p) (hg_sum : Summable fun i => g i ^ q) : ∑' i, f i * g i ≤ (∑' i, f i ^ p) ^ (1 / p) * (∑' i, g i ^ q) ^ (1 / q) := - (inner_le_Lp_mul_Lq_tsum_of_nonneg hpq hf hg hf_sum hg_sum).2 + (summable_and_inner_le_Lp_mul_Lq_tsum_of_nonneg hpq hf hg hf_sum hg_sum).2 + +@[deprecated (since := "2026-02-12")] +alias inner_le_Lp_mul_Lq_of_nonneg' := inner_le_Lp_mul_Lq_of_nonneg /-- **Hölder inequality**: the scalar product of two functions is bounded by the product of their `L^p` and `L^q` norms when `p` and `q` are conjugate exponents. A version for `NNReal`-valued diff --git a/Mathlib/Analysis/Normed/Affine/AddTorsorBases.lean b/Mathlib/Analysis/Normed/Affine/AddTorsorBases.lean index 58d5a6a4531223..9ce6fe4f1ad9a8 100644 --- a/Mathlib/Analysis/Normed/Affine/AddTorsorBases.lean +++ b/Mathlib/Analysis/Normed/Affine/AddTorsorBases.lean @@ -113,14 +113,12 @@ theorem IsOpen.exists_subset_affineIndependent_span_eq_top {u : Set P} (hu : IsO (singleton_nonempty _) (affineIndependent_of_subsingleton _ _) with ⟨s, -, hsu, hs⟩ exact ⟨s, hsu, hs⟩ -set_option backward.isDefEq.respectTransparency false in /-- The affine span of a nonempty open set is `⊤`. -/ theorem IsOpen.affineSpan_eq_top {u : Set P} (hu : IsOpen u) (hne : u.Nonempty) : affineSpan ℝ u = ⊤ := let ⟨_, hsu, _, hs'⟩ := hu.exists_subset_affineIndependent_span_eq_top hne top_unique <| hs' ▸ affineSpan_mono _ hsu -set_option backward.isDefEq.respectTransparency false in theorem affineSpan_eq_top_of_nonempty_interior {s : Set V} (hs : (interior <| convexHull ℝ s).Nonempty) : affineSpan ℝ s = ⊤ := top_unique <| isOpen_interior.affineSpan_eq_top hs ▸ diff --git a/Mathlib/Analysis/Normed/Field/Krasner.lean b/Mathlib/Analysis/Normed/Field/Krasner.lean index d7847550851e0b..91c2c811c59ed2 100644 --- a/Mathlib/Analysis/Normed/Field/Krasner.lean +++ b/Mathlib/Analysis/Normed/Field/Krasner.lean @@ -69,7 +69,6 @@ theorem krasner [Field K] [Algebra K L] variable [NontriviallyNormedField K] [CompleteSpace K] [IsUltrametricDist K] [NormedAlgebra K L] [Algebra.IsAlgebraic K L] -set_option backward.isDefEq.respectTransparency false in /-- Krasner's lemma assuming `Normal K L`. -/ theorem of_completeSpace_of_normal [Normal K L] : IsKrasner K L where krasner' {x} {y} xsep sp yint kr := by diff --git a/Mathlib/Analysis/Normed/Group/Submodule.lean b/Mathlib/Analysis/Normed/Group/Submodule.lean index e0f832a68cc37d..dc2c4f9ef9abe2 100644 --- a/Mathlib/Analysis/Normed/Group/Submodule.lean +++ b/Mathlib/Analysis/Normed/Group/Submodule.lean @@ -45,3 +45,11 @@ instance normedAddCommGroup [Ring 𝕜] [NormedAddCommGroup E] [Module 𝕜 E] eq_of_dist_eq_zero := eq_of_dist_eq_zero } end Submodule + +@[continuity, fun_prop] +theorem LinearMap.continuous_domRestrict {R R' M M' : Type*} [Semiring R] [Semiring R'] + [AddCommMonoid M] [AddCommMonoid M'] [Module R M] [Module R' M'] {σ₁₂ : R →+* R'} + (f : M →ₛₗ[σ₁₂] M') [TopologicalSpace M] [TopologicalSpace M'] (hf : Continuous f) + (p : Submodule R M) : Continuous (f.domRestrict p) := by + rw [coe_domRestrict] + fun_prop diff --git a/Mathlib/Analysis/Normed/Lp/Matrix.lean b/Mathlib/Analysis/Normed/Lp/Matrix.lean index dd3775f949a099..bbe4769e298c51 100644 --- a/Mathlib/Analysis/Normed/Lp/Matrix.lean +++ b/Mathlib/Analysis/Normed/Lp/Matrix.lean @@ -7,6 +7,7 @@ Authors: Eric Wieser module public import Mathlib.Analysis.Normed.Lp.PiLp +public import Mathlib.LinearAlgebra.Determinant /-! # Matrices are isomorphic with linear maps between Lp spaces @@ -87,3 +88,8 @@ theorem toLpLin_symm_pow (A : Module.End R (WithLp p (n → R))) (k : ℕ) : map_pow (toLpLinAlgEquiv p).symm A k end Matrix + +@[simp] +theorem LinearMap.det_toLpLin {ι R : Type*} [Fintype ι] [DecidableEq ι] [CommRing R] (p : ℝ≥0∞) + (m : Matrix ι ι R) : (m.toLpLin p p).det = m.det := by + simp [Matrix.toLpLin_eq_toLin] diff --git a/Mathlib/Analysis/Normed/Lp/PiLp.lean b/Mathlib/Analysis/Normed/Lp/PiLp.lean index ae8d24754881aa..51c0b3ab395673 100644 --- a/Mathlib/Analysis/Normed/Lp/PiLp.lean +++ b/Mathlib/Analysis/Normed/Lp/PiLp.lean @@ -137,6 +137,67 @@ end lemma toLp_apply (x : ∀ i, α i) (i : ι) : toLp p x i = x i := rfl +section Single +variable [DecidableEq ι] +variable {β} + +section Zero +variable [∀ i, Zero (β i)] + +/-- The vector given in `PiLp` by being `a : β i` at coordinate `i : ι` and `0 : β j` at +all other coordinates `j`. -/ +def single (i : ι) (a : β i) : PiLp p β := toLp p (Pi.single i a) + +@[simp] +lemma ofLp_single (i : ι) (a : β i) : ofLp (single p i a) = Pi.single i a := rfl + +@[simp] +lemma toLp_single (i : ι) (a : β i) : toLp p (Pi.single i a) = single p i a := rfl + +@[simp] +lemma single_eq_same (i : ι) (a : β i) : single p i a i = a := by + rw [ofLp_single, Pi.single_eq_same] + +@[simp] +lemma single_eq_of_ne {i i' : ι} (h : i' ≠ i) (a : β i) : single p i a i' = 0 := by + rw [ofLp_single, Pi.single_eq_of_ne h] + +/-- Changing the hypothesis direction in `PiLp.single_eq_of_ne` for for ease of use by simp. -/ +@[simp] +lemma single_eq_of_ne' {i i' : ι} (h : i ≠ i') (a : β i) : single p i a i' = 0 := by + rw [ofLp_single, Pi.single_eq_of_ne' h] + +end Zero + +@[simp] +lemma single_apply [Zero 𝕜] (i : ι) (a : 𝕜) (j : ι) : + (single p i a : PiLp p (fun _ ↦ 𝕜)) j = ite (j = i) a 0 := by + rw [← toLp_single, PiLp.toLp_apply, ← Pi.single_apply i a j] + +section AddCommGroup +variable [∀ i, AddCommGroup (β i)] + +@[simp] +theorem single_eq_zero_iff (p : ℝ≥0∞) (i : ι) {a : β i} : + single p i a = 0 ↔ a = 0 := + (toLp_eq_zero p).trans Pi.single_eq_zero_iff + +lemma single_add (p : ℝ≥0∞) (i : ι) {a b : β i} : + single p i (a + b) = single p i a + single p i b := by + simp_rw [← toLp_single, Pi.single_add, toLp_add] + +lemma single_sub (p : ℝ≥0∞) (i : ι) {a b : β i} : + single p i (a - b) = single p i a - single p i b := by + simp_rw [← toLp_single, Pi.single_sub, toLp_sub] + +lemma single_neg (p : ℝ≥0∞) (i : ι) {a : β i} : + single p i (-a) = -single p i a := by + simp_rw [← toLp_single, Pi.single_neg, toLp_neg] + +end AddCommGroup + +end Single + section DistNorm variable [Fintype ι] @@ -798,8 +859,7 @@ theorem _root_.LinearIsometryEquiv.piLpCongrLeft_symm (e : ι ≃ ι') : @[simp high] theorem _root_.LinearIsometryEquiv.piLpCongrLeft_single [DecidableEq ι] [DecidableEq ι'] (e : ι ≃ ι') (i : ι) (v : E) : - LinearIsometryEquiv.piLpCongrLeft p 𝕜 E e (toLp p <| Pi.single i v) = - toLp p (Pi.single (e i) v) := by + LinearIsometryEquiv.piLpCongrLeft p 𝕜 E e (single p i v) = single p (e i) v := by ext x simp [LinearIsometryEquiv.piLpCongrLeft_apply, Equiv.piCongrLeft', Pi.single, Function.update, Equiv.symm_apply_eq] @@ -847,8 +907,7 @@ theorem _root_.LinearIsometryEquiv.piLpCongrRight_symm (e : ∀ i, α i ≃ₗ @[simp high] theorem _root_.LinearIsometryEquiv.piLpCongrRight_single (e : ∀ i, α i ≃ₗᵢ[𝕜] β i) [DecidableEq ι] (i : ι) (v : α i) : - LinearIsometryEquiv.piLpCongrRight p e (toLp p <| Pi.single i v) = - toLp p (Pi.single i (e _ v)) := + LinearIsometryEquiv.piLpCongrRight p e (single p i v) = single p i (e _ v) := PiLp.ext <| Pi.apply_single (e ·) (fun _ => map_zero _) _ _ end piLpCongrRight @@ -927,8 +986,7 @@ variable [DecidableEq ι] set_option backward.isDefEq.respectTransparency false in @[simp] -theorem nnnorm_toLp_single (i : ι) (b : β i) : - ‖toLp p (Pi.single i b)‖₊ = ‖b‖₊ := by +theorem nnnorm_single (i : ι) (b : β i) : ‖single p i b‖₊ = ‖b‖₊ := by haveI : Nonempty ι := ⟨i⟩ induction p generalizing hp with | top => @@ -936,37 +994,60 @@ theorem nnnorm_toLp_single (i : ι) (b : β i) : refine ciSup_eq_of_forall_le_of_forall_lt_exists_gt (fun j => ?_) fun n hn => ⟨i, hn.trans_eq ?_⟩ · obtain rfl | hij := Decidable.eq_or_ne i j - · rw [Pi.single_eq_same] - · rw [Pi.single_eq_of_ne' hij, nnnorm_zero] + · rw [single_eq_same] + · rw [single_eq_of_ne' _ hij, nnnorm_zero] exact zero_le _ - · rw [Pi.single_eq_same] + · rw [single_eq_same] | coe p => have hp0 : (p : ℝ) ≠ 0 := mod_cast (zero_lt_one.trans_le <| Fact.out (p := 1 ≤ (p : ℝ≥0∞))).ne' rw [nnnorm_eq_sum ENNReal.coe_ne_top, ENNReal.coe_toReal, Fintype.sum_eq_single i, - toLp_apply, Pi.single_eq_same, ← NNReal.rpow_mul, one_div, + toLp_apply, single_eq_same, ← NNReal.rpow_mul, one_div, mul_inv_cancel₀ hp0, NNReal.rpow_one] intro j hij - rw [toLp_apply, Pi.single_eq_of_ne hij, nnnorm_zero, NNReal.zero_rpow hp0] + rw [toLp_apply, single_eq_of_ne _ hij, nnnorm_zero, NNReal.zero_rpow hp0] + +@[deprecated nnnorm_single (since := "2026-03-15")] +theorem nnnorm_toLp_single (i : ι) (b : β i) : ‖toLp p (Pi.single i b)‖₊ = ‖b‖₊ := + nnnorm_single p β i b @[simp] +lemma norm_single (i : ι) (b : β i) : ‖single p i b‖ = ‖b‖ := + congr_arg ((↑) : ℝ≥0 → ℝ) <| nnnorm_single p β i b + +@[deprecated norm_single (since := "2026-03-15")] lemma norm_toLp_single (i : ι) (b : β i) : ‖toLp p (Pi.single i b)‖ = ‖b‖ := - congr_arg ((↑) : ℝ≥0 → ℝ) <| nnnorm_toLp_single p β i b + norm_single p β i b @[simp] +lemma nndist_single_same (i : ι) (b₁ b₂ : β i) : + nndist (single p i b₁) (single p i b₂) = nndist b₁ b₂ := by + rw [nndist_eq_nnnorm, nndist_eq_nnnorm, ← single_sub, nnnorm_single] + +@[deprecated nndist_single_same (since := "2026-03-15")] lemma nndist_toLp_single_same (i : ι) (b₁ b₂ : β i) : - nndist (toLp p (Pi.single i b₁)) (toLp p (Pi.single i b₂)) = nndist b₁ b₂ := by - rw [nndist_eq_nnnorm, nndist_eq_nnnorm, ← toLp_sub, ← Pi.single_sub, nnnorm_toLp_single] + nndist (toLp p (Pi.single i b₁)) (toLp p (Pi.single i b₂)) = nndist b₁ b₂ := + nndist_single_same p β i b₁ b₂ @[simp] +lemma dist_single_same (i : ι) (b₁ b₂ : β i) : + dist (single p i b₁) (single p i b₂) = dist b₁ b₂ := + congr_arg ((↑) : ℝ≥0 → ℝ) <| nndist_single_same p β i b₁ b₂ + +@[deprecated dist_single_same (since := "2026-03-15")] lemma dist_toLp_single_same (i : ι) (b₁ b₂ : β i) : dist (toLp p (Pi.single i b₁)) (toLp p (Pi.single i b₂)) = dist b₁ b₂ := - congr_arg ((↑) : ℝ≥0 → ℝ) <| nndist_toLp_single_same p β i b₁ b₂ + dist_single_same p β i b₁ b₂ @[simp] +lemma edist_single_same (i : ι) (b₁ b₂ : β i) : + edist (single p i b₁) (single p i b₂) = edist b₁ b₂ := by + simp only [edist_nndist, nndist_single_same p β i b₁ b₂] + +@[deprecated edist_single_same (since := "2026-03-15")] lemma edist_toLp_single_same (i : ι) (b₁ b₂ : β i) : - edist (toLp p (Pi.single i b₁)) (toLp p (Pi.single i b₂)) = edist b₁ b₂ := by - simp only [edist_nndist, nndist_toLp_single_same p β i b₁ b₂] + edist (toLp p (Pi.single i b₁)) (toLp p (Pi.single i b₂)) = edist b₁ b₂ := + edist_single_same p β i b₁ b₂ end Single @@ -1061,8 +1142,8 @@ def basisFun : Basis ι 𝕜 (PiLp p fun _ : ι => 𝕜) := @[simp] theorem basisFun_apply [DecidableEq ι] (i) : - basisFun p 𝕜 ι i = toLp p (Pi.single i 1) := by - simp_rw [basisFun, Basis.coe_ofEquivFun, WithLp.coe_symm_linearEquiv] + basisFun p 𝕜 ι i = single p i 1 := by + simp_rw [basisFun, Basis.coe_ofEquivFun, WithLp.coe_symm_linearEquiv, toLp_single] @[simp] theorem basisFun_repr (x : PiLp p fun _ : ι => 𝕜) (i : ι) : (basisFun p 𝕜 ι).repr x i = x i := diff --git a/Mathlib/Analysis/Normed/Lp/SmoothApprox.lean b/Mathlib/Analysis/Normed/Lp/SmoothApprox.lean index d2d78a893ff66f..db401a5fba0e7a 100644 --- a/Mathlib/Analysis/Normed/Lp/SmoothApprox.lean +++ b/Mathlib/Analysis/Normed/Lp/SmoothApprox.lean @@ -5,8 +5,12 @@ Authors: Moritz Doll -/ module -public import Mathlib.Geometry.Manifold.SmoothApprox -public import Mathlib.MeasureTheory.Function.ContinuousMapDense +public import Mathlib.Analysis.Calculus.ContDiff.Defs +public import Mathlib.LinearAlgebra.FiniteDimensional.Defs +public import Mathlib.MeasureTheory.Function.LpSpace.Basic + +import Mathlib.Geometry.Manifold.SmoothApprox +import Mathlib.MeasureTheory.Function.ContinuousMapDense /-! diff --git a/Mathlib/Analysis/Normed/Module/Bases.lean b/Mathlib/Analysis/Normed/Module/Bases.lean new file mode 100644 index 00000000000000..1b6048851295e2 --- /dev/null +++ b/Mathlib/Analysis/Normed/Module/Bases.lean @@ -0,0 +1,525 @@ +/- +Copyright (c) 2025 Michał Świętek. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Michał Świętek +-/ +module + +public import Mathlib.Analysis.Normed.Group.InfiniteSum +public import Mathlib.Analysis.Normed.Operator.BanachSteinhaus +public import Mathlib.LinearAlgebra.FiniteDimensional.Lemmas +public import Mathlib.Topology.Algebra.Module.FiniteDimension + +/-! +# Schauder Bases and Generalized Bases + +This file defines the theory of bases in Banach spaces, unifying the classical +sequential notion with modern generalized bases. + +## Overview + +A **basis** in a normed space allows every vector to be expanded as a (potentially infinite) linear +combination of basis vectors. Historically, this was defined strictly for sequences with convergence +of partial sums (the "classical Schauder basis"). + +However, modern functional analysis requires bases indexed by arbitrary sets +`β` (e.g., for non-separable spaces or Hilbert spaces), where convergence +is defined via nets over finite subsets (unconditional convergence). + +This file provides a unified structure `GeneralSchauderBasis` that captures both: +* **Classical Schauder Bases:** Indexed by `ℕ`, using `SummationFilter.conditional` + to enforce sequential convergence of partial sums. +* **Unconditional/Extended Bases:** Indexed by an arbitrary type `β`, using + `SummationFilter.unconditional` to enforce convergence of the net of all finite subsets. + +## Main Definitions + +* `GeneralSchauderBasis β 𝕜 X L`: A structure representing a generalized Schauder basis for a + normed space `X` over a field `𝕜`, indexed by a type `β` with a `SummationFilter L`. +* `SchauderBasis 𝕜 X`: The classical Schauder basis, an abbreviation for + `GeneralSchauderBasis ℕ 𝕜 X (SummationFilter.conditional ℕ)`. +* `UnconditionalSchauderBasis β 𝕜 X`: An unconditional Schauder basis, an abbreviation for + `GeneralSchauderBasis β 𝕜 X (SummationFilter.unconditional β)`. +* `GeneralSchauderBasis.proj b A`: The projection onto a finite set `A` of basis vectors, + mapping `x ↦ ∑ i ∈ A, b.coord i x • b i`. +* `SchauderBasis.proj b n`: The `n`-th projection `X → X`, + mapping `x ↦ ∑ i ∈ Finset.range n, b.coord i x • b i`. +* `UnconditionalSchauderBasis.enormProjBound`: The supremum of projection norms (`ℝ≥0∞`). +* `UnconditionalSchauderBasis.nnnormProjBound`: The supremum of projection norms (`ℝ≥0`), + requires `[CompleteSpace X]`. +* `RankOneDecomposition 𝕜 X`: Data for constructing a Schauder basis from + a sequence of finite-rank projections whose differences are rank one. +* `RankOneDecomposition.basis`: Constructs a `SchauderBasis` from a `RankOneDecomposition`. + +## Main Results + +* `GeneralSchauderBasis.linearIndependent`: A Schauder basis is linearly independent. +* `GeneralSchauderBasis.tendsto_proj`: The projections `proj A` converge to identity + along the summation filter. +* `GeneralSchauderBasis.range_proj_eq_span`: The range of `proj A` is the span of the basis + elements in `A`. +* `GeneralSchauderBasis.proj_comp`: Composition of projections satisfies + `proj A (proj B x) = proj (A ∩ B) x`. +* `SchauderBasis.exists_norm_proj_le`: In a Banach space, the projections are uniformly bounded. +* `UnconditionalSchauderBasis.exists_norm_proj_le`: For unconditional bases, projections + onto all finite sets are uniformly bounded. +## References + +* [Albiac, Fernando. and Kalton, Nigel J., Topics in Banach Space Theory][Albiac_Kalton_2016]. +* [Singer, Ivan, Bases in Banach spaces][Singer_1970]. +* [Marti, Jürg T., Introduction to the theory of bases][MartiJurg1969]. + +-/ + +@[expose] public section + +noncomputable section + +open Filter Topology LinearMap Set ENNReal NNReal + +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] +variable {X : Type*} [NormedAddCommGroup X] [NormedSpace 𝕜 X] + +open scoped Classical in +/-- +A generalized Schauder basis indexed by `β` with summation along filter `L`. + +The key fields are: +* `basis`: The basis vectors `e i` for `i : β` +* `coord`: The coordinate functionals `f i` for `i : β` in the dual space +* `ortho`: Biorthogonality condition `f i (e j) = if i = j then 1 else 0` +* `expansion`: Every `x` equals `∑ i, f i x • e i`, converging along `L` + +See `SchauderBasis` for the classical `ℕ`-indexed case with conditional convergence, +and `UnconditionalSchauderBasis` for the unconditional case. +-/ +@[ext] +structure GeneralSchauderBasis (β : Type*) (𝕜 : Type*) + (X : Type*) [NontriviallyNormedField 𝕜] [NormedAddCommGroup X] [NormedSpace 𝕜 X] + (L : SummationFilter β) where + /-- The basis vectors. -/ + basis : β → X + /-- Coordinate functionals. -/ + coord : β → StrongDual 𝕜 X + /-- Biorthogonality. -/ + ortho (i j : β) : coord i (basis j) = (Pi.single j (1 : 𝕜) : β → 𝕜) i + /-- The sum converges to `x` along the provided `SummationFilter L`. -/ + expansion (x : X) : HasSum (fun i ↦ (coord i) x • basis i) x L + +variable {β : Type*} +variable {L : SummationFilter β} + +/-- A classical Schauder basis indexed by `ℕ` with conditional convergence. -/ +abbrev SchauderBasis (𝕜 : Type*) (X : Type*) [NontriviallyNormedField 𝕜] + [NormedAddCommGroup X] [NormedSpace 𝕜 X] := + GeneralSchauderBasis ℕ 𝕜 X (SummationFilter.conditional ℕ) + +/-- +An unconditional Schauder basis indexed by `β`. + +In the literature, this is known as: +* An **Extended Basis** [Marti, Jürg T., Introduction to the theory of bases][MartiJurg1969]: +Defined via convergence of the net of finite partial sums. +* An **Unconditional Basis** [Singer, Ivan., Bases in Banach spaces][Singer_1970]: On an arbitrary +set, convergence is necessarily unconditional. + +This structure generalizes the classical Schauder basis by replacing sequential +convergence with summability over the directed set of finite subsets. +-/ +abbrev UnconditionalSchauderBasis (β : Type*) + (𝕜 : Type*) (X : Type*) [NontriviallyNormedField 𝕜] [NormedAddCommGroup X] [NormedSpace 𝕜 X] := + GeneralSchauderBasis β 𝕜 X (SummationFilter.unconditional β) + +/-- Coercion from a `GeneralSchauderBasis` to the underlying basis function. -/ +instance : CoeFun (GeneralSchauderBasis β 𝕜 X L) (fun _ ↦ β → X) where + coe b := b.basis +attribute [coe] GeneralSchauderBasis.basis +namespace GeneralSchauderBasis + +variable (b : GeneralSchauderBasis β 𝕜 X L) + +/-- The basis vectors are linearly independent. -/ +theorem linearIndependent : LinearIndependent 𝕜 b := by + classical + refine linearIndependent_iff.mpr (fun l hl ↦ l.ext ?_) + simpa [l.linearCombination_apply, Finsupp.sum, b.ortho, Pi.single_apply] using + fun i ↦ congr_arg (b.coord i) hl + +/-- Projection onto a finite set of basis vectors. -/ +def proj (A : Finset β) : X →L[𝕜] X := ∑ i ∈ A, (b.coord i).smulRight (b i) + +/-- The projection on the empty set is the zero map. -/ +@[simp] +theorem proj_empty : b.proj ∅ = 0 := by simp [proj] + +/-- The action of the projection on a vector `x`. -/ +@[simp] +theorem proj_apply (A : Finset β) (x : X) : b.proj A x = ∑ i ∈ A, b.coord i x • b i := by + simp [proj, ContinuousLinearMap.sum_apply, ContinuousLinearMap.smulRight_apply] + +open scoped Classical in +/-- The action of the projection on a basis element `e i`. -/ +theorem proj_apply_basis_mem (A : Finset β) (i : β) : + b.proj A (b i) = if i ∈ A then b i else 0 := by + simp [b.ortho, Pi.single_apply] + +/-- The projections `b.proj A x` converge to `x` along the summation filter. -/ +theorem tendsto_proj (x : X) : Tendsto (fun A ↦ b.proj A x) L.filter (𝓝 x) := by + simpa using b.expansion x + +/-- The range of the projection is the span of the basis elements in `A`. -/ +theorem range_proj_eq_span (A : Finset β) : + (b.proj A).toLinearMap.range = Submodule.span 𝕜 (b '' A) := by + apply le_antisymm + · rintro _ ⟨x, rfl⟩ + rw [ContinuousLinearMap.coe_coe, proj_apply] + exact Submodule.sum_mem _ fun i hi ↦ + Submodule.smul_mem _ _ (Submodule.subset_span ⟨i, hi, rfl⟩) + · rw [Submodule.span_le] + rintro _ ⟨i, hi, rfl⟩ + use b i + rw [ContinuousLinearMap.coe_coe, proj_apply_basis_mem, if_pos (Finset.mem_coe.mp hi)] + +open Classical in +/-- Composition of projections: `proj A (proj B x) = proj (A ∩ B) x`. -/ +theorem proj_comp (A B : Finset β) (x : X) : b.proj A (b.proj B x) = b.proj (A ∩ B) x := by + simp only [proj_apply, map_sum, map_smul, b.ortho, Pi.single_apply, ite_smul, one_smul, zero_smul, + Finset.sum_ite_eq', smul_ite, smul_zero, Finset.sum_ite_mem] + congr 1 + ext _ + simp [and_comm] + +/-- The dimension of the range of the projection `proj A` equals the cardinality of `A`. -/ +theorem finrank_range_proj (A : Finset β) : + Module.finrank 𝕜 (b.proj A).toLinearMap.range = A.card := by + rw [range_proj_eq_span, Set.image_eq_range, finrank_span_eq_card] + · exact Fintype.card_coe A + · exact b.linearIndependent.comp (fun i : A ↦ i.val) Subtype.val_injective + +end GeneralSchauderBasis + +/-! ### Unconditional Schauder bases -/ + +namespace UnconditionalSchauderBasis + +variable (b : UnconditionalSchauderBasis β 𝕜 X) + +/-- The basis constant for unconditional bases (supremum over all finite sets) as `enorm`. -/ +noncomputable def enormProjBound : ℝ≥0∞ := ⨆ A : Finset β, ‖b.proj A‖ₑ + +/-- The `enorm` of any projection is bounded by the basis constant. -/ +theorem enorm_proj_le_enormProjBound (A : Finset β) : ‖b.proj A‖ₑ ≤ b.enormProjBound := + le_iSup (fun A ↦ ‖b.proj A‖ₑ) A + +/-- Projections are uniformly bounded for unconditional bases. -/ +theorem exists_norm_proj_le [CompleteSpace X] : ∃ C : ℝ, ∀ A : Finset β, ‖b.proj A‖ ≤ C := by + classical + apply banach_steinhaus + intro x + obtain ⟨A₀, hA₀⟩ := summable_iff_vanishing_norm.mp (b.expansion x).summable 1 zero_lt_one + use (A₀.powerset.image fun B ↦ ‖b.proj B x‖).sup' ((Finset.powerset_nonempty A₀).image _) id + 1 + intro A + have hdecomp : b.proj A x = b.proj (A ∩ A₀) x + b.proj (A \ A₀) x := by + simp only [GeneralSchauderBasis.proj_apply] + rw [← Finset.sum_union (Finset.disjoint_sdiff_inter A A₀).symm, + Finset.union_comm, Finset.sdiff_union_inter] + rw [hdecomp] + -- -- The projection on the tail (A \ A₀) at `x` is bounded by 1 + have htail : ‖b.proj (A \ A₀) x‖ < 1 := by + rw [GeneralSchauderBasis.proj_apply] + exact hA₀ (A \ A₀) Finset.sdiff_disjoint + apply (norm_add_le _ _).trans (add_le_add _ htail.le) + -- The projection on (A ∩ A₀) at `x` is bounded by the `sup'`. + exact Finset.le_sup' id <| Finset.mem_image_of_mem (fun B ↦ ‖b.proj B x‖) + (Finset.mem_powerset.2 Finset.inter_subset_right) + +/-- The basis constant for unconditional bases (supremum over all finite sets) as `nnnorm`. + It requires completeness to guarantee that the supremum is finite, + see lemma `bddAbove_range_nnnorm_proj` below. -/ +noncomputable def nnnormProjBound : ℝ≥0 := ⨆ A : Finset β, ‖b.proj A‖₊ + +/-- The projection norms are bounded above in a complete space. -/ +theorem bddAbove_range_nnnorm_proj [CompleteSpace X] : + BddAbove (Set.range (fun A : Finset β ↦ ‖b.proj A‖₊)) := by + obtain ⟨C, hC⟩ := b.exists_norm_proj_le + have hCpos : 0 ≤ C := by simpa [GeneralSchauderBasis.proj_empty] using hC ∅ + refine ⟨C.toNNReal, ?_⟩ + rintro _ ⟨A, rfl⟩ + rw [← NNReal.coe_le_coe, Real.coe_toNNReal C hCpos, coe_nnnorm] + exact hC A + +/-- The `nnnorm` of any projection is bounded by the basis constant. -/ +theorem nnnorm_proj_le_nnnormProjBound [CompleteSpace X] (A : Finset β) : + ‖b.proj A‖₊ ≤ b.nnnormProjBound := + le_ciSup (bddAbove_range_nnnorm_proj b) A + +/-- The norm of any projection is bounded by the basis constant. -/ +theorem norm_proj_le_nnnormProjBound [CompleteSpace X] (A : Finset β) : + ‖b.proj A‖ ≤ b.nnnormProjBound := + mod_cast b.nnnorm_proj_le_nnnormProjBound A + +end UnconditionalSchauderBasis + +/-! ### ℕ-indexed Schauder bases with conditional convergence -/ + +namespace SchauderBasis + +variable (b : SchauderBasis 𝕜 X) + +/-- The `n`-th projection `P_n = b.proj (Finset.range n)`, given by: + `P_n x = ∑ i ∈ Finset.range n, b.coord i x • b i` -/ +def proj (n : ℕ) : X →L[𝕜] X := GeneralSchauderBasis.proj b (Finset.range n) + +/-- The projection at `0` is the zero map. -/ +@[simp] +theorem proj_zero : b.proj 0 = 0 := by rw [proj, Finset.range_zero, GeneralSchauderBasis.proj_empty] + +/-- The action of the projection on a vector. -/ +@[simp] +theorem proj_apply (n : ℕ) (x : X) : b.proj n x = ∑ i ∈ Finset.range n, b.coord i x • b i := by + rw [proj, GeneralSchauderBasis.proj_apply] + +/-- The action of the projection on a basis element `e i`. -/ +theorem proj_apply_basis_mem (n i : ℕ) : b.proj n (b i) = if i < n then b i else 0 := by + rw [proj, GeneralSchauderBasis.proj_apply_basis_mem] + simp + +/-- The range of the projection is the span of the first `n` basis elements. -/ +theorem range_proj_eq_span (n : ℕ) : + (b.proj n).toLinearMap.range = Submodule.span 𝕜 (b '' ↑(Finset.range n)) := by + rw [proj, GeneralSchauderBasis.range_proj_eq_span] + +/-- The dimension of the range of the projection `P n` is `n`. -/ +theorem finrank_range_proj (n : ℕ) : + Module.finrank 𝕜 (b.proj n).toLinearMap.range = n := by + rw [proj, GeneralSchauderBasis.finrank_range_proj, Finset.card_range] + +/-- The projections converge pointwise to the identity map. -/ +theorem tendsto_proj (x : X) : Tendsto (fun n ↦ b.proj n x) atTop (𝓝 x) := by + have := GeneralSchauderBasis.tendsto_proj b x + rwa [SummationFilter.conditional_filter_eq_map_range] at this + +/-- Composition of projections: `proj n (proj m x) = proj (min n m) x`. -/ +theorem proj_comp (n m : ℕ) (x : X) : b.proj n (b.proj m x) = b.proj (min n m) x := by + simp only [proj, GeneralSchauderBasis.proj_comp] + congr 2 + ext _ + simp only [Finset.mem_inter, Finset.mem_range] + omega + +/-- The projections are uniformly bounded. -/ +theorem exists_norm_proj_le [CompleteSpace X] : ∃ C : ℝ, ∀ n : ℕ, ‖b.proj n‖ ≤ C := by + apply banach_steinhaus + intro x + obtain ⟨M, hM⟩ := isBounded_iff_forall_norm_le.mp + (Metric.isBounded_range_of_tendsto (fun n ↦ b.proj n x) (tendsto_proj b x)) + exact ⟨M, Set.forall_mem_range.mp hM⟩ + +/-- The basis constant for Schauder bases (supremum over projections) as `enorm`. -/ +noncomputable def enormProjBound : ℝ≥0∞ := ⨆ n, ‖b.proj n‖ₑ + +/-- The enorm of any projection is bounded by the basis constant. -/ +theorem enorm_proj_le_enormProjBound (n : ℕ) : ‖b.proj n‖ₑ ≤ b.enormProjBound := + le_iSup (fun i ↦ ‖b.proj i‖ₑ) n + +/-- The basis constant for Schauder bases (supremum over projections) as `nnnorm`. + Requires completeness to guarantee the supremum is finite, + see lemma `bddAbove_range_nnnorm_proj` below. -/ +noncomputable def nnnormProjBound : ℝ≥0 := ⨆ n, ‖b.proj n‖₊ + +/-- The projection norms are bounded above in a complete space. -/ +theorem bddAbove_range_nnnorm_proj [CompleteSpace X] : + BddAbove (Set.range (fun n : ℕ ↦ ‖b.proj n‖₊)) := by + obtain ⟨C, hC⟩ := b.exists_norm_proj_le + have hCpos : 0 ≤ C := by simpa [proj_zero] using hC 0 + refine ⟨C.toNNReal, ?_⟩ + rintro _ ⟨n, rfl⟩ + rw [← NNReal.coe_le_coe, Real.coe_toNNReal C hCpos, coe_nnnorm] + exact hC n + +/-- The `nnnorm` of any projection is bounded by the basis constant. -/ +theorem nnnorm_proj_le_nnnormProjBound [CompleteSpace X] (n : ℕ) : + ‖b.proj n‖₊ ≤ b.nnnormProjBound := + le_ciSup (bddAbove_range_nnnorm_proj b) n + +/-- The norm of any projection is bounded by the basis constant. -/ +theorem norm_proj_le_nnnormProjBound [CompleteSpace X] (n : ℕ) : + ‖b.proj n‖ ≤ b.nnnormProjBound := + mod_cast b.nnnorm_proj_le_nnnormProjBound n + +/-! +### Construction of Schauder basis + +We explain how to construct a Schauder basis from a sequence `P n` of projections +satisfying `P n ∘ P m = P (min n m)`, converging to the identity pointwise, and such that each +`P (n+1) - P n` has rank one. The idea is to define the basis vectors as +`e n = (P (n+1) - P n) x` for some `x` such that this is non-zero, and then +show that these vectors form a Schauder basis. -/ + +/-- The difference operator `P (n + 1) - P n`. -/ +def succSub (P : ℕ → X →L[𝕜] X) (n : ℕ) : X →L[𝕜] X := P (n + 1) - P n + +/-- The sum of `succSub` operators up to `n` equals `P n`. -/ +@[simp] +lemma sum_succSub (P : ℕ → X →L[𝕜] X) (h0 : P 0 = 0) (n : ℕ) : + ∑ i ∈ Finset.range n, succSub P i = P n := by + induction n with + | zero => simp [h0] + | succ n ih => rw [Finset.sum_range_succ, ih, succSub]; abel + +/-- The operators `succSub P i` satisfy a biorthogonality relation. -/ +lemma succSub_ortho {P : ℕ → X →L[𝕜] X} (hcomp : ∀ n m, ∀ x : X, P n (P m x) = P (min n m) x) + (i j : ℕ) (x : X) : succSub P i (succSub P j x) = if i = j then succSub P j x else 0 := by + simp only [succSub, ContinuousLinearMap.sub_apply, map_sub, hcomp, + Nat.add_min_add_right] + split_ifs with h + · rw [h, min_self, min_eq_right (Nat.le_succ j), Nat.min_eq_left (Nat.le_succ j)] + abel + · rcases Nat.lt_or_gt_of_ne h with h' | h' + · rw [min_eq_left_of_lt h', min_eq_left (Nat.succ_le_of_lt h'), + min_eq_left_of_lt (Nat.lt_succ_of_lt h')] + abel + · rw [min_eq_right_of_lt h', min_eq_right (Nat.succ_le_of_lt h'), + min_eq_right_of_lt (Nat.lt_succ_of_lt h')] + abel + +/-- Assuming that the `finrank` of the range of `P n` is `n` then the `finrank` of the range of + `succSub P n` is `1`. -/ +lemma finrank_range_succSub_eq_one {P : ℕ → X →L[𝕜] X} + (hrank : ∀ n, Module.finrank 𝕜 (P n).toLinearMap.range = n) + (hcomp : ∀ n m, ∀ x : X, P n (P m x) = P (min n m) x) (n : ℕ) : + Module.finrank 𝕜 (succSub P n).toLinearMap.range = 1 := by + let U := (succSub P n).toLinearMap.range + let V := (P n).toLinearMap.range + let W := (P (n + 1)).toLinearMap.range + have hV : V ≤ W := by + rintro _ ⟨y, rfl⟩ + exact ⟨P n y, by simp [ContinuousLinearMap.coe_coe, hcomp]⟩ + have hUW : U ≤ W := by + rintro _ ⟨y, rfl⟩ + exact Submodule.sub_mem W ⟨y, rfl⟩ (hV ⟨y, rfl⟩) + have hW : W = U ⊔ V := by + apply le_antisymm + · rintro x ⟨y, hy⟩ + rw [← hy, ContinuousLinearMap.coe_coe, ← sub_add_cancel ((P (n + 1)) y) ((P n) y)] + exact Submodule.add_mem_sup ⟨y, rfl⟩ ⟨y, rfl⟩ + · exact sup_le hUW hV + have hdisj : U ⊓ V = ⊥ := eq_bot_iff.mpr fun x ⟨⟨y, hy⟩, ⟨z, hz⟩⟩ ↦ by + simp only [Submodule.mem_bot] + calc x = (P n) x := by rw [← hz, ContinuousLinearMap.coe_coe, hcomp, min_self] + _ = 0 := by rw [← hy, ContinuousLinearMap.coe_coe]; simp [succSub, map_sub, hcomp] + have : FiniteDimensional 𝕜 W := .of_finrank_pos (by rw [hrank]; exact Nat.succ_pos n) + have : FiniteDimensional 𝕜 U := Submodule.finiteDimensional_of_le hUW + have : FiniteDimensional 𝕜 V := Submodule.finiteDimensional_of_le hV + have h_dim := Submodule.finrank_sup_add_finrank_inf_eq U V + rw [hdisj, finrank_bot, add_zero, ← hW, hrank, hrank, Nat.add_comm] at h_dim + exact Nat.add_right_cancel h_dim.symm + +variable (𝕜 X) in +/-- Data for constructing a Schauder basis from a sequence of finite-rank projections. + +Given a sequence of continuous linear maps `P n : X →L[𝕜] X` satisfying: +* `P 0 = 0` and `finrank(range(P n)) = n`, +* `P n ∘ P m = P (min n m)` (the projections are nested and commute), +* `P n x → x` for every `x` (pointwise convergence to the identity), + +the differences `succSub P n = P (n+1) - P n` are rank-one operators +(see `finrank_range_succSub_eq_one`). Choosing a nonzero vector `e n` in the range of each +`succSub P n` yields a Schauder basis for `X`. + +Use `RankOneDecomposition.basis` to construct the `SchauderBasis` from this data. -/ +structure RankOneDecomposition where + /-- The sequence of finite-rank projections. -/ + P : ℕ → X →L[𝕜] X + /-- The sequence of candidate basis vectors. -/ + e : ℕ → X + /-- The projections start at `0`. -/ + proj_zero : P 0 = 0 + /-- The `n`-th projection has rank `n`. -/ + finrank_range (n : ℕ) : Module.finrank 𝕜 (P n).toLinearMap.range = n + /-- The projections commute and are nested `P n (P m) = P (min n m)`. -/ + proj_comp (n m : ℕ) (x : X) : P n (P m x) = P (min n m) x + /-- The projections converge pointwise to the identity. -/ + proj_tendsto (x : X) : Tendsto (fun n ↦ P n x) atTop (𝓝 x) + /-- The vector `e_n` lies in the range of the operator `succSub P n = P (n+1) - P n`. -/ + e_mem_range (n : ℕ) : e n ∈ (succSub P n).toLinearMap.range + /-- The vector `e_n` is non-zero. -/ + e_ne_zero (n : ℕ) : e n ≠ 0 + +namespace RankOneDecomposition + +variable (D : RankOneDecomposition 𝕜 X) + +/-- There exists a coefficient scaling `e n` to match `(succSub D.P n) x`. -/ +lemma exists_coeff (n : ℕ) (x : X) : + ∃ c : 𝕜, c • D.e n = (succSub D.P n) x := by + let S := (succSub D.P n).toLinearMap + have hrank : Module.finrank 𝕜 S.range = 1 := + finrank_range_succSub_eq_one D.finrank_range D.proj_comp n + have : FiniteDimensional 𝕜 S.range := .of_finrank_pos (hrank.symm ▸ zero_lt_one) + have hspan : Submodule.span 𝕜 {D.e n} = S.range := by + apply Submodule.eq_of_le_of_finrank_eq + · exact (Submodule.span_singleton_le_iff_mem _ _).mpr (D.e_mem_range n) + · simp [hrank, finrank_span_singleton (D.e_ne_zero n)] + exact Submodule.mem_span_singleton.mp (hspan.symm ▸ LinearMap.mem_range_self S x) + +/-- The coefficient functional value for the basis construction. -/ +def basisCoeff (n : ℕ) (x : X) : 𝕜 := + Classical.choose (exists_coeff D n x) + +/-- The coefficient satisfies `basisCoeff D n x • D.e n = (succSub D.P n) x`. -/ +@[simp] +lemma basisCoeff_spec (n : ℕ) (x : X) : + basisCoeff D n x • D.e n = (succSub D.P n) x := + Classical.choose_spec (exists_coeff D n x) + +/-- Constructs a Schauder basis from rank one decomposition. -/ +def basis : SchauderBasis 𝕜 X := + let coeff := basisCoeff D + have hcoeff : ∀ n x, (succSub D.P n) x = coeff n x • D.e n := fun n x ↦ + (basisCoeff_spec D n x).symm + { basis := D.e + coord := fun n ↦ LinearMap.mkContinuous + { toFun := coeff n + map_add' := fun x y ↦ smul_left_injective 𝕜 (D.e_ne_zero n) <| by + simp only [add_smul, ← hcoeff, map_add] + map_smul' := fun c x ↦ smul_left_injective 𝕜 (D.e_ne_zero n) <| by + dsimp only [RingHom.id_apply] + rw [smul_eq_mul, ← smul_smul, ← hcoeff, ← hcoeff, map_smul] } + (‖succSub D.P n‖ / ‖D.e n‖) + (fun x ↦ by + rw [div_mul_eq_mul_div, le_div_iff₀ (norm_pos_iff.mpr (D.e_ne_zero n))] + calc ‖coeff n x‖ * ‖D.e n‖ = ‖coeff n x • D.e n‖ := (norm_smul _ _).symm + _ = ‖(succSub D.P n) x‖ := by rw [hcoeff] + _ ≤ ‖succSub D.P n‖ * ‖x‖ := ContinuousLinearMap.le_opNorm _ _) + ortho := fun i j ↦ smul_left_injective 𝕜 (D.e_ne_zero i) <| by + obtain ⟨x, hx⟩ : ∃ x, (succSub D.P j) x = D.e j := D.e_mem_range j + simp only [mkContinuous_apply, LinearMap.coe_mk, AddHom.coe_mk] + rw [← hcoeff, ← hx, succSub_ortho D.proj_comp, hx] + simp only [Pi.single_apply] + split_ifs with h <;> simp [h] + expansion := fun x ↦ by + rw [HasSum, SummationFilter.conditional_filter_eq_map_range, tendsto_map'_iff] + exact (D.proj_tendsto x).congr fun n ↦ by + simp only [Function.comp, LinearMap.coe_mk, AddHom.coe_mk, + LinearMap.mkContinuous_apply, ← hcoeff] + rw [← ContinuousLinearMap.sum_apply, sum_succSub D.P D.proj_zero] } + +/-- The projections of the constructed basis correspond to the input data `D.P`. -/ +@[simp] +theorem basis_proj : (basis D).proj = D.P := by + ext n _ + rw [SchauderBasis.proj_apply, ← sum_succSub D.P D.proj_zero n] + simp only [ContinuousLinearMap.coe_sum', Finset.sum_apply] + refine Finset.sum_congr rfl fun i _ ↦ ?_ + dsimp [basis, mkContinuous_apply, IsLinearMap.mk'_apply] + rw [basisCoeff_spec] + +/-- The sequence of the constructed basis corresponds to the input data `D.e`. -/ +@[simp] +theorem basis_coe : ⇑(basis D) = D.e := + rfl + +end RankOneDecomposition + +end SchauderBasis diff --git a/Mathlib/Analysis/Normed/Module/Basic.lean b/Mathlib/Analysis/Normed/Module/Basic.lean index ff92c488066ec0..d369e5ef2e1346 100644 --- a/Mathlib/Analysis/Normed/Module/Basic.lean +++ b/Mathlib/Analysis/Normed/Module/Basic.lean @@ -400,7 +400,6 @@ abbrev NormedAlgebra.induced {F : Type*} (𝕜 R S : Type*) [NormedField 𝕜] [ letI := SeminormedRing.induced R S f ⟨fun a b ↦ show ‖f (a • b)‖ ≤ ‖a‖ * ‖f b‖ from (map_smul f a b).symm ▸ norm_smul_le a (f b)⟩ -set_option backward.isDefEq.respectTransparency false in instance Subalgebra.toNormedAlgebra {𝕜 A : Type*} [SeminormedRing A] [NormedField 𝕜] [NormedAlgebra 𝕜 A] (S : Subalgebra 𝕜 A) : NormedAlgebra 𝕜 S := NormedAlgebra.induced 𝕜 S A S.val diff --git a/Mathlib/Analysis/Normed/Module/WeakDual.lean b/Mathlib/Analysis/Normed/Module/WeakDual.lean index 5f815ea6c9e0f8..863719339842c4 100644 --- a/Mathlib/Analysis/Normed/Module/WeakDual.lean +++ b/Mathlib/Analysis/Normed/Module/WeakDual.lean @@ -107,13 +107,13 @@ def toWeakDual : StrongDual R M ≃ₗ[R] WeakDual R M := @[deprecated (since := "2025-08-3")] alias _root_.NormedSpace.Dual.toWeakDual := toWeakDual +theorem coe_toWeakDual (x' : StrongDual R M) : (toWeakDual x' : M → R) = x' := rfl + @[simp] -theorem coe_toWeakDual (x' : StrongDual R M) : toWeakDual x' = x' := - rfl +theorem toWeakDual_apply (x' : StrongDual R M) (y : M) : (toWeakDual x') y = x' y := rfl @[deprecated (since := "2025-08-3")] alias _root_.NormedSpace.Dual.coe_toWeakDual := coe_toWeakDual -@[simp] theorem toWeakDual_inj (x' y' : StrongDual R M) : toWeakDual x' = toWeakDual y' ↔ x' = y' := (LinearEquiv.injective toWeakDual).eq_iff @@ -134,14 +134,11 @@ equivalence `StrongDual.toWeakDual` in the other direction. -/ def toStrongDual : WeakDual 𝕜 E ≃ₗ[𝕜] StrongDual 𝕜 E := StrongDual.toWeakDual.symm -theorem toStrongDual_apply (x : WeakDual 𝕜 E) (y : E) : (toStrongDual x) y = x y := - rfl - @[simp] -theorem coe_toStrongDual (x' : WeakDual 𝕜 E) : toStrongDual x' = x' := - rfl +theorem toStrongDual_apply (x : WeakDual 𝕜 E) (y : E) : (toStrongDual x) y = x y := rfl + +theorem coe_toStrongDual (x' : WeakDual 𝕜 E) : (toStrongDual x' : E → 𝕜) = x' := rfl -@[simp] theorem toStrongDual_inj (x' y' : WeakDual 𝕜 E) : toStrongDual x' = toStrongDual y' ↔ x' = y' := (LinearEquiv.injective toStrongDual).eq_iff diff --git a/Mathlib/Analysis/Normed/Operator/Basic.lean b/Mathlib/Analysis/Normed/Operator/Basic.lean index 70e9db87b7da9c..4e3337c2fd6862 100644 --- a/Mathlib/Analysis/Normed/Operator/Basic.lean +++ b/Mathlib/Analysis/Normed/Operator/Basic.lean @@ -195,7 +195,7 @@ theorem isLeast_opNorm [RingHomIsometric σ₁₂] (f : E →SL[σ₁₂] F) : IsLeast {c | 0 ≤ c ∧ ∀ x, ‖f x‖ ≤ c * ‖x‖} ‖f‖ := by refine IsClosed.isLeast_csInf ?_ bounds_nonempty bounds_bddBelow simp only [setOf_and, setOf_forall] - refine isClosed_Ici.inter <| isClosed_iInter fun _ ↦ isClosed_le ?_ ?_ <;> continuity + refine isClosed_Ici.inter <| isClosed_iInter fun _ ↦ isClosed_le ?_ ?_ <;> fun_prop /-- If one controls the norm of every `A x`, then one controls the norm of `A`. -/ theorem opNorm_le_bound (f : E →SL[σ₁₂] F) {M : ℝ} (hMp : 0 ≤ M) (hM : ∀ x, ‖f x‖ ≤ M * ‖x‖) : diff --git a/Mathlib/Analysis/Normed/Ring/Lemmas.lean b/Mathlib/Analysis/Normed/Ring/Lemmas.lean index 0511134aa6e10d..845c295111d96b 100644 --- a/Mathlib/Analysis/Normed/Ring/Lemmas.lean +++ b/Mathlib/Analysis/Normed/Ring/Lemmas.lean @@ -210,7 +210,6 @@ end SeparationQuotient namespace NNReal -set_option backward.isDefEq.respectTransparency false in lemma lipschitzWith_sub : LipschitzWith 2 (fun (p : ℝ≥0 × ℝ≥0) ↦ p.1 - p.2) := by rw [← NNReal.isometry_coe.lipschitzWith_iff] have : Isometry (Prod.map ((↑) : ℝ≥0 → ℝ) ((↑) : ℝ≥0 → ℝ)) := diff --git a/Mathlib/Analysis/Normed/Ring/WithAbs.lean b/Mathlib/Analysis/Normed/Ring/WithAbs.lean index f1a6f0eaf32f0e..20e0a5a5aee606 100644 --- a/Mathlib/Analysis/Normed/Ring/WithAbs.lean +++ b/Mathlib/Analysis/Normed/Ring/WithAbs.lean @@ -165,7 +165,6 @@ section CommSemiring variable [CommSemiring R] (v : AbsoluteValue R S) -set_option backward.isDefEq.respectTransparency false in instance : CommSemiring (WithAbs v) := fast_instance% (equiv v).commSemiring end CommSemiring @@ -174,7 +173,6 @@ section Ring variable [Ring R] -set_option backward.isDefEq.respectTransparency false in instance (v : AbsoluteValue R S) : Ring (WithAbs v) := fast_instance% (equiv v).ring noncomputable instance normedRing (v : AbsoluteValue R ℝ) : NormedRing (WithAbs v) := @@ -201,7 +199,6 @@ section CommRing variable [CommRing R] (v : AbsoluteValue R S) -set_option backward.isDefEq.respectTransparency false in instance : CommRing (WithAbs v) := fast_instance% (equiv v).commRing end CommRing diff --git a/Mathlib/Analysis/Normed/Unbundled/AlgebraNorm.lean b/Mathlib/Analysis/Normed/Unbundled/AlgebraNorm.lean index adde9cd41200ab..fe5e0f748292e6 100644 --- a/Mathlib/Analysis/Normed/Unbundled/AlgebraNorm.lean +++ b/Mathlib/Analysis/Normed/Unbundled/AlgebraNorm.lean @@ -89,7 +89,6 @@ theorem extends_norm' (hf1 : f 1 = 1) (a : R) : f (a • (1 : S)) = ‖a‖ := b theorem extends_norm (hf1 : f 1 = 1) (a : R) : f (algebraMap R S a) = ‖a‖ := by rw [Algebra.algebraMap_eq_smul_one]; exact extends_norm' hf1 _ -set_option backward.isDefEq.respectTransparency false in set_option linter.style.whitespace false in -- manual alignment is not recognised /-- The restriction of an algebra norm to a subalgebra. -/ def restriction (A : Subalgebra R S) (f : AlgebraNorm R S) : AlgebraNorm R A where diff --git a/Mathlib/Analysis/Normed/Unbundled/IsPowMulFaithful.lean b/Mathlib/Analysis/Normed/Unbundled/IsPowMulFaithful.lean index bf66ac89079ffa..0b5ae669bf8d4d 100644 --- a/Mathlib/Analysis/Normed/Unbundled/IsPowMulFaithful.lean +++ b/Mathlib/Analysis/Normed/Unbundled/IsPowMulFaithful.lean @@ -78,7 +78,6 @@ theorem eq_seminorms {F : Type*} {α : outParam (Type*)} [Ring α] [FunLike F α variable {R S : Type*} [NormedCommRing R] [CommRing S] [Algebra R S] -set_option backward.isDefEq.respectTransparency false in /-- If `R` is a normed commutative ring and `f₁` and `f₂` are two power-multiplicative `R`-algebra norms on `S`, then if `f₁` and `f₂` are equivalent on every subring `R[y]` for `y : S`, it follows that `f₁ = f₂` [BGR, Proposition 3.1.5/1][bosch-guntzer-remmert]. -/ diff --git a/Mathlib/Analysis/Normed/Unbundled/SpectralNorm.lean b/Mathlib/Analysis/Normed/Unbundled/SpectralNorm.lean index 5a7a41104ba0b9..761ad3ce906dd2 100644 --- a/Mathlib/Analysis/Normed/Unbundled/SpectralNorm.lean +++ b/Mathlib/Analysis/Normed/Unbundled/SpectralNorm.lean @@ -399,7 +399,6 @@ theorem spectralNorm.eq_of_tower {E : Type*} [Field E] [Algebra K E] [Algebra E variable (E : IntermediateField K L) -set_option backward.isDefEq.respectTransparency false in /-- If `L/E/K` is a tower of fields, then the spectral norm of `x : E` when regarded as an element of the normal closure of `E` equals its spectral norm when regarding `x` as an element of `L`. -/ theorem spectralNorm.eq_of_normalClosure' (x : E) : @@ -413,7 +412,6 @@ theorem spectralNorm.eq_of_normalClosure' (x : E) : x, ← minpoly.algebraMap_eq (algebraMap (↥E) L).injective x] simp_rw [h_min] -set_option backward.isDefEq.respectTransparency false in /-- If `L/E/K` is a tower of fields and `x = algebraMap E L g`, then the spectral norm of `g : E` when regarded as an element of the normal closure of `E` equals the spectral norm of `x : L`. -/ @@ -593,7 +591,6 @@ theorem spectralNorm_one : spectralNorm K L 1 = 1 := by variable [IsUltrametricDist K] -set_option backward.isDefEq.respectTransparency false in /-- `spectralNorm K L (-y) = spectralNorm K L y` . -/ theorem spectralNorm_neg {y : L} (hy : IsAlgebraic K y) : spectralNorm K L (-y) = spectralNorm K L y := by @@ -607,7 +604,6 @@ theorem spectralNorm_neg {y : L} (hy : IsAlgebraic K y) : ← spectralAlgNorm_of_finiteDimensional_normal_def] exact map_neg_eq_map _ _ -set_option backward.isDefEq.respectTransparency false in /-- The spectral norm is compatible with the action of `K`. -/ theorem spectralNorm_smul (k : K) {y : L} (hy : IsAlgebraic K y) : spectralNorm K L (k • y) = ‖k‖₊ * spectralNorm K L y := by @@ -624,7 +620,6 @@ theorem spectralNorm_smul (k : K) {y : L} (hy : IsAlgebraic K y) : rw [← spectralAlgNorm_of_finiteDimensional_normal_def] apply map_smul_eq_mul -set_option backward.isDefEq.respectTransparency false in /-- The spectral norm is submultiplicative. -/ theorem spectralNorm_mul {x y : L} (hx : IsAlgebraic K x) (hy : IsAlgebraic K y) : spectralNorm K L (x * y) ≤ spectralNorm K L x * spectralNorm K L y := by @@ -644,7 +639,6 @@ section IsAlgebraic variable [h_alg : Algebra.IsAlgebraic K L] -set_option backward.isDefEq.respectTransparency false in /-- The spectral norm is power-multiplicative. -/ theorem isPowMul_spectralNorm : IsPowMul (spectralNorm K L) := by intro x n hn @@ -658,7 +652,6 @@ theorem isPowMul_spectralNorm : IsPowMul (spectralNorm K L) := by exact isPowMul_spectralNorm_of_finiteDimensional_normal _ _ ((algebraMap ↥K⟮x⟯ ↥(normalClosure K (↥K⟮x⟯) (AlgebraicClosure ↥K⟮x⟯))) g) hn -set_option backward.isDefEq.respectTransparency false in /-- The spectral norm is nonarchimedean. -/ theorem isNonarchimedean_spectralNorm : IsNonarchimedean (spectralNorm K L) := by intro x y diff --git a/Mathlib/Analysis/RCLike/Basic.lean b/Mathlib/Analysis/RCLike/Basic.lean index 7a78fe2eecb52e..df6ced33c10236 100644 --- a/Mathlib/Analysis/RCLike/Basic.lean +++ b/Mathlib/Analysis/RCLike/Basic.lean @@ -1183,7 +1183,7 @@ lemma instOrderClosedTopology : OrderClosedTopology K where isClosed_le' := by conv in _ ≤ _ => rw [RCLike.le_iff_re_im] simp_rw [Set.setOf_and] - refine IsClosed.inter (isClosed_le ?_ ?_) (isClosed_eq ?_ ?_) <;> continuity + refine IsClosed.inter (isClosed_le ?_ ?_) (isClosed_eq ?_ ?_) <;> fun_prop scoped[ComplexOrder] attribute [instance] RCLike.instOrderClosedTopology diff --git a/Mathlib/Analysis/SpecialFunctions/Arcosh.lean b/Mathlib/Analysis/SpecialFunctions/Arcosh.lean index 1efb6bb63bb6a2..bafadd377628f2 100644 --- a/Mathlib/Analysis/SpecialFunctions/Arcosh.lean +++ b/Mathlib/Analysis/SpecialFunctions/Arcosh.lean @@ -132,7 +132,7 @@ def coshPartialEquiv : PartialEquiv ℝ ℝ where theorem continuousOn_arcosh : ContinuousOn arcosh (Ici 1) := have {x : ℝ} (hx : x ∈ Ici 1) : 0 < x + √(x ^ 2 - 1) := add_pos_of_pos_of_nonneg (show 0 < x by grind) (sqrt_nonneg _) - continuousOn_log.comp (Continuous.continuousOn (by continuity)) (by grind [MapsTo]) + continuousOn_log.comp (by fun_prop) (by grind [MapsTo]) /-- `Real.cosh` as an `OpenPartialHomeomorph` from (0, ∞) to (1, ∞). -/ def coshOpenPartialHomeomorph : OpenPartialHomeomorph ℝ ℝ where @@ -146,7 +146,7 @@ def coshOpenPartialHomeomorph : OpenPartialHomeomorph ℝ ℝ where right_inv' _ hr := cosh_arcosh (le_of_lt hr) open_source := isOpen_Ioi open_target := isOpen_Ioi - continuousOn_toFun := continuous_cosh.continuousOn + continuousOn_toFun := by fun_prop continuousOn_invFun := continuousOn_arcosh.mono Ioi_subset_Ici_self theorem hasStrictDerivAt_arcosh {x : ℝ} (hx : x ∈ Ioi 1) : diff --git a/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Rpow/Basic.lean b/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Rpow/Basic.lean index 8726f4fa545785..6be2c5644dc24d 100644 --- a/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Rpow/Basic.lean +++ b/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Rpow/Basic.lean @@ -462,43 +462,43 @@ lemma rpow_add {a : A} {x y : ℝ} (ha : IsUnit a) : simp [NNReal.rpow_add this _ _] lemma rpow_rpow [IsTopologicalRing A] [T2Space A] - (a : A) (x y : ℝ) (ha₁ : IsUnit a) (hx : x ≠ 0) (ha₂ : 0 ≤ a := by cfc_tac) : + (a : A) (x y : ℝ) (hx : x ≠ 0) (ha : IsStrictlyPositive a := by cfc_tac) : (a ^ x) ^ y = a ^ (x * y) := by - have ha₁' : 0 ∉ spectrum ℝ≥0 a := spectrum.zero_notMem _ ha₁ + have ha₁' : 0 ∉ spectrum ℝ≥0 a := spectrum.zero_notMem _ ha.isUnit simp only [rpow_def] - rw [← cfc_comp _ _ a ha₂] + rw [← cfc_comp _ _ a ha.nonneg] refine cfc_congr fun _ _ => ?_ simp [NNReal.rpow_mul] lemma rpow_rpow_inv [IsTopologicalRing A] [T2Space A] - (a : A) (x : ℝ) (ha₁ : IsUnit a) (hx : x ≠ 0) (ha₂ : 0 ≤ a := by cfc_tac) : + (a : A) (x : ℝ) (hx : x ≠ 0) (ha : IsStrictlyPositive a := by cfc_tac) : (a ^ x) ^ x⁻¹ = a := by - rw [rpow_rpow a x x⁻¹ ha₁ hx ha₂, mul_inv_cancel₀ hx, rpow_one a ha₂] + rw [rpow_rpow a x x⁻¹ hx, mul_inv_cancel₀ hx, rpow_one a ha.nonneg] lemma rpow_inv_rpow [IsTopologicalRing A] [T2Space A] - (a : A) (x : ℝ) (ha₁ : IsUnit a) (hx : x ≠ 0) (ha₂ : 0 ≤ a := by cfc_tac) : + (a : A) (x : ℝ) (hx : x ≠ 0) (ha : IsStrictlyPositive a := by cfc_tac) : (a ^ x⁻¹) ^ x = a := by - simpa using rpow_rpow_inv a x⁻¹ ha₁ (inv_ne_zero hx) ha₂ + simpa using rpow_rpow_inv a x⁻¹ (inv_ne_zero hx) lemma rpow_rpow_of_exponent_nonneg [IsTopologicalRing A] [T2Space A] (a : A) (x y : ℝ) - (hx : 0 ≤ x) (hy : 0 ≤ y) (ha₂ : 0 ≤ a := by cfc_tac) : (a ^ x) ^ y = a ^ (x * y) := by + (hx : 0 ≤ x) (hy : 0 ≤ y) (ha : 0 ≤ a := by cfc_tac) : (a ^ x) ^ y = a ^ (x * y) := by simp only [rpow_def] rw [← cfc_comp _ _ a] refine cfc_congr fun _ _ => ?_ simp [NNReal.rpow_mul] -lemma rpow_mul_rpow_neg {a : A} (x : ℝ) (ha : IsUnit a) - (ha' : 0 ≤ a := by cfc_tac) : a ^ x * a ^ (-x) = 1 := by - rw [← rpow_add ha, add_neg_cancel, rpow_zero a] +lemma rpow_mul_rpow_neg {a : A} (x : ℝ) (ha : IsStrictlyPositive a := by cfc_tac) : + a ^ x * a ^ (-x) = 1 := by + rw [← rpow_add ha.isUnit, add_neg_cancel, rpow_zero a] -lemma rpow_neg_mul_rpow {a : A} (x : ℝ) (ha : IsUnit a) - (ha' : 0 ≤ a := by cfc_tac) : a ^ (-x) * a ^ x = 1 := by - rw [← rpow_add ha, neg_add_cancel, rpow_zero a] +lemma rpow_neg_mul_rpow {a : A} (x : ℝ) (ha : IsStrictlyPositive a := by cfc_tac) : + a ^ (-x) * a ^ x = 1 := by + rw [← rpow_add ha.isUnit, neg_add_cancel, rpow_zero a] lemma rpow_neg_one_eq_inv (a : Aˣ) (ha : (0 : A) ≤ a := by cfc_tac) : a ^ (-1 : ℝ) = (↑a⁻¹ : A) := by refine a.inv_eq_of_mul_eq_one_left ?_ |>.symm - simpa [rpow_one (a : A)] using rpow_neg_mul_rpow 1 a.isUnit + simpa [rpow_one (a : A)] using rpow_neg_mul_rpow 1 (a.isStrictlyPositive_iff.mpr ha) lemma rpow_neg_one_eq_cfc_inv {A : Type*} [PartialOrder A] [NormedRing A] [StarRing A] [StarOrderedRing A] [NormedAlgebra ℝ A] [NonnegSpectrumClass ℝ A] @@ -506,6 +506,11 @@ lemma rpow_neg_one_eq_cfc_inv {A : Type*} [PartialOrder A] [NormedRing A] [StarR a ^ (-1 : ℝ) = cfc (·⁻¹ : ℝ≥0 → ℝ≥0) a := cfc_congr fun x _ ↦ NNReal.rpow_neg_one x +lemma inverse_eq_rpow_neg_one {a : A} (ha : IsStrictlyPositive a := by cfc_tac) : + Ring.inverse a = a ^ (-1 : ℝ) := by + obtain ⟨ax, hax⟩ := ha.isUnit + simp only [← hax, Ring.inverse_invertible, invOf_units, CFC.rpow_neg_one_eq_inv ax] + lemma rpow_neg [IsTopologicalRing A] [T2Space A] (a : Aˣ) (x : ℝ) (ha' : (0 : A) ≤ a := by cfc_tac) : (a : A) ^ (-x) = (↑a⁻¹ : A) ^ x := by suffices h₁ : ContinuousOn (fun z ↦ z ^ x) (Inv.inv '' (spectrum ℝ≥0 (a : A))) by @@ -526,7 +531,7 @@ lemma rpow_intCast (a : Aˣ) (n : ℤ) (ha : (0 : A) ≤ a := by cfc_tac) : /-- `a ^ x` bundled as an element of `Aˣ` for `a : Aˣ`. -/ @[simps] noncomputable def _root_.Units.cfcRpow (a : Aˣ) (x : ℝ) (ha : (0 : A) ≤ a := by cfc_tac) : Aˣ := - ⟨(a : A) ^ x, (a : A) ^ (-x), rpow_mul_rpow_neg x (by simp), rpow_neg_mul_rpow x (by simp)⟩ + ⟨(a : A) ^ x, (a : A) ^ (-x), rpow_mul_rpow_neg x, rpow_neg_mul_rpow x⟩ @[aesop safe apply, grind ←] lemma _root_.IsUnit.cfcRpow {a : A} (ha : IsUnit a) (x : ℝ) (ha_nonneg : 0 ≤ a := by cfc_tac) : @@ -666,15 +671,17 @@ lemma sqrt_rpow {a : A} {x : ℝ} (h : IsUnit a) (hx : x ≠ 0) : sqrt (a ^ x) = a ^ (x / 2) := by by_cases hnonneg : 0 ≤ a case pos => - simp only [sqrt_eq_rpow, div_eq_mul_inv, one_mul, rpow_rpow _ _ _ h hx] + have : IsStrictlyPositive a := by grind + simp [sqrt_eq_rpow, div_eq_mul_inv, one_mul, rpow_rpow _ _ _ hx] case neg => simp [sqrt_eq_cfc, rpow_def, cfc_apply_of_not_predicate a hnonneg] -- TODO: relate to a strict positivity condition lemma rpow_sqrt (a : A) (x : ℝ) (h : IsUnit a) (ha : 0 ≤ a := by cfc_tac) : (sqrt a) ^ x = a ^ (x / 2) := by + have : IsStrictlyPositive a := by grind rw [sqrt_eq_rpow, div_eq_mul_inv, one_mul, - rpow_rpow _ _ _ h (by simp), inv_mul_eq_div] + rpow_rpow _ _ _ (by simp), inv_mul_eq_div] lemma sqrt_rpow_nnreal {a : A} {x : ℝ≥0} : sqrt (a ^ (x : ℝ)) = a ^ (x / 2 : ℝ) := by by_cases htriv : 0 ≤ a @@ -720,18 +727,26 @@ lemma _root_.IsUnit.cfcSqrt (a : A) (ha_unit : IsUnit a) (ha : 0 ≤ a := by cfc (isUnit_sqrt_iff a ha).mpr ha_unit @[aesop safe apply] -lemma _root_.IsStrictlyPositive.nnrpow {a : A} {y : ℝ≥0} (ha : IsStrictlyPositive a) (hy : y ≠ 0) : - IsStrictlyPositive (a ^ y) := by grind +lemma _root_.IsStrictlyPositive.nnrpow (a : A) (y : ℝ≥0) (hy : y ≠ 0) + (ha : IsStrictlyPositive a := by cfc_tac) : IsStrictlyPositive (a ^ y) := by grind @[aesop safe apply] -lemma _root_.IsStrictlyPositive.sqrt {a : A} (ha : IsStrictlyPositive a) : +lemma _root_.IsStrictlyPositive.sqrt (a : A) (ha : IsStrictlyPositive a := by cfc_tac) : IsStrictlyPositive (sqrt a) := by grind omit [T2Space A] [IsTopologicalRing A] in @[aesop safe apply] -lemma _root_.IsStrictlyPositive.rpow {a : A} {y : ℝ} (ha : IsStrictlyPositive a) : +lemma _root_.IsStrictlyPositive.rpow (a : A) (y : ℝ) (ha : IsStrictlyPositive a := by cfc_tac) : IsStrictlyPositive (a ^ y) := by grind +lemma inverse_rpow (a : A) (x : ℝ) (hx : x ≠ 0) (ha : IsStrictlyPositive a := by cfc_tac) : + Ring.inverse (a ^ x) = a ^ (-x) := by + have : a ^ (-x) = (a ^ x) ^ (-1 : ℝ) := by + rw [rpow_rpow (hx := hx) (ha := by grind)] + simp + rw [← inverse_eq_rpow_neg_one (by grind)] at this + rw [this] + /-- For an element `a` in a C⋆-algebra, TFAE: 1. `a` is strictly positive, 2. `sqrt a` is strictly positive and `a = sqrt a * sqrt a`, diff --git a/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean b/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean index b8238f1064caa7..7652303237efff 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean @@ -72,9 +72,7 @@ theorem GammaIntegral_convergent {s : ℝ} (h : 0 < s) : refine (intervalIntegrable_iff_integrableOn_Icc_of_le zero_le_one).mp ?_ exact intervalIntegrable_rpow' (by linarith) · refine integrable_of_isBigO_exp_neg one_half_pos ?_ (Gamma_integrand_isLittleO _).isBigO - refine continuousOn_id.neg.rexp.mul (continuousOn_id.rpow_const ?_) - intro x hx - exact Or.inl ((zero_lt_one : (0 : ℝ) < 1).trans_le hx).ne' + exact continuousOn_id.neg.rexp.mul (continuousOn_id.rpow_const (by grind)) end Real diff --git a/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean b/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean index 41e413a9508f22..c62c90eeb1a2b3 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean @@ -410,7 +410,7 @@ theorem log_nat_eq_sum_factorization (n : ℕ) : rcases eq_or_ne n 0 with (rfl | hn) · simp -- relies on junk values of `log` and `Nat.factorization` · simp only [← log_pow, ← Nat.cast_pow] - rw [← Finsupp.log_prod, ← Nat.cast_finsuppProd, Nat.factorization_prod_pow_eq_self hn] + rw [← Finsupp.log_prod, ← Nat.cast_finsuppProd, Nat.prod_factorization_pow_eq_self hn] intro p hp rw [eq_zero_of_pow_eq_zero (Nat.cast_eq_zero.1 hp), Nat.factorization_zero_right] diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Chebyshev/Extremal.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Chebyshev/Extremal.lean index d2a8a9b1f2ab21..46a4dae876953f 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Chebyshev/Extremal.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Chebyshev/Extremal.lean @@ -14,17 +14,25 @@ public import Mathlib.Tactic.Positivity /-! # Chebyshev polynomials over the reals: some extremal properties -Chebyshev polynomials have largest leading coefficient, +* Chebyshev polynomials have largest leading coefficient, following proof in https://math.stackexchange.com/a/978145/1277 +* Chebyshev polynomials maximize iterated derivatives at 1 and beyond ## Main statements * leadingCoeff_le_of_forall_abs_le_one: If `P` is a real polynomial of degree at most `n` and `|P (x)| ≤ 1` for all `x ∈ [-1, 1]` then the leading coefficient of `P` is at most `2 ^ (n - 1)` * leadingCoeff_eq_iff_of_forall_abs_le_one: When `n ≥ 2`, equality holds iff `P = T_n` +* eval_iterate_derivative_le_of_forall_abs_le_one: If `P` is a real polynomial of degree at most `n` + and `|P (x)| ≤ 1` for all `x ∈ [-1, 1]` then for all `x ≥ 1`, `P ^ (k) (x) ≤ T_n ^ (k)(x)` +* eval_iterate_derivative_eq_iff_of_forall_abs_le_one: If `0 < k ≤ n` then equality holds iff + `P = T_n` ## Implementation +We describe the proof for the leading coefficient; the proof for iterated derivatives uses a +similar approach. + By monotonicity of `2 ^ (n - 1)`, we can assume that `P` has degree exactly `n`. Using Lagrange interpolation, we can give a formula for the leading coefficient of `P` as a linear combination of the values of `P` on the Chebyshev nodes (sumNodes_eq_coeff). @@ -228,4 +236,69 @@ theorem leadingCoeff_eq_iff_of_forall_abs_le_one {n : ℕ} {P : ℝ[X]} (hn : 2 calc P.leadingCoeff ≤ 2 ^ (d - 1) := leadingCoeff_le_of_forall_abs_le_one (le_of_eq hd.symm) hPbnd _ < 2 ^ (n - 1) := by gcongr; norm_num +/-- Coefficients used to compute the iterated derivative of a polynomial given its values on the +Chebyshev nodes. -/ +private noncomputable def iterateDerivativeC (n k : ℕ) (x : ℝ) (i : ℕ) := + k.factorial * (∏ j ∈ (Finset.range (n + 1)).erase i, ((node n i) - (node n j)))⁻¹ * + ∑ t ∈ ((Finset.range (n + 1)).erase i).powersetCard (n - k), ∏ a ∈ t, (x - node n a) + +private theorem sumNodes_eq_eval_iterate_derivative {n k : ℕ} (hk : k ≤ n) (x : ℝ) + {P : ℝ[X]} (hP : P.degree ≤ n) : + sumNodes n (iterateDerivativeC n k x) P = (derivative^[k] P).eval x := by + simp_rw [sumNodes, iterateDerivativeC] + have h₁ : P.degree < (Finset.range (n + 1)).card := by + rw [Finset.card_range]; grw [hP]; norm_cast; simp + convert (Lagrange.eval_iterate_derivative_eq_sum (strictAntiOn_node n).injOn h₁ + (show k < _ by simp [hk]) x).symm + rw [Finset.mul_sum] + grind [Nat.range_succ_eq_Iic, Nat.card_Iic] + +private theorem negOnePow_mul_iterateDerivativeC_nonneg + {n k i : ℕ} (hi : i ≤ n) {x : ℝ} (hx : 1 ≤ x) : + 0 ≤ (-1) ^ i * iterateDerivativeC n k x i := by + rw [iterateDerivativeC, ← mul_assoc] + refine mul_nonneg ?_ (Finset.sum_nonneg' ?_) + · rw [← mul_assoc, mul_comm (a := (-1) ^ i), mul_assoc] + exact le_of_lt <| mul_pos (Nat.cast_pos.mpr <| Nat.factorial_pos k) + (negOnePow_mul_leadingCoeffC_pos hi) + · exact fun t => Finset.prod_nonneg (fun a _ => by grind [show node n a ≤ 1 from cos_le_one _]) + +private theorem negOnePow_mul_iterateDerivativeC_pos + {n k i : ℕ} (hk₁ : 0 < k) (hk₂ : k ≤ n) (hi : i ≤ n) {x : ℝ} (hx : 1 ≤ x) : + 0 < (-1) ^ i * iterateDerivativeC n k x i := by + rw [iterateDerivativeC, ← mul_assoc] + refine mul_pos ?_ (Finset.sum_pos' ?_ ?_) + · rw [← mul_assoc, mul_comm (a := (-1) ^ i), mul_assoc] + exact mul_pos (Nat.cast_pos.mpr <| Nat.factorial_pos k) (negOnePow_mul_leadingCoeffC_pos hi) + · exact fun t _ => Finset.prod_nonneg (fun a _ => by grind [show node n a ≤ 1 from cos_le_one _]) + · have : ∃ s ⊆ (Finset.range (n + 1)).erase i, s.card = n - k ∧ 0 ∉ s := by + by_cases 1 ≤ i ∧ i ≤ n - k + case neg => exact ⟨Finset.Icc 1 (n - k), by grind, by grind [Nat.card_Icc], by simp⟩ + case pos => exact ⟨(Finset.Icc 1 (n - k + 1)).erase i, by grind, by grind [Nat.card_Icc], + by simp⟩ + obtain ⟨s, hs, hscard, hsn⟩ := this + refine ⟨s, by simp [hs, hscard], Finset.prod_pos (fun a ha => ?_)⟩ + grind [show node n a < 1 by rw [← node_eq_one (n := n)]; exact node_lt (by grind) (by grind)] + +theorem eval_iterate_derivative_le_of_forall_abs_le_one {n : ℕ} {P : ℝ[X]} + {k : ℕ} {x : ℝ} (hx : 1 ≤ x) + (hPdeg : P.degree ≤ n) (hPbnd : ∀ x ∈ Set.Icc (-1) 1, |P.eval x| ≤ 1) : + (derivative^[k] P).eval x ≤ (derivative^[k] (T ℝ n)).eval x := by + by_cases! hk : n < k + · rw [iterate_derivative_eq_zero_of_degree_lt (by grw [hPdeg]; simpa), + iterate_derivative_eq_zero_of_degree_lt (by simp [hk])] + convert sumNodes_le_sumNodes_T + (fun i hi => negOnePow_mul_iterateDerivativeC_nonneg hi hx) hPbnd using 1 + · rw [sumNodes_eq_eval_iterate_derivative hk x hPdeg] + · rw [sumNodes_eq_eval_iterate_derivative hk x (le_of_eq (degree_T ℝ n))] + +theorem eval_iterate_derivative_eq_iff_of_bounded {n : ℕ} {P : ℝ[X]} + {k : ℕ} (hk₁ : 0 < k) (hk₂ : k ≤ n) {x : ℝ} (hx : 1 ≤ x) + (hPdeg : P.degree ≤ n) (hPbnd : ∀ x ∈ Set.Icc (-1) 1, |P.eval x| ≤ 1) : + (derivative^[k] P).eval x = (derivative^[k] (T ℝ n)).eval x ↔ P = T ℝ n := by + convert sumNodes_eq_sumNodes_T_iff + (fun i hi => negOnePow_mul_iterateDerivativeC_pos hk₁ hk₂ hi hx) hPdeg hPbnd using 2 + · rw [sumNodes_eq_eval_iterate_derivative hk₂ x hPdeg] + · rw [sumNodes_eq_eval_iterate_derivative hk₂ x (le_of_eq (degree_T ℝ n))] + end Polynomial.Chebyshev diff --git a/Mathlib/CategoryTheory/Abelian/GrothendieckCategory/ColimCoyoneda.lean b/Mathlib/CategoryTheory/Abelian/GrothendieckCategory/ColimCoyoneda.lean index 0ec2d1c92dfaf9..f646ff4d4ee3b9 100644 --- a/Mathlib/CategoryTheory/Abelian/GrothendieckCategory/ColimCoyoneda.lean +++ b/Mathlib/CategoryTheory/Abelian/GrothendieckCategory/ColimCoyoneda.lean @@ -85,7 +85,6 @@ lemma hf (j : Under j₀) : colimit.ι (kernel (g y)) j ≫ f y = (kernel.ι (g y)).app j := (IsColimit.ι_map _ _ _ _).trans (by simp) -set_option backward.isDefEq.respectTransparency false in variable {y} in include hc hy in lemma epi_f [IsFiltered J] : Epi (f y) := by diff --git a/Mathlib/CategoryTheory/Abelian/Pseudoelements.lean b/Mathlib/CategoryTheory/Abelian/Pseudoelements.lean index d9c920029b9885..cb3c947d32f534 100644 --- a/Mathlib/CategoryTheory/Abelian/Pseudoelements.lean +++ b/Mathlib/CategoryTheory/Abelian/Pseudoelements.lean @@ -273,8 +273,8 @@ set_option backward.isDefEq.respectTransparency false in /-- A monomorphism is injective on pseudoelements. -/ theorem pseudo_injective_of_mono {P Q : C} (f : P ⟶ Q) [Mono f] : Function.Injective f := by intro abar abar' - refine Quotient.inductionOn₂ abar abar' fun a a' ha => ?_ - apply Quotient.sound + induction abar, abar' using Quotient.inductionOn₂ with | _ a a' + refine fun ha ↦ Quotient.sound ?_ have : (⟦(a.hom ≫ f : Over Q)⟧ : Quotient (setoid Q)) = ⟦↑(a'.hom ≫ f)⟧ := by convert ha have ⟨R, p, q, ep, Eq, comm⟩ := Quotient.exact this exact ⟨R, p, q, ep, Eq, (cancel_mono f).1 <| by diff --git a/Mathlib/CategoryTheory/Action/Basic.lean b/Mathlib/CategoryTheory/Action/Basic.lean index 1f5007c7c69637..c8c92137048221 100644 --- a/Mathlib/CategoryTheory/Action/Basic.lean +++ b/Mathlib/CategoryTheory/Action/Basic.lean @@ -445,7 +445,6 @@ def mapActionCongr {F F' : V ⥤ W} (e : F ≅ F') : end Functor -set_option backward.isDefEq.respectTransparency false in /-- An equivalence of categories induces an equivalence of the categories of `G`-actions within those categories. -/ @[simps functor inverse] diff --git a/Mathlib/CategoryTheory/Action/Continuous.lean b/Mathlib/CategoryTheory/Action/Continuous.lean index 74ac4decbed9ce..514a95e0e82125 100644 --- a/Mathlib/CategoryTheory/Action/Continuous.lean +++ b/Mathlib/CategoryTheory/Action/Continuous.lean @@ -202,7 +202,6 @@ def mapContActionCongr end Functor -set_option backward.isDefEq.respectTransparency false in /-- Continuous version of `Equivalence.mapAction`. -/ @[simps functor inverse] def Equivalence.mapContAction (E : V ≌ W) diff --git a/Mathlib/CategoryTheory/Adjunction/Basic.lean b/Mathlib/CategoryTheory/Adjunction/Basic.lean index a5df6575068d83..0909b1b0edb866 100644 --- a/Mathlib/CategoryTheory/Adjunction/Basic.lean +++ b/Mathlib/CategoryTheory/Adjunction/Basic.lean @@ -734,7 +734,6 @@ namespace Equivalence variable (e : C ≌ D) -set_option backward.isDefEq.respectTransparency false in /-- The adjunction given by an equivalence of categories. (To obtain the opposite adjunction, simply use `e.symm.toAdjunction`.) -/ @[simps] diff --git a/Mathlib/CategoryTheory/Adjunction/FullyFaithfulLimits.lean b/Mathlib/CategoryTheory/Adjunction/FullyFaithfulLimits.lean new file mode 100644 index 00000000000000..67c89872350287 --- /dev/null +++ b/Mathlib/CategoryTheory/Adjunction/FullyFaithfulLimits.lean @@ -0,0 +1,62 @@ +/- +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.Adjunction.FullyFaithful +public import Mathlib.CategoryTheory.Adjunction.Limits + +/-! +# Preservation of colimits and reflective adjunctions + +Let `adj : F ⊣ G` be an adjunction with `G : D ⥤ C` full and faithful. +We show that if colimits of shape `J` exist in `C`, then a functor +`H : D ⥤ E` preserves colimits of shape `J` iff `F ⋙ H` does. + +In particular, a functor from a category of sheaves preserves colimits +iff it does so after precomposition with the sheafification functor. + +-/ + +@[expose] public section + +universe v u v₁ v₂ v₃ u₁ u₂ u₃ + +namespace CategoryTheory.Adjunction + +open Limits + +variable {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D] + {F : C ⥤ D} {G : D ⥤ C} (adj : F ⊣ G) + {E : Type u₃} [Category.{v₃} E] (H : D ⥤ E) + (J : Type u) [Category.{v} J] + +include adj + +lemma preservesColimitsOfShape_iff (J : Type u) [Category.{v} J] + [HasColimitsOfShape J C] [G.Full] [G.Faithful] : + PreservesColimitsOfShape J H ↔ PreservesColimitsOfShape J (F ⋙ H) := by + have := adj.isLeftAdjoint + refine ⟨fun _ ↦ inferInstance, fun _ ↦ ⟨fun {K} ↦ ?_⟩⟩ + let iso : (K ⋙ G) ⋙ F ≅ K := + Functor.associator _ _ _ ≪≫ Functor.isoWhiskerLeft _ (asIso adj.counit) ≪≫ K.rightUnitor + refine preservesColimit_of_preserves_colimit_cocone + ((IsColimit.precomposeInvEquiv iso _).symm + (isColimitOfPreserves F (colimit.isColimit (K ⋙ G)))) ?_ + exact IsColimit.ofIsoColimit + ((IsColimit.precomposeInvEquiv + ((Functor.associator _ _ _).symm ≪≫ Functor.isoWhiskerRight iso H) _).symm + (isColimitOfPreserves (F ⋙ H) (colimit.isColimit (K ⋙ G)))) + (Cocone.ext (Iso.refl _)) + +lemma preservesColimitsOfSize_iff + [HasColimitsOfSize.{v, u} C] [G.Full] [G.Faithful] : + PreservesColimitsOfSize.{v, u} H ↔ PreservesColimitsOfSize.{v, u} (F ⋙ H) := by + have := adj.isLeftAdjoint + refine ⟨fun _ ↦ inferInstance, fun _ ↦ ⟨fun {J _} ↦ ?_⟩⟩ + rw [adj.preservesColimitsOfShape_iff] + infer_instance + +end CategoryTheory.Adjunction diff --git a/Mathlib/CategoryTheory/Bicategory/Functor/Pseudofunctor.lean b/Mathlib/CategoryTheory/Bicategory/Functor/Pseudofunctor.lean index 6206aaaa30f76b..812a7390fb5ca8 100644 --- a/Mathlib/CategoryTheory/Bicategory/Functor/Pseudofunctor.lean +++ b/Mathlib/CategoryTheory/Bicategory/Functor/Pseudofunctor.lean @@ -155,12 +155,6 @@ def comp (F : B ⥤ᵖ C) (G : C ⥤ᵖ D) : B ⥤ᵖ D where toPrelaxFunctor := F.toPrelaxFunctor.comp G.toPrelaxFunctor mapId := fun a => G.map₂Iso (F.mapId a) ≪≫ G.mapId (F.obj a) mapComp := fun f g => (G.map₂Iso (F.mapComp f g)) ≪≫ G.mapComp (F.map f) (F.map g) - -- Note: whilst these are all provable by `cat_disch`, the proof is very slow - map₂_whisker_left f η := by simp - map₂_whisker_right η h := by simp - map₂_associator f g h := by simp - map₂_left_unitor f := by simp - map₂_right_unitor f := by simp section diff --git a/Mathlib/CategoryTheory/Comma/Arrow.lean b/Mathlib/CategoryTheory/Comma/Arrow.lean index 706c60c4316985..e6b396b312d393 100644 --- a/Mathlib/CategoryTheory/Comma/Arrow.lean +++ b/Mathlib/CategoryTheory/Comma/Arrow.lean @@ -375,7 +375,6 @@ def mapArrowFunctor : (C ⥤ D) ⥤ (Arrow C ⥤ Arrow D) where variable {C D} -set_option backward.isDefEq.respectTransparency false in /-- The equivalence of categories `Arrow C ≌ Arrow D` induced by an equivalence `C ≌ D`. -/ def mapArrowEquivalence (e : C ≌ D) : Arrow C ≌ Arrow D where functor := e.functor.mapArrow diff --git a/Mathlib/CategoryTheory/Comma/Over/Basic.lean b/Mathlib/CategoryTheory/Comma/Over/Basic.lean index 2c06853a066418..d6c3c85933cfff 100644 --- a/Mathlib/CategoryTheory/Comma/Over/Basic.lean +++ b/Mathlib/CategoryTheory/Comma/Over/Basic.lean @@ -471,7 +471,6 @@ instance isRightAdjoint_post {Y : D} {G : D ⥤ T} [G.IsRightAdjoint] : (post (X := Y) G).IsRightAdjoint := let ⟨F, ⟨a⟩⟩ := ‹G.IsRightAdjoint›; ⟨_, ⟨postAdjunctionRight a⟩⟩ -set_option backward.isDefEq.respectTransparency false in /-- An equivalence of categories induces an equivalence on over categories. -/ @[simps] def postEquiv (F : T ≌ D) : Over X ≌ Over (F.functor.obj X) where @@ -507,7 +506,6 @@ protected def lift {J : Type*} [Category* J] (D : J ⥤ T) {X : T} (s : D ⟶ (F obj j := mk (s.app j) map f := homMk (D.map f) -set_option backward.isDefEq.respectTransparency false in /-- The induced cone on `Over X` on the lifted functor. -/ @[simps] def liftCone {J : Type*} [Category* J] (D : J ⥤ T) {X : T} (s : D ⟶ (Functor.const J).obj X) @@ -533,7 +531,6 @@ def isLimitLiftCone {J : Type*} [Category* J] [Nonempty J] end Over -set_option backward.isDefEq.respectTransparency false in /-- Restrict a cone to the diagram over `j`. This preserves being limiting if the forgetful functor `Over j ⥤ J` is initial (see `CategoryTheory.Limits.IsLimit.overPost`). @@ -960,7 +957,6 @@ def postAdjunctionLeft {X : T} {F : T ⥤ D} {G : D ⥤ T} (a : F ⊣ G) : instance isLeftAdjoint_post [F.IsLeftAdjoint] : (post (X := X) F).IsLeftAdjoint := let ⟨G, ⟨a⟩⟩ := ‹F.IsLeftAdjoint›; ⟨_, ⟨postAdjunctionLeft a⟩⟩ -set_option backward.isDefEq.respectTransparency false in /-- An equivalence of categories induces an equivalence on under categories. -/ @[simps] def postEquiv (F : T ≌ D) : Under X ≌ Under (F.functor.obj X) where @@ -987,7 +983,6 @@ protected def lift {J : Type*} [Category* J] (D : J ⥤ T) {X : T} (s : (Functor obj j := .mk (s.app j) map f := Under.homMk (D.map f) (by simpa using (s.naturality f).symm) -set_option backward.isDefEq.respectTransparency false in /-- The induced cocone on `Under X` from on the lifted functor. -/ @[simps] def liftCocone {J : Type*} [Category* J] (D : J ⥤ T) {X : T} (s : (Functor.const J).obj X ⟶ D) @@ -1013,7 +1008,6 @@ def isColimitLiftCocone {J : Type*} [Category* J] [Nonempty J] end Under -set_option backward.isDefEq.respectTransparency false in /-- Restrict a cocone to the diagram under `j`. This preserves being colimiting if the forgetful functor `Over j ⥤ J` is final (see `CategoryTheory.Limits.IsColimit.underPost`). diff --git a/Mathlib/CategoryTheory/Core.lean b/Mathlib/CategoryTheory/Core.lean index 776901e439d1a1..c8fdb8daac2bef 100644 --- a/Mathlib/CategoryTheory/Core.lean +++ b/Mathlib/CategoryTheory/Core.lean @@ -232,7 +232,6 @@ variable (D : Type u₂) [Category.{v₂} D] namespace Equivalence -set_option backward.isDefEq.respectTransparency false in variable {D} in /-- Equivalent categories have equivalent cores. -/ @[simps!] diff --git a/Mathlib/CategoryTheory/Equivalence.lean b/Mathlib/CategoryTheory/Equivalence.lean index 9375cc9690b96a..4aee85b929e584 100644 --- a/Mathlib/CategoryTheory/Equivalence.lean +++ b/Mathlib/CategoryTheory/Equivalence.lean @@ -445,7 +445,6 @@ def congrLeft (e : C ≌ D) : C ⥤ E ≌ D ⥤ E where simp only [funInvIdAssoc_inv_app, id_obj, comp_obj, invFunIdAssoc_hom_app, Functor.comp_map, ← F.map_comp, unit_inverse_comp, map_id] -set_option backward.isDefEq.respectTransparency false in /-- If `C` is equivalent to `D`, then `E ⥤ C` is equivalent to `E ⥤ D`. -/ @[simps! functor inverse unitIso_hom_app unitIso_inv_app counitIso_hom_app counitIso_inv_app] def congrRight (e : C ≌ D) : E ⥤ C ≌ E ⥤ D where @@ -564,12 +563,10 @@ instance essSurj_functor (e : C ≌ E) : e.functor.EssSurj := instance essSurj_inverse (e : C ≌ E) : e.inverse.EssSurj := e.symm.essSurj_functor -set_option backward.isDefEq.respectTransparency false in /-- The functor of an equivalence of categories is fully faithful. -/ def fullyFaithfulFunctor (e : C ≌ E) : e.functor.FullyFaithful where preimage {X Y} f := e.unitIso.hom.app X ≫ e.inverse.map f ≫ e.unitIso.inv.app Y -set_option backward.isDefEq.respectTransparency false in /-- The inverse of an equivalence of categories is fully faithful. -/ def fullyFaithfulInverse (e : C ≌ E) : e.inverse.FullyFaithful where preimage {X Y} f := e.counitIso.inv.app X ≫ e.functor.map f ≫ e.counitIso.hom.app Y @@ -590,7 +587,6 @@ instance full_functor (e : C ≌ E) : e.functor.Full := instance full_inverse (e : C ≌ E) : e.inverse.Full := e.fullyFaithfulInverse.full -set_option backward.isDefEq.respectTransparency false in /-- If `e : C ≌ D` is an equivalence of categories, and `iso : e.functor ≅ G` is an isomorphism, then there is an equivalence of categories whose functor is `G`. -/ @[simps!] @@ -607,7 +603,6 @@ theorem changeFunctor_refl (e : C ≌ D) : e.changeFunctor (Iso.refl _) = e := b theorem changeFunctor_trans (e : C ≌ D) {G G' : C ⥤ D} (iso₁ : e.functor ≅ G) (iso₂ : G ≅ G') : (e.changeFunctor iso₁).changeFunctor iso₂ = e.changeFunctor (iso₁ ≪≫ iso₂) := by cat_disch -set_option backward.isDefEq.respectTransparency false in /-- If `e : C ≌ D` is an equivalence of categories, and `iso : e.functor ≅ G` is an isomorphism, then there is an equivalence of categories whose inverse is `G`. -/ @[simps!] @@ -784,7 +779,6 @@ construct an isomorphism `G.functor ≅ G.functor` from an isomorphism `G.invers def isoFunctorOfIsoInverse {G G' : C ≌ D} (i : G.inverse ≅ G'.inverse) : G.functor ≅ G'.functor := isoInverseOfIsoFunctor (G := G.symm) (G' := G'.symm) i -set_option backward.isDefEq.respectTransparency false in /-- Sanity check: `isoFunctorOfIsoInverse (isoInverseOfIsoFunctor i)` is just `i`. -/ @[simp] lemma isoFunctorOfIsoInverse_isoInverseOfIsoFunctor {G G' : C ≌ D} (i : G.functor ≅ G'.functor) : diff --git a/Mathlib/CategoryTheory/Functor/TypeValuedFlat.lean b/Mathlib/CategoryTheory/Functor/TypeValuedFlat.lean index 5c6533fab34ea8..a4ecbcf00ec67e 100644 --- a/Mathlib/CategoryTheory/Functor/TypeValuedFlat.lean +++ b/Mathlib/CategoryTheory/Functor/TypeValuedFlat.lean @@ -97,6 +97,8 @@ def fromOverFunctorElementsEquivalence : (by cat_disch) unitIso := Iso.refl _ counitIso := Iso.refl _ + -- `cat_disch` can fill in this proof, but is unfortunately quite slow. + functor_unitIso_comp X := by simp_all; rfl instance [IsCofiltered F.Elements] : IsCofiltered (fromOverFunctor F x).Elements := .of_equivalence (fromOverFunctorElementsEquivalence F x).symm diff --git a/Mathlib/CategoryTheory/Limits/ConeCategory.lean b/Mathlib/CategoryTheory/Limits/ConeCategory.lean index 6e8fcebc1ed0c0..2a9ca846d1b030 100644 --- a/Mathlib/CategoryTheory/Limits/ConeCategory.lean +++ b/Mathlib/CategoryTheory/Limits/ConeCategory.lean @@ -36,7 +36,6 @@ universe v₁ v₂ v₃ v₄ u₁ u₂ u₃ u₄ variable {J : Type u₁} [Category.{v₁} J] {K : Type u₂} [Category.{v₂} K] variable {C : Type u₃} [Category.{v₃} C] {D : Type u₄} [Category.{v₄} D] -set_option backward.isDefEq.respectTransparency false in /-- Given a cone `c` over `F`, we can interpret the legs of `c` as structured arrows `c.pt ⟶ F.obj -`. -/ @[simps] @@ -52,7 +51,6 @@ noncomputable def limit.toStructuredArrow (F : J ⥤ C) [HasLimit F] : obj j := StructuredArrow.mk (limit.π F j) map f := StructuredArrow.homMk f -set_option backward.isDefEq.respectTransparency false in /-- `Cone.toStructuredArrow` can be expressed in terms of `Functor.toStructuredArrow`. -/ def Cone.toStructuredArrowIsoToStructuredArrow {F : J ⥤ C} (c : Cone F) : c.toStructuredArrow ≅ (𝟭 J).toStructuredArrow c.pt F c.π.app (by simp) := @@ -91,7 +89,6 @@ lemma Cone.toStructuredArrow_comp_toUnder_comp_forget {F : J ⥤ C} (c : Cone F) c.toStructuredArrow ⋙ StructuredArrow.toUnder _ _ ⋙ Under.forget _ = F := rfl -set_option backward.isDefEq.respectTransparency false in /-- A cone `c` on `F : J ⥤ C` lifts to a cone in `Over c.pt` with cone point `𝟙 c.pt`. -/ @[simps] def Cone.toUnder {F : J ⥤ C} (c : Cone F) : @@ -119,7 +116,6 @@ def Cone.fromStructuredArrow (F : C ⥤ D) {X : D} (G : J ⥤ StructuredArrow X pt := X π := { app := fun j => (G.obj j).hom } -set_option backward.isDefEq.respectTransparency false in /-- Given a cone `c : Cone K` and a map `f : X ⟶ F.obj c.X`, we can construct a cone of structured arrows over `X` with `f` as the cone point. -/ @@ -199,7 +195,6 @@ noncomputable def IsLimit.ofReflectsConeTerminal {F : J ⥤ C} {F' : K ⥤ D} (G [ReflectsLimit (Functor.empty.{0} _) G] {c : Cone F} (hc : IsLimit (G.obj c)) : IsLimit c := (Cone.isLimitEquivIsTerminal _).symm <| (Cone.isLimitEquivIsTerminal _ hc).isTerminalOfObj _ _ -set_option backward.isDefEq.respectTransparency false in /-- Given a cocone `c` over `F`, we can interpret the legs of `c` as costructured arrows `F.obj - ⟶ c.pt`. -/ @[simps] @@ -215,7 +210,6 @@ noncomputable def colimit.toCostructuredArrow (F : J ⥤ C) [HasColimit F] : obj j := CostructuredArrow.mk (colimit.ι F j) map f := CostructuredArrow.homMk f -set_option backward.isDefEq.respectTransparency false in /-- `Cocone.toCostructuredArrow` can be expressed in terms of `Functor.toCostructuredArrow`. -/ def Cocone.toCostructuredArrowIsoToCostructuredArrow {F : J ⥤ C} (c : Cocone F) : c.toCostructuredArrow ≅ (𝟭 J).toCostructuredArrow F c.pt c.ι.app (by simp) := @@ -254,7 +248,6 @@ lemma Cocone.toCostructuredArrow_comp_toOver_comp_forget {F : J ⥤ C} (c : Coco c.toCostructuredArrow ⋙ CostructuredArrow.toOver _ _ ⋙ Over.forget _ = F := rfl -set_option backward.isDefEq.respectTransparency false in /-- A cocone `c` on `F : J ⥤ C` lifts to a cocone in `Over c.pt` with cone point `𝟙 c.pt`. -/ @[simps] def Cocone.toOver {F : J ⥤ C} (c : Cocone F) : @@ -283,7 +276,6 @@ def Cocone.fromCostructuredArrow (F : C ⥤ D) {X : D} (G : J ⥤ CostructuredAr pt := X ι := { app := fun j => (G.obj j).hom } -set_option backward.isDefEq.respectTransparency false in /-- Given a cocone `c : Cocone K` and a map `f : F.obj c.X ⟶ X`, we can construct a cocone of costructured arrows over `X` with `f` as the cone point. -/ @[simps] @@ -293,7 +285,6 @@ def Cocone.toCostructuredArrowCocone {K : J ⥤ C} (c : Cocone K) (F : C ⥤ D) pt := CostructuredArrow.mk f ι := { app := fun j => CostructuredArrow.homMk (c.ι.app j) rfl } -set_option backward.isDefEq.respectTransparency false in /-- Construct an object of the category `(F ↓ Δ)` from a cocone on `F`. This is part of an equivalence, see `Cocone.equivStructuredArrow`. -/ @[simps] diff --git a/Mathlib/CategoryTheory/Limits/Constructions/EventuallyConstant.lean b/Mathlib/CategoryTheory/Limits/Constructions/EventuallyConstant.lean index 1918b1f5c6cbfb..40f422b9e72ce4 100644 --- a/Mathlib/CategoryTheory/Limits/Constructions/EventuallyConstant.lean +++ b/Mathlib/CategoryTheory/Limits/Constructions/EventuallyConstant.lean @@ -115,7 +115,6 @@ noncomputable def cone : Cone F where let β : i ⟶ j := IsCofiltered.minToRight _ _ rw [h.coneπApp_eq j _ α β, assoc, h.coneπApp_eq j' _ α (β ≫ φ), map_comp] } -set_option backward.isDefEq.respectTransparency false in /-- When `h : F.IsEventuallyConstantTo i₀`, the limit of `F` exists and is `F.obj i₀`. -/ noncomputable def isLimitCone : IsLimit h.cone where lift s := s.π.app i₀ @@ -138,7 +137,6 @@ lemma isIso_π_of_isLimit' {c : Cone F} (hc : IsLimit c) (j : J) (π : j ⟶ i IsIso (c.π.app j) := (h.precomp π).isIso_π_of_isLimit hc -set_option backward.isDefEq.respectTransparency false in /-- Given a cone `c` on a cofiltered diagram `F` which `IsEventuallyConstantTo i₀`, such that `c.π.app i₀` is an isomorphism, `c` a limit cone. -/ noncomputable def isLimitOfIsIso (c : Cone F) [IsIso (c.π.app i₀)] : IsLimit c := diff --git a/Mathlib/CategoryTheory/Limits/Constructions/Over/Connected.lean b/Mathlib/CategoryTheory/Limits/Constructions/Over/Connected.lean index 0eed67d447f31a..be3afb7e07be3d 100644 --- a/Mathlib/CategoryTheory/Limits/Constructions/Over/Connected.lean +++ b/Mathlib/CategoryTheory/Limits/Constructions/Over/Connected.lean @@ -138,7 +138,6 @@ instance hasLimitsOfShape_of_isConnected {B : C} [IsConnected J] [HasLimitsOfSha HasLimitsOfShape J (Over B) where has_limit F := hasLimit_of_created F (forget B) -set_option backward.isDefEq.respectTransparency false in /-- The functor taking a cone over `F` to a cone over `Over.post F : Over i ⥤ Over (F.obj i)`. This takes limit cones to limit cones when `J` is cofiltered. See `isLimitConePost` -/ @[simps] diff --git a/Mathlib/CategoryTheory/Limits/Final.lean b/Mathlib/CategoryTheory/Limits/Final.lean index a346ac867f21ca..6a89caf407433a 100644 --- a/Mathlib/CategoryTheory/Limits/Final.lean +++ b/Mathlib/CategoryTheory/Limits/Final.lean @@ -1191,7 +1191,6 @@ section Restriction variable {J C : Type*} [Category* J] [Category* C] {D : J ⥤ C} -set_option backward.isDefEq.respectTransparency false in /-- If `Over j ⥤ J` is initial, restricting a limit cone to the diagram above `j`, preserves the limit. -/ noncomputable def Limits.IsLimit.overPost {c : Cone D} (hc : IsLimit c) (j : J) @@ -1206,7 +1205,6 @@ noncomputable def Limits.IsLimit.overPost {c : Cone D} (hc : IsLimit c) (j : J) · exact NatIso.ofComponents (fun k ↦ CategoryTheory.Over.isoMk (Iso.refl _)) · exact Cone.ext (Iso.refl _) -set_option backward.isDefEq.respectTransparency false in /-- If `Over j ⥤ J` is final, restricting a colimit cocone to the diagram below `j`, preserves the limit. -/ noncomputable def Limits.IsColimit.underPost {c : Cocone D} (hc : IsColimit c) (j : J) diff --git a/Mathlib/CategoryTheory/Limits/IsLimit.lean b/Mathlib/CategoryTheory/Limits/IsLimit.lean index 8c18b71afdb4b9..6ab2c102f31dea 100644 --- a/Mathlib/CategoryTheory/Limits/IsLimit.lean +++ b/Mathlib/CategoryTheory/Limits/IsLimit.lean @@ -190,7 +190,6 @@ def ofPointIso {r t : Cone F} (P : IsLimit r) [i : IsIso (P.lift t)] : IsLimit t variable {t : Cone F} -set_option backward.isDefEq.respectTransparency false in theorem hom_lift (h : IsLimit t) {W : C} (m : W ⟶ t.pt) : m = h.lift { pt := W, π := { app := fun b => m ≫ t.π.app b } } := h.uniq { pt := W, π := { app := fun b => m ≫ t.π.app b } } m fun _ => rfl @@ -579,7 +578,6 @@ def ofExistsUnique {t : Cocone F} choose s hs hs' using ht exact ⟨s, hs, hs'⟩ -set_option backward.isDefEq.respectTransparency false in /-- Alternative constructor for `IsColimit`, providing a morphism of cocones rather than a morphism between the cocone points and separately the factorisation condition. @@ -668,7 +666,6 @@ def ofPointIso {r t : Cocone F} (P : IsColimit r) [i : IsIso (P.desc t)] : IsCol variable {t : Cocone F} -set_option backward.isDefEq.respectTransparency false in theorem hom_desc (h : IsColimit t) {W : C} (m : t.pt ⟶ W) : m = h.desc @@ -929,7 +926,6 @@ def mapCoconeEquiv {D : Type u₄} [Category.{v₄} D] {K : J ⥤ C} {F G : C apply IsColimit.ofIsoColimit _ (precomposeWhiskerLeftMapCocone h c) apply (precomposeInvEquiv (isoWhiskerLeft K h :) _).symm t -set_option backward.isDefEq.respectTransparency false in /-- A cocone is a colimit cocone exactly if there is a unique cocone morphism from any other cocone. -/ diff --git a/Mathlib/CategoryTheory/Limits/Over.lean b/Mathlib/CategoryTheory/Limits/Over.lean index e7471394af71c5..f034e642335dd7 100644 --- a/Mathlib/CategoryTheory/Limits/Over.lean +++ b/Mathlib/CategoryTheory/Limits/Over.lean @@ -86,7 +86,6 @@ def _root_.CategoryTheory.Limits.colimit.isColimitToOver (F : J ⥤ C) [HasColim IsColimit (colimit.toOver F) := Over.isColimitToOver (colimit.isColimit F) -set_option backward.isDefEq.respectTransparency false in /-- Given an arrow `c.pt ⟶ X`, the diagram `J ⥤ C` can be lifted to `Over X ⥤ C`, and the cocone `c` also lifts to the diagram on `Over`. -/ @[simps] def liftCocone {F : J ⥤ C} (c : Cocone F) {X : C} (f : c.pt ⟶ X) : @@ -147,7 +146,6 @@ def _root_.CategoryTheory.Limits.limit.isLimitToOver (F : J ⥤ C) [HasLimit F] IsLimit (limit.toUnder F) := Under.isLimitToUnder (limit.isLimit F) -set_option backward.isDefEq.respectTransparency false in /-- Given an arrow `X ⟶ c.pt`, the diagram `J ⥤ C` can be lifted to `Under X ⥤ C`, and the cone `c` also lifts to the diagram on `Under`. -/ @[simps] def liftCone {F : J ⥤ C} (c : Cone F) {X : C} (f : X ⟶ c.pt) : diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Basic.lean b/Mathlib/CategoryTheory/Limits/Preserves/Basic.lean index 38a597fb39f62f..128472443817a4 100644 --- a/Mathlib/CategoryTheory/Limits/Preserves/Basic.lean +++ b/Mathlib/CategoryTheory/Limits/Preserves/Basic.lean @@ -232,7 +232,6 @@ lemma preservesLimits_of_natIso {F G : C ⥤ D} (h : F ≅ G) [PreservesLimitsOf PreservesLimitsOfSize.{w, w'} G where preservesLimitsOfShape := preservesLimitsOfShape_of_natIso h -set_option backward.isDefEq.respectTransparency false in /-- Transfer preservation of limits along an equivalence in the shape. -/ lemma preservesLimitsOfShape_of_equiv {J' : Type w₂} [Category.{w₂'} J'] (e : J ≌ J') (F : C ⥤ D) [PreservesLimitsOfShape J F] : PreservesLimitsOfShape J' F where @@ -292,7 +291,6 @@ lemma preservesColimits_of_natIso {F G : C ⥤ D} (h : F ≅ G) [PreservesColimi PreservesColimitsOfSize.{w, w'} G where preservesColimitsOfShape {_J} _𝒥₁ := preservesColimitsOfShape_of_natIso h -set_option backward.isDefEq.respectTransparency false in /-- Transfer preservation of colimits along an equivalence in the shape. -/ lemma preservesColimitsOfShape_of_equiv {J' : Type w₂} [Category.{w₂'} J'] (e : J ≌ J') (F : C ⥤ D) [PreservesColimitsOfShape J F] : PreservesColimitsOfShape J' F where diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Bifunctor.lean b/Mathlib/CategoryTheory/Limits/Preserves/Bifunctor.lean index 891abc86d1301b..f6e317a9c8fcc1 100644 --- a/Mathlib/CategoryTheory/Limits/Preserves/Bifunctor.lean +++ b/Mathlib/CategoryTheory/Limits/Preserves/Bifunctor.lean @@ -48,7 +48,6 @@ def Functor.mapCocone₂ (G : C₁ ⥤ C₂ ⥤ C) {K₁ : J₁ ⥤ C₁} {K₂ ← Functor.map_comp, NatTrans.naturality, const_obj_map, const_obj_obj, ← NatTrans.comp_app_assoc, c₁.w] } -set_option backward.isDefEq.respectTransparency false in /-- Given a bifunctor `G : C₁ ⥤ C₂ ⥤ C`, diagrams `K₁ : J₁ ⥤ C₁` and `K₂ : J₂ ⥤ C₂`, and cones over these diagrams, `G.mapCone₂ c₁ c₂` is the cone over the diagram `J₁ × J₂ ⥤ C` obtained by applying `G` to both `c₁` and `c₂`. -/ diff --git a/Mathlib/CategoryTheory/Limits/Preserves/BifunctorCokernel.lean b/Mathlib/CategoryTheory/Limits/Preserves/BifunctorCokernel.lean new file mode 100644 index 00000000000000..55f119c9d54706 --- /dev/null +++ b/Mathlib/CategoryTheory/Limits/Preserves/BifunctorCokernel.lean @@ -0,0 +1,107 @@ +/- +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.Limits.Preserves.Shapes.Kernels +public import Mathlib.CategoryTheory.Limits.Shapes.BinaryProducts + +/-! +# Action of bifunctors on cokernels + +Let `c₁` (resp. `c₂`) be a cokernel cofork for a morphism `f₁ : X₁ ⟶ Y₁` +in a category `C₁` (resp. `f₂ : X₂ ⟶ Y₂` in `C₂`). Given a bifunctor `F : C₁ ⥤ C₂ ⥤ C`, +we construct a cokernel cofork with point `(F.obj c₁.pt).obj c₂.pt` for +the obvious morphism `(F.obj X₁).obj Y₂ ⨿ (F.obj Y₁).obj X₂ ⟶ (F.obj Y₁).obj Y₂`, +and show that it is a colimit when both coforks are colimit, the cokernel of `f₁` +is preserved by `F.obj c₁.pt` and the cokernel of `f₂` is preserved by +`F.flip.obj X₁` and `F.flip.obj Y₁`. + +-/ + +@[expose] public section + +namespace CategoryTheory.Limits + +variable {C₁ C₂ C : Type*} [Category* C₁] [Category* C₂] [Category* C] + [HasZeroMorphisms C₁] [HasZeroMorphisms C₂] [HasZeroMorphisms C] + +namespace CokernelCofork + +variable {X₁ Y₁ : C₁} {f₁ : X₁ ⟶ Y₁} {c₁ : CokernelCofork f₁} (hc₁ : IsColimit c₁) + {X₂ Y₂ : C₂} {f₂ : X₂ ⟶ Y₂} {c₂ : CokernelCofork f₂} (hc₂ : IsColimit c₂) + (F : C₁ ⥤ C₂ ⥤ C) + [(F.obj c₁.pt).PreservesZeroMorphisms] + [F.PreservesZeroMorphisms] + +set_option backward.isDefEq.respectTransparency false in +variable (c₁ c₂) in +/-- Let `c₁` (resp. `c₂`) be a cokernel cofork for a morphism `f₁ : X₁ ⟶ Y₁` +in a category `C₁` (resp. `f₂ : X₂ ⟶ Y₂` in `C₂`). Given a bifunctor `F : C₁ ⥤ C₂ ⥤ C`, +this is the cokernel cofork with point `(F.obj c₁.pt).obj c₂.pt` for +the obvious morphism `(F.obj X₁).obj Y₂ ⨿ (F.obj Y₁).obj X₂ ⟶ (F.obj Y₁).obj Y₂`. -/ +noncomputable abbrev mapBifunctor [HasBinaryCoproduct ((F.obj X₁).obj Y₂) ((F.obj Y₁).obj X₂)] : + CokernelCofork (coprod.desc ((F.map f₁).app Y₂) ((F.obj Y₁).map f₂)) := + CokernelCofork.ofπ (Z := (F.obj c₁.pt).obj c₂.pt) + ((F.map c₁.π).app Y₂ ≫ (F.obj c₁.pt).map c₂.π) (by + ext + · simp [← NatTrans.comp_app_assoc, ← Functor.map_comp] + · simp [← Functor.map_comp]) + +variable [PreservesColimit (parallelPair f₂ 0) (F.obj c₁.pt)] + [PreservesColimit (parallelPair f₁ 0) (F.flip.obj Y₂)] + +namespace isColimitMapBifunctor + +include hc₁ hc₂ + +lemma hom_ext {T : C} {f g : (F.obj c₁.pt).obj c₂.pt ⟶ T} + (h : (F.map c₁.π).app Y₂ ≫ (F.obj c₁.pt).map c₂.π ≫ f = + (F.map c₁.π).app Y₂ ≫ (F.obj c₁.pt).map c₂.π ≫ g) : f = g := + Cofork.IsColimit.hom_ext (mapIsColimit _ hc₂ (F.obj c₁.pt)) + (Cofork.IsColimit.hom_ext (mapIsColimit _ hc₁ (F.flip.obj Y₂)) h) + +variable [HasBinaryCoproduct ((F.obj X₁).obj Y₂) ((F.obj Y₁).obj X₂)] + [PreservesColimit (parallelPair f₁ 0) (F.flip.obj X₂)] + +set_option backward.isDefEq.respectTransparency false in +lemma exists_desc (s : CokernelCofork (coprod.desc ((F.map f₁).app Y₂) ((F.obj Y₁).map f₂))) : + ∃ (l : (F.obj c₁.pt).obj c₂.pt ⟶ s.pt), + (F.map c₁.π).app Y₂ ≫ (F.obj c₁.pt).map c₂.π ≫ l = s.π := by + obtain ⟨l, hl⟩ := Cofork.IsColimit.desc' (mapIsColimit _ hc₁ (F.flip.obj Y₂)) s.π (by + have := coprod.inl ≫= s.condition + rw [coprod.inl_desc_assoc, comp_zero] at this + rwa [zero_comp]) + obtain ⟨l', hl'⟩ := Cofork.IsColimit.desc' (mapIsColimit _ hc₂ (F.obj c₁.pt)) l (by + have := coprod.inr ≫= s.condition + rw [coprod.inr_desc_assoc, ← dsimp% hl, NatTrans.naturality_assoc, comp_zero] at this + apply Cofork.IsColimit.hom_ext (mapIsColimit _ hc₁ (F.flip.obj X₂)) + rwa [zero_comp, comp_zero]) + exact ⟨l', by cat_disch⟩ + +end isColimitMapBifunctor + +variable [HasBinaryCoproduct ((F.obj X₁).obj Y₂) ((F.obj Y₁).obj X₂)] + [PreservesColimit (parallelPair f₁ 0) (F.flip.obj X₂)] + +open isColimitMapBifunctor in +/-- Let `c₁` (resp. `c₂`) be a colimit cokernel cofork for a morphism `f₁ : X₁ ⟶ Y₁` +in a category `C₁` (resp. `f₂ : X₂ ⟶ Y₂` in `C₂`). If `F : C₁ ⥤ C₂ ⥤ C` is a bifunctor, +then `(F.obj c₁.pt).obj c₂.pt` identifies to the cokernel of the morphism +`(F.obj X₁).obj Y₂ ⨿ (F.obj Y₁).obj X₂ ⟶ (F.obj Y₁).obj Y₂` +when the cokernel of `f₁` is preserved by `F.obj c₁.pt` and the cokernel of `f₂` +is preserved by `F.flip.obj X₁` and `F.flip.obj Y₁`. -/ +noncomputable def isColimitMapBifunctor : + IsColimit (mapBifunctor c₁ c₂ F) := + Cofork.IsColimit.mk _ + (fun s ↦ (exists_desc hc₁ hc₂ F s).choose) + (fun s ↦ by simpa using (exists_desc hc₁ hc₂ F s).choose_spec) + (fun s m hm ↦ hom_ext hc₁ hc₂ F (by + dsimp + rw [dsimp% (exists_desc hc₁ hc₂ F s).choose_spec, ← dsimp% hm, Category.assoc])) + +end CokernelCofork + +end CategoryTheory.Limits diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Equalizers.lean b/Mathlib/CategoryTheory/Limits/Shapes/Equalizers.lean index 0ef516024ae206..8e1d756057519b 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Equalizers.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Equalizers.lean @@ -619,7 +619,6 @@ theorem Cone.ofFork_π {F : WalkingParallelPair ⥤ C} (t : Fork (F.map left) (F theorem Cocone.ofCofork_ι {F : WalkingParallelPair ⥤ C} (t : Cofork (F.map left) (F.map right)) (j) : (Cocone.ofCofork t).ι.app j = eqToHom (by simp) ≫ t.ι.app j := rfl -set_option backward.isDefEq.respectTransparency false in /-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as `parallelPair (F.map left) (F.map right)` and a cone on `F`, we get a fork on `F.map left` and `F.map right`. -/ @@ -628,7 +627,6 @@ def Fork.ofCone {F : WalkingParallelPair ⥤ C} (t : Cone F) : Fork (F.map left) π := { app := fun X => t.π.app X ≫ eqToHom (by simp) naturality := by rintro _ _ (_ | _ | _) <;> simp } -set_option backward.isDefEq.respectTransparency false in /-- Given `F : WalkingParallelPair ⥤ C`, which is really the same as `parallelPair (F.map left) (F.map right)` and a cocone on `F`, we get a cofork on `F.map left` and `F.map right`. -/ diff --git a/Mathlib/CategoryTheory/Limits/Shapes/IsTerminal.lean b/Mathlib/CategoryTheory/Limits/Shapes/IsTerminal.lean index fe781bb15b2fea..760818d7b4b4b1 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/IsTerminal.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/IsTerminal.lean @@ -347,7 +347,6 @@ def coneOfDiagramInitial {X : J} (tX : IsInitial X) (F : J ⥤ C) : Cone F where dsimp rw [← F.map_comp, Category.id_comp, tX.hom_ext (tX.to j ≫ k) (tX.to j')] } -set_option backward.isDefEq.respectTransparency false in /-- From a functor `F : J ⥤ C`, given an initial object of `J`, show the cone `coneOfDiagramInitial` is a limit. -/ def limitOfDiagramInitial {X : J} (tX : IsInitial X) (F : J ⥤ C) : @@ -374,7 +373,6 @@ def coneOfDiagramTerminal {X : J} (hX : IsTerminal X) (F : J ⥤ C) simp only [IsIso.eq_inv_comp, IsIso.comp_inv_eq, Category.id_comp, ← F.map_comp, hX.hom_ext (hX.from i) (f ≫ hX.from j)] } -set_option backward.isDefEq.respectTransparency false in /-- From a functor `F : J ⥤ C`, given a terminal object of `J` and that the morphisms in the diagram are isomorphisms, show the cone `coneOfDiagramTerminal` is a limit. -/ def limitOfDiagramTerminal {X : J} (hX : IsTerminal X) (F : J ⥤ C) @@ -392,7 +390,6 @@ def coconeOfDiagramTerminal {X : J} (tX : IsTerminal X) (F : J ⥤ C) : Cocone F dsimp rw [← F.map_comp, Category.comp_id, tX.hom_ext (k ≫ tX.from j') (tX.from j)] } -set_option backward.isDefEq.respectTransparency false in /-- From a functor `F : J ⥤ C`, given a terminal object of `J`, show the cocone `coconeOfDiagramTerminal` is a colimit. -/ def colimitOfDiagramTerminal {X : J} (tX : IsTerminal X) (F : J ⥤ C) : @@ -422,7 +419,6 @@ def coconeOfDiagramInitial {X : J} (hX : IsInitial X) (F : J ⥤ C) simp only [IsIso.eq_inv_comp, IsIso.comp_inv_eq, Category.comp_id, ← F.map_comp, hX.hom_ext (hX.to i ≫ f) (hX.to j)] } -set_option backward.isDefEq.respectTransparency false in /-- From a functor `F : J ⥤ C`, given an initial object of `J` and that the morphisms in the diagram are isomorphisms, show the cone `coconeOfDiagramInitial` is a colimit. -/ def colimitOfDiagramInitial {X : J} (hX : IsInitial X) (F : J ⥤ C) @@ -471,4 +467,30 @@ def IsTerminal.unop {X : Cᵒᵖ} (hX : IsTerminal X) : IsInitial X.unop := IsInitial.ofUniqueHom (fun _ ↦ (hX.from _).unop) (fun _ _ ↦ Quiver.Hom.op_inj (hX.hom_ext _ _)) -end CategoryTheory.Limits +end Limits + +namespace Functor +open Limits +variable (C : Type*) [Category* C] {D : Type*} [Category* D] + +/-- The constant functor returning a specific terminal object is indeed terminal. -/ +def isTerminalConst {X : D} (hX : IsTerminal X) : + IsTerminal ((Functor.const C).obj X) := + .ofUniqueHom (fun Y => {app Z := hX.from (Y.obj Z)}) (by intros; ext; apply hX.hom_ext) + +@[simp] +lemma isTerminalConst_from_app {X : D} (hX : IsTerminal X) + (F : C ⥤ D) (Y : C) : ((isTerminalConst C hX).from F).app Y = hX.from (F.obj Y) := rfl + +/-- The constant functor returning a specific initial object is indeed initial. -/ +def isInitialConst {X : D} (hX : IsInitial X) : + IsInitial ((Functor.const C).obj X) := + .ofUniqueHom (fun Y => {app Z := hX.to (Y.obj Z)}) (by intros; ext; apply hX.hom_ext) + +@[simp] +lemma isInitialConst_to_app {X : D} (hX : IsInitial X) + (F : C ⥤ D) (Y : C) : ((isInitialConst C hX).to F).app Y = hX.to (F.obj Y) := rfl + +end Functor + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Multiequalizer.lean b/Mathlib/CategoryTheory/Limits/Shapes/Multiequalizer.lean index bf970094f28c53..34154aa9327bdc 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Multiequalizer.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Multiequalizer.lean @@ -566,7 +566,6 @@ def ext {t s : Multifork I} (e : t.pt ≅ s.pt) def isoOfι (t : Multifork I) : t ≅ ofι _ t.pt t.ι t.condition := ext (Iso.refl _) -set_option backward.isDefEq.respectTransparency false in /-- This definition provides a convenient way to show that a multifork is a limit. -/ @[simps] def IsLimit.mk (lift : ∀ E : Multifork I, E.pt ⟶ K.pt) diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/PullbackCone.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/PullbackCone.lean index 8a57de33de362a..b40573d65dd6fd 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/PullbackCone.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/PullbackCone.lean @@ -163,7 +163,6 @@ reconstructed using `PullbackCone.mk`. -/ def eta (t : PullbackCone f g) : t ≅ mk t.fst t.snd t.condition := PullbackCone.ext (Iso.refl _) -set_option backward.isDefEq.respectTransparency false in /-- This is a slightly more convenient method to verify that a pullback cone is a limit cone. It only asks for a proof of facts that carry any mathematical content -/ def isLimitAux (t : PullbackCone f g) (lift : ∀ s : PullbackCone f g, s.pt ⟶ t.pt) @@ -289,7 +288,6 @@ def PullbackCone.ofCone {F : WalkingCospan ⥤ C} (t : Cone F) : pt := t.pt π := t.π ≫ (diagramIsoCospan F).hom -set_option backward.isDefEq.respectTransparency false in /-- A diagram `WalkingCospan ⥤ C` is isomorphic to some `PullbackCone.mk` after composing with `diagramIsoCospan`. -/ @[simps!] @@ -508,7 +506,6 @@ def PushoutCocone.ofCocone {F : WalkingSpan ⥤ C} (t : Cocone F) : pt := t.pt ι := (diagramIsoSpan F).inv ≫ t.ι -set_option backward.isDefEq.respectTransparency false in /-- A diagram `WalkingSpan ⥤ C` is isomorphic to some `PushoutCocone.mk` after composing with `diagramIsoSpan`. -/ @[simps!] diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Reflexive.lean b/Mathlib/CategoryTheory/Limits/Shapes/Reflexive.lean index c2f6f160362791..c4427a2c7a7a58 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Reflexive.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Reflexive.lean @@ -518,14 +518,12 @@ def mk {X : C} (π : F.obj zero ⟶ X) (h : F.map left ≫ π = F.map right ≫ lemma mk_π {X : C} (π : F.obj zero ⟶ X) (h : F.map left ≫ π = F.map right ≫ π) : (mk π h).π = π := rfl -set_option backward.isDefEq.respectTransparency false in lemma condition (G : ReflexiveCofork F) : F.map left ≫ G.π = F.map right ≫ G.π := by rw [Cocone.w G left, Cocone.w G right] @[simp] lemma app_one_eq_π (G : ReflexiveCofork F) : G.ι.app zero = G.π := rfl -set_option backward.isDefEq.respectTransparency false in /-- The underlying `Cofork` of a `ReflexiveCofork`. -/ abbrev toCofork (G : ReflexiveCofork F) : Cofork (F.map left) (F.map right) := Cofork.ofπ G.π (by simp) diff --git a/Mathlib/CategoryTheory/Limits/Shapes/WideEqualizers.lean b/Mathlib/CategoryTheory/Limits/Shapes/WideEqualizers.lean index 7a982a522f520b..2423bd9a7cf3bd 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/WideEqualizers.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/WideEqualizers.lean @@ -293,7 +293,6 @@ def Cotrident.IsColimit.desc' [Nonempty J] {s : Cotrident f} (hs : IsColimit s) (h : ∀ j₁ j₂, f j₁ ≫ k = f j₂ ≫ k) : { l : s.pt ⟶ W // Cotrident.π s ≫ l = k } := ⟨hs.desc <| Cotrident.ofπ _ h, hs.fac _ _⟩ -set_option backward.isDefEq.respectTransparency false in /-- This is a slightly more convenient method to verify that a trident is a limit cone. It only asks for a proof of facts that carry any mathematical content -/ def Trident.IsLimit.mk [Nonempty J] (t : Trident f) (lift : ∀ s : Trident f, s.pt ⟶ t.pt) @@ -427,7 +426,6 @@ theorem Cocone.ofCotrident_ι {F : WalkingParallelFamily J ⥤ C} (Cocone.ofCotrident t).ι.app j = eqToHom (by cases j <;> cat_disch) ≫ t.ι.app j := rfl -set_option backward.isDefEq.respectTransparency false in /-- Given `F : WalkingParallelFamily ⥤ C`, which is really the same as `parallelFamily (fun j ↦ F.map (line j))` and a cone on `F`, we get a trident on `fun j ↦ F.map (line j)`. -/ @@ -438,7 +436,6 @@ def Trident.ofCone {F : WalkingParallelFamily J ⥤ C} (t : Cone F) : { app := fun X => t.π.app X ≫ eqToHom (by cases X <;> cat_disch) naturality := by rintro _ _ (_ | _) <;> cat_disch } -set_option backward.isDefEq.respectTransparency false in /-- Given `F : WalkingParallelFamily ⥤ C`, which is really the same as `parallelFamily (F.map left) (F.map right)` and a cocone on `F`, we get a cotrident on `fun j ↦ F.map (line j)`. -/ diff --git a/Mathlib/CategoryTheory/Limits/Sifted.lean b/Mathlib/CategoryTheory/Limits/Sifted.lean index 1f14c94309daef..49df3ad334f74e 100644 --- a/Mathlib/CategoryTheory/Limits/Sifted.lean +++ b/Mathlib/CategoryTheory/Limits/Sifted.lean @@ -65,7 +65,6 @@ namespace IsSifted variable {C} -set_option backward.isDefEq.respectTransparency false in /-- Being sifted is preserved by equivalences of categories -/ lemma isSifted_of_equiv [IsSifted C] {D : Type u₁} [Category.{v₁} D] (e : D ≌ C) : IsSifted D := letI : Final (diag D) := by diff --git a/Mathlib/CategoryTheory/Limits/Types/Products.lean b/Mathlib/CategoryTheory/Limits/Types/Products.lean index 6e0454d4149ca1..af9ff2a28bf9ed 100644 --- a/Mathlib/CategoryTheory/Limits/Types/Products.lean +++ b/Mathlib/CategoryTheory/Limits/Types/Products.lean @@ -62,48 +62,38 @@ theorem pi_map_π_apply' {β : Type v} {f g : β → Type v} (α : ∀ j, f j (Pi.π g b : ∏ᶜ g → g b) (Pi.map α x) = α b ((Pi.π f b : ∏ᶜ f → f b) x) := by simp -/-- The category of types has `PUnit` as a terminal object. -/ -def terminalLimitCone : Limits.LimitCone (Functor.empty (Type u)) where - -- Porting note: tidy was able to fill the structure automatically - cone := - { pt := PUnit - π := (Functor.uniqueFromEmpty _).hom } - isLimit := - { lift := fun _ _ => PUnit.unit - fac := fun _ => by rintro ⟨⟨⟩⟩ } - /-- The terminal object in `Type u` is `PUnit`. -/ -noncomputable def terminalIso : ⊤_ Type u ≅ PUnit := - limit.isoLimitCone terminalLimitCone.{u, 0} +def isTerminalPUnit : IsTerminal (PUnit : Type u) := + letI (X : Type u) : Unique (X ⟶ PUnit) := inferInstanceAs (Unique (X → PUnit)) + .ofUnique _ -/-- The terminal object in `Type u` is `PUnit`. -/ -noncomputable def isTerminalPUnit : IsTerminal (PUnit : Type u) := - terminalIsTerminal.ofIso terminalIso +@[simp] +lemma isTerminalPUnit_from_apply {X : Type u} (x : X) : isTerminalPUnit.from X x = .unit := rfl @[deprecated (since := "2026-02-08")] alias isTerminalPunit := isTerminalPUnit -noncomputable instance : Inhabited (⊤_ (Type u)) := - ⟨@terminal.from (Type u) _ _ (ULift (Fin 1)) (ULift.up 0)⟩ - -instance : Subsingleton (⊤_ (Type u)) := ⟨fun a b => - congr_fun (@Subsingleton.elim (_ ⟶ ⊤_ (Type u)) _ - (fun _ => a) (fun _ => b)) (ULift.up (0 : Fin 1))⟩ +/-- The category of types has `PUnit` as a terminal object. -/ +def terminalLimitCone : Limits.LimitCone (Functor.empty (Type u)) := ⟨_, isTerminalPUnit⟩ -noncomputable instance : Unique (⊤_ (Type u)) := Unique.mk' _ +/-- The terminal object in `Type u` is `PUnit`. -/ +noncomputable def terminalIso : ⊤_ Type u ≅ PUnit := + terminalIsTerminal.uniqueUpToIso isTerminalPUnit /-- A type is terminal if and only if it contains exactly one element. -/ -noncomputable def isTerminalEquivUnique (X : Type u) : IsTerminal X ≃ Unique X := +def isTerminalEquivUnique (X : Type u) : IsTerminal X ≃ Unique X := equivOfSubsingletonOfSubsingleton - (fun h => ((Iso.toEquiv (terminalIsoIsTerminal h).symm).unique)) - (fun _ => IsTerminal.ofIso terminalIsTerminal (Equiv.toIso (Equiv.ofUnique _ _))) + (fun h => (IsTerminal.uniqueUpToIso h isTerminalPUnit).toEquiv.unique) + (fun _ => IsTerminal.ofIso isTerminalPUnit (Equiv.toIso (Equiv.ofUnique _ _))) /-- A type is terminal if and only if it is isomorphic to `PUnit`. -/ -noncomputable def isTerminalEquivIsoPUnit (X : Type u) : IsTerminal X ≃ (X ≅ PUnit) := by +def isTerminalEquivIsoPUnit (X : Type u) : IsTerminal X ≃ (X ≅ PUnit) := by calc IsTerminal X ≃ Unique X := isTerminalEquivUnique _ _ ≃ (X ≃ PUnit.{u + 1}) := uniqueEquivEquivUnique _ _ _ ≃ (X ≅ PUnit) := equivEquivIso +noncomputable instance : Unique (⊤_ (Type u)) := isTerminalEquivUnique _ terminalIsTerminal + open CategoryTheory.Limits.WalkingPair -- We manually generate the other projection lemmas since the simp-normal form for the legs is diff --git a/Mathlib/CategoryTheory/Limits/VanKampen.lean b/Mathlib/CategoryTheory/Limits/VanKampen.lean index b22fb60001e7e3..90d4b3a49c990e 100644 --- a/Mathlib/CategoryTheory/Limits/VanKampen.lean +++ b/Mathlib/CategoryTheory/Limits/VanKampen.lean @@ -89,7 +89,6 @@ theorem IsInitial.isVanKampenColimit [HasStrictInitialObjects C] {X : C} (h : Is section Functor -set_option backward.isDefEq.respectTransparency false in theorem IsUniversalColimit.of_iso {F : J ⥤ C} {c c' : Cocone F} (hc : IsUniversalColimit c) (e : c ≅ c') : IsUniversalColimit c' := by intro F' c'' α f h hα H @@ -101,7 +100,6 @@ theorem IsUniversalColimit.of_iso {F : J ⥤ C} {c c' : Cocone F} (hc : IsUniver rw [← Category.comp_id (α.app j)] exact (H j).paste_vert (IsPullback.of_vert_isIso ⟨by simp⟩) -set_option backward.isDefEq.respectTransparency false in theorem IsVanKampenColimit.of_iso {F : J ⥤ C} {c c' : Cocone F} (H : IsVanKampenColimit c) (e : c ≅ c') : IsVanKampenColimit c' := by intro F' c'' α f h hα @@ -194,7 +192,6 @@ theorem IsUniversalColimit.whiskerEquivalence {K : Type*} [Category* K] (e : J refine (H (e.inverse.obj k)).paste_vert ?_ exact IsPullback.of_vert_isIso ⟨by simp⟩ -set_option backward.isDefEq.respectTransparency false in theorem IsUniversalColimit.whiskerEquivalence_iff {K : Type*} [Category* K] (e : J ≌ K) {F : K ⥤ C} {c : Cocone F} : IsUniversalColimit (c.whisker e.functor) ↔ IsUniversalColimit c := @@ -227,7 +224,6 @@ theorem IsVanKampenColimit.whiskerEquivalence {K : Type*} [Category* K] (e : J · ext k simpa using congr_app e' (e.inverse.obj k) -set_option backward.isDefEq.respectTransparency false in theorem IsVanKampenColimit.whiskerEquivalence_iff {K : Type*} [Category* K] (e : J ≌ K) {F : K ⥤ C} {c : Cocone F} : IsVanKampenColimit (c.whisker e.functor) ↔ IsVanKampenColimit c := diff --git a/Mathlib/CategoryTheory/Monad/Basic.lean b/Mathlib/CategoryTheory/Monad/Basic.lean index 81b0b334de6c60..854258c393b2fa 100644 --- a/Mathlib/CategoryTheory/Monad/Basic.lean +++ b/Mathlib/CategoryTheory/Monad/Basic.lean @@ -143,10 +143,6 @@ instance : Category (Monad C) where { toNatTrans := { app := fun X => f.app X ≫ g.app X naturality := fun X Y h => by rw [assoc, f.1.naturality_assoc, g.1.naturality] } } - -- `cat_disch` can fill in these proofs, but is unfortunately slightly slow. - id_comp _ := MonadHom.ext (by funext; simp only [NatTrans.id_app, id_comp]) - comp_id _ := MonadHom.ext (by funext; simp only [NatTrans.id_app, comp_id]) - assoc _ _ _ := MonadHom.ext (by funext; simp only [assoc]) set_option backward.isDefEq.respectTransparency false in instance : Category (Comonad C) where @@ -155,10 +151,6 @@ instance : Category (Comonad C) where { toNatTrans := { app := fun X => f.app X ≫ g.app X naturality := fun X Y h => by rw [assoc, f.1.naturality_assoc, g.1.naturality] } } - -- `cat_disch` can fill in these proofs, but is unfortunately slightly slow. - id_comp _ := ComonadHom.ext (by funext; simp only [NatTrans.id_app, id_comp]) - comp_id _ := ComonadHom.ext (by funext; simp only [NatTrans.id_app, comp_id]) - assoc _ _ _ := ComonadHom.ext (by funext; simp only [assoc]) instance {T : Monad C} : Inhabited (MonadHom T T) := ⟨𝟙 T⟩ diff --git a/Mathlib/CategoryTheory/Monoidal/Braided/Transport.lean b/Mathlib/CategoryTheory/Monoidal/Braided/Transport.lean index 821642e106bb7a..c8ebbd726c789b 100644 --- a/Mathlib/CategoryTheory/Monoidal/Braided/Transport.lean +++ b/Mathlib/CategoryTheory/Monoidal/Braided/Transport.lean @@ -66,17 +66,14 @@ instance (e : C ≌ D) [MonoidalCategory C] [BraidedCategory C] : (e' e).functor.Braided where braided X Y := by apply (e' e).inverse.map_injective - have : Functor.LaxMonoidal.μ (((e' e).functor ⋙ (e' e).inverse)) X Y ≫ - ((e' e).functor ⋙ (e' e).inverse).map (β_ X Y).hom ≫ - Functor.OplaxMonoidal.δ ((e' e).functor ⋙ (e' e).inverse) Y X = - (β_ (((e' e).functor ⋙ (e' e).inverse).obj X) - (((e' e).functor ⋙ (e' e).inverse).obj Y)).hom := by + have : (β_ (((e' e).functor ⋙ (e' e).inverse).obj X) + (((e' e).functor ⋙ (e' e).inverse).obj Y)).hom = + Functor.LaxMonoidal.μ (((e' e).functor ⋙ (e' e).inverse)) X Y ≫ + ((e' e).functor ⋙ (e' e).inverse).map (β_ X Y).hom ≫ + Functor.OplaxMonoidal.δ ((e' e).functor ⋙ (e' e).inverse) Y X := by simp only [((e' e).functor ⋙ (e' e).inverse).map_braiding X Y, assoc, Functor.Monoidal.μ_δ, comp_id, Functor.Monoidal.μ_δ_assoc] - simp? [-Adjunction.rightAdjointLaxMonoidal_μ] at this says - simp only [Functor.comp_obj, comp_μ, Functor.comp_map, - Equivalence.inv_fun_map, Functor.id_obj, comp_δ, assoc] at this - simp [-Adjunction.rightAdjointLaxMonoidal_μ, ← this] + simp_all end diff --git a/Mathlib/CategoryTheory/Monoidal/CommGrp_.lean b/Mathlib/CategoryTheory/Monoidal/CommGrp_.lean index c4ba237414b931..d09c2f39f6bb87 100644 --- a/Mathlib/CategoryTheory/Monoidal/CommGrp_.lean +++ b/Mathlib/CategoryTheory/Monoidal/CommGrp_.lean @@ -307,7 +307,6 @@ end Adjunction namespace Equivalence variable (e : C ≌ D) [e.functor.Braided] [e.inverse.Braided] -set_option backward.isDefEq.respectTransparency false in /-- An equivalence of categories lifts to an equivalence of their commutative group objects. -/ @[simps] noncomputable def mapCommGrp : CommGrp C ≌ CommGrp D where functor := e.functor.mapCommGrp diff --git a/Mathlib/CategoryTheory/Monoidal/CommMon_.lean b/Mathlib/CategoryTheory/Monoidal/CommMon_.lean index 2380309888aa25..c927ae9096af91 100644 --- a/Mathlib/CategoryTheory/Monoidal/CommMon_.lean +++ b/Mathlib/CategoryTheory/Monoidal/CommMon_.lean @@ -274,7 +274,6 @@ end Adjunction namespace Equivalence -set_option backward.isDefEq.respectTransparency false in /-- An equivalence of categories lifts to an equivalence of their commutative monoid objects. -/ @[simps] def mapCommMon (e : C ≌ D) [e.functor.Braided] [e.inverse.Braided] [e.IsMonoidal] : diff --git a/Mathlib/CategoryTheory/Monoidal/Free/Basic.lean b/Mathlib/CategoryTheory/Monoidal/Free/Basic.lean index 41a8593128b4eb..0fe00ad70615e2 100644 --- a/Mathlib/CategoryTheory/Monoidal/Free/Basic.lean +++ b/Mathlib/CategoryTheory/Monoidal/Free/Basic.lean @@ -256,8 +256,7 @@ theorem Hom.inductionOn {motive : {X Y : F C} → (X ⟶ Y) → Prop} {X Y : F C (whiskerLeft : (X : F C) → {Y Z : F C} → (f : Y ⟶ Z) → motive f → motive (X ◁ f)) (whiskerRight : {X Y : F C} → (f : X ⟶ Y) → (Z : F C) → motive f → motive (f ▷ Z)) : motive t := by - apply Quotient.inductionOn - intro f + induction t using Quotient.inductionOn with | _ f induction f with | id X => exact id X | α_hom X Y Z => exact α_hom X Y Z @@ -266,15 +265,15 @@ theorem Hom.inductionOn {motive : {X Y : F C} → (X ⟶ Y) → Prop} {X Y : F C | l_inv X => exact l_inv X | ρ_hom X => exact ρ_hom X | ρ_inv X => exact ρ_inv X - | comp f g hf hg => exact comp _ _ (hf ⟦f⟧) (hg ⟦g⟧) - | whiskerLeft X f hf => exact whiskerLeft X _ (hf ⟦f⟧) - | whiskerRight f X hf => exact whiskerRight _ X (hf ⟦f⟧) + | comp f g hf hg => exact comp _ _ hf hg + | whiskerLeft X f hf => exact whiskerLeft X _ hf + | whiskerRight f X hf => exact whiskerRight _ X hf | @tensor W X Y Z f g hf hg => have : homMk f ⊗ₘ homMk g = homMk f ▷ X ≫ Y ◁ homMk g := Quotient.sound (HomEquiv.tensorHom_def f g) change motive (homMk f ⊗ₘ homMk g) rw [this] - exact comp _ _ (whiskerRight _ _ (hf ⟦f⟧)) (whiskerLeft _ _ (hg ⟦g⟧)) + exact comp _ _ (whiskerRight _ _ hf) (whiskerLeft _ _ hg) section Functor diff --git a/Mathlib/CategoryTheory/Monoidal/Functor.lean b/Mathlib/CategoryTheory/Monoidal/Functor.lean index 9bdf6ec1fc38fc..2cd5163e968fa4 100644 --- a/Mathlib/CategoryTheory/Monoidal/Functor.lean +++ b/Mathlib/CategoryTheory/Monoidal/Functor.lean @@ -613,7 +613,44 @@ attribute [reassoc (attr := simp)] μIso_hom_natural_left attribute [reassoc] left_unitality right_unitality -variable {F} (h : F.CoreMonoidal) +variable {F} + +/-- Alternative constructor for `CoreMonoidal`, for which the axioms are stated +in terms on the inverses of `εIso` and `μIso`. -/ +@[simps] +def mk' (εIso : 𝟙_ D ≅ F.obj (𝟙_ C)) + (μIso : ∀ X Y : C, F.obj X ⊗ F.obj Y ≅ F.obj (X ⊗ Y)) + (μIso_inv_natural_left : ∀ {X Y : C} (f : X ⟶ Y) (X' : C), + (μIso X X').inv ≫ F.map f ▷ F.obj X' = F.map (f ▷ X') ≫ (μIso Y X').inv := by cat_disch) + (μIso_inv_natural_right : ∀ {X Y : C} (X' : C) (f : X ⟶ Y), + (μIso X' X).inv ≫ F.obj X' ◁ F.map f = F.map (X' ◁ f) ≫ (μIso X' Y).inv := by cat_disch) + (oplax_associativity : ∀ X Y Z : C, + (μIso (X ⊗ Y) Z).inv ≫ (μIso X Y).inv ▷ F.obj Z ≫ + (α_ (F.obj X) (F.obj Y) (F.obj Z)).hom = + F.map (α_ X Y Z).hom ≫ (μIso X (Y ⊗ Z)).inv ≫ F.obj X ◁ (μIso Y Z).inv := by cat_disch) + (oplax_left_unitality : ∀ X : C, (λ_ (F.obj X)).inv = + F.map (λ_ X).inv ≫ (μIso (𝟙_ C) X).inv ≫ εIso.inv ▷ F.obj X := by cat_disch) + (oplax_right_unitality : ∀ X : C, (ρ_ (F.obj X)).inv = + F.map (ρ_ X).inv ≫ (μIso X (𝟙_ C)).inv ≫ F.obj X ◁ εIso.inv := by cat_disch) : + F.CoreMonoidal where + εIso := εIso + μIso := μIso + μIso_hom_natural_left {X Y} f X' := by + simp [← cancel_epi (μIso X X').inv, reassoc_of% μIso_inv_natural_left f X'] + μIso_hom_natural_right {X Y} X' g := by + simp [← cancel_mono (μIso X' Y).inv, ← (μIso_inv_natural_right X' g)] + associativity X Y Z := by + rw [← cancel_epi ((μIso X Y).inv ▷ F.obj Z), ← cancel_epi (μIso (X ⊗ Y) Z).inv, + reassoc_of% oplax_associativity] + simp + left_unitality X := by + rw [← cancel_mono (λ_ (F.obj X)).inv, Iso.hom_inv_id, oplax_left_unitality] + simp + right_unitality X := by + rw [← cancel_mono (ρ_ (F.obj X)).inv, Iso.hom_inv_id, oplax_right_unitality] + simp + +variable (h : F.CoreMonoidal) /-- The lax monoidal functor structure induced by a `Functor.CoreMonoidal` structure. -/ @[simps -isSimp, implicit_reducible] @@ -856,7 +893,7 @@ variable [F.OplaxMonoidal] set_option backward.isDefEq.respectTransparency false in /-- The right adjoint of an oplax monoidal functor is lax monoidal. -/ -@[simps, implicit_reducible] +@[simps -isSimp, implicit_reducible] def rightAdjointLaxMonoidal : G.LaxMonoidal where ε := adj.homEquiv _ _ (η F) μ X Y := adj.homEquiv _ _ (δ F _ _ ≫ (adj.counit.app X ⊗ₘ adj.counit.app Y)) @@ -971,7 +1008,7 @@ variable [G.LaxMonoidal] set_option backward.isDefEq.respectTransparency false in /-- The left adjoint of a lax monoidal functor is oplax monoidal. -/ -@[simps, implicit_reducible] +@[simps -isSimp, implicit_reducible] def leftAdjointOplaxMonoidal : F.OplaxMonoidal where η := (adj.homEquiv _ _).symm (ε G) δ X Y := (adj.homEquiv _ _).symm ((adj.unit.app X ⊗ₘ adj.unit.app Y) ≫ μ G _ _) @@ -1022,12 +1059,14 @@ instance : adj.IsMonoidal := by letI := adj.leftAdjointOplaxMonoidal refine ⟨?_, fun X Y ↦ ?_⟩ - · simp [homEquiv_counit] - · simp [homEquiv_counit, ← μ_natural] + · simp [homEquiv_counit, leftAdjointOplaxMonoidal_η] + · simp [homEquiv_counit, ← μ_natural, leftAdjointOplaxMonoidal_δ] end OplaxMonoidal set_option backward.isDefEq.respectTransparency false in +attribute [local simp] leftAdjointOplaxMonoidal_η leftAdjointOplaxMonoidal_δ + rightAdjointLaxMonoidal_ε rightAdjointLaxMonoidal_μ in /-- If `F ⊣ G` is an adjunction, the `G` is lax monoidal iff `F` is oplax monoidal. It is advisable to use `Adjunction.leftAdjointOplaxMonoidal` and `Adjunction.rightAdjointLaxMonoidal`, because compatibilities between diff --git a/Mathlib/CategoryTheory/Monoidal/FunctorCategory.lean b/Mathlib/CategoryTheory/Monoidal/FunctorCategory.lean index 5c9944463f26c0..9df889a2ad3b0c 100644 --- a/Mathlib/CategoryTheory/Monoidal/FunctorCategory.lean +++ b/Mathlib/CategoryTheory/Monoidal/FunctorCategory.lean @@ -243,7 +243,6 @@ instance (E : Type*) [Category* E] [MonoidalCategory E] (e : C ≌ D) : (e.congrLeft (E := E)).inverse.Monoidal := inferInstanceAs ((Functor.whiskeringLeft _ _ E).obj e.functor).Monoidal -set_option backward.isDefEq.respectTransparency false in instance (E : Type*) [Category* E] [MonoidalCategory E] (e : C ≌ D) : (e.congrLeft (E := E)).IsMonoidal where leftAdjoint_μ X Y := by diff --git a/Mathlib/CategoryTheory/Monoidal/Grp_.lean b/Mathlib/CategoryTheory/Monoidal/Grp_.lean index 53d67fa6c22694..e9f76582a41e15 100644 --- a/Mathlib/CategoryTheory/Monoidal/Grp_.lean +++ b/Mathlib/CategoryTheory/Monoidal/Grp_.lean @@ -666,7 +666,6 @@ end Adjunction namespace Equivalence variable (e : C ≌ D) [e.functor.Monoidal] [e.inverse.Monoidal] -set_option backward.isDefEq.respectTransparency false in /-- An equivalence of categories lifts to an equivalence of their group objects. -/ @[simps] def mapGrp : Grp C ≌ Grp D where functor := e.functor.mapGrp diff --git a/Mathlib/CategoryTheory/Monoidal/Limits/Colimits.lean b/Mathlib/CategoryTheory/Monoidal/Limits/Colimits.lean index ce6236af681f9e..00d60c62e88fba 100644 --- a/Mathlib/CategoryTheory/Monoidal/Limits/Colimits.lean +++ b/Mathlib/CategoryTheory/Monoidal/Limits/Colimits.lean @@ -59,7 +59,6 @@ section variable {F₁ F₂ : J ⥤ C} {c₁ : Cocone F₁} {c₂ : Cocone F₂} -set_option backward.isDefEq.respectTransparency false in variable (c₁ c₂) in /-- The tensor product of two cocones. -/ @[simps!] diff --git a/Mathlib/CategoryTheory/Monoidal/Mon_.lean b/Mathlib/CategoryTheory/Monoidal/Mon_.lean index 83bb843d016c66..13ef478848d635 100644 --- a/Mathlib/CategoryTheory/Monoidal/Mon_.lean +++ b/Mathlib/CategoryTheory/Monoidal/Mon_.lean @@ -887,7 +887,6 @@ end Adjunction namespace Equivalence -set_option backward.isDefEq.respectTransparency false in /-- An equivalence of categories lifts to an equivalence of their monoid objects. -/ @[simps] def mapMon (e : C ≌ D) [e.functor.Monoidal] [e.inverse.Monoidal] [e.IsMonoidal] : diff --git a/Mathlib/CategoryTheory/Monoidal/Transport.lean b/Mathlib/CategoryTheory/Monoidal/Transport.lean index 02ab7565d07327..407bffeffde5a5 100644 --- a/Mathlib/CategoryTheory/Monoidal/Transport.lean +++ b/Mathlib/CategoryTheory/Monoidal/Transport.lean @@ -154,7 +154,6 @@ def transportStruct (e : C ≌ D) : MonoidalCategoryStruct.{v₂} D where #adaptation_note /-- Prior to https://github.com/leanprover/lean4/pull/12244 the fields `whiskerList_eq` and following were all filled by the `cat_disch` auto_param. -/ attribute [local simp] transportStruct in -set_option backward.isDefEq.respectTransparency false in /-- Transport a monoidal structure along an equivalence of (plain) categories. -/ @[implicit_reducible] diff --git a/Mathlib/CategoryTheory/MorphismProperty/Limits.lean b/Mathlib/CategoryTheory/MorphismProperty/Limits.lean index 9d4bde353611dd..8ee98ed0d0cdbc 100644 --- a/Mathlib/CategoryTheory/MorphismProperty/Limits.lean +++ b/Mathlib/CategoryTheory/MorphismProperty/Limits.lean @@ -187,7 +187,6 @@ instance IsStableUnderBaseChange.isomorphisms : (isomorphisms C).IsStableUnderBaseChange where of_isPullback h _ := h.isIso_snd_of_isIso -set_option backward.isDefEq.respectTransparency false in instance IsStableUnderBaseChange.monomorphisms : (monomorphisms C).IsStableUnderBaseChange where of_isPullback h _ := h.mono_snd_of_mono @@ -310,7 +309,6 @@ instance IsStableUnderCobaseChange.isomorphisms : (isomorphisms C).IsStableUnderCobaseChange where of_isPushout h _ := h.isIso_inl_of_isIso -set_option backward.isDefEq.respectTransparency false in variable (C) in instance IsStableUnderCobaseChange.epimorphisms : (epimorphisms C).IsStableUnderCobaseChange where @@ -524,7 +522,6 @@ lemma colimitsOfShape_colimMap {X Y : J ⥤ C} W.colimitsOfShape J (colimMap f) := ⟨_, _, _, _, _, colimit.isColimit Y, _, hf⟩ -set_option backward.isDefEq.respectTransparency false in attribute [local instance] IsCofiltered.isConnected in variable {W} in lemma colimitsOfShape.of_isColimit diff --git a/Mathlib/CategoryTheory/MorphismProperty/OfObjectProperty.lean b/Mathlib/CategoryTheory/MorphismProperty/OfObjectProperty.lean index c541ac54bc4c0c..5d23ea9ac6d0b5 100644 --- a/Mathlib/CategoryTheory/MorphismProperty/OfObjectProperty.lean +++ b/Mathlib/CategoryTheory/MorphismProperty/OfObjectProperty.lean @@ -48,7 +48,6 @@ lemma ofObjectProperty_inverseImage {D : Type*} [Category* D] (F : D ⥤ C) : (ofObjectProperty P Q).inverseImage F := by rfl -set_option backward.isDefEq.respectTransparency false in lemma ofObjectProperty_map_le {D : Type*} [Category* D] (F : C ⥤ D) : (ofObjectProperty P Q).map F ≤ ofObjectProperty (P.map F) (Q.map F) := by intro X Y f ⟨X', Y', f', ⟨hX', hY'⟩, ⟨i⟩⟩ diff --git a/Mathlib/CategoryTheory/ObjectProperty/Kernels.lean b/Mathlib/CategoryTheory/ObjectProperty/Kernels.lean new file mode 100644 index 00000000000000..b4509dcb9a049c --- /dev/null +++ b/Mathlib/CategoryTheory/ObjectProperty/Kernels.lean @@ -0,0 +1,153 @@ +/- +Copyright (c) 2026 Justus Springer. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Justus Springer +-/ +module + +public import Mathlib.CategoryTheory.Limits.FullSubcategory +public import Mathlib.CategoryTheory.MorphismProperty.OfObjectProperty +public import Mathlib.CategoryTheory.ObjectProperty.EpiMono + +/-! +# Objects that are (co)kernels of morphisms + +Given a morphism property `W` on a category, we introduce two object properties +`kernels W` and `cokernels W`, consisting of all (co)kernels of morphisms +satisfying `W`. + +Given an object property `P`, we also introduce two predicates +`P.IsClosedUnderKernels` and `P.IsClosedUnderCokernels`, stating that all +(co)kernels of morphisms between objects in `P` remain in `P`. + +-/ + +@[expose] public section + +namespace CategoryTheory + +open Limits + +variable {C : Type*} [Category* C] [HasZeroMorphisms C] + +namespace MorphismProperty + +variable (W : MorphismProperty C) + +/-- The property of objects that are kernels of morphisms satisfying `W`. -/ +inductive kernels : ObjectProperty C + | of_isLimit {X₁ X₂ : C} (f : X₁ ⟶ X₂) (k : KernelFork f) (hk : IsLimit k) + (hf : W f) : kernels k.pt + +set_option backward.isDefEq.respectTransparency false in +instance : W.kernels.IsClosedUnderIsomorphisms where + of_iso := by + rintro _ _ i ⟨f, k, hk, hf⟩ + exact .of_isLimit f (KernelFork.ofι (i.inv ≫ k.ι) (by simp)) + (IsLimit.ofIsoLimit hk (Fork.ext i)) hf + +/-- The property of objects that are cokernels of morphisms satisfying `W`. -/ +inductive cokernels : ObjectProperty C + | of_isColimit {X₁ X₂ : C} (f : X₁ ⟶ X₂) (k : CokernelCofork f) (hk : IsColimit k) + (hf : W f) : cokernels k.pt + +set_option backward.isDefEq.respectTransparency false in +instance : W.cokernels.IsClosedUnderIsomorphisms where + of_iso := by + rintro _ _ i ⟨f, k, hk, hf⟩ + exact .of_isColimit f (CokernelCofork.ofπ (k.π ≫ i.hom) (by simp)) + (IsColimit.ofIsoColimit hk (Cofork.ext i)) hf + +end MorphismProperty + +namespace ObjectProperty + +variable (P : ObjectProperty C) + +/-- A property of objects satisfies `P.IsClosedUnderKernels` if whenever `X` and `Y` +satisfy `P`, all kernels of morphisms from `X` to `Y` satisfy `P`. -/ +@[mk_iff] +class IsClosedUnderKernels : Prop where + kernels_le : (MorphismProperty.ofObjectProperty P P).kernels ≤ P + +lemma prop_of_isLimit_kernelFork [P.IsClosedUnderKernels] {X Y : C} {f : X ⟶ Y} {k : KernelFork f} + (hk : IsLimit k) (hX : P X) (hY : P Y) : P k.pt := + IsClosedUnderKernels.kernels_le _ (.of_isLimit _ k hk ⟨hX, hY⟩) + +lemma prop_kernel [P.IsClosedUnderKernels] {X Y : C} (f : X ⟶ Y) [HasKernel f] (hX : P X) + (hY : P Y) : P (kernel f) := + (P.prop_of_isLimit_kernelFork (kernelIsKernel f) hX hY :) + +set_option backward.isDefEq.respectTransparency false in +instance [P.IsClosedUnderSubobjects] : P.IsClosedUnderKernels where + kernels_le := by + intro _ ⟨_, k, hk, hf⟩ + letI := Fork.IsLimit.mono hk + exact P.prop_of_mono k.ι hf.1 + +lemma hasLimit_parallelPair_comp_ι {X Y : P.FullSubcategory} (f : X ⟶ Y) [HasKernel f.hom] : + HasLimit (parallelPair f 0 ⋙ P.ι) := + hasLimit_of_iso (F := parallelPair f.hom 0) (Iso.symm (diagramIsoParallelPair _)) + +/-- If an object property `P` is closed under kernels, then `P.ι` creates kernels. +In particular, this implies `P.ι` preserves kernels. -/ +@[reducible] +noncomputable def createsKernels [P.IsClosedUnderKernels] {X Y : P.FullSubcategory} + (f : X ⟶ Y) [HasKernel f.hom] : CreatesLimit (parallelPair f 0) P.ι := by + fapply createsLimitFullSubcategoryInclusion' + · exact (Cone.postcompose (Iso.symm (diagramIsoParallelPair _)).hom).obj + (Fork.ofι (kernel.ι f.hom) (by simp)) + · exact (IsLimit.postcomposeInvEquiv _ _).symm (kernelIsKernel f.hom) + · exact P.prop_kernel f.hom X.property Y.property + +instance [P.IsClosedUnderKernels] [HasKernels C] : HasKernels P.FullSubcategory where + has_limit f := + letI := P.createsKernels f + letI := P.hasLimit_parallelPair_comp_ι f + hasLimit_of_created _ P.ι + +/-- A property of objects satisfies `P.IsClosedUnderCokernels` if whenever `X` and `Y` +satisfy `P`, all kernels of morphisms from `X` to `Y` satisfy `P`. -/ +@[mk_iff] +class IsClosedUnderCokernels : Prop where + cokernels_le : (MorphismProperty.ofObjectProperty P P).cokernels ≤ P + +lemma prop_of_isColimit_cokernelCofork [P.IsClosedUnderCokernels] {X Y : C} {f : X ⟶ Y} + {k : CokernelCofork f} (hk : IsColimit k) (hX : P X) (hY : P Y) : P k.pt := + IsClosedUnderCokernels.cokernels_le _ (.of_isColimit _ k hk ⟨hX, hY⟩) + +lemma prop_cokernel [P.IsClosedUnderCokernels] {X Y : C} (f : X ⟶ Y) [HasCokernel f] (hX : P X) + (hY : P Y) : P (cokernel f) := + (P.prop_of_isColimit_cokernelCofork (cokernelIsCokernel f) hX hY :) + +set_option backward.isDefEq.respectTransparency false in +instance [P.IsClosedUnderQuotients] : P.IsClosedUnderCokernels where + cokernels_le := by + intro _ ⟨_, k, hk, hf⟩ + letI := Cofork.IsColimit.epi hk + exact P.prop_of_epi k.π hf.2 + +lemma hasColimit_parallelPair_comp_ι {X Y : P.FullSubcategory} (f : X ⟶ Y) [HasCokernel f.hom] : + HasColimit (parallelPair f 0 ⋙ P.ι) := + hasColimit_of_iso (F := parallelPair f.hom 0) (diagramIsoParallelPair _) + +/-- If an object property `P` is closed under cokernels, then `P.ι` creates cokernels. +In particular, this implies `P.ι` preserves cokernels. -/ +@[reducible] +noncomputable def createsCokernels [P.IsClosedUnderCokernels] {X Y : P.FullSubcategory} + (f : X ⟶ Y) [HasCokernel f.hom] : CreatesColimit (parallelPair f 0) P.ι := by + fapply createsColimitFullSubcategoryInclusion' + · exact (Cocone.precompose (diagramIsoParallelPair _).hom).obj + (Cofork.ofπ (cokernel.π f.hom) (by simp)) + · exact (IsColimit.precomposeHomEquiv _ _).symm (cokernelIsCokernel f.hom) + · exact P.prop_cokernel f.hom X.property Y.property + +instance [P.IsClosedUnderCokernels] [HasCokernels C] : HasCokernels P.FullSubcategory where + has_colimit f := + letI := P.createsCokernels f + letI := P.hasColimit_parallelPair_comp_ι f + hasColimit_of_created _ P.ι + +end ObjectProperty + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Opposites.lean b/Mathlib/CategoryTheory/Opposites.lean index fc2b631727a492..621cd9eadf41f6 100644 --- a/Mathlib/CategoryTheory/Opposites.lean +++ b/Mathlib/CategoryTheory/Opposites.lean @@ -729,7 +729,6 @@ namespace Equivalence variable {D : Type u₂} [Category.{v₂} D] -set_option backward.isDefEq.respectTransparency false in /-- An equivalence between categories gives an equivalence between the opposite categories. -/ @[simps] @@ -742,7 +741,6 @@ def op (e : C ≌ D) : Cᵒᵖ ≌ Dᵒᵖ where apply Quiver.Hom.unop_inj simp -set_option backward.isDefEq.respectTransparency false in /-- An equivalence between opposite categories gives an equivalence between the original categories. -/ @[simps] diff --git a/Mathlib/CategoryTheory/PUnit.lean b/Mathlib/CategoryTheory/PUnit.lean index bcae6fc48aefbc..63cca9bb5186de 100644 --- a/Mathlib/CategoryTheory/PUnit.lean +++ b/Mathlib/CategoryTheory/PUnit.lean @@ -61,7 +61,6 @@ def equiv : Discrete PUnit.{w + 1} ⥤ C ≌ C where end Functor -set_option backward.isDefEq.respectTransparency false in /-- A category being equivalent to `PUnit` is equivalent to it having a unique morphism between any two objects. (In fact, such a category is also a groupoid; see `CategoryTheory.Groupoid.ofHomUnique`) -/ diff --git a/Mathlib/CategoryTheory/Pi/Basic.lean b/Mathlib/CategoryTheory/Pi/Basic.lean index 7a45061db19318..71dbea923898f9 100644 --- a/Mathlib/CategoryTheory/Pi/Basic.lean +++ b/Mathlib/CategoryTheory/Pi/Basic.lean @@ -350,7 +350,6 @@ namespace Equivalence variable {C} variable {D : I → Type u₂} [∀ i, Category.{v₂} (D i)] -set_option backward.isDefEq.respectTransparency false in /-- Assemble an `I`-indexed family of equivalences of categories into a single equivalence. -/ @[simps] diff --git a/Mathlib/CategoryTheory/Products/Basic.lean b/Mathlib/CategoryTheory/Products/Basic.lean index e2a09b392f7646..350d600149a34a 100644 --- a/Mathlib/CategoryTheory/Products/Basic.lean +++ b/Mathlib/CategoryTheory/Products/Basic.lean @@ -323,7 +323,6 @@ end NatIso namespace Equivalence -set_option backward.isDefEq.respectTransparency false in /-- The Cartesian product of two equivalences of categories. -/ @[simps] def prod (E₁ : A ≌ B) (E₂ : C ≌ D) : A × C ≌ B × D where diff --git a/Mathlib/CategoryTheory/Sites/Closed.lean b/Mathlib/CategoryTheory/Sites/Closed.lean index 1aab51374dab5c..4250e42207bd5e 100644 --- a/Mathlib/CategoryTheory/Sites/Closed.lean +++ b/Mathlib/CategoryTheory/Sites/Closed.lean @@ -7,6 +7,7 @@ module public import Mathlib.CategoryTheory.Sites.SheafOfTypes public import Mathlib.Order.Closure +public import Mathlib.CategoryTheory.Subfunctor.Basic /-! # Closed sieves @@ -147,24 +148,32 @@ theorem close_eq_top_iff_mem {X : C} (S : Sieve X) : J₁.close S = ⊤ ↔ S end GrothendieckTopology +variable (C) in +/-- The presheaf sending each object to the type of sieves on it. This will turn out to be a +subobject classifier for the category of presheaves. -/ +@[simps] +def Functor.sieves : Cᵒᵖ ⥤ Type max v u where + obj X := Sieve X.unop + map f S := S.pullback f.unop + /-- The presheaf sending each object to the set of `J`-closed sieves on it. This presheaf is a `J`-sheaf (and will turn out to be a subobject classifier for the category of `J`-sheaves). -/ @[simps] -def Functor.closedSieves : Cᵒᵖ ⥤ Type max v u where - obj X := { S : Sieve X.unop // J₁.IsClosed S } - map f S := ⟨S.1.pullback f.unop, J₁.isClosed_pullback f.unop _ S.2⟩ +def Functor.closedSieves : Subfunctor (Functor.sieves C) where + obj X := {S : Sieve X.unop | J₁.IsClosed S} + map f _ := J₁.isClosed_pullback f.unop _ /-- The presheaf of `J`-closed sieves is a `J`-sheaf. The proof of this is adapted from [MM92], Chapter III, Section 7, Lemma 1. -/ -theorem classifier_isSheaf : Presieve.IsSheaf J₁ (Functor.closedSieves J₁) := by +theorem classifier_isSheaf : Presieve.IsSheaf J₁ (Functor.closedSieves J₁).toFunctor := by intro X S hS rw [← Presieve.isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor] refine ⟨?_, ?_⟩ · rintro x ⟨M, hM⟩ ⟨N, hN⟩ hM₂ hN₂ - simp only [Functor.closedSieves_obj] + dsimp at S M N ⊢ ext Y f dsimp only [Subtype.coe_mk] rw [← J₁.covers_iff_mem_of_isClosed hM, ← J₁.covers_iff_mem_of_isClosed hN] @@ -194,7 +203,7 @@ theorem classifier_isSheaf : Presieve.IsSheaf J₁ (Functor.closedSieves J₁) : have : ∀ ⦃Y⦄ (f : Y ⟶ X) (hf : S f), M.pullback f = (x f hf).1 := by intro Y f hf apply le_antisymm - · rintro Z u ⟨W, g, f', hf', hg : (x f' hf').1 _, c⟩ + · rintro Z u ⟨W, g, f', hf', hg : (x f' hf').1.1 _, c⟩ rw [Sieve.mem_iff_pullback_eq_top, ← show (x (u ≫ f) _).1 = (x f hf).1.pullback u from congr_arg Subtype.val (hx f u hf)] conv_lhs => congr; congr; rw [← c] -- Porting note: Originally `simp_rw [← c]` @@ -203,7 +212,7 @@ theorem classifier_isSheaf : Presieve.IsSheaf J₁ (Functor.closedSieves J₁) : · apply Sieve.le_pullback_bind S fun Y f hf => (x f hf).1 refine ⟨⟨_, J₁.close_isClosed M⟩, ?_⟩ intro Y f hf - simp only [Functor.closedSieves_obj] + dsimp ext1 dsimp rw [← J₁.pullback_close, this _ hf] @@ -213,7 +222,7 @@ theorem classifier_isSheaf : Presieve.IsSheaf J₁ (Functor.closedSieves J₁) : is a sheaf for `S`. -/ lemma GrothendieckTopology.mem_iff_isSheafFor_closedSieves (J : GrothendieckTopology C) {X : C} (S : Sieve X) : - S ∈ J X ↔ Presieve.IsSheafFor (Functor.closedSieves J) S.arrows := by + S ∈ J X ↔ Presieve.IsSheafFor (Functor.closedSieves J).toFunctor S.arrows := by refine ⟨fun hS ↦ classifier_isSheaf _ _ hS, fun H ↦ ?_⟩ rw [← J.close_eq_top_iff_mem] have : J.IsClosed (⊤ : Sieve X) := by @@ -223,7 +232,7 @@ lemma GrothendieckTopology.mem_iff_isSheafFor_closedSieves rw [Subtype.ext_iff] at this exact this refine H.isSeparatedFor.ext fun Y f hf ↦ ?_ - simp only [Functor.closedSieves_obj] + simp only [Subfunctor.toFunctor_obj, Functor.sieves_obj, Functor.closedSieves_obj, Set.coe_setOf] ext1 dsimp rw [Sieve.pullback_top, ← J.pullback_close, S.pullback_eq_top_of_mem hf, @@ -234,7 +243,7 @@ lemma GrothendieckTopology.mem_iff_isSheafFor_closedSieves `classifier_isSheaf` and `isSheaf_of_le`. -/ theorem le_topology_of_closedSieves_isSheaf {J₁ J₂ : GrothendieckTopology C} - (h : Presieve.IsSheaf J₁ (Functor.closedSieves J₂)) : J₁ ≤ J₂ := by + (h : Presieve.IsSheaf J₁ (Functor.closedSieves J₂).toFunctor) : J₁ ≤ J₂ := by intro X S hS rw [GrothendieckTopology.mem_iff_isSheafFor_closedSieves] exact h _ hS diff --git a/Mathlib/CategoryTheory/Sites/CoversTop.lean b/Mathlib/CategoryTheory/Sites/CoversTop.lean index ded444d15e3544..b552a398c59fbf 100644 --- a/Mathlib/CategoryTheory/Sites/CoversTop.lean +++ b/Mathlib/CategoryTheory/Sites/CoversTop.lean @@ -61,7 +61,6 @@ include hY `J.CoversTop Y` -/ abbrev cover (W : C) : Cover J W := ⟨Sieve.ofObjects Y W, hY W⟩ -set_option backward.isDefEq.respectTransparency false in lemma ext (F : Sheaf J A) {c : Cone F.1} (hc : IsLimit c) {X : A} {f g : X ⟶ c.pt} (h : ∀ (i : I), f ≫ c.π.app (Opposite.op (Y i)) = g ≫ c.π.app (Opposite.op (Y i))) : diff --git a/Mathlib/CategoryTheory/Sites/Equivalence.lean b/Mathlib/CategoryTheory/Sites/Equivalence.lean index df7256b8fe0529..b1a84418a95e38 100644 --- a/Mathlib/CategoryTheory/Sites/Equivalence.lean +++ b/Mathlib/CategoryTheory/Sites/Equivalence.lean @@ -52,7 +52,6 @@ variable (A : Type u₃) [Category.{v₃} A] namespace Equivalence -set_option backward.isDefEq.respectTransparency false in instance (priority := 900) [G.IsEquivalence] : IsCoverDense G J where is_cover U := by let e := (asEquivalence G).symm @@ -79,7 +78,6 @@ lemma eq_inducedTopology_of_isDenseSubsite [e.inverse.IsDenseSubsite K J] : ext exact (e.inverse.functorPushforward_mem_iff K J).symm -set_option backward.isDefEq.respectTransparency false in lemma isDenseSubsite_functor_of_isCocontinuous [e.functor.IsCocontinuous J K] [e.inverse.IsCocontinuous K J] : e.functor.IsDenseSubsite J K where @@ -132,7 +130,6 @@ def sheafCongr.counitIso : inverse J K e A ⋙ functor J K e A ≅ 𝟭 (Sheaf _ NatIso.ofComponents (fun F ↦ ObjectProperty.isoMk _ (isoWhiskerRight e.op.counitIso F.obj)) -set_option backward.isDefEq.respectTransparency false in /-- The equivalence of sheaf categories. -/ @[simps] def sheafCongr : Sheaf J A ≌ Sheaf K A where diff --git a/Mathlib/CategoryTheory/Sites/IsSheafFor.lean b/Mathlib/CategoryTheory/Sites/IsSheafFor.lean index 06deb8f1d03f05..2c4b953291fa87 100644 --- a/Mathlib/CategoryTheory/Sites/IsSheafFor.lean +++ b/Mathlib/CategoryTheory/Sites/IsSheafFor.lean @@ -476,7 +476,6 @@ See the discussion before Equation (3) of [MM92], Chapter III, Section 4. See al def YonedaSheafCondition (P : Cᵒᵖ ⥤ Type v₁) (S : Sieve X) : Prop := ∀ f : S.functor ⟶ P, ∃! g, S.functorInclusion ≫ g = f -set_option backward.isDefEq.respectTransparency false in /-- (Implementation). This is a (primarily internal) equivalence between natural transformations and compatible families. @@ -510,7 +509,6 @@ noncomputable def shrinkFunctorHomEquiv [LocallySmall.{w} C] {F : Cᵒᵖ ⥤ Ty @[deprecated "In terms of `Sieve.shrinkFunctor`" (since := "2026-03-13")] alias natTransEquivCompatibleFamily := shrinkFunctorHomEquiv -set_option backward.isDefEq.respectTransparency false in lemma shrinkFunctor_ι_comp_eq_iff_isAmalgamation [LocallySmall.{w} C] (F : Cᵒᵖ ⥤ Type w) (f : S.shrinkFunctor.toFunctor ⟶ F) (g : shrinkYoneda.{w}.obj X ⟶ F) : S.shrinkFunctor.ι ≫ g = f ↔ diff --git a/Mathlib/CategoryTheory/Sites/Sheaf.lean b/Mathlib/CategoryTheory/Sites/Sheaf.lean index 8e9b45a69fd9d1..df2d7918806dde 100644 --- a/Mathlib/CategoryTheory/Sites/Sheaf.lean +++ b/Mathlib/CategoryTheory/Sites/Sheaf.lean @@ -457,6 +457,23 @@ def Sheaf.isTerminalOfBotCover (F : Sheaf J A) (X : C) (H : ⊥ ∈ J X) : choose t h using F.2 Y _ H (by tauto) (by tauto) exact ⟨⟨t⟩, fun a => h.2 a (by tauto)⟩ +variable (J) in +/-- A terminal object in `A` gives rise to a terminal object in `Sheaf J` -/ +@[simps] +def Sheaf.terminal {X : A} (hX : IsTerminal X) : Sheaf J A where + obj := (CategoryTheory.Functor.const _).obj X + property := Presheaf.isSheaf_of_isTerminal J hX + +variable (J) in +/-- The constant sheaf of a terminal object is indeed terminal -/ +def Sheaf.isTerminalTerminal {X : A} (hX : IsTerminal X) : IsTerminal (Sheaf.terminal J hX) := + .ofUniqueHom (⟨(Functor.isTerminalConst _ hX).from ·.obj⟩) + (by intros; ext; simpa using hX.hom_ext _ _) + +@[simp] +lemma Sheaf.isTerminalTerminal_from_hom {X : A} (hX : IsTerminal X) (G : Sheaf J A) : + ((Sheaf.isTerminalTerminal J hX).from G).hom = (Functor.isTerminalConst _ hX).from G.obj := rfl + /-- If the topology is discrete, any sheaf is terminal. -/ noncomputable def Sheaf.isTerminalOfEqTop (H : J = ⊤) (F : Sheaf J A) : IsTerminal F := by @@ -497,7 +514,6 @@ variable (P : Cᵒᵖ ⥤ A) (P' : Cᵒᵖ ⥤ A') section MultiequalizerConditions -set_option backward.isDefEq.respectTransparency false in /-- When `P` is a sheaf and `S` is a cover, the associated multifork is a limit. -/ def isLimitOfIsSheaf {X : C} (S : J.Cover X) (hP : IsSheaf J P) : IsLimit (S.multifork P) where lift := fun E : Multifork _ => hP.amalgamate S (fun _ => E.ι _) @@ -517,7 +533,6 @@ def isLimitOfIsSheaf {X : C} (S : J.Cover X) (hP : IsSheaf J P) : IsLimit (S.mul symm apply hP.amalgamate_map -set_option backward.isDefEq.respectTransparency false in theorem isSheaf_iff_multifork : IsSheaf J P ↔ ∀ (X : C) (S : J.Cover X), Nonempty (IsLimit (S.multifork P)) := by refine ⟨fun hP X S => ⟨isLimitOfIsSheaf _ _ _ hP⟩, ?_⟩ diff --git a/Mathlib/CategoryTheory/Sites/Sieves.lean b/Mathlib/CategoryTheory/Sites/Sieves.lean index 1c53ee638b41c4..67429825063e33 100644 --- a/Mathlib/CategoryTheory/Sites/Sieves.lean +++ b/Mathlib/CategoryTheory/Sites/Sieves.lean @@ -1134,7 +1134,6 @@ lemma functorPullback_functorPushforward_eq {X : C} {S : Sieve X} [F.Full] [F.Fa Sieve.functorPullback F (Sieve.functorPushforward F S) = S := (Sieve.fullyFaithfulFunctorGaloisCoinsertion _ _).u_l_eq _ -set_option backward.isDefEq.respectTransparency false in lemma functorPushforward_functor (S : Sieve X) (e : C ≌ D) : S.functorPushforward e.functor = (S.pullback (e.unitInv.app X)).functorPullback e.inverse := by ext Y iYX @@ -1325,7 +1324,6 @@ def shrinkFunctor [LocallySmall.{w} C] {X : C} (S : Sieve X) : simpa [shrinkYonedaObjObjEquiv_obj_map] using S.downward_closed hf _ variable (S) in -set_option backward.isDefEq.respectTransparency false in /-- `Sieve.shrinkFunctor` is compatible with universe lifting. -/ noncomputable def shrinkFunctorUliftFunctorIso [LocallySmall.{w} C] [LocallySmall.{max w' w} C] : diff --git a/Mathlib/CategoryTheory/SmallObject/Iteration/FunctorOfCocone.lean b/Mathlib/CategoryTheory/SmallObject/Iteration/FunctorOfCocone.lean index fc0e626c0c43dc..d95c42bbbe4907 100644 --- a/Mathlib/CategoryTheory/SmallObject/Iteration/FunctorOfCocone.lean +++ b/Mathlib/CategoryTheory/SmallObject/Iteration/FunctorOfCocone.lean @@ -68,7 +68,6 @@ lemma map_id (i : J) (hi : i ≤ j) : dsimp [map] grind -set_option backward.isDefEq.respectTransparency false in lemma map_comp (i₁ i₂ i₃ : J) (hi : i₁ ≤ i₂) (hi' : i₂ ≤ i₃) (hi₃ : i₃ ≤ j) : map c i₁ i₃ (hi.trans hi') hi₃ = map c i₁ i₂ hi (hi'.trans hi₃) ≫ diff --git a/Mathlib/CategoryTheory/SmallObject/TransfiniteCompositionLifting.lean b/Mathlib/CategoryTheory/SmallObject/TransfiniteCompositionLifting.lean index df0c116ec93cc5..7c4063c214d76d 100644 --- a/Mathlib/CategoryTheory/SmallObject/TransfiniteCompositionLifting.lean +++ b/Mathlib/CategoryTheory/SmallObject/TransfiniteCompositionLifting.lean @@ -109,7 +109,6 @@ include sq' in lemma w : f ≫ p = c.ι.app ⊥ ≫ g := by rw [← sq'.w₁, assoc, sq'.w₂, Cocone.w_assoc] -set_option backward.isDefEq.respectTransparency false in /-- Given `sq' : SqStruct c p f g j`, this is the commutative square ``` @@ -128,7 +127,6 @@ lemma sq [SuccOrder J] : CommSq sq'.f' (F.map (homOfLE (Order.le_succ j))) p (c.ι.app _ ≫ g) where w := by simp -set_option backward.isDefEq.respectTransparency false in /-- Auxiliary definition for `sqFunctor`. -/ @[simps] def map {j' : J} (α : j' ⟶ j) : SqStruct c p f g j' where @@ -168,7 +166,6 @@ lemma liftHom_fac (i : J) (hi : i < j) : F.map (homOfLE hi.le) ≫ liftHom hj s = (s.1 ⟨⟨i, hi⟩⟩).f' := (F.isColimitOfIsWellOrderContinuous j hj).fac _ ⟨i, hi⟩ -set_option backward.isDefEq.respectTransparency false in /-- Auxiliary definition for `transfiniteComposition.wellOrderInductionData`. -/ @[simps] noncomputable def lift : (sqFunctor c p f g).obj (Opposite.op j) where diff --git a/Mathlib/CategoryTheory/Subobject/Basic.lean b/Mathlib/CategoryTheory/Subobject/Basic.lean index 0b2435c4699554..78de75ecb650e8 100644 --- a/Mathlib/CategoryTheory/Subobject/Basic.lean +++ b/Mathlib/CategoryTheory/Subobject/Basic.lean @@ -119,16 +119,14 @@ attribute [local ext] CategoryTheory.Comma protected theorem ind {X : C} (p : Subobject X → Prop) (h : ∀ ⦃A : C⦄ (f : A ⟶ X) [Mono f], p (Subobject.mk f)) (P : Subobject X) : p P := by - apply Quotient.inductionOn' - intro a + induction P using Quotient.inductionOn' with | _ a exact h a.arrow protected theorem ind₂ {X : C} (p : Subobject X → Subobject X → Prop) (h : ∀ ⦃A B : C⦄ (f : A ⟶ X) (g : B ⟶ X) [Mono f] [Mono g], p (Subobject.mk f) (Subobject.mk g)) (P Q : Subobject X) : p P Q := by - apply Quotient.inductionOn₂' - intro a b + induction P, Q using Quotient.inductionOn₂' with | _ a b exact h a.arrow b.arrow end diff --git a/Mathlib/CategoryTheory/Subobject/Limits.lean b/Mathlib/CategoryTheory/Subobject/Limits.lean index 8727d9fe898051..1cedaac3f3dc10 100644 --- a/Mathlib/CategoryTheory/Subobject/Limits.lean +++ b/Mathlib/CategoryTheory/Subobject/Limits.lean @@ -444,13 +444,14 @@ def imageSubobjectMap {W X Y Z : C} {f : W ⟶ X} [HasImage f] {g : Y ⟶ Z} [Ha (imageSubobject f : C) ⟶ (imageSubobject g : C) := (imageSubobjectIso f).hom ≫ image.map sq ≫ (imageSubobjectIso g).inv -set_option backward.isDefEq.respectTransparency false in @[reassoc (attr := simp)] theorem imageSubobjectMap_arrow {W X Y Z : C} {f : W ⟶ X} [HasImage f] {g : Y ⟶ Z} [HasImage g] (sq : Arrow.mk f ⟶ Arrow.mk g) [HasImageMap sq] : imageSubobjectMap sq ≫ (imageSubobject g).arrow = (imageSubobject f).arrow ≫ sq.right := by - simp only [imageSubobjectMap, Category.assoc, imageSubobject_arrow'] - erw [image.map_ι, ← Category.assoc, imageSubobject_arrow] + simp only [imageSubobjectMap, Category.assoc, Arrow.mk_left, Functor.id_obj, Arrow.mk_right, + Arrow.mk_hom, imageSubobject_arrow'] + rw [dsimp% image.map_ι sq] + simp theorem image_map_comp_imageSubobjectIso_inv {W X Y Z : C} {f : W ⟶ X} [HasImage f] {g : Y ⟶ Z} [HasImage g] (sq : Arrow.mk f ⟶ Arrow.mk g) [HasImageMap sq] : diff --git a/Mathlib/CategoryTheory/Subobject/MonoOver.lean b/Mathlib/CategoryTheory/Subobject/MonoOver.lean index b9cbf48ccea074..002617706524ea 100644 --- a/Mathlib/CategoryTheory/Subobject/MonoOver.lean +++ b/Mathlib/CategoryTheory/Subobject/MonoOver.lean @@ -382,7 +382,6 @@ section variable (X) -set_option backward.isDefEq.respectTransparency false in /-- An equivalence of categories `e` between `C` and `D` induces an equivalence between `MonoOver X` and `MonoOver (e.functor.obj X)` whenever `X` is an object of `C`. -/ @[simps] diff --git a/Mathlib/CategoryTheory/Topos/Sheaf.lean b/Mathlib/CategoryTheory/Topos/Sheaf.lean new file mode 100644 index 00000000000000..d5f9f38a39e220 --- /dev/null +++ b/Mathlib/CategoryTheory/Topos/Sheaf.lean @@ -0,0 +1,229 @@ +/- +Copyright (c) 2026 Edward van de Meent. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Edward van de Meent +-/ +module + +public import Mathlib.CategoryTheory.Sites.Closed +public import Mathlib.CategoryTheory.Sites.Equivalence +public import Mathlib.CategoryTheory.Topos.Classifier +public import Mathlib.CategoryTheory.Subfunctor.Image + +/-! + +# (Elementary) Sheaf Topos + +We define a subobject classifier for categories of sheaves of (large enough) types. + +## Main definitions + +Let `C` refer to a category with (when relevant) Grothendieck topology `J`. + +* `Presheaf.classifier C` is a construction of a subobject classifier in `Cᵒᵖ ⥤ Type (max u v)`. +* `Sheaf.classifier J` is a construction of a subobject classifier in `Sheaf J (Type (max u v))`. +* `inferInstance : HasClassifier (Cᵒᵖ ⥤ Type w)` says that `Cᵒᵖ ⥤ Type w` has a subobject + classifier if `C` is `w`-essentially small. +* `inferInstance : HasClassifier (Sheaf J (Type w))` says that `Sheaf J (Type w)` has a + subobject classifier if `C` is `w`-essentially small. + +## Main results + +* Any category of sheaves of types has a subobject classifier if the site is essentially small. +* As a consequence, (because categories of sheaves are cartesian monoidal and have finite limits,) + such categories are Elementary Topoi. + +## TODOS: + +* generalize `Presheaf.isClosed_χ_app_apply_of` to only assuming `G` is separated + +-/ + +@[expose] public section + +universe w v u + +namespace CategoryTheory + +variable {C : Type u} [Category.{v} C] +open Limits + +section presheaf + +variable (C) in +/-- The truth morphism in the category of presheaves. At each component `X : C`, it is the constant +map returning `⊤ : Sieve X`. -/ +@[simps] +def Presheaf.truth : (Functor.const _).obj PUnit ⟶ Functor.sieves C where + app X _ := (⊤ : Sieve X.unop) + +variable {F G : Cᵒᵖ ⥤ Type (max u v)} + +/-- +The characteristic map of an inclusion of presheaves. +Given a monomorphism of sheaves `m : F ⟶ G`, an object X of the site, map an element `x : G(X)` +to the (closed) sieve on X where `f : Y → X` is in the sieve iff + `∃ a ∈ F(Y), G(f)(x) = m_Y(a)` +-/ +@[simps app] +def Presheaf.χ (m : F ⟶ G) : G ⟶ Functor.sieves C where + app X x := ⟨fun Y f => ∃ a, G.map f.op x = m.app (.op Y) a, by + intro Y Z f ⟨a, ha⟩ g + use F.map g.op a + simp [ha, FunctorToTypes.naturality]⟩ + +lemma Presheaf.comp_χ_eq (m : F ⟶ G) : m ≫ Presheaf.χ m = + (Functor.isTerminalConst _ Types.isTerminalPUnit).from F ≫ Presheaf.truth C := by + ext + apply Sieve.ext + simp [← FunctorToTypes.naturality F G m] + +lemma Presheaf.isPullback_χ_truth (m : F ⟶ G) [Mono m] : + IsPullback m ((Functor.isTerminalConst _ Types.isTerminalPUnit).from F) (χ m) (truth C) := by + refine IsPullback.of_forall_isPullback_app fun X => ?_ + rw [Types.isPullback_iff] + refine ⟨congr(($(comp_χ_eq m)).app X), ?_, ?_⟩ + · simpa using (mono_iff_injective (m.app X)).mp (inferInstance) + · simp only [Functor.const_obj_obj, Functor.sieves_obj, χ_app, Opposite.op_unop, truth_app, + Functor.isTerminalConst_from_app, Types.isTerminalPUnit_from_apply, and_true, forall_const] + intro p hp + simpa [eq_comm] using congr($(hp).arrows (𝟙 _)) + +lemma Presheaf.χ_unique (m : F ⟶ G) (χ' : G ⟶ Functor.sieves C) + (hχ' : IsPullback m ((Functor.isTerminalConst _ Types.isTerminalPUnit).from _) χ' (truth C)) : + χ' = χ m := by + ext X x + simp only [IsPullback.iff_app, Functor.const_obj_obj, Functor.sieves_obj, + Functor.isTerminalConst_from_app, Types.isPullback_iff, and_true, truth_app, forall_const, + forall_and] at hχ' + obtain ⟨h₁, h₂, h₃⟩ := hχ' + refine Sieve.ext fun Y f => ?_ + simp only [χ_app, Opposite.op_unop] + rw [Sieve.mem_iff_pullback_eq_top, ← Quiver.Hom.unop_op f, + ← Functor.sieves_map C (f.op) (χ'.app X x), + ← FunctorToTypes.naturality G (Functor.sieves C) χ' f.op x, Quiver.Hom.unop_op] + constructor + · intro h + obtain ⟨z, hz⟩ := h₃ _ _ h + use z, hz.symm + · rintro ⟨a, h⟩ + rw [h, ← FunctorToTypes.comp, NatTrans.comp_app] + simpa using congr($(h₁ (.op Y)) a) + +variable (C) in +/-- A construction of a subject classifier in a category of presheaves. -/ +@[simps! Ω truth Ω₀ χ χ₀] +def Presheaf.classifier : Classifier (Cᵒᵖ ⥤ Type (max u v)) := + .mkOfTerminalΩ₀ ((Functor.const Cᵒᵖ).obj PUnit) + (Functor.isTerminalConst _ (Types.isTerminalPUnit)) (Functor.sieves C) (Presheaf.truth C) + (Presheaf.χ ·) Presheaf.isPullback_χ_truth (Presheaf.χ_unique ·) + +/-- Presheaf categories on an essentially small domain have a subobject classifier. -/ +instance [EssentiallySmall.{w} C] : HasClassifier (Cᵒᵖ ⥤ Type w) where + exists_classifier := ⟨(Presheaf.classifier (SmallModel C)).ofEquivalence + (Equivalence.congrLeft (E := Type w) (equivSmallModel C).op).symm⟩ + +end presheaf + +variable {J : GrothendieckTopology C} + +open Presheaf in +lemma GrothendieckTopology.isClosed_χ_app_apply_of_isSheaf_of_isSeparated + {F G : Cᵒᵖ ⥤ Type (max u v)} (m : F ⟶ G) [Mono m] (hF : Presieve.IsSheaf J F) + (hG : Presieve.IsSeparated J G) (X : Cᵒᵖ) (x : G.obj X) : + J.IsClosed ((Presheaf.χ m).app X x) := by + intro Y f hf + simp only [Presheaf.χ_app, Opposite.op_unop] at hf ⊢ + choose a ha using fun Z (g : Z ⟶ Y) (hg : (Sieve.pullback f ((χ m).app X x)).arrows g) => hg + refine ⟨(hF _ hf).amalgamate a ?_, ?_⟩ + · introv Y₁ h + apply (mono_iff_injective (m.app (.op Z))).mp inferInstance + simp_rw [FunctorToTypes.naturality, ← ha, ← FunctorToTypes.map_comp_apply, ← op_comp, + reassoc_of% h] + · refine (hG _ hf).ext fun Z f' hf' => ?_ + rw [← FunctorToTypes.naturality, (hF _ hf).valid_glue _ _ hf', ← (ha _ _ _), + op_comp, FunctorToTypes.map_comp_apply] + +namespace Sheaf +open Functor +variable {F G : Sheaf J (Type max u v)} + +/-- The sheaf of closed sieves w/r/t `J`. See also `Functor.closedSieves` and `Sheaf.classifier` -/ +@[simps] +def Ω (J : GrothendieckTopology C) : Sheaf J (Type max u v) where + obj := (Functor.closedSieves J).toFunctor + property := by + rw [CategoryTheory.isSheaf_iff_isSheaf_of_type] + exact CategoryTheory.classifier_isSheaf J + +set_option backward.isDefEq.respectTransparency false in +/-- The morphism `t : 1 ⟶ Ω` which picks out the maximal sieve -/ +@[simps] +def truth (J : GrothendieckTopology C) : + Sheaf.terminal J (Types.isTerminalPUnit) ⟶ Sheaf.Ω J where + hom := (Functor.closedSieves J).lift (Presheaf.truth C) fun {X} x => by cat_disch + +set_option backward.isDefEq.respectTransparency false in +/-- +Given a monomorphism of sheaves `η : F ⟶ G`, an object X of the site, map an element `x : G(X)` +to the (closed) sieve on X where `f : Y → X` is in the sieve iff + `∃ a ∈ F(Y), G(f)(x) = η_Y(a)` +-/ +@[simps] +def χ (m : F ⟶ G) [Mono m] : G ⟶ Sheaf.Ω J where + hom := (closedSieves J).lift (Presheaf.χ m.hom) (by + intro X + simp only [sieves_obj, Subfunctor.range_obj, closedSieves_obj, Set.le_iff_subset, + Set.range_subset_iff, Set.mem_setOf_eq] + exact J.isClosed_χ_app_apply_of_isSheaf_of_isSeparated m.hom + ((isSheaf_iff_isSheaf_of_type _ _).mp F.property) + ((isSheaf_iff_isSheaf_of_type _ _).mp G.property).isSeparated _) + +lemma isPullback_χ_truth (m : F ⟶ G) [Mono m] : + IsPullback m ((isTerminalTerminal J _).from F) (Sheaf.χ m) (Sheaf.truth J) := by + apply IsPullback.of_map (sheafToPresheaf J _) + · ext : 1 + simp only [Ω_obj, ObjectProperty.FullSubcategory.comp_hom, χ_hom, terminal_obj, truth_hom, + ← cancel_mono (closedSieves J).ι, Category.assoc, Subfunctor.lift_ι] + exact Presheaf.comp_χ_eq m.hom + · simp only [ObjectProperty.ι_obj, terminal_obj, Ω_obj, ObjectProperty.ι_map, χ_hom, truth_hom] + apply IsPullback.of_right _ + ((cancel_mono ((closedSieves J).ι)).mp (by simpa using Presheaf.comp_χ_eq _)) + (.of_horiz_isIso_mono ⟨_⟩ : IsPullback (𝟙 _) _ (Presheaf.χ m.hom) (closedSieves J).ι) + · simp only [Category.comp_id] + exact Presheaf.isPullback_χ_truth m.hom + · simp_all + +set_option backward.isDefEq.respectTransparency false in +lemma χ_unique (m : F ⟶ G) [Mono m] (χ' : G ⟶ Sheaf.Ω J) + (hχ' : IsPullback m ((isTerminalTerminal J _).from F) χ' (Sheaf.truth J)) : + χ' = Sheaf.χ m := by + ext : 1 + rw [← cancel_mono (closedSieves J).ι,χ_hom, Subfunctor.lift_ι] + apply Presheaf.χ_unique _ + have pb : IsPullback (𝟙 G.obj) χ'.hom (χ'.hom ≫ (closedSieves J).ι) + (closedSieves J).ι := IsPullback.of_horiz_isIso_mono (by simp) + have : IsPullback m.hom ?_ χ'.hom <| (truth J).hom := by + simpa using hχ'.map (sheafToPresheaf J _) + simpa using this.paste_horiz pb + +/-- +A construction of a subobject classifier for sheaf categories. `Ω` is the sheaf of closed sieves, +and `truth` maps for each object `X : C`, an element of `PUnit` to the maximal `Sieve X`, which is +always closed. +-/ +@[simps! Ω truth Ω₀ χ χ₀] +def classifier (J : GrothendieckTopology C) : Classifier (Sheaf J (Type max u v)) := + .mkOfTerminalΩ₀ (.terminal J Types.isTerminalPUnit) (isTerminalTerminal _ _) (Sheaf.Ω J) + (Sheaf.truth J) Sheaf.χ Sheaf.isPullback_χ_truth Sheaf.χ_unique + +/-- Sheaf categories on essentially small sites have a subobject classifier. -/ +instance [EssentiallySmall.{w} C] : HasClassifier (Sheaf J (Type w)) where + exists_classifier := ⟨Sheaf.classifier ((equivSmallModel C).inverse.inducedTopology J) + |>.ofEquivalence (Equivalence.sheafCongr _ _ (equivSmallModel C) _).symm⟩ + +end Sheaf + +end CategoryTheory + +end diff --git a/Mathlib/CategoryTheory/Whiskering.lean b/Mathlib/CategoryTheory/Whiskering.lean index a872627953c96f..c766816beb537c 100644 --- a/Mathlib/CategoryTheory/Whiskering.lean +++ b/Mathlib/CategoryTheory/Whiskering.lean @@ -43,27 +43,27 @@ variable {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D] set_option backward.isDefEq.respectTransparency false in /-- If `α : G ⟶ H` then `whiskerLeft F α : F ⋙ G ⟶ F ⋙ H` has components `α.app (F.obj X)`. -/ -@[simps] +@[to_dual self, simps (attr := to_dual self (reorder := G H))] def whiskerLeft (F : C ⥤ D) {G H : D ⥤ E} (α : G ⟶ H) : F ⋙ G ⟶ F ⋙ H where app X := α.app (F.obj X) naturality X Y f := by rw [Functor.comp_map, Functor.comp_map, α.naturality] -@[simp] +@[simp, to_dual self] lemma id_hcomp (F : C ⥤ D) {G H : D ⥤ E} (α : G ⟶ H) : 𝟙 F ◫ α = whiskerLeft F α := by ext simp set_option backward.isDefEq.respectTransparency false in /-- If `α : G ⟶ H` then `whiskerRight α F : G ⋙ F ⟶ H ⋙ F` has components `F.map (α.app X)`. -/ -@[simps] +@[to_dual self, simps (attr := to_dual self (reorder := G H))] def whiskerRight {G H : C ⥤ D} (α : G ⟶ H) (F : D ⥤ E) : G ⋙ F ⟶ H ⋙ F where app X := F.map (α.app X) naturality X Y f := by rw [Functor.comp_map, Functor.comp_map, ← F.map_comp, ← F.map_comp, α.naturality] -@[simp] +@[simp, to_dual self] lemma hcomp_id {G H : C ⥤ D} (α : G ⟶ H) (F : D ⥤ E) : α ◫ 𝟙 F = whiskerRight α F := by ext simp @@ -190,22 +190,23 @@ theorem whiskerRight_id {G : C ⥤ D} (F : D ⥤ E) : theorem whiskerRight_id' {G : C ⥤ D} (F : D ⥤ E) : whiskerRight (𝟙 G) F = 𝟙 (G.comp F) := ((whiskeringRight C D E).obj F).map_id _ -@[simp, reassoc] +@[simp, to_dual self, reassoc] theorem whiskerLeft_comp (F : C ⥤ D) {G H K : D ⥤ E} (α : G ⟶ H) (β : H ⟶ K) : whiskerLeft F (α ≫ β) = whiskerLeft F α ≫ whiskerLeft F β := rfl -@[simp, reassoc] +@[simp, to_dual self, reassoc] theorem whiskerRight_comp {G H K : C ⥤ D} (α : G ⟶ H) (β : H ⟶ K) (F : D ⥤ E) : whiskerRight (α ≫ β) F = whiskerRight α F ≫ whiskerRight β F := ((whiskeringRight C D E).obj F).map_comp α β -@[reassoc] +@[to_dual none, reassoc] theorem whiskerLeft_comp_whiskerRight {F G : C ⥤ D} {H K : D ⥤ E} (α : F ⟶ G) (β : H ⟶ K) : whiskerLeft F β ≫ whiskerRight α K = whiskerRight α H ≫ whiskerLeft G β := by ext simp +@[to_dual hcomp_eq_whiskerRight_comp_whiskerLeft] lemma NatTrans.hcomp_eq_whiskerLeft_comp_whiskerRight {F G : C ⥤ D} {H K : D ⥤ E} (α : F ⟶ G) (β : H ⟶ K) : α ◫ β = whiskerLeft F β ≫ whiskerRight α K := by ext @@ -261,22 +262,24 @@ lemma isoWhiskerRight_refl (F : C ⥤ D) (G : D ⥤ E) : isoWhiskerRight (Iso.refl F) G = Iso.refl _ := by cat_disch +@[to_dual self] instance isIso_whiskerLeft (F : C ⥤ D) {G H : D ⥤ E} (α : G ⟶ H) [IsIso α] : IsIso (whiskerLeft F α) := (isoWhiskerLeft F (asIso α)).isIso_hom +@[to_dual self] instance isIso_whiskerRight {G H : C ⥤ D} (α : G ⟶ H) (F : D ⥤ E) [IsIso α] : IsIso (whiskerRight α F) := (isoWhiskerRight (asIso α) F).isIso_hom -@[simp] +@[simp, to_dual self] theorem inv_whiskerRight {G H : C ⥤ D} (α : G ⟶ H) (F : D ⥤ E) [IsIso α] : inv (whiskerRight α F) = whiskerRight (inv α) F := by symm apply IsIso.eq_inv_of_inv_hom_id simp [← whiskerRight_comp] -@[simp] +@[simp, to_dual self] theorem inv_whiskerLeft (F : C ⥤ D) {G H : D ⥤ E} (α : G ⟶ H) [IsIso α] : inv (whiskerLeft F α) = whiskerLeft F (inv α) := by symm @@ -301,18 +304,19 @@ theorem isoWhiskerLeft_trans_isoWhiskerRight {F G : C ⥤ D} {H K : D ⥤ E} (α variable {B : Type u₄} [Category.{v₄} B] -@[simp] +@[simp, to_dual none] theorem whiskerLeft_twice (F : B ⥤ C) (G : C ⥤ D) {H K : D ⥤ E} (α : H ⟶ K) : whiskerLeft F (whiskerLeft G α) = (Functor.associator _ _ _).inv ≫ whiskerLeft (F ⋙ G) α ≫ (Functor.associator _ _ _).hom := by cat_disch -@[simp] +@[simp, to_dual none] theorem whiskerRight_twice {H K : B ⥤ C} (F : C ⥤ D) (G : D ⥤ E) (α : H ⟶ K) : whiskerRight (whiskerRight α F) G = (Functor.associator _ _ _).hom ≫ whiskerRight α (F ⋙ G) ≫ (Functor.associator _ _ _).inv := by cat_disch +@[to_dual none] theorem whiskerRight_left (F : B ⥤ C) {G H : C ⥤ D} (α : G ⟶ H) (K : D ⥤ E) : whiskerRight (whiskerLeft F α) K = (Functor.associator _ _ _).hom ≫ whiskerLeft F (whiskerRight α K) ≫ diff --git a/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean b/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean index 78aea4020c9cee..c3048ed1189216 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean @@ -55,11 +55,13 @@ def IsAcyclic : Prop := ∀ ⦃v : V⦄ (c : G.Walk v v), ¬c.IsCycle /-- A *tree* is a connected acyclic graph. -/ @[mk_iff] -structure IsTree : Prop where - /-- Graph is connected. -/ - protected isConnected : G.Connected - /-- Graph is acyclic. -/ - protected IsAcyclic : G.IsAcyclic +structure IsTree : Prop extends + connected : G.Connected where + /-- A tree is acyclic. -/ + isAcyclic : G.IsAcyclic + +@[deprecated (since := "2026-03-18")] alias IsTree.isConnected := IsTree.connected +@[deprecated (since := "2026-03-18")] alias IsTree.IsAcyclic := IsTree.isAcyclic variable {G G'} @@ -132,13 +134,19 @@ theorem exists_maximal_isAcyclic_of_le_isAcyclic /-- A connected component of an acyclic graph is a tree. -/ lemma IsAcyclic.isTree_connectedComponent (h : G.IsAcyclic) (c : G.ConnectedComponent) : c.toSimpleGraph.IsTree where - isConnected := c.connected_toSimpleGraph - IsAcyclic := h.comap c.toSimpleGraph_hom <| by simp [ConnectedComponent.toSimpleGraph_hom] + connected := c.connected_toSimpleGraph + isAcyclic := h.comap c.toSimpleGraph_hom <| by simp [ConnectedComponent.toSimpleGraph_hom] + +set_option backward.isDefEq.respectTransparency false in +theorem IsAcyclic.of_card_le_two (h : ENat.card V ≤ 2) : G.IsAcyclic := by + intro v p hp + have := hp.three_le_length + have := Nat.cast_le.mp <| hp.support_nodup.length_le_enatCard.trans h + rw [List.length_tail, p.length_support] at this + lia lemma IsAcyclic.of_subsingleton [Subsingleton V] {G : SimpleGraph V} : G.IsAcyclic := - fun v p hp ↦ hp.ne_nil <| match p with - | nil => rfl - | cons hadj _ => (G.irrefl <| Subsingleton.elim v _ ▸ hadj).elim + .of_card_le_two <| ENat.card_le_one.trans one_le_two lemma Subgraph.isAcyclic_coe_bot (G : SimpleGraph V) : (⊥ : G.Subgraph).coe.IsAcyclic := @IsAcyclic.of_subsingleton _ (Set.isEmpty_coe_sort.mpr rfl).instSubsingleton _ @@ -293,7 +301,7 @@ theorem IsAcyclic.isPath_iff_isTrail (hG : G.IsAcyclic) {v w : V} (p : G.Walk v lemma IsTree.card_edgeFinset [Fintype V] [Fintype G.edgeSet] (hG : G.IsTree) : Finset.card G.edgeFinset + 1 = Fintype.card V := by - have := hG.isConnected.nonempty + have := hG.connected.nonempty inhabit V classical have : Finset.card ({default} : Finset V)ᶜ + 1 = Fintype.card V := by @@ -350,10 +358,10 @@ lemma isTree_of_minimal_connected (h : Minimal Connected G) : IsTree G := by set_option backward.isDefEq.respectTransparency false in lemma isTree_iff_minimal_connected : IsTree G ↔ Minimal Connected G := by - refine ⟨fun htree ↦ ⟨htree.isConnected, fun G' h' hle u v hadj ↦ ?_⟩, isTree_of_minimal_connected⟩ + refine ⟨fun htree ↦ ⟨htree.connected, fun G' h' hle u v hadj ↦ ?_⟩, isTree_of_minimal_connected⟩ have ⟨p, hp⟩ := h'.exists_isPath u v have := congrArg Walk.edges <| congrArg Subtype.val <| - htree.IsAcyclic.path_unique ⟨p.mapLe hle, hp.mapLe hle⟩ <| Path.singleton hadj + htree.isAcyclic.path_unique ⟨p.mapLe hle, hp.mapLe hle⟩ <| Path.singleton hadj simp only [edges_map, Hom.coe_ofLE, Sym2.map_id, List.map_id_fun, id_eq] at this simp [this, p.adj_of_mem_edges] @@ -423,8 +431,8 @@ theorem Connected.maximal_le_isAcyclic_iff_isTree {T : SimpleGraph V} (hG : G.Co have := hG.nonempty refine ⟨fun h ↦ ⟨⟨fun u v ↦ ?_⟩, h.1.2⟩, fun hT' ↦ ?_⟩ · exact G.reachable_eq_of_maximal_isAcyclic T h ▸ hG.preconnected u v - · rw [maximal_isAcyclic_iff_reachable_eq hT hT'.IsAcyclic, - T.preconnected_iff_reachable_eq_top.mp hT'.isConnected.preconnected, + · rw [maximal_isAcyclic_iff_reachable_eq hT hT'.isAcyclic, + T.preconnected_iff_reachable_eq_top.mp hT'.preconnected, G.preconnected_iff_reachable_eq_top.mp hG.preconnected] @[simp] @@ -436,7 +444,7 @@ theorem maximal_isAcyclic_iff_isTree [Nonempty V] {T : SimpleGraph V} : with `Nonempty V` as part of the iff rather than an assumption. -/ theorem isTree_iff_maximal_isAcyclic : G.IsTree ↔ Nonempty V ∧ Maximal IsAcyclic G := by refine ⟨fun h ↦ ?_, fun ⟨_, h⟩ ↦ G.maximal_isAcyclic_iff_isTree.mp h⟩ - have := h.isConnected.nonempty + have := h.nonempty exact ⟨this, G.maximal_isAcyclic_iff_isTree.mpr h⟩ /-- Every acyclic subgraph can be extended to a spanning forest. -/ @@ -480,7 +488,7 @@ lemma isTree_iff_connected_and_card [Finite V] : G.IsTree ↔ G.Connected ∧ Nat.card G.edgeSet + 1 = Nat.card V := by have := Fintype.ofFinite V classical - refine ⟨fun h ↦ ⟨h.isConnected, by simpa [edgeFinset] using h.card_edgeFinset⟩, + refine ⟨fun h ↦ ⟨h.connected, by simpa [edgeFinset] using h.card_edgeFinset⟩, fun ⟨h₁, h₂⟩ ↦ ⟨h₁, ?_⟩⟩ simp_rw [isAcyclic_iff_forall_adj_isBridge] refine fun x y h ↦ by_contra fun hbr ↦ @@ -500,7 +508,7 @@ lemma IsTree.minDegree_eq_one_of_nontrivial (h : G.IsTree) [Fintype V] [Nontrivi exact le_trans q (G.minDegree_le_degree _) rw [Finset.sum_const, Finset.card_univ, smul_eq_mul] at hle lia - · have := h.isConnected.preconnected.minDegree_pos_of_nontrivial + · have := h.preconnected.minDegree_pos_of_nontrivial lia /-- A nontrivial tree has a vertex of degree one. -/ @@ -574,7 +582,7 @@ lemma IsAcyclic.dist_ne_of_adj (hG : G.IsAcyclic) {u v w : V} (hadj : G.Adj v w) lemma IsTree.dist_ne_of_adj (hG : G.IsTree) (u : V) {v w : V} (hadj : G.Adj v w) : G.dist u v ≠ G.dist u w := - hG.IsAcyclic.dist_ne_of_adj hadj <| hG.isConnected u v + hG.isAcyclic.dist_ne_of_adj hadj <| hG.connected u v lemma IsAcyclic.dist_eq_dist_add_one_of_adj_of_reachable (hG : G.IsAcyclic) (u : V) {v w : V} (hadj : G.Adj v w) (hreach : G.Reachable u v) : @@ -592,7 +600,7 @@ noncomputable def IsTree.coloringTwoOfVert (hG : G.IsTree) (u : V) : G.Coloring /-- Arbitrary coloring with two colors for a tree -/ noncomputable def IsTree.coloringTwo (hG : G.IsTree) : G.Coloring (Fin 2) := - hG.coloringTwoOfVert hG.isConnected.nonempty.some + hG.coloringTwoOfVert hG.connected.nonempty.some lemma IsTree.isBipartite (hG : G.IsTree) : G.IsBipartite := ⟨hG.coloringTwo⟩ @@ -622,7 +630,7 @@ lemma IsAcyclic.colorable_two (hG : G.IsAcyclic) : G.Colorable 2 := /-- A tree is 2-colorable. -/ lemma IsTree.colorable_two (hG : G.IsTree) : G.Colorable 2 := - hG.IsAcyclic.colorable_two + hG.isAcyclic.colorable_two /-- The chromatic number of an acyclic graph (forest) is at most 2. -/ lemma IsAcyclic.chromaticNumber_le_two (hG : G.IsAcyclic) : G.chromaticNumber ≤ 2 := diff --git a/Mathlib/Combinatorics/SimpleGraph/AdjMatrix.lean b/Mathlib/Combinatorics/SimpleGraph/AdjMatrix.lean index f86fee03986309..31394102482ce6 100644 --- a/Mathlib/Combinatorics/SimpleGraph/AdjMatrix.lean +++ b/Mathlib/Combinatorics/SimpleGraph/AdjMatrix.lean @@ -5,7 +5,7 @@ Authors: Aaron Anderson, Jalex Stark, Kyle Miller, Lu-Ming Zhang -/ module -public import Mathlib.Combinatorics.SimpleGraph.Connectivity.WalkCounting +public import Mathlib.Combinatorics.SimpleGraph.Walks.Counting public import Mathlib.LinearAlgebra.Matrix.Symmetric public import Mathlib.LinearAlgebra.Matrix.Trace public import Mathlib.LinearAlgebra.Matrix.Hadamard @@ -26,8 +26,8 @@ properties to computational properties of the matrix. (2) `A` is symmetric, (3) every diagonal entry of `A` is `0`. -* `Matrix.IsAdjMatrix.to_graph`: for `A : Matrix V V α` and `h : A.IsAdjMatrix`, - `h.to_graph` is the simple graph induced by `A`. +* `Matrix.IsAdjMatrix.toGraph`: for `A : Matrix V V α` and `h : A.IsAdjMatrix`, + `h.toGraph` is the simple graph induced by `A`. * `Matrix.compl`: for `A : Matrix V V α`, `A.compl` is supposed to be the adjacency matrix of the complement graph of the graph induced by `A`. @@ -170,6 +170,17 @@ theorem adjMatrix_apply (v w : V) [Zero α] [One α] : G.adjMatrix α v w = if G.Adj v w then 1 else 0 := rfl +@[simp] +theorem adjMatrix_bot [Zero α] [One α] : + (⊥ : SimpleGraph V).adjMatrix α = 0 := by + ext; simp + +@[simp] +theorem adjMatrix_top [DecidableEq V] [Ring α] : + (⊤ : SimpleGraph V).adjMatrix α = .of (fun i j ↦ if i = j then 0 else 1) := by + ext i j + cases eq_or_ne i j <;> simp [‹_›] + @[simp] theorem transpose_adjMatrix [Zero α] [One α] : (G.adjMatrix α)ᵀ = G.adjMatrix α := by ext diff --git a/Mathlib/Combinatorics/SimpleGraph/Circulant.lean b/Mathlib/Combinatorics/SimpleGraph/Circulant.lean index ecbf2e5f47d081..49ed19fe773584 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Circulant.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Circulant.lean @@ -138,35 +138,39 @@ theorem cycleGraph_connected {n : ℕ} : (cycleGraph (n + 1)).Connected := (pathGraph_connected n).mono pathGraph_le_cycleGraph set_option backward.privateInPublic true in -private def cycleGraph_EulerianCircuit_cons (n : ℕ) : - ∀ m : Fin (n + 3), (cycleGraph (n + 3)).Walk m 0 +private def cycleGraph.cycleCons (n : ℕ) : ∀ m : Fin (n + 3), (cycleGraph (n + 3)).Walk m 0 | ⟨0, h⟩ => Walk.nil | ⟨m + 1, h⟩ => have hadj : (cycleGraph (n + 3)).Adj ⟨m + 1, h⟩ ⟨m, Nat.lt_of_succ_lt h⟩ := by simp [cycleGraph_adj, Fin.ext_iff, Fin.sub_val_of_le] - Walk.cons hadj (cycleGraph_EulerianCircuit_cons n ⟨m, Nat.lt_of_succ_lt h⟩) + Walk.cons hadj (cycleGraph.cycleCons n ⟨m, Nat.lt_of_succ_lt h⟩) set_option backward.privateInPublic true in set_option backward.privateInPublic.warn false in -/-- Eulerian trail of `cycleGraph (n + 3)` -/ -def cycleGraph_EulerianCircuit (n : ℕ) : (cycleGraph (n + 3)).Walk 0 0 := +/-- The Eulerian cycle of `cycleGraph (n + 3)` -/ +def cycleGraph.cycle (n : ℕ) : (cycleGraph (n + 3)).Walk 0 0 := have hadj : (cycleGraph (n + 3)).Adj 0 (Fin.last (n + 2)) := by simp [cycleGraph_adj] - Walk.cons hadj (cycleGraph_EulerianCircuit_cons n (Fin.last (n + 2))) + Walk.cons hadj (cycleGraph.cycleCons n (Fin.last (n + 2))) -private theorem cycleGraph_EulerianCircuit_cons_length (n : ℕ) : ∀ m : Fin (n + 3), - (cycleGraph_EulerianCircuit_cons n m).length = m.val +@[deprecated (since := "2026-02-15")] +alias cycleGraph_EulerianCircuit := cycleGraph.cycle + +private theorem cycleGraph.length_cycle_cons (n : ℕ) : + ∀ m : Fin (n + 3), (cycleGraph.cycleCons n m).length = m.val | ⟨0, h⟩ => by - unfold cycleGraph_EulerianCircuit_cons + unfold cycleGraph.cycleCons rfl | ⟨m + 1, h⟩ => by - unfold cycleGraph_EulerianCircuit_cons + unfold cycleGraph.cycleCons simp only [Walk.length_cons] - rw [cycleGraph_EulerianCircuit_cons_length n] + rw [cycleGraph.length_cycle_cons n] + +theorem cycleGraph.length_cycle {n : ℕ} : (cycleGraph.cycle n).length = n + 3 := by + unfold cycleGraph.cycle + simp [cycleGraph.length_cycle_cons] -theorem cycleGraph_EulerianCircuit_length {n : ℕ} : - (cycleGraph_EulerianCircuit n).length = n + 3 := by - unfold cycleGraph_EulerianCircuit - simp [cycleGraph_EulerianCircuit_cons_length] +@[deprecated (since := "2026-02-15")] +alias cycleGraph_EulerianCircuit_length := cycleGraph.length_cycle end SimpleGraph diff --git a/Mathlib/Combinatorics/SimpleGraph/Coloring.lean b/Mathlib/Combinatorics/SimpleGraph/Coloring.lean index 2e7d7c59c50c7e..b7dcf9072e1887 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Coloring.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Coloring.lean @@ -120,8 +120,12 @@ theorem Coloring.card_colorClasses_le [Fintype α] [Fintype C.colorClasses] : theorem Coloring.not_adj_of_mem_colorClass {c : α} {v w : V} (hv : v ∈ C.colorClass c) (hw : w ∈ C.colorClass c) : ¬G.Adj v w := fun h => C.valid h (Eq.trans hv (Eq.symm hw)) +theorem Coloring.isIndepSet_colorClass (c : α) : G.IsIndepSet <| C.colorClass c := + fun _ hv _ hw _ ↦ C.not_adj_of_mem_colorClass hv hw + +@[deprecated isIndepSet_colorClass (since := "2026-02-07")] theorem Coloring.color_classes_independent (c : α) : IsAntichain G.Adj (C.colorClass c) := - fun _ hv _ hw _ => C.not_adj_of_mem_colorClass hv hw + C.isIndepSet_colorClass c -- TODO make this computable noncomputable instance [Fintype V] [Fintype α] : Fintype (Coloring G α) := by diff --git a/Mathlib/Combinatorics/SimpleGraph/ConcreteColorings.lean b/Mathlib/Combinatorics/SimpleGraph/ConcreteColorings.lean index 8ff885b2b98237..406384d4490d96 100644 --- a/Mathlib/Combinatorics/SimpleGraph/ConcreteColorings.lean +++ b/Mathlib/Combinatorics/SimpleGraph/ConcreteColorings.lean @@ -157,9 +157,9 @@ theorem chromaticNumber_cycleGraph_of_odd (n : ℕ) (h : 2 ≤ n) (hOdd : Odd n) intro h2 rw [← h2] at hOdd exact (Nat.not_odd_iff.mpr rfl) hOdd - let w : (cycleGraph (n - 3 + 3)).Walk 0 0 := cycleGraph_EulerianCircuit (n - 3) + let w : (cycleGraph (n - 3 + 3)).Walk 0 0 := cycleGraph.cycle (n - 3) have hOdd' : Odd w.length := by - rw [cycleGraph_EulerianCircuit_length, hn3] + rw [cycleGraph.length_cycle, hn3] exact hOdd rw [← hn3] exact Walk.three_le_chromaticNumber_of_odd_loop w hOdd' diff --git a/Mathlib/Combinatorics/SimpleGraph/Connectivity/Connected.lean b/Mathlib/Combinatorics/SimpleGraph/Connectivity/Connected.lean index 5bc4c5725297ce..4357d4fcebe2c0 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Connectivity/Connected.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Connectivity/Connected.lean @@ -803,9 +803,9 @@ theorem adj_and_reachable_delete_edges_iff_exists_cycle {v w : V} : intro p simpa [Sym2.eq_swap] using hb p.reverse have hvc : v ∈ c.support := Walk.fst_mem_support_of_mem_edges c he - refine reachable_deleteEdges_iff_exists_cycle.aux hb' (c.rotate hvc) (hc.isTrail.rotate hvc) + refine reachable_deleteEdges_iff_exists_cycle.aux hb' (c.rotate v hvc) (hc.isTrail.rotate hvc) ?_ (Walk.start_mem_support _) - rwa [(Walk.rotate_edges c hvc).mem_iff, Sym2.eq_swap] + rwa [(c.rotate_edges v hvc).mem_iff, Sym2.eq_swap] theorem isBridge_iff_adj_and_forall_cycle_notMem {v w : V} : G.IsBridge s(v, w) ↔ G.Adj v w ∧ ∀ ⦃u : V⦄ (p : G.Walk u u), p.IsCycle → s(v, w) ∉ p.edges := by @@ -830,12 +830,12 @@ lemma Connected.connected_delete_edge_of_not_isBridge (hG : G.Connected) {x y : refine (connected_iff_exists_forall_reachable _).2 ⟨x, fun w ↦ ?_⟩ obtain ⟨P, hP⟩ := hG.exists_isPath w x obtain heP | heP := em' <| s(x, y) ∈ P.edges - · exact ⟨(P.toDeleteEdges {s(x, y)} (by aesop)).reverse⟩ + · exact ⟨(P.toDeleteEdges {s(x, y)} (by grind)).reverse⟩ have hyP := P.snd_mem_support_of_mem_edges heP let P₁ := P.takeUntil y hyP have hxP₁ := Walk.endpoint_notMem_support_takeUntil hP hyP hxy.ne have heP₁ : s(x, y) ∉ P₁.edges := fun h ↦ hxP₁ <| P₁.fst_mem_support_of_mem_edges h - exact (h hxy).trans (Reachable.symm ⟨P₁.toDeleteEdges {s(x, y)} (by aesop)⟩) + exact (h hxy).trans (Reachable.symm ⟨P₁.toDeleteEdges {s(x, y)} (by grind)⟩) /-- If `e` is an edge in `G` and is a bridge in a larger graph `G'`, then it's a bridge in `G`. -/ theorem IsBridge.anti_of_mem_edgeSet {G' : SimpleGraph V} {e : Sym2 V} (hle : G ≤ G') diff --git a/Mathlib/Combinatorics/SimpleGraph/Connectivity/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Connectivity/Finite.lean new file mode 100644 index 00000000000000..271eb5d6434292 --- /dev/null +++ b/Mathlib/Combinatorics/SimpleGraph/Connectivity/Finite.lean @@ -0,0 +1,129 @@ +/- +Copyright (c) 2021 Kyle Miller. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kyle Miller +-/ +module + +public import Mathlib.Algebra.BigOperators.Ring.Nat +public import Mathlib.Combinatorics.SimpleGraph.Connectivity.Connected +public import Mathlib.Combinatorics.SimpleGraph.Walks.Counting +public import Mathlib.Data.Set.Card + +/-! +# Counting walks of a given length + +## Main definitions +- `walkLengthTwoEquivCommonNeighbors`: bijective correspondence between walks of length two +from `u` to `v` and common neighbours of `u` and `v`. Note that `u` and `v` may be the same. +- `finsetWalkLength`: the `Finset` of length-`n` walks from `u` to `v`. +This is used to give `{p : G.walk u v | p.length = n}` a `Fintype` instance, and it +can also be useful as a recursive description of this set when `V` is finite. + +TODO: should this be extended further? +-/ + +@[expose] public section + +assert_not_exists Field + +open Finset Function + +universe u v w + +namespace SimpleGraph + +variable {V : Type u} (G : SimpleGraph V) + +theorem ConnectedComponent.card_le_card_of_le [Finite V] {G G' : SimpleGraph V} (h : G ≤ G') : + Nat.card G'.ConnectedComponent ≤ Nat.card G.ConnectedComponent := + Nat.card_le_card_of_surjective _ <| ConnectedComponent.surjective_map_ofLE h + +section Fintype + +variable [DecidableEq V] [Fintype V] [DecidableRel G.Adj] + +theorem reachable_iff_exists_finsetWalkLength_nonempty (u v : V) : + G.Reachable u v ↔ ∃ n : Fin (Fintype.card V), (G.finsetWalkLength n u v).Nonempty := by + constructor + · intro r + refine r.elim_path fun p => ?_ + refine ⟨⟨_, p.isPath.length_lt⟩, p, ?_⟩ + simp [mem_finsetWalkLength_iff] + · rintro ⟨_, p, _⟩ + exact ⟨p⟩ + +instance : DecidableRel G.Reachable := fun u v => + decidable_of_iff' _ (reachable_iff_exists_finsetWalkLength_nonempty G u v) + +instance : Fintype G.ConnectedComponent := + @Quotient.fintype _ _ G.reachableSetoid (inferInstance : DecidableRel G.Reachable) + +instance : Decidable G.Preconnected := + inferInstanceAs <| Decidable (∀ u v, G.Reachable u v) + +instance : Decidable G.Connected := + decidable_of_iff (G.Preconnected ∧ (Finset.univ : Finset V).Nonempty) <| by + rw [connected_iff, ← Finset.univ_nonempty_iff] + +instance instDecidableMemSupp (c : G.ConnectedComponent) (v : V) : Decidable (v ∈ c.supp) := + c.recOn (fun w ↦ decidable_of_iff (G.Reachable v w) <| by simp) + (fun _ _ _ _ ↦ Subsingleton.elim _ _) + +variable {G} in +lemma disjiUnion_supp_toFinset_eq_supp_toFinset {G' : SimpleGraph V} (h : G ≤ G') + (c' : ConnectedComponent G') [Fintype c'.supp] + [DecidablePred fun c : G.ConnectedComponent ↦ c.supp ⊆ c'.supp] : + .disjiUnion {c : ConnectedComponent G | c.supp ⊆ c'.supp} (fun c ↦ c.supp.toFinset) + (fun x _ y _ hxy ↦ by simpa using pairwise_disjoint_supp_connectedComponent _ hxy) = + c'.supp.toFinset := + Finset.coe_injective <| by simpa using ConnectedComponent.biUnion_supp_eq_supp h _ + +end Fintype + +/-- The odd components are the connected components of odd cardinality. This definition excludes +infinite components. -/ +abbrev oddComponents : Set G.ConnectedComponent := {c : G.ConnectedComponent | Odd c.supp.ncard} + +set_option backward.isDefEq.respectTransparency false in +lemma ConnectedComponent.odd_oddComponents_ncard_subset_supp [Finite V] {G'} + (h : G ≤ G') (c' : ConnectedComponent G') : + Odd {c ∈ G.oddComponents | c.supp ⊆ c'.supp}.ncard ↔ Odd c'.supp.ncard := by + simp_rw [← Nat.card_coe_set_eq] + classical + cases nonempty_fintype V + rw [Nat.card_eq_card_toFinset c'.supp, ← disjiUnion_supp_toFinset_eq_supp_toFinset h] + simp only [Finset.card_disjiUnion, Set.toFinset_card, Fintype.card_ofFinset] + rw [Finset.odd_sum_iff_odd_card_odd, Nat.card_eq_fintype_card, Fintype.card_ofFinset] + congr! 2 + ext c + simp_rw [Set.toFinset_setOf, mem_filter, ← Set.ncard_coe_finset, coe_filter, + mem_supp_iff, mem_univ, true_and, supp, and_comm] + +lemma odd_ncard_oddComponents [Finite V] : Odd G.oddComponents.ncard ↔ Odd (Nat.card V) := by + classical + cases nonempty_fintype V + rw [Nat.card_eq_fintype_card] + simp only [← (set_fintype_card_eq_univ_iff _).mpr G.iUnion_connectedComponentSupp, + ← Set.toFinset_card, Set.toFinset_iUnion ConnectedComponent.supp] + rw [Finset.card_biUnion + (fun x _ y _ hxy ↦ Set.disjoint_toFinset.mpr (pairwise_disjoint_supp_connectedComponent _ hxy))] + simp_rw [← Set.ncard_eq_toFinset_card', ← Finset.coe_filter_univ, Set.ncard_coe_finset] + exact (Finset.odd_sum_iff_odd_card_odd (fun x : G.ConnectedComponent ↦ x.supp.ncard)).symm + +lemma ncard_oddComponents_mono [Finite V] {G' : SimpleGraph V} (h : G ≤ G') : + G'.oddComponents.ncard ≤ G.oddComponents.ncard := by + have aux (c : G'.ConnectedComponent) (hc : Odd c.supp.ncard) : + {c' : G.ConnectedComponent | Odd c'.supp.ncard ∧ c'.supp ⊆ c.supp}.Nonempty := by + refine Set.nonempty_of_ncard_ne_zero fun h' ↦ ?_ + simpa [-Nat.card_eq_fintype_card, -Set.coe_setOf, h'] + using (c.odd_oddComponents_ncard_subset_supp _ h).2 hc + let f : G'.oddComponents → G.oddComponents := + fun ⟨c, hc⟩ ↦ ⟨(aux c hc).choose, (aux c hc).choose_spec.1⟩ + refine Nat.card_le_card_of_injective f fun c c' fcc' ↦ ?_ + simp only [Subtype.mk.injEq, f] at fcc' + exact Subtype.val_injective (ConnectedComponent.eq_of_common_vertex + ((fcc' ▸ (aux c.1 c.2).choose_spec.2) (ConnectedComponent.nonempty_supp _).some_mem) + ((aux c'.1 c'.2).choose_spec.2 (ConnectedComponent.nonempty_supp _).some_mem)) + +end SimpleGraph diff --git a/Mathlib/Combinatorics/SimpleGraph/Connectivity/Represents.lean b/Mathlib/Combinatorics/SimpleGraph/Connectivity/Represents.lean index 86ac43e038fd2b..ef491f78f4c9f8 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Connectivity/Represents.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Connectivity/Represents.lean @@ -5,7 +5,7 @@ Authors: Pim Otte -/ module -public import Mathlib.Combinatorics.SimpleGraph.Connectivity.WalkCounting +public import Mathlib.Combinatorics.SimpleGraph.Connectivity.Finite public import Mathlib.Data.Set.Card /-! diff --git a/Mathlib/Combinatorics/SimpleGraph/Connectivity/Subgraph.lean b/Mathlib/Combinatorics/SimpleGraph/Connectivity/Subgraph.lean index b6218d893a3627..37a8f1c5efec6e 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Connectivity/Subgraph.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Connectivity/Subgraph.lean @@ -244,7 +244,7 @@ theorem toSubgraph_reverse (p : G.Walk u v) : p.reverse.toSubgraph = p.toSubgrap set_option backward.isDefEq.respectTransparency false in @[simp] theorem toSubgraph_rotate [DecidableEq V] (c : G.Walk v v) (h : u ∈ c.support) : - (c.rotate h).toSubgraph = c.toSubgraph := by + (c.rotate u h).toSubgraph = c.toSubgraph := by rw [rotate, toSubgraph_append, sup_comm, ← toSubgraph_append, take_spec] @[simp] diff --git a/Mathlib/Combinatorics/SimpleGraph/Copy.lean b/Mathlib/Combinatorics/SimpleGraph/Copy.lean index 7c5fbca91d9dd3..d90d3d83516d3d 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Copy.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Copy.lean @@ -253,11 +253,13 @@ theorem IsContained.trans : A ⊑ B → B ⊑ C → A ⊑ C := fun ⟨f⟩ ⟨g /-- If `B` contains `C` and `A` contains `B`, then `A` contains `C`. -/ theorem IsContained.trans' : B ⊑ C → A ⊑ B → A ⊑ C := flip IsContained.trans +@[gcongr] lemma IsContained.mono_right {B' : SimpleGraph β} (h_isub : A ⊑ B) (h_sub : B ≤ B') : A ⊑ B' := h_isub.trans <| IsContained.of_le h_sub alias IsContained.trans_le := IsContained.mono_right +@[gcongr] lemma IsContained.mono_left {A' : SimpleGraph α} (h_sub : A ≤ A') (h_isub : A' ⊑ B) : A ⊑ B := (IsContained.of_le h_sub).trans h_isub @@ -276,6 +278,15 @@ lemma isContained_congr_right (e₂ : B ≃g C) : A ⊑ B ↔ A ⊑ C := isConta alias ⟨_, IsContained.congr_right⟩ := isContained_congr_right +instance : IsPreorder (SimpleGraph α) IsContained where + refl := .refl + trans _ _ _ := .trans + +instance : + Trans (α := SimpleGraph α) (β := SimpleGraph β) (γ := SimpleGraph γ) + IsContained IsContained IsContained where + trans := .trans + /-- A simple graph having no vertices is contained in any simple graph. -/ lemma IsContained.of_isEmpty [IsEmpty α] : A ⊑ B := ⟨⟨isEmptyElim, fun {a} ↦ isEmptyElim a⟩, isEmptyElim⟩ @@ -366,6 +377,15 @@ protected lemma Subgraph.IsInduced.isIndContained {G' : G.Subgraph} (hG' : G'.Is lemma IsIndContained.rfl : G ⊴ G := .refl _ @[trans] lemma IsIndContained.trans : G ⊴ H → H ⊴ I → G ⊴ I := fun ⟨f⟩ ⟨g⟩ ↦ ⟨g.comp f⟩ +instance : IsPreorder (SimpleGraph α) IsIndContained where + refl := .refl + trans _ _ _ := .trans + +instance : + Trans (α := SimpleGraph α) (β := SimpleGraph β) (γ := SimpleGraph γ) + IsIndContained IsIndContained IsIndContained where + trans := .trans + lemma IsIndContained.of_isEmpty [IsEmpty V] : G ⊴ H := ⟨{ toFun := isEmptyElim inj' := isEmptyElim diff --git a/Mathlib/Combinatorics/SimpleGraph/Hamiltonian.lean b/Mathlib/Combinatorics/SimpleGraph/Hamiltonian.lean index be999e72a52301..43b9055a339433 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Hamiltonian.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Hamiltonian.lean @@ -264,10 +264,10 @@ theorem not_isHamiltonian_of_isBridge (G : SimpleGraph V) have hWalkAllMem : ∀ p : G.Walk x y, s(x, y) ∈ p.edges := (SimpleGraph.isBridge_iff_adj_and_forall_walk_mem_edges.mp hbr).2 - let cX := c.rotate (hcHam.mem_support x) + let cX := c.rotate x (hcHam.mem_support x) have hcycleX : cX.IsCycle := hcHam.isCycle.rotate (hcHam.mem_support x) have he_not_in_cX : s(x, y) ∉ cX.edges := - fun h => he_not_in_cycle ((Walk.rotate_edges c (hcHam.mem_support x)).mem_iff.mp h) + fun h => he_not_in_cycle ((c.rotate_edges x (hcHam.mem_support x)).mem_iff.mp h) have hyX : y ∈ cX.support := by by_cases hxy : x = y · subst hxy @@ -280,7 +280,7 @@ theorem not_isHamiltonian_of_isBridge (G : SimpleGraph V) Walk.support_tail_of_not_nil c hc_not_nil rw [this] at hy_tail have hperm : cX.support.tail.Perm c.support.tail := - (Walk.support_rotate c (hcHam.mem_support x)).perm + (c.support_rotate _ (hcHam.mem_support x)).perm have : y ∈ cX.support.tail := hperm.symm.mem_iff.mp hy_tail exact List.mem_of_mem_tail this let p := cX.takeUntil y hyX diff --git a/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean b/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean index 8ec675edaa9ce7..5cdaded28624eb 100644 --- a/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean +++ b/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean @@ -7,6 +7,7 @@ module public import Mathlib.Analysis.Matrix.Order public import Mathlib.Combinatorics.SimpleGraph.AdjMatrix +public import Mathlib.Combinatorics.SimpleGraph.Connectivity.Finite /-! # Laplacian Matrix @@ -29,11 +30,28 @@ This module defines the Laplacian matrix of a graph, and proves some of its elem open Finset Matrix Module +namespace Matrix.IsAdjMatrix + +variable {α V : Type*} [NonAssocSemiring α] [StarRing α] {A : Matrix V V α} (h : A.IsAdjMatrix) +include h + +@[simp] +protected theorem isHermitian : A.IsHermitian := by + ext i j + rcases h.zero_or_one i j with heq | heq + <;> simp [heq, h.symm.apply] + +end Matrix.IsAdjMatrix + namespace SimpleGraph variable {V : Type*} (R : Type*) variable [Fintype V] (G : SimpleGraph V) [DecidableRel G.Adj] +omit [Fintype V] in +theorem isHermitian_adjMatrix [NonAssocSemiring R] [StarRing R] : (G.adjMatrix R).IsHermitian := + G.isAdjMatrix_adjMatrix R |>.isHermitian + theorem degree_eq_sum_if_adj {R : Type*} [AddCommMonoidWithOne R] (i : V) : (G.degree i : R) = ∑ j : V, if G.Adj i j then 1 else 0 := by unfold degree neighborFinset neighborSet @@ -48,13 +66,19 @@ def degMatrix [AddMonoidWithOne R] : Matrix V V R := Matrix.diagonal (G.degree is the matrix `L = D - A` where `D` is the degree and `A` the adjacency matrix of `G`. -/ def lapMatrix [AddGroupWithOne R] : Matrix V V R := G.degMatrix R - G.adjMatrix R -variable {R} - theorem isSymm_degMatrix [AddMonoidWithOne R] : (G.degMatrix R).IsSymm := isSymm_diagonal _ +theorem isHermitian_degMatrix [NonAssocSemiring R] [StarRing R] : (G.degMatrix R).IsHermitian := + Matrix.isHermitian_diagonal_iff.mpr <| by simp + theorem isSymm_lapMatrix [AddGroupWithOne R] : (G.lapMatrix R).IsSymm := - (isSymm_degMatrix _).sub (isSymm_adjMatrix _) + G.isSymm_degMatrix R |>.sub G.isSymm_adjMatrix + +theorem isHermitian_lapMatrix [NonAssocRing R] [StarRing R] : (G.lapMatrix R).IsHermitian := + G.isHermitian_degMatrix R |>.sub <| G.isHermitian_adjMatrix R + +variable {R} theorem degMatrix_mulVec_apply [NonAssocSemiring R] (v : V) (vec : V → R) : (G.degMatrix R *ᵥ vec) v = G.degree v * vec v := by @@ -145,14 +169,7 @@ lemma mem_ker_toLin'_lapMatrix_of_connectedComponent {G : SimpleGraph V} [Decida (fun i ↦ if connectedComponentMk G i = c then 1 else 0) ∈ LinearMap.ker (toLin' (lapMatrix ℝ G)) := by rw [LinearMap.mem_ker, toLin'_apply, lapMatrix_mulVec_eq_zero_iff_forall_reachable] - intro i j h - split_ifs with h₁ h₂ h₃ - · rfl - · rw [← ConnectedComponent.eq] at h - exact (h₂ (h₁ ▸ h.symm)).elim - · rw [← ConnectedComponent.eq] at h - exact (h₁ (h₃ ▸ h)).elim - · rfl + grind [ConnectedComponent.eq] /-- Given a connected component `c` of a graph `G`, `lapMatrix_ker_basis_aux c` is the map `V → ℝ` which is `1` on the vertices in `c` and `0` elsewhere. @@ -160,7 +177,7 @@ The family of these maps indexed by the connected components of `G` proves to be of the kernel of `lapMatrix G R` -/ def lapMatrix_ker_basis_aux (c : G.ConnectedComponent) : LinearMap.ker (Matrix.toLin' (G.lapMatrix ℝ)) := - ⟨fun i ↦ if G.connectedComponentMk i = c then (1 : ℝ) else 0, + ⟨fun i ↦ if G.connectedComponentMk i = c then (1 : ℝ) else 0, mem_ker_toLin'_lapMatrix_of_connectedComponent c⟩ lemma linearIndependent_lapMatrix_ker_basis_aux : @@ -196,16 +213,14 @@ lemma top_le_span_range_lapMatrix_ker_basis_aux : the basis is made up of the functions `V → ℝ` which are `1` on the vertices of the given connected component and `0` elsewhere. -/ noncomputable def lapMatrix_ker_basis := - Basis.mk (linearIndependent_lapMatrix_ker_basis_aux G) - (top_le_span_range_lapMatrix_ker_basis_aux G) + Basis.mk G.linearIndependent_lapMatrix_ker_basis_aux G.top_le_span_range_lapMatrix_ker_basis_aux end /-- The number of connected components in `G` is the dimension of the nullspace of its Laplacian. -/ theorem card_connectedComponent_eq_finrank_ker_toLin'_lapMatrix : - Fintype.card G.ConnectedComponent = - Module.finrank ℝ (LinearMap.ker (Matrix.toLin' (G.lapMatrix ℝ))) := by + Fintype.card G.ConnectedComponent = Module.finrank ℝ (G.lapMatrix ℝ).toLin'.ker := by classical - rw [Module.finrank_eq_card_basis (lapMatrix_ker_basis G)] + rw [Module.finrank_eq_card_basis G.lapMatrix_ker_basis] end SimpleGraph diff --git a/Mathlib/Combinatorics/SimpleGraph/Matching.lean b/Mathlib/Combinatorics/SimpleGraph/Matching.lean index b91bc49150dcd4..79eeeb252aacb0 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Matching.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Matching.lean @@ -6,8 +6,8 @@ Authors: Alena Gusakov, Arthur Paulino, Kyle Miller, Pim Otte module public import Mathlib.Combinatorics.SimpleGraph.Clique +public import Mathlib.Combinatorics.SimpleGraph.Connectivity.Finite public import Mathlib.Combinatorics.SimpleGraph.Connectivity.Subgraph -public import Mathlib.Combinatorics.SimpleGraph.Connectivity.WalkCounting public import Mathlib.Combinatorics.SimpleGraph.DegreeSum public import Mathlib.Combinatorics.SimpleGraph.Operations public import Mathlib.Data.Set.Card.Arithmetic @@ -172,7 +172,7 @@ lemma IsMatching.exists_of_disjoint_sets_of_equiv {s t : Set V} (h : Disjoint s obtain (⟨hv, rfl⟩ | ⟨hw, rfl⟩) := h · exact hadj ⟨v, _⟩ · exact (hadj ⟨w, _⟩).symm - edge_vert := by aesop } + edge_vert := by grind } simp only [Subgraph.IsMatching, Set.mem_union, true_and] intro v hv rcases hv with hl | hr @@ -368,7 +368,7 @@ lemma IsCycles.existsUnique_ne_adj (h : G.IsCycles) (hadj : G.Adj v w) : intro y ⟨hwy, hwy'⟩ obtain ⟨x, y', hxy'⟩ := Set.ncard_eq_two.mp (h ⟨w, hadj⟩) simp_rw [← SimpleGraph.mem_neighborSet] at * - aesop + grind lemma IsCycles.toSimpleGraph (c : G.ConnectedComponent) (h : G.IsCycles) : c.toSimpleGraph.spanningCoe.IsCycles := by @@ -394,7 +394,7 @@ lemma Walk.IsPath.isCycles_spanningCoe_toSubgraph_sup_edge {u v} {p : G.Walk u v ext w x simp only [sup_adj, Subgraph.spanningCoe_adj, completeGraph_eq_top, edge_adj, c, Walk.toSubgraph, Subgraph.sup_adj, subgraphOfAdj_adj, adj_toSubgraph_mapLe] - aesop + grind exact this ▸ IsCycle.isCycles_spanningCoe_toSubgraph (by simp [Walk.cons_isCycle_iff, c, hp, hs]) lemma Walk.IsCycle.adj_toSubgraph_iff_of_isCycles [LocallyFinite G] {u} {p : G.Walk u u} @@ -528,7 +528,7 @@ lemma IsCycles.exists_cycle_toSubgraph_verts_eq_connectedComponentSupp [Finite V rw [← hc', Walk.mem_verts_toSubgraph] exact hvp simp_all - use p.rotate hvp + use p.rotate v hvp rw [← this] exact ⟨hp.1.rotate _, by simp⟩ @@ -562,19 +562,19 @@ lemma IsAlternating.sup_edge {u x : V} (halt : G.IsAlternating G') (hnadj : ¬G' simp only [sup_adj, edge_adj] at hvw hvv' obtain hl | hr := hvw <;> obtain h1 | h2 := hvv' · exact halt hww' hl h1 - · rw [G'.adj_congr_of_sym2 (by aesop : s(v, w') = s(u, x))] + · rw [G'.adj_congr_of_sym2 (by grind : s(v, w') = s(u, x))] simp only [hnadj, not_false_eq_true, iff_true] rcases h2.1 with ⟨h2l1, h2l2⟩ | ⟨h2r1, h2r2⟩ · subst h2l1 h2l2 exact (hx' _ hww' hl.symm).symm · simp_all - · rw [G'.adj_congr_of_sym2 (by aesop : s(v, w) = s(u, x))] + · rw [G'.adj_congr_of_sym2 (by grind : s(v, w) = s(u, x))] simp only [hnadj, false_iff, not_not] rcases hr.1 with ⟨hrl1, hrl2⟩ | ⟨hrr1, hrr2⟩ · subst hrl1 hrl2 exact (hx' _ hww'.symm h1.symm).symm - · aesop - · aesop + · grind + · grind set_option backward.isDefEq.respectTransparency false in lemma Subgraph.IsPerfectMatching.symmDiff_of_isAlternating (hM : M.IsPerfectMatching) @@ -591,7 +591,7 @@ lemma Subgraph.IsPerfectMatching.symmDiff_of_isAlternating (hM : M.IsPerfectMatc simp only [Subgraph.top_adj, SimpleGraph.sup_adj, sdiff_adj, Subgraph.spanningCoe_adj, hmadj.mp hw.1, hw'.2, not_true_eq_false, and_self, not_false_eq_true, or_true, true_and] rintro y (hl | hr) - · aesop + · grind · obtain ⟨w'', hw''⟩ := hG'cyc.other_adj_of_adj hr.1 by_contra! hc simp_all [show M.Adj v y ↔ ¬M.Adj v w' from by simpa using hG' hc hr.1 hw'.2] diff --git a/Mathlib/Combinatorics/SimpleGraph/Operations.lean b/Mathlib/Combinatorics/SimpleGraph/Operations.lean index e109a411cefabc..fc72b7a761745f 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Operations.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Operations.lean @@ -72,13 +72,13 @@ theorem edgeSet_replaceVertex_of_not_adj (hn : ¬G.Adj s t) : (G.replaceVertex s G.edgeSet \ G.incidenceSet t ∪ (s(·, t)) '' (G.neighborSet s) := by ext e; refine e.inductionOn ?_ simp only [replaceVertex, mem_edgeSet, Set.mem_union, Set.mem_diff, mk'_mem_incidenceSet_iff] - intros; split_ifs; exacts [by simp_all, by aesop, by rw [adj_comm]; aesop, by aesop] + intros; split_ifs; exacts [by simp_all, by aesop, by rw [adj_comm]; aesop, by grind] theorem edgeSet_replaceVertex_of_adj (ha : G.Adj s t) : (G.replaceVertex s t).edgeSet = (G.edgeSet \ G.incidenceSet t ∪ (s(·, t)) '' (G.neighborSet s)) \ {s(t, t)} := by ext e; refine e.inductionOn ?_ simp only [replaceVertex, mem_edgeSet, Set.mem_union, Set.mem_diff, mk'_mem_incidenceSet_iff] - intros; split_ifs; exacts [by simp_all, by aesop, by rw [adj_comm]; aesop, by aesop] + intros; split_ifs; exacts [by simp_all, by aesop, by rw [adj_comm]; aesop, by grind] variable [Fintype V] [DecidableRel G.Adj] diff --git a/Mathlib/Combinatorics/SimpleGraph/Partition.lean b/Mathlib/Combinatorics/SimpleGraph/Partition.lean index fb86cc26d63eef..9d7e035770826e 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Partition.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Partition.lean @@ -124,7 +124,7 @@ def Coloring.toPartition {α : Type v} (C : G.Coloring α) : G.Partition where isPartition := C.colorClasses_isPartition independent := by rintro s ⟨c, rfl⟩ - apply C.color_classes_independent + apply C.isIndepSet_colorClass namespace Partition /-- The partition where every vertex is in its own part. -/ diff --git a/Mathlib/Combinatorics/SimpleGraph/Paths.lean b/Mathlib/Combinatorics/SimpleGraph/Paths.lean index 0e581147e2510e..defd302511252b 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Paths.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Paths.lean @@ -5,7 +5,7 @@ Authors: Kyle Miller -/ module -public import Mathlib.Combinatorics.SimpleGraph.Connectivity.WalkDecomp +public import Mathlib.Combinatorics.SimpleGraph.Walks.Decomp public import Mathlib.Combinatorics.SimpleGraph.Walks.Maps public import Mathlib.Combinatorics.SimpleGraph.Walks.Subwalks public import Mathlib.Order.Preorder.Finite @@ -564,12 +564,12 @@ lemma IsTrail.disjoint_edges_takeUntil_dropUntil {x : V} {w : G.Walk u v} (hw : List.disjoint_of_nodup_append <| by simpa [← edges_append] using hw.edges_nodup protected theorem IsTrail.rotate {u v : V} {c : G.Walk v v} (hc : c.IsTrail) (h : u ∈ c.support) : - (c.rotate h).IsTrail := by - rw [isTrail_def, (c.rotate_edges h).perm.nodup_iff] + (c.rotate u h).IsTrail := by + rw [isTrail_def, (c.rotate_edges u h).perm.nodup_iff] exact hc.edges_nodup protected theorem IsCircuit.rotate {u v : V} {c : G.Walk v v} (hc : c.IsCircuit) - (h : u ∈ c.support) : (c.rotate h).IsCircuit := by + (h : u ∈ c.support) : (c.rotate u h).IsCircuit := by refine ⟨hc.isTrail.rotate _, ?_⟩ cases c · exact (hc.ne_nil rfl).elim @@ -579,9 +579,9 @@ protected theorem IsCircuit.rotate {u v : V} {c : G.Walk v v} (hc : c.IsCircuit) simp at hn' protected theorem IsCycle.rotate {u v : V} {c : G.Walk v v} (hc : c.IsCycle) (h : u ∈ c.support) : - (c.rotate h).IsCycle := by + (c.rotate u h).IsCycle := by refine ⟨hc.isCircuit.rotate _, ?_⟩ - rw [List.IsRotated.nodup_iff (support_rotate _ _)] + rw [(support_rotate ..).nodup_iff] exact hc.support_nodup lemma IsCycle.isPath_takeUntil {c : G.Walk v v} (hc : c.IsCycle) (h : w ∈ c.support) : diff --git a/Mathlib/Combinatorics/SimpleGraph/Tutte.lean b/Mathlib/Combinatorics/SimpleGraph/Tutte.lean index 4d45d65d9c1e6c..e3237438877822 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Tutte.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Tutte.lean @@ -169,7 +169,7 @@ private theorem tutte_exists_isPerfectMatching_of_near_matchings {x a b c : V} -- Neither matching contains the edge that would make the other matching of G perfect have hM1nac : ¬M1.Adj a c := fun h ↦ by simpa [hnGac, edge_adj, hnac, hxa.ne, hnbc.symm, hab.ne] using h.adj_sub - have hsupG : G ⊔ edge x b ⊔ (G ⊔ edge a c) = (G ⊔ edge a c) ⊔ edge x b := by aesop + have hsupG : G ⊔ edge x b ⊔ (G ⊔ edge a c) = (G ⊔ edge a c) ⊔ edge x b := by grind -- We state conditions for our cycle that hold in all cases and show that this suffices suffices ∃ (G' : SimpleGraph V), G'.IsAlternating M2.spanningCoe ∧ G'.IsCycles ∧ ¬G'.Adj x b ∧ G'.Adj a c ∧ G' ≤ G ⊔ edge a c by @@ -228,7 +228,7 @@ private theorem tutte_exists_isPerfectMatching_of_near_matchings {x a b c : V} have : (p'.takeUntil x' hx'p).toSubgraph.Adj a (p'.takeUntil x' hx'p).snd := by apply Walk.toSubgraph_adj_snd rw [Walk.nil_takeUntil] - aesop + grind rwa [Walk.snd_takeUntil, hp'.2.1] at this simp only [Finset.mem_insert, Finset.mem_singleton] at hx' obtain rfl | rfl := hx' diff --git a/Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkCounting.lean b/Mathlib/Combinatorics/SimpleGraph/Walks/Counting.lean similarity index 59% rename from Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkCounting.lean rename to Mathlib/Combinatorics/SimpleGraph/Walks/Counting.lean index 949ad3c46d0f67..2eefd53e23cf03 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkCounting.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Walks/Counting.lean @@ -5,10 +5,7 @@ Authors: Kyle Miller -/ module -public import Mathlib.Algebra.BigOperators.Ring.Nat -public import Mathlib.Combinatorics.SimpleGraph.Connectivity.Connected -public import Mathlib.Data.Set.Card -public import Mathlib.Data.Set.Finite.Lattice +public import Mathlib.Combinatorics.SimpleGraph.Paths /-! # Counting walks of a given length @@ -35,10 +32,6 @@ namespace SimpleGraph variable {V : Type u} (G : SimpleGraph V) -/-! ### Walks of a given length -/ - -section WalkCounting - theorem set_walk_self_length_zero_eq (u : V) : {p : G.Walk u u | p.length = 0} = {Walk.nil} := by simp @@ -172,37 +165,9 @@ instance fintypeSubtypePathLengthLT (u v : V) (n : ℕ) : end LocallyFinite -theorem ConnectedComponent.card_le_card_of_le [Finite V] {G G' : SimpleGraph V} (h : G ≤ G') : - Nat.card G'.ConnectedComponent ≤ Nat.card G.ConnectedComponent := - Nat.card_le_card_of_surjective _ <| ConnectedComponent.surjective_map_ofLE h - section Fintype - variable [DecidableEq V] [Fintype V] [DecidableRel G.Adj] -theorem reachable_iff_exists_finsetWalkLength_nonempty (u v : V) : - G.Reachable u v ↔ ∃ n : Fin (Fintype.card V), (G.finsetWalkLength n u v).Nonempty := by - constructor - · intro r - refine r.elim_path fun p => ?_ - refine ⟨⟨_, p.isPath.length_lt⟩, p, ?_⟩ - simp [mem_finsetWalkLength_iff] - · rintro ⟨_, p, _⟩ - exact ⟨p⟩ - -instance : DecidableRel G.Reachable := fun u v => - decidable_of_iff' _ (reachable_iff_exists_finsetWalkLength_nonempty G u v) - -instance : Fintype G.ConnectedComponent := - @Quotient.fintype _ _ G.reachableSetoid (inferInstance : DecidableRel G.Reachable) - -instance : Decidable G.Preconnected := - inferInstanceAs <| Decidable (∀ u v, G.Reachable u v) - -instance : Decidable G.Connected := - decidable_of_iff (G.Preconnected ∧ (Finset.univ : Finset V).Nonempty) <| by - rw [connected_iff, ← Finset.univ_nonempty_iff] - instance Path.instFintype {u v : V} : Fintype (G.Path u v) where elems := (univ (α := { p : G.Walk u v | p.IsPath ∧ p.length < Fintype.card V })).map ⟨fun p ↦ { val := p.val, property := p.prop.left }, @@ -211,66 +176,5 @@ instance Path.instFintype {u v : V} : Fintype (G.Path u v) where ⟨p.val, ⟨p.prop, p.prop.length_lt⟩⟩, ⟨mem_univ _, rfl⟩⟩ -instance instDecidableMemSupp (c : G.ConnectedComponent) (v : V) : Decidable (v ∈ c.supp) := - c.recOn (fun w ↦ decidable_of_iff (G.Reachable v w) <| by simp) - (fun _ _ _ _ ↦ Subsingleton.elim _ _) - -variable {G} in -lemma disjiUnion_supp_toFinset_eq_supp_toFinset {G' : SimpleGraph V} (h : G ≤ G') - (c' : ConnectedComponent G') [Fintype c'.supp] - [DecidablePred fun c : G.ConnectedComponent ↦ c.supp ⊆ c'.supp] : - .disjiUnion {c : ConnectedComponent G | c.supp ⊆ c'.supp} (fun c ↦ c.supp.toFinset) - (fun x _ y _ hxy ↦ by simpa using pairwise_disjoint_supp_connectedComponent _ hxy) = - c'.supp.toFinset := - Finset.coe_injective <| by simpa using ConnectedComponent.biUnion_supp_eq_supp h _ - end Fintype - -/-- The odd components are the connected components of odd cardinality. This definition excludes -infinite components. -/ -abbrev oddComponents : Set G.ConnectedComponent := {c : G.ConnectedComponent | Odd c.supp.ncard} - -set_option backward.isDefEq.respectTransparency false in -lemma ConnectedComponent.odd_oddComponents_ncard_subset_supp [Finite V] {G'} - (h : G ≤ G') (c' : ConnectedComponent G') : - Odd {c ∈ G.oddComponents | c.supp ⊆ c'.supp}.ncard ↔ Odd c'.supp.ncard := by - simp_rw [← Nat.card_coe_set_eq] - classical - cases nonempty_fintype V - rw [Nat.card_eq_card_toFinset c'.supp, ← disjiUnion_supp_toFinset_eq_supp_toFinset h] - simp only [Finset.card_disjiUnion, Set.toFinset_card, Fintype.card_ofFinset] - rw [Finset.odd_sum_iff_odd_card_odd, Nat.card_eq_fintype_card, Fintype.card_ofFinset] - congr! 2 - ext c - simp_rw [Set.toFinset_setOf, mem_filter, ← Set.ncard_coe_finset, coe_filter, - mem_supp_iff, mem_univ, true_and, supp, and_comm] - -lemma odd_ncard_oddComponents [Finite V] : Odd G.oddComponents.ncard ↔ Odd (Nat.card V) := by - classical - cases nonempty_fintype V - rw [Nat.card_eq_fintype_card] - simp only [← (set_fintype_card_eq_univ_iff _).mpr G.iUnion_connectedComponentSupp, - ← Set.toFinset_card, Set.toFinset_iUnion ConnectedComponent.supp] - rw [Finset.card_biUnion - (fun x _ y _ hxy ↦ Set.disjoint_toFinset.mpr (pairwise_disjoint_supp_connectedComponent _ hxy))] - simp_rw [← Set.ncard_eq_toFinset_card', ← Finset.coe_filter_univ, Set.ncard_coe_finset] - exact (Finset.odd_sum_iff_odd_card_odd (fun x : G.ConnectedComponent ↦ x.supp.ncard)).symm - -lemma ncard_oddComponents_mono [Finite V] {G' : SimpleGraph V} (h : G ≤ G') : - G'.oddComponents.ncard ≤ G.oddComponents.ncard := by - have aux (c : G'.ConnectedComponent) (hc : Odd c.supp.ncard) : - {c' : G.ConnectedComponent | Odd c'.supp.ncard ∧ c'.supp ⊆ c.supp}.Nonempty := by - refine Set.nonempty_of_ncard_ne_zero fun h' ↦ ?_ - simpa [-Nat.card_eq_fintype_card, -Set.coe_setOf, h'] - using (c.odd_oddComponents_ncard_subset_supp _ h).2 hc - let f : G'.oddComponents → G.oddComponents := - fun ⟨c, hc⟩ ↦ ⟨(aux c hc).choose, (aux c hc).choose_spec.1⟩ - refine Nat.card_le_card_of_injective f fun c c' fcc' ↦ ?_ - simp only [Subtype.mk.injEq, f] at fcc' - exact Subtype.val_injective (ConnectedComponent.eq_of_common_vertex - ((fcc' ▸ (aux c.1 c.2).choose_spec.2) (ConnectedComponent.nonempty_supp _).some_mem) - ((aux c'.1 c'.2).choose_spec.2 (ConnectedComponent.nonempty_supp _).some_mem)) - -end WalkCounting - end SimpleGraph diff --git a/Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkDecomp.lean b/Mathlib/Combinatorics/SimpleGraph/Walks/Decomp.lean similarity index 95% rename from Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkDecomp.lean rename to Mathlib/Combinatorics/SimpleGraph/Walks/Decomp.lean index ec2975fc839993..697d555beb5327 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkDecomp.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Walks/Decomp.lean @@ -297,30 +297,28 @@ lemma notMem_support_takeUntil_support_takeUntil_subset {p : G.Walk u v} {w x : lia /-- Rotate a loop walk such that it is centered at the given vertex. -/ -def rotate {u v : V} (c : G.Walk v v) (h : u ∈ c.support) : G.Walk u u := +def rotate (c : G.Walk v v) (u : V) (h : u ∈ c.support) : G.Walk u u := (c.dropUntil u h).append (c.takeUntil u h) @[simp] -theorem support_rotate {u v : V} (c : G.Walk v v) (h : u ∈ c.support) : - (c.rotate h).support.tail ~r c.support.tail := by +theorem support_rotate (c : G.Walk v v) (u : V) (h) : + (c.rotate u h).support.tail ~r c.support.tail := by simp only [rotate, tail_support_append] apply List.IsRotated.trans List.isRotated_append rw [← tail_support_append, take_spec] @[simp] -theorem mem_support_rotate_iff (c : G.Walk v v) (h : u ∈ c.support) : - w ∈ (c.rotate h).support ↔ w ∈ c.support := by +theorem mem_support_rotate_iff (c : G.Walk v v) (u : V) (h) : + w ∈ (c.rotate u h).support ↔ w ∈ c.support := by grind [rotate, take_spec, mem_support_append_iff] -theorem rotate_darts {u v : V} (c : G.Walk v v) (h : u ∈ c.support) : - (c.rotate h).darts ~r c.darts := by +theorem rotate_darts (c : G.Walk v v) (u : V) (h) : (c.rotate u h).darts ~r c.darts := by simp only [rotate, darts_append] apply List.IsRotated.trans List.isRotated_append rw [← darts_append, take_spec] -theorem rotate_edges {u v : V} (c : G.Walk v v) (h : u ∈ c.support) : - (c.rotate h).edges ~r c.edges := - (rotate_darts c h).map _ +theorem rotate_edges (c : G.Walk v v) (u : V) (h) : (c.rotate u h).edges ~r c.edges := + (rotate_darts c u h).map _ end WalkDecomp diff --git a/Mathlib/Combinatorics/SimpleGraph/Walks/Operations.lean b/Mathlib/Combinatorics/SimpleGraph/Walks/Operations.lean index 20561a26488c23..756317cf4e5aff 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Walks/Operations.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Walks/Operations.lean @@ -580,6 +580,11 @@ lemma take_support_eq_support_take_succ {u v} (p : G.Walk u v) (n : ℕ) : (p.take n).support = p.support.take (n + 1) := by induction p generalizing n <;> cases n <;> simp [*, take] +lemma take_take (p : G.Walk u v) (n m : ℕ) : + (p.take n).take m = (p.take (min n m)).copy rfl (p.take_getVert n m).symm := by + apply ext_support + simp [take_support_eq_support_take_succ, List.take_take, Nat.min_left_comm] + lemma take_of_length_le {u v n} {p : G.Walk u v} (h : p.length ≤ n) : p.take n = p.copy rfl (p.getVert_of_length_le h).symm := by induction n generalizing p u with diff --git a/Mathlib/Combinatorics/Tiling/Tile.lean b/Mathlib/Combinatorics/Tiling/Tile.lean index 7a8279f5230242..1a43b33cf369ce 100644 --- a/Mathlib/Combinatorics/Tiling/Tile.lean +++ b/Mathlib/Combinatorics/Tiling/Tile.lean @@ -154,7 +154,8 @@ element of `G`, used with `induction pt using PlacedTile.induction_on`. -/ @[elab_as_elim] protected lemma induction_on {ppt : PlacedTile ps → Prop} (pt : PlacedTile ps) (h : ∀ i : ιₚ, ∀ gx : G, ppt ⟨i, gx⟩) : ppt pt := by rcases pt with ⟨i, gx⟩ - exact Quotient.inductionOn' gx (h i) + induction gx using Quotient.inductionOn + apply h /-- An alternative extensionality principle for `PlacedTile` that avoids `HEq`, using existence of a common group element. -/ diff --git a/Mathlib/Computability/Primrec/List.lean b/Mathlib/Computability/Primrec/List.lean index 52674a4a975413..b09e849a75f9ef 100644 --- a/Mathlib/Computability/Primrec/List.lean +++ b/Mathlib/Computability/Primrec/List.lean @@ -373,6 +373,26 @@ theorem nat_omega_rec (f : α → β → σ) {m : α → β → ℕ} (hg.comp₂ (fst.comp₂ .left) (Primrec₂.pair.comp₂ (snd.comp₂ .left) .right)) (by simpa using Ord) (by simpa [Function.comp] using H) +/-- `List.drop` is primitive recursive. -/ +theorem list_drop : Primrec₂ (List.drop : ℕ → List α → List α) := + (nat_iterate fst snd (list_tail.comp₂ .right)).to₂.of_eq fun n l => l.tail_iterate n + +/-- `List.take` is primitive recursive. -/ +theorem list_take : Primrec₂ (List.take : ℕ → List α → List α) := + (list_reverse.comp (list_drop.comp (nat_sub.comp (list_length.comp snd) fst) + (list_reverse.comp snd))).of_eq fun ⟨n, l⟩ => by + rw [← List.reverse_reverse (l.take n), List.reverse_take] + +/-- `List.takeWhile` is primitive recursive. -/ +theorem list_takeWhile {p : α → Bool} (hp : Primrec p) : Primrec (List.takeWhile p) := + (list_take.comp (list_findIdx Primrec.id (Primrec.not.comp (hp.comp snd)).to₂) + Primrec.id).of_eq fun _ => List.takeWhile_eq_take_findIdx_not.symm + +/-- `List.dropWhile` is primitive recursive. -/ +theorem list_dropWhile {p : α → Bool} (hp : Primrec p) : Primrec (List.dropWhile p) := + (list_drop.comp (list_findIdx Primrec.id (Primrec.not.comp (hp.comp snd)).to₂) + Primrec.id).of_eq fun _ => List.dropWhile_eq_drop_findIdx_not.symm + end Primrec namespace PrimrecPred diff --git a/Mathlib/Computability/TuringMachine/Tape.lean b/Mathlib/Computability/TuringMachine/Tape.lean index c4a59c71c4096c..22ad98a2f1fb51 100644 --- a/Mathlib/Computability/TuringMachine/Tape.lean +++ b/Mathlib/Computability/TuringMachine/Tape.lean @@ -226,14 +226,16 @@ theorem ListBlank.nth_mk {Γ} [Inhabited Γ] (l : List Γ) (n : ℕ) : @[simp] theorem ListBlank.nth_zero {Γ} [Inhabited Γ] (l : ListBlank Γ) : l.nth 0 = l.head := by - conv => lhs; rw [← ListBlank.cons_head_tail l] - exact Quotient.inductionOn' l.tail fun l ↦ rfl + rw [← ListBlank.cons_head_tail l] + induction l.tail using Quotient.inductionOn' + rfl @[simp] theorem ListBlank.nth_succ {Γ} [Inhabited Γ] (l : ListBlank Γ) (n : ℕ) : l.nth (n + 1) = l.tail.nth n := by - conv => lhs; rw [← ListBlank.cons_head_tail l] - exact Quotient.inductionOn' l.tail fun l ↦ rfl + rw [← ListBlank.cons_head_tail l] + induction l.tail using Quotient.inductionOn' + rfl @[ext] theorem ListBlank.ext {Γ} [i : Inhabited Γ] {L₁ L₂ : ListBlank Γ} : @@ -313,14 +315,16 @@ theorem ListBlank.map_mk {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap @[simp] theorem ListBlank.head_map {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap Γ Γ') (l : ListBlank Γ) : (l.map f).head = f l.head := by - conv => lhs; rw [← ListBlank.cons_head_tail l] - exact Quotient.inductionOn' l fun a ↦ rfl + rw [← ListBlank.cons_head_tail l] + induction l using Quotient.inductionOn' + rfl @[simp] theorem ListBlank.tail_map {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap Γ Γ') (l : ListBlank Γ) : (l.map f).tail = l.tail.map f := by - conv => lhs; rw [← ListBlank.cons_head_tail l] - exact Quotient.inductionOn' l fun a ↦ rfl + rw [← ListBlank.cons_head_tail l] + induction l using Quotient.inductionOn' + rfl @[simp] theorem ListBlank.map_cons {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap Γ Γ') diff --git a/Mathlib/Control/Bitraversable/Basic.lean b/Mathlib/Control/Bitraversable/Basic.lean index 77e9aad542956d..fc520096d44b85 100644 --- a/Mathlib/Control/Bitraversable/Basic.lean +++ b/Mathlib/Control/Bitraversable/Basic.lean @@ -21,12 +21,12 @@ def AList (key val : Type) := List (key × val) ``` Then we can use `f : key → IO key'` and `g : val → IO val'` to manipulate the `AList`'s key -and value respectively with `Bitraverse f g : AList key val → IO (AList key' val')`. +and value respectively with `bitraverse f g : AList key val → IO (AList key' val')`. ## Main definitions -* `Bitraversable`: Bare typeclass to hold the `Bitraverse` function. -* `LawfulBitraversable`: Typeclass for the laws of the `Bitraverse` function. Similar to +* `Bitraversable`: Bare typeclass to hold the `bitraverse` function. +* `LawfulBitraversable`: Typeclass for the laws of the `bitraverse` function. Similar to `LawfulTraversable`. ## References diff --git a/Mathlib/Control/Lawful.lean b/Mathlib/Control/Lawful.lean index 8db9b32124cda0..982e427a300a0a 100644 --- a/Mathlib/Control/Lawful.lean +++ b/Mathlib/Control/Lawful.lean @@ -5,7 +5,7 @@ Authors: Sebastian Ullrich -/ module -public import Mathlib.Tactic.Basic +public import Mathlib.Tactic.Lemma /-! # Functor Laws, applicative laws, and monad Laws diff --git a/Mathlib/Data/ENat/Basic.lean b/Mathlib/Data/ENat/Basic.lean index c436ec43f4aab8..029e2d1be15f9b 100644 --- a/Mathlib/Data/ENat/Basic.lean +++ b/Mathlib/Data/ENat/Basic.lean @@ -73,9 +73,14 @@ variable {a b c d m n : ℕ∞} theorem coe_inj {a b : ℕ} : (a : ℕ∞) = b ↔ a = b := WithTop.coe_inj -set_option backward.isDefEq.respectTransparency false in +@[simp] theorem succ_coe (n : ℕ) : SuccOrder.succ (n : ℕ∞) = (n + 1 : ℕ) := by + simp [SuccOrder.succ] + rfl + +@[simp] theorem succ_top : SuccOrder.succ (⊤ : ℕ∞) = ⊤ := rfl + instance : SuccAddOrder ℕ∞ where - succ_eq_add_one x := by cases x <;> simp [SuccOrder.succ] + succ_eq_add_one x := by cases x <;> simp theorem coe_zero : ((0 : ℕ) : ℕ∞) = 0 := rfl diff --git a/Mathlib/Data/ENat/BigOperators.lean b/Mathlib/Data/ENat/BigOperators.lean index d7f3063e69d75e..c9b2924b86b2b4 100644 --- a/Mathlib/Data/ENat/BigOperators.lean +++ b/Mathlib/Data/ENat/BigOperators.lean @@ -1,10 +1,12 @@ /- Copyright (c) 2024 Joachim Breitner, Yaël Dillies. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Joachim Breitner, Yaël Dillies +Authors: Joachim Breitner, Yaël Dillies, Bhavik Mehta -/ module +public import Mathlib.Algebra.BigOperators.Ring.Finset +public import Mathlib.Algebra.BigOperators.WithTop public import Mathlib.Algebra.Order.BigOperators.Group.Finset public import Mathlib.Data.ENat.Lattice @@ -18,6 +20,78 @@ assert_not_exists Field namespace ENat +variable {a b c d : ℕ∞} {r p q : ℕ} + +section OperationsAndInfty + +variable {α : Type*} + +@[simp] +theorem toNat_prod {ι : Type*} {s : Finset ι} {f : ι → ℕ∞} : + (∏ i ∈ s, f i).toNat = ∏ i ∈ s, (f i).toNat := + map_prod toNatHom _ _ + +theorem iInf_sum {ι α : Type*} {f : ι → α → ℕ∞} {s : Finset α} [Nonempty ι] + (h : ∀ (t : Finset α) (i j : ι), ∃ k, ∀ a ∈ t, f k a ≤ f i a ∧ f k a ≤ f j a) : + ⨅ i, ∑ a ∈ s, f i a = ∑ a ∈ s, ⨅ i, f i a := by + induction s using Finset.cons_induction_on with + | empty => simp only [Finset.sum_empty, ciInf_const] + | cons a s ha ih => + simp only [Finset.sum_cons, ← ih] + refine (iInf_add_iInf fun i j => ?_).symm + refine (h (Finset.cons a s ha) i j).imp fun k hk => ?_ + rw [Finset.forall_mem_cons] at hk + exact add_le_add hk.1.1 (Finset.sum_le_sum fun a ha => (hk.2 a ha).2) + +end OperationsAndInfty + +section Sum + +open Finset + +variable {α : Type*} {s : Finset α} {f : α → ℕ∞} + +/-- A product of finite numbers is still finite. -/ +lemma prod_ne_top (h : ∀ a ∈ s, f a ≠ ⊤) : ∏ a ∈ s, f a ≠ ⊤ := WithTop.prod_ne_top h + +/-- A product of finite numbers is still finite. -/ +lemma prod_lt_top (h : ∀ a ∈ s, f a < ⊤) : ∏ a ∈ s, f a < ⊤ := WithTop.prod_lt_top h + +/-- A sum is infinite iff one of the summands is infinite. -/ +@[simp] lemma sum_eq_top : ∑ x ∈ s, f x = ⊤ ↔ ∃ a ∈ s, f a = ⊤ := WithTop.sum_eq_top + +/-- A sum is finite iff all summands are finite. -/ +lemma sum_ne_top : ∑ a ∈ s, f a ≠ ⊤ ↔ ∀ a ∈ s, f a ≠ ⊤ := WithTop.sum_ne_top + +/-- A sum is finite iff all summands are finite. -/ +@[simp] lemma sum_lt_top : ∑ a ∈ s, f a < ⊤ ↔ ∀ a ∈ s, f a < ⊤ := WithTop.sum_lt_top + +theorem lt_top_of_sum_ne_top {s : Finset α} {f : α → ℕ∞} (h : ∑ x ∈ s, f x ≠ ⊤) {a : α} + (ha : a ∈ s) : f a < ⊤ := + sum_lt_top.1 h.lt_top a ha + +/-- Seeing `ℕ∞` as `ℕ` does not change their sum, unless one of the `ℕ∞` is +infinity -/ +theorem toNat_sum {s : Finset α} {f : α → ℕ∞} (hf : ∀ a ∈ s, f a ≠ ⊤) : + ENat.toNat (∑ a ∈ s, f a) = ∑ a ∈ s, ENat.toNat (f a) := by + rw [← coe_inj, coe_toNat (sum_ne_top.2 hf), Nat.cast_sum] + exact sum_congr rfl fun x hx => (coe_toNat (hf x hx)).symm + +theorem sum_lt_sum_of_nonempty {s : Finset α} (hs : s.Nonempty) {f g : α → ℕ∞} + (Hlt : ∀ i ∈ s, f i < g i) : ∑ i ∈ s, f i < ∑ i ∈ s, g i := by + induction hs using Nonempty.cons_induction with + | singleton => simp [Hlt _ (mem_singleton_self _)] + | cons _ _ _ _ ih => + simp only [sum_cons, forall_mem_cons] at Hlt ⊢ + exact ENat.add_lt_add Hlt.1 (ih Hlt.2) + +theorem exists_le_of_sum_le {s : Finset α} (hs : s.Nonempty) {f g : α → ℕ∞} + (Hle : ∑ i ∈ s, f i ≤ ∑ i ∈ s, g i) : ∃ i ∈ s, f i ≤ g i := by + contrapose! Hle + apply sum_lt_sum_of_nonempty hs Hle + +end Sum + lemma sum_iSup {α ι : Type*} {s : Finset α} {f : α → ι → ℕ∞} (hf : ∀ i j, ∃ k, ∀ a, f a i ≤ f a k ∧ f a j ≤ f a k) : ∑ a ∈ s, ⨆ i, f a i = ⨆ i, ∑ a ∈ s, f a i := by diff --git a/Mathlib/Data/ENat/Pow.lean b/Mathlib/Data/ENat/Pow.lean index 07e6c0ed37fa98..d1efefdffb2caf 100644 --- a/Mathlib/Data/ENat/Pow.lean +++ b/Mathlib/Data/ENat/Pow.lean @@ -35,6 +35,12 @@ instance : Pow ℕ∞ ℕ∞ where | x, some y => x ^ y | x, ⊤ => if x = 0 then 0 else if x = 1 then 1 else ⊤ +lemma epow_def {x y : ℕ∞} : + x ^ y = if y < ⊤ then x ^ y.toNat else if x = 0 then 0 else if x = 1 then 1 else ⊤ := by + cases y with + | top => simp only [lt_self_iff_false, ↓reduceIte]; rfl + | coe n => simp only [coe_lt_top, ↓reduceIte, toNat_coe]; rfl + @[simp, norm_cast] lemma epow_natCast {y : ℕ} : x ^ (y : ℕ∞) = x ^ y := rfl @@ -71,7 +77,8 @@ lemma epow_one : x ^ (1 : ℕ∞) = x := by rw [← coe_one, epow_natCast, pow_one] lemma epow_top (h : 1 < x) : x ^ (⊤ : ℕ∞) = ⊤ := by - simp +instances only [instHPow, instPow, (zero_le_one.trans_lt h).ne.symm, ↓reduceIte, h.ne.symm] + have : (0 : ℕ∞) ≤ 1 := zero_le_one + rw [epow_def, if_neg, if_neg, if_neg] <;> grind set_option backward.isDefEq.respectTransparency false in lemma epow_right_mono (h : x ≠ 0) : Monotone (fun y : ℕ∞ ↦ x ^ y) := by diff --git a/Mathlib/Data/Finite/Card.lean b/Mathlib/Data/Finite/Card.lean index 225afa71ad381b..df3169184f03d3 100644 --- a/Mathlib/Data/Finite/Card.lean +++ b/Mathlib/Data/Finite/Card.lean @@ -229,3 +229,20 @@ theorem eq_top_of_card_le_of_finite [Finite α] {s : Set α} (h : Nat.card α Nat.card_congr (Equiv.Set.univ α) ▸ h end Set + +namespace List.Nodup + +variable {l : List α} (h : l.Nodup) +include h + +theorem length_le_natCard [Finite α] : l.length ≤ Nat.card α := by + have := Fintype.ofFinite α + grw [h.length_le_card, Fintype.card_eq_nat_card] + +theorem length_le_enatCard : l.length ≤ ENat.card α := by + cases finite_or_infinite α + · grw [h.length_le_natCard, ENat.card_eq_coe_natCard] + · grw [ENat.card_eq_top_of_infinite] + exact le_top + +end List.Nodup diff --git a/Mathlib/Data/Finsupp/Indicator.lean b/Mathlib/Data/Finsupp/Indicator.lean index 03ef160aa11fd1..60b9ff31463e75 100644 --- a/Mathlib/Data/Finsupp/Indicator.lean +++ b/Mathlib/Data/Finsupp/Indicator.lean @@ -28,7 +28,7 @@ variable {ι α : Type*} namespace Finsupp -variable [Zero α] {s : Finset ι} (f : ∀ i ∈ s, α) {i : ι} +variable [Zero α] {s t : Finset ι} (f : ∀ i ∈ s, α) {i : ι} /-- Create an element of `ι →₀ α` from a finset `s` and a function `f` defined on this finset. -/ def indicator (s : Finset ι) (f : ∀ i ∈ s, α) : ι →₀ α where @@ -71,4 +71,25 @@ lemma single_eq_indicator (b : α) : single i b = indicator {i} (fun _ _ => b) : ext j simp [single_apply, indicator_apply, @eq_comm _ j] +theorem indicator_indicator [DecidableEq ι] : + indicator t (fun i _ ↦ indicator s f i) = + indicator (s ∩ t) (fun i hi ↦ f i (Finset.mem_of_mem_inter_left hi)) := by + ext i + grind [indicator_apply] + +theorem eq_indicator_iff {g : ι → α} : + g = indicator s f ↔ g.support ⊆ s ∧ ∀ ⦃i⦄ (hi : i ∈ s), f i hi = g i := by + classical + suffices g.support ⊆ s ∧ (∀ i (hi : i ∈ s), f i hi = g i) ↔ + (∀ i , if hi : i ∈ s then f i hi = g i else g i = 0) by + simp only [this, funext_iff, indicator_apply] + grind + rw [Set.subset_def, and_comm] + have : (∀ (i : ι), if hi : i ∈ s then f i hi = g i else g i = 0) ↔ + ((∀ (i : ι) (hi : i ∈ s), f i hi = g i) ∧ ∀ i (hi : i ∉ s), g i = 0) := by grind + simp [this, not_imp_comm] + +theorem eq_indicator_self_iff {d : ι →₀ α} : (d = indicator s fun i _ ↦ d i) ↔ d.support ⊆ s := by + grind [indicator] + end Finsupp diff --git a/Mathlib/Data/Fintype/Basic.lean b/Mathlib/Data/Fintype/Basic.lean index 9e8c44d553c5c2..d2c9f004482ba2 100644 --- a/Mathlib/Data/Fintype/Basic.lean +++ b/Mathlib/Data/Fintype/Basic.lean @@ -289,9 +289,4 @@ theorem exists_seq_of_forall_finset_exists' {α : Type*} (P : α → Prop) (r : ∃ f : ℕ → α, (∀ n, P (f n)) ∧ Pairwise (r on f) := by rcases exists_seq_of_forall_finset_exists P r h with ⟨f, hf, hf'⟩ refine ⟨f, hf, fun m n hmn => ?_⟩ - rcases lt_trichotomy m n with (h | rfl | h) - · exact hf' m n h - · exact (hmn rfl).elim - · unfold Function.onFun - apply symm - exact hf' n m h + grind +splitIndPred diff --git a/Mathlib/Data/Fintype/Card.lean b/Mathlib/Data/Fintype/Card.lean index 6726fd6e433c51..acca9b0f9856a7 100644 --- a/Mathlib/Data/Fintype/Card.lean +++ b/Mathlib/Data/Fintype/Card.lean @@ -143,6 +143,14 @@ theorem Finset.card_compl_add_card [DecidableEq α] [Fintype α] (s : Finset α) #sᶜ + #s = Fintype.card α := by rw [Nat.add_comm, card_add_card_compl] +theorem Finset.compl_eq_of_disjoint_of_card_add_eq + {ι : Type*} [DecidableEq ι] [Fintype ι] {S₁ S₂ : Finset ι} (h : Disjoint S₁ S₂) + (h' : S₁.card + S₂.card = Finset.card (.univ : Finset ι)) : + S₁ᶜ = S₂ := + (Finset.eq_of_subset_of_card_le + (by rwa [Finset.subset_compl_iff_disjoint_left]) + (by simp [← Nat.add_le_add_iff_left (n := S₁.card), h'])).symm + theorem Fintype.card_compl_set [Fintype α] (s : Set α) [Fintype s] [Fintype (↥sᶜ : Sort _)] : Fintype.card (↥sᶜ : Sort _) = Fintype.card α - Fintype.card s := by classical rw [← Set.toFinset_card, ← Set.toFinset_card, ← Finset.card_compl, Set.toFinset_compl] diff --git a/Mathlib/Data/FunLike/Basic.lean b/Mathlib/Data/FunLike/Basic.lean index 70231ca39b5848..89086e2f6db619 100644 --- a/Mathlib/Data/FunLike/Basic.lean +++ b/Mathlib/Data/FunLike/Basic.lean @@ -5,6 +5,7 @@ Authors: Anne Baanen -/ module +public meta import Lean.Meta.CoeAttr public import Mathlib.Logic.Function.Basic public import Mathlib.Logic.Unique public import Mathlib.Util.CompileInductive diff --git a/Mathlib/Data/List/Defs.lean b/Mathlib/Data/List/Defs.lean index 06634a18061859..ff784acfe41bc8 100644 --- a/Mathlib/Data/List/Defs.lean +++ b/Mathlib/Data/List/Defs.lean @@ -468,4 +468,11 @@ theorem length_mapAccumr₂ : end MapAccumr +section consecutivePairs + +/-- `consecutivePairs [a, b, c, d]` is `[(a, b), (b, c), (c, d)]`. -/ +abbrev consecutivePairs (l : List α) : List (α × α) := l.zip l.tail + +end consecutivePairs + end List diff --git a/Mathlib/Data/List/TakeDrop.lean b/Mathlib/Data/List/TakeDrop.lean index 0ead2e17629786..a297cc1411a9ef 100644 --- a/Mathlib/Data/List/TakeDrop.lean +++ b/Mathlib/Data/List/TakeDrop.lean @@ -7,6 +7,7 @@ module public import Mathlib.Data.List.Defs public import Mathlib.Tactic.Common +public import Mathlib.Logic.Function.Iterate /-! # `Take` and `Drop` lemmas for lists @@ -81,6 +82,12 @@ lemma drop_length_sub_one {l : List α} (h : l ≠ []) : l.drop (l.length - 1) = rw [length_cons, Nat.add_one_sub_one, List.drop_length_cons hl a] simp [getLast_cons, hl] +/-- Applying `tail` to a list `n` times is equivalent to dropping `n` elements. -/ +theorem tail_iterate (l : List α) (n : ℕ) : (List.tail^[n]) l = l.drop n := by + induction n generalizing l with + | zero => rfl + | succ n ih => cases l <;> simp [*] + section TakeI variable [Inhabited α] diff --git a/Mathlib/Data/Multiset/Functor.lean b/Mathlib/Data/Multiset/Functor.lean index 679a4ecdc4b58d..aab50961e376cd 100644 --- a/Mathlib/Data/Multiset/Functor.lean +++ b/Mathlib/Data/Multiset/Functor.lean @@ -92,39 +92,34 @@ theorem map_comp_coe {α β} (h : α → β) : funext; simp only [Function.comp_apply, fmap_def, map_coe, List.map_eq_map] theorem id_traverse {α : Type*} (x : Multiset α) : traverse (pure : α → Id α) x = pure x := by - refine Quotient.inductionOn x ?_ - intro + induction x using Quotient.inductionOn simp [traverse] theorem comp_traverse {G H : Type _ → Type _} [Applicative G] [Applicative H] [CommApplicative G] [CommApplicative H] {α β γ : Type _} (g : α → G β) (h : β → H γ) (x : Multiset α) : traverse (Comp.mk ∘ Functor.map h ∘ g) x = Comp.mk (Functor.map (traverse h) (traverse g x)) := by - refine Quotient.inductionOn x ?_ - intro + induction x using Quotient.inductionOn simp only [traverse, quot_mk_to_coe, lift_coe, Function.comp_apply, Functor.map_map, functor_norm] theorem map_traverse {G : Type* → Type _} [Applicative G] [CommApplicative G] {α β γ : Type _} (g : α → G β) (h : β → γ) (x : Multiset α) : Functor.map (Functor.map h) (traverse g x) = traverse (Functor.map h ∘ g) x := by - refine Quotient.inductionOn x ?_ - intro + induction x using Quotient.inductionOn simp only [traverse, quot_mk_to_coe, lift_coe, Function.comp_apply, Functor.map_map] rw [Traversable.map_traverse'] simp only [fmap_def, Function.comp_apply, Functor.map_map, List.map_eq_map, map_coe] theorem traverse_map {G : Type* → Type _} [Applicative G] [CommApplicative G] {α β γ : Type _} (g : α → β) (h : β → G γ) (x : Multiset α) : traverse h (map g x) = traverse (h ∘ g) x := by - refine Quotient.inductionOn x ?_ - intro + induction x using Quotient.inductionOn simp only [traverse, quot_mk_to_coe, map_coe, lift_coe, Function.comp_apply] rw [← Traversable.traverse_map h g, List.map_eq_map] theorem naturality {G H : Type _ → Type _} [Applicative G] [Applicative H] [CommApplicative G] [CommApplicative H] (eta : ApplicativeTransformation G H) {α β : Type _} (f : α → G β) (x : Multiset α) : eta (traverse f x) = traverse (@eta _ ∘ f) x := by - refine Quotient.inductionOn x ?_ - intro + induction x using Quotient.inductionOn simp only [quot_mk_to_coe, traverse, lift_coe, Function.comp_apply, ApplicativeTransformation.preserves_map, LawfulTraversable.naturality] diff --git a/Mathlib/Data/Multiset/Sym.lean b/Mathlib/Data/Multiset/Sym.lean index 92e5dca884ecab..fe557531e167ba 100644 --- a/Mathlib/Data/Multiset/Sym.lean +++ b/Mathlib/Data/Multiset/Sym.lean @@ -80,7 +80,7 @@ protected theorem Nodup.sym2 {m : Multiset α} (h : m.Nodup) : m.sym2.Nodup := open scoped List in @[simp, mono] theorem sym2_mono {m m' : Multiset α} (h : m ≤ m') : m.sym2 ≤ m'.sym2 := by - refine Quotient.inductionOn₂ m m' (fun xs ys h => ?_) h + induction m, m' using Quotient.inductionOn₂ with | _ xs ys suffices xs <+~ ys from this.sym2 simpa only [quot_mk_to_coe, coe_le, sym2_coe] using h diff --git a/Mathlib/Data/NNRat/Encodable.lean b/Mathlib/Data/NNRat/Encodable.lean new file mode 100644 index 00000000000000..4782364b7e71bf --- /dev/null +++ b/Mathlib/Data/NNRat/Encodable.lean @@ -0,0 +1,26 @@ +/- +Copyright (c) 2026 Aaron Liu. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Aaron Liu +-/ +module + +public import Mathlib.Logic.Encodable.Basic +public import Mathlib.Data.NNRat.Defs + +/-! # The nonnegative rationals are `Encodable`. + +As a consequence we also get the instance `Countable ℚ≥0`. +-/ + +namespace NNRat + +public instance : Encodable ℚ≥0 := + Encodable.ofEquiv (Σ n : ℕ, { d : ℕ // 0 < d ∧ n.Coprime d }) + ⟨fun q => ⟨q.num, q.den, q.den_pos, q.coprime_num_den⟩, + fun ⟨num, den, prop⟩ => ⟨⟨num, den, Nat.pos_iff_ne_zero.mp prop.1, prop.2⟩, + Rat.num_nonneg.mp (Int.natCast_nonneg num)⟩, + fun ⟨⟨num, _, _, _⟩, hq⟩ => by lift num to ℕ using Rat.num_nonneg.mpr hq; rfl, + Eq.refl⟩ + +end NNRat diff --git a/Mathlib/Data/NNReal/Defs.lean b/Mathlib/Data/NNReal/Defs.lean index fff9102387d2a0..ef3641b09fd830 100644 --- a/Mathlib/Data/NNReal/Defs.lean +++ b/Mathlib/Data/NNReal/Defs.lean @@ -99,7 +99,6 @@ noncomputable instance : SMul ℚ≥0 ℝ≥0 where noncomputable instance zpow : Pow ℝ≥0 ℤ where pow x n := ⟨(x : ℝ) ^ n, zpow_nonneg x.2 _⟩ -set_option backward.isDefEq.respectTransparency false in /-- Redo the `Nonneg.semifield` instance, because this will get unfolded a lot, and ends up inserting the non-reducible defeq `ℝ≥0 = { x // x ≥ 0 }` in places where it needs to be reducible(-with-instances). diff --git a/Mathlib/Data/Nat/Bits.lean b/Mathlib/Data/Nat/Bits.lean index 81b53b91e14cf1..2981aaf537466c 100644 --- a/Mathlib/Data/Nat/Bits.lean +++ b/Mathlib/Data/Nat/Bits.lean @@ -7,7 +7,7 @@ module public import Mathlib.Data.Nat.BinaryRec public import Mathlib.Data.List.Defs -public import Mathlib.Tactic.Basic +public import Mathlib.Tactic.Lemma /-! # Additional properties of binary recursion on `Nat` diff --git a/Mathlib/Data/Nat/Choose/Factorization.lean b/Mathlib/Data/Nat/Choose/Factorization.lean index 17390b916e3029..ab5859f3bc15a2 100644 --- a/Mathlib/Data/Nat/Choose/Factorization.lean +++ b/Mathlib/Data/Nat/Choose/Factorization.lean @@ -266,7 +266,7 @@ theorem le_two_mul_of_factorization_centralBinom_pos /-- A binomial coefficient is the product of its prime factors, which are at most `n`. -/ theorem prod_pow_factorization_choose (n k : ℕ) (hkn : k ≤ n) : (∏ p ∈ Finset.range (n + 1), p ^ (Nat.choose n k).factorization p) = choose n k := by - conv_rhs => rw [← factorization_prod_pow_eq_self (choose_ne_zero hkn)] + conv_rhs => rw [← prod_factorization_pow_eq_self (choose_ne_zero hkn)] rw [eq_comm] apply Finset.prod_subset · intro p hp diff --git a/Mathlib/Data/Nat/Choose/Multinomial.lean b/Mathlib/Data/Nat/Choose/Multinomial.lean index 9214c51881d1e8..b02b01200a76fb 100644 --- a/Mathlib/Data/Nat/Choose/Multinomial.lean +++ b/Mathlib/Data/Nat/Choose/Multinomial.lean @@ -83,6 +83,32 @@ theorem multinomial_congr {f g : α → ℕ} (h : ∀ a ∈ s, f a = g a) : · rw [Finset.sum_congr rfl h] · exact Finset.prod_congr rfl fun a ha => by rw [h a ha] +theorem multinomial_congr_of_eq_on_inter [DecidableEq α] {f g : α → ℕ} {s t : Finset α} + (hf : ∀ a ∈ s \ t, f a = 0) (hg : ∀ a ∈ t \ s, g a = 0) (hfg : ∀ a ∈ s ∩ t, f a = g a) : + multinomial s f = multinomial t g := by + rw [← Nat.mul_right_inj (prod_ne_zero_iff.mpr (fun x _ ↦ factorial_ne_zero (g x))), + multinomial_spec, prod_congr_of_eq_on_inter (g := fun a ↦ (f a)!) (s₂ := s) (by aesop) + (by aesop) (by aesop), multinomial_spec s f] + congr 1 + exact sum_congr_of_eq_on_inter (by grind) (by grind) (by grind) + +theorem multinomial_congr_of_sdiff [DecidableEq α] {f g : α → ℕ} {s t : Finset α} + (hst : s ⊆ t) (hg : ∀ a ∈ t \ s, g a = 0) (hfg : ∀ a ∈ s, f a = g a) : + multinomial s f = multinomial t g := + multinomial_congr_of_eq_on_inter (by grind) hg (by grind) + +variable (s a) in +theorem multinomial_single [DecidableEq α] : + multinomial s (Pi.single a n) = 1 := by + rw [← Nat.mul_right_inj (prod_ne_zero_iff.mpr (fun _ _ ↦ factorial_ne_zero _)), mul_one, + multinomial_spec, sum_pi_single'] + split_ifs with ha + · rw [Finset.prod_eq_single a (by simp_all) (by simp_all), Pi.single_eq_same] + · rw [eq_comm, factorial_zero] + apply Finset.prod_eq_one + intro _ hb + rw [Pi.single_apply, if_neg (ne_of_mem_of_not_mem hb ha), factorial_zero] + /-! ### Connection to binomial coefficients When `Nat.multinomial` is applied to a `Finset` of two elements `{a, b}`, the diff --git a/Mathlib/Data/Nat/Digits/Lemmas.lean b/Mathlib/Data/Nat/Digits/Lemmas.lean index d53b069b2c464f..54710594e597fd 100644 --- a/Mathlib/Data/Nat/Digits/Lemmas.lean +++ b/Mathlib/Data/Nat/Digits/Lemmas.lean @@ -50,7 +50,8 @@ theorem ofDigits_eq_sum_mapIdx (b : ℕ) (L : List ℕ) : This section contains various lemmas of properties relating to `digits` and `ofDigits`. -/ -theorem digits_len (b n : ℕ) (hb : 1 < b) (hn : n ≠ 0) : (b.digits n).length = b.log n + 1 := by +theorem length_digits (b n : ℕ) (hb : 1 < b) (hn : n ≠ 0) : + (b.digits n).length = b.log n + 1 := by induction n using Nat.strong_induction_on with | _ n IH rw [digits_eq_cons_digits_div hb hn, List.length] by_cases h : n / b = 0 @@ -62,12 +63,14 @@ theorem digits_len (b n : ℕ) (hb : 1 < b) (hn : n ≠ 0) : (b.digits n).length contrapose! h exact div_eq_of_lt h +@[deprecated (since := "2026-03-18")] alias digits_len := length_digits + theorem digits_length_le_iff {b k : ℕ} (hb : 1 < b) (n : ℕ) : (b.digits n).length ≤ k ↔ n < b ^ k := by by_cases h : n = 0 · have : 0 < b ^ k := by positivity simpa [h] - rw [digits_len b n hb h, ← log_lt_iff_lt_pow hb h] + rw [length_digits b n hb h, ← log_lt_iff_lt_pow hb h] exact add_one_le_iff theorem lt_digits_length_iff {b k : ℕ} (hb : 1 < b) (n : ℕ) : @@ -112,16 +115,21 @@ theorem digits_append_zeroes_append_digits {b k m n : ℕ} (hb : 1 < b) (hm : 0 simp only [digits_append_digits (zero_lt_of_lt hb), digits_inj_iff, add_right_inj] ring -theorem digits_len_le_digits_len_succ (b n : ℕ) : +theorem length_digits_le_length_digits_succ (b n : ℕ) : (digits b n).length ≤ (digits b (n + 1)).length := by rcases Decidable.eq_or_ne n 0 with (rfl | hn) · simp rcases le_or_gt b 1 with hb | hb · interval_cases b <;> simp +arith [digits_zero_succ', hn] - simpa [digits_len, hb, hn] using log_mono_right (le_succ _) + simpa [length_digits, hb, hn] using log_mono_right (le_succ _) + +@[deprecated (since := "2026-03-18")] +alias digits_len_le_digits_len_succ := length_digits_le_length_digits_succ + +theorem le_length_digits_le (b n m : ℕ) (h : n ≤ m) : (digits b n).length ≤ (digits b m).length := + monotone_nat_of_le_succ (length_digits_le_length_digits_succ b) h -theorem le_digits_len_le (b n m : ℕ) (h : n ≤ m) : (digits b n).length ≤ (digits b m).length := - monotone_nat_of_le_succ (digits_len_le_digits_len_succ b) h +@[deprecated (since := "2026-03-18")] alias le_digits_len_le := le_length_digits_le theorem pow_length_le_mul_ofDigits {b : ℕ} {l : List ℕ} (hl : l ≠ []) (hl2 : l.getLast hl ≠ 0) : (b + 2) ^ l.length ≤ (b + 2) * ofDigits (b + 2) l := by @@ -195,7 +203,7 @@ theorem sub_one_mul_sum_log_div_pow_eq_sub_sum_digits {p : ℕ} (n : ℕ) : · simp · convert sub_one_mul_sum_div_pow_eq_sub_sum_digits (p.digits n) (getLast_digit_ne_zero p hn) <| (fun l a ↦ digits_lt_base h a) - · refine (digits_len p n h hn).symm + · refine (length_digits p n h hn).symm all_goals exact (ofDigits_digits p n).symm · simp · simp [lt_one_iff.mp h] diff --git a/Mathlib/Data/Nat/Factorization/Basic.lean b/Mathlib/Data/Nat/Factorization/Basic.lean index 0a557f4090a222..2c0ac5a056a707 100644 --- a/Mathlib/Data/Nat/Factorization/Basic.lean +++ b/Mathlib/Data/Nat/Factorization/Basic.lean @@ -73,7 +73,7 @@ theorem factorization_pow_self {p n : ℕ} (hp : p.Prime) : (p ^ n).factorizatio /-- If the factorization of `n` contains just one number `p` then `n` is a power of `p` -/ theorem eq_pow_of_factorization_eq_single {n p k : ℕ} (hn : n ≠ 0) (h : n.factorization = Finsupp.single p k) : n = p ^ k := by - rw [← Nat.factorization_prod_pow_eq_self hn, h] + rw [← Nat.prod_factorization_pow_eq_self hn, h] simp /-- The only prime factor of prime `p` is `p` itself. -/ @@ -83,14 +83,10 @@ theorem Prime.eq_of_factorization_pos {p q : ℕ} (hp : Prime p) (h : p.factoriz /-! ### Equivalence between `ℕ+` and `ℕ →₀ ℕ` with support in the primes. -/ -theorem eq_factorization_iff {n : ℕ} {f : ℕ →₀ ℕ} (hn : n ≠ 0) (hf : ∀ p ∈ f.support, Prime p) : - f = n.factorization ↔ f.prod (· ^ ·) = n := - ⟨fun h => by rw [h, factorization_prod_pow_eq_self hn], fun h => by - rw [← h, prod_pow_factorization_eq_self hf]⟩ - +@[deprecated factorizationEquiv_symm_apply_coe (since := "2026-03-18")] theorem factorizationEquiv_inv_apply {f : ℕ →₀ ℕ} (hf : ∀ p ∈ f.support, Prime p) : (factorizationEquiv.symm ⟨f, hf⟩).1 = f.prod (· ^ ·) := - rfl + factorizationEquiv_symm_apply_coe ⟨f, hf⟩ theorem ordProj_of_not_prime (n p : ℕ) (hp : ¬p.Prime) : ordProj[p] n = 1 := by simp [hp] @@ -359,27 +355,18 @@ theorem prod_primeFactors_dvd (n : ℕ) : ∏ p ∈ n.primeFactors, p ∣ n := b theorem factorization_gcd {a b : ℕ} (ha_pos : a ≠ 0) (hb_pos : b ≠ 0) : (gcd a b).factorization = a.factorization ⊓ b.factorization := by - let dfac := a.factorization ⊓ b.factorization - let d := dfac.prod (· ^ ·) - have dfac_prime : ∀ p : ℕ, p ∈ dfac.support → Prime p := by - intro p hp - have : p ∈ a.primeFactorsList ∧ p ∈ b.primeFactorsList := by simpa [dfac] using hp - exact prime_of_mem_primeFactorsList this.1 - have h1 : d.factorization = dfac := prod_pow_factorization_eq_self dfac_prime - have hd_pos : d ≠ 0 := (factorizationEquiv.invFun ⟨dfac, dfac_prime⟩).2.ne' - suffices d = gcd a b by rwa [← this] + suffices (a.factorization ⊓ b.factorization).prod (· ^ ·) = gcd a b by + rw [← this, factorization_prod_pow_eq_self_of_le_factorization inf_le_left] apply gcd_greatest - · rw [← factorization_le_iff_dvd hd_pos ha_pos, h1] - exact inf_le_left - · rw [← factorization_le_iff_dvd hd_pos hb_pos, h1] - exact inf_le_right + · exact prod_pow_dvd_of_le_factorization inf_le_left + · exact prod_pow_dvd_of_le_factorization inf_le_right · intro e hea heb - rcases Decidable.eq_or_ne e 0 with (rfl | he_pos) - · simp only [zero_dvd_iff] at hea - contradiction + rcases eq_or_ne e 0 with (rfl | he_pos) + · exact absurd (zero_dvd_iff.mp hea) ha_pos + apply dvd_prod_pow_of_factorization_le he_pos have hea' := (factorization_le_iff_dvd he_pos ha_pos).mpr hea have heb' := (factorization_le_iff_dvd he_pos hb_pos).mpr heb - simp [dfac, ← factorization_le_iff_dvd he_pos hd_pos, h1, hea', heb'] + simp [hea', heb'] theorem factorization_lcm {a b : ℕ} (ha : a ≠ 0) (hb : b ≠ 0) : (a.lcm b).factorization = a.factorization ⊔ b.factorization := by @@ -478,7 +465,7 @@ theorem eq_iff_prime_padicValNat_eq (a b : ℕ) (ha : a ≠ 0) (hb : b ≠ 0) : theorem prod_pow_prime_padicValNat (n : Nat) (hn : n ≠ 0) (m : Nat) (pr : n < m) : ∏ p ∈ range m with p.Prime, p ^ padicValNat p n = n := by - nth_rw 2 [← factorization_prod_pow_eq_self hn] + nth_rw 2 [← prod_factorization_pow_eq_self hn] rw [eq_comm] apply Finset.prod_subset_one_on_sdiff · exact fun p hp => Finset.mem_filter.mpr ⟨Finset.mem_range.2 <| pr.trans_le' <| @@ -492,7 +479,7 @@ theorem prod_pow_prime_padicValNat (n : Nat) (hn : n ≠ 0) (m : Nat) (pr : n < lemma prod_pow_primeFactors_factorization (hn : n ≠ 0) : n = ∏ (p : n.primeFactors), (p : ℕ) ^ (n.factorization p) := by - nth_rw 1 [← factorization_prod_pow_eq_self hn] + nth_rw 1 [← prod_factorization_pow_eq_self hn] rw [prod_factorization_eq_prod_primeFactors _] exact prod_subtype n.primeFactors (fun _ ↦ Iff.rfl) fun a ↦ a ^ n.factorization a diff --git a/Mathlib/Data/Nat/Factorization/Defs.lean b/Mathlib/Data/Nat/Factorization/Defs.lean index 54841a2eba48d6..59c4d51d7ff7a2 100644 --- a/Mathlib/Data/Nat/Factorization/Defs.lean +++ b/Mathlib/Data/Nat/Factorization/Defs.lean @@ -94,11 +94,14 @@ theorem multiplicity_eq_factorization {n p : ℕ} (pp : p.Prime) (hn : n ≠ 0) @[simp] -theorem factorization_prod_pow_eq_self {n : ℕ} (hn : n ≠ 0) : n.factorization.prod (· ^ ·) = n := by +theorem prod_factorization_pow_eq_self {n : ℕ} (hn : n ≠ 0) : n.factorization.prod (· ^ ·) = n := by rw [factorization_eq_primeFactorsList_multiset n] simp only [← prod_toMultiset, Multiset.prod_coe, Multiset.toFinsupp_toMultiset] exact prod_primeFactorsList hn +@[deprecated (since := "2026-03-19")] +alias factorization_prod_pow_eq_self := prod_factorization_pow_eq_self + theorem eq_of_factorization_eq {a b : ℕ} (ha : a ≠ 0) (hb : b ≠ 0) (h : ∀ p : ℕ, a.factorization p = b.factorization p) : a = b := eq_of_perm_primeFactorsList ha hb @@ -161,7 +164,7 @@ theorem factorization_mul {a b : ℕ} (ha : a ≠ 0) (hb : b ≠ 0) : theorem factorization_le_iff_dvd {d n : ℕ} (hd : d ≠ 0) (hn : n ≠ 0) : d.factorization ≤ n.factorization ↔ d ∣ n := by refine ⟨fun hdn ↦ ?_, fun ⟨c, h⟩ ↦ ?_⟩ - · rw [← factorization_prod_pow_eq_self hn, ← factorization_prod_pow_eq_self hd] + · rw [← prod_factorization_pow_eq_self hn, ← prod_factorization_pow_eq_self hd] exact prod_dvd_prod_of_subset_of_dvd (support_mono hdn) fun a _ ↦ pow_dvd_pow a (hdn a) · subst h rw [factorization_mul hd <| right_ne_zero_of_mul hn] @@ -218,21 +221,52 @@ lemma factorization_minFac_ne_zero {n : ℕ} (hn : 1 < n) : /-! ### Equivalence between `ℕ+` and `ℕ →₀ ℕ` with support in the primes. -/ +variable {f : ℕ →₀ ℕ} +-- TODO: Rename to `factorization_prod_pow_eq_self` /-- Any Finsupp `f : ℕ →₀ ℕ` whose support is in the primes is equal to the factorization of the product `∏ (a : ℕ) ∈ f.support, a ^ f a`. -/ -theorem prod_pow_factorization_eq_self {f : ℕ →₀ ℕ} (hf : ∀ p : ℕ, p ∈ f.support → Prime p) : +theorem prod_pow_factorization_eq_self (hf : ∀ p ∈ f.support, Prime p) : (f.prod (· ^ ·)).factorization = f := by rw [Finsupp.prod, factorization_prod (pow_ne_zero _ <| hf · · |>.ne_zero), sum_congr rfl (hf · · |>.factorization_pow)] exact sum_single f +theorem eq_factorization_iff (hn : n ≠ 0) (hf : ∀ p ∈ f.support, Prime p) : + f = n.factorization ↔ f.prod (· ^ ·) = n := by + constructor <;> rintro rfl + exacts [prod_factorization_pow_eq_self hn, prod_pow_factorization_eq_self hf |>.symm] + +theorem factorization_prod_pow_eq_self_of_le_factorization (hf : f ≤ n.factorization) : + (f.prod (· ^ ·)).factorization = f := + prod_pow_factorization_eq_self fun _ hp ↦ prime_of_mem_primeFactors <| support_mono hf hp + +theorem prod_pow_dvd_of_le_factorization (hf : f ≤ n.factorization) : f.prod (· ^ ·) ∣ n := by + rcases eq_or_ne n 0 with (rfl | hn) + · simp + rwa [← factorization_le_iff_dvd ?_ hn, factorization_prod_pow_eq_self_of_le_factorization hf] + refine f.prod_ne_zero_iff.mpr fun _ hp ↦ ?_ + exact pow_ne_zero _ (prime_of_mem_primeFactors <| support_mono hf hp).ne_zero + +theorem dvd_prod_pow_of_factorization_le (hn : n ≠ 0) (hf : n.factorization ≤ f) : + n ∣ f.prod (· ^ ·) := by + rw [← add_tsub_cancel_of_le hf, Finsupp.prod_add_index' (by simp) Nat.pow_add, + prod_factorization_pow_eq_self hn] + apply n.dvd_mul_right + +theorem dvd_iff_exists_le_factorization {d : ℕ} (hd : d ≠ 0) (hn : n ≠ 0) : + d ∣ n ↔ ∃ f ≤ n.factorization, d = f.prod (· ^ ·) := by + rw [← factorization_le_iff_dvd hd hn] + refine ⟨fun h ↦ ⟨_, h, prod_factorization_pow_eq_self hd |>.symm⟩, fun ⟨f, hle, hprod⟩ ↦ ?_⟩ + rwa [hprod, factorization_prod_pow_eq_self_of_le_factorization hle] + /-- The equiv between `ℕ+` and `ℕ →₀ ℕ` with support in the primes. -/ -def factorizationEquiv : ℕ+ ≃ { f : ℕ →₀ ℕ | ∀ p ∈ f.support, Prime p } where +@[simps] +def factorizationEquiv : ℕ+ ≃ { f : ℕ →₀ ℕ // ∀ p ∈ f.support, Prime p } where toFun := fun ⟨n, _⟩ => ⟨n.factorization, fun _ => prime_of_mem_primeFactors⟩ invFun := fun ⟨f, hf⟩ => ⟨f.prod _, prod_pow_pos_of_zero_notMem_support fun H => not_prime_zero (hf 0 H)⟩ - left_inv := fun ⟨_, hx⟩ => Subtype.ext <| factorization_prod_pow_eq_self hx.ne.symm + left_inv := fun ⟨_, hx⟩ => Subtype.ext <| prod_factorization_pow_eq_self hx.ne.symm right_inv := fun ⟨_, hf⟩ => Subtype.ext <| prod_pow_factorization_eq_self hf /-! ### Factorization and coprimes -/ diff --git a/Mathlib/Data/Nat/Factorization/Divisors.lean b/Mathlib/Data/Nat/Factorization/Divisors.lean new file mode 100644 index 00000000000000..5dd2f286092cd0 --- /dev/null +++ b/Mathlib/Data/Nat/Factorization/Divisors.lean @@ -0,0 +1,83 @@ +/- +Copyright (c) 2026 Snir Broshi. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Snir Broshi +-/ +module + +public import Mathlib.Data.Finsupp.Interval +public import Mathlib.Data.Nat.Factorization.Defs +public import Mathlib.NumberTheory.Divisors + +/-! +# Results about divisors and factorizations +-/ + +public section + +open Finsupp + +namespace Nat + +theorem coe_divisors_eq_prod_pow_le_factorization {n : ℕ} (hn : n ≠ 0) : + n.divisors = { f.prod (· ^ ·) | f ≤ n.factorization } := by + refine Set.ext fun k ↦ ⟨fun h ↦ ?_, fun ⟨f, hle, h⟩ ↦ mem_divisors.mpr ⟨?_, hn⟩⟩ + · have hdvd := dvd_of_mem_divisors h + have hk := ne_zero_of_dvd_ne_zero hn hdvd + exact ⟨_, factorization_le_iff_dvd hk hn |>.mpr hdvd, prod_factorization_pow_eq_self hk⟩ + · rw [← h, ← prod_factorization_pow_eq_self hn] + exact prod_dvd_prod_of_subset_of_dvd (support_mono hle) fun p _ ↦ Nat.pow_dvd_pow p <| hle p + +theorem divisors_eq_image_Iic_factorization_prod_pow {n : ℕ} (hn : n ≠ 0) : + n.divisors = (Finset.Iic n.factorization).image (·.prod (· ^ ·)) := by + apply Finset.coe_inj.mp + grind [coe_divisors_eq_prod_pow_le_factorization] + +theorem Iic_factorization_prod_pow_injective (n : ℕ) : + (·.val.prod (· ^ ·) : Finset.Iic n.factorization → _).Injective := by + grind [Function.Injective, factorization_prod_pow_eq_self_of_le_factorization] + +theorem divisors_eq_map_attach_Iic_factorization_prod_pow {n : ℕ} (hn : n ≠ 0) : + n.divisors = (Finset.Iic n.factorization).attach.map + ⟨(·.val.prod (· ^ ·)), Iic_factorization_prod_pow_injective n⟩ := by + rw [Finset.map_eq_image] + change _ = (Finset.Iic n.factorization).attach.image ((·.prod (· ^ ·)) ∘ Subtype.val) + rw [← Finset.image_image, Finset.attach_image_val] + exact divisors_eq_image_Iic_factorization_prod_pow hn + +theorem coe_properDivisors_eq_prod_pow_lt_factorization {n : ℕ} : + n.properDivisors = { f.prod (· ^ ·) | f < n.factorization } := by + by_cases hn : n = 0 + · simp [hn] + refine Set.ext fun k ↦ ⟨fun h ↦ ?_, fun ⟨f, hlt, h⟩ ↦ ?_⟩ + · have ⟨hdvd, hlt⟩ := mem_properDivisors.mp h + have hk := ne_zero_of_dvd_ne_zero hn hdvd + refine ⟨_, ?_, prod_factorization_pow_eq_self hk⟩ + apply lt_of_le_of_ne <| factorization_le_iff_dvd hk hn |>.mpr hdvd + exact mt (Nat.eq_of_factorization_eq' hk hn) hlt.ne + · have : k ∣ n := by + rw [← h, ← prod_factorization_pow_eq_self hn] + apply prod_dvd_prod_of_subset_of_dvd <| support_mono hlt.le + exact fun p _ ↦ Nat.pow_dvd_pow p <| hlt.le p + refine mem_properDivisors.mpr ⟨this, lt_of_le_of_ne (le_of_dvd (Nat.pos_of_ne_zero hn) this) ?_⟩ + suffices k.factorization = f from (this ▸ hlt.ne <| congrArg _ ·) + exact h ▸ factorization_prod_pow_eq_self_of_le_factorization hlt.le + +theorem properDivisors_eq_image_Iio_factorization_prod_pow {n : ℕ} : + n.properDivisors = (Finset.Iio n.factorization).image (·.prod (· ^ ·)) := by + apply Finset.coe_inj.mp + grind [coe_properDivisors_eq_prod_pow_lt_factorization] + +theorem Iio_factorization_prod_pow_injective (n : ℕ) : + (·.val.prod (· ^ ·) : Finset.Iio n.factorization → _).Injective := by + grind [Function.Injective, factorization_prod_pow_eq_self_of_le_factorization] + +theorem properDivisors_eq_map_attach_Iio_factorization_prod_pow {n : ℕ} : + n.properDivisors = (Finset.Iio n.factorization).attach.map + ⟨(·.val.prod (· ^ ·)), Iio_factorization_prod_pow_injective n⟩ := by + rw [Finset.map_eq_image] + change _ = (Finset.Iio n.factorization).attach.image ((·.prod (· ^ ·)) ∘ Subtype.val) + rw [← Finset.image_image, Finset.attach_image_val] + exact properDivisors_eq_image_Iio_factorization_prod_pow + +end Nat diff --git a/Mathlib/Data/Nat/Factorization/LCM.lean b/Mathlib/Data/Nat/Factorization/LCM.lean index 602e28795bf094..3ce1e57a546954 100644 --- a/Mathlib/Data/Nat/Factorization/LCM.lean +++ b/Mathlib/Data/Nat/Factorization/LCM.lean @@ -66,7 +66,7 @@ variable {a b} lemma factorizationLCMLeft_mul_factorizationLCMRight (ha : a ≠ 0) (hb : b ≠ 0) : (factorizationLCMLeft a b) * (factorizationLCMRight a b) = lcm a b := by - rw [← factorization_prod_pow_eq_self (lcm_ne_zero ha hb), factorizationLCMLeft, + rw [← prod_factorization_pow_eq_self (lcm_ne_zero ha hb), factorizationLCMLeft, factorizationLCMRight, ← prod_mul] congr; ext p n; split_ifs <;> simp @@ -77,7 +77,7 @@ lemma factorizationLCMLeft_dvd_left : factorizationLCMLeft a b ∣ a := by · simp only [dvd_zero] rcases eq_or_ne b 0 with rfl | hb · simp [factorizationLCMLeft] - nth_rewrite 2 [← factorization_prod_pow_eq_self ha] + nth_rewrite 2 [← prod_factorization_pow_eq_self ha] rw [prod_of_support_subset (s := (lcm a b).factorization.support)] · apply prod_dvd_prod_of_dvd; rintro p -; dsimp only; split_ifs with le · rw [factorization_lcm ha hb]; apply pow_dvd_pow; exact sup_le le_rfl le @@ -91,7 +91,7 @@ lemma factorizationLCMRight_dvd_right : factorizationLCMRight a b ∣ b := by · simp [factorizationLCMRight] rcases eq_or_ne b 0 with rfl | hb · simp only [dvd_zero] - nth_rewrite 2 [← factorization_prod_pow_eq_self hb] + nth_rewrite 2 [← prod_factorization_pow_eq_self hb] rw [prod_of_support_subset (s := (lcm a b).factorization.support)] · apply Finset.prod_dvd_prod_of_dvd; rintro p -; dsimp only; split_ifs with le · apply one_dvd diff --git a/Mathlib/Data/Nat/Factorization/Root.lean b/Mathlib/Data/Nat/Factorization/Root.lean index ab18a93653fa60..42294f86588833 100644 --- a/Mathlib/Data/Nat/Factorization/Root.lean +++ b/Mathlib/Data/Nat/Factorization/Root.lean @@ -80,9 +80,8 @@ lemma floorRoot_ne_zero : floorRoot n a ≠ 0 ↔ n ≠ 0 ∧ a ≠ 0 := by rw [floorRoot_def] split_ifs with h · obtain rfl | rfl := h <;> simp - refine prod_pow_factorization_eq_self fun p hp ↦ ?_ - have : p.Prime ∧ p ∣ a ∧ ¬a = 0 := by simpa using support_floorDiv_subset hp - exact this.1 + apply a.factorization_prod_pow_eq_self_of_le_factorization + exact le_self_nsmul (by simp) (by lia) |>.trans <| smul_floorDiv_le (by lia) /-- Galois connection between `a ↦ a ^ n : ℕ → ℕ` and `floorRoot n : ℕ → ℕ` where `ℕ` is ordered by divisibility. -/ diff --git a/Mathlib/Data/Nat/Init.lean b/Mathlib/Data/Nat/Init.lean index 06ab147597680f..7a09edfa81c4ad 100644 --- a/Mathlib/Data/Nat/Init.lean +++ b/Mathlib/Data/Nat/Init.lean @@ -6,10 +6,10 @@ Authors: Floris van Doorn, Leonardo de Moura, Jeremy Avigad, Mario Carneiro module public import Batteries.Tactic.Alias +public import Batteries.Util.LibraryNote public import Mathlib.Init public import Mathlib.Data.Int.Notation public import Mathlib.Data.Nat.Notation -public import Mathlib.Tactic.Basic public import Mathlib.Tactic.Lemma public import Mathlib.Tactic.TypeStar diff --git a/Mathlib/Data/Nat/PartENat.lean b/Mathlib/Data/Nat/PartENat.lean index d2c66a6681ef18..0c258fcaa0e841 100644 --- a/Mathlib/Data/Nat/PartENat.lean +++ b/Mathlib/Data/Nat/PartENat.lean @@ -720,11 +720,7 @@ theorem find_dom (h : ∃ n, P n) : (find P).Dom := theorem lt_find (n : ℕ) (h : ∀ m ≤ n, ¬P m) : (n : PartENat) < find P := by rw [coe_lt_iff] intro h₁ - rw [find_get] - have h₂ := @Nat.find_spec P _ h₁ - revert h₂ - contrapose! - exact h _ + simpa theorem lt_find_iff (n : ℕ) : (n : PartENat) < find P ↔ ∀ m ≤ n, ¬P m := by refine ⟨?_, lt_find P n⟩ diff --git a/Mathlib/Data/Nat/Totient.lean b/Mathlib/Data/Nat/Totient.lean index 086964f6fe6937..7a940f0ec32100 100644 --- a/Mathlib/Data/Nat/Totient.lean +++ b/Mathlib/Data/Nat/Totient.lean @@ -300,7 +300,7 @@ theorem totient_mul_prod_primeFactors (n : ℕ) : (φ n * ∏ p ∈ n.primeFactors, p) = n * ∏ p ∈ n.primeFactors, (p - 1) := by by_cases hn : n = 0; · simp [hn] rw [totient_eq_prod_factorization hn] - nth_rw 3 [← factorization_prod_pow_eq_self hn] + nth_rw 3 [← prod_factorization_pow_eq_self hn] simp only [prod_primeFactors_prod_factorization, ← Finsupp.prod_mul] refine Finsupp.prod_congr (M := ℕ) (N := ℕ) fun p hp => ?_ rw [Finsupp.mem_support_iff, ← zero_lt_iff] at hp diff --git a/Mathlib/Data/PFunctor/Multivariate/Basic.lean b/Mathlib/Data/PFunctor/Multivariate/Basic.lean index c9b9781e3dbb3a..76e39bff9afce8 100644 --- a/Mathlib/Data/PFunctor/Multivariate/Basic.lean +++ b/Mathlib/Data/PFunctor/Multivariate/Basic.lean @@ -175,11 +175,7 @@ theorem liftR_iff {α : TypeVec n} (r : ∀ ⦃i⦄, α i → α i → Prop) (x intro i j exact (f i j).property rintro ⟨a, f₀, f₁, xeq, yeq, h⟩ - use ⟨a, fun i j => ⟨(f₀ i j, f₁ i j), h i j⟩⟩ - dsimp; constructor - · rw [xeq] - rfl - rw [yeq]; rfl + exact ⟨⟨a, fun i j => ⟨(f₀ i j, f₁ i j), h i j⟩⟩, xeq.symm, yeq.symm⟩ open Set diff --git a/Mathlib/Data/Prod/Basic.lean b/Mathlib/Data/Prod/Basic.lean index de1e9f8f5e8367..afaeaafe82632a 100644 --- a/Mathlib/Data/Prod/Basic.lean +++ b/Mathlib/Data/Prod/Basic.lean @@ -5,6 +5,7 @@ Authors: Johannes Hölzl -/ module +public import Lean.PrettyPrinter.Delaborator.Builtins public import Mathlib.Logic.Function.Defs public import Mathlib.Logic.Function.Iterate public import Mathlib.Tactic.Inhabit diff --git a/Mathlib/Data/Real/ConjExponents.lean b/Mathlib/Data/Real/ConjExponents.lean index 8ca9a2d1628a3c..06f66035c76433 100644 --- a/Mathlib/Data/Real/ConjExponents.lean +++ b/Mathlib/Data/Real/ConjExponents.lean @@ -108,6 +108,10 @@ theorem one_div_nonneg' : 0 ≤ 1 / r := le_of_lt h.one_div_pos' /-- For `r`, instead of `p` -/ theorem one_div_ne_zero' : 1 / r ≠ 0 := ne_of_gt h.one_div_pos' +/-- useful for introducing all three facts simultaneously within a proof. -/ +@[grind →] +theorem all_pos : 0 < p ∧ 0 < q ∧ 0 < r := ⟨h.pos, h.symm.pos, h.pos'⟩ + lemma inv_eq : r⁻¹ = p⁻¹ + q⁻¹ := h.inv_add_inv_eq_inv.symm lemma one_div_add_one_div : 1 / p + 1 / q = 1 / r := by simpa using h.inv_add_inv_eq_inv lemma one_div_eq : 1 / r = 1 / p + 1 / q := h.one_div_add_one_div.symm @@ -288,6 +292,10 @@ theorem one_div_nonneg' : 0 ≤ 1 / r := le_of_lt h.one_div_pos' /-- For `r`, instead of `p` -/ theorem one_div_ne_zero' : 1 / r ≠ 0 := ne_of_gt h.one_div_pos' +/-- useful for introducing all three facts simultaneously within a proof. -/ +@[grind →] +theorem all_pos : 0 < p ∧ 0 < q ∧ 0 < r := ⟨h.pos, h.symm.pos, h.pos'⟩ + lemma inv_eq : r⁻¹ = p⁻¹ + q⁻¹ := h.inv_add_inv_eq_inv.symm lemma one_div_add_one_div : 1 / p + 1 / q = 1 / r := by exact_mod_cast h.coe.one_div_add_one_div lemma one_div_eq : 1 / r = 1 / p + 1 / q := h.one_div_add_one_div.symm diff --git a/Mathlib/Data/Set/Basic.lean b/Mathlib/Data/Set/Basic.lean index 1a11e7891601fa..4df0e1cfce1949 100644 --- a/Mathlib/Data/Set/Basic.lean +++ b/Mathlib/Data/Set/Basic.lean @@ -296,9 +296,13 @@ theorem subset_iff_notMem : s ⊆ t ↔ ∀ ⦃a⦄, a ∉ t → a ∉ s := by theorem not_subset : ¬s ⊆ t ↔ ∃ a ∈ s, a ∉ t := by simp only [subset_def, not_forall, exists_prop] -theorem not_top_subset : ¬⊤ ⊆ s ↔ ∃ a, a ∉ s := by +theorem not_univ_subset : ¬univ ⊆ s ↔ ∃ a, a ∉ s := by simp [not_subset] +@[deprecated not_univ_subset (since := "2026-03-12")] +theorem not_top_subset : ¬⊤ ⊆ s ↔ ∃ a, a ∉ s := + not_univ_subset + lemma eq_of_forall_subset_iff (h : ∀ u, s ⊆ u ↔ t ⊆ u) : s = t := eq_of_forall_ge_iff h /-! ### Definition of strict subsets `s ⊂ t` and basic properties. -/ @@ -569,6 +573,18 @@ theorem univ_unique [Unique α] : @Set.univ α = {default} := theorem ssubset_univ_iff : s ⊂ univ ↔ s ≠ univ := lt_top_iff_ne_top +theorem ssubset_univ_iff_nonempty_compl : s ⊂ univ ↔ sᶜ.Nonempty := by + rw [ssubset_def, Set.not_univ_subset, Set.nonempty_def] + simp + +alias ⟨_, Nonempty.ssubset_univ⟩ := ssubset_univ_iff_nonempty_compl + +theorem compl_ssubset_univ : sᶜ ⊂ univ ↔ s.Nonempty := by + rw [ssubset_def, Set.not_univ_subset, Set.nonempty_def] + simp + +alias ⟨_, Nonempty.compl_ssubset_univ⟩ := compl_ssubset_univ + instance nontrivial_of_nonempty [Nonempty α] : Nontrivial (Set α) := ⟨⟨∅, univ, empty_ne_univ⟩⟩ diff --git a/Mathlib/Data/Set/Insert.lean b/Mathlib/Data/Set/Insert.lean index 67c7ed78ac51d9..f42ae05cba7e8e 100644 --- a/Mathlib/Data/Set/Insert.lean +++ b/Mathlib/Data/Set/Insert.lean @@ -28,11 +28,9 @@ assert_not_exists HeytingAlgebra open Function -universe u v - namespace Set -variable {α : Type u} {s t : Set α} {a b : α} +variable {α β : Type*} {s t : Set α} {a b : α} /-! ### Lemmas about `insert` @@ -372,6 +370,11 @@ theorem Nonempty.subset_pair_iff_eq (hs : s.Nonempty) : s ⊆ {a, b} ↔ s = {a} ∨ s = {b} ∨ s = {a, b} := by rw [Set.subset_pair_iff_eq, or_iff_right]; exact hs.ne_empty +theorem range_ite_const {p : α → Prop} [DecidablePred p] {x y : β} + (hp : ∃ a, p a) (hn : ∃ a, ¬ p a) : + Set.range (fun a ↦ if p a then x else y) = {x, y} := by + grind + /-! ### Powerset -/ /-- The powerset of a singleton contains only `∅` and the singleton itself. -/ @@ -392,7 +395,7 @@ end /-! ### Decidability instances for sets -/ -variable {α : Type u} (s t : Set α) (a b : α) +variable (s t : Set α) (a b : α) instance decidableSingleton [Decidable (a = b)] : Decidable (a ∈ ({b} : Set α)) := inferInstanceAs (Decidable (a = b)) diff --git a/Mathlib/Data/Setoid/Basic.lean b/Mathlib/Data/Setoid/Basic.lean index 451786c69abc27..88aae9451df30c 100644 --- a/Mathlib/Data/Setoid/Basic.lean +++ b/Mathlib/Data/Setoid/Basic.lean @@ -115,10 +115,9 @@ def prodQuotientEquiv (r : Setoid α) (s : Setoid β) : fun x y hxy ↦ Prod.ext (by simpa [Quotient.eq] using hxy.1) (by simpa [Quotient.eq] using hxy.2) left_inv q := by rcases q with ⟨qa, qb⟩ - exact Quotient.inductionOn₂' qa qb fun _ _ ↦ rfl - right_inv q := by - simp only - refine Quotient.inductionOn' q fun _ ↦ rfl + induction qa, qb using Quotient.inductionOn₂' + rfl + right_inv q := by induction q using Quotient.inductionOn'; rfl /-- A bijection between an indexed product of quotients and the quotient by the product of the equivalence relations. -/ @@ -133,7 +132,7 @@ noncomputable def piQuotientEquiv {ι : Sort*} {α : ι → Sort*} (r : ∀ i, S ext i simp right_inv q := by - refine Quotient.inductionOn' q fun _ ↦ ?_ + induction q using Quotient.inductionOn' simp only [Quotient.liftOn'_mk'', Quotient.eq''] intro i change Setoid.r _ _ diff --git a/Mathlib/Data/String/Lemmas.lean b/Mathlib/Data/String/Lemmas.lean index 15ab763f8f9d58..9b5aa17042fa77 100644 --- a/Mathlib/Data/String/Lemmas.lean +++ b/Mathlib/Data/String/Lemmas.lean @@ -7,7 +7,7 @@ module public import Mathlib.Data.Nat.Notation public import Mathlib.Data.String.Defs -public import Mathlib.Tactic.Basic +public import Mathlib.Tactic.Lemma /-! # Miscellaneous lemmas about strings diff --git a/Mathlib/Dynamics/Ergodic/MeasurePreserving.lean b/Mathlib/Dynamics/Ergodic/MeasurePreserving.lean index 15f695aecba898..50546625b17b4c 100644 --- a/Mathlib/Dynamics/Ergodic/MeasurePreserving.lean +++ b/Mathlib/Dynamics/Ergodic/MeasurePreserving.lean @@ -59,6 +59,12 @@ protected theorem id (μ : Measure α) : MeasurePreserving id μ μ := protected theorem aemeasurable {f : α → β} (hf : MeasurePreserving f μa μb) : AEMeasurable f μa := hf.1.aemeasurable +protected theorem congr {f f' : α → β} (hf : MeasurePreserving f μa μb) (hf' : Measurable f') + (h : f =ᵐ[μa] f') : MeasurePreserving f' μa μb := by + refine ⟨hf', ?_⟩ + rw [Measure.map_congr h.symm] + exact hf.map_eq + @[nontriviality] theorem of_isEmpty [IsEmpty β] (f : α → β) (μa : Measure α) (μb : Measure β) : MeasurePreserving f μa μb := diff --git a/Mathlib/FieldTheory/AbelRuffini.lean b/Mathlib/FieldTheory/AbelRuffini.lean index 889798ce93df86..fee0765af94893 100644 --- a/Mathlib/FieldTheory/AbelRuffini.lean +++ b/Mathlib/FieldTheory/AbelRuffini.lean @@ -5,8 +5,9 @@ Authors: Thomas Browning, Patrick Lutz -/ module -public import Mathlib.GroupTheory.Solvable +public import Mathlib.FieldTheory.AlgebraicClosure public import Mathlib.FieldTheory.PolynomialGaloisGroup +public import Mathlib.GroupTheory.Solvable public import Mathlib.RingTheory.RootsOfUnity.Basic /-! @@ -21,19 +22,15 @@ by radicals, then its minimal polynomial has solvable Galois group. ## Main results -* the Abel-Ruffini Theorem `solvableByRad.isSolvable'` : An irreducible polynomial with a root +* The Abel-Ruffini Theorem `isSolvable_gal_of_irreducible`: An irreducible polynomial with a root that is solvable by radicals has a solvable Galois group. -/ -@[expose] public section - -noncomputable section +public section open Polynomial -section AbelRuffini - -variable {F : Type*} [Field F] {E : Type*} [Field E] [Algebra F E] +variable {F E : Type*} [Field F] [Field E] [Algebra F E] theorem gal_zero_isSolvable : IsSolvable (0 : F[X]).Gal := by infer_instance @@ -193,9 +190,15 @@ theorem gal_X_pow_sub_C_isSolvable (n : ℕ) (x : F) : IsSolvable (X ^ n - C x). end GalXPowSubC -variable (F) +variable (F E) in +/-- The intermediate field of elements solvable by radicals, defined as the smallest subfield which +is closed under `n`-th roots. -/ +def solvableByRad : IntermediateField F E := + sInf {s | ∀ x, ∀ n ≠ 0, x ^ n ∈ s → x ∈ s} +variable (F) in /-- Inductive definition of solvable by radicals -/ +@[deprecated solvableByRad (since := "2026-02-28")] inductive IsSolvableByRad : E → Prop | base (α : F) : IsSolvableByRad (algebraMap F E α) | add (α β : E) : IsSolvableByRad α → IsSolvableByRad β → IsSolvableByRad (α + β) @@ -204,91 +207,70 @@ inductive IsSolvableByRad : E → Prop | inv (α : E) : IsSolvableByRad α → IsSolvableByRad α⁻¹ | rad (α : E) (n : ℕ) (hn : n ≠ 0) : IsSolvableByRad (α ^ n) → IsSolvableByRad α -variable (E) - -/-- The intermediate field of solvable-by-radicals elements -/ -def solvableByRad : IntermediateField F E where - carrier := IsSolvableByRad F - zero_mem' := by - change IsSolvableByRad F 0 - convert IsSolvableByRad.base (E := E) (0 : F); rw [map_zero] - add_mem' := by apply IsSolvableByRad.add - one_mem' := by - change IsSolvableByRad F 1 - convert IsSolvableByRad.base (E := E) (1 : F); rw [map_one] - mul_mem' := by apply IsSolvableByRad.mul - inv_mem' := IsSolvableByRad.inv - algebraMap_mem' := IsSolvableByRad.base - -namespace solvableByRad - -variable {F} {E} {α : E} - -theorem induction (P : solvableByRad F E → Prop) - (base : ∀ α : F, P (algebraMap F (solvableByRad F E) α)) - (add : ∀ α β : solvableByRad F E, P α → P β → P (α + β)) - (neg : ∀ α : solvableByRad F E, P α → P (-α)) - (mul : ∀ α β : solvableByRad F E, P α → P β → P (α * β)) - (inv : ∀ α : solvableByRad F E, P α → P α⁻¹) - (rad : ∀ α : solvableByRad F E, ∀ n : ℕ, n ≠ 0 → P (α ^ n) → P α) (α : solvableByRad F E) : - P α := by - revert α - suffices ∀ α : E, IsSolvableByRad F α → ∃ β : solvableByRad F E, ↑β = α ∧ P β by - intro α - obtain ⟨α₀, hα₀, Pα⟩ := this α (Subtype.mem α) - convert Pα - exact Subtype.ext hα₀.symm - apply IsSolvableByRad.rec - · exact fun α => ⟨algebraMap F (solvableByRad F E) α, rfl, base α⟩ - · intro α β _ _ Pα Pβ - obtain ⟨⟨α₀, hα₀, Pα⟩, β₀, hβ₀, Pβ⟩ := Pα, Pβ - exact ⟨α₀ + β₀, by rw [← hα₀, ← hβ₀]; rfl, add α₀ β₀ Pα Pβ⟩ - · intro α _ Pα - obtain ⟨α₀, hα₀, Pα⟩ := Pα - exact ⟨-α₀, by rw [← hα₀]; rfl, neg α₀ Pα⟩ - · intro α β _ _ Pα Pβ - obtain ⟨⟨α₀, hα₀, Pα⟩, β₀, hβ₀, Pβ⟩ := Pα, Pβ - exact ⟨α₀ * β₀, by rw [← hα₀, ← hβ₀]; rfl, mul α₀ β₀ Pα Pβ⟩ - · intro α _ Pα - obtain ⟨α₀, hα₀, Pα⟩ := Pα - exact ⟨α₀⁻¹, by rw [← hα₀]; rfl, inv α₀ Pα⟩ - · intro α n hn hα Pα - obtain ⟨α₀, hα₀, Pα⟩ := Pα - refine ⟨⟨α, IsSolvableByRad.rad α n hn hα⟩, rfl, rad _ n hn ?_⟩ - convert Pα - exact Subtype.ext (Eq.trans ((solvableByRad F E).coe_pow _ n) hα₀.symm) - -theorem isIntegral (α : solvableByRad F E) : IsIntegral F α := by - revert α - apply solvableByRad.induction - · exact fun _ => isIntegral_algebraMap - · exact fun _ _ => IsIntegral.add - · exact fun _ => IsIntegral.neg - · exact fun _ _ => IsIntegral.mul - · intro α hα - exact IsIntegral.inv hα - · intro α n hn hα - obtain ⟨p, h1, h2⟩ := hα.isAlgebraic - refine IsAlgebraic.isIntegral ⟨p.comp (X ^ n), - ⟨fun h => h1 (leadingCoeff_eq_zero.mp ?_), by rw [aeval_comp, aeval_X_pow, h2]⟩⟩ - rwa [← leadingCoeff_eq_zero, leadingCoeff_comp, leadingCoeff_X_pow, one_pow, mul_one] at h +theorem solvableByRad_le {s : IntermediateField F E} (H : ∀ x, ∀ n ≠ 0, x ^ n ∈ s → x ∈ s) : + solvableByRad F E ≤ s := + sInf_le H + +theorem solvableByRad.rad_mem {x : E} {n : ℕ} (hn : n ≠ 0) (hx : x ^ n ∈ solvableByRad F E) : + x ∈ solvableByRad F E := by + grind [solvableByRad] + +variable (F E) in +theorem solvableByRad_le_algClosure : solvableByRad F E ≤ algebraicClosure F E := by + refine solvableByRad_le fun x n hn hx ↦ ?_ + rw [mem_algebraicClosure_iff] at hx ⊢ + obtain ⟨p, h1, h2⟩ := hx + refine ⟨p.comp (X ^ n), ⟨fun h ↦ h1 (leadingCoeff_eq_zero.mp ?_), ?_⟩⟩ + · rwa [← leadingCoeff_eq_zero, leadingCoeff_comp, leadingCoeff_X_pow, one_pow, mul_one] at h rwa [natDegree_X_pow] - -/-- The statement to be proved inductively -/ -def P (α : solvableByRad F E) : Prop := - IsSolvable (minpoly F α).Gal - -/-- An auxiliary induction lemma, which is generalized by `solvableByRad.isSolvable`. -/ -theorem induction3 {α : solvableByRad F E} {n : ℕ} (hn : n ≠ 0) (hα : P (α ^ n)) : P α := by - let p := minpoly F (α ^ n) + · simpa [aeval_comp] + +theorem isAlgebraic_solvableByRad : (solvableByRad F E).IsAlgebraic := + fun _ hx ↦ mem_algebraicClosure_iff.1 (solvableByRad_le_algClosure _ _ hx) + +theorem isIntegral_of_mem_solvableByRad {x : E} (hx : x ∈ solvableByRad F E) : IsIntegral F x := + (isAlgebraic_solvableByRad _ hx).isIntegral + +@[deprecated (since := "2026-02-28")] +alias solvableByRad.isIntegral := isIntegral_of_mem_solvableByRad + +/-- An induction principle for `solvableByRad`. -/ +@[elab_as_elim] +protected theorem solvableByRad.induction (motive : ∀ x, x ∈ solvableByRad F E → Prop) + (mem : ∀ x, motive (algebraMap F E x) (algebraMap_mem _ _)) + (add : ∀ x y (hx : x ∈ solvableByRad F E) (hy : y ∈ solvableByRad F E), + motive x hx → motive y hy → motive (x + y) (add_mem hx hy)) + (mul : ∀ x y (hx : x ∈ solvableByRad F E) (hy : y ∈ solvableByRad F E), + motive x hx → motive y hy → motive (x * y) (mul_mem hx hy)) + (rad : ∀ n x (hn : n ≠ 0) (hx : x ^ n ∈ solvableByRad F E), + motive (x ^ n) hx → motive x (rad_mem hn hx)) + {x : E} (hx : x ∈ solvableByRad F E) : motive x hx := by + let s : Subalgebra F E := + { carrier := {x | ∃ hx : x ∈ solvableByRad F E, motive x hx} + algebraMap_mem' a := ⟨algebraMap_mem _ a, mem a⟩ + add_mem' := fun ⟨ha, ha'⟩ ⟨hb, hb'⟩ ↦ ⟨add_mem ha hb, add _ _ ha hb ha' hb'⟩ + mul_mem' := fun ⟨ha, ha'⟩ ⟨hb, hb'⟩ ↦ ⟨mul_mem ha hb, mul _ _ ha hb ha' hb'⟩ } + let t : IntermediateField F E := Subalgebra.IsAlgebraic.toIntermediateField (S := s) <| by + rintro x ⟨hx, hx'⟩ + apply isAlgebraic_solvableByRad + exact hx + have ht (x n) (hn : n ≠ 0) : x ^ n ∈ t → x ∈ t := by + rintro ⟨hx, hx'⟩ + exact ⟨rad_mem hn hx, rad _ _ hn hx hx'⟩ + obtain ⟨_, h⟩ := solvableByRad_le (s := t) ht hx + exact h + +private theorem induction_rad {x : E} (hx : x ∈ solvableByRad F E) {n : ℕ} (hn : n ≠ 0) + (hα : IsSolvable (minpoly F (x ^ n)).Gal) : IsSolvable (minpoly F x).Gal := by + let p := minpoly F (x ^ n) have hp : p.comp (X ^ n) ≠ 0 := by intro h rcases comp_eq_zero_iff.mp h with h' | h' - · exact minpoly.ne_zero (isIntegral (α ^ n)) h' + · exact minpoly.ne_zero (isIntegral_of_mem_solvableByRad (pow_mem hx n)) h' · exact hn (by rw [← @natDegree_C F, ← h'.2, natDegree_X_pow]) apply gal_isSolvable_of_splits · exact ⟨(SplittingField.splits (p.comp (X ^ n))).of_dvd (map_ne_zero hp) - ((map_dvd_map' _).mpr (minpoly.dvd F α (by rw [aeval_comp, aeval_X_pow, minpoly.aeval])))⟩ + ((map_dvd_map' _).mpr (minpoly.dvd F x (by rw [aeval_comp, aeval_X_pow, minpoly.aeval])))⟩ · refine gal_isSolvable_tower p (p.comp (X ^ n)) ?_ hα ?_ · exact Gal.splits_in_splittingField_of_comp _ _ (by rwa [natDegree_X_pow]) · obtain ⟨s, hs⟩ := splits_iff_exists_multiset.1 (SplittingField.splits p) @@ -306,62 +288,54 @@ theorem induction3 {α : solvableByRad F E} {n : ℕ} (hn : n ≠ 0) (hα : P ( open IntermediateField -set_option backward.isDefEq.respectTransparency false in -/-- An auxiliary induction lemma, which is generalized by `solvableByRad.isSolvable`. -/ -theorem induction2 {α β γ : solvableByRad F E} (hγ : γ ∈ F⟮α, β⟯) (hα : P α) (hβ : P β) : P γ := by - let p := minpoly F α - let q := minpoly F β +private theorem induction_step {x y z : E} + (hx : x ∈ solvableByRad F E) (hy : y ∈ solvableByRad F E) (hz : z ∈ solvableByRad F E) + (hx' : IsSolvable (minpoly F x).Gal) (hy' : IsSolvable (minpoly F y).Gal) (hz' : z ∈ F⟮x, y⟯) : + IsSolvable (minpoly F z).Gal := by + let p := minpoly F x + let q := minpoly F y have hpq := SplittingField.splits (p * q) - rw [Polynomial.map_mul, splits_mul_iff (map_ne_zero (minpoly.ne_zero (isIntegral α))) - (map_ne_zero (minpoly.ne_zero (isIntegral β)))] at hpq - let f : ↥F⟮α, β⟯ →ₐ[F] (p * q).SplittingField := + rw [Polynomial.map_mul, + splits_mul_iff (map_ne_zero (minpoly.ne_zero (isIntegral_of_mem_solvableByRad hx))) + (map_ne_zero (minpoly.ne_zero (isIntegral_of_mem_solvableByRad hy)))] at hpq + have f : ↥F⟮x, y⟯ →ₐ[F] (p * q).SplittingField := Classical.choice <| nonempty_algHom_adjoin_of_splits <| by - intro x hx - push _ ∈ _ at hx - cases hx with rw [hx] - | inl hx => exact ⟨isIntegral α, hpq.1⟩ - | inr hx => exact ⟨isIntegral β, hpq.2⟩ - have key : minpoly F γ = minpoly F (f ⟨γ, hγ⟩) := by + rintro a (rfl | rfl) + · exact ⟨isIntegral_of_mem_solvableByRad hx, hpq.1⟩ + · exact ⟨isIntegral_of_mem_solvableByRad hy, hpq.2⟩ + have key : minpoly F z = minpoly F (f ⟨z, hz'⟩) := by refine minpoly.eq_of_irreducible_of_monic - (minpoly.irreducible (isIntegral γ)) ?_ (minpoly.monic (isIntegral γ)) + (minpoly.irreducible (isIntegral_of_mem_solvableByRad hz)) ?_ + (minpoly.monic (isIntegral_of_mem_solvableByRad hz)) rw [aeval_algHom_apply, map_eq_zero] - apply (algebraMap (↥F⟮α, β⟯) (solvableByRad F E)).injective - simp only [map_zero, ← aeval_algebraMap_apply] - exact minpoly.aeval F γ - rw [P, key] - refine gal_isSolvable_of_splits ⟨Normal.splits ?_ (f ⟨γ, hγ⟩)⟩ (gal_mul_isSolvable hα hβ) - apply SplittingField.instNormal - -/-- An auxiliary induction lemma, which is generalized by `solvableByRad.isSolvable`. -/ -theorem induction1 {α β : solvableByRad F E} (hβ : β ∈ F⟮α⟯) (hα : P α) : P β := - induction2 (adjoin.mono F _ _ (ge_of_eq (Set.pair_eq_singleton α)) hβ) hα hα - -theorem isSolvable (α : solvableByRad F E) : IsSolvable (minpoly F α).Gal := by - revert α - apply solvableByRad.induction - · exact fun α => by rw [minpoly.eq_X_sub_C (solvableByRad F E)]; exact gal_X_sub_C_isSolvable α - · exact fun α β => induction2 (add_mem (subset_adjoin F _ (Set.mem_insert α _)) - (subset_adjoin F _ (Set.mem_insert_of_mem α (Set.mem_singleton β)))) - · exact fun α => induction1 (neg_mem (mem_adjoin_simple_self F α)) - · exact fun α β => induction2 (mul_mem (subset_adjoin F _ (Set.mem_insert α _)) - (subset_adjoin F _ (Set.mem_insert_of_mem α (Set.mem_singleton β)))) - · exact fun α => induction1 (inv_mem (mem_adjoin_simple_self F α)) - · exact fun α n => induction3 - -set_option backward.isDefEq.respectTransparency false in -/-- **Abel-Ruffini Theorem** (one direction): An irreducible polynomial with an -`IsSolvableByRad` root has solvable Galois group -/ -theorem isSolvable' {α : E} {q : F[X]} (q_irred : Irreducible q) (q_aeval : aeval α q = 0) - (hα : IsSolvableByRad F α) : IsSolvable q.Gal := by - have : _root_.IsSolvable (q * C q.leadingCoeff⁻¹).Gal := by - rw [minpoly.eq_of_irreducible q_irred q_aeval, ← - show minpoly F (⟨α, hα⟩ : solvableByRad F E) = minpoly F α from - (minpoly.algebraMap_eq (RingHom.injective _) _).symm] - exact isSolvable ⟨α, hα⟩ + apply (algebraMap (↥F⟮x, y⟯) E).injective + simp [← aeval_algebraMap_apply] + rw [key] + refine gal_isSolvable_of_splits ⟨Normal.splits ?_ (f ⟨z, hz'⟩)⟩ (gal_mul_isSolvable hx' hy') + infer_instance + +theorem isSolvable_gal_minpoly {x : E} (hx : x ∈ solvableByRad F E) : + IsSolvable (minpoly F x).Gal := by + induction hx using solvableByRad.induction with + | mem y => rw [minpoly.eq_X_sub_C E]; infer_instance + | add y z hy hz hy' hz' => + apply induction_step hy hz (add_mem hy hz) hy' hz' (add_mem ..) <;> apply subset_adjoin <;> simp + | mul y z hy hz hy' hz' => + apply induction_step hy hz (mul_mem hy hz) hy' hz' (mul_mem ..) <;> apply subset_adjoin <;> simp + | rad n y hn hy hy' => exact induction_rad (solvableByRad.rad_mem hn hy) hn hy' + +@[deprecated (since := "2026-02-28")] +alias solvableByRad.isSolvable := isSolvable_gal_minpoly + +/-- **Abel-Ruffini Theorem** (one direction): An irreducible polynomial with a `solvableByRad` root +has a solvable Galois group. -/ +theorem isSolvable_gal_of_irreducible {x : E} (hx : x ∈ solvableByRad F E) {q : F[X]} + (q_irred : Irreducible q) (q_aeval : aeval x q = 0) : IsSolvable q.Gal := by + have : IsSolvable (q * C q.leadingCoeff⁻¹).Gal := by + rw [minpoly.eq_of_irreducible q_irred q_aeval] + exact isSolvable_gal_minpoly hx refine solvable_of_surjective (Gal.restrictDvd_surjective ⟨C q.leadingCoeff⁻¹, rfl⟩ ?_) - rw [mul_ne_zero_iff, Ne, Ne, C_eq_zero, inv_eq_zero] - exact ⟨q_irred.ne_zero, leadingCoeff_ne_zero.mpr q_irred.ne_zero⟩ - -end solvableByRad + aesop -end AbelRuffini +@[deprecated (since := "2026-02-28")] +alias solvableByRad.isSolvable' := isSolvable_gal_of_irreducible diff --git a/Mathlib/FieldTheory/AlgebraicClosure.lean b/Mathlib/FieldTheory/AlgebraicClosure.lean index 2e0d116a5e9eef..d115030664b2ef 100644 --- a/Mathlib/FieldTheory/AlgebraicClosure.lean +++ b/Mathlib/FieldTheory/AlgebraicClosure.lean @@ -115,14 +115,12 @@ instance isIntegralClosure : IsIntegralClosure (algebraicClosure F E) F E := end algebraicClosure -set_option backward.isDefEq.respectTransparency false in protected theorem Transcendental.algebraicClosure {a : E} (ha : Transcendental F a) : Transcendental (algebraicClosure F E) a := ha.extendScalars _ variable (F E K) -set_option backward.isDefEq.respectTransparency false in /-- An intermediate field of `E / F` is contained in the algebraic closure of `F` in `E` if all of its elements are algebraic over `F`. -/ theorem le_algebraicClosure' {L : IntermediateField F E} (hs : ∀ x : L, IsAlgebraic F x) : @@ -135,7 +133,6 @@ if it is algebraic over `F`. -/ theorem le_algebraicClosure (L : IntermediateField F E) [Algebra.IsAlgebraic F L] : L ≤ algebraicClosure F E := le_algebraicClosure' F E (Algebra.IsAlgebraic.isAlgebraic) -set_option backward.isDefEq.respectTransparency false in /-- An intermediate field of `E / F` is contained in the algebraic closure of `F` in `E` if and only if it is algebraic over `F`. -/ theorem le_algebraicClosure_iff (L : IntermediateField F E) : @@ -147,14 +144,12 @@ theorem le_algebraicClosure_iff (L : IntermediateField F E) : namespace algebraicClosure -set_option backward.isDefEq.respectTransparency false in /-- The algebraic closure in `E` of the algebraic closure of `F` in `E` is equal to itself. -/ theorem algebraicClosure_eq_bot : algebraicClosure (algebraicClosure F E) E = ⊥ := bot_unique fun x hx ↦ mem_bot.2 ⟨⟨x, isIntegral_trans x (mem_algebraicClosure_iff'.1 hx)⟩, rfl⟩ -set_option backward.isDefEq.respectTransparency false in /-- The normal closure in `E/F` of the algebraic closure of `F` in `E` is equal to itself. -/ theorem normalClosure_eq_self : normalClosure F (algebraicClosure F E) E = algebraicClosure F E := @@ -184,7 +179,6 @@ theorem IntermediateField.isAlgebraic_adjoin_iff_isAlgebraic {S : Set E} : namespace algebraicClosure -set_option backward.isDefEq.respectTransparency false in /-- If `E` is algebraically closed, then the algebraic closure of `F` in `E` is an absolute algebraic closure of `F`. -/ instance isAlgClosure [IsAlgClosed E] : IsAlgClosure F (algebraicClosure F E) := diff --git a/Mathlib/FieldTheory/AxGrothendieck.lean b/Mathlib/FieldTheory/AxGrothendieck.lean index be0bb7d6a638ac..8e53ea1d5b9e54 100644 --- a/Mathlib/FieldTheory/AxGrothendieck.lean +++ b/Mathlib/FieldTheory/AxGrothendieck.lean @@ -45,7 +45,6 @@ noncomputable section open MvPolynomial Finset -set_option backward.isDefEq.respectTransparency false in /-- Any injective polynomial map over an algebraic extension of a finite field is surjective. -/ theorem ax_grothendieck_of_locally_finite {ι K R : Type*} [Field K] [Finite K] [CommRing R] [Finite ι] [Algebra K R] [alg : Algebra.IsAlgebraic K R] (ps : ι → MvPolynomial ι R) diff --git a/Mathlib/FieldTheory/CardinalEmb.lean b/Mathlib/FieldTheory/CardinalEmb.lean index a952954829d7cb..b4dab978e0f9d2 100644 --- a/Mathlib/FieldTheory/CardinalEmb.lean +++ b/Mathlib/FieldTheory/CardinalEmb.lean @@ -113,7 +113,6 @@ attribute [local instance] noMaxOrder_rank_toType open _root_.Algebra (IsAlgebraic) variable [IsAlgebraic F E] -set_option backward.isDefEq.respectTransparency false in variable (F E) in /-- `leastExt i` is defined to be the smallest `k : ι` that generates a nontrivial extension over (i.e. does not lie in) the subalgebra (= intermediate field) generated by all previous @@ -172,13 +171,11 @@ theorem strictMono_filtration : StrictMono (E⟮<·⟯) := fun i _ h ↦ ⟨adjoin.mono _ _ _ (image_mono <| Iio_subset_Iio h.le), fun incl ↦ (isLeast_leastExt i).1 (incl <| subset_adjoin _ _ ⟨i, h, rfl⟩)⟩ -set_option backward.isDefEq.respectTransparency false in theorem filtration_succ (i : ι) : E⟮ Field.Emb (E⟮ iso.trans (ϕ.trans iso.symm)) fun ϕ => iso.symm.trans (ϕ.trans iso) -set_option backward.isDefEq.respectTransparency false in /-- A galois extension with finite galois group is finite dimensional. The dimension is then equal to the order of the galois group via `IsGalois.card_aut_eq_finrank`. -/ lemma finiteDimensional_of_finite [IsGalois F E] [Finite Gal(E/F)] : FiniteDimensional F E := by @@ -158,13 +155,11 @@ theorem IsGalois.tower_top_of_isGalois [IsGalois F E] : IsGalois K E := variable {F E} -set_option backward.isDefEq.respectTransparency false in -- see Note [lower instance priority] instance (priority := 100) IsGalois.tower_top_intermediateField (K : IntermediateField F E) [IsGalois F E] : IsGalois K E := IsGalois.tower_top_of_isGalois F K E -set_option backward.isDefEq.respectTransparency false in theorem isGalois_iff_isGalois_bot : IsGalois (⊥ : IntermediateField F E) E ↔ IsGalois F E := by constructor · intro h @@ -269,14 +264,12 @@ theorem fixingSubgroup_sup {K L : IntermediateField F E} : exact ⟨fun h ↦ ⟨fixingSubgroup_antitone le_sup_left h, fixingSubgroup_antitone le_sup_right h⟩, by simp [← Subgroup.zpowers_le, ← IntermediateField.le_iff_le]⟩ -set_option backward.isDefEq.respectTransparency false in /-- The fixing subgroup of `K : IntermediateField F E` is isomorphic to `Gal(E/K)`. -/ def fixingSubgroupEquiv : fixingSubgroup K ≃* Gal(E/K) where toFun ϕ := { AlgEquiv.toRingEquiv (ϕ : Gal(E/F)) with commutes' := ϕ.mem } invFun ϕ := ⟨ϕ.restrictScalars _, ϕ.commutes⟩ map_mul' _ _ := by ext; rfl -set_option backward.isDefEq.respectTransparency false in theorem fixingSubgroup_fixedField [FiniteDimensional F E] : fixingSubgroup (fixedField H) = H := by have H_le : H ≤ fixingSubgroup (fixedField H) := (le_iff_le _ _).mp le_rfl classical @@ -317,7 +310,6 @@ end IntermediateField namespace IsGalois -set_option backward.isDefEq.respectTransparency false in /-- See `InfiniteGalois.fixedField_fixingSubgroup` for the infinite case, i.e. without the `[FiniteDimensional F E]` assumption. -/ theorem fixedField_fixingSubgroup [FiniteDimensional F E] [h : IsGalois F E] : @@ -418,7 +410,6 @@ open IntermediateField open scoped Pointwise -set_option backward.isDefEq.respectTransparency false in lemma IntermediateField.restrictNormalHom_ker (E : IntermediateField K L) [Normal K E] : (restrictNormalHom E).ker = E.fixingSubgroup := by simp only [Subgroup.ext_iff, MonoidHom.mem_ker, AlgEquiv.ext_iff, one_apply, Subtype.ext_iff, @@ -428,7 +419,6 @@ namespace IsGalois variable (E : IntermediateField K L) -set_option backward.isDefEq.respectTransparency false in /-- If `H` is a normal Subgroup of `Gal(L / K)`, then `fixedField H` is Galois over `K`. -/ instance of_fixedField_normal_subgroup [IsGalois K L] (H : Subgroup Gal(L/K)) [hn : Subgroup.Normal H] : IsGalois K (fixedField H) where @@ -438,7 +428,6 @@ instance of_fixedField_normal_subgroup [IsGalois K L] rintro σ x ⟨a, ha, rfl⟩ τ exact (symm_apply_eq σ).mp (ha ⟨σ⁻¹ * τ * σ, Subgroup.Normal.conj_mem' hn τ.1 τ.2 σ⟩) -set_option backward.isDefEq.respectTransparency false in /-- If `H` is a normal Subgroup of `Gal(L / K)`, then `Gal(fixedField H / K)` is isomorphic to `Gal(L / K) ⧸ H`. -/ noncomputable def normalAutEquivQuotient [FiniteDimensional K L] [IsGalois K L] @@ -447,7 +436,6 @@ noncomputable def normalAutEquivQuotient [FiniteDimensional K L] [IsGalois K L] QuotientGroup.liftEquiv _ (restrictNormalHom_surjective L) <| (fixingSubgroup_fixedField H).symm.trans (fixedField H).restrictNormalHom_ker.symm -set_option backward.isDefEq.respectTransparency false in lemma normalAutEquivQuotient_apply [FiniteDimensional K L] [IsGalois K L] (H : Subgroup Gal(L/K)) [Subgroup.Normal H] (σ : Gal(L/K)) : normalAutEquivQuotient H σ = (restrictNormalHom (fixedField H)) σ := rfl @@ -498,7 +486,6 @@ theorem of_fixedField_eq_bot [FiniteDimensional F E] rw [← isGalois_iff_isGalois_bot, ← h] classical exact IsGalois.of_fixed_field E (⊤ : Subgroup Gal(E/F)) -set_option backward.isDefEq.respectTransparency false in /-- Let $E / F$ be a finite extension of fields. If $|\text{Aut}(E/F)| = [E : F]$, then $E$ is Galois over $F$. -/ @[stacks 09I1 "'if' part"] @@ -515,7 +502,6 @@ theorem of_card_aut_eq_finrank [FiniteDimensional F E] variable {F} {E} variable {p : F[X]} -set_option backward.isDefEq.respectTransparency false in theorem of_separable_splitting_field_aux [hFE : FiniteDimensional F E] [sp : p.IsSplittingField F E] (hp : p.Separable) (K : Type*) [Field K] [Algebra F K] [Algebra K E] [IsScalarTower F K E] {x : E} (hx : x ∈ p.aroots E) : @@ -546,7 +532,6 @@ theorem of_separable_splitting_field_aux [hFE : FiniteDimensional F E] [sp : p.I · apply sp.splits.of_dvd (Polynomial.map_ne_zero h1) rwa [← f.comp_algebraMap, ← p.map_map, RingHom.algebraMap_toAlgebra, Polynomial.map_dvd_map'] -set_option backward.isDefEq.respectTransparency false in theorem of_separable_splitting_field [sp : p.IsSplittingField F E] (hp : p.Separable) : IsGalois F E := by haveI hFE : FiniteDimensional F E := Polynomial.IsSplittingField.finiteDimensional E p @@ -593,7 +578,6 @@ theorem tfae [FiniteDimensional F E] : List.TFAE [ tfae_have 4 → 1 := fun ⟨h, hp1, _⟩ ↦ of_separable_splitting_field hp1 tfae_finish -set_option backward.isDefEq.respectTransparency false in /-- If `K/F` is a finite Galois extension, then for any extension `L/F`, the extension `KL/L` is also Galois. @@ -621,7 +605,6 @@ section normalClosure variable (k K F : Type*) [Field k] [Field K] [Field F] [Algebra k K] [Algebra k F] [Algebra K F] [IsScalarTower k K F] [IsGalois k F] -set_option backward.isDefEq.respectTransparency false in /-- Let $F / K / k$ be a tower of field extensions. If $F$ is Galois over $k$, then the normal closure of $K$ over $k$ in $F$ is Galois over $k$. -/ @[stacks 0EXM] @@ -658,13 +641,11 @@ noncomputable def restrictRestrictAlgEquivMapHom (F K L E : Type*) [Field F] [Fi variable {F E : Type*} [Field F] [Field E] [Algebra F E] (K L : IntermediateField F E) [Normal F K] -set_option backward.isDefEq.respectTransparency false in @[simp] theorem restrictRestrictAlgEquivMapHom_apply (φ : Gal(E/L)) (x : K) : restrictRestrictAlgEquivMapHom F K L E φ x = φ x := by simp [restrictRestrictAlgEquivMapHom, AlgEquiv.restrictNormalHom_apply] -set_option backward.isDefEq.respectTransparency false in theorem restrictRestrictAlgEquivMapHom_injective (h : K ⊔ L = ⊤) : Function.Injective (restrictRestrictAlgEquivMapHom F K L E) := by refine (injective_iff_map_eq_one _).mpr fun φ hφ ↦ ?_ @@ -672,7 +653,6 @@ theorem restrictRestrictAlgEquivMapHom_injective (h : K ⊔ L = ⊤) : rw [← Subgroup.mem_bot, ← fixingSubgroup_top, ← h, fixingSubgroup_sup] exact ⟨fun x ↦ (hφ ▸ restrictRestrictAlgEquivMapHom_apply K L φ x).symm, φ.commutes⟩ -set_option backward.isDefEq.respectTransparency false in theorem restrictRestrictAlgEquivMapHom_surjective [FiniteDimensional F K] [FiniteDimensional L E] [IsGalois L E] (h : K ⊓ L = ⊥) : Function.Surjective (restrictRestrictAlgEquivMapHom F K L E) := by diff --git a/Mathlib/FieldTheory/Galois/GaloisClosure.lean b/Mathlib/FieldTheory/Galois/GaloisClosure.lean index 7f692e2f2d6360..b08c80a7d8ed8a 100644 --- a/Mathlib/FieldTheory/Galois/GaloisClosure.lean +++ b/Mathlib/FieldTheory/Galois/GaloisClosure.lean @@ -60,13 +60,11 @@ lemma val_injective : Function.Injective (toIntermediateField (k := k) (K := K)) instance (L₁ L₂ : IntermediateField k K) [IsGalois k L₁] [IsGalois k L₂] : IsGalois k ↑(L₁ ⊔ L₂) where -set_option backward.isDefEq.respectTransparency false in instance (L₁ L₂ : IntermediateField k K) [FiniteDimensional k L₁] : FiniteDimensional k ↑(L₁ ⊓ L₂) := .of_injective (IntermediateField.inclusion (E := L₁ ⊓ L₂) (F := L₁) inf_le_left).toLinearMap (IntermediateField.inclusion (E := L₁ ⊓ L₂) (F := L₁) inf_le_left).toRingHom.injective -set_option backward.isDefEq.respectTransparency false in instance (L₁ L₂ : IntermediateField k K) [FiniteDimensional k L₂] : FiniteDimensional k ↑(L₁ ⊓ L₂) := .of_injective (IntermediateField.inclusion (E := L₁ ⊓ L₂) (F := L₂) inf_le_right).toLinearMap @@ -104,7 +102,6 @@ lemma le_iff (L₁ L₂ : FiniteGaloisIntermediateField k K) : L₁ ≤ L₂ ↔ L₁.toIntermediateField ≤ L₂.toIntermediateField := Iff.rfl -set_option backward.isDefEq.respectTransparency false in variable (k) in /-- The minimal (finite) Galois intermediate field containing a finite set `s : Set K` in a Galois extension `K/k` defined as the normal closure of the field obtained by adjoining @@ -151,7 +148,6 @@ theorem adjoin_simple_map_algEquiv [IsGalois k K] (f : Gal(K/k)) (x : K) : adjoin k {f x} = adjoin k {x} := adjoin_simple_map_algHom (f : K →ₐ[k] K) x -set_option backward.isDefEq.respectTransparency false in nonrec lemma mem_fixingSubgroup_iff (α : Gal(K/k)) (L : FiniteGaloisIntermediateField k K) : α ∈ L.fixingSubgroup ↔ α.restrictNormalHom L = 1 := by simp [IntermediateField.fixingSubgroup, mem_fixingSubgroup_iff, AlgEquiv.ext_iff, Subtype.ext_iff, diff --git a/Mathlib/FieldTheory/Galois/Infinite.lean b/Mathlib/FieldTheory/Galois/Infinite.lean index 81eca59c3e99ae..b99c4ab9c0f509 100644 --- a/Mathlib/FieldTheory/Galois/Infinite.lean +++ b/Mathlib/FieldTheory/Galois/Infinite.lean @@ -80,7 +80,6 @@ lemma fixingSubgroup_isClosed (L : IntermediateField k K) [IsGalois k K] : use 1 simp only [SetLike.mem_coe, smul_eq_mul, mul_one, and_true, Subgroup.one_mem] -set_option backward.isDefEq.respectTransparency false in lemma fixedField_fixingSubgroup (L : IntermediateField k K) [IsGalois k K] : IntermediateField.fixedField L.fixingSubgroup = L := by apply le_antisymm @@ -114,7 +113,6 @@ theorem mem_range_algebraMap_iff_fixed [IsGalois k K] (x : K) : x ∈ Set.range (algebraMap k K) ↔ ∀ f : Gal(K/k), f x = x := mem_bot_iff_fixed x -set_option backward.isDefEq.respectTransparency false in open IntermediateField in /-- For a subgroup `H` of `Gal(K/k)`, the fixed field of the image of `H` under the restriction to a normal intermediate field `E` is equal to the fixed field of `H` in `K` intersecting with `E`. -/ @@ -142,7 +140,6 @@ lemma restrict_fixedField (H : Subgroup Gal(K/k)) (L : IntermediateField k K) [N nth_rw 2 [← this] exact (AlgEquiv.restrictNormal_commutes σ L ⟨x, xL⟩).symm -set_option backward.isDefEq.respectTransparency false in open IntermediateField in lemma fixingSubgroup_fixedField (H : ClosedSubgroup Gal(K/k)) [IsGalois k K] : (IntermediateField.fixedField H).fixingSubgroup = H.1 := by @@ -223,7 +220,6 @@ def GaloisCoinsertionIntermediateFieldSubgroup [IsGalois k K] : u_l_le K := le_of_eq (fixedField_fixingSubgroup K) choice_eq _ _ := rfl -set_option backward.isDefEq.respectTransparency false in open IntermediateField in /-- If `H` is a closed normal subgroup of `Gal(K / k)`, then `Gal(fixedField H / k)` is isomorphic to `Gal(K / k) ⧸ H`. -/ @@ -233,7 +229,6 @@ noncomputable def normalAutEquivQuotient [IsGalois k K] QuotientGroup.liftEquiv _ (restrictNormalHom_surjective K) ((fixingSubgroup_fixedField H).symm.trans (fixedField H.1).restrictNormalHom_ker.symm) -set_option backward.isDefEq.respectTransparency false in open IntermediateField in lemma normalAutEquivQuotient_apply [IsGalois k K] (H : ClosedSubgroup Gal(K/k)) [H.Normal] (σ : Gal(K/k)) : @@ -261,7 +256,6 @@ theorem isOpen_iff_finite (L : IntermediateField k K) [IsGalois k K] : let _ : Algebra L L'.1 := RingHom.toAlgebra (IntermediateField.inclusion this) exact FiniteDimensional.left k L L'.1 -set_option backward.isDefEq.respectTransparency false in theorem normal_iff_isGalois (L : IntermediateField k K) [IsGalois k K] : L.fixingSubgroup.Normal ↔ IsGalois k L := by refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ diff --git a/Mathlib/FieldTheory/Galois/IsGaloisGroup.lean b/Mathlib/FieldTheory/Galois/IsGaloisGroup.lean index 084cbadfaf36a7..1037b73efc5046 100644 --- a/Mathlib/FieldTheory/Galois/IsGaloisGroup.lean +++ b/Mathlib/FieldTheory/Galois/IsGaloisGroup.lean @@ -124,13 +124,13 @@ theorem IsGaloisGroup.to_isFractionRing [Finite G] [hGAB : IsGaloisGroup G A B] refine ⟨⟨fun h ↦ ?_⟩, ⟨fun g x y ↦ ?_⟩, ⟨fun x h ↦ ?_⟩⟩ · have := hGAB.faithful exact eq_of_smul_eq_smul fun y ↦ by simpa [← algebraMap.coe_smul'] using h (algebraMap B L y) - · obtain ⟨a, b, hb, rfl⟩ := IsFractionRing.div_surjective (A := A) x - obtain ⟨c, d, hd, rfl⟩ := IsFractionRing.div_surjective (A := B) y + · obtain ⟨a, b, hb, rfl⟩ := IsFractionRing.div_surjective A x + obtain ⟨c, d, hd, rfl⟩ := IsFractionRing.div_surjective B y simp [Algebra.smul_def, smul_mul', smul_div₀', hc, ← algebraMap.coe_smul'] · have := hGAB.isInvariant.isIntegral have : Nontrivial A := (IsFractionRing.nontrivial_iff_nontrivial A K).mpr inferInstance have : Nontrivial B := (IsFractionRing.nontrivial_iff_nontrivial B L).mpr inferInstance - obtain ⟨x, y, hy, rfl⟩ := IsFractionRing.div_surjective (A := B) x + obtain ⟨x, y, hy, rfl⟩ := IsFractionRing.div_surjective B x have hy' : algebraMap B L y ≠ 0 := by simpa using nonZeroDivisors.ne_zero hy obtain ⟨b, a, ha, hb⟩ := (Algebra.IsAlgebraic.isAlgebraic (R := A) y).exists_smul_eq_mul x hy rw [mul_comm, Algebra.smul_def, mul_comm] at hb @@ -152,7 +152,7 @@ theorem IsGaloisGroup.of_isFractionRing [hGKL : IsGaloisGroup G K L] refine ⟨⟨fun h ↦ ?_⟩, ⟨fun g x y ↦ IsFractionRing.injective B L ?_⟩, ⟨fun x h ↦ ?_⟩⟩ · have := hGKL.faithful refine eq_of_smul_eq_smul fun (y : L) ↦ ?_ - obtain ⟨a, b, hb, rfl⟩ := IsFractionRing.div_surjective (A := B) y + obtain ⟨a, b, hb, rfl⟩ := IsFractionRing.div_surjective B y simp only [smul_div₀', ← algebraMap.coe_smul', h] · simp [Algebra.smul_def, algebraMap.coe_smul', ← hc] · obtain ⟨b, hb⟩ := hGKL.isInvariant.isInvariant (algebraMap B L x) @@ -288,7 +288,6 @@ instance subgroup [hGKL : IsGaloisGroup G K L] : commutes := inferInstanceAs <| SMulCommClass H (FixedPoints.subfield H L) L isInvariant := ⟨fun x h ↦ ⟨⟨x, h⟩, rfl⟩⟩ -set_option backward.isDefEq.respectTransparency false in open IntermediateField in theorem fixedPoints_of_isGaloisGroup [hGKL : IsGaloisGroup G K L] [hHFL : IsGaloisGroup H F L] : FixedPoints.intermediateField H = F := by @@ -324,7 +323,6 @@ theorem smul_mem_of_normal (N : Subgroup G) [hN : N.Normal] [hF : IsGaloisGroup obtain ⟨y, hy⟩ := hF.isInvariant.isInvariant (g • x) this simp [← hy] -set_option backward.isDefEq.respectTransparency false in @[simp] theorem finrank_fixedPoints_eq_card_subgroup [IsGaloisGroup G K L] : Module.finrank (FixedPoints.intermediateField H : IntermediateField K L) L = Nat.card H := @@ -338,7 +336,6 @@ instance fixedPoints [Finite G] [FaithfulSMul G L] : IsGaloisGroup G (FixedPoints.subfield G L) L := of_mulEquiv_algEquiv (FixedPoints.toAlgAutMulEquiv _ _) fun _ _ ↦ rfl -set_option backward.isDefEq.respectTransparency false in instance intermediateField [Finite G] [hGKL : IsGaloisGroup G K L] : IsGaloisGroup (fixingSubgroup G (F : Set L)) F L := let e := ((mulEquivAlgEquiv G K L).subgroupMap (fixingSubgroup G (F : Set L))).trans <| @@ -347,7 +344,6 @@ instance intermediateField [Finite G] [hGKL : IsGaloisGroup G K L] : have := hGKL.isGalois .of_mulEquiv_algEquiv e fun _ _ ↦ rfl -set_option backward.isDefEq.respectTransparency false in @[simp] theorem card_fixingSubgroup_eq_finrank [Finite G] [IsGaloisGroup G K L] : Nat.card (fixingSubgroup G (F : Set L)) = Module.finrank F L := @@ -452,7 +448,6 @@ instance : SMul (G ⧸ N) F where lemma coe_quotient_smul (g : G) (x : F) : ((g : G ⧸ N) • x : F) = g • (x : L) := rfl -set_option backward.isDefEq.respectTransparency false in instance : MulSemiringAction (G ⧸ N) F where one_smul _ := Subtype.ext <| by rw [← QuotientGroup.mk_one, coe_quotient_smul, one_smul] smul_zero g := Quotient.inductionOn' g fun g ↦ Subtype.ext <| by simp @@ -462,13 +457,11 @@ instance : MulSemiringAction (G ⧸ N) F where smul_one g := Quotient.inductionOn' g fun g ↦ Subtype.ext <| by simp smul_mul g x y := Quotient.inductionOn' g fun g ↦ Subtype.ext <| by simp [smul_mul'] -set_option backward.isDefEq.respectTransparency false in instance [SMulCommClass G K L] : SMulCommClass (G ⧸ N) K F := ⟨fun g k x ↦ Quotient.inductionOn' g fun g ↦ Subtype.ext <| by simp [smul_comm]⟩ variable [hK : IsGaloisGroup G K L] [Finite G] -set_option backward.isDefEq.respectTransparency false in instance quotient : IsGaloisGroup (G ⧸ N) K F where faithful.eq_of_smul_eq_smul := fun {g₁} {g₂} ↦ Quotient.inductionOn₂' g₁ g₂ fun g₁ g₂ h ↦ by rw [QuotientGroup.eq, ← fixingSubgroup_fixedPoints G K L N, subgroup_iff.mp hF, @@ -486,7 +479,6 @@ instance quotient : IsGaloisGroup (G ⧸ N) K F where variable (E : IntermediateField K L) (H : Subgroup G) [hE : IsGaloisGroup H E L] -set_option backward.isDefEq.respectTransparency false in theorem quotientMap (h : E ≤ F) : letI : Algebra E F := (IntermediateField.inclusion h).toAlgebra IsGaloisGroup (H.map (QuotientGroup.mk' N)) E F := diff --git a/Mathlib/FieldTheory/Galois/Profinite.lean b/Mathlib/FieldTheory/Galois/Profinite.lean index 9cd3329a9fdbc6..d405236a25bc43 100644 --- a/Mathlib/FieldTheory/Galois/Profinite.lean +++ b/Mathlib/FieldTheory/Galois/Profinite.lean @@ -61,7 +61,6 @@ variable {k K : Type*} [Field k] [Field K] [Algebra k K] section Profinite -set_option backward.isDefEq.respectTransparency false in /-- The (finite) Galois group `Gal(L / k)` associated to a `L : FiniteGaloisIntermediateField k K` `L`. -/ def FiniteGaloisIntermediateField.finGaloisGroup (L : FiniteGaloisIntermediateField k K) : @@ -69,7 +68,6 @@ def FiniteGaloisIntermediateField.finGaloisGroup (L : FiniteGaloisIntermediateFi letI := AlgEquiv.fintype k L FiniteGrp.of Gal(L/k) -set_option backward.isDefEq.respectTransparency false in /-- For `FiniteGaloisIntermediateField` s `L₁` and `L₂` with `L₂ ≤ L₁` the restriction homomorphism from `Gal(L₁/k)` to `Gal(L₂/k)` -/ noncomputable def finGaloisGroupMap {L₁ L₂ : (FiniteGaloisIntermediateField k K)ᵒᵖ} @@ -86,7 +84,6 @@ lemma map_id (L : (FiniteGaloisIntermediateField k K)ᵒᵖ) : (finGaloisGroupMap (𝟙 L)) = 𝟙 L.unop.finGaloisGroup := ConcreteCategory.ext (AlgEquiv.restrictNormalHom_id _ _) -set_option backward.isDefEq.respectTransparency false in @[simp] lemma map_comp {L₁ L₂ L₃ : (FiniteGaloisIntermediateField k K)ᵒᵖ} (f : L₁ ⟶ L₂) (g : L₂ ⟶ L₃) : finGaloisGroupMap (f ≫ g) = finGaloisGroupMap f ≫ finGaloisGroupMap g := by @@ -127,7 +124,6 @@ noncomputable abbrev asProfiniteGaloisGroupFunctor : (FiniteGaloisIntermediateField k K)ᵒᵖ ⥤ ProfiniteGrp := (finGaloisGroupFunctor k K) ⋙ forget₂ FiniteGrp ProfiniteGrp -set_option backward.isDefEq.respectTransparency false in variable (k K) in /-- The homomorphism from `Gal(K/k)` to `lim Gal(L/k)` where `L` is a @@ -149,7 +145,6 @@ noncomputable def algEquivToLimit : Gal(K/k) →* limit (asProfiniteGaloisGroupF simp only [map_mul] rfl -set_option backward.isDefEq.respectTransparency false in theorem restrictNormalHom_continuous (L : IntermediateField k K) [Normal k L] : Continuous (AlgEquiv.restrictNormalHom (F := k) (K₁ := K) L) := by apply continuous_of_continuousAt_one _ (continuousAt_def.mpr _) @@ -189,7 +184,6 @@ lemma finGaloisGroupFunctor_map_proj_eq_proj (g : limit (asProfiniteGaloisGroupF (finGaloisGroupFunctor k K).map h.op (proj L₂ g) = proj L₁ g := g.prop h.op -set_option backward.isDefEq.respectTransparency false in lemma proj_of_le (L : FiniteGaloisIntermediateField k K) (g : limit (asProfiniteGaloisGroupFunctor k K)) (x : L) (L' : FiniteGaloisIntermediateField k K) (h : L ≤ L') : @@ -231,7 +225,6 @@ lemma mk_toAlgEquivAux [IsGalois k K] (g : limit (asProfiniteGaloisGroupFunctor (⟨toAlgEquivAux g x, hx'⟩ : L.toIntermediateField) = proj L g ⟨x, hx⟩ := by rw [Subtype.ext_iff, Subtype.coe_mk, toAlgEquivAux_eq_proj_of_mem] -set_option backward.isDefEq.respectTransparency false in set_option backward.privateInPublic true in set_option backward.privateInPublic.warn false in lemma toAlgEquivAux_eq_liftNormal [IsGalois k K] (g : limit (asProfiniteGaloisGroupFunctor k K)) @@ -276,7 +269,6 @@ noncomputable def limitToAlgEquiv [IsGalois k K] commutes' x := by simp only [toAlgEquivAux_eq_liftNormal g _ ⊥ (algebraMap_mem _ x), AlgEquiv.commutes] -set_option backward.isDefEq.respectTransparency false in variable (k K) in /-- `algEquivToLimit` as a `MulEquiv`. -/ noncomputable def mulEquivToLimit [IsGalois k K] : diff --git a/Mathlib/FieldTheory/IntermediateField/Adjoin/Algebra.lean b/Mathlib/FieldTheory/IntermediateField/Adjoin/Algebra.lean index 5c2c5f7ca82f09..71e3c13d768536 100644 --- a/Mathlib/FieldTheory/IntermediateField/Adjoin/Algebra.lean +++ b/Mathlib/FieldTheory/IntermediateField/Adjoin/Algebra.lean @@ -55,12 +55,10 @@ scoped instance (X) [MulAction E X] : IsScalarTower (Algebra.adjoin F S) (adjoin scoped instance : FaithfulSMul (Algebra.adjoin F S) (adjoin F S) := Subalgebra.inclusion.faithfulSMul (algebra_adjoin_le_adjoin F S) -set_option backward.isDefEq.respectTransparency false in scoped instance : IsFractionRing (Algebra.adjoin F S) (adjoin F S) := .of_field _ _ fun ⟨_, h⟩ ↦ have ⟨x, hx, y, hy, eq⟩ := mem_adjoin_iff_div.mp h ⟨⟨x, hx⟩, ⟨y, hy⟩, Subtype.ext eq⟩ -set_option backward.isDefEq.respectTransparency false in scoped instance : Algebra.IsAlgebraic (Algebra.adjoin F S) (adjoin F S) := IsLocalization.isAlgebraic _ (nonZeroDivisors (Algebra.adjoin F S)) @@ -90,7 +88,6 @@ section FG variable {F} -set_option backward.isDefEq.respectTransparency false in open scoped algebraAdjoinAdjoin in lemma fg_top_iff : (⊤ : IntermediateField F E).FG ↔ Algebra.EssFiniteType F E := by @@ -133,7 +130,6 @@ section AdjoinSimple variable (α : E) -set_option backward.isDefEq.respectTransparency false in @[simp] theorem AdjoinSimple.isIntegral_gen : IsIntegral F (AdjoinSimple.gen F α) ↔ IsIntegral F α := by conv_rhs => rw [← AdjoinSimple.algebraMap_gen F α] @@ -210,7 +206,6 @@ noncomputable def RingHom.adjoinAlgebraMapOfAlgebra : noncomputable instance : Algebra (Algebra.adjoin A {b}) A⟮(algebraMap B C) b⟯ := RingHom.toAlgebra (RingHom.adjoinAlgebraMapOfAlgebra _) -set_option backward.isDefEq.respectTransparency false in instance : IsScalarTower (Algebra.adjoin A {b}) A⟮(algebraMap B C) b⟯ C := IsScalarTower.of_algebraMap_eq' rfl @@ -223,7 +218,6 @@ variable {K L : Type*} [Field K] [Field L] [Algebra K L] (E1 E2 : IntermediateFi theorem le_sup_toSubalgebra : E1.toSubalgebra ⊔ E2.toSubalgebra ≤ (E1 ⊔ E2).toSubalgebra := sup_le (show E1 ≤ E1 ⊔ E2 from le_sup_left) (show E2 ≤ E1 ⊔ E2 from le_sup_right) -set_option backward.isDefEq.respectTransparency false in theorem sup_toSubalgebra_of_isAlgebraic_right [Algebra.IsAlgebraic K E2] : (E1 ⊔ E2).toSubalgebra = E1.toSubalgebra ⊔ E2.toSubalgebra := by have : (adjoin E1 (E2 : Set L)).toSubalgebra = _ := adjoin_toSubalgebra_of_isAlgebraic fun x h ↦ @@ -249,12 +243,10 @@ theorem sup_toSubalgebra_of_isAlgebraic halg.elim (fun _ ↦ sup_toSubalgebra_of_isAlgebraic_left E1 E2) (fun _ ↦ sup_toSubalgebra_of_isAlgebraic_right E1 E2) -set_option backward.isDefEq.respectTransparency false in theorem sup_toSubalgebra_of_left [FiniteDimensional K E1] : (E1 ⊔ E2).toSubalgebra = E1.toSubalgebra ⊔ E2.toSubalgebra := sup_toSubalgebra_of_isAlgebraic_left E1 E2 -set_option backward.isDefEq.respectTransparency false in theorem sup_toSubalgebra_of_right [FiniteDimensional K E2] : (E1 ⊔ E2).toSubalgebra = E1.toSubalgebra ⊔ E2.toSubalgebra := sup_toSubalgebra_of_isAlgebraic_right E1 E2 @@ -266,7 +258,6 @@ section Tower variable (E) variable {K : Type*} [Field K] [Algebra F K] [Algebra E K] [IsScalarTower F E K] -set_option backward.isDefEq.respectTransparency false in /-- If `K / E / F` is a field extension tower, `L` is an intermediate field of `K / F`, such that either `E / F` or `L / F` is algebraic, then `E(L) = E[L]`. -/ theorem adjoin_intermediateField_toSubalgebra_of_isAlgebraic (L : IntermediateField F K) @@ -317,7 +308,6 @@ theorem fg_of_fg_toSubalgebra (S : IntermediateField F E) (h : S.toSubalgebra.FG theorem fg_of_noetherian (S : IntermediateField F E) [IsNoetherian F E] : S.FG := S.fg_of_fg_toSubalgebra S.toSubalgebra.fg_of_noetherian -set_option backward.isDefEq.respectTransparency false in theorem induction_on_adjoin [FiniteDimensional F E] (P : IntermediateField F E → Prop) (base : P ⊥) (ih : ∀ (K : IntermediateField F E) (x : E), P K → P (K⟮x⟯.restrictScalars F)) (K : IntermediateField F E) : P K := diff --git a/Mathlib/FieldTheory/IntermediateField/Adjoin/Basic.lean b/Mathlib/FieldTheory/IntermediateField/Adjoin/Basic.lean index 297724562adae6..af39f0abcd1b04 100644 --- a/Mathlib/FieldTheory/IntermediateField/Adjoin/Basic.lean +++ b/Mathlib/FieldTheory/IntermediateField/Adjoin/Basic.lean @@ -75,7 +75,6 @@ section Supremum variable {K L : Type*} [Field K] [Field L] [Algebra K L] (E1 E2 : IntermediateField K L) -set_option backward.isDefEq.respectTransparency false in instance finiteDimensional_sup [FiniteDimensional K E1] [FiniteDimensional K E2] : FiniteDimensional K (E1 ⊔ E2 : IntermediateField K L) := by let g := Algebra.TensorProduct.productMap E1.val E2.val @@ -152,7 +151,6 @@ theorem finiteDimensional_iSup_of_finset' have := Subtype.forall'.mp h iSup_subtype'' s t ▸ IntermediateField.finiteDimensional_iSup_of_finite -set_option backward.isDefEq.respectTransparency false in /-- A compositum of splitting fields is a splitting field -/ theorem isSplittingField_iSup {p : ι → K[X]} {s : Finset ι} (h0 : ∏ i ∈ s, p i ≠ 0) (h : ∀ i ∈ s, (p i).IsSplittingField K (t i)) : @@ -172,7 +170,6 @@ section Tower variable (E) variable {K : Type*} [Field K] [Algebra F K] [Algebra E K] [IsScalarTower F E K] -set_option backward.isDefEq.respectTransparency false in /-- If `K / E / F` is a field extension tower, `L` is an intermediate field of `K / F`, such that either `E / F` or `L / F` is algebraic, then `[E(L) : E] ≤ [L : F]`. A corollary of `Subalgebra.adjoin_rank_le` since in this case `E(L) = E[L]`. -/ @@ -287,18 +284,18 @@ protected theorem rank_bot : Module.rank F (⊥ : IntermediateField F E) = 1 := protected theorem finrank_bot : finrank F (⊥ : IntermediateField F E) = 1 := by rw [finrank_eq_one_iff] -set_option backward.isDefEq.respectTransparency false in @[simp] theorem rank_bot' : Module.rank (⊥ : IntermediateField F E) E = Module.rank F E := by rw [← rank_mul_rank F (⊥ : IntermediateField F E) E, IntermediateField.rank_bot, one_mul] -@[simp] theorem finrank_bot' : finrank (⊥ : IntermediateField F E) E = finrank F E := +@[simp, nolint simpNF] -- `simpNF` hits a (deterministic) timeout at `typeclass` +theorem finrank_bot' : finrank (⊥ : IntermediateField F E) E = finrank F E := congr(Cardinal.toNat $(rank_bot')) -set_option backward.isDefEq.respectTransparency false in @[simp] protected theorem rank_top : Module.rank (⊤ : IntermediateField F E) E = 1 := Subalgebra.bot_eq_top_iff_rank_eq_one.mp <| top_le_iff.mp fun x _ ↦ ⟨⟨x, trivial⟩, rfl⟩ -@[simp] protected theorem finrank_top : finrank (⊤ : IntermediateField F E) E = 1 := +@[simp, nolint simpNF] -- `simpNF` hits a (deterministic) timeout at `typeclass` +protected theorem finrank_top : finrank (⊤ : IntermediateField F E) E = 1 := rank_eq_one_iff_finrank_eq_one.mp IntermediateField.rank_top @[simp] theorem rank_top' : Module.rank F (⊤ : IntermediateField F E) = Module.rank F E := @@ -307,7 +304,6 @@ set_option backward.isDefEq.respectTransparency false in @[simp] theorem finrank_top' : finrank F (⊤ : IntermediateField F E) = finrank F E := finrank_top F E -set_option backward.isDefEq.respectTransparency false in lemma finrank_eq_one_iff_eq_top {K : IntermediateField F E} : Module.finrank K E = 1 ↔ K = ⊤ := by refine ⟨?_, (· ▸ IntermediateField.finrank_top)⟩ @@ -385,19 +381,16 @@ universe u variable (F : Type*) [Field F] {E : Type*} [Field E] [Algebra F E] {α : E} variable {K : Type u} [Field K] [Algebra F K] -set_option backward.isDefEq.respectTransparency false in theorem minpoly_gen (α : E) : minpoly F (AdjoinSimple.gen F α) = minpoly F α := by rw [← minpoly.algebraMap_eq (algebraMap F⟮α⟯ E).injective, AdjoinSimple.algebraMap_gen] -set_option backward.isDefEq.respectTransparency false in theorem aeval_gen_minpoly (α : E) : aeval (AdjoinSimple.gen F α) (minpoly F α) = 0 := by ext convert minpoly.aeval F α conv in aeval α => rw [← AdjoinSimple.algebraMap_gen F α] exact (aeval_algebraMap_apply E (AdjoinSimple.gen F α) _).symm -set_option backward.isDefEq.respectTransparency false in /-- algebra isomorphism between `AdjoinRoot` and `F⟮α⟯` -/ @[stacks 09G1 "Algebraic case"] noncomputable def adjoinRootEquivAdjoin (h : IsIntegral F α) : @@ -467,11 +460,9 @@ noncomputable def adjoin.powerBasis {x : L} (hx : IsIntegral K x) : PowerBasis K theorem adjoin.finiteDimensional {x : L} (hx : IsIntegral K x) : FiniteDimensional K K⟮x⟯ := (adjoin.powerBasis hx).finite -set_option backward.isDefEq.respectTransparency false in theorem isAlgebraic_adjoin_simple {x : L} (hx : IsIntegral K x) : Algebra.IsAlgebraic K K⟮x⟯ := have := adjoin.finiteDimensional hx; Algebra.IsAlgebraic.of_finite K K⟮x⟯ -set_option backward.isDefEq.respectTransparency false in /-- If `x` is an algebraic element of field `K`, then its minimal polynomial has degree `[K(x) : K]`. -/ @[stacks 09GN] @@ -488,7 +479,6 @@ theorem adjoin_eq_top_of_adjoin_eq_top [Algebra E K] [IsScalarTower F E K] rw [restrictScalars_top, ← top_le_iff, ← hprim, adjoin_le_iff, coe_restrictScalars, ← adjoin_le_iff] -set_option backward.isDefEq.respectTransparency false in /-- If `E / F` is a finite extension such that `E = F(α)`, then for any intermediate field `K`, the `F` adjoin the coefficients of `minpoly K α` is equal to `K` itself. -/ theorem adjoin_minpoly_coeff_of_exists_primitive_element @@ -521,7 +511,6 @@ theorem adjoin_minpoly_coeff_of_exists_primitive_element instance : Module.Finite F (⊥ : IntermediateField F E) := Subalgebra.finite_bot -set_option backward.isDefEq.respectTransparency false in variable {F} in /-- If `E / F` is an infinite algebraic extension, then there exists an intermediate field `L / F` with arbitrarily large finite extension degree. -/ @@ -552,7 +541,6 @@ theorem _root_.minpoly.degree_le (x : L) [FiniteDimensional K L] : (minpoly K x).degree ≤ finrank K L := degree_le_of_natDegree_le (minpoly.natDegree_le x) -set_option backward.isDefEq.respectTransparency false in /-- If `x : L` is an integral element in a field extension `L` over `K`, then the degree of the minimal polynomial of `x` over `K` divides `[L : K]`. -/ theorem _root_.minpoly.degree_dvd {x : L} (hx : IsIntegral K x) : @@ -561,7 +549,6 @@ theorem _root_.minpoly.degree_dvd {x : L} (hx : IsIntegral K x) : use finrank K⟮x⟯ L rw [mul_comm, finrank_mul_finrank] -set_option backward.isDefEq.respectTransparency false in -- TODO: generalize to `Sort` /-- A compositum of algebraic extensions is algebraic -/ theorem isAlgebraic_iSup {ι : Type*} {t : ι → IntermediateField K L} diff --git a/Mathlib/FieldTheory/IntermediateField/Adjoin/Defs.lean b/Mathlib/FieldTheory/IntermediateField/Adjoin/Defs.lean index 7293bb55a9b592..6af03c45761cd7 100644 --- a/Mathlib/FieldTheory/IntermediateField/Adjoin/Defs.lean +++ b/Mathlib/FieldTheory/IntermediateField/Adjoin/Defs.lean @@ -150,9 +150,12 @@ theorem sup_toSubfield (S T : IntermediateField F E) : exact Set.mem_union_left _ (algebraMap_mem S x) @[simp, norm_cast] -theorem coe_sInf (S : Set (IntermediateField F E)) : (↑(sInf S) : Set E) = - sInf ((fun (x : IntermediateField F E) => (x : Set E)) '' S) := - rfl +theorem coe_sInf (S : Set (IntermediateField F E)) : (↑(sInf S) : Set E) = ⋂ s ∈ S, ↑s := + show sInf ((fun (x : IntermediateField F E) => (x : Set E)) '' S) = ⋂ s ∈ S, ↑s by simp + +@[simp, grind =] +theorem mem_sInf {S : Set (IntermediateField F E)} {x : E} : x ∈ sInf S ↔ ∀ p ∈ S, x ∈ p := by + simpa only [Set.mem_iInter] using Set.ext_iff.1 (coe_sInf S) x @[simp] theorem sInf_toSubalgebra (S : Set (IntermediateField F E)) : @@ -221,7 +224,6 @@ theorem coe_algebraMap_over_bot : IntermediateField.botEquiv F E := rfl -set_option backward.isDefEq.respectTransparency false in instance isScalarTower_over_bot : IsScalarTower (⊥ : IntermediateField F E) F E := IsScalarTower.of_algebraMap_eq (by @@ -239,7 +241,6 @@ def topEquiv : (⊤ : IntermediateField F E) ≃ₐ[F] E := section RestrictScalars -set_option backward.isDefEq.respectTransparency false in @[simp] theorem restrictScalars_bot_eq_self (K : IntermediateField F E) : (⊥ : IntermediateField K E).restrictScalars _ = K := @@ -371,7 +372,6 @@ theorem adjoin_subset_adjoin_iff {F' : Type*} [Field F'] [Algebra F' E] {S S' : (subset_adjoin _ _).trans h⟩, fun ⟨hF, hS⟩ => (Subfield.closure_le (t := (adjoin F' S').toSubfield)).mpr (Set.union_subset hF hS)⟩ -set_option backward.isDefEq.respectTransparency false in /-- Adjoining S and then T is the same as adjoining `S ∪ T`. -/ theorem adjoin_adjoin_left (T : Set E) : (adjoin (adjoin F S) T).restrictScalars _ = adjoin F (S ∪ T) := by @@ -395,7 +395,6 @@ theorem adjoin_insert_adjoin (x : E) : adjoin_le_iff.mpr (subset_adjoin_of_subset_right _ _ (Set.subset_insert _ _))⟩)) (by grw [← subset_adjoin]) -set_option backward.isDefEq.respectTransparency false in /-- `F[S][T] = F[T][S]` -/ theorem adjoin_adjoin_comm (T : Set E) : (adjoin (adjoin F S) T).restrictScalars F = (adjoin (adjoin F T) S).restrictScalars F := by @@ -436,12 +435,10 @@ theorem lift_inf (K : IntermediateField F E) (L L' : IntermediateField F K) : theorem adjoin_self (K : IntermediateField F E) : adjoin F K = K := le_antisymm (adjoin_le_iff.2 fun _ ↦ id) (subset_adjoin F _) -set_option backward.isDefEq.respectTransparency false in theorem restrictScalars_adjoin (K : IntermediateField F E) (S : Set E) : restrictScalars F (adjoin K S) = adjoin F (K ∪ S) := by rw [← adjoin_self _ K, adjoin_adjoin_left, adjoin_self _ K] -set_option backward.isDefEq.respectTransparency false in variable {F} in theorem extendScalars_adjoin {K : IntermediateField F E} {S : Set E} (h : K ≤ adjoin F S) : extendScalars h = adjoin K S := restrictScalars_injective F <| by @@ -452,7 +449,6 @@ theorem extendScalars_adjoin {K : IntermediateField F E} {S : Set E} (h : K ≤ theorem adjoin_union {S T : Set E} : adjoin F (S ∪ T) = adjoin F S ⊔ adjoin F T := gc.l_sup -set_option backward.isDefEq.respectTransparency false in theorem restrictScalars_adjoin_eq_sup (K : IntermediateField F E) (S : Set E) : restrictScalars F (adjoin K S) = K ⊔ adjoin F S := by rw [restrictScalars_adjoin, adjoin_union, adjoin_self] @@ -576,11 +572,9 @@ theorem AdjoinSimple.coe_aeval_gen_apply (f : F[X]) : aeval (AdjoinSimple.gen F α) f = aeval α f := Polynomial.coe_aeval_mk_apply .. -set_option backward.isDefEq.respectTransparency false in theorem adjoin_simple_adjoin_simple (β : E) : F⟮α⟯⟮β⟯.restrictScalars F = F⟮α, β⟯ := adjoin_adjoin_left _ _ _ -set_option backward.isDefEq.respectTransparency false in theorem adjoin_simple_comm (β : E) : F⟮α⟯⟮β⟯.restrictScalars F = F⟮β⟯⟮α⟯.restrictScalars F := adjoin_adjoin_comm _ _ _ @@ -606,7 +600,6 @@ def RingHom.adjoinAlgebraMap : A⟮b⟯ →+* A⟮((algebraMap B C) b)⟯ := instance : Algebra A⟮b⟯ A⟮(algebraMap B C) b⟯ := RingHom.toAlgebra (RingHom.adjoinAlgebraMap _) -set_option backward.isDefEq.respectTransparency false in instance : IsScalarTower A⟮b⟯ A⟮(algebraMap B C) b⟯ C := IsScalarTower.of_algebraMap_eq' (by rfl) @@ -680,7 +673,6 @@ theorem fg_iSup {ι : Sort*} [Finite ι] {S : ι → IntermediateField F E} (h : simp_rw [← hs, ← adjoin_iUnion] exact fg_adjoin_of_finite (Set.finite_iUnion fun _ ↦ Finset.finite_toSet _) -set_option backward.isDefEq.respectTransparency false in theorem induction_on_adjoin_finset (S : Finset E) (P : IntermediateField F E → Prop) (base : P ⊥) (ih : ∀ (K : IntermediateField F E), ∀ x ∈ S, P K → P (K⟮x⟯.restrictScalars F)) : P (adjoin F S) := by @@ -690,7 +682,6 @@ theorem induction_on_adjoin_finset (S : Finset E) (P : IntermediateField F E → · rw [Finset.coe_insert, Set.insert_eq, Set.union_comm, ← adjoin_adjoin_left] exact ih (adjoin F _) _ ha h -set_option backward.isDefEq.respectTransparency false in theorem induction_on_adjoin_fg (P : IntermediateField F E → Prop) (base : P ⊥) (ih : ∀ (K : IntermediateField F E) (x : E), P K → P (K⟮x⟯.restrictScalars F)) (K : IntermediateField F E) (hK : K.FG) : P K := by @@ -758,12 +749,10 @@ namespace IntermediateField variable (F : IntermediateField K L) -set_option backward.isDefEq.respectTransparency false in @[simp] theorem extendScalars_self : extendScalars (le_refl F) = ⊥ := restrictScalars_injective K (by simp) -set_option backward.isDefEq.respectTransparency false in @[simp] theorem extendScalars_top : extendScalars (le_top : F ≤ ⊤) = ⊤ := restrictScalars_injective K (by simp) diff --git a/Mathlib/FieldTheory/IntermediateField/Algebraic.lean b/Mathlib/FieldTheory/IntermediateField/Algebraic.lean index 98b631caa913f6..a6f80e8bd9464c 100644 --- a/Mathlib/FieldTheory/IntermediateField/Algebraic.lean +++ b/Mathlib/FieldTheory/IntermediateField/Algebraic.lean @@ -33,7 +33,6 @@ def Subalgebra.IsAlgebraic.toIntermediateField {S : Subalgebra K L} (hS : S.IsAl inv_mem' x hx := Algebra.adjoin_le_iff.mpr (Set.singleton_subset_iff.mpr hx) (hS x hx).isIntegral.inv_mem_adjoin -set_option backward.isDefEq.respectTransparency false in /-- Turn an algebraic subalgebra into an intermediate field, `Algebra.IsAlgebraic` version. -/ abbrev Algebra.IsAlgebraic.toIntermediateField (S : Subalgebra K L) [Algebra.IsAlgebraic K S] : IntermediateField K L := (S.isAlgebraic_iff.mpr ‹_›).toIntermediateField @@ -43,7 +42,6 @@ namespace IntermediateField instance isAlgebraic_tower_bot [Algebra.IsAlgebraic K L] : Algebra.IsAlgebraic K S := Algebra.IsAlgebraic.of_injective S.val S.val.injective -set_option backward.isDefEq.respectTransparency false in instance isAlgebraic_tower_top [Algebra.IsAlgebraic K L] : Algebra.IsAlgebraic S L := Algebra.IsAlgebraic.tower_top (K := K) S @@ -54,19 +52,16 @@ variable (F E : IntermediateField K L) instance finiteDimensional_left [FiniteDimensional K L] : FiniteDimensional K F := .left K F L instance finiteDimensional_right [FiniteDimensional K L] : FiniteDimensional F L := .right K F L -set_option backward.isDefEq.respectTransparency false in @[simp] theorem rank_eq_rank_subalgebra : Module.rank K F.toSubalgebra = Module.rank K F := rfl -set_option backward.isDefEq.respectTransparency false in @[simp] theorem finrank_eq_finrank_subalgebra : finrank K F.toSubalgebra = finrank K F := rfl variable {F} {E} -set_option backward.isDefEq.respectTransparency false in /-- If `F ≤ E` are two intermediate fields of `L / K` such that `[E : K] ≤ [F : K]` are finite, then `F = E`. -/ theorem eq_of_le_of_finrank_le [hfin : FiniteDimensional K E] (h_le : F ≤ E) @@ -80,7 +75,6 @@ theorem eq_of_le_of_finrank_eq [FiniteDimensional K E] (h_le : F ≤ E) (h_finrank : finrank K F = finrank K E) : F = E := eq_of_le_of_finrank_le h_le h_finrank.ge -set_option backward.isDefEq.respectTransparency false in -- If `F ≤ E` are two intermediate fields of a finite extension `L / K` such that -- `[L : F] ≤ [L : E]`, then `F = E`. Marked as private since it's a direct corollary of -- `eq_of_le_of_finrank_le'` (the `FiniteDimensional K L` implies `FiniteDimensional F L` @@ -93,7 +87,6 @@ private theorem eq_of_le_of_finrank_le'' [FiniteDimensional K L] (h_le : F ≤ E have h3 : 0 < finrank E L := finrank_pos nlinarith -set_option backward.isDefEq.respectTransparency false in /-- If `F ≤ E` are two intermediate fields of `L / K` such that `[L : F] ≤ [L : E]` are finite, then `F = E`. -/ theorem eq_of_le_of_finrank_le' [FiniteDimensional F L] (h_le : F ≤ E) @@ -108,7 +101,6 @@ theorem eq_of_le_of_finrank_eq' [FiniteDimensional F L] (h_le : F ≤ E) (h_finrank : finrank F L = finrank E L) : F = E := eq_of_le_of_finrank_le' h_le h_finrank.le -set_option backward.isDefEq.respectTransparency false in lemma finrank_lt_of_gt [FiniteDimensional F L] (H : F < E) : Module.finrank E L < Module.finrank F L := by letI := (IntermediateField.inclusion H.le).toAlgebra @@ -117,13 +109,11 @@ lemma finrank_lt_of_gt [FiniteDimensional F L] (H : F < E) : · exact Module.finrank_top_le_finrank_of_isScalarTower _ _ _ · exact .symm (mt (eq_of_le_of_finrank_eq' H.le) H.ne) -set_option backward.isDefEq.respectTransparency false in theorem finrank_dvd_of_le_left (h : F ≤ E) : finrank E L ∣ finrank F L := by let _ := (inclusion h).toRingHom.toAlgebra have : IsScalarTower F E L := IsScalarTower.of_algebraMap_eq fun x ↦ rfl exact Dvd.intro_left (finrank F E) (finrank_mul_finrank F E L) -set_option backward.isDefEq.respectTransparency false in theorem finrank_dvd_of_le_right (h : F ≤ E) : finrank K F ∣ finrank K E := by let _ := (inclusion h).toRingHom.toAlgebra exact Dvd.intro (finrank F E) (finrank_mul_finrank K F E) @@ -134,7 +124,6 @@ theorem finrank_le_of_le_left [FiniteDimensional F L] (h : F ≤ E) : finrank E theorem finrank_le_of_le_right [FiniteDimensional K E] (h : F ≤ E) : finrank K F ≤ finrank K E := Nat.le_of_dvd Module.finrank_pos (finrank_dvd_of_le_right h) -set_option backward.isDefEq.respectTransparency false in /-- Mapping a finite-dimensional intermediate field along an algebra equivalence gives a finite-dimensional intermediate field. -/ instance finiteDimensional_map (f : L →ₐ[K] L) [FiniteDimensional K E] : @@ -143,14 +132,12 @@ instance finiteDimensional_map (f : L →ₐ[K] L) [FiniteDimensional K E] : end FiniteDimensional -set_option backward.isDefEq.respectTransparency false in theorem isAlgebraic_iff {x : S} : IsAlgebraic K x ↔ IsAlgebraic K (x : L) := (isAlgebraic_algebraMap_iff (algebraMap S L).injective).symm theorem isIntegral_iff {x : S} : IsIntegral K x ↔ IsIntegral K (x : L) := (isIntegral_algHom_iff S.val S.val.injective).symm -set_option backward.isDefEq.respectTransparency false in theorem minpoly_eq (x : S) : minpoly K x = minpoly K (x : L) := (minpoly.algebraMap_eq (algebraMap S L).injective x).symm diff --git a/Mathlib/FieldTheory/IntermediateField/Basic.lean b/Mathlib/FieldTheory/IntermediateField/Basic.lean index b862d57bf32188..71969b4010082e 100644 --- a/Mathlib/FieldTheory/IntermediateField/Basic.lean +++ b/Mathlib/FieldTheory/IntermediateField/Basic.lean @@ -70,6 +70,7 @@ protected theorem neg_mem {x : L} (hx : x ∈ S) : -x ∈ S := by change -x ∈ S.toSubalgebra; simpa /-- Reinterpret an `IntermediateField` as a `Subfield`. -/ +@[reducible] def toSubfield : Subfield L := { S.toSubalgebra with neg_mem' := S.neg_mem, @@ -116,7 +117,6 @@ theorem mem_mk (s : Subsemiring L) (hK : ∀ x, algebraMap K L x ∈ s) (hi) (x theorem mem_toSubalgebra (s : IntermediateField K L) (x : L) : x ∈ s.toSubalgebra ↔ x ∈ s := Iff.rfl -@[simp] theorem mem_toSubfield (s : IntermediateField K L) (x : L) : x ∈ s.toSubfield ↔ x ∈ s := Iff.rfl @@ -401,7 +401,6 @@ instance [Semiring X] [MulSemiringAction L X] (F : IntermediateField K L) : MulS instance toAlgebra : Algebra S L := inferInstanceAs (Algebra S.toSubalgebra L) -set_option backward.isDefEq.respectTransparency false in instance module' {R} [Semiring R] [SMul R K] [Module R L] [IsScalarTower R K L] : Module R S := inferInstanceAs (Module R S.toSubalgebra) @@ -620,7 +619,6 @@ variable {F E : IntermediateField K L} @[simp] theorem toSubalgebra_inj : F.toSubalgebra = E.toSubalgebra ↔ F = E := toSubalgebra_injective.eq_iff -@[simp] theorem toSubfield_inj : F.toSubfield = E.toSubfield ↔ F = E := toSubfield_injective.eq_iff theorem map_injective (f : L →ₐ[K] L') : Function.Injective (map f) := by @@ -725,7 +723,6 @@ theorem restrictScalars_inj {E E' : IntermediateField L' L} : end RestrictScalars -set_option backward.isDefEq.respectTransparency false in /-- This was formerly an instance called `lift2_alg`, but an instance above already provides it. -/ example {F : IntermediateField K L} {E : IntermediateField F L} : Algebra K E := by infer_instance @@ -803,7 +800,7 @@ variable (F) into an order isomorphism from `{ E : Subfield L // F ≤ E }` to `IntermediateField F L`. Its inverse is `IntermediateField.toSubfield`. -/ -@[simps] +@[simps apply symm_apply] def extendScalars.orderIso : { E : Subfield L // F ≤ E } ≃o IntermediateField F L where toFun E := extendScalars E.2 @@ -822,7 +819,6 @@ namespace IntermediateField variable {F E E' : IntermediateField K L} (h : F ≤ E) (h' : F ≤ E') {x : L} -set_option backward.isDefEq.respectTransparency false in /-- If `F ≤ E` are two intermediate fields of `L / K`, then `E` is also an intermediate field of `L / F`. It can be viewed as an inverse to `IntermediateField.restrictScalars`. -/ def extendScalars : IntermediateField F L := @@ -831,7 +827,6 @@ def extendScalars : IntermediateField F L := @[simp] theorem coe_extendScalars : (extendScalars h : Set L) = (E : Set L) := rfl -set_option backward.isDefEq.respectTransparency false in @[simp] theorem extendScalars_toSubfield : (extendScalars h).toSubfield = E.toSubfield := SetLike.coe_injective rfl @@ -839,23 +834,19 @@ theorem extendScalars_toSubfield : (extendScalars h).toSubfield = E.toSubfield : @[simp] theorem mem_extendScalars : x ∈ extendScalars h ↔ x ∈ E := Iff.rfl -set_option backward.isDefEq.respectTransparency false in @[simp] theorem extendScalars_restrictScalars : (extendScalars h).restrictScalars K = E := rfl theorem extendScalars_le_extendScalars_iff : extendScalars h ≤ extendScalars h' ↔ E ≤ E' := Iff.rfl -set_option backward.isDefEq.respectTransparency false in theorem extendScalars_le_iff (E' : IntermediateField F L) : extendScalars h ≤ E' ↔ E ≤ E'.restrictScalars K := Iff.rfl -set_option backward.isDefEq.respectTransparency false in theorem le_extendScalars_iff (E' : IntermediateField F L) : E' ≤ extendScalars h ↔ E'.restrictScalars K ≤ E := Iff.rfl variable (F) -set_option backward.isDefEq.respectTransparency false in /-- `IntermediateField.extendScalars.orderIso` bundles `IntermediateField.extendScalars` into an order isomorphism from `{ E : IntermediateField K L // F ≤ E }` to `IntermediateField F L`. Its inverse is diff --git a/Mathlib/FieldTheory/IsAlgClosed/AlgebraicClosure.lean b/Mathlib/FieldTheory/IsAlgClosed/AlgebraicClosure.lean index a80a2172b07bb7..fe197b767cf6bd 100644 --- a/Mathlib/FieldTheory/IsAlgClosed/AlgebraicClosure.lean +++ b/Mathlib/FieldTheory/IsAlgClosed/AlgebraicClosure.lean @@ -214,7 +214,6 @@ namespace IntermediateField variable {K L : Type*} [Field K] [Field L] [Algebra K L] (E : IntermediateField K L) -set_option backward.isDefEq.respectTransparency false in instance [Algebra.IsAlgebraic K E] : IsAlgClosure K (AlgebraicClosure E) := ⟨AlgebraicClosure.isAlgClosed E, Algebra.IsAlgebraic.trans K E (AlgebraicClosure E)⟩ diff --git a/Mathlib/FieldTheory/IsAlgClosed/Classification.lean b/Mathlib/FieldTheory/IsAlgClosed/Classification.lean index 8d9cddba46d3c9..f68f24028abb3f 100644 --- a/Mathlib/FieldTheory/IsAlgClosed/Classification.lean +++ b/Mathlib/FieldTheory/IsAlgClosed/Classification.lean @@ -47,7 +47,6 @@ variable {ι : Type*} (v : ι → K) variable {κ : Type*} (w : κ → L) variable (hv : AlgebraicIndependent R v) -set_option backward.isDefEq.respectTransparency false in theorem isAlgClosure_of_transcendence_basis [IsAlgClosed K] (hv : IsTranscendenceBasis R v) : IsAlgClosure (Algebra.adjoin R (Set.range v)) K := letI := RingHom.domain_nontrivial (algebraMap R K) @@ -56,7 +55,6 @@ theorem isAlgClosure_of_transcendence_basis [IsAlgClosed K] (hv : IsTranscendenc variable (hw : AlgebraicIndependent R w) -set_option backward.isDefEq.respectTransparency false in /-- setting `R` to be `ZMod (ringChar R)` this result shows that if two algebraically closed fields have equipotent transcendence bases and the same characteristic then they are isomorphic. -/ @@ -85,7 +83,6 @@ variable {ι : Type w} (v : ι → K) variable {K' : Type u} [Field K'] [Algebra R K'] [IsAlgClosed K'] variable {ι' : Type u} (v' : ι' → K') -set_option backward.isDefEq.respectTransparency false in /-- The cardinality of an algebraically closed `R`-algebra is less than or equal to the maximum of the cardinality of `R`, the cardinality of a transcendence basis and `ℵ₀` diff --git a/Mathlib/FieldTheory/Isaacs.lean b/Mathlib/FieldTheory/Isaacs.lean index 4e50b0ceff0d24..3f214bd9523737 100644 --- a/Mathlib/FieldTheory/Isaacs.lean +++ b/Mathlib/FieldTheory/Isaacs.lean @@ -38,7 +38,6 @@ open Polynomial IntermediateField variable {F E K : Type*} [Field F] [Field E] [Field K] [Algebra F E] [Algebra F K] variable [alg : Algebra.IsAlgebraic F E] -set_option backward.isDefEq.respectTransparency false in theorem nonempty_algHom_of_exists_root (h : ∀ x : E, ∃ y : K, aeval y (minpoly F x) = 0) : Nonempty (E →ₐ[F] K) := by refine Lifts.nonempty_algHom_of_exist_lifts_finset fun S ↦ ⟨⟨adjoin F S, ?_⟩, subset_adjoin _ _⟩ diff --git a/Mathlib/FieldTheory/KrullTopology.lean b/Mathlib/FieldTheory/KrullTopology.lean index fc1f5dc8ee75bd..a353f904b654cc 100644 --- a/Mathlib/FieldTheory/KrullTopology.lean +++ b/Mathlib/FieldTheory/KrullTopology.lean @@ -154,7 +154,6 @@ lemma krullTopology_mem_nhds_one_iff (K L : Type*) [Field K] [Field L] [Algebra · rintro ⟨E, fin, hE⟩ exact ⟨E.fixingSubgroup, ⟨E.fixingSubgroup, ⟨E, fin, rfl⟩, rfl⟩, hE⟩ -set_option backward.isDefEq.respectTransparency false in open scoped Topology in lemma krullTopology_mem_nhds_one_iff_of_normal (K L : Type*) [Field K] [Field L] [Algebra K L] [Normal K L] (s : Set Gal(L/K)) : s ∈ 𝓝 1 ↔ ∃ E : IntermediateField K L, @@ -307,7 +306,6 @@ theorem map_fixingSubgroup_index [Normal k E] [Normal k K] : rw [L.map_fixingSubgroup K, L.fixingSubgroup.index_comap_of_surjective (AlgEquiv.restrictNormalHom_surjective _)] -set_option backward.isDefEq.respectTransparency false in variable {K} in /-- If `K / k` is a Galois extension, `L` is an intermediate field of `K / k`, then `[L : k]` as a natural number is equal to the index of the fixing subgroup of `L`. -/ diff --git a/Mathlib/FieldTheory/LinearDisjoint.lean b/Mathlib/FieldTheory/LinearDisjoint.lean index a179797e7d0059..0f1bfa063dae7e 100644 --- a/Mathlib/FieldTheory/LinearDisjoint.lean +++ b/Mathlib/FieldTheory/LinearDisjoint.lean @@ -163,7 +163,6 @@ theorem linearDisjoint_iff : variable {A B L} -set_option backward.isDefEq.respectTransparency false in /-- Two intermediate fields are linearly disjoint if and only if they are linearly disjoint as subalgebras. -/ theorem linearDisjoint_iff' : @@ -172,12 +171,10 @@ theorem linearDisjoint_iff' : congr! ext; simp -set_option backward.isDefEq.respectTransparency false in /-- Linear disjointness is symmetric. -/ theorem LinearDisjoint.symm (H : A.LinearDisjoint B) : B.LinearDisjoint A := linearDisjoint_iff'.2 (linearDisjoint_iff'.1 H).symm -set_option backward.isDefEq.respectTransparency false in /-- Linear disjointness is symmetric. -/ theorem linearDisjoint_comm : A.LinearDisjoint B ↔ B.LinearDisjoint A := ⟨LinearDisjoint.symm, LinearDisjoint.symm⟩ @@ -201,7 +198,6 @@ end namespace LinearDisjoint -set_option backward.isDefEq.respectTransparency false in /-- Linear disjointness of intermediate fields is preserved by algebra homomorphisms. -/ theorem map (H : A.LinearDisjoint B) {K : Type*} [Field K] [Algebra F K] (f : E →ₐ[F] K) : (A.map f).LinearDisjoint (B.map f) := @@ -234,7 +230,6 @@ theorem map'' {L' : Type*} [Field L'] [Algebra F L'] [Algebra L' E] [IsScalarTow variable (A) in theorem self_right : A.LinearDisjoint F := Subalgebra.LinearDisjoint.bot_right _ -set_option backward.isDefEq.respectTransparency false in variable (A) in theorem bot_right : A.LinearDisjoint (⊥ : IntermediateField F E) := linearDisjoint_iff'.2 (Subalgebra.LinearDisjoint.bot_right _) @@ -243,7 +238,6 @@ variable (F E L) in theorem bot_left : (⊥ : IntermediateField F E).LinearDisjoint L := Subalgebra.LinearDisjoint.bot_left _ -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `L` are linearly disjoint, then any `F`-linearly independent family on `A` remains linearly independent over `L`. -/ theorem linearIndependent_left (H : A.LinearDisjoint L) @@ -260,14 +254,12 @@ theorem of_basis_left {ι : Type*} (a : Basis ι F A) (AlgEquiv.ofInjectiveField (IsScalarTower.toAlgHom F L E)) (AddMonoidHom.id E) (AlgEquiv.surjective _) (by simp) (fun _ _ ↦ by simp_rw [Algebra.smul_def]; rfl) -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are linearly disjoint, then any `F`-linearly independent family on `B` remains linearly independent over `A`. -/ theorem linearIndependent_right (H : A.LinearDisjoint B) {ι : Type*} {b : ι → B} (hb : LinearIndependent F b) : LinearIndependent A (B.val ∘ b) := (linearDisjoint_iff'.1 H).linearIndependent_right_of_flat hb -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are linearly disjoint and such that `A.toSubalgebra ⊔ B.toSubalgebra = ⊤`, then any `F`-basis of `B` is also an `A`-basis of `E`. @@ -280,20 +272,17 @@ noncomputable def basisOfBasisRight (H : A.LinearDisjoint B) Basis ι A E := (linearDisjoint_iff'.mp H).basisOfBasisRight H' b -set_option backward.isDefEq.respectTransparency false in @[simp] theorem basisOfBasisRight_apply (H : A.LinearDisjoint B) (H' : A.toSubalgebra ⊔ B.toSubalgebra = ⊤) {ι : Type*} (b : Basis ι F B) (i : ι) : H.basisOfBasisRight H' b i = algebraMap B E (b i) := (linearDisjoint_iff'.mp H).algebraMap_basisOfBasisRight_apply H' b i -set_option backward.isDefEq.respectTransparency false in theorem algebraMap_basisOfBasisRight_repr_apply (H : A.LinearDisjoint B) (H' : A.toSubalgebra ⊔ B.toSubalgebra = ⊤) {ι : Type*} (b : Basis ι F B) (x : B) (i : ι) : algebraMap A E ((H.basisOfBasisRight H' b).repr x i) = algebraMap F E (b.repr x i) := (linearDisjoint_iff'.mp H).algebraMap_basisOfBasisRight_repr_apply H' b x i -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are linearly disjoint and such that `A.toSubalgebra ⊔ B.toSubalgebra = ⊤`, then any `F`-basis of `A` is also a `B`-basis of `E`. @@ -306,27 +295,23 @@ noncomputable def basisOfBasisLeft (H : A.LinearDisjoint B) Basis ι B E := (linearDisjoint_iff'.mp H).basisOfBasisLeft H' b -set_option backward.isDefEq.respectTransparency false in @[simp] theorem basisOfBasisLeft_apply (H : A.LinearDisjoint B) (H' : A.toSubalgebra ⊔ B.toSubalgebra = ⊤) {ι : Type*} (b : Basis ι F A) (i : ι) : H.basisOfBasisLeft H' b i = algebraMap A E (b i) := (linearDisjoint_iff'.mp H).basisOfBasisLeft_apply H' b i -set_option backward.isDefEq.respectTransparency false in theorem basisOfBasisLeft_repr_apply (H : A.LinearDisjoint B) (H' : A.toSubalgebra ⊔ B.toSubalgebra = ⊤) {ι : Type*} (b : Basis ι F A) (x : A) (i : ι) : algebraMap B E ((H.basisOfBasisLeft H' b).repr x i) = algebraMap F E (b.repr x i) := (linearDisjoint_iff'.mp H).basisOfBasisLeft_repr_apply H' b x i -set_option backward.isDefEq.respectTransparency false in /-- If there exists an `F`-basis of `B` which remains linearly independent over `A`, then `A` and `B` are linearly disjoint. -/ theorem of_basis_right {ι : Type*} (b : Basis ι F B) (H : LinearIndependent A (B.val ∘ b)) : A.LinearDisjoint B := linearDisjoint_iff'.2 (.of_basis_right _ _ b H) -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `L` are linearly disjoint, then any `F`-linearly independent family on `L` remains linearly independent over `A`. -/ theorem linearIndependent_right' (H : A.LinearDisjoint L) {ι : Type*} {b : ι → L} @@ -334,7 +319,6 @@ theorem linearIndependent_right' (H : A.LinearDisjoint L) {ι : Type*} {b : ι apply Subalgebra.LinearDisjoint.linearIndependent_right_of_flat H <| hb.map' _ (AlgEquiv.ofInjectiveField (IsScalarTower.toAlgHom F L E)).toLinearEquiv.ker -set_option backward.isDefEq.respectTransparency false in /-- If there exists an `F`-basis of `L` which remains linearly independent over `A`, then `A` and `L` are linearly disjoint. -/ theorem of_basis_right' {ι : Type*} (b : Basis ι F L) @@ -342,7 +326,6 @@ theorem of_basis_right' {ι : Type*} (b : Basis ι F L) Subalgebra.LinearDisjoint.of_basis_right _ _ (b.map (AlgEquiv.ofInjectiveField (IsScalarTower.toAlgHom F L E)).toLinearEquiv) H -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are linearly disjoint, then for any `F`-linearly independent families `{ u_i }`, `{ v_j }` of `A`, `B`, the products `{ u_i * v_j }` are linearly independent over `F`. -/ @@ -351,7 +334,6 @@ theorem linearIndependent_mul (H : A.LinearDisjoint B) {κ ι : Type*} {a : κ LinearIndependent F fun (i : κ × ι) ↦ (a i.1).1 * (b i.2).1 := (linearDisjoint_iff'.1 H).linearIndependent_mul_of_flat_left ha hb -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `L` are linearly disjoint, then for any `F`-linearly independent families `{ u_i }`, `{ v_j }` of `A`, `L`, the products `{ u_i * v_j }` are linearly independent over `F`. -/ @@ -361,14 +343,12 @@ theorem linearIndependent_mul' (H : A.LinearDisjoint L) {κ ι : Type*} {a : κ apply Subalgebra.LinearDisjoint.linearIndependent_mul_of_flat_left H ha <| hb.map' _ (AlgEquiv.ofInjectiveField (IsScalarTower.toAlgHom F L E)).toLinearEquiv.ker -set_option backward.isDefEq.respectTransparency false in /-- If there are `F`-bases `{ u_i }`, `{ v_j }` of `A`, `B`, such that the products `{ u_i * v_j }` are linearly independent over `F`, then `A` and `B` are linearly disjoint. -/ theorem of_basis_mul {κ ι : Type*} (a : Basis κ F A) (b : Basis ι F B) (H : LinearIndependent F fun (i : κ × ι) ↦ (a i.1).1 * (b i.2).1) : A.LinearDisjoint B := linearDisjoint_iff'.2 (.of_basis_mul _ _ a b H) -set_option backward.isDefEq.respectTransparency false in /-- If there are `F`-bases `{ u_i }`, `{ v_j }` of `A`, `L`, such that the products `{ u_i * v_j }` are linearly independent over `F`, then `A` and `L` are linearly disjoint. -/ theorem of_basis_mul' {κ ι : Type*} (a : Basis κ F A) (b : Basis ι F L) @@ -381,7 +361,6 @@ theorem of_le_left {A' : IntermediateField F E} (H : A.LinearDisjoint L) (h : A' ≤ A) : A'.LinearDisjoint L := Subalgebra.LinearDisjoint.of_le_left_of_flat H h -set_option backward.isDefEq.respectTransparency false in theorem of_le_right {B' : IntermediateField F E} (H : A.LinearDisjoint B) (h : B' ≤ B) : A.LinearDisjoint B' := linearDisjoint_iff'.2 ((linearDisjoint_iff'.1 H).of_le_right_of_flat h) @@ -394,7 +373,6 @@ theorem of_le_right' (H : A.LinearDisjoint L) (L' : Type*) [Field L'] convert AlgHom.range_comp_le_range (IsScalarTower.toAlgHom F L' L) (IsScalarTower.toAlgHom F L E) ext; exact IsScalarTower.algebraMap_apply L' L E _ -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are linearly disjoint, `A'` and `B'` are contained in `A` and `B`, respectively, then `A'` and `B'` are also linearly disjoint. -/ theorem of_le {A' B' : IntermediateField F E} (H : A.LinearDisjoint B) @@ -408,7 +386,6 @@ theorem of_le' {A' : IntermediateField F E} (H : A.LinearDisjoint L) [Algebra L' E] [IsScalarTower F L' E] [IsScalarTower L' L E] : A'.LinearDisjoint L' := H.of_le_left hA |>.of_le_right' L' -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are linearly disjoint over `F`, then their intersection is equal to `F`. This is actually an equivalence if `A/F` and `B/F` are finite dimensional, and `A/F` is Galois, @@ -417,12 +394,10 @@ see `IntermediateField.LinearDisjoint.iff_inf_eq_bot`. theorem inf_eq_bot (H : A.LinearDisjoint B) : A ⊓ B = ⊥ := toSubalgebra_injective (linearDisjoint_iff'.1 H).inf_eq_bot -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `A` itself are linearly disjoint over `F`, then it is equal to `F`. -/ theorem eq_bot_of_self (H : A.LinearDisjoint A) : A = ⊥ := inf_idem A ▸ H.inf_eq_bot -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are linearly disjoint over `F`, then the rank of `A ⊔ B` is equal to the product of that of `A` and `B`. -/ theorem rank_sup (H : A.LinearDisjoint B) : @@ -432,13 +407,11 @@ theorem rank_sup (H : A.LinearDisjoint B) : (linearDisjoint_iff'.1 H).rank_sup_of_free.ge.trans <| (Subalgebra.inclusion h).toLinearMap.rank_le_of_injective (Subalgebra.inclusion_injective h) -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are linearly disjoint over `F`, then the `Module.finrank` of `A ⊔ B` is equal to the product of that of `A` and `B`. -/ theorem finrank_sup (H : A.LinearDisjoint B) : finrank F ↥(A ⊔ B) = finrank F A * finrank F B := by simpa only [map_mul] using congr(Cardinal.toNat $(H.rank_sup)) -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are finite extensions of `F`, such that rank of `A ⊔ B` is equal to the product of the rank of `A` and `B`, then `A` and `B` are linearly disjoint. -/ @@ -446,7 +419,6 @@ theorem of_finrank_sup [FiniteDimensional F A] [FiniteDimensional F B] (H : finrank F ↥(A ⊔ B) = finrank F A * finrank F B) : A.LinearDisjoint B := linearDisjoint_iff'.2 <| .of_finrank_sup_of_free (by rwa [← sup_toSubalgebra_of_left]) -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are linearly disjoint over `F` and `A ⊔ B = E`, then the `Module.finrank` of `E` over `A` is equal to the `Module.finrank` of `B` over `F`. -/ @@ -455,7 +427,6 @@ theorem finrank_left_eq_finrank [Module.Finite F A] (h₁ : A.LinearDisjoint B) have := h₁.finrank_sup rwa [h₂, finrank_top', ← finrank_mul_finrank F A E, mul_right_inj' finrank_pos.ne'] at this -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are linearly disjoint over `F` and `A ⊔ B = E`, then the `Module.finrank` of `E` over `B` is equal to the `Module.finrank` of `A` over `F`. -/ @@ -463,7 +434,6 @@ theorem finrank_right_eq_finrank [Module.Finite F B] (h₁ : A.LinearDisjoint B) finrank B E = finrank F A := h₁.symm.finrank_left_eq_finrank (by rwa [sup_comm]) -set_option backward.isDefEq.respectTransparency false in private theorem of_inf_eq_bot_aux [IsGalois F A] [FiniteDimensional F E] (h₁ : A ⊔ B = ⊤) (h₂ : A ⊓ B = ⊥) : A.LinearDisjoint B := by apply LinearDisjoint.of_finrank_sup @@ -475,7 +445,6 @@ private theorem of_inf_eq_bot_aux [IsGalois F A] [FiniteDimensional F E] (h₁ : ⟨restrictRestrictAlgEquivMapHom_injective _ _ h₁, restrictRestrictAlgEquivMapHom_surjective _ _ h₂⟩ -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are finite extensions of `F`, with `A/F` Galois, such that `A ⊓ B = F`, then `A` and `B` are linearly disjoint over `F`. @@ -495,13 +464,11 @@ theorem of_inf_eq_bot [IsGalois F A] [FiniteDimensional F A] [FiniteDimensional have : IsGalois F A' := IsGalois.of_algEquiv <| restrict_algEquiv .. exact of_inf_eq_bot_aux h₁ h₂ -set_option backward.isDefEq.respectTransparency false in @[simp] theorem iff_inf_eq_bot [IsGalois F A] [FiniteDimensional F A] [FiniteDimensional F B] : A.LinearDisjoint B ↔ A ⊓ B = ⊥ := ⟨fun h ↦ inf_eq_bot h, fun h ↦ of_inf_eq_bot h⟩ -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `L` are linearly disjoint over `F`, one of them is algebraic, then `[L(A) : L] = [A : F]`. -/ theorem adjoin_rank_eq_rank_left_of_isAlgebraic (H : A.LinearDisjoint L) @@ -532,7 +499,6 @@ theorem adjoin_rank_eq_rank_left_of_isAlgebraic_right (H : A.LinearDisjoint L) [Algebra.IsAlgebraic F L] : Module.rank L (adjoin L (A : Set E)) = Module.rank F A := H.adjoin_rank_eq_rank_left_of_isAlgebraic (.inr ‹_›) -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `L` are linearly disjoint over `F`, one of them is algebraic, then `[L(A) : A] = [L : F]`. Note that in Lean `L(A)` is not naturally an `A`-algebra, so this result is stated in a cumbersome way. -/ @@ -571,7 +537,6 @@ theorem lift_adjoin_rank_eq_lift_rank_right_of_isAlgebraic_right (H : A.LinearDi Cardinal.lift.{v} (Module.rank F L) := H.lift_adjoin_rank_eq_lift_rank_right_of_isAlgebraic (.inr ‹_›) -set_option backward.isDefEq.respectTransparency false in /-- If `A` is an intermediate field of `E / F`, `L` is an abstract field between `E / F`, such that they are linearly disjoint over `F`, and one of them is algebraic, then `[L : F] * [E : L(A)] = [E : A]`. -/ @@ -648,14 +613,12 @@ theorem of_finrank_coprime (H : (finrank F A).Coprime (finrank F L)) : A.LinearD Subalgebra.LinearDisjoint.of_finrank_coprime_of_free <| by rwa [(AlgEquiv.ofInjectiveField (IsScalarTower.toAlgHom F L E)).toLinearEquiv.finrank_eq] at H -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `L` are linearly disjoint over `F`, then `A ⊗[F] L` is a domain. -/ theorem isDomain (H : A.LinearDisjoint L) : IsDomain (A ⊗[F] L) := have : IsDomain (A ⊗[F] _) := Subalgebra.LinearDisjoint.isDomain H (Algebra.TensorProduct.congr (AlgEquiv.refl : A ≃ₐ[F] A) (AlgEquiv.ofInjective (IsScalarTower.toAlgHom F L E) (RingHom.injective _))).toMulEquiv.isDomain -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are field extensions of `F`, there exists a field extension `E` of `F` that `A` and `B` embed into with linearly disjoint images, then `A ⊗[F] B` is a domain. -/ theorem isDomain' {A B : Type*} [Field A] [Algebra F A] [Field B] [Algebra F B] @@ -664,7 +627,6 @@ theorem isDomain' {A B : Type*} [Field A] [Algebra F A] [Field B] [Algebra F B] simp_rw [linearDisjoint_iff', AlgHom.fieldRange_toSubalgebra] at H exact H.isDomain_of_injective fa.injective fb.injective -set_option backward.isDefEq.respectTransparency false in /-- If `A ⊗[F] L` is a field, then `A` and `L` are linearly disjoint over `F`. -/ theorem of_isField (H : IsField (A ⊗[F] L)) : A.LinearDisjoint L := by apply Subalgebra.LinearDisjoint.of_isField @@ -678,7 +640,6 @@ theorem of_isField (H : IsField (A ⊗[F] L)) : A.LinearDisjoint L := by (AlgEquiv.ofInjective (IsScalarTower.toAlgHom F L E) (RingHom.injective _)) |>.symm.toMulEquiv.isField H -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are field extensions of `F`, such that `A ⊗[F] B` is a field, then for any field extension of `F` that `A` and `B` embed into, their images are linearly disjoint. -/ theorem of_isField' {A : Type v} [Field A] {B : Type w} [Field B] @@ -690,7 +651,6 @@ theorem of_isField' {A : Type v} [Field A] {B : Type w} [Field B] exact Algebra.TensorProduct.congr (AlgEquiv.ofInjective fa fa.injective) (AlgEquiv.ofInjective fb fb.injective) |>.symm.toMulEquiv.isField H -set_option backward.isDefEq.respectTransparency false in variable (F) in /-- If `A` and `B` are field extensions of `F`, such that `A ⊗[F] B` is a domain, then there exists a field extension of `F` that `A` and `B` embed into with linearly disjoint images. -/ @@ -703,7 +663,6 @@ theorem exists_field_of_isDomain (A : Type v) [Field A] (B : Type w) [Field B] (RingHom.injective _) (RingHom.injective _) ⟨K, inst1, inst2, fa, fb, linearDisjoint_iff'.2 H⟩ -set_option backward.isDefEq.respectTransparency false in variable (F) in /-- If for any field extension `K` of `F` that `A` and `B` embed into, their images are linearly disjoint, then `A ⊗[F] B` is a field. (In the proof we choose `K` to be the quotient @@ -731,7 +690,6 @@ theorem isField_of_forall (A : Type v) [Field A] (B : Type w) [Field B] change Function.Injective (Ideal.Quotient.mk M) at H rwa [RingHom.injective_iff_ker_eq_bot, Ideal.mk_ker] at H -set_option backward.isDefEq.respectTransparency false in variable (F E) in /-- If `E` and `K` are field extensions of `F`, one of them is algebraic, such that `E ⊗[F] K` is a domain, then `E ⊗[F] K` is also a field. It is a corollary of @@ -753,7 +711,6 @@ theorem _root_.Algebra.TensorProduct.isField_of_isAlgebraic (AlgEquiv.ofInjective fb hfb).isAlgebraic_iff] at halg).symm) f.toMulEquiv.isField (Field.toIsField _) -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `L` are linearly disjoint over `F` and one of them is algebraic, then `A ⊗[F] L` is a field. -/ theorem isField_of_isAlgebraic (H : A.LinearDisjoint L) @@ -761,7 +718,6 @@ theorem isField_of_isAlgebraic (H : A.LinearDisjoint L) have := H.isDomain Algebra.TensorProduct.isField_of_isAlgebraic F A L halg -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are field extensions of `F`, one of them is algebraic, such that there exists a field `E` that `A` and `B` embeds into with linearly disjoint images, then `A ⊗[F] B` is a field. -/ @@ -771,7 +727,6 @@ theorem isField_of_isAlgebraic' {A B : Type*} [Field A] [Algebra F A] [Field B] have := H.isDomain' Algebra.TensorProduct.isField_of_isAlgebraic F A B halg -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `L` are linearly disjoint, one of them is algebraic, then for any `B` and `L'` isomorphic to `A` and `L` respectively, `B` and `L'` are also linearly disjoint. -/ theorem algEquiv_of_isAlgebraic (H : A.LinearDisjoint L) @@ -784,7 +739,6 @@ theorem algEquiv_of_isAlgebraic (H : A.LinearDisjoint L) .of_isField ((Algebra.TensorProduct.congr f1 f2).symm.toMulEquiv.isField (H.isField_of_isAlgebraic halg)) -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are linearly disjoint, then `trace` and `algebraMap` commutes. -/ @@ -795,7 +749,6 @@ theorem trace_algebraMap [FiniteDimensional F E] (h₁ : A.LinearDisjoint B) (h refine h₁.trace_algebraMap ?_ x simpa [sup_toSubalgebra_of_isAlgebraic_right] using congr_arg toSubalgebra h₂ -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are linearly disjoint, then `norm` and `algebraMap` commutes. -/ diff --git a/Mathlib/FieldTheory/Minpoly/Basic.lean b/Mathlib/FieldTheory/Minpoly/Basic.lean index 0b03f9fa219149..cc1e574160935b 100644 --- a/Mathlib/FieldTheory/Minpoly/Basic.lean +++ b/Mathlib/FieldTheory/Minpoly/Basic.lean @@ -231,7 +231,6 @@ theorem two_le_natDegree_iff (int : IsIntegral A x) : rw [iff_not_comm, ← natDegree_eq_one_iff, not_le] exact ⟨fun h ↦ h.trans_lt one_lt_two, fun h ↦ by linarith only [minpoly.natDegree_pos int, h]⟩ -set_option backward.isDefEq.respectTransparency false in theorem two_le_natDegree_subalgebra {B} [CommRing B] [Algebra A B] [Nontrivial B] {S : Subalgebra A B} {x : B} (int : IsIntegral S x) : 2 ≤ (minpoly S x).natDegree ↔ x ∉ S := by rw [two_le_natDegree_iff int, Iff.not] diff --git a/Mathlib/FieldTheory/Minpoly/IsIntegrallyClosed.lean b/Mathlib/FieldTheory/Minpoly/IsIntegrallyClosed.lean index 49fccc9d5b6cf6..eaf908bb432598 100644 --- a/Mathlib/FieldTheory/Minpoly/IsIntegrallyClosed.lean +++ b/Mathlib/FieldTheory/Minpoly/IsIntegrallyClosed.lean @@ -204,7 +204,6 @@ open Algebra Polynomial AdjoinRoot variable {x : S} -set_option backward.isDefEq.respectTransparency false in theorem ToAdjoin.injective (hx : IsIntegral R x) : Function.Injective (Minpoly.toAdjoin R x) := by refine (injective_iff_map_eq_zero _).2 fun P₁ hP₁ => ?_ obtain ⟨P, rfl⟩ := mk_surjective P₁ @@ -221,26 +220,22 @@ theorem equivAdjoin_toAlgHom (hx : IsIntegral R x) : equivAdjoin hx = Minpoly.to @[simp] theorem coe_equivAdjoin (hx : IsIntegral R x) : ⇑(equivAdjoin hx) = Minpoly.toAdjoin R x := rfl -set_option backward.isDefEq.respectTransparency false in /-- The `PowerBasis` of `adjoin R {x}` given by `x`. See `Algebra.adjoin.powerBasis` for a version over a field. -/ def _root_.Algebra.adjoin.powerBasis' (hx : IsIntegral R x) : PowerBasis R (Algebra.adjoin R ({x} : Set S)) := PowerBasis.map (AdjoinRoot.powerBasis' (minpoly.monic hx)) (minpoly.equivAdjoin hx) -set_option backward.isDefEq.respectTransparency false in @[simp] theorem _root_.Algebra.adjoin.powerBasis'_dim (hx : IsIntegral R x) : (Algebra.adjoin.powerBasis' hx).dim = (minpoly R x).natDegree := rfl -set_option backward.isDefEq.respectTransparency false in @[simp] theorem _root_.Algebra.adjoin.powerBasis'_gen (hx : IsIntegral R x) : (adjoin.powerBasis' hx).gen = ⟨x, SetLike.mem_coe.1 <| subset_adjoin <| mem_singleton x⟩ := by rw [Algebra.adjoin.powerBasis', PowerBasis.map_gen, AdjoinRoot.powerBasis'_gen, equivAdjoin, AlgEquiv.ofBijective_apply, Minpoly.toAdjoin, liftAlgHom_root] -set_option backward.isDefEq.respectTransparency false in /-- If `x` generates `S` over `R` and is integral over `R`, then it defines a power basis. See `PowerBasis.ofAdjoinEqTop` for a version over a field. @@ -265,7 +260,6 @@ theorem _root_.PowerBasis.ofAdjoinEqTop'_dim {x : S} (hx : IsIntegral R x) (hx' : adjoin R {x} = ⊤) : (PowerBasis.ofAdjoinEqTop' hx hx').dim = (minpoly R x).natDegree := rfl -set_option backward.isDefEq.respectTransparency false in @[simp] theorem _root_.PowerBasis.ofAdjoinEqTop'_gen {x : S} (hx : IsIntegral R x) (hx' : adjoin R {x} = ⊤) : (PowerBasis.ofAdjoinEqTop' hx hx').gen = x := by @@ -293,7 +287,6 @@ instance : SMul A (integralClosure A L) := Algebra.toSMul instance : IsScalarTower A ((integralClosure A L)) L := IsScalarTower.subalgebra' A L L (integralClosure A L) -set_option backward.isDefEq.respectTransparency false in /-- The minimal polynomial of `x : L` over `K` agrees with its minimal polynomial over the integrally closed subring `A`. -/ theorem ofSubring (x : integralClosure A L) : diff --git a/Mathlib/FieldTheory/Normal/Basic.lean b/Mathlib/FieldTheory/Normal/Basic.lean index d19d959218e55f..4bd92293c88905 100644 --- a/Mathlib/FieldTheory/Normal/Basic.lean +++ b/Mathlib/FieldTheory/Normal/Basic.lean @@ -59,7 +59,6 @@ variable {E F} open IntermediateField -set_option backward.isDefEq.respectTransparency false in @[stacks 09HU "Normal part"] theorem Normal.of_isSplittingField (p : F[X]) [hFEp : IsSplittingField F E p] : Normal F E := by rcases eq_or_ne p 0 with (rfl | hp) @@ -137,7 +136,6 @@ instance normal_sup Normal F (E ⊔ E' : IntermediateField F K) := iSup_bool_eq (f := Bool.rec E' E) ▸ normal_iSup (h := by rintro (_ | _) <;> infer_instance) -set_option backward.isDefEq.respectTransparency false in /-- An intersection of normal extensions is normal. -/ @[stacks 09HP] instance normal_iInf {ι : Type*} [hι : Nonempty ι] @@ -172,7 +170,6 @@ section Restrict variable (E : Type*) [Field E] [Algebra F E] [Algebra E K₁] [Algebra E K₂] [Algebra E K₃] [IsScalarTower F E K₁] [IsScalarTower F E K₂] [IsScalarTower F E K₃] -set_option backward.isDefEq.respectTransparency false in theorem AlgHom.fieldRange_of_normal {E : IntermediateField F K} [Normal F E] (f : E →ₐ[F] K) : f.fieldRange = E := by let g := f.restrictNormal' E @@ -267,7 +264,6 @@ variable {K L : Type _} [Field K] [Field L] [Algebra K L] open AlgEquiv IntermediateField -set_option backward.isDefEq.respectTransparency false in /-- If `x : L` is a root of `minpoly K y`, then we can find `(σ : Gal(L/K))` with `σ x = y`. That is, `x` and `y` are Galois conjugates. -/ theorem exists_algEquiv_of_root [Normal K L] {x y : L} (hy : IsAlgebraic K y) diff --git a/Mathlib/FieldTheory/Normal/Closure.lean b/Mathlib/FieldTheory/Normal/Closure.lean index bc0b12a5348dd5..abf6261bb0378d 100644 --- a/Mathlib/FieldTheory/Normal/Closure.lean +++ b/Mathlib/FieldTheory/Normal/Closure.lean @@ -191,11 +191,9 @@ instance : IsScalarTower F K (normalClosure F K L) := by ext x exact algebraMap_apply F K L x -set_option backward.isDefEq.respectTransparency false in instance : IsScalarTower K (normalClosure F K L) L := of_algebraMap_eq' rfl -set_option backward.isDefEq.respectTransparency false in lemma restrictScalars_eq : (toAlgHom K (normalClosure F K L) L).fieldRange.restrictScalars F = normalClosure F K L := SetLike.ext' Subtype.range_val @@ -240,7 +238,6 @@ lemma normalClosure_of_normal [Normal F K] : normalClosure F K L = K := by variable [Normal F L] -set_option backward.isDefEq.respectTransparency false in lemma normalClosure_def' : normalClosure F K L = ⨆ f : L →ₐ[F] L, K.map f := by refine (normalClosure_def F K L).trans (le_antisymm (iSup_le (fun f ↦ ?_)) (iSup_le (fun f ↦ ?_))) · exact le_iSup_of_le (f.liftNormal L) (fun b ⟨a, h⟩ ↦ ⟨a, a.2, h ▸ f.liftNormal_commutes L a⟩) diff --git a/Mathlib/FieldTheory/Normal/Defs.lean b/Mathlib/FieldTheory/Normal/Defs.lean index e326050c5cb00c..6651230cdecd2a 100644 --- a/Mathlib/FieldTheory/Normal/Defs.lean +++ b/Mathlib/FieldTheory/Normal/Defs.lean @@ -71,7 +71,6 @@ theorem Normal.tower_top_of_normal [h : Normal F E] : Normal K E := exact ⟨hx.tower_top, hhx.of_dvd (map_ne_zero (map_ne_zero (minpoly.ne_zero hx))) ((map_dvd_map' _).mpr (minpoly.dvd_map_of_isScalarTower F K x))⟩ -set_option backward.isDefEq.respectTransparency false in instance IntermediateField.normal (K : IntermediateField F E) [Normal F E] : Normal K E := Normal.tower_top_of_normal F K E @@ -188,7 +187,6 @@ theorem AlgEquiv.restrictNormal_trans [Normal F E] : def AlgEquiv.restrictNormalHom [Normal F E] : Gal(K₁/F) →* Gal(E/F) := MonoidHom.mk' (fun χ => χ.restrictNormal E) fun ω χ => χ.restrictNormal_trans ω E -set_option backward.isDefEq.respectTransparency false in lemma AlgEquiv.restrictNormalHom_apply (L : IntermediateField F K₁) [Normal F L] (σ : Gal(K₁/F)) (x : L) : restrictNormalHom L σ x = σ x := AlgEquiv.restrictNormal_commutes σ L x diff --git a/Mathlib/FieldTheory/NormalizedTrace.lean b/Mathlib/FieldTheory/NormalizedTrace.lean index 3f40710a8f3137..1b6f208b52823d 100644 --- a/Mathlib/FieldTheory/NormalizedTrace.lean +++ b/Mathlib/FieldTheory/NormalizedTrace.lean @@ -51,7 +51,6 @@ private noncomputable def normalizedTraceAux (a : K) : F := private theorem normalizedTraceAux_def (a : K) : normalizedTraceAux F K a = (Module.finrank F F⟮a⟯ : F)⁻¹ • trace F F⟮a⟯ (AdjoinSimple.gen F a) := rfl -set_option backward.isDefEq.respectTransparency false in private theorem normalizedTraceAux_map {E : Type*} [Field E] [Algebra F E] (f : E →ₐ[F] K) (a : E) : normalizedTraceAux F K (f a) = normalizedTraceAux F E a := by let e := (F⟮a⟯.equivMap f).trans (equivOfEq <| Set.image_singleton ▸ adjoin_map F {a} f) @@ -65,7 +64,6 @@ private theorem normalizedTraceAux_intermediateField {E : IntermediateField F K} variable [CharZero F] -set_option backward.isDefEq.respectTransparency false in variable {K} in private theorem normalizedTraceAux_eq_of_finiteDimensional [FiniteDimensional F K] (a : K) : normalizedTraceAux F K a = (Module.finrank F K : F)⁻¹ • trace F K a := by @@ -77,7 +75,6 @@ private theorem normalizedTraceAux_eq_of_finiteDimensional [FiniteDimensional F variable [Algebra.IsIntegral F K] -set_option backward.isDefEq.respectTransparency false in set_option backward.privateInPublic true in set_option backward.privateInPublic.warn false in /-- The normalized trace map from an algebraic extension `K` to the base field `F`. -/ @@ -213,7 +210,6 @@ private theorem normalizedTrace_trans_apply_aux [FiniteDimensional F E] [Algebra ← normalizedTrace_intermediateField F K a'] congr -set_option backward.isDefEq.respectTransparency false in /-- For a tower `K / E / F` of algebraic extensions, the normalized trace from `K` to `E` composed with the normalized trace from `E` to `F` equals the normalized trace from `K` to `F`. -/ theorem normalizedTrace_trans_apply [Algebra.IsIntegral E K] [CharZero E] (a : K) : diff --git a/Mathlib/FieldTheory/PrimitiveElement.lean b/Mathlib/FieldTheory/PrimitiveElement.lean index c0870d6b7f5937..dae3523ccef036 100644 --- a/Mathlib/FieldTheory/PrimitiveElement.lean +++ b/Mathlib/FieldTheory/PrimitiveElement.lean @@ -100,7 +100,6 @@ theorem primitive_element_inf_aux_exists_c (f g : F[X]) : variable (F) variable [Algebra F E] -set_option backward.isDefEq.respectTransparency false in /-- This is the heart of the proof of the primitive element theorem. It shows that if `F` is infinite and `α` and `β` are separable over `F` then `F⟮α, β⟯` is generated by a single element. -/ theorem primitive_element_inf_aux [Algebra.IsSeparable F E] : ∃ γ : E, F⟮α, β⟯ = F⟮γ⟯ := by @@ -208,7 +207,6 @@ section SeparableAssumption variable [FiniteDimensional F E] [Algebra.IsSeparable F E] -set_option backward.isDefEq.respectTransparency false in /-- **Primitive element theorem**: a finite separable field extension `E` of `F` has a primitive element, i.e. there is an `α ∈ E` such that `F⟮α⟯ = (⊤ : Subalgebra F E)`. -/ @[stacks 030N "The moreover part"] @@ -277,7 +275,6 @@ theorem isAlgebraic_of_finite_intermediateField have ⟨_m, _n, hneq, heq⟩ := Finite.exists_ne_map_eq_of_infinite fun n ↦ F⟮α ^ n⟯ isAlgebraic_of_adjoin_eq_adjoin F E hneq heq⟩ -set_option backward.isDefEq.respectTransparency false in theorem FiniteDimensional.of_finite_intermediateField [Finite (IntermediateField F E)] : FiniteDimensional F E := by let IF := { K : IntermediateField F E // ∃ x, K = F⟮x⟯ } @@ -290,7 +287,6 @@ theorem FiniteDimensional.of_finite_intermediateField rw [htop] at hfin exact topEquiv.toLinearEquiv.finiteDimensional -set_option backward.isDefEq.respectTransparency false in theorem exists_primitive_element_of_finite_intermediateField [Finite (IntermediateField F E)] (K : IntermediateField F E) : ∃ α : E, F⟮α⟯ = K := by haveI := FiniteDimensional.of_finite_intermediateField F E @@ -302,7 +298,6 @@ theorem exists_primitive_element_of_finite_intermediateField simp_rw [adjoin_simple_adjoin_simple, eq_comm] exact primitive_element_inf_aux_of_finite_intermediateField F α β -set_option backward.isDefEq.respectTransparency false in theorem FiniteDimensional.of_exists_primitive_element [Algebra.IsAlgebraic F E] (h : ∃ α : E, F⟮α⟯ = ⊤) : FiniteDimensional F E := by obtain ⟨α, hprim⟩ := h @@ -310,7 +305,6 @@ theorem FiniteDimensional.of_exists_primitive_element [Algebra.IsAlgebraic F E] rw [hprim] at hfin exact topEquiv.toLinearEquiv.finiteDimensional -set_option backward.isDefEq.respectTransparency false in -- A finite simple extension has only finitely many intermediate fields theorem finite_intermediateField_of_exists_primitive_element [Algebra.IsAlgebraic F E] (h : ∃ α : E, F⟮α⟯ = ⊤) : Finite (IntermediateField F E) := by @@ -403,7 +397,6 @@ theorem primitive_element_iff_algHom_eq_of_eval' (α : E) : ← AlgHom.card_of_splits F E A hA, Fintype.card, toFinset_range, Finset.card_image_iff, Finset.coe_univ, injOn_univ] -set_option backward.isDefEq.respectTransparency false in theorem primitive_element_iff_algHom_eq_of_eval (α : E) (φ : E →ₐ[F] A) : F⟮α⟯ = ⊤ ↔ ∀ ψ : E →ₐ[F] A, φ α = ψ α → φ = ψ := by refine ⟨fun h ψ hψ ↦ (Field.primitive_element_iff_algHom_eq_of_eval' F A hA α).mp h hψ, diff --git a/Mathlib/FieldTheory/PurelyInseparable/Basic.lean b/Mathlib/FieldTheory/PurelyInseparable/Basic.lean index ce0fb8300b9d8c..dac142b5c63c64 100644 --- a/Mathlib/FieldTheory/PurelyInseparable/Basic.lean +++ b/Mathlib/FieldTheory/PurelyInseparable/Basic.lean @@ -165,7 +165,6 @@ theorem IsPurelyInseparable.bijective_algebraMap_of_isSeparable [IsPurelyInseparable F E] [Algebra.IsSeparable F E] : Function.Bijective (algebraMap F E) := ⟨FaithfulSMul.algebraMap_injective F E, surjective_algebraMap_of_isSeparable F E⟩ -set_option backward.isDefEq.respectTransparency false in variable {F E} in /-- If a subalgebra of `E / F` is both purely inseparable and separable, then it is equal to `F`. -/ @@ -273,11 +272,9 @@ namespace IntermediateField variable (M : IntermediateField F K) -set_option backward.isDefEq.respectTransparency false in instance isPurelyInseparable_tower_bot [IsPurelyInseparable F K] : IsPurelyInseparable F M := IsPurelyInseparable.tower_bot F M K -set_option backward.isDefEq.respectTransparency false in instance isPurelyInseparable_tower_top [IsPurelyInseparable F K] : IsPurelyInseparable M K := IsPurelyInseparable.tower_top F M K @@ -321,7 +318,6 @@ theorem IsPurelyInseparable.minpoly_eq_X_sub_C_pow (q : ℕ) [ExpChar F q] [IsPu (x : E) : ∃ n : ℕ, (minpoly F x).map (algebraMap F E) = (X - C x) ^ q ^ n := (isPurelyInseparable_iff_minpoly_eq_X_sub_C_pow F q).1 ‹_› x -set_option backward.isDefEq.respectTransparency false in variable (E) in lemma IsPurelyInseparable.finrank_eq_pow (q : ℕ) [ExpChar F q] [IsPurelyInseparable F E] [FiniteDimensional F E] : @@ -349,7 +345,6 @@ lemma IsPurelyInseparable.finrank_eq_pow variable (E) -set_option backward.isDefEq.respectTransparency false in variable {F E} in /-- If an extension has finite separable degree one, then it is purely inseparable. -/ theorem isPurelyInseparable_of_finSepDegree_eq_one @@ -450,7 +445,6 @@ lemma isSeparable_iff_finInsepDegree_eq_one : Algebra.IsSeparable F K ↔ finInsepDegree F K = 1 := by rw [← separableClosure.eq_top_iff, ← IntermediateField.finrank_eq_one_iff_eq_top, finInsepDegree] -set_option backward.isDefEq.respectTransparency false in variable {F E} in /-- An algebraic extension is purely inseparable if and only if all of its finite-dimensional subextensions are purely inseparable. -/ @@ -473,7 +467,6 @@ instance IsPurelyInseparable.normal [IsPurelyInseparable F E] : Normal F E where rw [h] exact Splits.pow (Splits.X_sub_C _) _ -set_option backward.isDefEq.respectTransparency false in /-- If `E / F` is algebraic, then `E` is purely inseparable over the separable closure of `F` in `E`. -/ @[stacks 030K "$E/E_{sep}$ is purely inseparable."] @@ -487,19 +480,16 @@ instance separableClosure.isPurelyInseparable [Algebra.IsAlgebraic F E] : have hx : x ∈ restrictScalars F L⟮x⟯ := mem_adjoin_simple_self _ x exact ⟨⟨x, mem_separableClosure_iff.2 <| isSeparable_of_mem_isSeparable F E hx⟩, rfl⟩ -set_option backward.isDefEq.respectTransparency false in open Cardinal in theorem Field.Emb.cardinal_separableClosure [Algebra.IsAlgebraic F E] : #(Field.Emb F <| separableClosure F E) = #(Field.Emb F E) := by rw [← (embProdEmbOfIsAlgebraic F (separableClosure F E) E).cardinal_eq, mk_prod, mk_eq_one (Emb _ E), lift_one, mul_one, lift_id] -set_option backward.isDefEq.respectTransparency false in lemma finInsepDegree_eq_pow (q : ℕ) [ExpChar F q] [FiniteDimensional F E] : ∃ n, finInsepDegree F E = q ^ n := IsPurelyInseparable.finrank_eq_pow .. -set_option backward.isDefEq.respectTransparency false in /-- An intermediate field of `E / F` contains the separable closure of `F` in `E` if `E` is purely inseparable over it. -/ theorem separableClosure_le (L : IntermediateField F E) @@ -508,7 +498,6 @@ theorem separableClosure_le (L : IntermediateField F E) IsSeparable.tower_top L (mem_separableClosure_iff.1 hx) exact y.2 -set_option backward.isDefEq.respectTransparency false in /-- If `E / F` is algebraic, then an intermediate field of `E / F` contains the separable closure of `F` in `E` if and only if `E` is purely inseparable over it. -/ theorem separableClosure_le_iff [Algebra.IsAlgebraic F E] (L : IntermediateField F E) : @@ -519,14 +508,12 @@ theorem separableClosure_le_iff [Algebra.IsAlgebraic F E] (L : IntermediateField haveI : IsScalarTower (separableClosure F E) L E := IsScalarTower.of_algebraMap_eq (congrFun rfl) exact IsPurelyInseparable.tower_top (separableClosure F E) L E -set_option backward.isDefEq.respectTransparency false in /-- If an intermediate field of `E / F` is separable over `F`, and `E` is purely inseparable over it, then it is equal to the separable closure of `F` in `E`. -/ theorem eq_separableClosure (L : IntermediateField F E) [Algebra.IsSeparable F L] [IsPurelyInseparable L E] : L = separableClosure F E := le_antisymm (le_separableClosure F E L) (separableClosure_le F E L) -set_option backward.isDefEq.respectTransparency false in open separableClosure in /-- If `E / F` is algebraic, then an intermediate field of `E / F` is equal to the separable closure of `F` in `E` if and only if it is separable over `F`, and `E` is purely inseparable @@ -577,7 +564,6 @@ theorem Algebra.IsAlgebraic.isSepClosed [Algebra.IsAlgebraic F E] namespace Field -set_option backward.isDefEq.respectTransparency false in /-- If `E / F` is algebraic, then the `Field.finSepDegree F E` is equal to `Field.sepDegree F E` as a natural number. This means that the cardinality of `Field.Emb F E` and the degree of `(separableClosure F E) / F` are both finite or infinite, and when they are finite, they @@ -589,7 +575,6 @@ theorem finSepDegree_eq [Algebra.IsAlgebraic F E] : rwa [finSepDegree_eq_finrank_of_isSeparable F (separableClosure F E), IsPurelyInseparable.finSepDegree_eq_one (separableClosure F E) E, mul_one] at h -set_option backward.isDefEq.respectTransparency false in /-- The finite separable degree multiply by the finite inseparable degree is equal to the (finite) field extension degree. -/ theorem finSepDegree_mul_finInsepDegree : finSepDegree F E * finInsepDegree F E = finrank F E := by @@ -608,7 +593,6 @@ namespace separableClosure variable [Algebra E K] [IsScalarTower F E K] {F E} -set_option backward.isDefEq.respectTransparency false in /-- If `K / E / F` is a field extension tower, such that `E / F` is algebraic and `K / E` is separable, then `E` adjoin `separableClosure F K` is equal to `K`. It is a special case of `separableClosure.adjoin_eq_of_isAlgebraic`, and is an intermediate result used to prove it. -/ @@ -628,7 +612,6 @@ lemma adjoin_eq_of_isAlgebraic_of_isSeparable [Algebra.IsAlgebraic F E] obtain ⟨y, rfl⟩ := IsPurelyInseparable.surjective_algebraMap_of_isSeparable L K x exact y.2 -set_option backward.isDefEq.respectTransparency false in /-- If `K / E / F` is a field extension tower, such that `E / F` is algebraic, then `E` adjoin `separableClosure F K` is equal to `separableClosure E K`. -/ theorem adjoin_eq_of_isAlgebraic [Algebra.IsAlgebraic F E] : diff --git a/Mathlib/FieldTheory/PurelyInseparable/PerfectClosure.lean b/Mathlib/FieldTheory/PurelyInseparable/PerfectClosure.lean index bd1cf055e2acfd..7a3c681f45009c 100644 --- a/Mathlib/FieldTheory/PurelyInseparable/PerfectClosure.lean +++ b/Mathlib/FieldTheory/PurelyInseparable/PerfectClosure.lean @@ -100,7 +100,6 @@ instance perfectClosure.isPurelyInseparable : IsPurelyInseparable F (perfectClos instance perfectClosure.isAlgebraic : Algebra.IsAlgebraic F (perfectClosure F E) := IsPurelyInseparable.isAlgebraic F _ -set_option backward.isDefEq.respectTransparency false in /-- If `E / F` is separable, then the perfect closure of `F` in `E` is equal to `F`. Note that the converse is not necessarily true (see https://math.stackexchange.com/a/3009197) even when `E / F` is algebraic. -/ @@ -230,7 +229,6 @@ instance isPurelyInseparable_iSup {ι : Sort*} {t : ι → IntermediateField F E simp_rw [← le_perfectClosure_iff] at h ⊢ exact iSup_le h -set_option backward.isDefEq.respectTransparency false in /-- If `F` is a field of exponential characteristic `q`, `F(S) / F` is separable, then `F(S) = F(S ^ (q ^ n))` for any natural number `n`. -/ theorem adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable (S : Set E) @@ -251,7 +249,6 @@ theorem adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable (S : Set E) simpa only [extendScalars_restrictScalars, restrictScalars_bot_eq_self] using congr_arg (restrictScalars F) (extendScalars hi).eq_bot_of_isPurelyInseparable_of_isSeparable -set_option backward.isDefEq.respectTransparency false in /-- If `E / F` is a separable field extension of exponential characteristic `q`, then `F(S) = F(S ^ (q ^ n))` for any subset `S` of `E` and any natural number `n`. -/ theorem adjoin_eq_adjoin_pow_expChar_pow_of_isSeparable' [Algebra.IsSeparable F E] (S : Set E) @@ -344,7 +341,6 @@ private theorem LinearIndependent.map_pow_expChar_pow_of_fd_isSeparable simp_rw [Function.comp_apply, b] rw [Basis.extend_apply_self] -set_option backward.isDefEq.respectTransparency false in /-- If `E / F` is a separable extension of exponential characteristic `q`, if `{ u_i }` is a family of elements of `E` which is `F`-linearly independent, then `{ u_i ^ (q ^ n) }` is also `F`-linearly independent for any natural number `n`. -/ diff --git a/Mathlib/FieldTheory/PurelyInseparable/Tower.lean b/Mathlib/FieldTheory/PurelyInseparable/Tower.lean index 9116e99c3346be..ea8d74cc1dff7b 100644 --- a/Mathlib/FieldTheory/PurelyInseparable/Tower.lean +++ b/Mathlib/FieldTheory/PurelyInseparable/Tower.lean @@ -142,7 +142,6 @@ lemma insepDegree_eq_of_isSeparable [Algebra.IsSeparable F E] : rw [insepDegree, insepDegree, separableClosure.eq_restrictScalars_of_isSeparable F E K] rfl -set_option backward.isDefEq.respectTransparency false in /-- If `K / E / F` is a field extension tower, such that `E / F` is purely inseparable, then $[K:F]_s = [K:E]_s$. It is a special case of `Field.lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic`, and is an @@ -173,7 +172,6 @@ lemma rank_mul_insepDegree_of_isPurelyInseparable (K : Type v) [Field K] [Algebr Module.rank F E * insepDegree E K = insepDegree F K := by simpa only [Cardinal.lift_id] using lift_rank_mul_lift_insepDegree_of_isPurelyInseparable F E K -set_option backward.isDefEq.respectTransparency false in /-- If `K / E / F` is a field extension tower, such that `E / F` is algebraic, then their separable degrees satisfy the tower law: $[E:F]_s [K:E]_s = [K:F]_s$. -/ theorem lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic [Algebra.IsAlgebraic F E] : @@ -189,7 +187,6 @@ theorem sepDegree_mul_sepDegree_of_isAlgebraic (K : Type v) [Field K] [Algebra F sepDegree F E * sepDegree E K = sepDegree F K := by simpa only [Cardinal.lift_id] using lift_sepDegree_mul_lift_sepDegree_of_isAlgebraic F E K -set_option backward.isDefEq.respectTransparency false in /-- If `K / E / F` is a field extension tower, such that `E / F` is algebraic, then their inseparable degrees satisfy the tower law: $[E:F]_i [K:E]_i = [K:F]_i$. -/ theorem lift_insepDegree_mul_lift_insepDegree_of_isAlgebraic [Algebra.IsAlgebraic F E] : @@ -215,7 +212,6 @@ theorem finInsepDegree_mul_finInsepDegree_of_isAlgebraic [Algebra.IsAlgebraic F end Field -set_option backward.isDefEq.respectTransparency false in variable {F K} in /-- If `K / E / F` is a field extension tower, such that `E / F` is purely inseparable, then for any subset `S` of `K` such that `F(S) / F` is algebraic, the `E(S) / E` and `F(S) / F` have @@ -262,7 +258,6 @@ theorem IntermediateField.sepDegree_adjoin_eq_of_isAlgebraic_of_isPurelyInsepara have := sepDegree_adjoin_eq_of_isAlgebraic_of_isPurelyInseparable (F := F) E (S : Set K) rwa [adjoin_self] at this -set_option backward.isDefEq.respectTransparency false in variable {F K} in /-- If `K / E / F` is a field extension tower, such that `E / F` is purely inseparable, then for any element `x` of `K` separable over `F`, it has the same minimal polynomials over `F` and diff --git a/Mathlib/FieldTheory/RatFunc/AsPolynomial.lean b/Mathlib/FieldTheory/RatFunc/AsPolynomial.lean index e578d3c566eae9..77dbf9a59c00ba 100644 --- a/Mathlib/FieldTheory/RatFunc/AsPolynomial.lean +++ b/Mathlib/FieldTheory/RatFunc/AsPolynomial.lean @@ -87,6 +87,10 @@ theorem aeval_X_left_eq_algebraMap (p : K[X]) : p.aeval (X : K⟮X⟯) = algebraMap K[X] K⟮X⟯ p := by induction p using Polynomial.induction_on' <;> simp_all +@[simp] +theorem coePolynomial_eq_algebraMap (p : K[X]) : + (p : RatFunc K) = algebraMap (Polynomial K) (RatFunc K) p := rfl + @[simp] lemma liftRingHom_C {L : Type*} [Field L] (φ : K[X] →+* L) (hφ : K[X]⁰ ≤ L⁰.comap φ) (x : K) : liftRingHom φ hφ (C x) = φ (.C x) := @@ -218,13 +222,11 @@ open Polynomial IntermediateField algebraAdjoinAdjoin variable {K L : Type*} [Field K] [Field L] [Algebra K L] (f : L) (h : Transcendental K f) -set_option backward.isDefEq.respectTransparency false in /-- Given a transcendental `f : L`, the `K`-algebra isomorphism between `RatFunc K` and `L` given by sending `X` to `f`. -/ noncomputable def algEquivOfTranscendental : RatFunc K ≃ₐ[K] K⟮f⟯ := IsFractionRing.algEquivOfAlgEquiv (Polynomial.algEquivOfTranscendental K f h) -set_option backward.isDefEq.respectTransparency false in @[simp] theorem algEquivOfTranscendental_algebraMap (g : K[X]) : algEquivOfTranscendental f h (algebraMap K[X] (RatFunc K) g) = @@ -237,19 +239,16 @@ theorem algEquivOfTranscendental_X : algEquivOfTranscendental f h (X : RatFunc K) = f := by simp [← algebraMap_X] -set_option backward.isDefEq.respectTransparency false in theorem algEquivOfTranscendental_apply (u : RatFunc K) : algEquivOfTranscendental f h u = aeval f u.num / aeval f u.denom := by conv_lhs => rw [← num_div_denom u] simp [-num_div_denom] -set_option backward.isDefEq.respectTransparency false in @[simp] theorem algEquivOfTranscendental_symm_aeval (g : K[X]) : (algEquivOfTranscendental f h).symm (aeval (AdjoinSimple.gen _ f) g) = algebraMap _ _ g := by simp [algEquivOfTranscendental, ← algebraMap_eq_gen_self, aeval_algebraMap_apply] -set_option backward.isDefEq.respectTransparency false in @[simp] theorem algEquivOfTranscendental_symm_gen : (algEquivOfTranscendental f h).symm (AdjoinSimple.gen _ f) = (X : RatFunc K) := by @@ -313,18 +312,15 @@ variable {Γ : Type*} [LinearOrderedCommGroupWithZero Γ] section Algebra -variable (L : Type*) [Field L] [Algebra K L] {v : Valuation L Γ} - (hv : ∀ a : K, a ≠ 0 → v (algebraMap K L a) = 1) - -include hv +variable (L : Type*) [Field L] [Algebra K L] {v : Valuation L Γ} [hv : v.IsTrivialOn K] lemma valuation_aeval_monomial_eq_valuation_pow (w : L) (n : ℕ) {a : K} (ha : a ≠ 0) : v ((monomial n a).aeval w) = (v w) ^ n := by - simp [← C_mul_X_pow_eq_monomial, map_mul, map_pow, one_mul, hv a ha] + simp [← C_mul_X_pow_eq_monomial, map_mul, map_pow, one_mul, hv.eq_one a ha] theorem valuation_aeval_eq_valuation_X_pow_natDegree_of_one_lt_valuation_X (w : L) (hpos : 1 < v w) {p : Polynomial K} (hp : p ≠ 0) : v (p.aeval w) = v w ^ p.natDegree := by - rw [← valuation_aeval_monomial_eq_valuation_pow _ _ hv _ _ (leadingCoeff_ne_zero.mpr hp)] + rw [← valuation_aeval_monomial_eq_valuation_pow _ _ _ _ ((leadingCoeff_ne_zero).mpr hp)] nth_rw 1 [as_sum_range p, map_sum] apply Valuation.map_sum_eq_of_lt _ (by simp) intro i hi @@ -332,32 +328,30 @@ theorem valuation_aeval_eq_valuation_X_pow_natDegree_of_one_lt_valuation_X (w : ← lt_iff_le_and_ne] at hi simp only [← C_mul_X_pow_eq_monomial, map_mul, aeval_C, map_pow, aeval_X, coeff_natDegree] by_cases h0 : (p.coeff i) = 0 - · simp [h0, map_zero, zero_mul, one_mul, hv p.leadingCoeff (leadingCoeff_ne_zero.mpr hp), + · simp [h0, map_zero, zero_mul, one_mul, hv.eq_one p.leadingCoeff (leadingCoeff_ne_zero.mpr hp), pow_pos (lt_trans zero_lt_one hpos) p.natDegree] - · simp [one_mul, hv p.leadingCoeff (leadingCoeff_ne_zero.mpr hp), - hv _ h0, one_mul, pow_lt_pow_right₀ hpos hi] + · simp [one_mul, hv.eq_one p.leadingCoeff ((leadingCoeff_ne_zero).mpr hp), + hv.eq_one _ h0, one_mul, pow_lt_pow_right₀ hpos hi] end Algebra -variable {v : Valuation K⟮X⟯ Γ} (hv : ∀ a : K, a ≠ 0 → v (C a) = 1) +variable {v : Valuation K⟮X⟯ Γ} [hv : v.IsTrivialOn K] open Valuation -include hv - /-- If a valuation `v` is trivial on constants then for every `n : ℕ` the valuation of `(monomial n a)` is equal to `(v RatFunc.X) ^ n`. -/ lemma valuation_monomial_eq_valuation_X_pow (n : ℕ) {a : K} (ha : a ≠ 0) : v (monomial n a) = v RatFunc.X ^ n := by - simp_all [RatFunc.coePolynomial, ← C_mul_X_pow_eq_monomial] + simp_all [← RatFunc.algebraMap_eq_C, hv.eq_one] /-- If a valuation `v` is trivial on constants and `1 < v RatFunc.X` then for every polynomial `p`, `v p = v RatFunc.X ^ p.natDegree`. Note: The condition `1 < v RatFunc.X` is typically satisfied by the valuation at infinity. -/ -theorem valuation_eq_valuation_X_pow_natDegree_of_one_lt_valuation_X (hlt : 1 < v RatFunc.X) - {p : K[X]} (hp : p ≠ 0) : v p = v RatFunc.X ^ p.natDegree := by - convert valuation_aeval_eq_valuation_X_pow_natDegree_of_one_lt_valuation_X K K⟮X⟯ hv +theorem valuation_eq_valuation_X_pow_natDegree_of_one_lt_valuation_X + (hlt : 1 < v RatFunc.X) {p : K[X]} (hp : p ≠ 0) : v p = v RatFunc.X ^ p.natDegree := by + convert valuation_aeval_eq_valuation_X_pow_natDegree_of_one_lt_valuation_X K K⟮X⟯ RatFunc.X hlt hp ext p nth_rw 1 [RatFunc.X, ← aeval_X_left_apply p (R := K)] @@ -373,14 +367,14 @@ theorem valuation_le_one_of_valuation_X_le_one (hle : v RatFunc.X ≤ 1) (p : K[ by_cases h0 : p.coeff i = 0 · simp_all · rw [← RatFunc.coePolynomial] - simp_all [valuation_monomial_eq_valuation_X_pow, pow_le_one'] + simp_all [pow_le_one', ← RatFunc.algebraMap_eq_C, hv.eq_one _ h0] /-- If a valuation `v` is trivial on constants then for every `n : ℕ` the valuation of `1 / (monomial n a)` (as an element of the field of rational functions) is equal to `(v RatFunc.X) ^ (- n)`. -/ lemma valuation_inv_monomial_eq_valuation_X_zpow (n : ℕ) {a : K} (ha : a ≠ 0) : v (1 / monomial n a) = v RatFunc.X ^ (-(n : ℤ)) := by - simpa using valuation_monomial_eq_valuation_X_pow _ hv n ha + simp [← RatFunc.algebraMap_eq_C, hv.eq_one _ ha] end TrivialOnConstants diff --git a/Mathlib/FieldTheory/RatFunc/Degree.lean b/Mathlib/FieldTheory/RatFunc/Degree.lean index b585e642b6874c..3a50b92aaa10bf 100644 --- a/Mathlib/FieldTheory/RatFunc/Degree.lean +++ b/Mathlib/FieldTheory/RatFunc/Degree.lean @@ -82,6 +82,12 @@ theorem intDegree_mul {x y : K⟮X⟯} (hx : x ≠ 0) (hy : y ≠ 0) : theorem intDegree_inv (x : K⟮X⟯) : intDegree (x⁻¹) = - intDegree x := by by_cases hx : x = 0 <;> simp [hx, eq_neg_iff_add_eq_zero, ← intDegree_mul (inv_ne_zero hx) hx] +set_option backward.isDefEq.respectTransparency false in +lemma intDegree_div {x y : RatFunc K} (hx : x ≠ 0) (hy : y ≠ 0) : + (x / y).intDegree = x.intDegree - y.intDegree := by + rw [div_eq_mul_inv, intDegree_mul, intDegree_inv, ← sub_eq_add_neg] <;> grind + +set_option backward.isDefEq.respectTransparency false in @[simp] theorem intDegree_neg (x : K⟮X⟯) : intDegree (-x) = intDegree x := by by_cases hx : x = 0 diff --git a/Mathlib/FieldTheory/RatFunc/Luroth.lean b/Mathlib/FieldTheory/RatFunc/Luroth.lean index 2feb548df6401f..f5f70a3ea08401 100644 --- a/Mathlib/FieldTheory/RatFunc/Luroth.lean +++ b/Mathlib/FieldTheory/RatFunc/Luroth.lean @@ -47,13 +47,11 @@ local notation "K[f]" => Algebra.adjoin K {(f : K⟮X⟯)} theorem adjoin_X : K⟮(X : K⟮X⟯)⟯ = ⊤ := eq_top_iff.mpr fun g _ ↦ (mem_adjoin_simple_iff _ _).mpr ⟨g.num, g.denom, by simp⟩ -set_option backward.isDefEq.respectTransparency false in theorem IntermediateField.adjoin_X (E : IntermediateField K K⟮X⟯) : E⟮(X : K⟮X⟯)⟯ = ⊤ := by rw [← restrictScalars_eq_top_iff (K := K), restrictScalars_adjoin, eq_top_iff] exact le_trans (le_of_eq RatFunc.adjoin_X.symm) (IntermediateField.adjoin.mono _ _ _ (by simp)) -set_option backward.isDefEq.respectTransparency false in /-- The equivalence between `E⟮X⟯` and `K⟮X⟯` as `E`-algebras. -/ noncomputable def IntermediateField.adjoinXEquiv (E : IntermediateField K K⟮X⟯) : E⟮(X : K⟮X⟯)⟯ ≃ₐ[E] K⟮X⟯ := @@ -76,7 +74,6 @@ theorem minpolyX_map (A : Type*) [CommRing A] [Algebra K A] [Algebra (Algebra.ad theorem C_minpolyX (x : K) : (C x).minpolyX K⟮C x⟯ = 0 := by simp [minpolyX, sub_eq_zero, Subtype.ext_iff] -set_option backward.isDefEq.respectTransparency false in theorem minpolyX_aeval_X : (f.minpolyX K⟮f⟯).aeval (X : K⟮X⟯) = 0 := by simp only [aeval_sub, aeval_map_algebraMap, aeval_X_left_eq_algebraMap, map_mul, aeval_C, IntermediateField.algebraMap_apply, coe_algebraMap] @@ -84,7 +81,6 @@ theorem minpolyX_aeval_X : (f.minpolyX K⟮f⟯).aeval (X : K⟮X⟯) = 0 := by rw [div_mul_cancel₀ _ (algebraMap_ne_zero f.denom_ne_zero)] exact sub_self _ -set_option backward.isDefEq.respectTransparency false in theorem eq_C_of_minpolyX_coeff_eq_zero (hf : (f.minpolyX K⟮f⟯).coeff f.denom.natDegree = (0 : K⟮X⟯)) : ∃ c, f = C c := by use f.num.coeff f.denom.natDegree / f.denom.leadingCoeff @@ -92,15 +88,12 @@ theorem eq_C_of_minpolyX_coeff_eq_zero (leadingCoeff_ne_zero.mpr f.denom_ne_zero)), eq_comm] simpa [sub_eq_zero] using hf -set_option backward.isDefEq.respectTransparency false in theorem minpolyX_eq_zero_iff : (f.minpolyX K⟮f⟯) = 0 ↔ ∃ c, f = C c := ⟨fun h ↦ f.eq_C_of_minpolyX_coeff_eq_zero (by simp [h]), by rintro ⟨c, rfl⟩; simp⟩ -set_option backward.isDefEq.respectTransparency false in theorem isAlgebraic_adjoin_simple_X (hf : ¬∃ c, f = C c) : IsAlgebraic K⟮f⟯ (X : K⟮X⟯) := ⟨f.minpolyX K⟮f⟯, fun H ↦ hf (f.minpolyX_eq_zero_iff.mp H), f.minpolyX_aeval_X⟩ -set_option backward.isDefEq.respectTransparency false in theorem isAlgebraic_adjoin_simple_X' (hf : ¬∃ c, f = C c) : Algebra.IsAlgebraic K⟮f⟯ K⟮X⟯ := by have : Algebra.IsAlgebraic K⟮f⟯ K⟮f⟯⟮(X : K⟮X⟯)⟯ := @@ -141,7 +134,6 @@ theorem natDegree_minpolyX : · exact max_le (natDegree_num_le_natDegree_minpolyX f hf) <| le_natDegree_of_ne_zero fun H ↦ hf (f.eq_C_of_minpolyX_coeff_eq_zero congr($(H).val)) -set_option backward.isDefEq.respectTransparency false in theorem transcendental_of_ne_C (hf : ¬∃ c, f = C c) : Transcendental K f := by intro H have := IntermediateField.isAlgebraic_adjoin_simple H.isIntegral @@ -149,7 +141,6 @@ theorem transcendental_of_ne_C (hf : ¬∃ c, f = C c) : Transcendental K f := b rw [Algebra.transcendental_iff_not_isAlgebraic] at tr exact tr <| Algebra.IsAlgebraic.trans _ _ _ (alg := f.isAlgebraic_adjoin_simple_X' hf) -set_option backward.isDefEq.respectTransparency false in theorem irreducible_minpolyX' (hf : ¬∃ c, f = C c) : Irreducible (f.minpolyX K[f]) := by let e := Polynomial.algEquivOfTranscendental K f (f.transcendental_of_ne_C hf) let φ : K[X][X] := f.num.map (algebraMap ..) - @@ -174,7 +165,6 @@ theorem irreducible_minpolyX' (hf : ¬∃ c, f = C c) : Irreducible (f.minpolyX rw [add_comm, X_mul_C, map_neg, neg_mul] exact sub_eq_add_neg (Polynomial.C f.num) (Polynomial.C f.denom * Polynomial.X) -set_option backward.isDefEq.respectTransparency false in theorem irreducible_minpolyX (hf : ¬∃ c, f = C c) : Irreducible (f.minpolyX K⟮f⟯) := by haveI : UniqueFactorizationMonoid K[f] := (f.transcendental_of_ne_C hf).uniqueFactorizationMonoid_adjoin @@ -188,7 +178,6 @@ theorem irreducible_minpolyX (hf : ¬∃ c, f = C c) : Irreducible (f.minpolyX K Nat.max_eq_zero_iff, ← f.eq_C_iff] at this exact hf this -set_option backward.isDefEq.respectTransparency false in theorem finrank_eq_max_natDegree : Module.finrank K⟮f⟯ K⟮X⟯ = max f.num.natDegree f.denom.natDegree := by by_cases hf : ∃ c, f = C c @@ -203,7 +192,6 @@ theorem finrank_eq_max_natDegree : natDegree_C_mul <| inv_ne_zero <| leadingCoeff_ne_zero.mpr fun H ↦ hf ((minpolyX_eq_zero_iff f).mp H), natDegree_minpolyX] -set_option backward.isDefEq.respectTransparency false in theorem IntermediateField.isAlgebraic_X {E : IntermediateField K K⟮X⟯} (hE : E ≠ ⊥) : IsAlgebraic E (X : K⟮X⟯) := by rw [ne_eq, ← le_bot_iff, SetLike.not_le_iff_exists] at hE @@ -223,25 +211,20 @@ variable {E : IntermediateField K K⟮X⟯} -- The proof of Lüroth's theorem begins here. We follow the approach from -- [Cohn, Basic Algebra: Groups, Rings and Fields][cohn_2003]. -set_option backward.isDefEq.respectTransparency false in variable (E) in /-- The minimal polynomial of `X` with coefficients in `E`. -/ abbrev φ : E[X] := minpoly E (X : K⟮X⟯) -set_option backward.isDefEq.respectTransparency false in lemma φ_ne_zero (h : E ≠ ⊥) : φ E ≠ 0 := minpoly.ne_zero (IntermediateField.isAlgebraic_X h).isIntegral -set_option backward.isDefEq.respectTransparency false in lemma φ_monic (h : E ≠ ⊥) : (φ E).Monic := minpoly.monic (IntermediateField.isAlgebraic_X h).isIntegral -set_option backward.isDefEq.respectTransparency false in lemma φ_natDegree (h : E ≠ ⊥) : (φ E).natDegree = Module.finrank E K⟮X⟯ := by rw [← (IntermediateField.adjoinXEquiv E).toLinearEquiv.finrank_eq, adjoin.finrank (IntermediateField.isAlgebraic_X h).isIntegral] -set_option backward.isDefEq.respectTransparency false in /-- Since `X` is transcendental over `K`, not all coefficients of `φ` can be in `K`. -/ lemma exists_φ_coeff_not_mem (h : E ≠ ⊥) : ∃ i, (φ E).coeff i ∉ (algebraMap K E).range := by @@ -345,7 +328,6 @@ open Classical in /-- The primitive part of `Φ'`. -/ abbrev Φ : K[X][Y] := (Φ' E).primPart -set_option backward.isDefEq.respectTransparency false in /-- We have `c * φ = Φ` as polynomials with coefficients in `Ratfunc K`. See Equation (11.3.5) in Cohn's proof. -/ lemma C_c_mul_φ (h : E ≠ ⊥) : @@ -364,7 +346,6 @@ lemma Φ_natDegree_eq_φ_natDegree (h : E ≠ ⊥) : (Φ E).natDegree = (φ E).n natDegree_mul (C_ne_zero.mpr (c_ne_zero h)) (map_ne_zero (φ_ne_zero h)), natDegree_C, natDegree_map, zero_add] -set_option backward.isDefEq.respectTransparency false in lemma Φ_coeff_φ_natDegree (h : E ≠ ⊥) : algebraMap K[X] K⟮X⟯ ((Φ E).coeff (φ E).natDegree) = c E := by have := congr($(C_c_mul_φ h).coeff (φ E).natDegree) @@ -387,7 +368,6 @@ lemma Φ_coeff_φ_natDegree_ne_zero (h : E ≠ ⊥) : rw [Φ_coeff_φ_natDegree' h] exact num_ne_zero (c_ne_zero h) -set_option backward.isDefEq.respectTransparency false in lemma Φ_coeff_generatorIndex (h : E ≠ ⊥) : algebraMap K[X] K⟮X⟯ ((Φ E).coeff (generatorIndex h)) = algebraMap K[X] K⟮X⟯ (c E).num * generator E := by @@ -462,7 +442,6 @@ lemma m_le_swap_Φ_natDegree (h : E ≠ ⊥) : instance : Algebra K⟮generator E⟯ E := (IntermediateField.inclusion adjoin_generator_le).toAlgebra -set_option backward.isDefEq.respectTransparency false in /-- Since `minpolyX` of our `generator` annihilates `X`, the minimal polynomial `φ` must divide it. -/ lemma φ_dvd_generator_minpolyX : @@ -520,7 +499,6 @@ lemma θ_natDegree_le (h : E ≠ ⊥) : (θ E).natDegree ≤ m E := by · rw [natDegree_mul (C_ne_zero.mpr (num_ne_zero (generator_ne_zero h))) (Polynomial.map_ne_zero (generator E).denom_ne_zero), natDegree_C, zero_add, natDegree_map] -set_option backward.isDefEq.respectTransparency false in /-- Equation (11.3.8) from Cohns proof, viewed as an equation of polynomials with coefficients in `K⟮X⟯`. -/ lemma Q₀_mul_Φ (h : E ≠ ⊥) : diff --git a/Mathlib/FieldTheory/Relrank.lean b/Mathlib/FieldTheory/Relrank.lean index 4549a018783644..030887a3456822 100644 --- a/Mathlib/FieldTheory/Relrank.lean +++ b/Mathlib/FieldTheory/Relrank.lean @@ -45,7 +45,6 @@ when `A ≤ B` it is `[B : A]`, the degree of the field extension `B / A`. This is similar to `Subgroup.relIndex` but it is `Cardinal` valued. -/ noncomputable def relrank := Module.rank ↥(A ⊓ B) (extendScalars (inf_le_right : A ⊓ B ≤ B)) -set_option backward.isDefEq.respectTransparency false in /-- The `Nat` version of `Subfield.relrank`. If `B / A ⊓ B` is an infinite extension, then it is zero. -/ noncomputable def relfinrank := finrank ↥(A ⊓ B) (extendScalars (inf_le_right : A ⊓ B ≤ B)) @@ -68,7 +67,6 @@ theorem relrank_eq_rank_of_le (h : A ≤ B) : relrank A B = Module.rank A (exten have := inf_of_le_left h congr! -set_option backward.isDefEq.respectTransparency false in /-- If `A ≤ B`, then `Subfield.relfinrank A B` is `[B : A]`. -/ theorem relfinrank_eq_finrank_of_le (h : A ≤ B) : relfinrank A B = finrank A (extendScalars h) := congr(toNat $(relrank_eq_rank_of_le h)) @@ -139,7 +137,6 @@ theorem relrank_top_right : relrank A ⊤ = Module.rank A E := by theorem relfinrank_top_right : relfinrank A ⊤ = finrank A E := by simp [relfinrank_eq_toNat_relrank, finrank] -set_option backward.isDefEq.respectTransparency false in theorem lift_relrank_map_map (f : E →+* L) : lift.{v} (relrank (A.map f) (B.map f)) = lift.{w} (relrank A B) := -- typeclass inference is slow @@ -441,7 +438,6 @@ variable {A B} in theorem relfinrank_mul_finrank_top (h : A ≤ B) : relfinrank A B * finrank B E = finrank A E := by simpa using congr(toNat $(relrank_mul_rank_top h)) -set_option backward.isDefEq.respectTransparency false in variable {A B} in theorem rank_bot_mul_relrank (h : A ≤ B) : Module.rank F A * relrank A B = Module.rank F B := by rw [relrank_eq_rank_of_le h] diff --git a/Mathlib/FieldTheory/Separable.lean b/Mathlib/FieldTheory/Separable.lean index 61e1a640dbfff3..58a86f5001398f 100644 --- a/Mathlib/FieldTheory/Separable.lean +++ b/Mathlib/FieldTheory/Separable.lean @@ -595,7 +595,6 @@ lemma IsSeparable.map [Ring L] [Algebra F L] {x : K} (f : K →ₐ[F] L) (hf : F (H : IsSeparable F x) : IsSeparable F (f x) := (isSeparable_map_iff f hf).mpr H -set_option backward.isDefEq.respectTransparency false in lemma Subalgebra.isSeparable_iff [Ring L] [Algebra F L] {S : Subalgebra F L} : Algebra.IsSeparable F S ↔ ∀ x ∈ S, IsSeparable F x := by simp_rw [Algebra.isSeparable_def, Subtype.forall, @@ -718,11 +717,9 @@ namespace IntermediateField variable [Field K] [Algebra F K] (M : IntermediateField F K) -set_option backward.isDefEq.respectTransparency false in instance isSeparable_tower_bot [Algebra.IsSeparable F K] : Algebra.IsSeparable F M := Algebra.isSeparable_tower_bot_of_isSeparable F M K -set_option backward.isDefEq.respectTransparency false in instance isSeparable_tower_top [Algebra.IsSeparable F K] : Algebra.IsSeparable M K := Algebra.isSeparable_tower_top_of_isSeparable F M K diff --git a/Mathlib/FieldTheory/SeparableClosure.lean b/Mathlib/FieldTheory/SeparableClosure.lean index e3a18776ec617f..ec0fca0547a611 100644 --- a/Mathlib/FieldTheory/SeparableClosure.lean +++ b/Mathlib/FieldTheory/SeparableClosure.lean @@ -166,7 +166,6 @@ theorem le_separableClosure_iff (L : IntermediateField F E) : L ≤ separableClosure F E ↔ Algebra.IsSeparable F L := Subalgebra.isSeparable_iff.symm -set_option backward.isDefEq.respectTransparency false in /-- The separable closure in `E` of the separable closure of `F` in `E` is equal to itself. -/ theorem separableClosure.separableClosure_eq_bot : separableClosure (separableClosure F E) E = ⊥ := @@ -200,7 +199,6 @@ theorem IsSepClosed.separableClosure_eq_bot_iff [IsSepClosed E] : obtain ⟨x, rfl⟩ := h ▸ mem_separableClosure_iff.2 (hsep.of_dvd <| minpoly.dvd _ x hx) exact ⟨x, by simpa [Algebra.ofId_apply] using hx⟩ -set_option backward.isDefEq.respectTransparency false in /-- If `E` is separably closed, then the separable closure of `F` in `E` is an absolute separable closure of `F`. -/ instance separableClosure.isSepClosure [IsSepClosed E] : IsSepClosure F (separableClosure F E) := @@ -261,13 +259,11 @@ instance IntermediateField.isSeparable_iSup {ι : Type*} {t : ι → Intermediat simp_rw [← le_separableClosure_iff] at h ⊢ exact iSup_le h -set_option backward.isDefEq.respectTransparency false in variable {F E} in theorem le_restrictScalars_separableClosure (L : IntermediateField F E) : L ≤ (separableClosure L E).restrictScalars F := fun x hx ↦ isSeparable_algebraMap (F := L) ⟨x, hx⟩ -set_option backward.isDefEq.respectTransparency false in /-- `separableClosure` as a `ClosureOperator`. -/ abbrev separableClosureOperator : ClosureOperator (IntermediateField F E) := by refine .mk' (fun K ↦ (separableClosure K E).restrictScalars F) (fun K L le x hx ↦ ?_) @@ -284,7 +280,6 @@ lemma isClosed_restrictScalars_separableClosure [Algebra K E] [IsScalarTower F K obtain ⟨x, rfl⟩ := (separableClosure.separableClosure_eq_bot K E).le hx exact x.2 -set_option backward.isDefEq.respectTransparency false in lemma separableClosure_le_separableClosure_iff [Algebra K E] [IsScalarTower F K E] {L : IntermediateField F E} : (separableClosure L E).restrictScalars F ≤ (separableClosure K E).restrictScalars F ↔ @@ -330,7 +325,6 @@ theorem sepDegree_eq_of_equiv (K : Type v) [Field K] [Algebra F K] (i : E ≃ₐ sepDegree F E = sepDegree F K := i.separableClosure.toLinearEquiv.rank_eq -set_option backward.isDefEq.respectTransparency false in /-- The separable degree multiplied by the inseparable degree is equal to the (infinite) field extension degree. -/ theorem sepDegree_mul_insepDegree : sepDegree F E * insepDegree F E = Module.rank F E := @@ -342,14 +336,12 @@ theorem sepDegree_le_rank : sepDegree F E ≤ Module.rank F E := theorem insepDegree_le_rank : insepDegree F E ≤ Module.rank F E := Module.rank_top_le_rank_of_isScalarTower _ _ _ -set_option backward.isDefEq.respectTransparency false in /-- If `E` and `K` are isomorphic as `F`-algebras, then they have the same inseparable degree over `F`. -/ theorem lift_insepDegree_eq_of_equiv (i : E ≃ₐ[F] K) : Cardinal.lift.{w} (insepDegree F E) = Cardinal.lift.{v} (insepDegree F K) := Algebra.lift_rank_eq_of_equiv_equiv i.separableClosure i rfl -set_option backward.isDefEq.respectTransparency false in /-- The same-universe version of `Field.lift_insepDegree_eq_of_equiv`. -/ theorem insepDegree_eq_of_equiv (K : Type v) [Field K] [Algebra F K] (i : E ≃ₐ[F] K) : insepDegree F E = insepDegree F K := @@ -378,7 +370,6 @@ end Field namespace IntermediateField -set_option backward.isDefEq.respectTransparency false in /-- In a finitely generated field extension, there exists a maximal separably generated field extension. -/ lemma exists_finset_maximalFor_isTranscendenceBasis_separableClosure @@ -467,7 +458,6 @@ theorem sepDegree_bot' : sepDegree F (⊥ : IntermediateField E K) = sepDegree F theorem insepDegree_bot' : insepDegree F (⊥ : IntermediateField E K) = insepDegree F E := insepDegree_eq_of_equiv _ _ _ ((botEquiv E K).restrictScalars F) -set_option backward.isDefEq.respectTransparency false in variable (F) in lemma _root_.Field.insepDegree_top_le_insepDegree_of_isScalarTower : insepDegree E K ≤ insepDegree F K := by @@ -477,7 +467,6 @@ lemma _root_.Field.insepDegree_top_le_insepDegree_of_isScalarTower : exact Module.rank_top_le_rank_of_isScalarTower (separableClosure F K) ((separableClosure E K).restrictScalars F) K -set_option backward.isDefEq.respectTransparency false in variable {K} in lemma _root_.Field.insepDegree_le_of_left_le {E₁ E₂ : IntermediateField F K} (H : E₁ ≤ E₂) : insepDegree E₂ K ≤ insepDegree E₁ K := by @@ -485,7 +474,6 @@ lemma _root_.Field.insepDegree_le_of_left_le {E₁ E₂ : IntermediateField F K} have : IsScalarTower E₁ E₂ K := .of_algebraMap_eq' rfl exact insepDegree_top_le_insepDegree_of_isScalarTower _ _ _ -set_option backward.isDefEq.respectTransparency false in variable (F) in lemma _root_.Field.finInsepDegree_top_le_finInsepDegree_of_isScalarTower [Module.Finite F K] : finInsepDegree E K ≤ finInsepDegree F K := by @@ -495,7 +483,6 @@ lemma _root_.Field.finInsepDegree_top_le_finInsepDegree_of_isScalarTower [Module exact Module.finrank_top_le_finrank_of_isScalarTower (separableClosure F K) ((separableClosure E K).restrictScalars F) K -set_option backward.isDefEq.respectTransparency false in variable {K} in lemma finInsepDegree_le_of_left_le {E₁ E₂ : IntermediateField F K} (H : E₁ ≤ E₂) [Module.Finite E₁ K] : finInsepDegree E₂ K ≤ finInsepDegree E₁ K := by diff --git a/Mathlib/FieldTheory/SeparableDegree.lean b/Mathlib/FieldTheory/SeparableDegree.lean index 55b176c8f290bd..c284d1445b0b04 100644 --- a/Mathlib/FieldTheory/SeparableDegree.lean +++ b/Mathlib/FieldTheory/SeparableDegree.lean @@ -695,7 +695,6 @@ theorem finSepDegree_adjoin_simple_eq_natSepDegree {α : E} (halg : IsAlgebraic ← Fintype.card_coe] simp_rw [Multiset.mem_toFinset] -set_option backward.isDefEq.respectTransparency false in -- The separable degree of `F⟮α⟯ / F` divides the degree of `F⟮α⟯ / F`. -- Marked as `private` because it is a special case of `finSepDegree_dvd_finrank`. private theorem finSepDegree_adjoin_simple_dvd_finrank (α : E) : @@ -726,7 +725,6 @@ end IntermediateField namespace Field -set_option backward.isDefEq.respectTransparency false in /-- The separable degree of any field extension `E / F` divides the degree of `E / F`. -/ theorem finSepDegree_dvd_finrank : finSepDegree F E ∣ finrank F E := by by_cases hfd : FiniteDimensional F E @@ -746,7 +744,6 @@ theorem finSepDegree_dvd_finrank : finSepDegree F E ∣ finrank F E := by theorem finSepDegree_le_finrank [FiniteDimensional F E] : finSepDegree F E ≤ finrank F E := Nat.le_of_dvd finrank_pos <| finSepDegree_dvd_finrank F E -set_option backward.isDefEq.respectTransparency false in /-- If `E / F` is a separable extension, then its separable degree is equal to its degree. When `E / F` is infinite, it means that `Field.Emb F E` has infinitely many elements. (But the cardinality of `Field.Emb F E` is not equal to `Module.rank F E` in general!) -/ @@ -773,7 +770,6 @@ theorem finSepDegree_eq_finrank_of_isSeparable [Algebra.IsSeparable F E] : alias Algebra.IsSeparable.finSepDegree_eq := finSepDegree_eq_finrank_of_isSeparable -set_option backward.isDefEq.respectTransparency false in /-- If `E / F` is a finite extension, then its separable degree is equal to its degree if and only if it is a separable extension. -/ @[stacks 09HA "The equality condition"] @@ -794,7 +790,6 @@ lemma IntermediateField.isSeparable_of_mem_isSeparable {L : IntermediateField F [Algebra.IsSeparable F L] {x : E} (h : x ∈ L) : IsSeparable F x := by simpa only [IsSeparable, minpoly_eq] using Algebra.IsSeparable.isSeparable F (K := L) ⟨x, h⟩ -set_option backward.isDefEq.respectTransparency false in /-- `F⟮x⟯ / F` is a separable extension if and only if `x` is a separable element. As a consequence, any rational function of `x` is also a separable element. -/ theorem IntermediateField.isSeparable_adjoin_simple_iff_isSeparable {x : E} : @@ -806,7 +801,6 @@ theorem IntermediateField.isSeparable_adjoin_simple_iff_isSeparable {x : E} : rwa [← finSepDegree_eq_finrank_iff, finSepDegree_adjoin_simple_eq_finrank_iff F E x h.isAlgebraic] -set_option backward.isDefEq.respectTransparency false in variable {E K} in /-- If `K / E / F` is an extension tower such that `E / F` is separable, `x : K` is separable over `E`, then it's also separable over `F`. -/ @@ -845,7 +839,6 @@ theorem Algebra.IsSeparable.trans [Algebra E K] [IsScalarTower F E K] ⟨fun x ↦ IsSeparable.of_algebra_isSeparable_of_isSeparable F (Algebra.IsSeparable.isSeparable E x)⟩ -set_option backward.isDefEq.respectTransparency false in /-- If `x` and `y` are both separable elements, then `F⟮x, y⟯ / F` is a separable extension. As a consequence, any rational function of `x` and `y` is also a separable element. -/ theorem IntermediateField.isSeparable_adjoin_pair_of_isSeparable {x y : E} diff --git a/Mathlib/FieldTheory/SeparablyGenerated.lean b/Mathlib/FieldTheory/SeparablyGenerated.lean index efb1405038c848..e88fbfd4f2e0fb 100644 --- a/Mathlib/FieldTheory/SeparablyGenerated.lean +++ b/Mathlib/FieldTheory/SeparablyGenerated.lean @@ -123,7 +123,6 @@ theorem coeff_toPolynomialAdjoinImageCompl_ne_zero simp_rw [← H, ← AlgHom.comp_apply] congr; ext; simp -set_option backward.isDefEq.respectTransparency false in theorem isAlgebraic_of_mem_vars_of_forall_totalDegree_le (hFa : F.aeval a = 0) (i : ι) (hi : i ∈ F.vars) : IsAlgebraic (Algebra.adjoin k (a '' {i}ᶜ)) (a i) := by classical @@ -186,7 +185,6 @@ variable [ExpChar k p] include hp H -set_option backward.isDefEq.respectTransparency false in /-- Suppose `k` has chararcteristic `p` and `a₁,...,aₙ` is a transcendental basis of `K/k`. Suppose furthermore that if `{ sᵢ } ⊆ K` is an arbitrary `k`-linearly independent set, @@ -236,7 +234,6 @@ lemma exists_isTranscendenceBasis_and_isSeparable_of_linearIndepOn_pow (by simpa using hF₂irr.ne_zero), zero_mul, eq_comm, Polynomial.coeff_map, map_eq_zero_iff _ (FaithfulSMul.algebraMap_injective ..)] at eq -set_option backward.isDefEq.respectTransparency false in lemma exists_isTranscendenceBasis_and_isSeparable_of_linearIndepOn_pow' (s : Set ι) (n : ι) (ha : IsTranscendenceBasis k fun i : s ↦ a i) (hn : n ∉ s) : ∃ i : ι, IsTranscendenceBasis k (fun j : ↥(insert n s \ {i}) ↦ a j) ∧ @@ -250,7 +247,6 @@ lemma exists_isTranscendenceBasis_and_isSeparable_of_linearIndepOn_pow' have : a '' (insert n s \ {i.1}) = (a ·.1) '' {i}ᶜ := by ext; aesop refine ⟨i, hi.comp_equiv e₂.symm, by convert hi'⟩ -set_option backward.isDefEq.respectTransparency false in /-- Suppose `k` has chararcteristic `p` and `K/k` is generated by `a₁,...,aₙ₊₁`, where `a₁,...aₙ` forms a transcendental basis. @@ -274,7 +270,6 @@ lemma exists_isTranscendenceBasis_and_isSeparable_of_linearIndepOn_pow_of_adjoin · exact hi.2 · exact isSeparable_algebraMap (F := adjoin k (a '' {i}ᶜ)) ⟨_, subset_adjoin _ _ ⟨x, ne, rfl⟩⟩ -set_option backward.isDefEq.respectTransparency false in /-- Suppose `k` has chararcteristic `p` and `K/k` is finitely generated. Suppose furthermore that if `{ sᵢ } ⊆ K` is an arbitrary `k`-linearly independent set, @@ -305,7 +300,6 @@ lemma exists_isTranscendenceBasis_and_isSeparable_of_linearIndepOn_pow_of_essFin end -set_option backward.isDefEq.respectTransparency false in variable (k K) in /-- Any finitely generated extension over perfect fields are separably generated. -/ lemma exists_isTranscendenceBasis_and_isSeparable_of_perfectField diff --git a/Mathlib/FieldTheory/SplittingField/IsSplittingField.lean b/Mathlib/FieldTheory/SplittingField/IsSplittingField.lean index b8d7c80a3bbe04..0f31d6e1ed6b54 100644 --- a/Mathlib/FieldTheory/SplittingField/IsSplittingField.lean +++ b/Mathlib/FieldTheory/SplittingField/IsSplittingField.lean @@ -157,7 +157,6 @@ open Polynomial variable {K L} [Field K] [Field L] [Algebra K L] {p : K[X]} {F : IntermediateField K L} -set_option backward.isDefEq.respectTransparency false in theorem IntermediateField.splits_of_splits (h : (p.map (algebraMap K L)).Splits) (hF : ∀ x ∈ p.rootSet L, x ∈ F) : (p.map (algebraMap K F)).Splits := by classical @@ -172,7 +171,6 @@ theorem IntermediateField.splits_iff_mem (h : (p.map (algebraMap K L)).Splits) : rw [← hF.image_rootSet F.val, Set.forall_mem_image] exact fun x _ ↦ x.2 -set_option backward.isDefEq.respectTransparency false in theorem IsIntegral.mem_intermediateField_of_minpoly_splits {x : L} (int : IsIntegral K x) {F : IntermediateField K L} (h : Splits ((minpoly K x).map (algebraMap K F))) : x ∈ F := by rw [← F.fieldRange_val]; exact int.mem_range_algebraMap_of_minpoly_splits h diff --git a/Mathlib/Geometry/Euclidean/PerpBisector.lean b/Mathlib/Geometry/Euclidean/PerpBisector.lean index 63dcafb27c3c4d..edf5f73730f982 100644 --- a/Mathlib/Geometry/Euclidean/PerpBisector.lean +++ b/Mathlib/Geometry/Euclidean/PerpBisector.lean @@ -108,7 +108,6 @@ theorem perpBisector_comm (p₁ p₂ : P) : perpBisector p₁ p₂ = perpBisecto @[simp] theorem left_mem_perpBisector : p₁ ∈ perpBisector p₁ p₂ ↔ p₁ = p₂ := by rw [perpBisector_comm, right_mem_perpBisector, eq_comm] -set_option backward.isDefEq.respectTransparency false in @[simp] theorem perpBisector_self (p : P) : perpBisector p p = ⊤ := top_unique fun _ ↦ by simp [mem_perpBisector_iff_inner_eq_inner] diff --git a/Mathlib/Geometry/Euclidean/Projection.lean b/Mathlib/Geometry/Euclidean/Projection.lean index 6e1b28c0ffc256..5d3ef7739b6681 100644 --- a/Mathlib/Geometry/Euclidean/Projection.lean +++ b/Mathlib/Geometry/Euclidean/Projection.lean @@ -244,7 +244,6 @@ lemma orthogonalProjection_eq_orthogonalProjection_iff_vsub_mem {s : AffineSubsp (vsub_orthogonalProjection_mem_direction_orthogonal s q)] simp -set_option backward.isDefEq.respectTransparency false in /-- If the orthogonal projections of a point onto two subspaces are equal, so is the projection onto their supremum. -/ lemma orthogonalProjection_sup_of_orthogonalProjection_eq {s₁ s₂ : AffineSubspace 𝕜 P} [Nonempty s₁] diff --git a/Mathlib/Geometry/Euclidean/Sphere/Basic.lean b/Mathlib/Geometry/Euclidean/Sphere/Basic.lean index 75c4b7025b68df..bc585fd005ade0 100644 --- a/Mathlib/Geometry/Euclidean/Sphere/Basic.lean +++ b/Mathlib/Geometry/Euclidean/Sphere/Basic.lean @@ -9,6 +9,7 @@ public import Mathlib.Analysis.Convex.StrictConvexBetween public import Mathlib.Analysis.InnerProductSpace.Convex public import Mathlib.Analysis.Normed.Affine.Convex public import Mathlib.Geometry.Euclidean.Basic +public import Mathlib.Geometry.Euclidean.Projection /-! # Spheres @@ -177,12 +178,34 @@ theorem cospherical_singleton (p : P) : Cospherical ({p} : Set P) := by use p simp +/-- If `ps` is cospherical, then any of its isometric images is cospherical. -/ +theorem _root_.Isometry.cospherical {E F : Type*} [MetricSpace E] [MetricSpace F] {f : E → F} + (hf : Isometry f) {ps : Set E} (hps : Cospherical ps) : Cospherical (f '' ps) := by + rcases hps with ⟨c, r, hc⟩ + refine ⟨f c, r, ?_⟩ + rintro _ ⟨p, hp, rfl⟩ + rw [hf.dist_eq, hc p hp] + end MetricSpace section NormedSpace variable [NormedAddCommGroup V] [NormedSpace ℝ V] [MetricSpace P] [NormedAddTorsor V P] +/-- If a set of points is cospherical, then its image under the inclusion of any affine subspace +containing it is cospherical. -/ +theorem Cospherical.inclusion {S₁ S₂ : AffineSubspace ℝ P} [Nonempty S₁] {ps : Set S₁} + (hps : Cospherical ps) (hS : S₁ ≤ S₂) : + Cospherical (AffineSubspace.inclusion hS '' ps) := by + refine Isometry.cospherical ?_ hps + exact S₁.subtypeₐᵢ.isometry + +/-- If a set of points in an affine subspace is cospherical, then its image under the coercion +to the ambient space is cospherical. -/ +theorem Cospherical.subtype_val {S : AffineSubspace ℝ P} [Nonempty S] {ps : Set S} + (hps : Cospherical ps) : Cospherical (Subtype.val '' ps) := + Isometry.cospherical S.subtypeₐᵢ.isometry hps + lemma Sphere.nonempty_iff [Nontrivial V] {s : Sphere P} : (s : Set P).Nonempty ↔ 0 ≤ s.radius := by refine ⟨fun ⟨p, hp⟩ ↦ radius_nonneg_of_mem hp, fun h ↦ ?_⟩ obtain ⟨v, hv⟩ := (NormedSpace.sphere_nonempty (x := (0 : V)) (r := s.radius)).2 h @@ -323,6 +346,32 @@ section EuclideanSpace variable [NormedAddCommGroup V] [InnerProductSpace ℝ V] [MetricSpace P] [NormedAddTorsor V P] +/-- A set of points in an affine subspace is cospherical if and only if its image in the ambient +space is cospherical. -/ +@[simp] +theorem Cospherical.subtype_val_iff {S : AffineSubspace ℝ P} [Nonempty S] + [S.direction.HasOrthogonalProjection] {ps : Set S} : + Cospherical (Subtype.val '' ps) ↔ Cospherical ps := by + refine ⟨fun h => ?_, Cospherical.subtype_val⟩ + rcases ps.eq_empty_or_nonempty with rfl | ⟨p₀, hp₀⟩ + · exact cospherical_empty + · rcases h with ⟨c, r, hr⟩ + let c' : S := orthogonalProjection S c + refine ⟨c', dist p₀ c', fun p hp => ?_⟩ + have hp_dist : dist (p : P) c = r := by grind + have hp₀_dist : dist (p₀ : P) c = r := by grind + have hpp₀ : dist (p : P) (c : P) = dist (p₀ : P) (c : P) := hp_dist.trans hp₀_dist.symm + exact (dist_eq_iff_dist_orthogonalProjection_eq (s := S) (p₃ := c) p.2 p₀.2).1 hpp₀ + +/-- A set of points is cospherical in an affine subspace `S₁` if and only if its image under the +inclusion into a larger affine subspace `S₂` is cospherical. -/ +theorem Cospherical.inclusion_iff {S₁ S₂ : AffineSubspace ℝ P} [Nonempty S₁] {ps : Set S₁} + [S₁.direction.HasOrthogonalProjection] [S₂.direction.HasOrthogonalProjection] (hS : S₁ ≤ S₂) : + Cospherical (AffineSubspace.inclusion hS '' ps) ↔ Cospherical ps := by + haveI : Nonempty S₂ := by obtain ⟨p⟩ := ‹Nonempty S₁›;exact ⟨⟨p, hS p.property⟩⟩ + simp [(Cospherical.subtype_val_iff (S := S₂) (ps := AffineSubspace.inclusion hS '' ps)).symm, + Set.image_image] + /-- Any three points in a cospherical set are affinely independent. -/ theorem Cospherical.affineIndependent {s : Set P} (hs : Cospherical s) {p : Fin 3 → P} (hps : Set.range p ⊆ s) (hpi : Function.Injective p) : AffineIndependent ℝ p := by diff --git a/Mathlib/Geometry/Euclidean/Sphere/OrthRadius.lean b/Mathlib/Geometry/Euclidean/Sphere/OrthRadius.lean index 9cef31d3336187..76e3d522805c60 100644 --- a/Mathlib/Geometry/Euclidean/Sphere/OrthRadius.lean +++ b/Mathlib/Geometry/Euclidean/Sphere/OrthRadius.lean @@ -63,7 +63,6 @@ lemma mem_orthRadius_iff_inner_right {s : Sphere P} {p x : P} : rw [mem_orthRadius_iff_inner_left, ← neg_vsub_eq_vsub_rev, inner_neg_left] simp -set_option backward.isDefEq.respectTransparency false in lemma orthRadius_le_orthRadius_iff {s : Sphere P} {p q : P} : s.orthRadius p ≤ s.orthRadius q ↔ p = q ∨ q = s.center := by refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ diff --git a/Mathlib/Geometry/Euclidean/Sphere/Power.lean b/Mathlib/Geometry/Euclidean/Sphere/Power.lean index 08374c4c739fae..83636119d4a2c9 100644 --- a/Mathlib/Geometry/Euclidean/Sphere/Power.lean +++ b/Mathlib/Geometry/Euclidean/Sphere/Power.lean @@ -5,10 +5,13 @@ Authors: Manuel Candales, Benjamin Davidson, Li Jiale -/ module + public import Mathlib.Geometry.Euclidean.Angle.Unoriented.Affine -public import Mathlib.Geometry.Euclidean.Sphere.Basic public import Mathlib.Geometry.Euclidean.Sphere.Tangent +import Mathlib.Geometry.Euclidean.Angle.Sphere +import Mathlib.Geometry.Euclidean.Similarity + /-! # Power of a point (intersecting chords and secants) @@ -30,9 +33,7 @@ secants) in spheres in real inner product spaces and Euclidean affine spaces. @[expose] public section -open Real - -open EuclideanGeometry RealInnerProductSpace Real +open Real EuclideanGeometry RealInnerProductSpace Real Module FiniteDimensional variable {V : Type*} [NormedAddCommGroup V] [InnerProductSpace ℝ V] @@ -120,6 +121,88 @@ theorem mul_dist_eq_mul_dist_of_cospherical_of_angle_eq_pi {a b c d p : P} rw [EuclideanGeometry.angle_eq_pi_iff_sbtw] at hapb hcpd exact mul_dist_eq_mul_dist_of_cospherical h hapb.wbtw.mem_affineSpan hcpd.wbtw.mem_affineSpan +private lemma cospherical_of_mul_dist_eq_mul_dist_of_angle_eq_pi_aux + [Fact (finrank ℝ V = 2)] [Oriented ℝ V (Fin 2)] {p₁ p₂ p₃ p₄ p : P} + (h : dist p₁ p * dist p₂ p = dist p₃ p * dist p₄ p) + (hp₁p₂ : ∠ p₁ p p₂ = π) (hp₃p₄ : ∠ p₃ p p₄ = π) (hn : ¬ Collinear ℝ ({p₁, p, p₃} : Set P)) : + Cospherical ({p₁, p₂, p₃, p₄} : Set P) := by + suffices h_equiv : Cospherical ({p₁, p₂, p₄, p₃} : Set P) by grind [Set.pair_comm p₄ p₃] + have h_angle_eq : ∠ p₁ p p₄ = ∠ p₃ p p₂ := by + grind [angle_comm, angle_eq_angle_of_angle_eq_pi_of_angle_eq_pi hp₃p₄] + rw [angle_eq_pi_iff_sbtw] at hp₁p₂ hp₃p₄ + have hcol_p₁pp₂ := hp₁p₂.wbtw.collinear + have hcol_p₃pp₄ := hp₃p₄.wbtw.collinear + have h_notcol_p₁p₂p₃ : ¬ Collinear ℝ ({p₁, p₂, p₃} : Set P) := by + have : AffineIndependent ℝ ![p₁, p, p₃] := affineIndependent_iff_not_collinear_set.mpr hn + rw [← affineIndependent_iff_not_collinear_set] + grind [hp₁p₂.left_ne_right, affineIndependent_of_affineIndependent_collinear_ne, + AffineIndependent.comm_left, AffineIndependent.comm_right] + apply cospherical_of_two_zsmul_oangle_eq_of_not_collinear ?_ h_notcol_p₁p₂p₃ + suffices ∡ p₁ p₂ p₃ = ∡ p₁ p₄ p₃ by grind + suffices ∠ p₁ p₂ p₃ = ∠ p₁ p₄ p₃ by + grind [oangle_eq_of_angle_eq_of_sign_eq, Sbtw.oangle_sign_eq_of_sbtw] + rw [angle_comm, ← angle_eq_angle_of_angle_eq_pi p₃ hp₁p₂.angle₃₂₁_eq_pi, + ← angle_eq_angle_of_angle_eq_pi p₁ hp₃p₄.angle₃₂₁_eq_pi] + suffices h_sim : Similar ![p₁, p, p₄] ![p₃, p, p₂] by + grind [angle_comm, h_sim.angle_eq_all.right.left] + have h_notcol_p₁pp₄ : ¬ Collinear ℝ ({p₁, p, p₄} : Set P) := by + intro hcol + suffices hcol : Collinear ℝ ({p₁, p, p₃} : Set P) by grind + suffices hcol : Collinear ℝ ({p₁, p₃, p, p₄} : Set P) by grind [Collinear.subset _ hcol] + have hne_pp₄ := hp₃p₄.ne_right + grind [collinear_insert_insert_of_mem_affineSpan_pair, Collinear.mem_affineSpan_of_mem_of_ne] + have h_notcol_p₃pp₂ : ¬ Collinear ℝ ({p₃, p, p₂} : Set P) := by + intro hcol + suffices hcol : Collinear ℝ ({p₁, p, p₃} : Set P) by grind + suffices hcol : Collinear ℝ ({p₃, p₁, p, p₂} : Set P) by grind [Collinear.subset _ hcol] + have hne_pp₂ := hp₁p₂.ne_right + grind [collinear_insert_insert_of_mem_affineSpan_pair, Collinear.mem_affineSpan_of_mem_of_ne] + apply similar_of_side_angle_side h_notcol_p₁pp₄ h_notcol_p₃pp₂ h_angle_eq ?_ + grind [dist_comm] + +/-- If `p` lies strictly between `p₁` and `p₂` on one line and strictly between `p₃` and `p₄` +on another line, and if `dist p₁ p * dist p₂ p = dist p₃ p * dist p₄ p`, +then the points `p₁`, `p₂`, `p₃`, and `p₄` are cospherical. -/ +theorem cospherical_of_mul_dist_eq_mul_dist_of_angle_eq_pi {p₁ p₂ p₃ p₄ p : P} + (h : dist p₁ p * dist p₂ p = dist p₃ p * dist p₄ p) + (hp₁p₂ : ∠ p₁ p p₂ = π) (hp₃p₄ : ∠ p₃ p p₄ = π) (hn : ¬ Collinear ℝ ({p₁, p, p₃} : Set P)) : + Cospherical ({p₁, p₂, p₃, p₄} : Set P) := by + have hp₁p₂_sbtw : Sbtw ℝ p₁ p p₂ := angle_eq_pi_iff_sbtw.mp hp₁p₂ + have hp₃p₄_sbtw : Sbtw ℝ p₃ p p₄ := angle_eq_pi_iff_sbtw.mp hp₃p₄ + have hindep : AffineIndependent ℝ ![p₁, p, p₃] := affineIndependent_iff_not_collinear_set.mpr hn + set t : Affine.Triangle ℝ P := ⟨_, hindep⟩ with ht + set S : AffineSubspace ℝ P := affineSpan ℝ (Set.range t.points) with hS + have hp₂ : p₂ ∈ S := by + suffices hmem : p₂ ∈ affineSpan ℝ {p₁, p} by exact affineSpan_mono ℝ (by simp [ht]; grind) hmem + simp [hp₁p₂_sbtw.wbtw.collinear.mem_affineSpan_of_mem_of_ne _ _ _ hp₁p₂_sbtw.left_ne] + have hp₄ : p₄ ∈ S := by + suffices hmem : p₄ ∈ affineSpan ℝ {p₃, p} by exact affineSpan_mono ℝ (by simp [ht]; grind) hmem + simp [hp₃p₄_sbtw.wbtw.collinear.mem_affineSpan_of_mem_of_ne _ _ _ hp₃p₄_sbtw.left_ne] + let s_isom : AffineIsometry ℝ S P := S.subtypeₐᵢ + let p₁' : S := ⟨p₁, mem_affineSpan ℝ (s := Set.range t.points) (by aesop)⟩ + let p' : S := ⟨p, mem_affineSpan ℝ (s := Set.range t.points) (by aesop)⟩ + let p₃' : S := ⟨p₃, mem_affineSpan ℝ (s := Set.range t.points) (by aesop)⟩ + let p₂' : S := ⟨p₂, hp₂⟩ + let p₄' : S := ⟨p₄, hp₄⟩ + have h_dist' : dist p₁' p' * dist p₂' p' = dist p₃' p' * dist p₄' p' := by + simpa [dist_eq_norm_vsub, ← s_isom.dist_map] using h + have hp₁'p₂' : ∠ p₁' p' p₂' = π := by simpa [AffineIsometry.angle_map s_isom] + have hp₃'p₄' : ∠ p₃' p' p₄' = π := by simpa [AffineIsometry.angle_map s_isom] + suffices h_cospherical' : Cospherical {p₁', p₂', p₃', p₄'} by + have h_cosp := Cospherical.subtype_val h_cospherical' + grind [Set.image_insert_eq, Set.image_singleton] + have hf2 : Fact (finrank ℝ S.direction = 2) := ⟨by + rw [hS, direction_affineSpan, t.independent.finrank_vectorSpan] + simp⟩ + letI : Module.Oriented ℝ S.direction (Fin 2) := + ⟨Basis.orientation (finBasisOfFinrankEq _ _ hf2.out)⟩ + have hncol : ¬ Collinear ℝ {p₁', p', p₃'} := by + rw [← affineIndependent_iff_not_collinear_set, + ← s_isom.toAffineMap.affineIndependent_iff s_isom.injective] + convert hindep + ext i; fin_cases i <;> rfl + exact cospherical_of_mul_dist_eq_mul_dist_of_angle_eq_pi_aux h_dist' hp₁'p₂' hp₃'p₄' hncol + /-- **Intersecting Secants Theorem**. -/ theorem mul_dist_eq_mul_dist_of_cospherical_of_angle_eq_zero {a b c d p : P} (h : Cospherical ({a, b, c, d} : Set P)) (hab : a ≠ b) (hcd : c ≠ d) (hapb : ∠ a p b = 0) diff --git a/Mathlib/Geometry/Euclidean/Sphere/Tangent.lean b/Mathlib/Geometry/Euclidean/Sphere/Tangent.lean index 8f90d7f3110b2f..a8b67bfb4325b9 100644 --- a/Mathlib/Geometry/Euclidean/Sphere/Tangent.lean +++ b/Mathlib/Geometry/Euclidean/Sphere/Tangent.lean @@ -86,7 +86,6 @@ lemma IsTangentAt.eq_of_isTangentAt {s : Sphere P} {p q : P} {as : AffineSubspac ← inner_sub_right, vsub_sub_vsub_cancel_right] at hqp simpa using hqp -set_option backward.isDefEq.respectTransparency false in lemma isTangentAt_center_iff {s : Sphere P} {as : AffineSubspace ℝ P} : s.IsTangentAt s.center as ↔ s.radius = 0 ∧ s.center ∈ as := by refine ⟨?_, ?_⟩ diff --git a/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean b/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean index 3a619b3a85bc8b..1a54a44b0301dc 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean @@ -6,12 +6,22 @@ Authors: Sébastien Gouëzel, Floris van Doorn module public import Mathlib.Geometry.Manifold.ContMDiff.Basic +import Mathlib.Geometry.Manifold.ContMDiff.NormedSpace /-! -## Smoothness of charts and local structomorphisms +# Smoothness of charts and local structomorphisms We show that the model with corners, charts, extended charts and their inverses are `C^n`, and that local structomorphisms are `C^n` with `C^n` inverses. + +## Implementation notes + +This file uses the name `writtenInExtend` (in analogy to `writtenInExtChart`) to refer to a +composition `ψ.extend J ∘ f ∘ φ.extend I` of `f : M → N` with charts `ψ` and `φ` extended by the +appropriate models with corners. This is not a definition, so technically deviating from the naming +convention. + +`isLocalStructomorphOn` is another made-up name. -/ assert_not_exists mfderiv @@ -80,6 +90,10 @@ theorem contMDiffAt_extend {x : M} (he : e ∈ maximalAtlas I n M) (hx : x ∈ e ContMDiffAt I 𝓘(𝕜, E) n (e.extend I) x := (contMDiff_model _).comp x <| contMDiffAt_of_mem_maximalAtlas he hx +theorem contMDiffOn_extend (he : e ∈ maximalAtlas I n M) : + ContMDiffOn I 𝓘(𝕜, E) n (e.extend I) e.source := + fun _x' hx' ↦ (contMDiffAt_extend he hx').contMDiffWithinAt + theorem contMDiffAt_extChartAt' {x' : M} (h : x' ∈ (chartAt H x).source) : ContMDiffAt I 𝓘(𝕜, E) n (extChartAt I x) x' := contMDiffAt_extend (chart_mem_maximalAtlas x) h @@ -291,3 +305,35 @@ theorem isLocalStructomorphOn_contDiffGroupoid_iff (f : OpenPartialHomeomorph M · simp only [c, c', hx', mfld_simps] end IsLocalStructomorph + +variable {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] {G : Type*} [TopologicalSpace G] + {J : ModelWithCorners 𝕜 F G} {N : Type*} [TopologicalSpace N] [ChartedSpace G N] + {n : WithTop ℕ∞} + [IsManifold I n M] [IsManifold J n N] {f : M → N} {s : Set M} + {φ : OpenPartialHomeomorph M H} {ψ : OpenPartialHomeomorph N G} + +/-- This is a smooth analogue of `OpenPartialHomeomorph.continuousWithinAt_writtenInExtend_iff`. -/ +theorem OpenPartialHomeomorph.contMDiffWithinAt_writtenInExtend_iff {y : M} + (hφ : φ ∈ maximalAtlas I n M) (hψ : ψ ∈ maximalAtlas J n N) + (hy : y ∈ φ.source) (hgy : f y ∈ ψ.source) (hmaps : MapsTo f s ψ.source) : + ContMDiffWithinAt 𝓘(𝕜, E) 𝓘(𝕜, F) n (ψ.extend J ∘ f ∘ (φ.extend I).symm) + ((φ.extend I).symm ⁻¹' s ∩ range I) (φ.extend I y) ↔ ContMDiffWithinAt I J n f s y := by + rw [contMDiffWithinAt_iff_of_mem_maximalAtlas hφ hψ hy hgy] + refine ⟨fun h ↦ ⟨?_, ?_⟩, fun h ↦ ?_⟩ + · rw [← φ.continuousWithinAt_writtenInExtend_iff (I := I) (I' := J) hy hgy hmaps] + exact h.continuousWithinAt + · rwa [← contMDiffWithinAt_iff_contDiffWithinAt] + · rw [contMDiffWithinAt_iff_contDiffWithinAt] + exact h.2 + +theorem OpenPartialHomeomorph.contMDiffOn_writtenInExtend_iff + (hφ : φ ∈ maximalAtlas I n M) (hψ : ψ ∈ maximalAtlas J n N) + (hs : s ⊆ φ.source) (hmaps : MapsTo f s ψ.source) : + ContMDiffOn 𝓘(𝕜, E) 𝓘(𝕜, F) n (ψ.extend J ∘ f ∘ (φ.extend I).symm) (φ.extend I '' s) ↔ + ContMDiffOn I J n f s := by + refine forall_mem_image.trans <| forall₂_congr fun x hx ↦ ?_ + refine (contMDiffWithinAt_congr_set ?_).trans + (contMDiffWithinAt_writtenInExtend_iff hφ hψ (hs hx) (hmaps hx) hmaps) + rw [← nhdsWithin_eq_iff_eventuallyEq, ← φ.map_extend_nhdsWithin_eq_image_of_subset, + ← φ.map_extend_nhdsWithin] + exacts [hs hx, hs hx, hs] diff --git a/Mathlib/Geometry/Manifold/Immersion.lean b/Mathlib/Geometry/Manifold/Immersion.lean index bb391c1512ba60..a619f189b62a52 100644 --- a/Mathlib/Geometry/Manifold/Immersion.lean +++ b/Mathlib/Geometry/Manifold/Immersion.lean @@ -405,11 +405,7 @@ lemma of_opens [IsManifold I n M] (s : TopologicalSpace.Opens M) (y : s) : (chart_mem_maximalAtlas y) (chart_mem_maximalAtlas y.val) intro x hx suffices I ((chartAt H ↑y) ((chartAt H y).symm (I.symm x))) = x by simpa +contextual - trans I (I.symm x) - · congr 1 - apply OpenPartialHomeomorph.right_inv - simp_all - · exact I.right_inv (by simp_all) + simp_all @[deprecated (since := "2025-12-16")] alias ofOpen := of_opens diff --git a/Mathlib/Geometry/Manifold/IsManifold/ExtChartAt.lean b/Mathlib/Geometry/Manifold/IsManifold/ExtChartAt.lean index 433adde6685619..9e0d9e9e42088a 100644 --- a/Mathlib/Geometry/Manifold/IsManifold/ExtChartAt.lean +++ b/Mathlib/Geometry/Manifold/IsManifold/ExtChartAt.lean @@ -40,6 +40,15 @@ in general, but we can still register them as `PartialEquiv`s. * `FiniteDimensional.of_locallyCompact_manifold`: a locally compact manifold must be modelled on a finite-dimensional space +## Implementation notes + +This file uses the name `writtenInExtend` (in analogy to `writtenInExtChart`) to refer to a +composition `ψ.extend J ∘ f ∘ φ.extend I` of `f : M → N` with charts `ψ` and `φ` extended by the +appropriate models with corners. This is not a definition, so technically deviating from the naming +convention. + +TODO: this file uses more made-up names; document these as well + -/ @[expose] public section @@ -85,6 +94,9 @@ theorem extend_target : (f.extend I).target = I.symm ⁻¹' f.target ∩ range I theorem extend_target' : (f.extend I).target = I '' f.target := by rw [extend, PartialEquiv.trans_target'', I.source_eq, univ_inter, I.toPartialEquiv_coe] +theorem extend_target_eq_image_source : (f.extend I).target = (f.extend I) '' f.source := by + rw [f.extend_target', ← f.image_source_eq_target, ← image_comp, f.extend_coe] + lemma isOpen_extend_target [I.Boundaryless] : IsOpen (f.extend I).target := by rw [extend_target, I.range_eq_univ, inter_univ] exact I.continuous_symm.isOpen_preimage _ f.open_target @@ -242,7 +254,6 @@ theorem tendsto_extend_comp_iff {α : Type*} {l : Filter α} {g : α → M} filter_upwards [hg, mem_map.1 (this hu)] with z hz hzu simpa only [(· ∘ ·), extend_left_inv _ hz, mem_preimage] using hzu --- there is no definition `writtenInExtend` but we already use some made-up names in this file theorem continuousWithinAt_writtenInExtend_iff {f' : OpenPartialHomeomorph M' H'} {g : M → M'} {y : M} (hy : y ∈ f.source) (hgy : g y ∈ f'.source) (hmaps : MapsTo g s f'.source) : ContinuousWithinAt (f'.extend I' ∘ g ∘ (f.extend I).symm) @@ -256,8 +267,6 @@ theorem continuousWithinAt_writtenInExtend_iff {f' : OpenPartialHomeomorph M' H' rw [comp_apply, extend_left_inv _ hz.2] exact hmaps hz.1 --- there is no definition `writtenInExtend` but we already use some made-up names in this file - /-- If `s ⊆ f.source` and `g x ∈ f'.source` whenever `x ∈ s`, then `g` is continuous on `s` if and only if `g` written in charts `f.extend I` and `f'.extend I'` is continuous on `f.extend I '' s`. -/ theorem continuousOn_writtenInExtend_iff {f' : OpenPartialHomeomorph M' H'} {g : M → M'} diff --git a/Mathlib/Geometry/Manifold/VectorBundle/CovariantDerivative/Basic.lean b/Mathlib/Geometry/Manifold/VectorBundle/CovariantDerivative/Basic.lean index 92e72d33cf3a41..f91202ea2fd00f 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/CovariantDerivative/Basic.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/CovariantDerivative/Basic.lean @@ -258,7 +258,6 @@ lemma _root_.ContMDiffCovariantDerivativeOn.affine_combination [IsManifold I 1 M · exact hf.smul_section <| Hcov.contMDiff hσ · exact (contMDiffOn_const.sub hf).smul_section <| Hcov'.contMDiff hσ -set_option backward.isDefEq.respectTransparency false in /-- A finite affine combination of covariant derivatives is a covariant derivative. -/ lemma finite_affine_combination {ι : Type*} {s : Finset ι} {u : Set M} {cov : ι → (Π x : M, V x) → (Π x : M, TangentSpace I x →L[𝕜] V x)} diff --git a/Mathlib/Geometry/Manifold/VectorBundle/CovariantDerivative/Torsion.lean b/Mathlib/Geometry/Manifold/VectorBundle/CovariantDerivative/Torsion.lean new file mode 100644 index 00000000000000..3b5f2fe1b20afb --- /dev/null +++ b/Mathlib/Geometry/Manifold/VectorBundle/CovariantDerivative/Torsion.lean @@ -0,0 +1,158 @@ +/- +Copyright (c) 2025 Patrick Massot. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Patrick Massot, Michael Rothgang, Heather Macbeth +-/ +module + +public import Mathlib.Topology.FiberBundle.Basic +public import Mathlib.Geometry.Manifold.VectorBundle.CovariantDerivative.Basic +public import Mathlib.Geometry.Manifold.VectorField.LieBracket + +/-! # Torsion of an affine connection + +We define the torsion tensor of an affine connection, i.e. a covariant derivative on the tangent +bundle `TM` of some manifold `M`. + +## Main definitions and results + +* `IsCovariantDerivativeOn.torsion`: the torsion tensor of an unbundled covariant derivative + on `TM` +* `CovariantDerivative.torsion`: the torsion tensor of a bundled covariant derivative on `TM` +* `CovariantDerivative.torsion_eq_zero_iff`: the torsion tensor of a bundled covariant derivative + `∇` vanishes if and only if `∇_X Y - ∇_Y X = [X, Y]` for all differentiable vector fields + `X` and `Y`. + +-/ + +public noncomputable section + +open Bundle Set NormedSpace FiberBundle +open scoped Manifold ContDiff + +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] + {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] + {H : Type*} [TopologicalSpace H] {I : ModelWithCorners 𝕜 E H} + {M : Type*} [TopologicalSpace M] [ChartedSpace H M] {x : M} + +/-! ## Torsion tensor of an unbundled covariant derivative on `TM` on a set `s` -/ +namespace IsCovariantDerivativeOn + +/-- The torsion of a covariant derivative on the tangent bundle `TM`, as a bare function. +Prefer to use `IsCovariantDerivativeOn.torsion` (which is a 2-tensor) instead. -/ +private def torsionAux + (cov : (Π x : M, TangentSpace I x) → (Π x : M, TangentSpace I x →L[𝕜] TangentSpace I x)) : + (Π x : M, TangentSpace I x) → (Π x : M, TangentSpace I x) → (Π x : M, TangentSpace I x) := + fun X Y x ↦ cov Y x (X x) - cov X x (Y x) - VectorField.mlieBracket I X Y x + +variable [IsManifold I 2 M] [CompleteSpace E] + {cov cov' : (Π x : M, TangentSpace I x) → (Π x : M, TangentSpace I x →L[𝕜] TangentSpace I x)} + {X X' Y : Π x : M, TangentSpace I x} + +private theorem torsionAux_tensorial₁ (hcov : IsCovariantDerivativeOn E cov) (x : M) + (Y : Π x, TangentSpace I x) : + TensorialAt I E (torsionAux cov · Y x) x where + smul hf hX := by + simp [torsionAux, hcov.leibniz hX hf, VectorField.mlieBracket_smul_left hf hX] + module + add hX hX' := by + simp [torsionAux, hcov.add hX hX', VectorField.mlieBracket_add_left hX hX'] + module + +private theorem torsionAux_tensorial₂ (hcov : IsCovariantDerivativeOn E cov) (x : M) + (X : Π x, TangentSpace I x) : + TensorialAt I E (torsionAux cov X · x) x where + smul hf hY := by + simp [torsionAux, hcov.leibniz hY hf, VectorField.mlieBracket_smul_right hf hY] + module + add hY hY' := by + simp [torsionAux, hcov.add hY hY', VectorField.mlieBracket_add_right hY hY'] + module + +variable [CompleteSpace 𝕜] [FiniteDimensional 𝕜 E] + +/-- The torsion tensor of an unbundled covariant derivative on `TM`. -/ +noncomputable def torsion (hcov : IsCovariantDerivativeOn E cov univ) (x : M) : + TangentSpace I x →L[𝕜] TangentSpace I x →L[𝕜] TangentSpace I x := + TensorialAt.mkHom₂ (torsionAux cov · · x) _ + (fun τ _ ↦ hcov.torsionAux_tensorial₁ x τ) + (fun σ _ ↦ hcov.torsionAux_tensorial₂ x σ) + +theorem torsion_apply (hcov : IsCovariantDerivativeOn E cov univ) {x} + {X : Π x : M, TangentSpace I x} (hX : MDiffAt (T% X) x) + {Y : Π x : M, TangentSpace I x} (hY : MDiffAt (T% Y) x) : + torsion hcov x (X x) (Y x) = cov Y x (X x) - cov X x (Y x) - VectorField.mlieBracket I X Y x := + TensorialAt.mkHom₂_apply _ _ hX hY + +theorem torsion_apply_eq_extend (hcov : IsCovariantDerivativeOn E cov univ) {x} + (X₀ Y₀ : TangentSpace I x) : + torsion hcov x X₀ Y₀ = + cov (extend E Y₀) x X₀ - cov (extend E X₀) x Y₀ - + VectorField.mlieBracket I (extend E X₀) (extend E Y₀) x := by + simp [torsion, torsionAux, TensorialAt.mkHom₂_apply_eq_extend] + +variable (X) in +@[simp] +lemma torsion_self (hcov : IsCovariantDerivativeOn E cov univ) (X₀ : TangentSpace I x) : + hcov.torsion x X₀ X₀ = 0 := by + simp [torsion_apply_eq_extend] + +variable (X Y) in +lemma torsion_antisymm (hcov : IsCovariantDerivativeOn E cov univ) (X₀ Y₀ : TangentSpace I x) : + hcov.torsion x X₀ Y₀ = - hcov.torsion x Y₀ X₀ := by + simp only [torsion_apply_eq_extend, neg_sub] + rw [VectorField.mlieBracket_swap] + dsimp + module + +end IsCovariantDerivativeOn + +/-! ## Torsion tensor of a bundled covariant derivative on `TM` -/ +namespace CovariantDerivative + +open VectorField + +variable [CompleteSpace 𝕜] [CompleteSpace E] [FiniteDimensional 𝕜 E] [IsManifold I 2 M] + (cov : CovariantDerivative I E (TangentSpace I : M → Type _)) + {X Y : Π x : M, TangentSpace I x} + +/-- The torsion tensor of a covariant derivative on the tangent bundle of a manifold. -/ +def torsion (x : M) : TangentSpace I x →L[𝕜] TangentSpace I x →L[𝕜] TangentSpace I x := + cov.isCovariantDerivativeOn.torsion x + +lemma torsion_apply (hX : MDiffAt (T% X) x) (hY : MDiffAt (T% Y) x) : + cov.torsion x (X x) (Y x) = cov Y x (X x) - cov X x (Y x) - mlieBracket I X Y x := by + unfold torsion IsCovariantDerivativeOn.torsion + apply TensorialAt.mkHom₂_apply + exacts [hX, hY] + +lemma torsion_apply_eq_extend (X₀ Y₀ : TangentSpace I x) : + cov.torsion x X₀ Y₀ = + cov (extend E Y₀) x (extend E X₀ x) - cov (extend E X₀) x (extend E Y₀ x) - + mlieBracket I (extend E X₀) (extend E Y₀) x := by + unfold torsion IsCovariantDerivativeOn.torsion + apply TensorialAt.mkHom₂_apply_eq_extend + +@[simp] +lemma torsion_self (X₀ : TangentSpace I x) : cov.torsion x X₀ X₀ = 0 := + cov.isCovariantDerivativeOn.torsion_self .. + +lemma torsion_antisymm (X₀ Y₀ : TangentSpace I x) : cov.torsion x X₀ Y₀ = - cov.torsion x Y₀ X₀ := + cov.isCovariantDerivativeOn.torsion_antisymm .. + +lemma torsion_eq_zero_iff : cov.torsion = 0 ↔ + ∀ {X Y x}, MDiffAt (T% X) x → MDiffAt (T% Y) x → + cov Y x (X x) - cov X x (Y x) = mlieBracket I X Y x := by + constructor + · intro h X Y x hX hY + replace h := congr($h x (X x) (Y x)) + rw [cov.torsion_apply hX hY] at h + simpa [sub_eq_iff_eq_add'] using h + · intro h + ext x u v + rw [torsion_apply_eq_extend, h] + · simp + · apply mdifferentiableAt_extend + · apply mdifferentiableAt_extend + +end CovariantDerivative diff --git a/Mathlib/Geometry/Manifold/VectorField/LieBracket.lean b/Mathlib/Geometry/Manifold/VectorField/LieBracket.lean index 4d40a03ef7721e..9974fb05fff614 100644 --- a/Mathlib/Geometry/Manifold/VectorField/LieBracket.lean +++ b/Mathlib/Geometry/Manifold/VectorField/LieBracket.lean @@ -29,7 +29,7 @@ The main results are the following: @[expose] public section -open Set Function Filter +open Set Function Filter NormedSpace open scoped Topology Manifold ContDiff noncomputable section @@ -361,7 +361,8 @@ lemma mlieBracketWithin_smul_right {f : M → 𝕜} (hf : MDiffAt[s] f x) (hW : MDiffAt[s] (fun x ↦ (W x : TangentBundle I M)) x) (hs : UniqueMDiffWithinAt I s x) : mlieBracketWithin I V (f • W) s x = - (mfderivWithin I 𝓘(𝕜) f s x) (V x) • (W x) + (f x) • mlieBracketWithin I V W s x := by + (fromTangentSpace (f x) (mfderiv[s] f x (V x))) • (W x) + + (f x) • mlieBracketWithin I V W s x := by simp only [mlieBracketWithin, mpullbackWithin_smul] -- Simplify local notation a bit. set V' := mpullbackWithin 𝓘(𝕜, E) I (extChartAt I x).symm V (range I) @@ -390,7 +391,9 @@ Product rule for Lie brackets: given two vector fields `V` and `W` on `M` and a -/ lemma mlieBracket_smul_right {f : M → 𝕜} (hf : MDiffAt f x) (hW : MDiffAt (fun x ↦ (W x : TangentBundle I M)) x) : - mlieBracket I V (f • W) x = (mfderiv% f x) (V x) • (W x) + (f x) • mlieBracket I V W x := by + mlieBracket I V (f • W) x = + (fromTangentSpace (f x) (mfderiv% f x (V x))) • (W x) + + (f x) • mlieBracket I V W x := by rw [← mdifferentiableWithinAt_univ] at hf hW rw [← mlieBracketWithin_univ, ← mfderivWithin_univ] exact mlieBracketWithin_smul_right hf hW (uniqueMDiffWithinAt_univ I) @@ -404,7 +407,8 @@ lemma mlieBracketWithin_smul_left {f : M → 𝕜} (hf : MDiffAt[s] f x) (hV : MDiffAt[s] (fun x ↦ (V x : TangentBundle I M)) x) (hs : UniqueMDiffWithinAt I s x) : mlieBracketWithin I (f • V) W s x = - -(mfderivWithin I 𝓘(𝕜) f s x) (W x) • (V x) + (f x) • mlieBracketWithin I V W s x := by + -(fromTangentSpace (f x) (mfderiv[s] f x (W x))) • (V x) + + (f x) • mlieBracketWithin I V W s x := by rw [mlieBracketWithin_swap, Pi.neg_apply, mlieBracketWithin_smul_right hf hV (V := W) hs, mlieBracketWithin_swap] simp; abel @@ -417,7 +421,8 @@ Product rule for Lie brackets: given two vector fields `V` and `W` on `M` and a lemma mlieBracket_smul_left {f : M → 𝕜} (hf : MDiffAt f x) (hV : MDiffAt (fun x ↦ (V x : TangentBundle I M)) x) : mlieBracket I (f • V) W x = - -(mfderiv% f x) (W x) • (V x) + (f x) • mlieBracket I V W x := by + - (fromTangentSpace (f x) (mfderiv% f x (W x))) • (V x) + + (f x) • mlieBracket I V W x := by rw [← mdifferentiableWithinAt_univ] at hf hV rw [← mlieBracketWithin_univ, ← mfderivWithin_univ] exact mlieBracketWithin_smul_left hf hV (uniqueMDiffWithinAt_univ I) diff --git a/Mathlib/GroupTheory/DoubleCoset.lean b/Mathlib/GroupTheory/DoubleCoset.lean index 3f01d1bf65f24c..5cd1e933b4211a 100644 --- a/Mathlib/GroupTheory/DoubleCoset.lean +++ b/Mathlib/GroupTheory/DoubleCoset.lean @@ -41,21 +41,21 @@ lemma doubleCoset_eq_image2 (a : α) (s t : Set α) : doubleCoset a s t = Set.image2 (· * a * ·) s t := by simp_rw [doubleCoset, Set.mul_singleton, ← Set.image2_mul, Set.image2_image_left] -theorem mem_doubleCoset {s t : Set α} {a b : α} : +lemma mem_doubleCoset {s t : Set α} {a b : α} : b ∈ doubleCoset a s t ↔ ∃ x ∈ s, ∃ y ∈ t, b = x * a * y := by simp only [doubleCoset_eq_image2, Set.mem_image2, eq_comm] -theorem mem_doubleCoset_self (H K : Subgroup G) (a : G) : a ∈ doubleCoset a H K := +lemma mem_doubleCoset_self (H K : Subgroup G) (a : G) : a ∈ doubleCoset a H K := mem_doubleCoset.mpr ⟨1, H.one_mem, 1, K.one_mem, (one_mul a).symm.trans (mul_one (1 * a)).symm⟩ -theorem doubleCoset_eq_of_mem {H K : Subgroup G} {a b : G} (hb : b ∈ doubleCoset a H K) : +lemma doubleCoset_eq_of_mem {H K : Subgroup G} {a b : G} (hb : b ∈ doubleCoset a H K) : doubleCoset b H K = doubleCoset a H K := by obtain ⟨h, hh, k, hk, rfl⟩ := mem_doubleCoset.1 hb rw [doubleCoset, doubleCoset, ← Set.singleton_mul_singleton, ← Set.singleton_mul_singleton, mul_assoc, mul_assoc, Subgroup.singleton_mul_subgroup hk, ← mul_assoc, ← mul_assoc, Subgroup.subgroup_mul_singleton hh] -theorem mem_doubleCoset_of_not_disjoint {H K : Subgroup G} {a b : G} +lemma mem_doubleCoset_of_not_disjoint {H K : Subgroup G} {a b : G} (h : ¬Disjoint (doubleCoset a H K) (doubleCoset b H K)) : b ∈ doubleCoset a H K := by rw [Set.not_disjoint_iff] at h simp only [mem_doubleCoset] at * @@ -63,7 +63,7 @@ theorem mem_doubleCoset_of_not_disjoint {H K : Subgroup G} {a b : G} refine ⟨y⁻¹ * l, H.mul_mem (H.inv_mem hy) hl, r * r'⁻¹, K.mul_mem hr (K.inv_mem hr'), ?_⟩ rwa [mul_assoc, mul_assoc, eq_inv_mul_iff_mul_eq, ← mul_assoc, ← mul_assoc, eq_mul_inv_iff_mul_eq] -theorem eq_of_not_disjoint {H K : Subgroup G} {a b : G} +lemma eq_of_not_disjoint {H K : Subgroup G} {a b : G} (h : ¬Disjoint (doubleCoset a H K) (doubleCoset b H K)) : doubleCoset a H K = doubleCoset b H K := by rw [disjoint_comm] at h @@ -79,13 +79,13 @@ def setoid (H K : Set G) : Setoid G := def Quotient (H K : Set G) : Type _ := _root_.Quotient (setoid H K) -theorem rel_iff {H K : Subgroup G} {x y : G} : +lemma rel_iff {H K : Subgroup G} {x y : G} : setoid ↑H ↑K x y ↔ ∃ a ∈ H, ∃ b ∈ K, y = a * x * b := Iff.trans ⟨fun (hxy : doubleCoset x H K = doubleCoset y H K) => hxy ▸ mem_doubleCoset_self H K y, fun hxy => (doubleCoset_eq_of_mem hxy).symm⟩ mem_doubleCoset -theorem bot_rel_eq_leftRel (H : Subgroup G) : +lemma bot_rel_eq_leftRel (H : Subgroup G) : ⇑(setoid ↑(⊥ : Subgroup G) ↑H) = ⇑(QuotientGroup.leftRel H) := by ext a b rw [rel_iff, QuotientGroup.leftRel_apply] @@ -95,7 +95,7 @@ theorem bot_rel_eq_leftRel (H : Subgroup G) : · rintro (h : a⁻¹ * b ∈ H) exact ⟨1, rfl, a⁻¹ * b, h, by rw [one_mul, mul_inv_cancel_left]⟩ -theorem rel_bot_eq_right_group_rel (H : Subgroup G) : +lemma rel_bot_eq_right_group_rel (H : Subgroup G) : ⇑(setoid ↑H ↑(⊥ : Subgroup G)) = ⇑(QuotientGroup.rightRel H) := by ext a b rw [rel_iff, QuotientGroup.rightRel_apply] @@ -116,16 +116,18 @@ abbrev mk (H K : Subgroup G) (a : G) : Quotient (H : Set G) K := instance (H K : Subgroup G) : Inhabited (Quotient (H : Set G) K) := ⟨mk H K (1 : G)⟩ -set_option backward.isDefEq.respectTransparency false in -theorem eq (H K : Subgroup G) (a b : G) : +lemma eq'' {a b : G} (H K : Subgroup G) : mk H K a = mk H K b ↔ setoid H K a b := + Quotient.eq + +lemma eq (H K : Subgroup G) (a b : G) : mk H K a = mk H K b ↔ ∃ h ∈ H, ∃ k ∈ K, b = h * a * k := by - rw [Quotient.eq''] - apply rel_iff + rw [eq''] + exact rel_iff -theorem out_eq' (H K : Subgroup G) (q : Quotient ↑H ↑K) : mk H K q.out = q := +lemma out_eq' (H K : Subgroup G) (q : Quotient ↑H ↑K) : mk H K q.out = q := Quotient.out_eq' q -theorem mk_out_eq_mul (H K : Subgroup G) (g : G) : +lemma mk_out_eq_mul (H K : Subgroup G) (g : G) : ∃ h k : G, h ∈ H ∧ k ∈ K ∧ (mk H K g : Quotient ↑H ↑K).out = h * g * k := by have := eq H K (mk H K g : Quotient ↑H ↑K).out g rw [out_eq'] at this @@ -133,18 +135,24 @@ theorem mk_out_eq_mul (H K : Subgroup G) (g : G) : refine ⟨h⁻¹, k⁻¹, H.inv_mem h_h, K.inv_mem hk, eq_mul_inv_of_mul_eq (eq_inv_mul_of_mul_eq ?_)⟩ rw [← mul_assoc, ← T] -theorem mk_eq_of_doubleCoset_eq {H K : Subgroup G} {a b : G} +lemma mk_eq_of_doubleCoset_eq {H K : Subgroup G} {a b : G} (h : doubleCoset a H K = doubleCoset b H K) : mk H K a = mk H K b := by rw [eq] exact mem_doubleCoset.mp (h.symm ▸ mem_doubleCoset_self H K b) -theorem disjoint_out {H K : Subgroup G} {a b : Quotient H K} : +lemma mem_quotToDoubleCoset_iff {H K : Subgroup G} (i : Quotient (H : Set G) K) (a : G) : + a ∈ quotToDoubleCoset H K i ↔ mk H K a = i := by + refine ⟨fun hg ↦ by simp [mk_eq_of_doubleCoset_eq (doubleCoset_eq_of_mem hg)], fun hg ↦ ?_⟩ + rw [← out_eq' _ _ i] at hg + exact mem_doubleCoset.mpr ((eq _ _ _ a).mp hg.symm) + +lemma disjoint_out {H K : Subgroup G} {a b : Quotient H K} : a ≠ b → Disjoint (doubleCoset a.out H K) (doubleCoset b.out (H : Set G) K) := by contrapose! intro h simpa [out_eq'] using mk_eq_of_doubleCoset_eq (eq_of_not_disjoint h) -theorem union_quotToDoubleCoset (H K : Subgroup G) : ⋃ q, quotToDoubleCoset H K q = Set.univ := by +lemma iUnion_quotToDoubleCoset (H K : Subgroup G) : ⋃ q, quotToDoubleCoset H K q = Set.univ := by ext x simp only [Set.mem_iUnion, quotToDoubleCoset, mem_doubleCoset, SetLike.mem_coe, Set.mem_univ, iff_true] @@ -153,7 +161,7 @@ theorem union_quotToDoubleCoset (H K : Subgroup G) : ⋃ q, quotToDoubleCoset H refine ⟨h⁻¹, H.inv_mem h3, k⁻¹, K.inv_mem h4, ?_⟩ simp only [h5, ← mul_assoc, one_mul, inv_mul_cancel, mul_inv_cancel_right] -theorem doubleCoset_union_rightCoset (H K : Subgroup G) (a : G) : +lemma doubleCoset_union_rightCoset (H K : Subgroup G) (a : G) : ⋃ k : K, op (a * k) • ↑H = doubleCoset a H K := by ext x simp only [mem_rightCoset_iff, mul_inv_rev, Set.mem_iUnion, mem_doubleCoset, @@ -166,7 +174,7 @@ theorem doubleCoset_union_rightCoset (H K : Subgroup G) (a : G) : refine ⟨⟨y, hy⟩, ?_⟩ simp only [hxy, ← mul_assoc, hx, mul_inv_cancel_right] -theorem doubleCoset_union_leftCoset (H K : Subgroup G) (a : G) : +lemma doubleCoset_union_leftCoset (H K : Subgroup G) (a : G) : ⋃ h : H, (h * a : G) • ↑K = doubleCoset a H K := by ext x simp only [mem_leftCoset_iff, mul_inv_rev, Set.mem_iUnion, mem_doubleCoset] @@ -178,18 +186,92 @@ theorem doubleCoset_union_leftCoset (H K : Subgroup G) (a : G) : refine ⟨⟨x, hx⟩, ?_⟩ simp only [hxy, ← mul_assoc, hy, one_mul, inv_mul_cancel, inv_mul_cancel_right] -theorem left_bot_eq_left_quot (H : Subgroup G) : +open Quotient QuotientGroup + +lemma left_bot_eq_left_quot (H : Subgroup G) : Quotient (⊥ : Subgroup G) (H : Set G) = (G ⧸ H) := by unfold Quotient congr ext simp_rw [← bot_rel_eq_leftRel H] -theorem right_bot_eq_right_quot (H : Subgroup G) : - Quotient (H : Set G) (⊥ : Subgroup G) = _root_.Quotient (QuotientGroup.rightRel H) := by +lemma right_bot_eq_right_quot (H : Subgroup G) : + Quotient (H : Set G) (⊥ : Subgroup G) = _root_.Quotient (rightRel H) := by unfold Quotient congr ext simp_rw [← rel_bot_eq_right_group_rel H] +lemma finite_quotient_iff_exists_finset_iUnion_eq_univ (H K : Subgroup G) : + Finite (Quotient (H : Set G) K) ↔ + ∃ I : Finset (Quotient (H : Set G) K), ⋃ i ∈ I, quotToDoubleCoset H K i = .univ := by + constructor + · intro _ + cases nonempty_fintype (Quotient (H : Set G) K) + exact ⟨Finset.univ, by simpa using iUnion_quotToDoubleCoset _ _⟩ + · rintro ⟨I, hI⟩ + suffices (I : Set (Quotient (H : Set G) K)) = Set.univ by + simp_rw [← Set.finite_univ_iff, ← this, I.finite_toSet] + rw [Set.eq_univ_iff_forall] at hI ⊢ + rintro ⟨g⟩ + obtain ⟨_, ⟨i, _, rfl⟩, T, ⟨hi, rfl⟩, hT : g ∈ quotToDoubleCoset H K i⟩ := hI g + simpa [← (mem_quotToDoubleCoset_iff _ _).mp hT] using hi + +lemma iUnion_image_mk_leftRel {H K : Subgroup G} : + ⋃ q : Quotient H K, Quot.mk (leftRel K) '' doubleCoset (out q : G) H K = Set.univ := by + have cover := iUnion_quotToDoubleCoset H K + rw [Set.iUnion_eq_univ_iff] + intro x + obtain ⟨y, hy⟩ := exists_rep x + have ⟨i, hi⟩ : ∃ i : Quotient H K, y ∈ doubleCoset (out i) H K := by + contrapose cover + exact (Set.ne_univ_iff_exists_notMem _).mpr ⟨y, by simpa using cover⟩ + exact ⟨i, y, hi, hy⟩ + +lemma iUnion_image_mk_rightRel {H K : Subgroup G} : + ⋃ q : Quotient H K, Quot.mk (rightRel H) '' doubleCoset (out q : G) H K = Set.univ := by + have cover := iUnion_quotToDoubleCoset H K + rw [Set.iUnion_eq_univ_iff] + intro x + obtain ⟨y, hy⟩ := exists_rep x + have ⟨i, hi⟩ : ∃ i : Quotient H K, y ∈ doubleCoset (out i) H K := by + contrapose cover + exact (Set.ne_univ_iff_exists_notMem _).mpr ⟨y, by simpa using cover⟩ + exact ⟨i, y, hi, hy⟩ + +lemma iUnion_finset_leftRel_eq_univ_of_leftRel {H K : Subgroup G} {t : Finset (Quotient H K)} + (ht : Set.univ ⊆ ⋃ i ∈ t, Quot.mk (leftRel K) '' doubleCoset (out i) H K) : + ⋃ q ∈ t, doubleCoset (out q) H K = Set.univ := by + contrapose ht + simp only [Set.univ_subset_iff, ← ne_eq] at ⊢ ht + obtain ⟨x, hx⟩ := (Set.ne_univ_iff_exists_notMem _).mp ht + refine (Set.ne_univ_iff_exists_notMem _).mpr ⟨Quot.mk (leftRel K) x, ?_⟩ + simp only [Set.mem_iUnion, Set.mem_image, exists_prop, not_exists, not_and] + intro y hy q hq + contrapose! hx + simp only [Set.mem_iUnion, exists_prop] + refine ⟨y, hy, ?_⟩ + rw [← doubleCoset_eq_of_mem hq, mem_doubleCoset] + obtain ⟨a', ha'⟩ := Quotient.eq.mp hx + exact ⟨1, one_mem H, MulOpposite.unop a'⁻¹, Subgroup.mem_op.mp (by simp), by simpa + using (eq_mul_inv_of_mul_eq ha')⟩ + +lemma iUnion_finset_rightRel_eq_univ_of_rightRel {H K : Subgroup G} {t : Finset (Quotient H K)} + (ht : Set.univ ⊆ ⋃ i ∈ t, Quot.mk (rightRel H) '' doubleCoset (out i) H K) : + ⋃ q ∈ t, doubleCoset (out q) H K = Set.univ := by + contrapose ht + simp only [Set.univ_subset_iff, ← ne_eq] at ⊢ ht + obtain ⟨x, hx⟩ := (Set.ne_univ_iff_exists_notMem _).mp ht + refine (Set.ne_univ_iff_exists_notMem _).mpr ⟨Quot.mk (rightRel H) x, ?_⟩ + simp only [Set.mem_iUnion, Set.mem_image, exists_prop, not_exists, not_and] + intro y hy q hq + contrapose! hx + simp only [Set.mem_iUnion, exists_prop] + refine ⟨y, hy, ?_⟩ + rw [← doubleCoset_eq_of_mem hq, mem_doubleCoset] + obtain ⟨a, ha⟩ : ∃ a : H, x = a * q := by + obtain ⟨a, ha⟩ : ∃ a : H, a * x = q := Quotient.eq.mp hx + exact ⟨⟨a⁻¹, by simp⟩, eq_inv_mul_of_mul_eq ha⟩ + exact ⟨a.1, a.2, ⟨1, Subgroup.one_mem K, by simpa using ha⟩⟩ + end DoubleCoset diff --git a/Mathlib/GroupTheory/FiniteIndexNormalSubgroup.lean b/Mathlib/GroupTheory/FiniteIndexNormalSubgroup.lean index c906abfa933292..05ffbe4a7f697a 100644 --- a/Mathlib/GroupTheory/FiniteIndexNormalSubgroup.lean +++ b/Mathlib/GroupTheory/FiniteIndexNormalSubgroup.lean @@ -103,6 +103,10 @@ instance instSemilatticeSupFiniteIndexNormalSubgroup : @[to_additive] instance : Lattice (FiniteIndexNormalSubgroup G) where +@[to_additive] +theorem mem_toSubgroup_iff {H : FiniteIndexNormalSubgroup G} {g : G} : g ∈ H.toSubgroup ↔ g ∈ H := + .rfl + /-- Bundle a subgroup with typeclass assumptions of normality and finite index. -/ @[to_additive /-- Bundle an additive subgroup with typeclass assumptions of normality and finite index. -/] diff --git a/Mathlib/GroupTheory/Perm/Cycle/Concrete.lean b/Mathlib/GroupTheory/Perm/Cycle/Concrete.lean index 5818dbf07f71e6..4c1eedbadd05e4 100644 --- a/Mathlib/GroupTheory/Perm/Cycle/Concrete.lean +++ b/Mathlib/GroupTheory/Perm/Cycle/Concrete.lean @@ -178,11 +178,8 @@ nonrec theorem formPerm_eq_formPerm_iff {α : Type*} [DecidableEq α] {s s' : Cy {hs' : s'.Nodup} : s.formPerm hs = s'.formPerm hs' ↔ s = s' ∨ s.Subsingleton ∧ s'.Subsingleton := by rw [Cycle.length_subsingleton_iff, Cycle.length_subsingleton_iff] - revert s s' - intro s s' - apply @Quotient.inductionOn₂' _ _ _ _ _ s s' - intro l l' hl hl' - simpa using formPerm_eq_formPerm_iff hl hl' + induction s, s' using Quotient.inductionOn₂' + simpa using formPerm_eq_formPerm_iff hs hs' end Cycle diff --git a/Mathlib/GroupTheory/ResiduallyFinite.lean b/Mathlib/GroupTheory/ResiduallyFinite.lean new file mode 100644 index 00000000000000..df0c7fbfad89f2 --- /dev/null +++ b/Mathlib/GroupTheory/ResiduallyFinite.lean @@ -0,0 +1,78 @@ +/- +Copyright (c) 2026 Thomas Browning. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Thomas Browning +-/ +module + +public import Mathlib.GroupTheory.FiniteIndexNormalSubgroup + +/-! +# Residually Finite Groups + +In this file we define residually finite groups and prove some basic properties. + +## Main definitions + +- `Group.ResiduallyFinite G`: A group `G` is residually finite if the intersection of all + finite index normal subgroups is trivial. + +-/ + +@[expose] public section + +/-- An additive group `G` is residually finite if the intersection of all finite index normal +additive subgroups is trivial. -/ +class AddGroup.ResiduallyFinite (G : Type*) [AddGroup G] : Prop where + iInf_eq_bot : ⨅ H : FiniteIndexNormalAddSubgroup G, H.toAddSubgroup = ⊥ + +namespace Group + +/-- A group `G` is residually finite if the intersection of all finite index normal subgroups is +trivial. -/ +class ResiduallyFinite (G : Type*) [Group G] : Prop where + iInf_eq_bot : ⨅ H : FiniteIndexNormalSubgroup G, H.toSubgroup = ⊥ + +attribute [to_additive existing] ResiduallyFinite + +variable {G : Type*} [Group G] + +@[to_additive] +theorem residuallyFinite_def : + ResiduallyFinite G ↔ ⨅ H : FiniteIndexNormalSubgroup G, H.toSubgroup = ⊥ := + ⟨fun h ↦ h.iInf_eq_bot, fun h ↦ ⟨h⟩⟩ + +@[to_additive] +theorem residuallyFinite_iff_forall_finiteIndexNormalSubgroup : + ResiduallyFinite G ↔ ∀ g : G, (∀ H : FiniteIndexNormalSubgroup G, g ∈ H) → g = 1 := by + simp_rw [residuallyFinite_def, Subgroup.eq_bot_iff_forall, Subgroup.mem_iInf, + FiniteIndexNormalSubgroup.mem_toSubgroup_iff] + +@[to_additive] +theorem eq_one_iff_forall_finiteIndexNormalSubroup [ResiduallyFinite G] + (g : G) (hg : ∀ H : FiniteIndexNormalSubgroup G, g ∈ H) : g = 1 := + residuallyFinite_iff_forall_finiteIndexNormalSubgroup.mp ‹_› g hg + +@[to_additive] +theorem residuallyFinite_iff_exists_finiteIndexNormalSubgroup : + ResiduallyFinite G ↔ ∀ g : G, g ≠ 1 → ∃ H : FiniteIndexNormalSubgroup G, g ∉ H := by + simp_rw [residuallyFinite_iff_forall_finiteIndexNormalSubgroup, ← not_forall, not_imp_not] + +-- todo: @[to_additive] once #34784 is merged +theorem residuallyFinite_iff_forall_finiteIndex : + ResiduallyFinite G ↔ ∀ g : G, (∀ (H : Subgroup G) [H.FiniteIndex], g ∈ H) → g = 1 := by + rw [residuallyFinite_iff_forall_finiteIndexNormalSubgroup] + exact forall_congr' fun g ↦ ⟨fun h hg ↦ h fun H ↦ hg H, + fun h hg ↦ h fun H hH ↦ H.normalCore_le (hg (.ofSubgroup H.normalCore))⟩ + +-- todo: @[to_additive] once #34784 is merged +theorem residuallyFinite_iff_exists_finiteIndex : + ResiduallyFinite G ↔ ∀ g : G, g ≠ 1 → ∃ (H : Subgroup G), H.FiniteIndex ∧ g ∉ H := by + simp_rw [residuallyFinite_iff_forall_finiteIndex, ← Classical.not_imp, ← not_forall, + not_imp_not] + +-- todo: @[to_additive] once #34784 is merged +instance [Finite G] : ResiduallyFinite G := + residuallyFinite_iff_forall_finiteIndex.mpr fun _ hg ↦ hg ⊥ + +end Group diff --git a/Mathlib/GroupTheory/Sylow.lean b/Mathlib/GroupTheory/Sylow.lean index 55f6999d5223e2..cbfb7269060b2a 100644 --- a/Mathlib/GroupTheory/Sylow.lean +++ b/Mathlib/GroupTheory/Sylow.lean @@ -815,6 +815,6 @@ noncomputable def directProductOfNormal [Finite G] _ = ∏ p ∈ ps, p ^ (Nat.card G).factorization p := (Finset.prod_finset_coe (fun p => p ^ (Nat.card G).factorization p) _) _ = (Nat.card G).factorization.prod (· ^ ·) := rfl - _ = Nat.card G := Nat.factorization_prod_pow_eq_self Nat.card_pos.ne' + _ = Nat.card G := Nat.prod_factorization_pow_eq_self Nat.card_pos.ne' end Sylow diff --git a/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Basic.lean b/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Basic.lean index b43f900fe4a553..b1b8b1f717c087 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Basic.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Basic.lean @@ -315,7 +315,6 @@ theorem vectorSpan_range_eq_span_range_vsub_right_ne (p : ι → P) (i₀ : ι) variable {k} -set_option backward.isDefEq.respectTransparency false in /-- A set, considered as a subset of its spanned affine subspace, spans the whole subspace. -/ @[simp] theorem affineSpan_coe_preimage_eq_top (A : Set P) [Nonempty A] : diff --git a/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Defs.lean b/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Defs.lean index 6f4e0d648b8e87..30bedebf1fee03 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Defs.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Defs.lean @@ -556,12 +556,10 @@ theorem eq_of_direction_eq_of_nonempty_of_le {s₁ s₂ : AffineSubspace k P} let ⟨p, hp⟩ := hn ext_of_direction_eq hd ⟨p, hp, hle hp⟩ -set_option backward.isDefEq.respectTransparency false in instance nonempty_sup_left (s₁ s₂ : AffineSubspace k P) [Nonempty s₁] : Nonempty (s₁ ⊔ s₂ : AffineSubspace k P) := .map (Set.inclusion <| SetLike.le_def.1 le_sup_left) ‹_› -set_option backward.isDefEq.respectTransparency false in instance nonempty_sup_right (s₁ s₂ : AffineSubspace k P) [Nonempty s₂] : Nonempty (s₁ ⊔ s₂ : AffineSubspace k P) := .map (Set.inclusion <| SetLike.le_def.1 le_sup_right) ‹_› @@ -584,13 +582,11 @@ protected def gi : GaloisInsertion (affineSpan k) ((↑) : AffineSubspace k P le_l_u _ := subset_spanPoints k _ choice_eq _ _ := rfl -set_option backward.isDefEq.respectTransparency false in /-- The span of the empty set is `⊥`. -/ @[simp] theorem span_empty : affineSpan k (∅ : Set P) = ⊥ := (AffineSubspace.gi k V P).gc.l_bot -set_option backward.isDefEq.respectTransparency false in /-- The span of `univ` is `⊤`. -/ @[simp] theorem span_univ : affineSpan k (Set.univ : Set P) = ⊤ := @@ -674,7 +670,6 @@ theorem affineSpan_eq_top_iff_vectorSpan_eq_top_of_nonempty {s : Set P} (hs : s. obtain ⟨x, hx⟩ := hs exact ⟨⟨x, mem_affineSpan k hx⟩⟩ -set_option backward.isDefEq.respectTransparency false in /-- For a non-trivial space, the affine span of a set is `⊤` iff its vector span is `⊤`. -/ theorem affineSpan_eq_top_iff_vectorSpan_eq_top_of_nontrivial {s : Set P} [Nontrivial P] : affineSpan k s = ⊤ ↔ vectorSpan k s = ⊤ := by @@ -724,7 +719,6 @@ theorem eq_bot_or_nonempty (Q : AffineSubspace k P) : Q = ⊥ ∨ (Q : Set P).No rw [nonempty_iff_ne_bot] apply eq_or_ne -set_option backward.isDefEq.respectTransparency false in instance [Subsingleton P] : IsSimpleOrder (AffineSubspace k P) where eq_bot_or_eq_top (s : AffineSubspace k P) := by rw [← coe_eq_bot_iff, ← coe_eq_univ_iff] @@ -930,13 +924,11 @@ theorem affineSpan_eq_bot : affineSpan k s = ⊥ ↔ s = ∅ := by rw [← not_iff_not, ← Ne, ← Ne, ← nonempty_iff_ne_bot, affineSpan_nonempty, nonempty_iff_ne_empty] -set_option backward.isDefEq.respectTransparency false in @[simp] theorem bot_lt_affineSpan : ⊥ < affineSpan k s ↔ s.Nonempty := by rw [bot_lt_iff_ne_bot, nonempty_iff_ne_empty] exact (affineSpan_eq_bot _).not -set_option backward.isDefEq.respectTransparency false in @[simp] lemma affineSpan_eq_top_iff_nonempty_of_subsingleton [Subsingleton P] : affineSpan k s = ⊤ ↔ s.Nonempty := by diff --git a/Mathlib/LinearAlgebra/AffineSpace/Basis.lean b/Mathlib/LinearAlgebra/AffineSpace/Basis.lean index a315e8e6416685..3b73839f1305da 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Basis.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Basis.lean @@ -118,7 +118,6 @@ theorem ind : AffineIndependent k b := theorem tot : affineSpan k (range b) = ⊤ := b.tot' -set_option backward.isDefEq.respectTransparency false in include b in protected theorem nonempty : Nonempty ι := not_isEmpty_iff.mp fun hι => by diff --git a/Mathlib/LinearAlgebra/AffineSpace/FiniteDimensional.lean b/Mathlib/LinearAlgebra/AffineSpace/FiniteDimensional.lean index 9fce3a60e806d6..e1df45c88d3825 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/FiniteDimensional.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/FiniteDimensional.lean @@ -267,7 +267,6 @@ lemma AffineIndependent.card_le_card_of_subset_affineSpan {s t : Finset V} erw [hs.finrank_vectorSpan_add_one] at finrank_le simpa using finrank_le.trans <| finrank_vectorSpan_range_add_one_le _ _ -set_option backward.isDefEq.respectTransparency false in open Finset in /-- If the affine span of an affine independent finset is strictly contained in the affine span of another finset, then its cardinality is strictly less than the cardinality of that finset. -/ @@ -335,7 +334,6 @@ theorem AffineIndependent.affineSpan_eq_of_le_of_card_eq_finrank_add_one [Fintyp rw [← Set.image_univ, ← Finset.coe_univ, ← Finset.coe_image] at hle ⊢ exact hi.affineSpan_image_finset_eq_of_le_of_card_eq_finrank_add_one hle hc -set_option backward.isDefEq.respectTransparency false in /-- The `affineSpan` of a finite affinely independent family is `⊤` iff the family's cardinality is one more than that of the finite-dimensional space. -/ theorem AffineIndependent.affineSpan_eq_top_iff_card_eq_finrank_add_one [FiniteDimensional k V] diff --git a/Mathlib/LinearAlgebra/AffineSpace/Matrix.lean b/Mathlib/LinearAlgebra/AffineSpace/Matrix.lean index 93e822bb4c0a63..40b806e1e82da0 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Matrix.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Matrix.lean @@ -71,7 +71,6 @@ theorem affineIndependent_of_toMatrix_right_inv [Fintype ι] [Finite ι'] [Decid replace hweq' := congr_arg (fun w => w ᵥ* A) hweq' simpa only [Matrix.vecMul_vecMul, hA, Matrix.vecMul_one] using hweq' -set_option backward.isDefEq.respectTransparency false in /-- Given a family of points `p : ι' → P` and an affine basis `b`, if the matrix whose rows are the coordinates of `p` with respect `b` has a left inverse, then `p` spans the entire space. -/ theorem affineSpan_eq_top_of_toMatrix_left_inv [Finite ι] [Fintype ι'] [DecidableEq ι] diff --git a/Mathlib/LinearAlgebra/Alternating/DomCoprod.lean b/Mathlib/LinearAlgebra/Alternating/DomCoprod.lean index b19d5171ca0480..21814ea9f9e69d 100644 --- a/Mathlib/LinearAlgebra/Alternating/DomCoprod.lean +++ b/Mathlib/LinearAlgebra/Alternating/DomCoprod.lean @@ -77,7 +77,7 @@ theorem domCoprod.summand_add_swap_smul_eq_zero (a : Mᵢ [⋀^ιa]→ₗ[R'] N (b : Mᵢ [⋀^ιb]→ₗ[R'] N₂) (σ : Perm.ModSumCongr ιa ιb) {v : ιa ⊕ ιb → Mᵢ} {i j : ιa ⊕ ιb} (hv : v i = v j) (hij : i ≠ j) : domCoprod.summand a b σ v + domCoprod.summand a b (swap i j • σ) v = 0 := by - refine Quotient.inductionOn' σ fun σ => ?_ + induction σ using Quotient.inductionOn' dsimp only [Quotient.liftOn'_mk'', Quotient.map'_mk'', MulAction.Quotient.smul_mk, domCoprod.summand] rw [smul_eq_mul, Perm.sign_mul, Perm.sign_swap hij] @@ -94,7 +94,7 @@ theorem domCoprod.summand_eq_zero_of_smul_invariant (a : Mᵢ [⋀^ιa]→ₗ[R' (b : Mᵢ [⋀^ιb]→ₗ[R'] N₂) (σ : Perm.ModSumCongr ιa ιb) {v : ιa ⊕ ιb → Mᵢ} {i j : ιa ⊕ ιb} (hv : v i = v j) (hij : i ≠ j) : swap i j • σ = σ → domCoprod.summand a b σ v = 0 := by - refine Quotient.inductionOn' σ fun σ => ?_ + induction σ using Quotient.inductionOn' with | _ σ dsimp only [Quotient.liftOn'_mk'', Quotient.map'_mk'', MultilinearMap.smul_apply, MultilinearMap.domDomCongr_apply, MultilinearMap.domCoprod_apply, domCoprod.summand] intro hσ @@ -165,7 +165,7 @@ def domCoprod' : Finset.smul_sum, MultilinearMap.sum_apply, domCoprod.summand] congr ext σ - refine Quotient.inductionOn' σ fun σ => ?_ + induction σ using Quotient.inductionOn' simp only [Quotient.liftOn'_mk'', coe_add, coe_smul, MultilinearMap.smul_apply, ← MultilinearMap.domCoprod'_apply] simp only [TensorProduct.add_tmul, ← TensorProduct.smul_tmul', TensorProduct.tmul_add, diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Even.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Even.lean index 18d5455a583cfb..d1a893f3f586cf 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Even.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Even.lean @@ -80,7 +80,6 @@ def EvenHom.compr₂ (g : EvenHom Q A) (f : A →ₐ[R] B) : EvenHom Q B where variable (Q) -set_option backward.isDefEq.respectTransparency false in /-- The embedding of pairs of vectors into the even subalgebra, as a bilinear map. -/ nonrec def even.ι : EvenHom Q (even Q) where bilin := @@ -97,13 +96,11 @@ nonrec def even.ι : EvenHom Q (even Q) where simp only [mul_assoc] _ = Q m₂ • (ι Q m₁ * ι Q m₃) := by rw [Algebra.smul_def, ι_sq_scalar, Algebra.left_comm] -set_option backward.isDefEq.respectTransparency false in instance : Inhabited (EvenHom Q (even Q)) := ⟨even.ι Q⟩ variable (f : EvenHom Q A) -set_option backward.isDefEq.respectTransparency false in /-- Two algebra morphisms from the even subalgebra are equal if they agree on pairs of generators. See note [partially-applied ext lemmas]. -/ @@ -192,7 +189,6 @@ private theorem fFold_fFold (m : M) (x : A × S f) : fFold f m (fFold f m x) = Q · rintro x hx _c ihx rw [LinearMap.smul_apply, LinearMap.smul_apply, mul_smul_comm, ihx, smul_comm] -set_option backward.isDefEq.respectTransparency false in set_option backward.privateInPublic true in set_option backward.privateInPublic.warn false in /-- The final auxiliary construction for `CliffordAlgebra.even.lift`. This map is the forwards @@ -206,7 +202,6 @@ def aux (f : EvenHom Q A) : CliffordAlgebra.even Q →ₗ[R] A := by theorem aux_one : aux f 1 = 1 := congr_arg Prod.fst (foldr_one _ _ _ _) -set_option backward.isDefEq.respectTransparency false in @[simp] theorem aux_ι (m₁ m₂ : M) : aux f ((even.ι Q).bilin m₁ m₂) = f.bilin m₁ m₂ := (congr_arg Prod.fst (foldr_mul _ _ _ _ _ _)).trans @@ -242,7 +237,6 @@ open even.lift variable (Q) -set_option backward.isDefEq.respectTransparency false in /-- Every algebra morphism from the even subalgebra is in one-to-one correspondence with a bilinear map that sends duplicate arguments to the quadratic form, and contracts across multiplication. -/ @@ -253,7 +247,6 @@ def even.lift : EvenHom Q A ≃ (CliffordAlgebra.even Q →ₐ[R] A) where left_inv f := EvenHom.ext <| LinearMap.ext₂ <| even.lift.aux_ι f right_inv _ := even.algHom_ext Q <| EvenHom.ext <| LinearMap.ext₂ <| even.lift.aux_ι _ -set_option backward.isDefEq.respectTransparency false in @[simp] theorem even.lift_ι (f : EvenHom Q A) (m₁ m₂ : M) : even.lift Q f ((even.ι Q).bilin m₁ m₂) = f.bilin m₁ m₂ := diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/EvenEquiv.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/EvenEquiv.lean index 7691fc25279ffe..bd60fab1306440 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/EvenEquiv.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/EvenEquiv.lean @@ -156,13 +156,11 @@ def ofEven : CliffordAlgebra.even (Q' Q) →ₐ[R] CliffordAlgebra Q := by rw [← mul_smul_comm, ← mul_assoc, mul_assoc (_ + _), ← (hc _ _).symm.mul_self_sub_mul_self_eq', Algebra.smul_def, ← mul_assoc, hm] -set_option backward.isDefEq.respectTransparency false in theorem ofEven_ι (x y : M × R) : ofEven Q ((even.ι (Q' Q)).bilin x y) = (ι Q x.1 + algebraMap R _ x.2) * (ι Q y.1 - algebraMap R _ y.2) := even.lift_ι (Q' Q) _ x y -set_option backward.isDefEq.respectTransparency false in theorem toEven_comp_ofEven : (toEven Q).comp (ofEven Q) = AlgHom.id R _ := even.algHom_ext (Q' Q) <| EvenHom.ext <| @@ -212,7 +210,6 @@ basis vector. -/ def equivEven : CliffordAlgebra Q ≃ₐ[R] CliffordAlgebra.even (Q' Q) := AlgEquiv.ofAlgHom (toEven Q) (ofEven Q) (toEven_comp_ofEven Q) (ofEven_comp_toEven Q) -set_option backward.isDefEq.respectTransparency false in /-- The representation of the clifford conjugate (i.e. the reverse of the involute) in the even subalgebra is just the reverse of the representation. -/ theorem coe_toEven_reverse_involute (x : CliffordAlgebra Q) : @@ -228,7 +225,6 @@ theorem coe_toEven_reverse_involute (x : CliffordAlgebra Q) : /-! ### Constructions needed for `CliffordAlgebra.evenEquivEvenNeg` -/ -set_option backward.isDefEq.respectTransparency false in /-- One direction of `CliffordAlgebra.evenEquivEvenNeg` -/ def evenToNeg (Q' : QuadraticForm R M) (h : Q' = -Q) : CliffordAlgebra.even Q →ₐ[R] CliffordAlgebra.even Q' := @@ -240,13 +236,11 @@ def evenToNeg (Q' : QuadraticForm R M) (h : Q' = -Q) : simp_rw [LinearMap.neg_apply, neg_mul_neg, EvenHom.contract_mid, h, QuadraticMap.neg_apply, smul_neg, neg_smul] } -set_option backward.isDefEq.respectTransparency false in @[simp] theorem evenToNeg_ι (Q' : QuadraticForm R M) (h : Q' = -Q) (m₁ m₂ : M) : evenToNeg Q Q' h ((even.ι Q).bilin m₁ m₂) = -(even.ι Q').bilin m₁ m₂ := even.lift_ι _ _ m₁ m₂ -set_option backward.isDefEq.respectTransparency false in theorem evenToNeg_comp_evenToNeg (Q' : QuadraticForm R M) (h : Q' = -Q) (h' : Q = -Q') : (evenToNeg Q' Q h').comp (evenToNeg Q Q' h) = AlgHom.id R _ := by ext m₁ m₂ : 4 diff --git a/Mathlib/LinearAlgebra/Dimension/Constructions.lean b/Mathlib/LinearAlgebra/Dimension/Constructions.lean index fbe86213994e83..095a6462a8ff75 100644 --- a/Mathlib/LinearAlgebra/Dimension/Constructions.lean +++ b/Mathlib/LinearAlgebra/Dimension/Constructions.lean @@ -544,7 +544,6 @@ section Ring variable {F E : Type*} [CommRing F] [IsDomain F] [Ring E] [Algebra F E] variable [StrongRankCondition F] [IsTorsionFree F E] [Nontrivial E] -set_option backward.isDefEq.respectTransparency false in @[simp] theorem Subalgebra.rank_bot : Module.rank F (⊥ : Subalgebra F E) = 1 := (Subalgebra.toSubmoduleEquiv (⊥ : Subalgebra F E)).symm.rank_eq.trans <| by @@ -552,7 +551,6 @@ theorem Subalgebra.rank_bot : Module.rank F (⊥ : Subalgebra F E) = 1 := have := Module.nontrivial F E exact .singleton one_ne_zero -set_option backward.isDefEq.respectTransparency false in @[simp] theorem Subalgebra.finrank_bot : finrank F (⊥ : Subalgebra F E) = 1 := finrank_eq_of_rank_eq (by simp) diff --git a/Mathlib/LinearAlgebra/Dimension/FreeAndStrongRankCondition.lean b/Mathlib/LinearAlgebra/Dimension/FreeAndStrongRankCondition.lean index 6f248047572d50..dce7e5eef7b085 100644 --- a/Mathlib/LinearAlgebra/Dimension/FreeAndStrongRankCondition.lean +++ b/Mathlib/LinearAlgebra/Dimension/FreeAndStrongRankCondition.lean @@ -239,7 +239,6 @@ namespace Subalgebra variable {F E : Type*} [CommRing F] [StrongRankCondition F] [Ring E] [Algebra F E] {S : Subalgebra F E} -set_option backward.isDefEq.respectTransparency false in theorem eq_bot_of_rank_le_one (h : Module.rank F S ≤ 1) [Module.Free F S] : S = ⊥ := by nontriviality E obtain ⟨κ, b⟩ := Module.Free.exists_basis (R := F) (M := S) @@ -254,13 +253,11 @@ theorem eq_bot_of_rank_le_one (h : Module.rank F S ≤ 1) [Module.Free F S] : S haveI := b.repr.toEquiv.subsingleton exact False.elim <| one_ne_zero congr(S.val $(Subsingleton.elim 1 0)) -set_option backward.isDefEq.respectTransparency false in theorem eq_bot_of_finrank_one (h : finrank F S = 1) [Module.Free F S] : S = ⊥ := by refine Subalgebra.eq_bot_of_rank_le_one ?_ rw [finrank, toNat_eq_one] at h rw [h] -set_option backward.isDefEq.respectTransparency false in @[simp] theorem rank_eq_one_iff [Nontrivial E] [Module.Free F S] : Module.rank F S = 1 ↔ S = ⊥ := by refine ⟨fun h ↦ Subalgebra.eq_bot_of_rank_le_one h.le, ?_⟩ @@ -276,19 +273,16 @@ theorem rank_eq_one_iff [Nontrivial E] [Module.Free F S] : Module.rank F S = 1 haveI := b.repr.toEquiv.subsingleton exact one_ne_zero congr((⊥ : Subalgebra F E).val $(Subsingleton.elim 1 0)) -set_option backward.isDefEq.respectTransparency false in @[simp] theorem finrank_eq_one_iff [Nontrivial E] [Module.Free F S] : finrank F S = 1 ↔ S = ⊥ := by rw [← Subalgebra.rank_eq_one_iff] exact toNat_eq_iff one_ne_zero -set_option backward.isDefEq.respectTransparency false in theorem bot_eq_top_iff_rank_eq_one [Nontrivial E] [Module.Free F E] : (⊥ : Subalgebra F E) = ⊤ ↔ Module.rank F E = 1 := by haveI := Module.Free.of_equiv (Subalgebra.topEquiv (R := F) (A := E)).toLinearEquiv.symm rw [← rank_top, Subalgebra.rank_eq_one_iff, eq_comm] -set_option backward.isDefEq.respectTransparency false in theorem bot_eq_top_iff_finrank_eq_one [Nontrivial E] [Module.Free F E] : (⊥ : Subalgebra F E) = ⊤ ↔ finrank F E = 1 := by haveI := Module.Free.of_equiv (Subalgebra.topEquiv (R := F) (A := E)).toLinearEquiv.symm diff --git a/Mathlib/LinearAlgebra/Eigenspace/Basic.lean b/Mathlib/LinearAlgebra/Eigenspace/Basic.lean index 831f098f3790af..e17cdb83d09412 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Basic.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Basic.lean @@ -470,6 +470,28 @@ lemma HasEigenvalue.pow {f : End R M} {μ : R} (h : f.HasEigenvalue μ) (n : ℕ (f ^ n).HasEigenvalue (μ ^ n) := h.pow n +theorem genEigenspace_mem_invtSubmodule (f : End R M) (μ : R) (n : ℕ∞) : + genEigenspace f μ n ∈ invtSubmodule f := by + intro x hx + simp only [Submodule.mem_comap, mem_genEigenspace, LinearMap.mem_ker] at hx ⊢ + obtain ⟨k, hk, hx⟩ := hx + refine ⟨k, hk, ?_⟩ + induction k generalizing x + case zero => simp_all + case succ k ih => + rw [pow_succ, mul_apply] at hx ⊢ + simpa using ih (le_trans (by simp) hk) hx + +theorem eigenspace_mem_invtSubmodule (f : End R M) (μ : R) : + eigenspace f μ ∈ invtSubmodule f := + genEigenspace_mem_invtSubmodule f μ 1 + +theorem restrict_eigenspace (f : End R M) (μ : R) : + f.restrict (f.mem_invtSubmodule_iff_forall_mem_of_mem.mp + (eigenspace_mem_invtSubmodule f μ)) = μ • LinearMap.id := by + ext x + exact mem_eigenspace_iff.mp x.2 + /-- A nilpotent endomorphism has nilpotent eigenvalues. See also `LinearMap.isNilpotent_trace_of_isNilpotent`. -/ diff --git a/Mathlib/LinearAlgebra/FiniteDimensional/Basic.lean b/Mathlib/LinearAlgebra/FiniteDimensional/Basic.lean index 5cf402695a66b1..3a976ed3595963 100644 --- a/Mathlib/LinearAlgebra/FiniteDimensional/Basic.lean +++ b/Mathlib/LinearAlgebra/FiniteDimensional/Basic.lean @@ -602,7 +602,6 @@ open Module variable {F E : Type*} [Field F] [Ring E] [Algebra F E] -set_option backward.isDefEq.respectTransparency false in /-- A `Subalgebra` is `FiniteDimensional` iff it is `FiniteDimensional` as a submodule. -/ theorem Subalgebra.finiteDimensional_toSubmodule {S : Subalgebra F E} : FiniteDimensional F (Subalgebra.toSubmodule S) ↔ FiniteDimensional F S := @@ -611,7 +610,6 @@ theorem Subalgebra.finiteDimensional_toSubmodule {S : Subalgebra F E} : alias ⟨FiniteDimensional.of_subalgebra_toSubmodule, FiniteDimensional.subalgebra_toSubmodule⟩ := Subalgebra.finiteDimensional_toSubmodule -set_option backward.isDefEq.respectTransparency false in instance FiniteDimensional.finiteDimensional_subalgebra [FiniteDimensional F E] (S : Subalgebra F E) : FiniteDimensional F S := FiniteDimensional.of_subalgebra_toSubmodule inferInstance diff --git a/Mathlib/LinearAlgebra/FiniteDimensional/Lemmas.lean b/Mathlib/LinearAlgebra/FiniteDimensional/Lemmas.lean index 218606ff59b7e7..18ac40084e7030 100644 --- a/Mathlib/LinearAlgebra/FiniteDimensional/Lemmas.lean +++ b/Mathlib/LinearAlgebra/FiniteDimensional/Lemmas.lean @@ -86,6 +86,25 @@ theorem isCompl_iff_disjoint [FiniteDimensional K V] (s t : Submodule K V) IsCompl s t ↔ Disjoint s t := ⟨fun h ↦ h.1, fun h ↦ ⟨h, codisjoint_iff.mpr <| eq_top_of_disjoint s t hdim h⟩⟩ +theorem sup_span_singleton_eq_top_iff [Module.Finite K V] {W : Submodule K V} {v : V} (hv : v ∉ W) : + W ⊔ span K {v} = ⊤ ↔ finrank K (V ⧸ W) = 1 := by + refine ⟨fun hW ↦ ?_, fun hW ↦ ?_⟩ + · suffices W ⊓ span K {v} = ⊥ by + have hv₀ : v ≠ 0 := by aesop + have aux := finrank_sup_add_finrank_inf_eq W (span K {v}) + rw [hW, finrank_span_singleton hv₀, this, finrank_bot, finrank_top, + ← finrank_quotient_add_finrank W] at aux + lia + refine (Submodule.eq_bot_iff _).mpr fun w hw ↦ ?_ + obtain ⟨ht, t, rfl⟩ : w ∈ W ∧ ∃ t : K, t • v = w := by simpa [mem_span_singleton] using hw + rcases eq_or_ne t 0 with rfl | ht₀; · simp + rw [Submodule.smul_mem_iff _ ht₀] at ht + contradiction + · apply Submodule.eq_top_of_disjoint + · rw [← W.finrank_quotient_add_finrank, add_comm, add_le_add_iff_left, hW] + aesop + · exact Submodule.disjoint_span_singleton_of_notMem hv + end DivisionRing end Submodule @@ -318,7 +337,6 @@ open Module variable {F E : Type*} [Field F] [Ring E] [Algebra F E] -set_option backward.isDefEq.respectTransparency false in theorem Subalgebra.isSimpleOrder_of_finrank (hr : finrank F E = 2) : IsSimpleOrder (Subalgebra F E) := let i := nontrivial_of_finrank_pos (zero_lt_two.trans_eq hr.symm) diff --git a/Mathlib/LinearAlgebra/FixedSubmodule.lean b/Mathlib/LinearAlgebra/FixedSubmodule.lean new file mode 100644 index 00000000000000..78197acb79f78d --- /dev/null +++ b/Mathlib/LinearAlgebra/FixedSubmodule.lean @@ -0,0 +1,163 @@ +/- +Copyright (c) 2026 Antoine Chambert-Loir. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Antoine Chambert-Loir +-/ + +module + +public import Mathlib.Algebra.Module.Submodule.Pointwise +public import Mathlib.GroupTheory.GroupAction.FixingSubgroup +public import Mathlib.GroupTheory.GroupAction.SubMulAction.OfFixingSubgroup +public import Mathlib.GroupTheory.GroupAction.Ring +public import Mathlib.LinearAlgebra.DFinsupp +public import Mathlib.LinearAlgebra.Quotient.Basic + +/-! +# The fixed submodule of a linear map + +- `LinearMap.fixedSubmodule`: the submodule of a linear map consisting of its fixed points. + +-/ + +@[expose] public section + +namespace LinearMap + +open Pointwise Submodule MulAction + +variable {R : Type*} [Semiring R] + {U V : Type*} [AddCommMonoid U] [AddCommMonoid V] + [Module R U] [Module R V] (e : V ≃ₗ[R] V) + + +/-- The fixed submodule of a linear map. -/ +def fixedSubmodule (f : V →ₗ[R] V) : Submodule R V where + carrier := { x | f x = x } + add_mem' {x y} hx hy := by aesop + zero_mem' := by simp + smul_mem' r x hx := by aesop + +@[simp] +theorem mem_fixedSubmodule_iff {f : V →ₗ[R] V} {v : V} : + v ∈ f.fixedSubmodule ↔ f v = v := by + simp [fixedSubmodule] + +theorem fixedSubmodule_eq_ker {R : Type*} [Ring R] + {V : Type*} [AddCommGroup V] [Module R V] (f : V →ₗ[R] V) : + f.fixedSubmodule = LinearMap.ker (f - id (R := R)) := by + ext; simp [sub_eq_zero] + +theorem fixedSubmodule_eq_top_iff {f : V →ₗ[R] V} : + f.fixedSubmodule = ⊤ ↔ f = id (R := R) := by + simp [LinearMap.ext_iff, Submodule.ext_iff] + +theorem fixedSubmodule_inf_fixedSubmodule_le_comp (f g : V →ₗ[R] V) : + f.fixedSubmodule ⊓ g.fixedSubmodule ≤ (f ∘ₗ g).fixedSubmodule := by + intro; simp_all + +theorem fixedSubmodule_comp_inf_fixedSubmodule_le (f g : V →ₗ[R] V) : + (f ∘ₗ g).fixedSubmodule ⊓ g.fixedSubmodule ≤ f.fixedSubmodule := by intro; aesop + +end LinearMap + +namespace LinearEquiv + +open Pointwise LinearMap Submodule MulAction + +variable {R : Type*} [Semiring R] + {U V : Type*} [AddCommMonoid U] [AddCommMonoid V] + [Module R U] [Module R V] (e : V ≃ₗ[R] V) + +variable {P : Submodule R U} {Q : Submodule R V} + +theorem fixedSubmodule_eq_top_iff {f : V ≃ₗ[R] V} : + f.fixedSubmodule = ⊤ ↔ f = .refl R V := by + simp [LinearEquiv.ext_iff, Submodule.ext_iff] + +theorem mem_stabilizer_submodule_of_le_fixedSubmodule + {e : V ≃ₗ[R] V} {W : Submodule R V} (hW : W ≤ LinearMap.fixedSubmodule e) : + e ∈ stabilizer (V ≃ₗ[R] V) W := by + rw [mem_stabilizer_submodule_iff_map_eq] + apply le_antisymm + · rintro _ ⟨x, hx : x ∈ W, rfl⟩ + suffices e x = x by simpa [this, coe_coe] + rw [← coe_toLinearMap, ← mem_fixedSubmodule_iff] + exact hW hx + · intro x hx + refine ⟨x, hx, ?_⟩ + simp only [DistribSMul.toLinearMap_apply, LinearEquiv.smul_def] + rw [← coe_toLinearMap, ← mem_fixedSubmodule_iff] + exact hW hx + +theorem mem_stabilizer_fixedSubmodule (e : V ≃ₗ[R] V) : + e ∈ stabilizer _ e.fixedSubmodule := + mem_stabilizer_submodule_of_le_fixedSubmodule (le_refl _) + +theorem map_eq_of_mem_fixingSubgroup (W : Submodule R V) + (he : e ∈ fixingSubgroup _ W.carrier) : + map e.toLinearMap W = W := by + ext v + simp only [mem_fixingSubgroup_iff, carrier_eq_coe, SetLike.mem_coe, LinearEquiv.smul_def] at he + refine ⟨fun ⟨w, hv, hv'⟩ ↦ ?_, fun hv ↦ ?_⟩ + · simp only [SetLike.mem_coe, coe_coe] at hv hv' + rwa [← hv', he w hv] + · refine ⟨v, hv, he v hv⟩ + +open Pointwise MulAction + +variable {R V : Type*} [Ring R] [AddCommGroup V] [Module R V] + +/-- When `u : V ≃ₗ[R] V` maps a submodule `W` into itself, +this is the induced linear equivalence of `V ⧸ W`, as a group homomorphism. -/ +def reduce (W : Submodule R V) : stabilizer (V ≃ₗ[R] V) W →* (V ⧸ W) ≃ₗ[R] (V ⧸ W) where + toFun u := Quotient.equiv W W u.val u.prop + map_mul' u v := by + ext x + obtain ⟨y, rfl⟩ := W.mkQ_surjective x + simp + map_one' := by aesop + +@[simp] +theorem reduce_mk (W : Submodule R V) (u : stabilizer (V ≃ₗ[R] V) W) (x : V) : + reduce W u (Submodule.Quotient.mk x) = Submodule.Quotient.mk (u.val x) := + rfl + +theorem reduce_mkQ (W : Submodule R V) (u : stabilizer (V ≃ₗ[R] V) W) (x : V) : + reduce W u (W.mkQ x) = W.mkQ (u.val x) := + rfl + +/-- The linear equivalence deduced from `e : V ≃ₗ[R] V` +by passing to the quotient by `e.fixedSubmodule`. -/ +def fixedReduce (e : V ≃ₗ[R] V) : + (V ⧸ e.fixedSubmodule) ≃ₗ[R] V ⧸ e.fixedSubmodule := + reduce e.fixedSubmodule ⟨e, e.mem_stabilizer_fixedSubmodule⟩ + +@[simp] +theorem fixedReduce_mk (e : V ≃ₗ[R] V) (x : V) : + fixedReduce e (Submodule.Quotient.mk x) = Submodule.Quotient.mk (e x) := + rfl + +@[simp] +theorem fixedReduce_mkQ (e : V ≃ₗ[R] V) (x : V) : + fixedReduce e (e.fixedSubmodule.mkQ x) = e.fixedSubmodule.mkQ (e x) := + rfl + +theorem fixedReduce_eq_smul_iff (e : V ≃ₗ[R] V) (a : R) : + (∀ x, e.fixedReduce x = a • x) ↔ + ∀ v, e v - a • v ∈ e.fixedSubmodule := by + simp only [← e.fixedSubmodule.ker_mkQ, mem_ker, map_sub, ← fixedReduce_mkQ, sub_eq_zero] + constructor + · intro H x; simp [H] + · intro H x + have ⟨y, hy⟩ := e.fixedSubmodule.mkQ_surjective x + rw [← hy] + apply H + +theorem fixedReduce_eq_one (e : V ≃ₗ[R] V) : + e.fixedReduce = LinearEquiv.refl R _ ↔ ∀ v, e v - v ∈ e.fixedSubmodule := by + simpa [LinearEquiv.ext_iff] using fixedReduce_eq_smul_iff e 1 + +end LinearEquiv + +end diff --git a/Mathlib/LinearAlgebra/FreeAlgebra.lean b/Mathlib/LinearAlgebra/FreeAlgebra.lean index 8e566f4f477c66..49dda5cc7ff39c 100644 --- a/Mathlib/LinearAlgebra/FreeAlgebra.lean +++ b/Mathlib/LinearAlgebra/FreeAlgebra.lean @@ -54,7 +54,6 @@ end FreeAlgebra open Cardinal -set_option backward.isDefEq.respectTransparency false in theorem Algebra.rank_adjoin_le {R : Type u} {S : Type v} [CommRing R] [Ring S] [Algebra R S] (s : Set S) : Module.rank R (adjoin R s) ≤ max #s ℵ₀ := by rw [adjoin_eq_range_freeAlgebra_lift] diff --git a/Mathlib/LinearAlgebra/JordanChevalley.lean b/Mathlib/LinearAlgebra/JordanChevalley.lean index b123bce982445e..3f7697c4168486 100644 --- a/Mathlib/LinearAlgebra/JordanChevalley.lean +++ b/Mathlib/LinearAlgebra/JordanChevalley.lean @@ -42,7 +42,6 @@ namespace Module.End variable {K V : Type*} [Field K] [AddCommGroup V] [Module K V] {f : End K V} -set_option backward.isDefEq.respectTransparency false in theorem exists_isNilpotent_isSemisimple_of_separable_of_dvd_pow {P : K[X]} {k : ℕ} (sep : P.Separable) (nil : minpoly K f ∣ P ^ k) : ∃ᵉ (n ∈ adjoin K {f}) (s ∈ adjoin K {f}), IsNilpotent n ∧ IsSemisimple s ∧ f = n + s := by diff --git a/Mathlib/LinearAlgebra/Matrix/WithConv.lean b/Mathlib/LinearAlgebra/Matrix/WithConv.lean index 33a87415985dd2..8307d12892cd6f 100644 --- a/Mathlib/LinearAlgebra/Matrix/WithConv.lean +++ b/Mathlib/LinearAlgebra/Matrix/WithConv.lean @@ -5,17 +5,20 @@ Authors: Monica Omar -/ module +public import Mathlib.Algebra.Star.LinearMap +public import Mathlib.Algebra.Star.StarAlgHom public import Mathlib.Algebra.WithConv public import Mathlib.LinearAlgebra.Matrix.Hadamard +public import Mathlib.LinearAlgebra.Matrix.Symmetric -/-! The convolutive star ring on matrices +/-! # The convolutive star ring on matrices In this file, we provide the star algebra instance on `WithConv (Matrix m n R)` given by the Hadamard product and intrinsic star (i.e., the star of each element in the matrix). -/ @[expose] public section -variable {α β m n : Type*} +variable {m n α β : Type*} open Matrix WithConv @@ -94,3 +97,47 @@ instance [Monoid β] [MulAction β α] [Mul α] [IsScalarTower β α α] : instance [CommSemiring β] [Semiring α] [Algebra β α] : Algebra β (WithConv (Matrix m n α)) := .ofModule smul_mul_assoc mul_smul_comm + +/-- All matrices are intrinsically self-adjoint if they are convolutively idempotent. -/ +theorem Matrix.WithConv.IsIdempotentElem.isSelfAdjoint [Semiring α] [IsLeftCancelMulZero α] + [StarRing α] {f : WithConv (Matrix m n α)} (hf : IsIdempotentElem f) : IsSelfAdjoint f := by + simp_rw [IsIdempotentElem, WithConv.ext_iff, ← Matrix.ext_iff, convMul_def, hadamard_apply, + ← isIdempotentElem_iff, IsIdempotentElem.iff_eq_zero_or_one] at hf + rw [IsSelfAdjoint, WithConv.ext_iff] + ext i j + obtain (h | h) := hf i j <;> simp_all + +section toLin' +variable [CommSemiring α] [StarRing α] [Fintype n] [DecidableEq n] + +namespace WithConv + +variable (m n α) in +/-- `WithConv (Matrix m n α)` is ⋆-algebraically equivalent to `WithConv ((n → α) →ₗ m → α)`. + +In particular, the convolutive product on linear maps corresponds to the Hadamard product +on matrices and the intrinsic star on linear maps corresponds to taking the star of each element in +the matrix. -/ +def matrixToLin'StarAlgEquiv : + WithConv (Matrix m n α) ≃⋆ₐ[α] WithConv ((n → α) →ₗ[α] m → α) where + __ := congrLinearEquiv toLin' + map_mul' _ _ := by ext; simp + map_star' _ := by classical exact Matrix.intrinsicStar_toLin' _ |>.symm + +@[simp] lemma matrixToLin'StarAlgEquiv_apply (x : WithConv (Matrix m n α)) : + matrixToLin'StarAlgEquiv m n α x = toConv x.ofConv.toLin' := rfl +@[simp] lemma symm_matrixToLin'StarAlgEquiv_apply (x : WithConv ((n → α) →ₗ[α] m → α)) : + (matrixToLin'StarAlgEquiv m n α).symm x = toConv x.ofConv.toMatrix' := rfl + +end WithConv + +omit [StarRing α] in +lemma Matrix.toLin'_hadamard (x y : Matrix m n α) : + (x ⊙ y).toLin' = (toConv x.toLin' * toConv y.toLin').ofConv := by ext; simp + +theorem Matrix.isSymm_iff_intrinsicStar_toLin' {A : Matrix n n α} : + A.IsSymm ↔ star (toConv A.toLin') = toConv (star A).toLin' := by + rw [intrinsicStar_toLin', toConv_injective.eq_iff, toLin'.injective.eq_iff, + ← transpose_conjTranspose, star_eq_conjTranspose, conjTranspose_inj, IsSymm] + +end toLin' diff --git a/Mathlib/LinearAlgebra/Quotient/Pi.lean b/Mathlib/LinearAlgebra/Quotient/Pi.lean index 3e89b04e1eca2f..03d4dbe3443496 100644 --- a/Mathlib/LinearAlgebra/Quotient/Pi.lean +++ b/Mathlib/LinearAlgebra/Quotient/Pi.lean @@ -106,8 +106,10 @@ set_option backward.isDefEq.respectTransparency false in theorem right_inv : Function.RightInverse (invFun p) (toFun p) := by dsimp only [toFun, invFun] rw [Function.rightInverse_iff_comp, ← coe_comp, ← @id_coe R] - refine congr_arg _ (pi_ext fun i x => Submodule.Quotient.induction_on _ x fun x' => - funext fun j => ?_) + congr + refine pi_ext fun i x ↦ ?_ + induction x using Submodule.Quotient.induction_on with | _ x' + refine funext fun j ↦ ?_ rw [comp_apply, piQuotientLift_single, mapQ_apply, quotientPiLift_mk, id_apply] by_cases hij : i = j <;> simp only [mkQ_apply, coe_single] diff --git a/Mathlib/LinearAlgebra/RootSystem/Base.lean b/Mathlib/LinearAlgebra/RootSystem/Base.lean index 2dd04b73c5cc3b..3421deb5ef6f56 100644 --- a/Mathlib/LinearAlgebra/RootSystem/Base.lean +++ b/Mathlib/LinearAlgebra/RootSystem/Base.lean @@ -258,7 +258,7 @@ lemma sub_notMem_range_root have hf : ∑ k ∈ b.support, f k • P.root k = P.root i - P.root j := by have : {i, j} ⊆ b.support := by aesop (add simp Finset.insert_subset_iff) rw [← Finset.sum_subset (s₁ := {i, j}) (s₂ := b.support) (by lia) (by aesop), - Finset.sum_insert (by aesop), Finset.sum_singleton] + Finset.sum_insert (by grind), Finset.sum_singleton] simp [f, hij, sub_eq_add_neg] intro contra rcases b.pos_or_neg_of_sum_smul_root_mem f (by rwa [hf]) (by aesop) with pos | neg diff --git a/Mathlib/LinearAlgebra/RootSystem/Finite/G2.lean b/Mathlib/LinearAlgebra/RootSystem/Finite/G2.lean index 8c68dcaf3cadae..96d7e6637691ca 100644 --- a/Mathlib/LinearAlgebra/RootSystem/Finite/G2.lean +++ b/Mathlib/LinearAlgebra/RootSystem/Finite/G2.lean @@ -560,7 +560,7 @@ lemma mem_allRoots (i : ι) : simp only [LinearMap.zero_apply] induction hx using Submodule.span_induction with | zero => simp - | mem => aesop + | mem => grind | add => simp_all | smul => simp_all simpa using LinearMap.congr_fun key (P.root i) diff --git a/Mathlib/LinearAlgebra/RootSystem/GeckConstruction/Lemmas.lean b/Mathlib/LinearAlgebra/RootSystem/GeckConstruction/Lemmas.lean index a3a76acb6c8e01..33513d59325d6c 100644 --- a/Mathlib/LinearAlgebra/RootSystem/GeckConstruction/Lemmas.lean +++ b/Mathlib/LinearAlgebra/RootSystem/GeckConstruction/Lemmas.lean @@ -236,7 +236,7 @@ private lemma chainBotCoeff_mul_chainTopCoeff.aux_1 have key₁ : P.pairingIn ℤ i k = 0 := by rwa [pairingIn_eq_zero_iff] have key₂ : P.pairingIn ℤ i m = 0 := P.pairingIn_eq_zero_iff.mp <| by simpa [aux₁] using aux₀ have key₃ : P.pairingIn ℤ j k = 2 := by - suffices 2 ≤ P.pairingIn ℤ j k by have := IsNotG2.pairingIn_mem_zero_one_two (P := P) j k; aesop + suffices 2 ≤ P.pairingIn ℤ j k by have := IsNotG2.pairingIn_mem_zero_one_two (P := P) j k; grind have hn₁ : P.pairingIn ℤ n k = 2 + P.pairingIn ℤ i k - P.pairingIn ℤ j k := by apply algebraMap_injective ℤ R simp only [map_add, map_sub, algebraMap_pairingIn, ← root_coroot_eq_pairing, hn] @@ -249,7 +249,7 @@ private lemma chainBotCoeff_mul_chainTopCoeff.aux_1 rw [pairing_eq_zero_iff, ← P.algebraMap_pairingIn ℤ, aux₁, map_zero] have hkj : P.pairing k j = 1 := by rw [← P.algebraMap_pairingIn ℤ] - have := P.pairingIn_pairingIn_mem_set_of_isCrystal_of_isRed' j k (by aesop) (by aesop) + have := P.pairingIn_pairingIn_mem_set_of_isCrystal_of_isRed' j k (by grind) (by grind) aesop apply algebraMap_injective ℤ R rw [algebraMap_pairingIn, ← root_coroot_eq_pairing, ← h₁] @@ -305,14 +305,14 @@ private lemma chainBotCoeff_mul_chainTopCoeff.aux_2 algebraMap_injective ℤ R <| by simpa only [algebraMap_pairingIn, map_add] simp [← P.root_coroot_eq_pairing l, ← h₁, add_comm] · have := IsNotG2.pairingIn_mem_zero_one_two (P := P) k j - aesop + grind /- Choose a positive invariant form. -/ obtain B : RootPositiveForm ℤ P := have : Fintype ι := Fintype.ofFinite ι; P.posRootForm ℤ /- Calculate root length relationships implied by the pairings calculated above. -/ have ⟨aux₃, aux₄⟩ : B.rootLength i = B.rootLength j ∧ B.rootLength j < B.rootLength k := by have hij_le : B.rootLength i ≤ B.rootLength j := B.rootLength_le_of_pairingIn_eq <| Or.inl aux₁ have hjk_lt : B.rootLength j < B.rootLength k := - B.rootLength_lt_of_pairingIn_notMem (by aesop) hkj_ne.2 <| by aesop + B.rootLength_lt_of_pairingIn_notMem (by grind) hkj_ne.2 <| by grind refine ⟨?_, hjk_lt⟩ simpa [posForm, rootLength] using (B.toInvariantForm.apply_eq_or_of_apply_ne (i := j) (j := k) (by simpa [posForm, rootLength] using hjk_lt.ne) i).resolve_right @@ -323,7 +323,7 @@ private lemma chainBotCoeff_mul_chainTopCoeff.aux_2 have aux : B.toInvariantForm.form (P.root i) (P.root i) = B.toInvariantForm.form (P.root j) (P.root j) := by simpa [posForm, rootLength] using aux₃ have := P.pairingIn_pairingIn_mem_set_of_length_eq_of_ne aux hij (b.root_ne_neg_of_ne hi hj hij) - aesop + grind /- Use the newly calculated pairing result to obtain further information about root lengths. -/ have aux₆ : B.rootLength k ≤ B.rootLength i := B.rootLength_le_of_pairingIn_eq <| Or.inl aux₅ /- We now have contradictory information about root lengths. -/ diff --git a/Mathlib/LinearAlgebra/SesquilinearForm/Basic.lean b/Mathlib/LinearAlgebra/SesquilinearForm/Basic.lean index b5627398ef5cae..eda96854d3d2e0 100644 --- a/Mathlib/LinearAlgebra/SesquilinearForm/Basic.lean +++ b/Mathlib/LinearAlgebra/SesquilinearForm/Basic.lean @@ -112,15 +112,7 @@ theorem ortho_smul_left {B : V₁ →ₛₗ[I₁] V₂ →ₛₗ[I₂] V} {x y} -- todo: this also holds for [CommRing R] [IsDomain R] when J₂ is invertible theorem ortho_smul_right {B : V₁ →ₛₗ[I₁] V₂ →ₛₗ[I₂] V} {x y} {a : K₂} {ha : a ≠ 0} : IsOrtho B x y ↔ IsOrtho B x (a • y) := by - dsimp only [IsOrtho] - constructor <;> intro H - · rw [map_smulₛₗ, H, smul_zero] - · rw [map_smulₛₗ, smul_eq_zero] at H - rcases H with H | H - · simp only [map_eq_zero] at H - exfalso - exact ha H - · exact H + simp_all [IsOrtho] /-- A set of orthogonal vectors `v` with respect to some sesquilinear map `B` is linearly independent if for all `i`, `B (v i) (v i) ≠ 0`. -/ diff --git a/Mathlib/LinearAlgebra/Span/Basic.lean b/Mathlib/LinearAlgebra/Span/Basic.lean index b4a063da3638d8..54d2c8b2f343e3 100644 --- a/Mathlib/LinearAlgebra/Span/Basic.lean +++ b/Mathlib/LinearAlgebra/Span/Basic.lean @@ -432,11 +432,14 @@ theorem _root_.LinearMap.exists_ne_zero_of_sSup_eq {N : Submodule R M} {f : N by rw [sSup_eq_iSup] at hs; rw [sSup_image, ← hs, biSup_comap_subtype_eq_top] ⟨m, hm, fun eq ↦ ne (LinearMap.ext fun x ↦ congr($eq ⟨x, x.2⟩))⟩ +lemma span_val_image_eq_iff (p : Submodule R M) (s : Set p) : + span R (Subtype.val '' s) = p ↔ span R s = ⊤ := by + simp [← (Submodule.map_injective_of_injective p.injective_subtype).eq_iff, Submodule.map_span] + lemma span_range_subtype_eq_top_iff {ι : Type*} (p : Submodule R M) {s : ι → M} (hs : ∀ i, s i ∈ p) : span R (Set.range fun i ↦ (⟨s i, hs i⟩ : p)) = ⊤ ↔ span R (Set.range s) = p := by - rw [← (map_injective_of_injective p.injective_subtype).eq_iff] - simp [map_span, ← Set.range_comp, Function.comp_def] + simp [← span_val_image_eq_iff, ← Set.range_comp, Function.comp_def] lemma comap_le_comap_iff_of_le_range {f : M →ₛₗ[σ₁₂] M₂} [RingHomSurjective σ₁₂] {p q : Submodule R₂ M₂} (hp : p ≤ LinearMap.range f) : diff --git a/Mathlib/LinearAlgebra/TensorAlgebra/Basic.lean b/Mathlib/LinearAlgebra/TensorAlgebra/Basic.lean index 909fcb1ac8eccc..c4015437834755 100644 --- a/Mathlib/LinearAlgebra/TensorAlgebra/Basic.lean +++ b/Mathlib/LinearAlgebra/TensorAlgebra/Basic.lean @@ -176,7 +176,6 @@ theorem hom_ext {A : Type*} [Semiring A] [Algebra R A] {f g : TensorAlgebra R M rw [← lift_symm_apply, ← lift_symm_apply] at w exact (lift R).symm.injective w -set_option backward.isDefEq.respectTransparency false in -- This proof closely follows `FreeAlgebra.induction` /-- If `C` holds for the `algebraMap` of `r : R` into `TensorAlgebra R M`, the `ι` of `x : M`, and is preserved under addition and multiplication, then it holds for all of `TensorAlgebra R M`. diff --git a/Mathlib/LinearAlgebra/TensorProduct/Quotient.lean b/Mathlib/LinearAlgebra/TensorProduct/Quotient.lean index affdc999b3907a..64b546bc3044f9 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/Quotient.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/Quotient.lean @@ -181,7 +181,6 @@ lemma quotTensorEquivQuotSMul_mk_tmul (I : Ideal R) (r : R) (x : M) : Submodule.Quotient.mk_smul I r 1) <| smul_tmul r _ x -set_option backward.isDefEq.respectTransparency false in @[simp] lemma quotTensorEquivQuotSMul_mk_one_tmul (I : Ideal R) (x : M) : quotTensorEquivQuotSMul M I (1 ⊗ₜ x) = Submodule.Quotient.mk x := by diff --git a/Mathlib/LinearAlgebra/TensorProduct/Subalgebra.lean b/Mathlib/LinearAlgebra/TensorProduct/Subalgebra.lean index 4e372c14628f18..a7cde0ff9d359e 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/Subalgebra.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/Subalgebra.lean @@ -52,7 +52,6 @@ namespace Subalgebra variable (A : Subalgebra R S) -set_option backward.isDefEq.respectTransparency false in /-- If `A` is a subalgebra of `S/R`, there is the natural `R`-algebra isomorphism between `i(R) ⊗[R] A` and `A` induced by multiplication in `S`, here `i : R → S` is the structure map. This generalizes `Algebra.TensorProduct.lid` as `i(R)` is not necessarily isomorphic to `R`. @@ -82,11 +81,9 @@ theorem lTensorBot_tmul (x : R) (a : A) : A.lTensorBot (algebraMap R _ x ⊗ₜ[ theorem lTensorBot_one_tmul (a : A) : A.lTensorBot (1 ⊗ₜ[R] a) = a := (toSubmodule A).lTensorOne_one_tmul a -set_option backward.isDefEq.respectTransparency false in @[simp] theorem lTensorBot_symm_apply (a : A) : A.lTensorBot.symm a = 1 ⊗ₜ[R] a := rfl -set_option backward.isDefEq.respectTransparency false in variable (A) in /-- If `A` is a subalgebra of `S/R`, there is the natural `R`-algebra isomorphism between `A ⊗[R] i(R)` and `A` induced by multiplication in `S`, here `i : R → S` is the structure map. @@ -115,7 +112,6 @@ theorem rTensorBot_tmul (x : R) (a : A) : A.rTensorBot (a ⊗ₜ[R] algebraMap R theorem rTensorBot_tmul_one (a : A) : A.rTensorBot (a ⊗ₜ[R] 1) = a := (toSubmodule A).rTensorOne_tmul_one a -set_option backward.isDefEq.respectTransparency false in @[simp] theorem rTensorBot_symm_apply (a : A) : A.rTensorBot.symm a = a ⊗ₜ[R] 1 := rfl @@ -177,7 +173,6 @@ theorem linearEquivIncludeRange_tmul (x y) : theorem linearEquivIncludeRange_symm_tmul (x y) : (linearEquivIncludeRange R S T).symm (x ⊗ₜ[R] y) = x.1 * y.1 := rfl -set_option backward.isDefEq.respectTransparency false in /-- Given `R`-algebras `S,T`, there is a natural `R`-algebra isomorphism from `S ⊗[R] T` to `S' ⊗[R] T'` where `S',T'` are the images of `S,T` in `S ⊗[R] T` respectively. -/ def algEquivIncludeRange : @@ -185,7 +180,6 @@ def algEquivIncludeRange : (includeRight : T →ₐ[R] S ⊗[R] T).range := algEquivOfLinearEquivTensorProduct (linearEquivIncludeRange R S T) (by simp) rfl -set_option backward.isDefEq.respectTransparency false in theorem algEquivIncludeRange_toAlgHom : (algEquivIncludeRange R S T).toAlgHom = map includeLeft.rangeRestrict includeRight.rangeRestrict := rfl @@ -196,7 +190,6 @@ theorem algEquivIncludeRange_tmul (x y) : ((includeLeft : S →ₐ[R] S ⊗[R] T).rangeRestrict x) ⊗ₜ[R] ((includeRight : T →ₐ[R] S ⊗[R] T).rangeRestrict y) := rfl -set_option backward.isDefEq.respectTransparency false in @[simp] theorem algEquivIncludeRange_symm_tmul (x y) : (algEquivIncludeRange R S T).symm (x ⊗ₜ[R] y) = x.1 * y.1 := rfl @@ -211,13 +204,11 @@ variable [CommSemiring R] [CommSemiring S] [Algebra R S] [CommSemiring T] [Algeb variable (A B : Subalgebra R S) -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are subalgebras in a commutative algebra `S` over `R`, there is the natural `R`-algebra homomorphism `A ⊗[R] B →ₐ[R] S` induced by multiplication in `S`. -/ def Subalgebra.mulMap : A ⊗[R] B →ₐ[R] S := Algebra.TensorProduct.productMap A.val B.val -set_option backward.isDefEq.respectTransparency false in variable (R S T) in theorem Algebra.TensorProduct.algEquivIncludeRange_symm_toAlgHom : (algEquivIncludeRange R S T).symm.toAlgHom = @@ -228,34 +219,27 @@ namespace Subalgebra @[simp] theorem mulMap_tmul (a : A) (b : B) : mulMap A B (a ⊗ₜ[R] b) = a.1 * b.1 := rfl -set_option backward.isDefEq.respectTransparency false in theorem mulMap_map_comp_eq (f : S →ₐ[R] T) : (mulMap (A.map f) (B.map f)).comp (Algebra.TensorProduct.map (f.subalgebraMap A) (f.subalgebraMap B)) = f.comp (mulMap A B) := by ext <;> simp -set_option backward.isDefEq.respectTransparency false in theorem mulMap_toLinearMap : (A.mulMap B).toLinearMap = (toSubmodule A).mulMap (toSubmodule B) := rfl -set_option backward.isDefEq.respectTransparency false in theorem mulMap_comm : mulMap B A = (mulMap A B).comp (Algebra.TensorProduct.comm R B A) := by ext <;> simp -set_option backward.isDefEq.respectTransparency false in theorem mulMap_range : (A.mulMap B).range = A ⊔ B := by simp_rw [mulMap, Algebra.TensorProduct.productMap_range, Subalgebra.range_val] -set_option backward.isDefEq.respectTransparency false in theorem mulMap_bot_left_eq : mulMap ⊥ A = A.val.comp A.lTensorBot.toAlgHom := AlgHom.toLinearMap_injective (toSubmodule A).mulMap_one_left_eq -set_option backward.isDefEq.respectTransparency false in theorem mulMap_bot_right_eq : mulMap A ⊥ = A.val.comp A.rTensorBot.toAlgHom := AlgHom.toLinearMap_injective (toSubmodule A).mulMap_one_right_eq -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are subalgebras in a commutative algebra `S` over `R`, there is the natural `R`-algebra homomorphism `A ⊗[R] B →ₐ[R] A ⊔ B` induced by multiplication in `S`, diff --git a/Mathlib/LinearAlgebra/TensorProduct/Submodule.lean b/Mathlib/LinearAlgebra/TensorProduct/Submodule.lean index 1fb0e0867a59c9..cb790fb68c5164 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/Submodule.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/Submodule.lean @@ -145,7 +145,6 @@ def lTensorOne' : (⊥ : Subalgebra R S) ⊗[R] N →ₗ[R] N := (LinearEquiv.ofEq _ _ (by rw [Algebra.toSubmodule_bot, mulMap_range, one_mul])).toLinearMap ∘ₗ (mulMap _ N).rangeRestrict -set_option backward.isDefEq.respectTransparency false in variable {N} in @[simp] theorem lTensorOne'_tmul (y : R) (n : N) : @@ -197,7 +196,6 @@ def rTensorOne' : M ⊗[R] (⊥ : Subalgebra R S) →ₗ[R] M := (LinearEquiv.ofEq _ _ (by rw [Algebra.toSubmodule_bot, mulMap_range, mul_one])).toLinearMap ∘ₗ (mulMap M _).rangeRestrict -set_option backward.isDefEq.respectTransparency false in variable {M} in @[simp] theorem rTensorOne'_tmul (y : R) (m : M) : diff --git a/Mathlib/LinearAlgebra/Transvection.lean b/Mathlib/LinearAlgebra/Transvection.lean index 9393f63e53376d..87e14055f02103 100644 --- a/Mathlib/LinearAlgebra/Transvection.lean +++ b/Mathlib/LinearAlgebra/Transvection.lean @@ -6,10 +6,11 @@ Authors: Antoine Chambert-Loir module +public import Mathlib.GroupTheory.GroupAction.SubMulAction.OfFixingSubgroup public import Mathlib.LinearAlgebra.Charpoly.BaseChange -public import Mathlib.LinearAlgebra.Dimension.FreeAndStrongRankCondition -public import Mathlib.LinearAlgebra.DFinsupp public import Mathlib.LinearAlgebra.Dual.BaseChange +public import Mathlib.LinearAlgebra.Dual.Lemmas +public import Mathlib.LinearAlgebra.FixedSubmodule /-! # Transvections in a module @@ -60,6 +61,8 @@ def transvection (f : Dual R V) (v : V) : V →ₗ[R] V where namespace transvection +open Submodule LinearMap + theorem apply (f : Dual R V) (v x : V) : transvection f v x = x + f x • v := rfl @@ -197,6 +200,18 @@ theorem inv_eq' {f : Dual R V} {v : V} end transvection +theorem mem_fixedSubmodule_transvection_iff {f : Dual R V} {v : V} {hfv : f v = 0} {x : V} : + x ∈ (LinearEquiv.transvection hfv).fixedSubmodule ↔ f x • v = 0 := by + simp [LinearMap.transvection.apply, add_eq_left] + +theorem ker_le_fixedSubmodule_transvection {f : Dual R V} {v : V} (hfv : f v = 0) : + LinearMap.ker f ≤ (transvection hfv).fixedSubmodule := by + intro x hx + rw [mem_ker] at hx + simp [LinearMap.transvection.apply, hx] + +section dilatransvections + variable (R V) in /-- The set of transvections in the group of linear equivalences -/ def transvections : Set (V ≃ₗ[R] V) := @@ -258,6 +273,14 @@ theorem transvections_subset_dilatransvections : theorem refl_mem_dilatransvections : refl R V ∈ dilatransvections R V := transvections_subset_dilatransvections one_mem_transvections +theorem transvection_mem_transvections {f : Dual R V} {v : V} {hfv : f v = 0} : + transvection hfv ∈ transvections R V := + ⟨f, v, hfv, rfl⟩ + +theorem transvection_mem_dilatransvections {f : Dual R V} {v : V} (hfv : f v = 0) : + transvection hfv ∈ dilatransvections R V := + transvections_subset_dilatransvections transvection_mem_transvections + @[simp] theorem one_mem_dilatransvections : 1 ∈ dilatransvections R V := refl_mem_dilatransvections @@ -284,11 +307,15 @@ theorem dilatransvections_pow_mono : Monotone (fun n : ℕ ↦ (dilatransvections R V) ^ n) := Set.pow_right_monotone one_mem_dilatransvections +section divisionRing + +variable {K : Type*} [DivisionRing K] [Module K V] + /-- Over a division ring, `dilatransvections` correspond to linear equivalences `e` such that the linear map `e - id` has rank at most 1. See also `LinearEquiv.mem_dilatransvections_iff_finrank`. -/ -theorem mem_dilatransvections_iff_rank {K : Type*} [DivisionRing K] [Module K V] {e : V ≃ₗ[K] V} : +theorem mem_dilatransvections_iff_rank {e : V ≃ₗ[K] V} : e ∈ dilatransvections K V ↔ Module.rank K (range ((e : V →ₗ[K] V) - LinearMap.id (R := K))) ≤ 1 := by simp only [dilatransvections] @@ -330,15 +357,88 @@ open Cardinal in equivalences `e` such that the linear map `e - id` has rank at most 1. See also `LinearEquiv.mem_dilatransvections_iff_rank`. -/ -theorem mem_dilatransvections_iff_finrank - {K : Type*} [DivisionRing K] [Module K V] [Module.Finite K V] - {e : V ≃ₗ[K] V} : +theorem mem_dilatransvections_iff_finrank [Module.Finite K V] {e : V ≃ₗ[K] V} : e ∈ dilatransvections K V ↔ finrank K (range ((e : V →ₗ[K] V) - LinearMap.id (R := K))) ≤ 1 := by rw [mem_dilatransvections_iff_rank, finrank, ← one_toNat, toNat_le_iff_le_of_lt_aleph0 (rank_lt_aleph0 K _) one_lt_aleph0] -end LinearEquiv +theorem mem_dilatransvections_iff_finrank_quotient [Module.Finite K V] {e : V ≃ₗ[K] V} : + e ∈ dilatransvections K V ↔ finrank K (V ⧸ e.fixedSubmodule) ≤ 1 := by + rw [mem_dilatransvections_iff_finrank, ← (quotKerEquivRange _).finrank_eq, + ← fixedSubmodule_eq_ker] + +theorem mem_dilatransvections_iff_rank_quotient {e : V ≃ₗ[K] V} : + e ∈ dilatransvections K V ↔ Module.rank K (V ⧸ e.fixedSubmodule) ≤ 1 := by + rw [mem_dilatransvections_iff_rank, ← (quotKerEquivRange _).rank_eq, ← fixedSubmodule_eq_ker] + +variable (e f : V ≃ₗ[K] V) +open Pointwise MulAction + +/-- Characterization of transvections within dilatransvections. -/ +theorem mem_transvections_iff_mem_dilatransvections_and_fixedReduce_eq_one + [Module.Finite K V] (e : V ≃ₗ[K] V) : + e ∈ transvections K V ↔ e ∈ dilatransvections K V ∧ e.fixedReduce = 1 := by + refine ⟨fun ⟨f, v, hfv, he⟩ ↦ ?_, fun ⟨he, he'⟩ ↦ ?_⟩ + · constructor + · rw [he] + exact transvection_mem_dilatransvections hfv + · rw [one_eq_refl, fixedReduce_eq_one, he] + intro x + apply ker_le_fixedSubmodule_transvection hfv + rw [transvection.apply] + simp [hfv] + · by_cases he_one : e = 1 + · use 0, 0, by simp, by aesop + have hefixed_ne_top : e.fixedSubmodule ≠ ⊤ := by + rwa [ne_eq, LinearEquiv.fixedSubmodule_eq_top_iff] + obtain ⟨w : V, hw : w ∉ e.fixedSubmodule⟩ := + SetLike.exists_not_mem_of_ne_top e.fixedSubmodule hefixed_ne_top rfl + obtain ⟨f, hfw, hf⟩ := Submodule.exists_dual_map_eq_bot_of_notMem hw inferInstance + rw [mem_dilatransvections_iff_finrank_quotient] at he + have hf' : e.fixedSubmodule = LinearMap.ker f := by + suffices finrank K (V ⧸ LinearMap.ker f) = 1 by + apply Submodule.eq_of_le_of_finrank_le + · intro x + rw [mem_ker, ← Submodule.mem_bot K, ← hf] + exact mem_map_of_mem + rw [← Nat.add_le_add_iff_right, finrank_quotient_add_finrank] at he + have := (LinearMap.ker f).finrank_quotient_add_finrank + linarith + rw [← Nat.add_left_inj, Submodule.finrank_quotient_add_finrank] + rw [← f.finrank_ker_add_one_of_ne_zero, add_comm] + aesop + have eq_top : e.fixedSubmodule ⊔ Submodule.span K {w} = ⊤ := by + rw [Submodule.sup_span_singleton_eq_top_iff hw] + apply le_antisymm he + apply Nat.one_le_of_lt + rw [← Nat.ne_zero_iff_zero_lt] + contrapose hefixed_ne_top + apply eq_top_of_finrank_eq + rw [← Nat.add_left_cancel_iff, finrank_quotient_add_finrank, hefixed_ne_top, zero_add] + set v := (f w)⁻¹ • (e w - w) + suffices hfv : f v = 0 by + use f, v, hfv + rw [← LinearEquiv.toLinearMap_inj, + ← sub_eq_zero, ← LinearMap.ker_eq_top, eq_top_iff, ← eq_top] + simp only [LinearEquiv.transvection.coe_toLinearMap, + sup_le_iff, Submodule.span_singleton_le_iff_mem, LinearMap.mem_ker, LinearMap.sub_apply, + LinearEquiv.coe_coe] + constructor + · intro x hx + suffices f x = 0 by + simpa [this, LinearMap.transvection.apply, sub_eq_zero] using hx + rwa [hf', LinearMap.mem_ker] at hx + · simp_all [v, LinearMap.transvection.apply] + suffices e w - w ∈ LinearMap.ker f by + simp only [LinearMap.mem_ker, map_sub] at this + simp only [v, LinearMap.map_smul, map_sub, this, smul_zero] + rw [← hf', ← Submodule.ker_mkQ e.fixedSubmodule, LinearMap.mem_ker] + simp [Submodule.mkQ_apply, Submodule.Quotient.mk_sub, ← fixedReduce_mk, he'] + +end divisionRing + +end LinearEquiv.dilatransvections section baseChange @@ -378,7 +478,6 @@ variable {R V A : Type*} [CommRing R] [AddCommGroup V] {W : Type*} [AddCommMonoid W] [Module R W] [Module A W] [IsScalarTower R A W] {ε : V →ₗ[R] W} (ibc : IsBaseChange A ε) - theorem LinearEquiv.transvection.baseChange (hA : f.baseChange A (1 ⊗ₜ[R] v) = 0 := by simp [Algebra.algebraMap_eq_smul_one]) : (LinearEquiv.transvection h).baseChange R A V V = LinearEquiv.transvection hA := by @@ -543,3 +642,5 @@ end transvection end LinearMap end determinant + +end diff --git a/Mathlib/Logic/Basic.lean b/Mathlib/Logic/Basic.lean index 57da66ed92527d..a73c145e201289 100644 --- a/Mathlib/Logic/Basic.lean +++ b/Mathlib/Logic/Basic.lean @@ -6,7 +6,8 @@ Authors: Jeremy Avigad, Leonardo de Moura module public import Mathlib.Tactic.AdaptationNote -public import Mathlib.Tactic.Basic +public import Mathlib.Tactic.TypeStar +public import Mathlib.Tactic.Lemma public import Batteries.Logic public import Batteries.Util.LibraryNote diff --git a/Mathlib/Logic/Equiv/Basic.lean b/Mathlib/Logic/Equiv/Basic.lean index c416f19729ae36..fbc5193ae2dbab 100644 --- a/Mathlib/Logic/Equiv/Basic.lean +++ b/Mathlib/Logic/Equiv/Basic.lean @@ -591,8 +591,11 @@ def subtypeQuotientEquivQuotientSubtype (p₁ : α → Prop) {s₁ : Setoid α} invFun a := Quotient.liftOn a (fun a => (⟨⟦a.1⟧, (hp₂ _).1 a.2⟩ : { x // p₂ x })) fun _ _ hab => Subtype.ext (Quotient.sound ((h _ _).1 hab)) - left_inv := by exact fun ⟨a, ha⟩ => Quotient.inductionOn a (fun b hb => rfl) ha - right_inv a := by exact Quotient.inductionOn a fun ⟨a, ha⟩ => rfl + left_inv a := by + obtain ⟨a, ha⟩ := a + induction a using Quotient.inductionOn + rfl + right_inv a := by induction a using Quotient.inductionOn; rfl @[simp] theorem subtypeQuotientEquivQuotientSubtype_mk (p₁ : α → Prop) diff --git a/Mathlib/Logic/Relation.lean b/Mathlib/Logic/Relation.lean index 052246f1cae6d1..2e3286a804d8a4 100644 --- a/Mathlib/Logic/Relation.lean +++ b/Mathlib/Logic/Relation.lean @@ -12,7 +12,6 @@ public import Mathlib.Tactic.SimpRw public import Mathlib.Order.Defs.Unbundled public import Batteries.Logic public import Batteries.Tactic.Trans -public import Mathlib.Tactic.Basic /-! # Relation closures diff --git a/Mathlib/MeasureTheory/Constructions/Polish/StronglyMeasurable.lean b/Mathlib/MeasureTheory/Constructions/Polish/StronglyMeasurable.lean index ac6512290a7bcd..339c14c20a1cf6 100644 --- a/Mathlib/MeasureTheory/Constructions/Polish/StronglyMeasurable.lean +++ b/Mathlib/MeasureTheory/Constructions/Polish/StronglyMeasurable.lean @@ -50,7 +50,7 @@ theorem measurableSet_exists_tendsto (hf : ∀ i, StronglyMeasurable (f i)) : fun ⟨c, hc⟩ ↦ ⟨c, tendsto_subtype_rng.1 hc⟩⟩ exact mem_closure_of_tendsto hc (Eventually.of_forall fun i ↦ mem_iUnion.2 ⟨i, ⟨x, rfl⟩⟩) -theorem limUnder [hE : Nonempty E] (hf : ∀ i, StronglyMeasurable (f i)) : +protected theorem limUnder [hE : Nonempty E] (hf : ∀ i, StronglyMeasurable (f i)) : StronglyMeasurable (fun x ↦ limUnder l (f · x)) := by obtain rfl | hl := eq_or_neBot l · simpa [limUnder, Filter.map_bot] using stronglyMeasurable_const @@ -59,8 +59,8 @@ theorem limUnder [hE : Nonempty E] (hf : ∀ i, StronglyMeasurable (f i)) : rw [stronglyMeasurable_iff_measurable_separable]; constructor · let conv := {x | ∃ c, Tendsto (f · x) l (𝓝 c)} have mconv : MeasurableSet conv := StronglyMeasurable.measurableSet_exists_tendsto hf - have : (fun x ↦ _root_.limUnder l (f · x)) = ((↑) : conv → X).extend - (fun x ↦ _root_.limUnder l (f · x)) (fun _ ↦ e) := by + have : (fun x ↦ limUnder l (f · x)) = ((↑) : conv → X).extend + (fun x ↦ limUnder l (f · x)) (fun _ ↦ e) := by ext x by_cases hx : x ∈ conv · rw [Function.extend_val_apply hx] diff --git a/Mathlib/MeasureTheory/Function/AEEqFun.lean b/Mathlib/MeasureTheory/Function/AEEqFun.lean index d3e767f5524bd0..30e7591ffabeb8 100644 --- a/Mathlib/MeasureTheory/Function/AEEqFun.lean +++ b/Mathlib/MeasureTheory/Function/AEEqFun.lean @@ -235,6 +235,38 @@ theorem coeFn_compQuasiMeasurePreserving (g : β →ₘ[ν] γ) (hf : QuasiMeasu rw [compQuasiMeasurePreserving_eq_mk] apply coeFn_mk +theorem compQuasiMeasurePreserving_congr (g : β →ₘ[ν] γ) (hf : QuasiMeasurePreserving f μ ν) + {f' : α → β} (hf' : Measurable f') (h : f =ᵐ[μ] f') : + compQuasiMeasurePreserving g f hf = compQuasiMeasurePreserving g f' (hf.congr hf' h) := by + ext + grw [coeFn_compQuasiMeasurePreserving, coeFn_compQuasiMeasurePreserving, h] + +@[simp] +theorem compQuasiMeasurePreserving_id (g : β →ₘ[ν] γ) : + compQuasiMeasurePreserving g id (.id ν) = g := by + ext + exact coeFn_compQuasiMeasurePreserving _ _ + +theorem compQuasiMeasurePreserving_comp {γ : Type*} {mγ : MeasurableSpace γ} + {ξ : Measure γ} (g : γ →ₘ[ξ] δ) {f : β → γ} (hf : QuasiMeasurePreserving f ν ξ) {f' : α → β} + (hf' : QuasiMeasurePreserving f' μ ν) : + compQuasiMeasurePreserving g (f ∘ f') (hf.comp hf') = + compQuasiMeasurePreserving (compQuasiMeasurePreserving g f hf) f' hf' := by + ext + grw [coeFn_compQuasiMeasurePreserving, coeFn_compQuasiMeasurePreserving, + coeFn_compQuasiMeasurePreserving, comp_assoc] + assumption + +theorem compQuasiMeasurePreserving_iterate (g : α →ₘ[μ] γ) {f : α → α} + (hf : QuasiMeasurePreserving f μ μ) (n : ℕ) : + (compQuasiMeasurePreserving · f hf)^[n] g = + compQuasiMeasurePreserving g (f^[n]) (hf.iterate n) := by + induction n with + | zero => simp + | succ n hind => + nth_rewrite 1 [add_comm] + simp [iterate_add, hind, ← compQuasiMeasurePreserving_comp] + end compQuasiMeasurePreserving section compMeasurePreserving @@ -264,6 +296,28 @@ theorem coeFn_compMeasurePreserving (g : β →ₘ[ν] γ) (hf : MeasurePreservi g.compMeasurePreserving f hf =ᵐ[μ] g ∘ f := g.coeFn_compQuasiMeasurePreserving _ +theorem compMeasurePreserving_congr (g : β →ₘ[ν] γ) (hf : MeasurePreserving f μ ν) + {f' : α → β} (hf' : Measurable f') (h : f =ᵐ[μ] f') : + compMeasurePreserving g f hf = compMeasurePreserving g f' (hf.congr hf' h) := + compQuasiMeasurePreserving_congr _ _ hf' h + +@[simp] +theorem compMeasurePreserving_id (g : β →ₘ[ν] γ) : + compMeasurePreserving g id (.id ν) = g := + compQuasiMeasurePreserving_id _ + +theorem compMeasurePreserving_comp {γ : Type*} {mγ : MeasurableSpace γ} + {ξ : Measure γ} (g : γ →ₘ[ξ] δ) {f : β → γ} (hf : MeasurePreserving f ν ξ) {f' : α → β} + (hf' : MeasurePreserving f' μ ν) : + compMeasurePreserving g (f ∘ f') (hf.comp hf') = + compMeasurePreserving (compMeasurePreserving g f hf) f' hf' := + compQuasiMeasurePreserving_comp _ _ _ + +theorem compMeasurePreserving_iterate (g : α →ₘ[μ] γ) {f : α → α} + (hf : MeasurePreserving f μ μ) (n : ℕ) : + (compMeasurePreserving · f hf)^[n] g = compMeasurePreserving g (f^[n]) (hf.iterate n) := + compQuasiMeasurePreserving_iterate _ _ _ + end compMeasurePreserving variable [TopologicalSpace β] [TopologicalSpace γ] diff --git a/Mathlib/MeasureTheory/Function/ConditionalExpectation/Basic.lean b/Mathlib/MeasureTheory/Function/ConditionalExpectation/Basic.lean index 88979f2a404acb..2ae454c73467c1 100644 --- a/Mathlib/MeasureTheory/Function/ConditionalExpectation/Basic.lean +++ b/Mathlib/MeasureTheory/Function/ConditionalExpectation/Basic.lean @@ -276,6 +276,7 @@ theorem condExp_bot_ae_eq (f : α → E) : · rw [ae_zero]; exact eventually_bot · exact Eventually.of_forall <| congr_fun (condExp_bot' f) +@[simp] theorem condExp_bot [IsProbabilityMeasure μ] (f : α → E) : μ[f | ⊥] = fun _ => ∫ x, f x ∂μ := by refine (condExp_bot' f).trans ?_ rw [probReal_univ, inv_one, one_smul] diff --git a/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondJensen.lean b/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondJensen.lean new file mode 100644 index 00000000000000..53f435cfad4ea1 --- /dev/null +++ b/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondJensen.lean @@ -0,0 +1,187 @@ +/- +Copyright (c) 2026 Yongxi Lin. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yongxi Lin, Thomas Zhu +-/ +module + +public import Mathlib.MeasureTheory.Function.ConditionalExpectation.Indicator + +import Mathlib.Analysis.Convex.Approximation +import Mathlib.Analysis.Convex.Continuous + +/-! +# Conditional Jensen's Inequality + +This file contains the conditional Jensen's inequality. We follow the proof in +[Hytonen_VanNeerven_Veraar_Wies_2016]. + +## Main Statement + +* `Convex.condExp_mem `: in a Banach space `E` with a finite measure `μ`, if `f` lies in a + closed convex set `s` a.e., then `μ[f | m]` lies in `s` a.e. +* `ConvexOn.map_condExp_le_univ`: in a Banach space `E` with a sigma finite measure `μ`, if + `φ : E → ℝ` is a convex lower-semicontinuous function, then for any `f : α → E` such that `f` and + `φ ∘ f` are integrable, we have `φ (𝔼[f | m]) ≤ 𝔼[φ ∘ f | m]` a.e. + +-/ + +public section + +open MeasureTheory Function Set Filter + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [CompleteSpace E] + {α : Type*} {f : α → E} {φ : E → ℝ} {m mα : MeasurableSpace α} {μ : Measure α} {s : Set E} + +/-- If `f` lies in a closed convex set `s` a.e., then `μ[f | m]` lies in `s` a.e. -/ +lemma Convex.condExp_mem [IsFiniteMeasure μ] [HereditarilyLindelofSpace E] (hm : m ≤ mα) + (hf_int : Integrable f μ) (hs : IsClosed s) (hc : Convex ℝ s) (hf : ∀ᵐ a ∂μ, f a ∈ s) : + ∀ᵐ a ∂μ, μ[f | m] a ∈ s := by + obtain ⟨L, c, hLc⟩ := RCLike.iInter_countable_halfSpaces_eq (𝕜 := ℝ) hc hs + simp_all only [← hLc, RCLike.re_to_real, mem_iInter, ae_all_iff] + intro n + have h1 := ContinuousLinearMap.comp_condExp_comm (m := m) hf_int (L n) + have h2 := condExp_mono (m := m) ((L n).integrable_comp hf_int) (integrable_const (c n)) (hf n) + filter_upwards [h1, h2] with a ha hb + simp_all only [condExp_const, comp_apply] + exact hb + +/-- Conditional Jensen's inequality for hereditarily Lindelof Spaces. -/ +private lemma ConvexOn.map_condExp_le_of_hereditarilyLindelofSpace [IsFiniteMeasure μ] + [HereditarilyLindelofSpace E] (hm : m ≤ mα) (hφ_cvx : ConvexOn ℝ s φ) + (hφ_cont : LowerSemicontinuousOn φ s) (hf : ∀ᵐ a ∂μ, f a ∈ s) (hs : IsClosed s) + (hf_int : Integrable f μ) (hφ_int : Integrable (φ ∘ f) μ) : + ∀ᵐ a ∂μ, φ (μ[f | m] a) ≤ μ[φ ∘ f | m] a := by + obtain ⟨L, c, hLc1, hLc2⟩ := hφ_cvx.real_sSup_of_nat_affine_eq hs hφ_cont + have hp := ae_all_iff.2 fun i => (L i).comp_condExp_add_const_comm hm hf_int (c i) + have hw : ∀ᵐ a ∂μ, ∀ i : ℕ, μ[(L i) ∘ f + const α (c i) | m] a ≤ μ[φ ∘ f | m] a := by + refine ae_all_iff.2 fun i => condExp_mono ?_ hφ_int ?_ + · exact ((L i).integrable_comp hf_int).add (integrable_const (c i)) + · filter_upwards [hf] with a ha using hLc1 i ⟨f a, ha⟩ + filter_upwards [hp, hw, hφ_cvx.1.condExp_mem hm hf_int hs hf] with a hp hw hq + rw [show φ (μ[f | m] a) = s.restrict φ ⟨μ[f | m] a, hq⟩ by simp, ← hLc2] + simpa [iSup_congr hp] using ciSup_le hw + +set_option backward.isDefEq.respectTransparency false +/-- Conditional Jensen's inequality for finite measures. -/ +private theorem ConvexOn.map_condExp_le_of_isFiniteMeasure [IsFiniteMeasure μ] (hm : m ≤ mα) + (hφ_cvx : ConvexOn ℝ s φ) (hφ_cont : LowerSemicontinuousOn φ s) (hf : ∀ᵐ a ∂μ, f a ∈ s) + (hs : IsClosed s) (hf_int : Integrable f μ) (hφ_int : Integrable (φ ∘ f) μ) : + φ ∘ μ[f | m] ≤ᵐ[μ] μ[φ ∘ f | m] := by + borelize E + obtain ⟨t, ht, htt⟩ := hf_int.aestronglyMeasurable.isSeparable_ae_range + let Y := (Submodule.span ℝ t).topologicalClosure + have : CompleteSpace Y := (Submodule.isClosed_topologicalClosure _).completeSpace_coe + have : SecondCountableTopology Y := ht.span.closure.secondCountableTopology + let φY := φ ∘ Y.subtypeL + classical + let fY : α → Y := fun a => if h : f a ∈ Y then ⟨f a, h⟩ else 0 + let fX : α → E := Y.subtypeL ∘ fY + have lem0 : ∀ᵐ a ∂μ, f a ∈ Y := by + filter_upwards [htt] with a ha using + (Submodule.closure_subset_topologicalClosure_span t) (subset_closure ha) + have lem1 : f =ᵐ[μ] fX := by + filter_upwards [lem0] with a ha + simp_all [fX, fY] + have hfY_int : Integrable fY μ := by + refine (hf_int.congr lem1).mono ?_ (by simp [fX]) + obtain ⟨g, hg1, hg2, hg3⟩ := hf_int.1.exists_stronglyMeasurable_range_subset + ((Submodule.isClosed_topologicalClosure _).measurableSet) Nonempty.of_subtype lem0 + refine ⟨codRestrict g Y hg2, (hg1.measurable.codRestrict hg2).stronglyMeasurable, ?_⟩ + filter_upwards [hg3] with a ha + have : g a ∈ Y := hg2 a + simp_all [fY, codRestrict] + have lem2 : μ[f | m] =ᵐ[μ] Y.subtypeL ∘ μ[fY | m] := calc + _ =ᵐ[μ] μ[fX | m] := condExp_congr_ae lem1 + _ =ᵐ[μ] _ := (Y.subtypeL.comp_condExp_comm hfY_int).symm + have lem3 : φ ∘ f =ᵐ[μ] φY ∘ fY := by filter_upwards [lem1] with a ha; simp [φY, ha, fX] + calc + φ ∘ μ[f | m] + =ᵐ[μ] φY ∘ μ[fY | m] := by filter_upwards [lem2] with a ha; simp [φY, ha] + _ ≤ᵐ[μ] μ[φY ∘ fY | m] := by + refine (hφ_cvx.comp_linearMap Y.subtype).map_condExp_le_of_hereditarilyLindelofSpace + (s := Y.subtypeL ⁻¹' s) hm ?_ ?_ ?_ hfY_int (Integrable.congr hφ_int lem3) + · exact hφ_cont.comp (by fun_prop) fun x => by grind + · filter_upwards [lem0, hf] with a ha hb + simp_all [fY] + · exact hs.preimage Y.subtypeL.continuous + _ =ᵐ[μ] μ[φ ∘ f | m] := condExp_congr_ae lem3.symm + +/-- **Conditional Jensen's inequality**: in a Banach space `E` with a measure `μ` that is σ-finite +on a sub-σ-algebra `m`, if `φ : E → ℝ` is convex and lower-semicontinuous on a closed set `s`, then +for any `f : α → E` such that `f` and `φ ∘ f` are integrable, and `f` lies in `s` a.e., we have +`φ (𝔼[f | m]) ≤ᵐ[μ] 𝔼[φ ∘ f | m]`. -/ +theorem ConvexOn.map_condExp_le (hm : m ≤ mα) [SigmaFinite (μ.trim hm)] + (hφ_cvx : ConvexOn ℝ s φ) (hφ_cont : LowerSemicontinuousOn φ s) (hf : ∀ᵐ a ∂μ, f a ∈ s) + (hs : IsClosed s) (hf_int : Integrable f μ) (hφ_int : Integrable (φ ∘ f) μ) : + φ ∘ μ[f | m] ≤ᵐ[μ] μ[φ ∘ f | m] := by + refine (isCountablySpanning_spanningSets (μ.trim hm)).null_of_forall_restrict_null + (fun t ⟨n, hn⟩ => ?_) fun t ⟨n, hn⟩ => hn ▸ ?_ + · exact hn ▸ hm _ (measurableSet_spanningSets (μ.trim hm) n) + have h1 := condExp_restrict_ae_eq_restrict hm (measurableSet_spanningSets (μ.trim hm) n) hf_int + have h2 := condExp_restrict_ae_eq_restrict hm (measurableSet_spanningSets (μ.trim hm) n) hφ_int + have : IsFiniteMeasure (μ.restrict (spanningSets (μ.trim hm) n)) := isFiniteMeasure_restrict.2 + ((le_trim hm).trans_lt (measure_spanningSets_lt_top (μ.trim hm) n)).ne + have h3 := hφ_cvx.map_condExp_le_of_isFiniteMeasure (μ := μ.restrict (spanningSets (μ.trim hm) n)) + hm hφ_cont (ae_restrict_of_ae hf) hs hf_int.restrict hφ_int.restrict + filter_upwards [h1, h2, h3] with a ha hb hc + simpa [← ha, ← hb] + +theorem ConcaveOn.condExp_map_le (hm : m ≤ mα) [SigmaFinite (μ.trim hm)] + (hφ_cvx : ConcaveOn ℝ s φ) (hφ_cont : UpperSemicontinuousOn φ s) (hf : ∀ᵐ a ∂μ, f a ∈ s) + (hs : IsClosed s) (hf_int : Integrable f μ) (hφ_int : Integrable (φ ∘ f) μ) : + μ[φ ∘ f | m] ≤ᵐ[μ] φ ∘ μ[f | m] := by + filter_upwards [hφ_cvx.neg.map_condExp_le hm hφ_cont.neg hf hs hf_int hφ_int.neg, + condExp_neg (φ ∘ f) m] with a h ha + simp_all [Pi.neg_comp] + +/-- **Conditional Jensen's inequality**: in a Banach space `E` with a measure `μ` that is σ-finite +on a sub-σ-algebra `m`, if `φ : E → ℝ` is convex and lower-semicontinuous, then for any `f : α → E` +such that `f` and `φ ∘ f` are integrable, we have `φ (𝔼[f | m]) ≤ᵐ[μ] 𝔼[φ ∘ f | m]`. -/ +theorem ConvexOn.map_condExp_le_univ (hm : m ≤ mα) [SigmaFinite (μ.trim hm)] + (hφ_cvx : ConvexOn ℝ univ φ) (hφ_cont : LowerSemicontinuous φ) + (hf_int : Integrable f μ) (hφ_int : Integrable (φ ∘ f) μ) : + φ ∘ μ[f | m] ≤ᵐ[μ] μ[φ ∘ f | m] := + ConvexOn.map_condExp_le hm hφ_cvx (lowerSemicontinuousOn_univ_iff.2 hφ_cont) (by simp) + isClosed_univ hf_int hφ_int + +theorem ConcaveOn.condExp_map_le_univ (hm : m ≤ mα) [SigmaFinite (μ.trim hm)] + (hφ_cvx : ConcaveOn ℝ univ φ) (hφ_cont : UpperSemicontinuous φ) + (hf_int : Integrable f μ) (hφ_int : Integrable (φ ∘ f) μ) : + μ[φ ∘ f | m] ≤ᵐ[μ] φ ∘ μ[f | m] := by + filter_upwards [hφ_cvx.neg.map_condExp_le_univ hm hφ_cont.neg hf_int hφ_int.neg, + condExp_neg (φ ∘ f) m] with a h ha + simp_all [Pi.neg_comp] + +/-- In a Banach space `E` with a measure `μ`, then for any `μ`-a.e. strongly measurable function +`f : α → E`, we have `‖𝔼[f | m])‖ ≤ᵐ[μ] 𝔼[‖f‖ | m]`. -/ +theorem AEStronglyMeasurable.norm_condExp_le (hf : AEStronglyMeasurable f μ) : + (‖μ[f | m] ·‖) ≤ᵐ[μ] μ[(‖f ·‖) | m] := by + by_cases! hm : ¬ m ≤ mα + · simp_all [condExp_of_not_le hm]; aesop + by_cases! hμm : ¬ SigmaFinite (μ.trim hm) + · simp [condExp_of_not_sigmaFinite hm hμm]; aesop + by_cases! hf_int : ¬ Integrable f μ + · have : ¬ Integrable (‖f ·‖) μ := by simpa [integrable_norm_iff hf] + simp [condExp_of_not_integrable hf_int, condExp_of_not_integrable this] + aesop + exact convexOn_univ_norm.map_condExp_le_univ hm continuous_norm.lowerSemicontinuous hf_int + hf_int.norm + +/-- **Conditional Jensen's inequality**: in a finite dimensional Banach space `E` with a measure +`μ` that is σ-finite on a sub-σ-algebra `m`, if `φ : E → ℝ` is convex, then for any `f : α → E` such +that `f` and `φ ∘ f` are integrable, we have `φ (𝔼[f | m]) ≤ᵐ[μ] 𝔼[φ ∘ f | m]`. -/ +theorem ConvexOn.map_condExp_le_of_finiteDimensional [FiniteDimensional ℝ E] (hm : m ≤ mα) + [SigmaFinite (μ.trim hm)] (hφ_cvx : ConvexOn ℝ univ φ) (hf_int : Integrable f μ) + (hφ_int : Integrable (φ ∘ f) μ) : + φ ∘ μ[f | m] ≤ᵐ[μ] μ[φ ∘ f | m] := + hφ_cvx.map_condExp_le_univ hm + (continuousOn_univ.1 (hφ_cvx.continuousOn isOpen_univ)).lowerSemicontinuous hf_int hφ_int + +theorem ConcaveOn.condExp_map_le_of_finiteDimensional [FiniteDimensional ℝ E] (hm : m ≤ mα) + [SigmaFinite (μ.trim hm)] (hφ_cvx : ConcaveOn ℝ univ φ) (hf_int : Integrable f μ) + (hφ_int : Integrable (φ ∘ f) μ) : + μ[φ ∘ f | m] ≤ᵐ[μ] φ ∘ μ[f | m] := by + filter_upwards [hφ_cvx.neg.map_condExp_le_of_finiteDimensional hm hf_int hφ_int.neg, + condExp_neg (φ ∘ f) m] with a h ha + simp_all [Pi.neg_comp] diff --git a/Mathlib/MeasureTheory/Function/FactorsThrough.lean b/Mathlib/MeasureTheory/Function/FactorsThrough.lean index cd93204c7e3245..ac036aed412880 100644 --- a/Mathlib/MeasureTheory/Function/FactorsThrough.lean +++ b/Mathlib/MeasureTheory/Function/FactorsThrough.lean @@ -69,7 +69,7 @@ theorem StronglyMeasurable.exists_eq_measurable_comp [Nonempty Z] [TopologicalSp exact ⟨t.piecewise h₁ h₂, mh₁.piecewise ht mh₂, by rw [piecewise_comp]⟩ | @lim g i hg hi h₁ h₂ => choose h mh hh using h₁ - refine ⟨fun y ↦ _root_.limUnder atTop (h · y), StronglyMeasurable.limUnder mh, ?_⟩ + refine ⟨fun y ↦ limUnder atTop (h · y), StronglyMeasurable.limUnder mh, ?_⟩ ext x rw [Function.comp_apply, Tendsto.limUnder_eq] simp_all diff --git a/Mathlib/MeasureTheory/Function/LpSpace/Basic.lean b/Mathlib/MeasureTheory/Function/LpSpace/Basic.lean index 7021522d7a80b5..1682125667c70e 100644 --- a/Mathlib/MeasureTheory/Function/LpSpace/Basic.lean +++ b/Mathlib/MeasureTheory/Function/LpSpace/Basic.lean @@ -570,6 +570,39 @@ theorem isometry_compMeasurePreserving [Fact (1 ≤ p)] (hf : MeasurePreserving theorem toLp_compMeasurePreserving {g : β → E} (hg : MemLp g p μb) (hf : MeasurePreserving f μ μb) : compMeasurePreserving f hf (hg.toLp g) = (hg.comp_measurePreserving hf).toLp _ := rfl +@[simp] +theorem compMeasurePreserving_id : + compMeasurePreserving (E := E) (p := p) id (.id μb) = AddMonoidHom.id _ := by + ext + simp + +theorem compMeasurePreserving_id_apply (g : Lp E p μb) : + compMeasurePreserving id (MeasurePreserving.id μb) g = g := by simp + +theorem compMeasurePreserving_comp {γ : Type*} {mγ : MeasurableSpace γ} {μc : Measure γ} + {f : β → γ} (hf : MeasurePreserving f μb μc) {f' : α → β} (hf' : MeasurePreserving f' μ μb) : + compMeasurePreserving (E := E) (p := p) (f ∘ f') (hf.comp hf') = + (compMeasurePreserving f' hf').comp (compMeasurePreserving f hf) := by + ext g + simp [AEEqFun.compMeasurePreserving_comp _ hf hf'] + +theorem compMeasurePreserving_comp_apply {γ : Type*} {mγ : MeasurableSpace γ} {μc : Measure γ} + (g : Lp E p μc) {f : β → γ} (hf : MeasurePreserving f μb μc) {f' : α → β} + (hf' : MeasurePreserving f' μ μb) : + (compMeasurePreserving (f ∘ f') (hf.comp hf')) g = + (compMeasurePreserving f' hf') ((compMeasurePreserving f hf) g) := by + simp [compMeasurePreserving_comp hf hf'] + +theorem compMeasurePreserving_iterate {f : α → α} (hf : MeasurePreserving f μ μ) (n : ℕ) : + (compMeasurePreserving (E := E) (p := p) f hf)^[n] = + compMeasurePreserving f^[n] (MeasurePreserving.iterate hf n) := by + funext + induction n with + | zero => simp + | succ n h => + nth_rewrite 1 [add_comm n 1] + simp [Function.iterate_add, h, compMeasurePreserving_comp (hf.iterate n) hf] + variable (𝕜 : Type*) [NormedRing 𝕜] [Module 𝕜 E] [IsBoundedSMul 𝕜 E] /-- `MeasureTheory.Lp.compMeasurePreserving` as a linear map. -/ diff --git a/Mathlib/MeasureTheory/Integral/Bochner/Set.lean b/Mathlib/MeasureTheory/Integral/Bochner/Set.lean index f943dd8505c383..aeb4b46d4d6fe1 100644 --- a/Mathlib/MeasureTheory/Integral/Bochner/Set.lean +++ b/Mathlib/MeasureTheory/Integral/Bochner/Set.lean @@ -144,6 +144,10 @@ theorem setIntegral_empty : ∫ x in ∅, f x ∂μ = 0 := by theorem setIntegral_univ : ∫ x in univ, f x ∂μ = ∫ x, f x ∂μ := by rw [Measure.restrict_univ] +lemma integral_eq_setIntegral (hs : ∀ᵐ x ∂μ, x ∈ s) (f : X → E) : + ∫ x, f x ∂μ = ∫ x in s, f x ∂μ := by + rw [← setIntegral_univ, ← setIntegral_congr_set]; rwa [ae_eq_univ] + theorem integral_add_compl₀ (hs : NullMeasurableSet s μ) (hfi : Integrable f μ) : ∫ x in s, f x ∂μ + ∫ x in sᶜ, f x ∂μ = ∫ x, f x ∂μ := by have := setIntegral_union₀ disjoint_compl_right.aedisjoint @@ -693,6 +697,9 @@ theorem integral_Ioc_eq_integral_Ioo : ∫ t in Ioc x y, f t ∂μ = ∫ t in Io theorem integral_Ico_eq_integral_Ioo : ∫ t in Ico x y, f t ∂μ = ∫ t in Ioo x y, f t ∂μ := integral_Ico_eq_integral_Ioo' <| measure_singleton x +theorem integral_Ico_eq_integral_Ioc : ∫ t in Ico x y, f t ∂μ = ∫ t in Ioc x y, f t ∂μ := by + rw [integral_Ico_eq_integral_Ioo, integral_Ioc_eq_integral_Ioo] + theorem integral_Icc_eq_integral_Ioo : ∫ t in Icc x y, f t ∂μ = ∫ t in Ioo x y, f t ∂μ := by rw [integral_Icc_eq_integral_Ico, integral_Ico_eq_integral_Ioo] diff --git a/Mathlib/MeasureTheory/Integral/DominatedConvergence.lean b/Mathlib/MeasureTheory/Integral/DominatedConvergence.lean index 7530413f38f51d..3aeb4ace15863c 100644 --- a/Mathlib/MeasureTheory/Integral/DominatedConvergence.lean +++ b/Mathlib/MeasureTheory/Integral/DominatedConvergence.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2019 Zhouhang Zhou. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Zhouhang Zhou, Yury Kudryashov, Patrick Massot +Authors: Zhouhang Zhou, Yury Kudryashov, Patrick Massot, Louis (Yiyang) Liu -/ module @@ -472,8 +472,7 @@ theorem continuousOn_primitive (h_int : IntegrableOn f (Icc a b) μ) : rw [continuousOn_congr this] intro x₀ _ refine continuousWithinAt_primitive (measure_singleton x₀) ?_ - simp only [intervalIntegrable_iff_integrableOn_Ioc_of_le, max_eq_right, h, - min_self] + simp only [intervalIntegrable_iff_integrableOn_Ioc_of_le, max_eq_right, h, min_self] exact h_int.mono Ioc_subset_Icc_self le_rfl · rw [Icc_eq_empty h] exact continuousOn_empty _ @@ -637,4 +636,96 @@ end ContinuousPrimitive end intervalIntegral +namespace MeasureTheory + +namespace IntegrableOn + +open intervalIntegral + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] {μ : Measure ℝ} {f : ℝ → E} + +theorem continuousWithinAt_Ici_primitive_Ioi {a₀ : ℝ} (hf : IntegrableOn f (Ioi a₀) μ) : + ContinuousWithinAt (fun b ↦ ∫ x in Ioi b, f x ∂μ) (Ici a₀) a₀ := by + simp_rw [← integral_indicator measurableSet_Ioi] + apply tendsto_integral_filter_of_dominated_convergence ((Ioi a₀).indicator (norm ∘ f)) + · filter_upwards [self_mem_nhdsWithin] with a ha + rw [aestronglyMeasurable_indicator_iff measurableSet_Ioi] + exact (hf.mono_set (Ioi_subset_Ioi ha)).aestronglyMeasurable + · filter_upwards [self_mem_nhdsWithin] with a ha + refine ae_of_all _ fun x ↦ ?_ + rw [norm_indicator_eq_indicator_norm] + apply indicator_le_indicator_of_subset (Ioi_subset_Ioi (by grind)) (fun a ↦ norm_nonneg (f a)) + · simpa [integrable_indicator_iff measurableSet_Ioi] using hf.norm + · refine ae_of_all _ fun x ↦ ?_ + simp only [indicator_apply, mem_Ioi] + by_cases hx : a₀ < x <;> apply tendsto_const_nhds.congr' + · filter_upwards [mem_nhdsWithin_of_mem_nhds (Iio_mem_nhds hx)] with a ha using by grind + · filter_upwards [self_mem_nhdsWithin] with a ha using by grind + +theorem continuousOn_Ici_primitive_Ioi [NoAtoms μ] {a₀ : ℝ} (hf : IntegrableOn f (Ioi a₀) μ) : + ContinuousOn (fun b ↦ ∫ x in Ioi b, f x ∂μ) (Ici a₀) := by + intro a (ha : a₀ ≤ a) + rw [continuousWithinAt_iff_continuous_left_right] + constructor + · rw [Ici_inter_Iic] + have h_int : IntervalIntegrable f μ a₀ a := + (intervalIntegrable_iff_integrableOn_Ioc_of_le ha).2 <| hf.mono_set Ioc_subset_Ioi_self + have h_split : ∀ b ∈ Icc a₀ a, ∫ x in Ioi b, f x ∂μ = + (∫ x in Ioi a₀, f x ∂μ) - ∫ x in a₀..b, f x ∂μ := by + intro b hb + simp [← integral_Ioi_sub_Ioi hf hb.1] + have h_cwa : ContinuousWithinAt (fun b ↦ ∫ x in a₀..b, f x ∂μ) (Icc a₀ a) a := + continuousWithinAt_primitive (measure_singleton a) (by simpa [ha]) + exact (continuousWithinAt_const.sub h_cwa).congr h_split (h_split a (right_mem_Icc.2 ha)) + · simpa [ha] using (hf.mono_set (Ioi_subset_Ioi ha)).continuousWithinAt_Ici_primitive_Ioi + +theorem continuousWithinAt_Iic_primitive_Iio {a₀ : ℝ} (hf : IntegrableOn f (Iio a₀) μ) : + ContinuousWithinAt (fun b ↦ ∫ x in Iio b, f x ∂μ) (Iic a₀) a₀ := by + simp_rw [← integral_indicator measurableSet_Iio] + apply tendsto_integral_filter_of_dominated_convergence ((Iio a₀).indicator (norm ∘ f)) + · filter_upwards [self_mem_nhdsWithin] with a ha + rw [aestronglyMeasurable_indicator_iff measurableSet_Iio] + exact (hf.mono_set (Iio_subset_Iio ha)).aestronglyMeasurable + · filter_upwards [self_mem_nhdsWithin] with a ha + refine ae_of_all _ fun x ↦ ?_ + rw [norm_indicator_eq_indicator_norm] + apply indicator_le_indicator_of_subset (Iio_subset_Iio (by grind)) (fun a ↦ norm_nonneg (f a)) + · simpa [integrable_indicator_iff measurableSet_Iio] using hf.norm + · refine ae_of_all _ fun x ↦ ?_ + simp only [indicator_apply, mem_Iio] + by_cases hx : x < a₀ <;> apply tendsto_const_nhds.congr' + · filter_upwards [mem_nhdsWithin_of_mem_nhds (Ioi_mem_nhds hx)] with a ha using by grind + · filter_upwards [self_mem_nhdsWithin] with a ha using by grind + +theorem continuousOn_Iic_primitive_Iio [NoAtoms μ] {a₀ : ℝ} (hf : IntegrableOn f (Iio a₀) μ) : + ContinuousOn (fun b ↦ ∫ x in Iio b, f x ∂μ) (Iic a₀) := by + intro a (ha : a ≤ a₀) + rw [continuousWithinAt_iff_continuous_left_right] + constructor + · simpa [ha] using (hf.mono_set (Iio_subset_Iio ha)).continuousWithinAt_Iic_primitive_Iio + · rw [Iic_inter_Ici] + have h_int : IntervalIntegrable f μ a a₀ := + (intervalIntegrable_iff_integrableOn_Ico_of_le ha).2 <| hf.mono_set Ico_subset_Iio_self + have h_split : ∀ b ∈ Icc a a₀, ∫ x in Iio b, f x ∂μ = + (∫ x in Iio a₀, f x ∂μ) + ∫ x in a₀..b, f x ∂μ := by + intro b hb + simp [integral_symm b a₀, ← integral_Iio_sub_Iio' hf (hf.mono_set (Iio_subset_Iio hb.2))] + have h_cwa : ContinuousWithinAt (fun b ↦ ∫ x in a₀..b, f x ∂μ) (Icc a a₀) a := + continuousWithinAt_primitive (measure_singleton a) (by simpa [ha]) + exact (continuousWithinAt_const.add h_cwa).congr h_split (h_split a (left_mem_Icc.2 ha)) + +theorem continuousOn_Ici_primitive_Ici [NoAtoms μ] {a₀ : ℝ} (hf : IntegrableOn f (Ici a₀) μ) : + ContinuousOn (fun b ↦ ∫ x in Ici b, f x ∂μ) (Ici a₀) := by + simp_rw [integral_Ici_eq_integral_Ioi] + exact (hf.mono_set Ioi_subset_Ici_self).continuousOn_Ici_primitive_Ioi + +theorem continuousOn_Iic_primitive_Iic [NoAtoms μ] {a₀ : ℝ} (hf : IntegrableOn f (Iic a₀) μ) : + ContinuousOn (fun b ↦ ∫ x in Iic b, f x ∂μ) (Iic a₀) := by + simp_rw [integral_Iic_eq_integral_Iio] + exact (hf.mono_set Iio_subset_Iic_self).continuousOn_Iic_primitive_Iio + +end IntegrableOn + +end MeasureTheory + end DominatedConvergenceTheorem diff --git a/Mathlib/MeasureTheory/Integral/IntervalIntegral/Basic.lean b/Mathlib/MeasureTheory/Integral/IntervalIntegral/Basic.lean index 6e2461079cbd7c..27d17ca7e66c3d 100644 --- a/Mathlib/MeasureTheory/Integral/IntervalIntegral/Basic.lean +++ b/Mathlib/MeasureTheory/Integral/IntervalIntegral/Basic.lean @@ -1128,6 +1128,30 @@ theorem integral_interval_add_Ioi' (ha : IntervalIntegrable f μ a b) ((intervalIntegrable_iff_integrableOn_Ioc_of_le h).1 ha) hb · exact hb.mono_set <| Ioi_subset_Ioi h.le +theorem integral_Ioi_sub_Ioi (hf : IntegrableOn f (Ioi a) μ) (hab : a ≤ b) : + ∫ x in Ioi a, f x ∂μ - ∫ x in Ioi b, f x ∂μ = ∫ x in a..b, f x ∂μ := + sub_eq_of_eq_add (integral_interval_add_Ioi hf (hf.mono_set (Ioi_subset_Ioi hab))).symm + +theorem integral_Ioi_sub_Ioi' (hf : IntegrableOn f (Ioi a) μ) (hg : IntegrableOn f (Ioi b) μ) : + ∫ x in Ioi a, f x ∂μ - ∫ x in Ioi b, f x ∂μ = ∫ x in a..b, f x ∂μ := by + wlog! hab : a ≤ b generalizing a b + · rw [integral_symm, ← this hg hf hab.le, neg_sub] + exact integral_Ioi_sub_Ioi hf hab + +theorem integral_Iio_sub_Iio (hf : IntegrableOn f (Iio b) μ) (hab : a ≤ b) : + ∫ x in Iio b, f x ∂μ - ∫ x in Iio a, f x ∂μ = ∫ x in Ico a b, f x ∂μ := by + have ha : IntegrableOn f (Iio a) μ := hf.mono_set (Iio_subset_Iio hab) + have h : IntegrableOn f (Ico a b) μ := hf.mono_set Ico_subset_Iio_self + rw [sub_eq_iff_eq_add', ← setIntegral_union (by grind) measurableSet_Ico ha h, + Iio_union_Ico_eq_Iio hab] + +theorem integral_Iio_sub_Iio' [NoAtoms μ] (hf : IntegrableOn f (Iio b) μ) + (hg : IntegrableOn f (Iio a) μ) : + ∫ x in Iio b, f x ∂μ - ∫ x in Iio a, f x ∂μ = ∫ x in a..b, f x ∂μ := by + wlog! hab : a ≤ b generalizing a b + · rw [integral_symm, ← this hg hf hab.le, neg_sub] + rw [integral_Iio_sub_Iio hf hab, integral_of_le hab, integral_Ico_eq_integral_Ioc] + theorem integral_Iic_add_Ioi (h_left : IntegrableOn f (Iic b) μ) (h_right : IntegrableOn f (Ioi b) μ) : (∫ x in Iic b, f x ∂μ) + (∫ x in Ioi b, f x ∂μ) = ∫ (x : ℝ), f x ∂μ := by diff --git a/Mathlib/MeasureTheory/Integral/SetToL1.lean b/Mathlib/MeasureTheory/Integral/SetToL1.lean index ef8ae1564503c0..a7948537dbdf45 100644 --- a/Mathlib/MeasureTheory/Integral/SetToL1.lean +++ b/Mathlib/MeasureTheory/Integral/SetToL1.lean @@ -819,13 +819,7 @@ theorem setToFun_nonneg [ClosedIciTopology G''] {T : Set α → G' →L[ℝ] G'' (hf : 0 ≤ᵐ[μ] f) : 0 ≤ setToFun μ T hT f := by by_cases hfi : Integrable f μ · simp_rw [setToFun_eq _ hfi] - refine L1.setToL1_nonneg hT hT_nonneg ?_ - rw [← Lp.coeFn_le] - have h0 := Lp.coeFn_zero G' 1 μ - have h := Integrable.coeFn_toL1 hfi - filter_upwards [h0, h, hf] with _ h0a ha hfa - rw [h0a, ha] - exact hfa + exact L1.setToL1_nonneg hT hT_nonneg hf · simp_rw [setToFun_undef _ hfi, le_rfl] theorem setToFun_mono [ClosedIciTopology G''] [IsOrderedAddMonoid G'] diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Constructions.lean b/Mathlib/MeasureTheory/MeasurableSpace/Constructions.lean index 3ca75e7ad4e5c6..33a903217f7176 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/Constructions.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/Constructions.lean @@ -227,6 +227,10 @@ theorem Measurable.subtype_mk {p : β → Prop} {f : α → β} (hf : Measurable Measurable fun x => (⟨f x, h x⟩ : Subtype p) := fun t ⟨s, hs⟩ => hs.2 ▸ by simp only [← preimage_comp, Function.comp_def, hf hs.1] +@[fun_prop] +theorem Measurable.codRestrict {s : Set β} {f : α → β} (hf : Measurable f) + (h : ∀ y, f y ∈ s) : Measurable (codRestrict f s h) := hf.subtype_mk + @[fun_prop] protected theorem Measurable.rangeFactorization {f : α → β} (hf : Measurable f) : Measurable (rangeFactorization f) := diff --git a/Mathlib/MeasureTheory/Measure/QuasiMeasurePreserving.lean b/Mathlib/MeasureTheory/Measure/QuasiMeasurePreserving.lean index c1450f855785e3..2d3c0542802430 100644 --- a/Mathlib/MeasureTheory/Measure/QuasiMeasurePreserving.lean +++ b/Mathlib/MeasureTheory/Measure/QuasiMeasurePreserving.lean @@ -89,6 +89,12 @@ protected theorem iterate {f : α → α} (hf : QuasiMeasurePreserving f μa μa protected theorem aemeasurable (hf : QuasiMeasurePreserving f μa μb) : AEMeasurable f μa := hf.1.aemeasurable +protected theorem congr (hf : QuasiMeasurePreserving f μa μb) {f' : α → β} (hf' : Measurable f') + (h : f =ᵐ[μa] f') : QuasiMeasurePreserving f' μa μb := by + refine ⟨hf', ?_⟩ + rw [Measure.map_congr h.symm] + exact hf.absolutelyContinuous + theorem smul_measure {R : Type*} [SMul R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ ℝ≥0∞] (hf : QuasiMeasurePreserving f μa μb) (c : R) : QuasiMeasurePreserving f (c • μa) (c • μb) := ⟨hf.1, by rw [Measure.map_smul]; exact hf.2.smul c⟩ @@ -103,6 +109,7 @@ theorem ae (h : QuasiMeasurePreserving f μa μb) {p : β → Prop} (hg : ∀ᵐ ∀ᵐ x ∂μa, p (f x) := h.tendsto_ae hg +@[gcongr] theorem ae_eq (h : QuasiMeasurePreserving f μa μb) {g₁ g₂ : β → δ} (hg : g₁ =ᵐ[μb] g₂) : g₁ ∘ f =ᵐ[μa] g₂ ∘ f := h.ae hg diff --git a/Mathlib/MeasureTheory/Measure/Restrict.lean b/Mathlib/MeasureTheory/Measure/Restrict.lean index f485a7eefe4835..bd1f9c58e66c4a 100644 --- a/Mathlib/MeasureTheory/Measure/Restrict.lean +++ b/Mathlib/MeasureTheory/Measure/Restrict.lean @@ -112,6 +112,25 @@ theorem restrict_apply' (hs : MeasurableSet s) : μ.restrict s t = μ (t ∩ s) Measure.restrict_toOuterMeasure_eq_toOuterMeasure_restrict hs, OuterMeasure.restrict_apply s t _, toOuterMeasure_apply] +theorem _root_.IsCountablySpanning.null_of_forall_inter_null {C : Set (Set α)} + (hC : IsCountablySpanning C) (ht : ∀ t ∈ C, μ (s ∩ t) = 0) : + μ s = 0 := by + obtain ⟨t, ht1, ht2⟩ := hC + rw [show s = ⋃ n, s ∩ t n by rw [← inter_iUnion, ht2, inter_univ], measure_iUnion_null_iff] + exact fun i => ht (t i) (ht1 i) + +theorem forall_measure_inter_isCountablySpanning_eq_zero {C : Set (Set α)} + (hC : IsCountablySpanning C) : (∀ t ∈ C, μ (s ∩ t) = 0) ↔ μ s = 0 where + mp := hC.null_of_forall_inter_null + mpr h t _ := measure_inter_null_of_null_left t h + +theorem _root_.IsCountablySpanning.null_of_forall_restrict_null {C : Set (Set α)} + (hC : IsCountablySpanning C) (hm : C ⊆ MeasurableSet) (ht : ∀ t ∈ C, μ.restrict t s = 0) : + μ s = 0 := by + rw [← forall_measure_inter_isCountablySpanning_eq_zero hC] + refine fun t htc => ?_ + simpa [← μ.restrict_apply' (hm htc)] using ht t htc + theorem restrict_apply₀' (hs : NullMeasurableSet s μ) : μ.restrict s t = μ (t ∩ s) := by rw [← restrict_congr_set hs.toMeasurable_ae_eq, restrict_apply' (measurableSet_toMeasurable _ _), diff --git a/Mathlib/MeasureTheory/Measure/Typeclasses/SFinite.lean b/Mathlib/MeasureTheory/Measure/Typeclasses/SFinite.lean index 46c98a45981c57..f9b4e767660a5b 100644 --- a/Mathlib/MeasureTheory/Measure/Typeclasses/SFinite.lean +++ b/Mathlib/MeasureTheory/Measure/Typeclasses/SFinite.lean @@ -198,6 +198,7 @@ namespace Measure /-- A set in a σ-finite space has zero measure if and only if its intersection with all members of the countable family of finite measure spanning sets has zero measure. -/ +@[deprecated forall_measure_inter_isCountablySpanning_eq_zero (since := "2026-03-13")] theorem forall_measure_inter_spanningSets_eq_zero [MeasurableSpace α] {μ : Measure α} [SigmaFinite μ] (s : Set α) : (∀ n, μ (s ∩ spanningSets μ n) = 0) ↔ μ s = 0 := by nth_rw 2 [show s = ⋃ n, s ∩ spanningSets μ n by @@ -209,8 +210,9 @@ some member of the countable family of finite measure spanning sets has positive theorem exists_measure_inter_spanningSets_pos [MeasurableSpace α] {μ : Measure α} [SigmaFinite μ] (s : Set α) : (∃ n, 0 < μ (s ∩ spanningSets μ n)) ↔ 0 < μ s := by contrapose! - simp only [nonpos_iff_eq_zero] - exact forall_measure_inter_spanningSets_eq_zero s + rw [nonpos_iff_eq_zero, ← forall_measure_inter_isCountablySpanning_eq_zero + (isCountablySpanning_spanningSets μ)] + simp /-- If the union of a.e.-disjoint null-measurable sets has finite measure, then there are only finitely many members of the union whose measure exceeds any given positive number. -/ diff --git a/Mathlib/NumberTheory/ArithmeticFunction/Carmichael.lean b/Mathlib/NumberTheory/ArithmeticFunction/Carmichael.lean index 6dcbaff5c6ea7c..1dc8cff279511d 100644 --- a/Mathlib/NumberTheory/ArithmeticFunction/Carmichael.lean +++ b/Mathlib/NumberTheory/ArithmeticFunction/Carmichael.lean @@ -115,7 +115,7 @@ theorem carmichael_finset_prod {α : Type*} {s : Finset α} {f : α → ℕ} theorem carmichael_factorization (n : ℕ) [NeZero n] : Carmichael n = n.primeFactors.lcm fun p ↦ Carmichael (p ^ n.factorization p) := by - nth_rw 1 [← n.factorization_prod_pow_eq_self <| NeZero.ne _] + nth_rw 1 [← n.prod_factorization_pow_eq_self <| NeZero.ne _] exact carmichael_finset_prod pairwise_coprime_pow_primeFactors_factorization.set_of_subtype theorem carmichael_two_pow_of_le_two_eq_totient {n : ℕ} (hn : n ≤ 2) : diff --git a/Mathlib/NumberTheory/ClassNumber/FunctionField.lean b/Mathlib/NumberTheory/ClassNumber/FunctionField.lean index a46c016ac015ee..d8bafaf8410b04 100644 --- a/Mathlib/NumberTheory/ClassNumber/FunctionField.lean +++ b/Mathlib/NumberTheory/ClassNumber/FunctionField.lean @@ -37,7 +37,6 @@ namespace RingOfIntegers open FunctionField -set_option backward.isDefEq.respectTransparency false in open scoped Classical in noncomputable instance : Fintype (ClassGroup (ringOfIntegers Fq F)) := ClassGroup.fintypeOfAdmissibleOfFinite (RatFunc Fq) F diff --git a/Mathlib/NumberTheory/Cyclotomic/Basic.lean b/Mathlib/NumberTheory/Cyclotomic/Basic.lean index bbde939525e2d3..1b7ad25d5a59fa 100644 --- a/Mathlib/NumberTheory/Cyclotomic/Basic.lean +++ b/Mathlib/NumberTheory/Cyclotomic/Basic.lean @@ -167,7 +167,6 @@ theorem subsingleton_iff [Subsingleton B] : · have : s = 1 := (subset_pair_iff.mp hS s hs).resolve_left hs' exact ⟨0, this ▸ IsPrimitiveRoot.of_subsingleton 0⟩ -set_option backward.isDefEq.respectTransparency false in /-- If `B` is a cyclotomic extension of `A` given by roots of unity of order in `S ∪ T`, then `B` is a cyclotomic extension of `adjoin A { b : B | ∃ a : ℕ, a ∈ S ∧ a ≠ 0 ∧ b ^ a = 1 }` given by roots of unity of order in `T`. -/ @@ -187,7 +186,6 @@ theorem union_right [h : IsCyclotomicExtension (S ∪ T) A B] : replace h := ((isCyclotomicExtension_iff _ _ _).1 h).2 b rwa [this, adjoin_union_eq_adjoin_adjoin, Subalgebra.mem_restrictScalars] at h -set_option backward.isDefEq.respectTransparency false in /-- If `B` is a cyclotomic extension of `A` given by roots of unity of order in `T` and `S ⊆ T`, then `adjoin A { b : B | ∃ a : ℕ, a ∈ S ∧ a ≠ 0 ∧ b ^ a = 1 }` is a cyclotomic extension of `B` given by roots of unity of order in `S`. -/ @@ -312,7 +310,6 @@ protected theorem neZero' [IsCyclotomicExtension {n} A B] [IsDomain B] : NeZero (n : A) := neZero_of_mem' n {n} A B (mem_singleton n) -set_option backward.isDefEq.respectTransparency false in /-- A cyclotomic extension is integral. -/ theorem integral [IsCyclotomicExtension S A B] : Algebra.IsIntegral A B := by rw [← (Subalgebra.equivOfEq _ _ ((IsCyclotomicExtension.iff_adjoin_eq_top S A B).1 ‹_›).2 @@ -320,7 +317,6 @@ theorem integral [IsCyclotomicExtension S A B] : Algebra.IsIntegral A B := by exact Algebra.IsIntegral.adjoin fun x ⟨n, hn, h1, h2⟩ ↦ ⟨X ^ n - 1, monic_X_pow_sub_C 1 h1, by simp [h2]⟩ -set_option backward.isDefEq.respectTransparency false in theorem _root_.Algebra.isCyclotomicExtension_adjoin_of_exists_isPrimitiveRoot (h : ∀ n ∈ S, n ≠ 0 → ∃ r : B, IsPrimitiveRoot r n) : IsCyclotomicExtension S A (adjoin A {b : B | ∃ n ∈ S, n ≠ 0 ∧ b ^ n = 1}) where @@ -386,7 +382,6 @@ theorem finite_of_singleton [IsDomain B] [h : IsCyclotomicExtension {n} A B] : exact ⟨X ^ n - 1, ⟨monic_X_pow_sub_C _ (hb.1 ▸ NeZero.ne _), by simpa [sub_eq_zero] using hb.2.2⟩⟩ -set_option backward.isDefEq.respectTransparency false in /-- If `S` is finite and `IsCyclotomicExtension S A B`, then `B` is a finite `A`-algebra. -/ protected theorem finite [IsDomain B] [h₁ : Finite S] [h₂ : IsCyclotomicExtension S A B] : Module.Finite A B := by @@ -472,7 +467,6 @@ theorem adjoin_primitive_root_eq_top {n : ℕ} [NeZero n] [IsDomain B] variable (A) -set_option backward.isDefEq.respectTransparency false in theorem _root_.IsPrimitiveRoot.adjoin_isCyclotomicExtension {ζ : B} {n : ℕ} [NeZero n] (h : IsPrimitiveRoot ζ n) : IsCyclotomicExtension {n} A (adjoin A ({ζ} : Set B)) := { exists_isPrimitiveRoot := fun hi hi' => by @@ -493,7 +487,6 @@ theorem _root_.IsPrimitiveRoot.adjoin_isCyclotomicExtension {ζ : B} {n : ℕ} [ · exact Subalgebra.add_mem _ hb₁ hb₂ · exact Subalgebra.mul_mem _ hb₁ hb₂ } -set_option backward.isDefEq.respectTransparency false in variable {L} in theorem _root_.IsPrimitiveRoot.intermediateField_adjoin_isCyclotomicExtension [Algebra.IsIntegral K L] {n : ℕ} [NeZero n] {ζ : L} (hζ : IsPrimitiveRoot ζ n) : @@ -526,7 +519,6 @@ theorem splits_cyclotomic [IsCyclotomicExtension S K L] (hS : n ∈ S) : variable (n S) -set_option backward.isDefEq.respectTransparency false in theorem _root_.IntermediateField.isCyclotomicExtension_adjoin_of_exists_isPrimitiveRoot (h : ∀ n ∈ S, n ≠ 0 → ∃ r : L, IsPrimitiveRoot r n) : IsCyclotomicExtension S K @@ -917,7 +909,6 @@ section Subalgebra variable {A B} [IsDomain B] -set_option backward.isDefEq.respectTransparency false in theorem IsCyclotomicExtension.mem_of_pow_eq_one (C : Subalgebra A B) [h : IsCyclotomicExtension S A C] {m : ℕ} {ζ : B} (h₁ : m ∈ S) (h₂ : m ≠ 0) (hζ : ζ ^ m = 1) : ζ ∈ C := by @@ -928,7 +919,6 @@ theorem IsCyclotomicExtension.mem_of_pow_eq_one (C : Subalgebra A B) rw [← map_pow] exact Subalgebra.pow_mem _ η.prop _ -set_option backward.isDefEq.respectTransparency false in theorem isCyclotomicExtension_iff_eq_adjoin (C : Subalgebra A B) (hS : ∀ n ∈ S, n ≠ 0 → ∃ r : B, IsPrimitiveRoot r n) : IsCyclotomicExtension S A C ↔ C = Algebra.adjoin A {x : B | ∃ n ∈ S, n ≠ 0 ∧ x ^ n = 1} := by @@ -941,7 +931,6 @@ theorem isCyclotomicExtension_iff_eq_adjoin (C : Subalgebra A B) exists_eq_right_right, and_iff_left_iff_imp, forall_exists_index, and_imp] exact fun n hn₁ hn₂ hx ↦ h.mem_of_pow_eq_one S C hn₁ hn₂ hx -set_option backward.isDefEq.respectTransparency false in theorem isCyclotomicExtension_singleton_iff_eq_adjoin (C : Subalgebra A B) {ζ : B} (hζ : IsPrimitiveRoot ζ n) : IsCyclotomicExtension {n} A C ↔ C = adjoin A {ζ} := by rw [isCyclotomicExtension_iff_eq_adjoin] @@ -955,7 +944,6 @@ theorem isCyclotomicExtension_singleton_iff_eq_adjoin (C : Subalgebra A B) {ζ : · simpa only [Set.mem_singleton_iff, ne_eq, forall_eq, NeZero.ne n, not_false_eq_true, forall_const] using ⟨ζ, hζ⟩ -set_option backward.isDefEq.respectTransparency false in theorem IsCyclotomicExtension.eq (C₁ C₂ : Subalgebra A B) [h₁ : IsCyclotomicExtension S A C₁] [h₂ : IsCyclotomicExtension S A C₂] : C₁ = C₂ := by have hC (n) (hn₁ : n ∈ S) (hn₂ : n ≠ 0) : ∃ x : B, IsPrimitiveRoot x n := by diff --git a/Mathlib/NumberTheory/Cyclotomic/Discriminant.lean b/Mathlib/NumberTheory/Cyclotomic/Discriminant.lean index 94d40bdf3fefea..c81e82dd632b24 100644 --- a/Mathlib/NumberTheory/Cyclotomic/Discriminant.lean +++ b/Mathlib/NumberTheory/Cyclotomic/Discriminant.lean @@ -35,7 +35,6 @@ namespace IsPrimitiveRoot variable {n : ℕ} [NeZero n] {K : Type u} [Field K] [CharZero K] {ζ : K} variable [ce : IsCyclotomicExtension {n} ℚ K] -set_option backward.isDefEq.respectTransparency false in /-- The discriminant of the power basis given by a primitive root of unity `ζ` is the same as the discriminant of the power basis given by `ζ - 1`. -/ theorem discr_zeta_eq_discr_zeta_sub_one (hζ : IsPrimitiveRoot ζ n) : diff --git a/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean b/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean index d7a058d797cef9..dbc584d9b0124c 100644 --- a/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean +++ b/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean @@ -118,7 +118,6 @@ namespace IsPrimitiveRoot variable {C} -set_option backward.isDefEq.respectTransparency false in /-- The `PowerBasis` given by a primitive root `η`. -/ @[simps!] protected noncomputable def powerBasis : PowerBasis K L := @@ -182,7 +181,6 @@ theorem finrank (hirr : Irreducible (cyclotomic n K)) : finrank K L = n.totient rw [((zeta_spec n K L).powerBasis K).finrank, IsPrimitiveRoot.powerBasis_dim, ← (zeta_spec n K L).minpoly_eq_cyclotomic_of_irreducible hirr, natDegree_cyclotomic] -set_option backward.isDefEq.respectTransparency false in variable {L} in /-- If `L` contains both a primitive `p`-th root of unity and `q`-th root of unity, and `Irreducible (cyclotomic (lcm p q) K)` (in particular for `K = ℚ`), then the `finrank K L` is at @@ -387,7 +385,6 @@ theorem minpoly_sub_one_eq_cyclotomic_comp [Algebra K A] [IsDomain A] {ζ : A} open scoped Cyclotomic -set_option backward.isDefEq.respectTransparency false in /-- If `Irreducible (cyclotomic (p ^ (k + 1)) K)` (in particular for `K = ℚ`) and `p` is a prime, then the norm of `ζ ^ (p ^ s) - 1` is `p ^ (p ^ s)` if `p ^ (k - s + 1) ≠ 2`. See the next lemmas for similar results. -/ diff --git a/Mathlib/NumberTheory/FunctionField.lean b/Mathlib/NumberTheory/FunctionField.lean index 6942020a09bba6..af71fedeb637ca 100644 --- a/Mathlib/NumberTheory/FunctionField.lean +++ b/Mathlib/NumberTheory/FunctionField.lean @@ -107,7 +107,6 @@ instance : IsIntegralClosure (ringOfIntegers Fq F) Fq[X] F := variable [Algebra (RatFunc Fq) F] [IsScalarTower Fq[X] (RatFunc Fq) F] -set_option backward.isDefEq.respectTransparency false in theorem algebraMap_injective : Function.Injective (⇑(algebraMap Fq[X] (ringOfIntegers Fq F))) := by have hinj : Function.Injective (⇑(algebraMap Fq[X] F)) := by rw [IsScalarTower.algebraMap_eq Fq[X] (RatFunc Fq) F] @@ -118,7 +117,6 @@ theorem algebraMap_injective : Function.Injective (⇑(algebraMap Fq[X] (ringOfI rw [injective_iff_map_eq_zero (algebraMap Fq[X] F)] at hinj exact hinj p hp -set_option backward.isDefEq.respectTransparency false in theorem not_isField : ¬IsField (ringOfIntegers Fq F) := by simpa [← (IsIntegralClosure.isIntegral_algebra Fq[X] F).isField_iff_isField (algebraMap_injective Fq F)] using @@ -132,11 +130,9 @@ instance : IsFractionRing (ringOfIntegers Fq F) F := instance : IsIntegrallyClosed (ringOfIntegers Fq F) := integralClosure.isIntegrallyClosedOfFiniteExtension (RatFunc Fq) -set_option backward.isDefEq.respectTransparency false in instance [Algebra.IsSeparable (RatFunc Fq) F] : IsNoetherian Fq[X] (ringOfIntegers Fq F) := IsIntegralClosure.isNoetherian _ (RatFunc Fq) F _ -set_option backward.isDefEq.respectTransparency false in instance [Algebra.IsSeparable (RatFunc Fq) F] : IsDedekindDomain (ringOfIntegers Fq F) := IsIntegralClosure.isDedekindDomain Fq[X] (RatFunc Fq) F _ @@ -226,6 +222,9 @@ theorem inftyValuation.polynomial {p : Fq[X]} (hp : p ≠ 0) : instance : Valuation.IsNontrivial (inftyValuation Fq) := ⟨RatFunc.X, by simp⟩ +instance : Valuation.IsTrivialOn Fq (inftyValuation Fq) := + ⟨fun _ hx ↦ by simp [inftyValuation.C _ hx]⟩ + /-- The valued field `Fq(t)` with the valuation at infinity. -/ @[implicit_reducible] def inftyValuedFqt : Valued (RatFunc Fq) ℤᵐ⁰ := diff --git a/Mathlib/NumberTheory/Height/MvPolynomial.lean b/Mathlib/NumberTheory/Height/MvPolynomial.lean index cc96377f2c3256..80a73288c605e3 100644 --- a/Mathlib/NumberTheory/Height/MvPolynomial.lean +++ b/Mathlib/NumberTheory/Height/MvPolynomial.lean @@ -234,15 +234,20 @@ lemma mulHeightBound_eq (p : ι' → MvPolynomial ι K) : ∏ᶠ v : nonarchAbsVal, ⨆ j, max (⨆ s : (p j).support, v.val (coeff s (p j))) 1 := rfl -lemma mulHeightBound_zero_one : mulHeightBound ![(0 : MvPolynomial (Fin 2) K), 1] = 1 := by - simp only [mulHeightBound, Nat.succ_eq_add_one, Nat.reduceAdd, iSup_fun_eq_max] - conv_rhs => rw [← one_mul 1] - congr - · convert Multiset.prod_map_one with v - simp [MvPolynomial.sum_def, support_one] - · refine finprod_eq_one_of_forall_eq_one fun v ↦ ?_ - rw [show ![(0 : MvPolynomial (Fin 2) K), 1] 1 = 1 from rfl, support_one] - simp +variable (K ι ι') in +lemma max_mulHeightBound_zero_one_eq_one : + max (mulHeightBound (0 : ι' → MvPolynomial ι K)) 1 = 1 := by + simp only [mulHeightBound_eq, Pi.zero_apply, support_zero, coeff_zero, AbsoluteValue.map_zero, + Real.iSup_of_isEmpty, zero_le_one, sup_of_le_right] + set_option backward.isDefEq.respectTransparency false in -- temporary measure + simp only [Finsupp.sum_zero_index] -- singling this out for needing the above + simp only [Real.iSup_const_zero, Multiset.map_const', Multiset.prod_replicate, zero_pow_eq] + rcases isEmpty_or_nonempty ι' + · split_ifs + · simpa using finprod_zero_le_one + · simp + · simp + grind variable [Finite ι'] @@ -378,4 +383,134 @@ theorem logHeight_eval_le' {N : ℕ} {p : ι' → MvPolynomial ι K} (hp : ∀ i end Height +/-! +### Lower bound for the height of the image under a polynomial map + +If +* `p : ι' → MvPolynomial ι K` is a family of homogeneous polynomials of the same degree `N`, +* `q : ι × ι' → MvPolynomial ι K` is a family of homogeneous polynomials of the same degree `M`, +* `x : ι → K` is such that for all `k : ι`, + `∑ j, (q (k, j)).eval x * (p j).eval x = (x k) ^ (M + N)`, +then the multiplicative height of `fun j ↦ (p j).eval x` is bounded below by an (explicit) positive +constant depending only on `q` times the `N`th power of the mutiplicative height of `x`. +A similar statement holds for the logarithmic height. + +Note that we only require the polynomial relations `∑ j, q (k, j) * p j = X k ^ (M + N)` +to hold after evaluating at `x`. In this way, we can apply the result to points on some +subvariety of projective space when the map given by `p` is a morphism on that subvariety, +but not necessarily on all of the ambient space. In fact, the proof does not even need that +`p j` is homogeneous (of fixed degree). In applications, this will be the case, however, +and if the third condition above holds on the level of polynomials, then it follows. + +The main idea is to reduce this to a combination of `mulHeight_linearMap_apply_le` +and `mulHeight_eval_le`. +-/ + +namespace Height + +variable {K : Type*} [Field K] {ι ι' : Type*} [Fintype ι'] + +private lemma mulHeight_eval_ge_aux {M N : ℕ} {q : ι × ι' → MvPolynomial ι K} [IsEmpty ι'] + (p : ι' → MvPolynomial ι K) {x : ι → K} + (h : ∀ k, ∑ j, (q (k, j)).eval x * (p j).eval x = (x k) ^ (M + N)) : + x = 0 := by + ext i + simp only [Finset.univ_eq_empty, Finset.sum_empty] at h + exact eq_zero_of_pow_eq_zero <| (h i).symm + +variable [AdmissibleAbsValues K] [Finite ι] + +open AdmissibleAbsValues + +/-- If +* `p : ι' → MvPolynomial ι K` is a family of polynomials (which in practice will be homogeneous + of the same degree `N`), +* `q : ι × ι' → MvPolynomial ι K` is a family of homogeneous polynomials of the same degree `M`, +* `x : ι → K` is such that for all `k : ι`, + `∑ j, (q (k, j)).eval x * (p j).eval x = (x k) ^ (M + N)`, +then the multiplicative height of `fun j ↦ (p j).eval x` is bounded below by an (explicit) positive +constant depending only on `q` times the `N`th power of the mutiplicative height of `x`. -/ +theorem mulHeight_eval_ge {M N : ℕ} {q : ι × ι' → MvPolynomial ι K} + (hq : ∀ a, (q a).IsHomogeneous M) (p : ι' → MvPolynomial ι K) {x : ι → K} + (h : ∀ k, ∑ j, (q (k, j)).eval x * (p j).eval x = (x k) ^ (M + N)) : + (Nat.card ι' ^ totalWeight K * max (mulHeightBound q) 1)⁻¹ * mulHeight x ^ N ≤ + mulHeight (fun j ↦ (p j).eval x) := by + rcases isEmpty_or_nonempty ι' + · simp [show q = 0 from Subsingleton.elim .., max_mulHeightBound_zero_one_eq_one K ι (ι × ι'), + mulHeight_eval_ge_aux p h] + grind [zero_pow_eq] + -- case `ι'` nonempty + let q' : ι × ι' → K := fun a ↦ (q a).eval x + have H : mulHeight x ^ (M + N) ≤ + Nat.card ι' ^ totalWeight K * mulHeight q' * mulHeight fun j ↦ (p j).eval x := by + rw [← mulHeight_pow x (M + N)] + have : x ^ (M + N) = fun k ↦ ∑ j, (q (k, j)).eval x * (p j).eval x := funext fun k ↦ (h k).symm + simpa [this] using mulHeight_linearMap_apply_le q' _ + rw [inv_mul_le_iff₀ ?hC, ← mul_le_mul_iff_left₀ (by positivity : 0 < mulHeight x ^ M)] + case hC => exact mul_pos (mod_cast Nat.one_le_pow _ _ Nat.card_pos) <| by positivity + rw [← pow_add, add_comm] + grw [H, mulHeight_eval_le hq x] + exact Eq.le (by ring) + +/-- If +* `p : ι' → MvPolynomial ι K` is a family of polynomials (which in practice will be homogeneous + of the same degree `N`), +* `q : ι × ι' → MvPolynomial ι K` is a family of homogeneous polynomials of the same degree `M`, +* `x : ι → K` is such that for all `k : ι`, + `∑ j, (q (k, j)).eval x * (p j).eval x = (x k) ^ (M + N)`, +then the multiplicative height of `fun j ↦ (p j).eval x` is bounded below by a positive +constant depending only on `q` times the `N`th power of the mutiplicative height of `x`. + +The difference to `mulHeight_eval_ge` is that the constant is not made explicit. -/ +theorem mulHeight_eval_ge' {M N : ℕ} {q : ι × ι' → MvPolynomial ι K} + (hq : ∀ a, (q a).IsHomogeneous M) : + ∃ C > 0, ∀ (p : ι' → MvPolynomial ι K) {x : ι → K} + (_h : ∀ k, ∑ j, (q (k, j)).eval x * (p j).eval x = (x k) ^ (M + N)), + C * mulHeight x ^ N ≤ mulHeight (fun j ↦ (p j).eval x) := by + rcases isEmpty_or_nonempty ι' + · exact ⟨1, zero_lt_one, fun p _ h ↦ by simp [mulHeight_eval_ge_aux p h]⟩ + have : 0 < Nat.card ι' := Nat.card_pos + exact ⟨_, by positivity, mulHeight_eval_ge hq⟩ + +open Real in +/-- If +* `p : ι' → MvPolynomial ι K` is a family of polynomials (which in practice will be homogeneous + of the same degree `N`), +* `q : ι × ι' → MvPolynomial ι K` is a family of homogeneous polynomials of the same degree `M`, +* `x : ι → K` is such that for all `k : ι`, + `∑ j, (q (k, j)).eval x * (p j).eval x = (x k) ^ (M + N)`, +then the logarithmic height of `fun j ↦ (p j).eval x` is bounded below by an (explicit) +constant depending only on `q` plus `N` times the logarithmic height of `x`. -/ +theorem logHeight_eval_ge {M N : ℕ} {q : ι × ι' → MvPolynomial ι K} + (hq : ∀ a, (q a).IsHomogeneous M) (p : ι' → MvPolynomial ι K) {x : ι → K} + (h : ∀ k, ∑ j, (q (k, j)).eval x * (p j).eval x = (x k) ^ (M + N)) : + -log (Nat.card ι' ^ totalWeight K * max (mulHeightBound q) 1) + N * logHeight x ≤ + logHeight (fun j ↦ (p j).eval x) := by + simp only [logHeight_eq_log_mulHeight] + rcases isEmpty_or_nonempty ι' + · simp [show q = 0 from Subsingleton.elim .., mulHeight_eval_ge_aux p h, + max_mulHeightBound_zero_one_eq_one K ι (ι × ι')] + have : (Nat.card ι' : ℝ) ^ totalWeight K ≠ 0 := by simp + pull (disch := first | assumption | positivity) log + exact (log_le_log <| by positivity) <| mulHeight_eval_ge hq p h + +/-- If +* `p : ι' → MvPolynomial ι K` is a family of polynomials (which in practice will be homogeneous + of the same degree `N`), +* `q : ι × ι' → MvPolynomial ι K` is a family of homogeneous polynomials of the same degree `M`, +* `x : ι → K` is such that for all `k : ι`, + `∑ j, (q (k, j)).eval x * (p j).eval x = (x k) ^ (M + N)`, +then the logarithmic height of `fun j ↦ (p j).eval x` is bounded below by a +constant plus `N` times the logarithmic height of `x`. + +The difference to `logHeight_eval_ge` is that the constant is not made explicit. -/ +theorem logHeight_eval_ge' {M N : ℕ} {q : ι × ι' → MvPolynomial ι K} + (hq : ∀ a, (q a).IsHomogeneous M) : + ∃ C, ∀ (p : ι' → MvPolynomial ι K) {x : ι → K} + (_h : ∀ k, ∑ j, (q (k, j)).eval x * (p j).eval x = (x k) ^ (M + N)), + C + N * logHeight x ≤ logHeight (fun j ↦ (p j).eval x) := + ⟨_, logHeight_eval_ge hq⟩ + +end Height + end diff --git a/Mathlib/NumberTheory/KummerDedekind.lean b/Mathlib/NumberTheory/KummerDedekind.lean index e014b6116415ec..2243c6abffde15 100644 --- a/Mathlib/NumberTheory/KummerDedekind.lean +++ b/Mathlib/NumberTheory/KummerDedekind.lean @@ -70,7 +70,6 @@ variable [Module.IsTorsionFree R S] attribute [local instance] Ideal.Quotient.field -set_option backward.isDefEq.respectTransparency false in /-- The isomorphism of rings between `S / I` and `(R / I)[X] / minpoly x` when `I` and `(conductor R x) ∩ R` are coprime. @@ -83,7 +82,6 @@ noncomputable def quotMapEquivQuotQuotMap (hx : (conductor R x).comap (algebraMa ((Algebra.adjoin.powerBasis' hx').quotientEquivQuotientMinpolyMap I).toRingEquiv.trans <| quotEquivOfEq (by rw [Algebra.adjoin.powerBasis'_minpoly_gen hx']) -set_option backward.isDefEq.respectTransparency false in lemma quotMapEquivQuotQuotMap_symm_apply (hx : (conductor R x).comap (algebraMap R S) ⊔ I = ⊤) (hx' : IsIntegral R x) (Q : R[X]) : (quotMapEquivQuotQuotMap hx hx').symm (Q.map (Ideal.Quotient.mk I)) = Q.aeval x := by diff --git a/Mathlib/NumberTheory/MahlerMeasure.lean b/Mathlib/NumberTheory/MahlerMeasure.lean index 9c45ea002af7e3..c24cf5d3c1a32c 100644 --- a/Mathlib/NumberTheory/MahlerMeasure.lean +++ b/Mathlib/NumberTheory/MahlerMeasure.lean @@ -176,7 +176,6 @@ lemma norm_root_le_one_of_mahlerMeasure_eq_one : ‖z‖ ≤ 1 := by _ ≤ 1 := by grind [prod_max_one_norm_roots_le_mahlerMeasure_of_one_le_leadingCoeff, norm_leadingCoeff_eq_one_of_mahlerMeasure_eq_one] -set_option backward.isDefEq.respectTransparency false in open IntermediateField in include hz₀ hz h in /-- If an integer polynomial has Mahler measure equal to 1, then all its complex nonzero roots are diff --git a/Mathlib/NumberTheory/ModularForms/Derivative.lean b/Mathlib/NumberTheory/ModularForms/Derivative.lean new file mode 100644 index 00000000000000..b557c4adfb676e --- /dev/null +++ b/Mathlib/NumberTheory/ModularForms/Derivative.lean @@ -0,0 +1,174 @@ +/- +Copyright (c) 2026 Seewoo Lee. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Seewoo Lee +-/ +module + +public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.E2.MDifferentiable + +/-! +# Derivatives of modular forms + +This file defines normalized derivative $D = \frac{1}{2\pi i} \frac{d}{dz}$ +and serre dervative $\partial_k := D - \frac{k}{12} E_2$ of modular forms. + +TODO: +- Serre derivative preserves modularity, i.e. $\partial_k (M_k) \subseteq M_{k+2}$. +- Use above, prove Ramanujan's identities. See [here](https://github.com/thefundamentaltheor3m/Sphere-Packing-Lean/blob/main/SpherePacking/ModularForms/RamanujanIdentities.lean) + for `sorry`-free proofs. +-/ + +open UpperHalfPlane hiding I +open Real Complex +open scoped Manifold + +namespace Derivative + +@[expose] public noncomputable section + +/-- +Normalized derivative $D = \frac{1}{2\pi i} \frac{d}{dz}$. +-/ +def normalizedDerivOfComplex (F : ℍ → ℂ) (z : ℍ) : ℂ := (2 * π * I)⁻¹ * deriv (F ∘ ofComplex) z + +/-- We denote the normalized derivative by `D`. -/ +scoped notation "D" => normalizedDerivOfComplex + +/-- +The derivative operator `D` preserves MDifferentiability. +If `F : ℍ → ℂ` is MDifferentiable, then `D F` is also MDifferentiable. +-/ +theorem normalizedDerivOfComplex_mdifferentiable {F : ℍ → ℂ} (hF : MDiff F) : MDiff (D F) := by + rw [UpperHalfPlane.mdifferentiable_iff] at hF ⊢ + let c : ℂ := (2 * π * I)⁻¹ + have hDeriv : DifferentiableOn ℂ (fun z ↦ c * deriv (F ∘ ofComplex) z) upperHalfPlaneSet := by + simpa [c] using (hF.deriv isOpen_upperHalfPlaneSet).const_mul ((2 * π * I)⁻¹) + refine hDeriv.congr ?_ + intro z hz + simp [normalizedDerivOfComplex, c, Function.comp_apply, ofComplex_apply_of_im_pos hz] + +/-! +Basic properties of normalized derivative. +-/ +@[simp] +theorem normalizedDerivOfComplex_add (F G : ℍ → ℂ) (hF : MDiff F) (hG : MDiff G) : + D (F + G) = D F + D G := by + ext z + have hFz := UpperHalfPlane.mdifferentiableAt_iff.mp (hF z) + have hGz := UpperHalfPlane.mdifferentiableAt_iff.mp (hG z) + simp only [normalizedDerivOfComplex, Pi.add_apply] + rw [show (F + G) ∘ ofComplex = F ∘ ofComplex + G ∘ ofComplex from rfl, + deriv_add hFz hGz, mul_add] + +@[simp] +theorem normalizedDerivOfComplex_sub (F G : ℍ → ℂ) (hF : MDiff F) (hG : MDiff G) : + D (F - G) = D F - D G := by + ext z + have hFz := UpperHalfPlane.mdifferentiableAt_iff.mp (hF z) + have hGz := UpperHalfPlane.mdifferentiableAt_iff.mp (hG z) + simp only [normalizedDerivOfComplex, Pi.sub_apply] + rw [show (F - G) ∘ ofComplex = F ∘ ofComplex - G ∘ ofComplex from rfl, + deriv_sub hFz hGz, mul_sub] + +@[simp] +theorem normalizedDerivOfComplex_const (c : ℂ) : D (fun _ ↦ c) = 0 := by + ext z + change (2 * π * I)⁻¹ * deriv (fun _ : ℂ ↦ c) (z : ℂ) = 0 + simp [deriv_const] + +@[simp] +theorem normalizedDerivOfComplex_smul (c : ℂ) (F : ℍ → ℂ) (hF : MDiff F) : D (c • F) = c • D F := by + ext z + have hFz := UpperHalfPlane.mdifferentiableAt_iff.mp (hF z) + simp only [normalizedDerivOfComplex, Pi.smul_apply, smul_eq_mul] + rw [show (c • F) ∘ ofComplex = c • (F ∘ ofComplex) from rfl, + deriv_const_smul c hFz, smul_eq_mul] + ring + +@[simp] +theorem normalizedDerivOfComplex_neg (F : ℍ → ℂ) (hF : MDiff F) : D (-F) = -D F := by + have : -F = (-1 : ℂ) • F := by ext; simp + rw [this, normalizedDerivOfComplex_smul _ _ hF] + ext + simp + +@[simp] +theorem normalizedDerivOfComplex_mul (F G : ℍ → ℂ) (hF : MDiff F) (hG : MDiff G) : + D (F * G) = D F * G + F * D G := by + ext z + have hFz := UpperHalfPlane.mdifferentiableAt_iff.mp (hF z) + have hGz := UpperHalfPlane.mdifferentiableAt_iff.mp (hG z) + simp only [normalizedDerivOfComplex, Pi.add_apply, Pi.mul_apply] + rw [show (F * G) ∘ ofComplex = (F ∘ ofComplex) * (G ∘ ofComplex) from rfl, + deriv_mul hFz hGz] + simp [Function.comp_apply, ofComplex_apply] + ring + +@[simp] +theorem normalizedDerivOfComplex_pow (F : ℍ → ℂ) (n : ℕ) (hF : MDiff F) : + D (F ^ n) = n * F ^ (n - 1) * D F := by + ext z + have hFz := UpperHalfPlane.mdifferentiableAt_iff.mp (hF z) + simp only [normalizedDerivOfComplex, Pi.mul_apply, Pi.pow_apply] + rw [show (F ^ n) ∘ ofComplex = (F ∘ ofComplex) ^ n from rfl, deriv_pow hFz n] + simp [Function.comp_apply, ofComplex_apply] + ring + +/-- +Serre derivative of weight $k$. +-/ +def serreDerivative (k : ℂ) (F : ℍ → ℂ) (z : ℍ) : ℂ := + D F z - k * 12⁻¹ * EisensteinSeries.E2 z * F z + +@[simp] +lemma serreDerivative_apply (k : ℂ) (F : ℍ → ℂ) (z : ℍ) : + serreDerivative k F z = D F z - k * 12⁻¹ * EisensteinSeries.E2 z * F z := rfl + +@[simp] +lemma serreDerivative_eq (k : ℂ) (F : ℍ → ℂ) : + serreDerivative k F = fun z ↦ D F z - k * 12⁻¹ * EisensteinSeries.E2 z * F z := rfl + +/-! +Basic properties of Serre derivative. +-/ +theorem serreDerivative_add (k : ℂ) (F G : ℍ → ℂ) (hF : MDiff F) (hG : MDiff G) : + serreDerivative k (F + G) = serreDerivative k F + serreDerivative k G := by + ext z + simp [serreDerivative, normalizedDerivOfComplex_add F G hF hG] + ring_nf + +theorem serreDerivative_sub (k : ℂ) (F G : ℍ → ℂ) (hF : MDiff F) (hG : MDiff G) : + serreDerivative k (F - G) = serreDerivative k F - serreDerivative k G := by + ext z + simp [serreDerivative, normalizedDerivOfComplex_sub F G hF hG] + ring_nf + +theorem serreDerivative_smul (k : ℂ) (c : ℂ) (F : ℍ → ℂ) (hF : MDiff F) : + serreDerivative k (c • F) = c • (serreDerivative k F) := by + ext z + simp [serreDerivative, normalizedDerivOfComplex_smul c F hF, smul_eq_mul] + ring_nf + +theorem serreDerivative_mul (k₁ k₂ : ℂ) (F G : ℍ → ℂ) (hF : MDiff F) (hG : MDiff G) : + serreDerivative (k₁ + k₂) (F * G) = (serreDerivative k₁ F) * G + F * (serreDerivative k₂ G) + := by + ext z + simp [serreDerivative, normalizedDerivOfComplex_mul F G hF hG] + ring_nf + +/-- +The Serre derivative preserves MDifferentiability. +If `F : ℍ → ℂ` is MDifferentiable, then `serreDerivative k F` is also MDifferentiable. +-/ +theorem serreDerivative_mdifferentiable {F : ℍ → ℂ} (k : ℂ) (hF : MDiff F) : + MDiff (serreDerivative k F) := by + refine (normalizedDerivOfComplex_mdifferentiable hF).sub ?_ + convert + (MDifferentiable.mul mdifferentiable_const (E2_mdifferentiable.mul hF) : + MDiff (fun z ↦ (k * 12⁻¹) * (EisensteinSeries.E2 z * F z))) + simp [Pi.mul_apply, mul_assoc, mul_left_comm, mul_comm] + +end + +end Derivative diff --git a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean index 5d767a6e2353db..b3677e3bfbc4cf 100644 --- a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean +++ b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/QExpansion.lean @@ -11,6 +11,7 @@ public import Mathlib.NumberTheory.LSeries.Dirichlet public import Mathlib.NumberTheory.LSeries.HurwitzZetaValues public import Mathlib.NumberTheory.ModularForms.EisensteinSeries.Basic public import Mathlib.NumberTheory.TsumDivisorsAntidiagonal +import Mathlib.Topology.EMetricSpace.Paracompact /-! # Eisenstein series q-expansions diff --git a/Mathlib/NumberTheory/NumberField/Basic.lean b/Mathlib/NumberTheory/NumberField/Basic.lean index bf916103078e9a..e85e53cd7be1bb 100644 --- a/Mathlib/NumberTheory/NumberField/Basic.lean +++ b/Mathlib/NumberTheory/NumberField/Basic.lean @@ -73,7 +73,6 @@ theorem of_module_finite [NumberField K] [Algebra K L] [Module.Finite K L] : Num letI := charZero_of_injective_algebraMap (algebraMap K L).injective Module.Finite.trans K L -set_option backward.isDefEq.respectTransparency false in variable {K} {L} in instance of_intermediateField [NumberField K] [NumberField L] [Algebra K L] (E : IntermediateField K L) : NumberField E := @@ -116,7 +115,6 @@ instance : CommRing (𝓞 K) := instance : IsDomain (𝓞 K) := inferInstanceAs (IsDomain (integralClosure _ _)) -set_option backward.isDefEq.respectTransparency false in instance [NumberField K] : CharZero (𝓞 K) := inferInstanceAs (CharZero (integralClosure _ _)) diff --git a/Mathlib/NumberTheory/NumberField/CMField.lean b/Mathlib/NumberTheory/NumberField/CMField.lean index c8071141d425ce..1eae846c38cfa2 100644 --- a/Mathlib/NumberTheory/NumberField/CMField.lean +++ b/Mathlib/NumberTheory/NumberField/CMField.lean @@ -517,7 +517,6 @@ theorem ofCMExtension : is_quadratic := ⟨(IsQuadraticExtension.finrank_eq_two F K) ▸ finrank_eq_of_equiv_equiv (CMExtension.equivMaximalRealSubfield F K).symm (RingEquiv.refl K) (by ext; simp)⟩ -set_option backward.isDefEq.respectTransparency false in open IntermediateField in /-- A totally complex field that has a unique complex conjugation is CM. @@ -565,7 +564,6 @@ namespace IsCyclotomicExtension.Rat variable (K : Type*) [Field K] [CharZero K] -set_option backward.isDefEq.respectTransparency false in open IntermediateField in /-- A nontrivial abelian extension of `ℚ` is CM. diff --git a/Mathlib/NumberTheory/NumberField/Completion/FinitePlace.lean b/Mathlib/NumberTheory/NumberField/Completion/FinitePlace.lean index 5f194f711d4161..4c4eaa3b446d8f 100644 --- a/Mathlib/NumberTheory/NumberField/Completion/FinitePlace.lean +++ b/Mathlib/NumberTheory/NumberField/Completion/FinitePlace.lean @@ -6,16 +6,12 @@ Authors: Fabrizio Barroero module public import Mathlib.Algebra.Order.Archimedean.Submonoid -public import Mathlib.Algebra.GroupWithZero.Range -public import Mathlib.Data.Int.WithZero +public import Mathlib.LinearAlgebra.FreeModule.IdealQuotient public import Mathlib.NumberTheory.NumberField.InfinitePlace.Embeddings -public import Mathlib.RingTheory.DedekindDomain.AdicValuation public import Mathlib.RingTheory.DedekindDomain.Factorization -public import Mathlib.RingTheory.Ideal.Norm.AbsNorm public import Mathlib.RingTheory.Valuation.Archimedean -public import Mathlib.Topology.Algebra.Valued.NormedValued -public import Mathlib.LinearAlgebra.FreeModule.IdealQuotient public import Mathlib.RingTheory.Valuation.Discrete.RankOne +public import Mathlib.Topology.Algebra.Valued.NormedValued import Mathlib.Algebra.FiniteSupport.Basic @@ -24,13 +20,18 @@ import Mathlib.Algebra.FiniteSupport.Basic This file defines finite places of a number field `K` as absolute values coming from an embedding into a completion of `K` associated to a non-zero prime ideal of `𝓞 K`. +Many of the results in this file are expressed in the generality of: `R` is a Dedekind domain +with field of fractions `K` such that `Module.Finite ℤ R` and `Module.Free ℤ R`. If `K` is +a number field, then this characterises `R` as being isomorphic to `𝓞 K` without explicitly +requiring `𝓞 K`. This is so that `ℤ` and `𝓞 ℚ` can be used interchangeably. + ## Main Definitions and Results * `NumberField.adicAbv`: a `v`-adic absolute value on `K`. * `NumberField.FinitePlace`: the type of finite places of a number field `K`. * `NumberField.FinitePlace.embedding`: the canonical embedding of a number field `K` to the `v`-adic completion `v.adicCompletion K` of `K`, where `v` is a non-zero prime ideal of `𝓞 K` * `NumberField.FinitePlace.norm_embedding`: the norm of `embedding v x` is the same as the `v`-adic - absolute value of `x`. See also `NumberField.FinitePlace.norm_def'` and + absolute value of `x`. See also `NumberField.FinitePlace.norm_embedding'` and `NumberField.FinitePlace.norm_embedding_int` for versions where the `v`-adic absolute value is unfolded. * `NumberField.FinitePlace.hasFiniteMulSupport`: the `v`-adic absolute value of a non-zero element @@ -83,16 +84,35 @@ instance : IsDiscreteValuationRing (v.adicCompletionIntegers K) where end DVR -variable {K : Type*} [Field K] [NumberField K] - namespace NumberField -variable (v : HeightOneSpectrum (𝓞 K)) +variable {K : Type*} [Field K] {R : Type*} [CommRing R] [Algebra R K] [IsDedekindDomain R] + [IsFractionRing R K] (v : HeightOneSpectrum R) + +/-- The embedding of a field inside its `adicCompletion` with respect to `v`. -/ +noncomputable def FinitePlace.embedding : K →+* adicCompletion K v := + UniformSpace.Completion.coeRingHom.comp (WithVal.equiv (v.valuation K)).symm -namespace RingOfIntegers.HeightOneSpectrum +theorem FinitePlace.embedding_apply (x : K) : embedding v x = ↑x := rfl section AbsoluteValue +noncomputable instance : ((Valued.v : Valuation (v.adicCompletion K) ℤᵐ⁰)).IsRankOneDiscrete where + exists_generator_lt_one' := by + have h : (v.valuation K).IsRankOneDiscrete := Valuation.IsRankOneDiscrete.mk' (valuation K v) + exact ⟨h.generator, by rw [h.generator_zpowers_eq_valueGroup, adicCompletion_valueGroup_eq], + h.generator_lt_one⟩ + +section FiniteFree + +/-! In this section we assume further that `Module.Finite ℤ R` and `Module.Free ℤ R`. +This characterises `R` as being isomorphic to `𝓞 K` without explicitly requiring that type. +As a result, if `F = ℚ`, then we can use `ℤ` and `𝓞 ℚ` interchangeably. -/ + +variable [Module.Finite ℤ R] [Module.Free ℤ R] + +namespace HeightOneSpectrum + /-- The norm of a maximal ideal is `> 1` -/ lemma one_lt_absNorm : 1 < absNorm v.asIdeal := by by_contra! h @@ -110,36 +130,18 @@ lemma one_lt_absNorm_nnreal : 1 < (absNorm v.asIdeal : ℝ≥0) := mod_cast one_ lemma absNorm_ne_zero : (absNorm v.asIdeal : ℝ≥0) ≠ 0 := ne_zero_of_lt (one_lt_absNorm_nnreal v) +variable (K) + /-- The `v`-adic absolute value on `K` defined as the norm of `v` raised to negative `v`-adic valuation -/ noncomputable def adicAbv : AbsoluteValue K ℝ := v.adicAbv <| one_lt_absNorm_nnreal v -theorem adicAbv_def {x : K} : adicAbv v x = toNNReal (absNorm_ne_zero v) (v.valuation K x) := rfl +theorem adicAbv_def {x : K} : adicAbv K v x = toNNReal (absNorm_ne_zero v) (v.valuation K x) := rfl /-- The `v`-adic absolute value is nonarchimedean -/ -theorem isNonarchimedean_adicAbv : IsNonarchimedean (adicAbv v) := +theorem isNonarchimedean_adicAbv : IsNonarchimedean (adicAbv K v) := v.isNonarchimedean_adicAbv <| one_lt_absNorm_nnreal v -end AbsoluteValue - -end RingOfIntegers.HeightOneSpectrum - -section FinitePlace - -open RingOfIntegers.HeightOneSpectrum - -/-- The embedding of a number field inside its completion with respect to `v`. -/ -noncomputable def FinitePlace.embedding : K →+* adicCompletion K v := - UniformSpace.Completion.coeRingHom.comp (WithVal.equiv (v.valuation K)).symm - -theorem FinitePlace.embedding_apply (x : K) : embedding v x = ↑x := rfl - -noncomputable instance : ((Valued.v : Valuation (v.adicCompletion K) ℤᵐ⁰)).IsRankOneDiscrete where - exists_generator_lt_one' := by - have h : (v.valuation K).IsRankOneDiscrete := Valuation.IsRankOneDiscrete.mk' (valuation K v) - exact ⟨h.generator, by rw [h.generator_zpowers_eq_valueGroup, adicCompletion_valueGroup_eq], - h.generator_lt_one⟩ - open Valuation.IsRankOneDiscrete noncomputable instance : (v.valuation K).RankOne := @@ -150,35 +152,59 @@ noncomputable instance instRankOneAdicCompletion : rankOne (Valued.v : Valuation (v.adicCompletion K) ℤᵐ⁰) (one_lt_absNorm_nnreal v) lemma rankOne_hom'_def : - (instRankOneAdicCompletion v).hom' = (toNNReal (absNorm_ne_zero v)).comp + (instRankOneAdicCompletion K v).hom' = (toNNReal (absNorm_ne_zero v)).comp (valueGroup₀_equiv_withZeroMulInt Valued.v).toMonoidWithZeroHom := rfl /-- The `v`-adic completion of `K` is a normed field. -/ noncomputable instance instNormedFieldValuedAdicCompletion : NormedField (adicCompletion K v) := Valued.toNormedField (adicCompletion K v) ℤᵐ⁰ -/-- A finite place of a number field `K` is a place associated to an embedding into a completion -with respect to a maximal ideal. -/ -def FinitePlace (K : Type*) [Field K] [NumberField K] := - {w : AbsoluteValue K ℝ // ∃ v : HeightOneSpectrum (𝓞 K), place (FinitePlace.embedding v) = w} - -/-- Return the finite place defined by a maximal ideal `v`. -/ -noncomputable def FinitePlace.mk (v : HeightOneSpectrum (𝓞 K)) : FinitePlace K := - ⟨place (embedding v), ⟨v, rfl⟩⟩ - lemma toNNReal_valued_eq_adicAbv (x : WithVal (v.valuation K)) : - toNNReal (absNorm_ne_zero v) (Valued.v x) = adicAbv v (WithVal.equiv _ x) := rfl + toNNReal (absNorm_ne_zero v) (Valued.v x) = adicAbv K v (WithVal.equiv _ x) := rfl -/-- A predicate singling out finite places among the absolute values on a number field `K`. -/ -def IsFinitePlace (w : AbsoluteValue K ℝ) : Prop := - ∃ v : IsDedekindDomain.HeightOneSpectrum (𝓞 K), place (FinitePlace.embedding v) = w +/-- The `v`-adic absolute value satisfies the ultrametric inequality. -/ +theorem adicAbv_add_le_max (x y : K) : + adicAbv K v (x + y) ≤ (adicAbv K v x) ⊔ (adicAbv K v y) := isNonarchimedean_adicAbv K v x y -lemma FinitePlace.isFinitePlace (v : FinitePlace K) : IsFinitePlace v.val := by - simp [IsFinitePlace, v.prop] +/-- The `v`-adic absolute value of a natural number is `≤ 1`. -/ +theorem adicAbv_natCast_le_one (n : ℕ) : adicAbv K v n ≤ 1 := + (isNonarchimedean_adicAbv K v).apply_natCast_le_one_of_isNonarchimedean -lemma isFinitePlace_iff (v : AbsoluteValue K ℝ) : - IsFinitePlace v ↔ ∃ w : FinitePlace K, w.val = v := - ⟨fun H ↦ ⟨⟨v, H⟩, rfl⟩, fun ⟨w, hw⟩ ↦ hw ▸ w.isFinitePlace⟩ +/-- The `v`-adic absolute value of an integer is `≤ 1`. -/ +theorem adicAbv_intCast_le_one (n : ℤ) : adicAbv K v n ≤ 1 := + (isNonarchimedean_adicAbv K v).apply_intCast_le_one_of_isNonarchimedean + +@[deprecated (since := "2026-03-11")] +alias NumberField.RingOfIntegers.HeightOneSpectrum.one_lt_absNorm := one_lt_absNorm +@[deprecated (since := "2026-03-11")] +alias NumberField.RingOfIntegers.HeightOneSpectrum.one_lt_absNorm_nnreal := one_lt_absNorm_nnreal +@[deprecated (since := "2026-03-11")] +alias NumberField.RingOfIntegers.HeightOneSpectrum.absNorm_ne_zero := absNorm_ne_zero +@[deprecated (since := "2026-03-11")] +alias NumberField.RingOfIntegers.HeightOneSpectrum.adicAbv := adicAbv +@[deprecated (since := "2026-03-11")] +alias NumberField.RingOfIntegers.HeightOneSpectrum.adicAbv_def := adicAbv_def +@[deprecated (since := "2026-03-11")] +alias NumberField.RingOfIntegers.HeightOneSpectrum.isNonarchimedean_adicAbv := + isNonarchimedean_adicAbv +@[deprecated (since := "2026-03-11")] +alias NumberField.instRankOneAdicCompletion := instRankOneAdicCompletion +@[deprecated (since := "2026-03-11")] +alias NumberField.instNormedFieldValuedAdicCompletion := instNormedFieldValuedAdicCompletion +@[deprecated (since := "2026-03-11")] +alias NumberField.rankOne_hom'_def := rankOne_hom'_def +@[deprecated (since := "2026-03-11")] +alias NumberField.toNNReal_valued_eq_adicAbv := toNNReal_valued_eq_adicAbv +@[deprecated (since := "2026-03-11")] +alias NumberField.RingOfIntegers.HeightOneSpectrum.adicAbv_add_le_max := adicAbv_add_le_max +@[deprecated (since := "2026-03-11")] +alias NumberField.RingOfIntegers.HeightOneSpectrum.adicAbv_natCast_le_one := adicAbv_natCast_le_one +@[deprecated (since := "2026-03-11")] +alias NumberField.RingOfIntegers.HeightOneSpectrum.adicAbv_intCast_le_one := adicAbv_intCast_le_one + +end HeightOneSpectrum + +open HeightOneSpectrum Valuation.IsRankOneDiscrete /-- The norm of an element in the `v`-adic completion of `K`. See `FinitePlace.norm_embedding` for the equality involving `‖embedding v x‖` on the LHS. -/ @@ -190,7 +216,7 @@ theorem FinitePlace.norm_def (x : v.adicCompletion K) : /-- The norm of the image after the embedding associated to `v` is equal to the `v`-adic absolute value. -/ -theorem FinitePlace.norm_embedding (x : K) : ‖embedding v x‖ = adicAbv v x := by +theorem FinitePlace.norm_embedding (x : K) : ‖embedding v x‖ = adicAbv K v x := by simp [norm_def, embedding_apply, adicAbv_def] /-- The norm of the image after the embedding associated to `v` is equal to the norm of `v` raised @@ -199,51 +225,79 @@ theorem FinitePlace.norm_embedding' (x : K) : ‖embedding v x‖ = toNNReal (absNorm_ne_zero v) (v.valuation K x) := by rw [norm_embedding, adicAbv_def] +variable (K) + /-- The norm of the image after the embedding associated to `v` is equal to the norm of `v` raised to the power of the `v`-adic valuation for integers. -/ -theorem FinitePlace.norm_embedding_int (x : 𝓞 K) : - ‖embedding v x‖ = toNNReal (absNorm_ne_zero v) (v.intValuation x) := by +theorem FinitePlace.norm_embedding_int (x : R) : + ‖embedding v (algebraMap _ K x)‖ = toNNReal (absNorm_ne_zero v) (v.intValuation x) := by simp [norm_embedding, adicAbv_def, valuation_of_algebraMap] @[deprecated (since := "2026-03-05")] alias FinitePlace.norm_def' := FinitePlace.norm_embedding' @[deprecated (since := "2026-03-05")] alias FinitePlace.norm_def_int := FinitePlace.norm_embedding_int -/-- The `v`-adic absolute value satisfies the ultrametric inequality. -/ -theorem RingOfIntegers.HeightOneSpectrum.adicAbv_add_le_max (x y : K) : - adicAbv v (x + y) ≤ (adicAbv v x) ⊔ (adicAbv v y) := isNonarchimedean_adicAbv v x y - -/-- The `v`-adic absolute value of a natural number is `≤ 1`. -/ -theorem RingOfIntegers.HeightOneSpectrum.adicAbv_natCast_le_one (n : ℕ) : adicAbv v n ≤ 1 := - (isNonarchimedean_adicAbv v).apply_natCast_le_one_of_isNonarchimedean - -/-- The `v`-adic absolute value of an integer is `≤ 1`. -/ -theorem RingOfIntegers.HeightOneSpectrum.adicAbv_intCast_le_one (n : ℤ) : adicAbv v n ≤ 1 := - (isNonarchimedean_adicAbv v).apply_intCast_le_one_of_isNonarchimedean - open FinitePlace /-- The `v`-adic norm of an integer is at most 1. -/ -theorem FinitePlace.norm_le_one (x : 𝓞 K) : ‖embedding v x‖ ≤ 1 := by +theorem FinitePlace.norm_le_one (x : R) : ‖embedding v (algebraMap _ K x)‖ ≤ 1 := by rw [norm_embedding] exact v.adicAbv_coe_le_one (one_lt_absNorm_nnreal v) x /-- The `v`-adic norm of an integer is 1 if and only if it is not in the ideal. -/ -theorem FinitePlace.norm_eq_one_iff_notMem (x : 𝓞 K) : - ‖embedding v x‖ = 1 ↔ x ∉ v.asIdeal := by +theorem FinitePlace.norm_eq_one_iff_notMem (x : R) : + ‖embedding v (algebraMap _ K x)‖ = 1 ↔ x ∉ v.asIdeal := by rw [norm_embedding] exact v.adicAbv_coe_eq_one_iff (one_lt_absNorm_nnreal v) x /-- The `v`-adic norm of an integer is less than 1 if and only if it is in the ideal. -/ -theorem FinitePlace.norm_lt_one_iff_mem (x : 𝓞 K) : - ‖embedding v x‖ < 1 ↔ x ∈ v.asIdeal := by +theorem FinitePlace.norm_lt_one_iff_mem (x : R) : + ‖embedding v (algebraMap _ K x)‖ < 1 ↔ x ∈ v.asIdeal := by rw [norm_embedding] exact v.adicAbv_coe_lt_one_iff (one_lt_absNorm_nnreal v) x -end FinitePlace +set_option backward.isDefEq.respectTransparency false in +lemma HeightOneSpectrum.embedding_mul_absNorm {x : R} (h_x_nezero : x ≠ 0) : + ‖embedding v (algebraMap _ K x)‖ * absNorm (v.maxPowDividing (span {x})) = 1 := by + rw [maxPowDividing, map_pow, Nat.cast_pow, norm_embedding, adicAbv_def, + WithZeroMulInt.toNNReal_neg_apply _ ((v.valuation K).ne_zero_iff.mpr + ((FaithfulSMul.algebraMap_eq_zero_iff R K).not.2 h_x_nezero))] + push_cast + rw [← zpow_natCast, ← zpow_add₀ <| mod_cast (zero_lt_one.trans (one_lt_absNorm_nnreal v)).ne'] + norm_cast + rw [zpow_eq_one_iff_right₀ (Nat.cast_nonneg' _) (mod_cast (one_lt_absNorm_nnreal v).ne')] + simp [valuation_of_algebraMap, intValuation_if_neg, h_x_nezero] + +end FiniteFree + +end AbsoluteValue + +open HeightOneSpectrum + +/-- A finite place of a number field `K` is a place associated to an embedding into a completion +with respect to a maximal ideal. -/ +def FinitePlace (K : Type*) [Field K] [NumberField K] := + {w : AbsoluteValue K ℝ // ∃ v : HeightOneSpectrum (𝓞 K), place (FinitePlace.embedding v) = w} + +/-- Return the finite place defined by a maximal ideal `v`. -/ +noncomputable def FinitePlace.mk [NumberField K] (v : HeightOneSpectrum (𝓞 K)) : FinitePlace K := + ⟨place (embedding v), ⟨v, rfl⟩⟩ + +/-- A predicate singling out finite places among the absolute values on a number field `K`. -/ +def IsFinitePlace [NumberField K] (w : AbsoluteValue K ℝ) : Prop := + ∃ v : IsDedekindDomain.HeightOneSpectrum (𝓞 K), place (FinitePlace.embedding v) = w + +lemma FinitePlace.isFinitePlace [NumberField K] (v : FinitePlace K) : IsFinitePlace v.val := by + simp [IsFinitePlace, v.prop] + +lemma isFinitePlace_iff [NumberField K] (v : AbsoluteValue K ℝ) : + IsFinitePlace v ↔ ∃ w : FinitePlace K, w.val = v := + ⟨fun H ↦ ⟨⟨v, H⟩, rfl⟩, fun ⟨w, hw⟩ ↦ hw ▸ w.isFinitePlace⟩ namespace FinitePlace +variable [NumberField K] + instance : FunLike (FinitePlace K) K ℝ where coe w x := w.1 x coe_injective' _ _ h := Subtype.ext (AbsoluteValue.ext <| congr_fun h) @@ -285,8 +339,8 @@ theorem mk_eq_iff {v₁ v₂ : HeightOneSpectrum (𝓞 K)} : mk v₁ = mk v₂ exact h <| HeightOneSpectrum.ext_iff.mpr <| IsMaximal.eq_of_le (isMaximal v₁) IsPrime.ne_top' H use x simp only [mk_apply] - rw [← norm_lt_one_iff_mem] at hx1 - rw [← norm_eq_one_iff_notMem] at hx2 + rw [← norm_lt_one_iff_mem K] at hx1 + rw [← norm_eq_one_iff_notMem K] at hx2 linarith theorem maximalIdeal_mk (v : HeightOneSpectrum (𝓞 K)) : maximalIdeal (mk v) = v := by @@ -310,7 +364,7 @@ lemma maximalIdeal_inj (w₁ w₂ : FinitePlace K) : maximalIdeal w₁ = maximal theorem hasFiniteMulSupport_int {x : 𝓞 K} (h_x_nezero : x ≠ 0) : (fun w : FinitePlace K ↦ w x).HasFiniteMulSupport := by have (w : FinitePlace K) : w x ≠ 1 ↔ w x < 1 := - ne_iff_lt_iff_le.mpr <| norm_embedding_eq w x ▸ norm_le_one w.maximalIdeal x + ne_iff_lt_iff_le.mpr <| norm_embedding_eq w x ▸ norm_le_one K w.maximalIdeal x simp_rw [Function.HasFiniteMulSupport, Function.mulSupport, this, ← norm_embedding_eq, norm_lt_one_iff_mem, ← Ideal.dvd_span_singleton] have h : {v : HeightOneSpectrum (𝓞 K) | v.asIdeal ∣ span {x}}.Finite := by @@ -326,7 +380,7 @@ theorem hasFiniteMulSupport_int {x : 𝓞 K} (h_x_nezero : x ≠ 0) : @[fun_prop] theorem hasFiniteMulSupport {x : K} (h_x_nezero : x ≠ 0) : (fun w : FinitePlace K ↦ w x).HasFiniteMulSupport := by - rcases IsFractionRing.div_surjective (A := 𝓞 K) x with ⟨a, b, hb, rfl⟩ + rcases IsFractionRing.div_surjective (𝓞 K) x with ⟨a, b, hb, rfl⟩ simp_all only [ne_eq, div_eq_zero_iff, FaithfulSMul.algebraMap_eq_zero_iff, not_or, map_div₀] obtain ⟨ha, hb⟩ := h_x_nezero simp_rw [← RingOfIntegers.coe_eq_algebraMap] @@ -338,47 +392,30 @@ protected lemma add_le (v : FinitePlace K) (x y : K) : v (x + y) ≤ max (v x) (v y) := by obtain ⟨w, hw⟩ := v.prop - have H x : v x = RingOfIntegers.HeightOneSpectrum.adicAbv w x := by + have H x : v x = NumberField.HeightOneSpectrum.adicAbv K w x := by rw [show v x = v.val x from rfl] grind only [place_apply, norm_embedding] - simpa only [H] using RingOfIntegers.HeightOneSpectrum.adicAbv_add_le_max w x y + simpa only [H] using adicAbv_add_le_max K w x y instance : NonarchimedeanHomClass (FinitePlace K) K ℝ where map_add_le_max v a b := FinitePlace.add_le v a b -end FinitePlace - -end NumberField - -namespace IsDedekindDomain.HeightOneSpectrum - -open NumberField.FinitePlace NumberField.RingOfIntegers - NumberField.RingOfIntegers.HeightOneSpectrum -open scoped NumberField - lemma equivHeightOneSpectrum_symm_apply (v : HeightOneSpectrum (𝓞 K)) (x : K) : (equivHeightOneSpectrum.symm v) x = ‖embedding v x‖ := rfl -set_option backward.isDefEq.respectTransparency false in -open Ideal in -lemma embedding_mul_absNorm (v : HeightOneSpectrum (𝓞 K)) {x : 𝓞 K} - (h_x_nezero : x ≠ 0) : ‖embedding v x‖ * absNorm (v.maxPowDividing (span {x})) = 1 := by - rw [maxPowDividing, map_pow, Nat.cast_pow, norm_embedding, adicAbv_def, - WithZeroMulInt.toNNReal_neg_apply _ - ((v.valuation K).ne_zero_iff.mpr (coe_ne_zero_iff.mpr h_x_nezero))] - push_cast - rw [← zpow_natCast, ← zpow_add₀ <| mod_cast (zero_lt_one.trans (one_lt_absNorm_nnreal v)).ne'] - norm_cast - rw [zpow_eq_one_iff_right₀ (Nat.cast_nonneg' _) (mod_cast (one_lt_absNorm_nnreal v).ne')] - simp [valuation_of_algebraMap, intValuation_if_neg, h_x_nezero] +@[deprecated (since := "2026-03-11")] +alias IsDedekindDomain.HeightOneSpectrum.equivHeightOneSpectrum_symm_apply := + equivHeightOneSpectrum_symm_apply +@[deprecated (since := "2026-03-11")] +alias IsDedekindDomain.HeightOneSpectrum.embedding_mul_absNorm := embedding_mul_absNorm -end IsDedekindDomain.HeightOneSpectrum +end FinitePlace section LiesOver -namespace NumberField.HeightOneSpectrum +namespace HeightOneSpectrum -variable {L : Type*} [Field L] [NumberField L] [Algebra K L] +variable {L : Type*} [NumberField K] [Field L] [NumberField L] [Algebra K L] variable (v : HeightOneSpectrum (𝓞 K)) (w : HeightOneSpectrum (𝓞 L)) variable [Algebra (v.adicCompletion K) (w.adicCompletion L)] [ContinuousSMul (v.adicCompletion K) (w.adicCompletion L)] @@ -399,6 +436,8 @@ instance : Module.Finite Kv Lw := rw [← Set.range_eq_univ, ← Φ.coe_range, ← Φ.range.closed_of_finiteDimensional.closure_eq] exact h_dense.closure_range) -end NumberField.HeightOneSpectrum +end HeightOneSpectrum end LiesOver + +end NumberField diff --git a/Mathlib/NumberTheory/NumberField/Cyclotomic/Basic.lean b/Mathlib/NumberTheory/NumberField/Cyclotomic/Basic.lean index 52a1f01515331f..d0144079a35962 100644 --- a/Mathlib/NumberTheory/NumberField/Cyclotomic/Basic.lean +++ b/Mathlib/NumberTheory/NumberField/Cyclotomic/Basic.lean @@ -74,7 +74,6 @@ theorem discr_prime_pow_eq_unit_mul_pow' [IsCyclotomicExtension {p ^ k} ℚ K] rw [hζ.discr_zeta_eq_discr_zeta_sub_one.symm] exact discr_prime_pow_eq_unit_mul_pow hζ (cyclotomic.irreducible_rat (NeZero.pos _)) -set_option backward.isDefEq.respectTransparency false in /-- If `K` is a `p ^ k`-th cyclotomic extension of `ℚ`, then `(adjoin ℤ {ζ})` is the integral closure of `ℤ` in `K`. -/ theorem isIntegralClosure_adjoin_singleton_of_prime_pow [hcycl : IsCyclotomicExtension {p ^ k} ℚ K] @@ -160,7 +159,6 @@ section CharZero variable [CharZero K] -set_option backward.isDefEq.respectTransparency false in /-- The algebra isomorphism `adjoin ℤ {ζ} ≃ₐ[ℤ] (𝓞 K)`, where `ζ` is a primitive `p ^ k`-th root of unity and `K` is a `p ^ k`-th cyclotomic extension of `ℚ`. -/ @[simps!] @@ -216,7 +214,6 @@ lemma toInteger_isPrimitiveRoot {k : ℕ} [NeZero k] (hζ : IsPrimitiveRoot ζ k variable [CharZero K] -set_option backward.isDefEq.respectTransparency false in @[simp] theorem integralPowerBasisOfPrimePow_gen [hcycl : IsCyclotomicExtension {p ^ k} ℚ K] (hζ : IsPrimitiveRoot ζ (p ^ k)) : @@ -840,7 +837,6 @@ namespace IsPrimitiveRoot variable [NeZero n] [CharZero K] -set_option backward.isDefEq.respectTransparency false in /-- The algebra isomorphism `adjoin ℤ {ζ} ≃ₐ[ℤ] (𝓞 K)`, where `ζ` is a primitive `n`-th root of unity and `K` is an `n`-th cyclotomic extension of `ℚ`. -/ @[simps!] @@ -865,7 +861,6 @@ noncomputable def integralPowerBasis [IsCyclotomicExtension {n} ℚ K] (hζ : IsPrimitiveRoot ζ n) : PowerBasis ℤ (𝓞 K) := (Algebra.adjoin.powerBasis' (hζ.isIntegral (NeZero.pos _))).map hζ.adjoinEquivRingOfIntegers -set_option backward.isDefEq.respectTransparency false in @[simp] theorem integralPowerBasis_gen [hcycl : IsCyclotomicExtension {n} ℚ K] (hζ : IsPrimitiveRoot ζ n) : hζ.integralPowerBasis.gen = hζ.toInteger := diff --git a/Mathlib/NumberTheory/NumberField/Ideal/Basic.lean b/Mathlib/NumberTheory/NumberField/Ideal/Basic.lean index a7ed3a42cc1806..164cd5ee234053 100644 --- a/Mathlib/NumberTheory/NumberField/Ideal/Basic.lean +++ b/Mathlib/NumberTheory/NumberField/Ideal/Basic.lean @@ -35,7 +35,6 @@ variable {K : Type*} [Field K] {I : Ideal (𝓞 K)} section torsionMapQuot -set_option backward.isDefEq.respectTransparency false in theorem IsPrimitiveRoot.not_coprime_norm_of_mk_eq_one [NumberField K] (hI : absNorm I ≠ 1) {n : ℕ} {ζ : K} (hn : 2 ≤ n) (hζ : IsPrimitiveRoot ζ n) (h : letI _ : NeZero n := NeZero.of_gt hn; Ideal.Quotient.mk I hζ.toInteger = 1) : diff --git a/Mathlib/NumberTheory/NumberField/InfinitePlace/TotallyRealComplex.lean b/Mathlib/NumberTheory/NumberField/InfinitePlace/TotallyRealComplex.lean index 84043b415dce7c..1ffcc713c6b731 100644 --- a/Mathlib/NumberTheory/NumberField/InfinitePlace/TotallyRealComplex.lean +++ b/Mathlib/NumberTheory/NumberField/InfinitePlace/TotallyRealComplex.lean @@ -78,7 +78,6 @@ theorem isTotallyReal_iff_ofRingEquiv (f : F ≃+* K) : IsTotallyReal F ↔ IsTo theorem isTotallyReal_top_iff : IsTotallyReal (⊤ : Subfield K) ↔ IsTotallyReal K := isTotallyReal_iff_ofRingEquiv Subfield.topEquiv -set_option backward.isDefEq.respectTransparency false in instance [IsTotallyReal K] [CharZero K] (F : IntermediateField ℚ K) [Algebra.IsAlgebraic F K] : IsTotallyReal F := IsTotallyReal.of_algebra F K diff --git a/Mathlib/NumberTheory/NumberField/Norm.lean b/Mathlib/NumberTheory/NumberField/Norm.lean index cab84ff940e977..2034567ef2873f 100644 --- a/Mathlib/NumberTheory/NumberField/Norm.lean +++ b/Mathlib/NumberTheory/NumberField/Norm.lean @@ -107,7 +107,6 @@ theorem norm_norm [Algebra F L] [FiniteDimensional F L] [IsScalarTower K F L] (x variable {F} -set_option backward.isDefEq.respectTransparency false in theorem isUnit_norm [CharZero K] {x : 𝓞 F} : IsUnit (norm K x) ↔ IsUnit x := by letI : Algebra K (AlgebraicClosure K) := AlgebraicClosure.instAlgebra K let L := normalClosure K F (AlgebraicClosure F) diff --git a/Mathlib/NumberTheory/NumberField/ProductFormula.lean b/Mathlib/NumberTheory/NumberField/ProductFormula.lean index 0205287bc1b15d..92c826af83ad03 100644 --- a/Mathlib/NumberTheory/NumberField/ProductFormula.lean +++ b/Mathlib/NumberTheory/NumberField/ProductFormula.lean @@ -70,7 +70,7 @@ theorem FinitePlace.prod_eq_inv_abs_norm_int {x : 𝓞 K} (h_x_nezero : x ≠ 0) ((Nat.castRingHom ℝ).toMonoidHom.comp absNorm.toMonoidHom).map_finprod_of_preimage_one (by simp) _ rw [h_prod, ← finprod_mul_distrib h_fin₁ h_fin₂] - exact finprod_eq_one_of_forall_eq_one fun v ↦ v.embedding_mul_absNorm h_x_nezero + exact finprod_eq_one_of_forall_eq_one fun v ↦ embedding_mul_absNorm _ v h_x_nezero set_option backward.isDefEq.respectTransparency false in /-- For any non-zero `x` in `K`, the product of `w x`, where `w` runs over `FinitePlace K`, is @@ -78,7 +78,7 @@ equal to the inverse of the absolute value of `Algebra.norm ℚ x`. -/ theorem FinitePlace.prod_eq_inv_abs_norm {x : K} (h_x_nezero : x ≠ 0) : ∏ᶠ w : FinitePlace K, w x = |(Algebra.norm ℚ) x|⁻¹ := by --reduce to 𝓞 K - rcases IsFractionRing.div_surjective (A := 𝓞 K) x with ⟨a, b, hb, rfl⟩ + rcases IsFractionRing.div_surjective (𝓞 K) x with ⟨a, b, hb, rfl⟩ apply nonZeroDivisors.ne_zero at hb have ha : a ≠ 0 := by rintro rfl diff --git a/Mathlib/NumberTheory/Ostrowski.lean b/Mathlib/NumberTheory/Ostrowski.lean index 58fb03fadf4262..83b4e5507d9bc0 100644 --- a/Mathlib/NumberTheory/Ostrowski.lean +++ b/Mathlib/NumberTheory/Ostrowski.lean @@ -327,7 +327,7 @@ lemma one_lt_of_not_bounded (notbdd : ¬ ∀ n : ℕ, f n ≤ 1) {n₀ : ℕ} (h _ = n₀ * (Nat.log n₀ m + 1) := by rw [List.mapIdx_eq_zipIdx_map, List.eq_replicate_of_mem (a := (n₀ : ℝ)) (l := L.zipIdx.map _), List.sum_replicate, List.length_map, List.length_zipIdx, nsmul_eq_mul, mul_comm, - Nat.digits_len n₀ m hn₀ (ne_zero_of_lt hm), Nat.cast_add_one] + Nat.length_digits n₀ m hn₀ (ne_zero_of_lt hm), Nat.cast_add_one] simp +contextual _ ≤ n₀ * (logb n₀ m + 1) := by gcongr; exact natLog_le_logb .. -- For h_ineq2 we need to exclude the case n = 0. @@ -379,7 +379,7 @@ private lemma param_upperbound {k : ℕ} (hk : k ≠ 0) : _ = m * ((Nat.digits m n).mapIdx fun i _ ↦ f m ^ i).sum := list_mul_sum (m.digits n) (f m) m _ = m * ((f m ^ (d + 1) - 1) / (f m - 1)) := by rw [list_geom _ (ne_of_gt (one_lt_of_not_bounded notbdd hm)), - ← Nat.digits_len m n hm (ne_zero_of_lt hn)] + ← Nat.length_digits m n hm (ne_zero_of_lt hn)] _ ≤ m * ((f m ^ (d + 1)) / (f m - 1)) := by gcongr · linarith only [one_lt_of_not_bounded notbdd hm] diff --git a/Mathlib/NumberTheory/Padics/PadicNumbers.lean b/Mathlib/NumberTheory/Padics/PadicNumbers.lean index 2d257a826cb013..b0c7dac294c66e 100644 --- a/Mathlib/NumberTheory/Padics/PadicNumbers.lean +++ b/Mathlib/NumberTheory/Padics/PadicNumbers.lean @@ -636,9 +636,10 @@ def padicNormE {p : ℕ} [hp : Fact p.Prime] : AbsoluteValue ℚ_[p] ℚ where trans max ((Quotient.lift PadicSeq.norm <| @PadicSeq.norm_equiv _ _) q) ((Quotient.lift PadicSeq.norm <| @PadicSeq.norm_equiv _ _) r) - · exact Quotient.inductionOn₂ q r <| PadicSeq.norm_nonarchimedean - refine max_le_add_of_nonneg (Quotient.inductionOn q <| PadicSeq.norm_nonneg) ?_ - exact Quotient.inductionOn r <| PadicSeq.norm_nonneg + · induction q, r using Quotient.inductionOn₂; apply PadicSeq.norm_nonarchimedean + · apply max_le_add_of_nonneg + · induction q using Quotient.inductionOn; apply PadicSeq.norm_nonneg + · induction r using Quotient.inductionOn; apply PadicSeq.norm_nonneg namespace padicNormE @@ -1083,7 +1084,8 @@ theorem valuation_zero : valuation (0 : ℚ_[p]) = 0 := dif_pos ((const_equiv p).2 rfl) theorem norm_eq_zpow_neg_valuation {x : ℚ_[p]} : x ≠ 0 → ‖x‖ = (p : ℝ) ^ (-x.valuation) := by - refine Quotient.inductionOn' x fun f hf => ?_ + induction x using Quotient.inductionOn with | _ f + intro hf change (PadicSeq.norm _ : ℝ) = (p : ℝ) ^ (-PadicSeq.valuation _) rw [PadicSeq.norm_eq_zpow_neg_valuation] · rw [Rat.cast_zpow, Rat.cast_natCast] diff --git a/Mathlib/NumberTheory/Padics/PadicVal/Defs.lean b/Mathlib/NumberTheory/Padics/PadicVal/Defs.lean index b453e6e1b67775..28c6213ed7eb0d 100644 --- a/Mathlib/NumberTheory/Padics/PadicVal/Defs.lean +++ b/Mathlib/NumberTheory/Padics/PadicVal/Defs.lean @@ -32,7 +32,6 @@ open Nat variable {p : ℕ} -set_option backward.isDefEq.respectTransparency false in theorem padicValNat_eq_emultiplicity_of_ne_one (hp : p ≠ 1) {n : ℕ} (hn : n ≠ 0) : padicValNat p n = emultiplicity p n := by rw [eq_comm, emultiplicity_eq_coe, pow_dvd_iff_le_padicValNat hp hn, diff --git a/Mathlib/NumberTheory/RamificationInertia/Basic.lean b/Mathlib/NumberTheory/RamificationInertia/Basic.lean index dddeaf499537f4..ff4e9afec2d984 100644 --- a/Mathlib/NumberTheory/RamificationInertia/Basic.lean +++ b/Mathlib/NumberTheory/RamificationInertia/Basic.lean @@ -697,12 +697,12 @@ noncomputable def quotientToQuotientRangePowQuotSucc S ⧸ P →ₗ[R ⧸ p] (P ^ i).map (Ideal.Quotient.mk (P ^ e)) ⧸ LinearMap.range (powQuotSuccInclusion p P i) where toFun := quotientToQuotientRangePowQuotSuccAux p P a_mem - map_add' := by - intro x y; refine Quotient.inductionOn' x fun x => Quotient.inductionOn' y fun y => ?_ + map_add' x y := by + induction x, y using Quotient.inductionOn₂' with | _ x y simp only [Submodule.Quotient.mk''_eq_mk, ← Submodule.Quotient.mk_add, quotientToQuotientRangePowQuotSuccAux_mk, mul_add, map_add, map_mul, AddMemClass.mk_add_mk] - map_smul' := by - intro x y; refine Quotient.inductionOn' x fun x => Quotient.inductionOn' y fun y => ?_ + map_smul' x y := by + induction x, y using Quotient.inductionOn₂' with | _ x y simp only [Submodule.Quotient.mk''_eq_mk, RingHom.id_apply, quotientToQuotientRangePowQuotSuccAux_mk] refine congr_arg Submodule.Quotient.mk ?_ diff --git a/Mathlib/NumberTheory/RamificationInertia/Galois.lean b/Mathlib/NumberTheory/RamificationInertia/Galois.lean index adb40e8e4640c2..9a7e4abe984244 100644 --- a/Mathlib/NumberTheory/RamificationInertia/Galois.lean +++ b/Mathlib/NumberTheory/RamificationInertia/Galois.lean @@ -361,7 +361,6 @@ variable (R K L S : Type*) [CommRing R] [CommRing S] [Algebra R S] [Field K] [Fi [Algebra K L] [Algebra R L] [IsScalarTower R S L] [IsScalarTower R K L] [IsIntegralClosure S R L] [FiniteDimensional K L] -set_option backward.isDefEq.respectTransparency false in lemma exists_comap_galRestrict_eq [IsDedekindDomain R] [IsGalois K L] {p : Ideal R} {P₁ P₂ : Ideal S} (hP₁ : P₁ ∈ primesOver p S) (hP₂ : P₂ ∈ primesOver p S) : ∃ σ, P₁.comap (galRestrict R K L S σ) = P₂ := by diff --git a/Mathlib/NumberTheory/RamificationInertia/HilbertTheory.lean b/Mathlib/NumberTheory/RamificationInertia/HilbertTheory.lean index 551d70b731b4a9..742d5304d6b27b 100644 --- a/Mathlib/NumberTheory/RamificationInertia/HilbertTheory.lean +++ b/Mathlib/NumberTheory/RamificationInertia/HilbertTheory.lean @@ -5,7 +5,8 @@ Authors: Xavier Roblot -/ module -public import Mathlib.FieldTheory.Galois.IsGaloisGroup +public import Mathlib.NumberTheory.RamificationInertia.Galois +public import Mathlib.RingTheory.Ideal.Quotient.HasFiniteQuotients /-! @@ -61,12 +62,10 @@ instance [MulSemiringAction Gal(L/K) B] [h : IsGaloisGroup (inertia Gal(L/K) P) variable [MulSemiringAction Gal(L/K) B] -set_option backward.isDefEq.respectTransparency false in instance [IsGalois K L] : IsDecompositionField K L P (FixedPoints.intermediateField (stabilizer Gal(L/K) P) : IntermediateField K L) where toIsGaloisGroup := IsGaloisGroup.subgroup Gal(L/K) K L (stabilizer Gal(L/K) P) -set_option backward.isDefEq.respectTransparency false in instance [IsGalois K L] : IsInertiaField K L P (FixedPoints.intermediateField (inertia Gal(L/K) P) : IntermediateField K L) where toIsGaloisGroup := IsGaloisGroup.subgroup Gal(L/K) K L (inertia Gal(L/K) P) @@ -78,23 +77,31 @@ section of_isGaloisGroup variable [Algebra B L] [IsFractionRing B L] [SMulDistribClass Gal(L/K) B L] [SMulDistribClass G B L] +/-- +If `G` is a Galois group for `L/K` and the stabilizer of `P` in `G` is a Galois group for +`L/D`, then `D` is a decomposition field for `P`. +-/ theorem IsDecompositionField.of_isGaloisGroup [h : IsGaloisGroup (stabilizer G P) D L] : IsDecompositionField K L P D := by refine (isDecompositionField_iff K L P D).mpr <| .of_mulEquiv (hG := h) ?_ fun _ x ↦ ?_ · refine (stabilizerEquiv _ (IsGaloisGroup.mulEquivAlgEquiv G K L) fun _ _ ↦ ?_).symm apply FaithfulSMul.algebraMap_injective B L simp [algebraMap.smul'] - · obtain ⟨y, z, _, rfl⟩ := IsFractionRing.div_surjective (A := B) x + · obtain ⟨y, z, _, rfl⟩ := IsFractionRing.div_surjective B x simp_rw [smul_div₀', subgroup_smul_def, ← algebraMap.smul', ← subgroup_smul_def, stabilizerEquiv_symm_apply_smul] -theorem IsInertiaField.of_isGaloisGroup [h : IsGaloisGroup (inertia G P) D L] : - IsInertiaField K L P D := by - refine (isInertiaField_iff K L P D).mpr <| .of_mulEquiv (hG := h) ?_ fun _ x ↦ ?_ +/-- +If `G` is a Galois group for `L/K` and the inertia group of `P` in `G` is a Galois group for +`L/E`, then `E` is an inertia field for `P`. +-/ +theorem IsInertiaField.of_isGaloisGroup [h : IsGaloisGroup (inertia G P) E L] : + IsInertiaField K L P E := by + refine (isInertiaField_iff K L P E).mpr <| .of_mulEquiv (hG := h) ?_ fun _ x ↦ ?_ · refine (inertiaEquiv _ (IsGaloisGroup.mulEquivAlgEquiv G K L) fun _ _ ↦ ?_).symm apply FaithfulSMul.algebraMap_injective B L simp [algebraMap.smul'] - · obtain ⟨y, z, _, rfl⟩ := IsFractionRing.div_surjective (A := B) x + · obtain ⟨y, z, _, rfl⟩ := IsFractionRing.div_surjective B x simp_rw [smul_div₀', subgroup_smul_def, ← algebraMap.smul', ← subgroup_smul_def, inertiaEquiv_symm_apply_smul] @@ -138,3 +145,81 @@ theorem IsInertiaField.algebraMap_ringEquiv_symm_apply [IsInertiaField K L P E] simp [IsInertiaField.ringEquiv, IsGaloisGroup.ringEquiv] end basic + +section rank + +attribute [local instance] Ideal.Quotient.field + +variable [FiniteDimensional K L] [MulSemiringAction Gal(L/K) B] + [IsGaloisGroup Gal(L/K) A B] [IsDedekindDomain A] [IsDedekindDomain B] [Module.Finite A B] + [Module.IsTorsionFree A B] [Ring.HasFiniteQuotients A] [P.IsMaximal] + +variable (D : Type*) [Field D] [Algebra D L] [IsDecompositionField K L P D] + +include K P + +/-- +The degree `[L : D]` of `L` over the decomposition field `D` equals the product of the +ramification index and the inertia degree of `p` in `B`. +-/ +theorem IsDecompositionField.rank_left (hp : p ≠ ⊥) : + Module.finrank D L = p.ramificationIdxIn B * p.inertiaDegIn B := by + have : p.IsMaximal := over_def P p ▸ Ideal.IsMaximal.under A P + have : Finite (A ⧸ p) := Ring.HasFiniteQuotients.finiteQuotient hp + rw [← IsGaloisGroup.card_eq_finrank (stabilizer Gal(L/K) P) D L, card_stabilizer_eq p hp] + +/-- +The degree `[D : K]` of the decomposition field `D` over `K` equals the number of prime ideals +of `B` lying over `p`. +-/ +theorem IsDecompositionField.rank_right [IsGalois K L] [Algebra K D] [IsScalarTower K D L] + (hp : p ≠ ⊥) : + Module.finrank K D = (p.primesOver B).ncard := by + have : p.IsMaximal := over_def P p ▸ Ideal.IsMaximal.under A P + have : FiniteDimensional D L := FiniteDimensional.right K D L + refine mul_left_injective₀ (b := Module.finrank D L) Module.finrank_pos.ne' ?_ + dsimp only + rw [Module.finrank_mul_finrank, rank_left A K L P D hp, + ncard_primesOver_mul_ramificationIdxIn_mul_inertiaDegIn hp B Gal(L/K), + IsGaloisGroup.card_eq_finrank Gal(L/K) K L] + +variable (E : Type*) [Field E] [Algebra E L] [IsInertiaField K L P E] + +/-- +The degree `[L : E]` of `L` over the inertia field `E` equals the ramification index of `p` in `B`. +-/ +theorem IsInertiaField.rank_left (hp : p ≠ ⊥) : + Module.finrank E L = p.ramificationIdxIn B := by + have : p.IsMaximal := over_def P p ▸ Ideal.IsMaximal.under A P + have : Finite (A ⧸ p) := Ring.HasFiniteQuotients.finiteQuotient hp + rw [← IsGaloisGroup.card_eq_finrank (inertia Gal(L/K) P) E L, + card_inertia_eq_ramificationIdxIn p hp] + +/-- +The degree `[E : K]` of the inertia field `E` over `K` equals the product of the number of +prime ideals of `B` lying over `p` and the inertia degree of `p` in `B`. +-/ +theorem IsInertiaField.rank_right [IsGalois K L] [Algebra K E] [IsScalarTower K E L] (hp : p ≠ ⊥) : + Module.finrank K E = (p.primesOver B).ncard * p.inertiaDegIn B := by + have : p.IsMaximal := over_def P p ▸ Ideal.IsMaximal.under A P + have : FiniteDimensional E L := FiniteDimensional.right K E L + refine mul_left_injective₀ (b := Module.finrank E L) Module.finrank_pos.ne' ?_ + dsimp only + rw [Module.finrank_mul_finrank, rank_left A K L P E hp, mul_assoc, mul_comm (p.inertiaDegIn B), + ncard_primesOver_mul_ramificationIdxIn_mul_inertiaDegIn hp B Gal(L/K), + IsGaloisGroup.card_eq_finrank Gal(L/K) K L] + +/-- +The degree `[E : D]` of the inertia field `E` over the decomposition field `D` equals the +inertia degree of `p` in `B`. +-/ +theorem IsInertiaField.rank_decompositionField [IsGalois K L] [Algebra K D] [Algebra K E] + [Algebra D E] [IsScalarTower K D E] [IsScalarTower K E L] [IsScalarTower K D L] (hp : p ≠ ⊥) : + Module.finrank D E = p.inertiaDegIn B := by + have : p.IsMaximal := over_def P p ▸ Ideal.IsMaximal.under A P + have := Module.finrank_mul_finrank K D E + rwa [IsInertiaField.rank_right A K L P E hp, IsDecompositionField.rank_right A K L P D hp, + mul_right_inj'] at this + exact primesOver_ncard_ne_zero p B + +end rank diff --git a/Mathlib/NumberTheory/RatFunc/Ostrowski.lean b/Mathlib/NumberTheory/RatFunc/Ostrowski.lean new file mode 100644 index 00000000000000..0a3050efe7e8d4 --- /dev/null +++ b/Mathlib/NumberTheory/RatFunc/Ostrowski.lean @@ -0,0 +1,285 @@ +/- +Copyright (c) 2025 María Inés de Frutos-Fernández & Xavier Généreux. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: María Inés de Frutos-Fernández, Xavier Généreux +-/ +module + +public import Mathlib.FieldTheory.Finite.Valuation +public import Mathlib.NumberTheory.FunctionField +public import Mathlib.RingTheory.Valuation.Discrete.Basic + +/-! +# Ostrowski's theorem for `K(X)` + +This file proves Ostrowski's theorem for the field of rational functions `K(X)`, where `K` is any +field: if `v` is a discrete valuation on `K(X)` which is trivial on elements of `K`, then `v` is +equivalent to either the `I`-adic valuation for some `I : HeightOneSpectrum K[X]`, or to the +valuation at infinity `FunctionField.inftyValuation K`. + +## Main results +- `RatFunc.valuation_isEquiv_infty_or_adic`: Ostrowski's theorem for `K(X)`. +-/ + +@[expose] public noncomputable section + + +open Multiplicative WithZero + +variable {K Γ : Type*} [Field K] [LinearOrderedCommGroupWithZero Γ] {v : Valuation (RatFunc K) Γ} + +namespace RatFunc + +section Infinity + +open FunctionField Polynomial Valuation + +lemma valuation_eq_valuation_X_zpow_intDegree_of_one_lt_valuation_X {f : RatFunc K} + [v.IsTrivialOn K] (hlt : 1 < v X) (hf : f ≠ 0) : v f = v RatFunc.X ^ f.intDegree := by + induction f using RatFunc.induction_on with + | f p q hq => + rw [intDegree_div (by grind only) (by grind only), v.map_div, zpow_sub₀ (ne_zero_of_lt hlt)] + simp_rw [intDegree_polynomial, zpow_natCast, ← coePolynomial_eq_algebraMap] + have hp : p ≠ 0 := by contrapose! hf; simp [hf] + rw [valuation_eq_valuation_X_pow_natDegree_of_one_lt_valuation_X _ hlt hp, + valuation_eq_valuation_X_pow_natDegree_of_one_lt_valuation_X _ hlt hq] + +variable [DecidableEq (RatFunc K)] + +lemma valuation_isEquiv_inftyValuation_of_one_lt_valuation_X [v.IsTrivialOn K] (hlt : 1 < v X) : + v.IsEquiv (inftyValuation K) := by + refine isEquiv_iff_val_lt_one.mpr fun {f} ↦ ?_ + rcases eq_or_ne f 0 with rfl | hf + · simp + · have hlt' : 1 < inftyValuation K X := by simp [← exp_zero] + rw [valuation_eq_valuation_X_zpow_intDegree_of_one_lt_valuation_X hlt hf, + valuation_eq_valuation_X_zpow_intDegree_of_one_lt_valuation_X hlt' hf] + grind [one_le_zpow_iff_right₀] + +end Infinity + +open IsDedekindDomain HeightOneSpectrum Set Valuation FunctionField Polynomial + +lemma setOf_polynomial_valuation_lt_one_and_ne_zero_nonempty [v.IsNontrivial] [v.IsTrivialOn K] + (hle : v RatFunc.X ≤ 1) : {p : K[X] | v p < 1 ∧ p ≠ 0}.Nonempty := by + obtain ⟨w , h0, h1⟩ := IsNontrivial.exists_lt_one (v := v) + induction w using RatFunc.induction_on with + | f p q => + simp only [ne_eq, _root_.div_eq_zero_iff, FaithfulSMul.algebraMap_eq_zero_iff, not_or, + map_div₀] at * + have hor : ¬v ↑p = 1 ∨ ¬v ↑q = 1 := by rw [← not_and_or]; aesop + suffices ∀ r : K[X], v (↑r) ≠ 1 → r ≠ 0 → {p : K[X] | v ↑p < 1 ∧ ¬p = 0}.Nonempty by + exact Or.elim hor (fun hp ↦ this p hp h0.1) (fun hq ↦ this q hq h0.2) + exact fun r hr hr0 ↦ ⟨r, lt_iff_le_and_ne.mpr + ⟨Polynomial.valuation_le_one_of_valuation_X_le_one _ hle r, hr⟩, hr0⟩ + +private lemma one_le_valuation_factor (hne : {p : K[X] | v p < 1 ∧ p ≠ 0}.Nonempty) {a b : K[X]} + (hab : v ↑(a * b) < 1 ∧ a ≠ 0 ∧ b ≠ 0) (hπᵥ : degree_lt_wf.min _ hne = a * b) + (hb : ¬IsUnit b) : 1 ≤ v ↑a := by + set πᵥ := degree_lt_wf.min _ hne + have hda : a.degree < πᵥ.degree := by + have hbpos := degree_pos_of_ne_zero_of_nonunit hab.2.2 hb + simp_rw [hπᵥ, degree_mul, degree_eq_natDegree hab.2.1, degree_eq_natDegree hab.2.2] at hbpos ⊢ + norm_cast + simpa using hbpos + have hlea := imp_not_comm.mp (degree_lt_wf.not_lt_min _) hda + grind + +lemma irreducible_min_polynomial_valuation_lt_one_and_ne_zero [v.IsTrivialOn K] + (hne : {p : K[X] | v p < 1 ∧ p ≠ 0}.Nonempty) : + Irreducible (degree_lt_wf.min {p : K[X] | v p < 1 ∧ p ≠ 0} hne) := by + set πᵥ := degree_lt_wf.min _ hne + have hπᵥ : v πᵥ < 1 ∧ πᵥ ≠ 0 := degree_lt_wf.min_mem _ hne + refine irreducible_iff.mpr ⟨?_, fun a b hab ↦ ?_⟩ + · simp only [Polynomial.isUnit_iff, isUnit_iff_ne_zero] + intro ⟨a, ha0, ha⟩ + rw [← ha, coePolynomial, algebraMap_C, ← algebraMap_eq_C] at hπᵥ + grind + · by_contra! H + simp only [hab, ne_eq, mul_eq_zero, not_or] at hπᵥ + have hva := one_le_valuation_factor hne hπᵥ hab H.2 + simp only [mul_comm a b, @and_comm (¬a = 0)] at hπᵥ hab + have := Right.one_le_mul (one_le_valuation_factor hne hπᵥ hab H.1) hva + simp only [coePolynomial_eq_algebraMap, map_mul] at hπᵥ this + grind + +section valuation_X_le_one + +variable [v.IsNontrivial] [v.IsTrivialOn K] (hle : v RatFunc.X ≤ 1) + +/-- A uniformizing element for the valuation `v`, as a polynomial in `K[X]`. -/ +abbrev uniformizingPolynomial : K[X] := + WellFounded.min degree_lt_wf _ (setOf_polynomial_valuation_lt_one_and_ne_zero_nonempty hle) + +@[inherit_doc] +local notation "πᵥ" => uniformizingPolynomial hle + +lemma uniformizingPolynomial_ne_zero : πᵥ ≠ 0 := by + have := degree_lt_wf.min_mem _ (setOf_polynomial_valuation_lt_one_and_ne_zero_nonempty hle) + simp_all [uniformizingPolynomial] + +lemma valuation_uniformizingPolynomial_lt_one : v πᵥ < 1 := by + simpa using (degree_lt_wf.min_mem _ + (setOf_polynomial_valuation_lt_one_and_ne_zero_nonempty hle)).1 + +open Ideal in +/-- The maximal ideal of `K[X]` generated by the `uniformizingPolynomial` for `v`. -/ +def valuationIdeal : HeightOneSpectrum K[X] where + asIdeal := Submodule.span K[X] {πᵥ} + isPrime := IsMaximal.isPrime (PrincipalIdealRing.isMaximal_of_irreducible + (irreducible_min_polynomial_valuation_lt_one_and_ne_zero + (setOf_polynomial_valuation_lt_one_and_ne_zero_nonempty hle))) + ne_bot := by simpa using uniformizingPolynomial_ne_zero hle + +@[inherit_doc] +local notation "Pᵥ" => RatFunc.valuationIdeal hle + +section Associates + +open EuclideanDomain in +lemma valuation_eq_valuation_uniformizingPolynomial_pow_of_valuation_X_le_one {p : K[X]} + (hp : p ≠ 0) : + v (algebraMap K[X] (RatFunc K) p) = v (πᵥ ^ ((Associates.mk (Pᵥ).asIdeal).count + (Associates.mk (Ideal.span {p})).factors)) := by + set π := πᵥ + have hne := setOf_polynomial_valuation_lt_one_and_ne_zero_nonempty hle + have hπirr : Irreducible π := irreducible_min_polynomial_valuation_lt_one_and_ne_zero hne + obtain ⟨k, q, hnq, heq⟩ := WfDvdMonoid.max_power_factor hp hπirr + have hπ : π ∈ _ := degree_lt_wf.min_mem _ hne + simp only [ne_eq, mem_setOf] at hπ + nth_rw 1 [heq] + simp only [map_mul, map_pow] + suffices v (algebraMap K[X] (RatFunc K) q) = 1 by + simp only [this, mul_one] + congr + exact (Ideal.count_associates_eq (irreducible_iff_prime.mp hπirr) hnq heq).symm + rw [← mod_add_div q π, map_add] + rw [← mod_eq_zero] at hnq + suffices v (algebraMap K[X] (RatFunc K) (q % π)) = 1 ∧ + v (algebraMap K[X] (RatFunc K) (π * (q / π))) < 1 by + obtain ⟨h₁, h₂⟩ := this + rw [← h₁] at h₂ ⊢ + exact Valuation.map_add_eq_of_lt_left _ h₂ + constructor + · rw [← coePolynomial_eq_algebraMap] + have hnπ : q % π ∉ {p : K[X] | v ↑p < 1 ∧ p ≠ 0} := + imp_not_comm.mp (degree_lt_wf.not_lt_min _) (EuclideanDomain.remainder_lt q hπ.2) + have := Polynomial.valuation_le_one_of_valuation_X_le_one _ hle (q % π) + grind + · simpa only [map_mul, ← coePolynomial_eq_algebraMap] + using mul_lt_one_of_lt_of_le hπ.1 <| (q / π).valuation_le_one_of_valuation_X_le_one _ hle + +lemma exists_zpow_uniformizingPolynomial {f : RatFunc K} (hf : f ≠ 0) : + ∃ (z : ℤ), v f = v πᵥ ^ z:= by + have h0 : v πᵥ ≠ 0 := by simpa using uniformizingPolynomial_ne_zero hle + induction f using RatFunc.induction_on with + | f p q hq => + use (Associates.mk (Pᵥ).asIdeal).count (Associates.mk (Ideal.span {p})).factors - + (Associates.mk (Pᵥ).asIdeal).count (Associates.mk (Ideal.span {q})).factors + simp only [map_div₀, map_pow, zpow_sub₀ h0, zpow_natCast, + valuation_eq_valuation_uniformizingPolynomial_pow_of_valuation_X_le_one hle hq, + valuation_eq_valuation_uniformizingPolynomial_pow_of_valuation_X_le_one hle + (p := p) (by aesop)] + +set_option backward.isDefEq.respectTransparency false in +lemma uniformizingPolynomial_isUniformizer [hv : IsRankOneDiscrete v] : + v.IsUniformizer πᵥ := by + have h0 : v πᵥ ≠ 0 := by simpa using uniformizingPolynomial_ne_zero hle + rw [IsUniformizer, ← hv.valueGroup_genLTOne_eq_generator, ← h0.isUnit.unit_spec, Units.val_inj] + apply LinearOrderedCommGroup.Subgroup.genLTOne_unique + · rw [← Units.val_lt_val, h0.isUnit.unit_spec, Units.val_one] + exact valuation_uniformizingPolynomial_lt_one hle + · ext γ + simp only [coePolynomial_eq_algebraMap, MonoidWithZeroHom.mem_valueGroup_iff_of_comm, ne_eq, + map_eq_zero, Subgroup.mem_zpowers_iff] + refine ⟨fun ⟨k, hk⟩ ↦ ?_, fun ⟨a, ha, b, hab⟩ ↦ ?_⟩ + · use 1, one_ne_zero, πᵥ ^ k + simp only [← Units.val_inj, Units.val_zpow_eq_zpow_val, h0.isUnit.unit_spec] at hk + simp [← hk] + · obtain ⟨ka, hka⟩ := exists_zpow_uniformizingPolynomial hle ha + obtain ⟨kb, hkb⟩ := exists_zpow_uniformizingPolynomial hle (f := b) (by aesop) + rw [hka, hkb] at hab + use kb - ka + have : v ↑πᵥ ^ ka ≠ 0 := zpow_ne_zero _ h0 + simp only [zpow_sub, ← Units.val_inj, Units.val_mul, Units.val_zpow_eq_zpow_val, + h0.isUnit.unit_spec, Units.val_inv_eq_inv_val, ← hab, field] + +lemma valuation_isEquiv_valuationIdeal_adic_of_valuation_X_le_one [IsRankOneDiscrete v] : + v.IsEquiv ((Pᵥ).valuation (RatFunc K)) := by + rw [isEquiv_iff_val_le_one] + intro f + rcases eq_or_ne f 0 with rfl | hf0 + · simp + · induction f using RatFunc.induction_on with + | f p q hq0 => + have hp0 : p ≠ 0 := by simp_all + set pi := πᵥ with hpi_def + have hpi : v.IsUniformizer (pi : RatFunc K) := uniformizingPolynomial_isUniformizer hle + simp only [map_div₀, valuation_of_algebraMap, intValuation_def, exp_neg, if_neg hp0, + if_neg hq0, div_inv_eq_mul] + rw [valuation_eq_valuation_uniformizingPolynomial_pow_of_valuation_X_le_one hle hp0, + valuation_eq_valuation_uniformizingPolynomial_pow_of_valuation_X_le_one hle hq0] + simp_all [div_le_one₀, inv_mul_le_one₀, + (pow_le_pow_iff_right_of_lt_one₀ (by simp_all) (IsRankOneDiscrete.generator_lt_one v))] + +end Associates + +end valuation_X_le_one + +lemma adicValuation_not_isEquiv_infty_valuation [DecidableEq (RatFunc K)] + (p : IsDedekindDomain.HeightOneSpectrum K[X]) : + ¬ (p.valuation (RatFunc K)).IsEquiv (inftyValuation K) := by + simp only [isEquiv_iff_val_le_one] + push Not + refine ⟨X, .inl ⟨p.valuation_le_one _, ?_⟩⟩ + rw [inftyValuation.X, ← log_lt_iff_lt_exp one_ne_zero, log_one] + exact zero_lt_one + +lemma adicValuation_ne_inftyValuation [DecidableEq (RatFunc K)] + (p : IsDedekindDomain.HeightOneSpectrum K[X]) : + p.valuation (RatFunc K) ≠ inftyValuation K := by + by_contra h + exact absurd Valuation.IsEquiv.refl (h ▸ adicValuation_not_isEquiv_infty_valuation p) + +section Discrete + +variable [IsRankOneDiscrete v] + +section IsTrivialOn + +variable [v.IsTrivialOn K] + +lemma valuation_isEquiv_adic_of_valuation_X_le_one (hle : v X ≤ 1) : + ∃ (u : HeightOneSpectrum K[X]), v.IsEquiv (u.valuation _) := + ⟨_, valuation_isEquiv_valuationIdeal_adic_of_valuation_X_le_one hle⟩ + +/-- **Ostrowski's Theorem** for `K(X)` with `K` any field: +A discrete valuation of rank 1 that is trivial on `K` is equivalent either to the valuation +at infinity or to the `p`-adic valuation for a unique maximal ideal `p` of `K[X]`. -/ +theorem valuation_isEquiv_infty_or_adic [DecidableEq (RatFunc K)] : + Xor' (v.IsEquiv (FunctionField.inftyValuation K)) + (∃! (u : HeightOneSpectrum K[X]), v.IsEquiv (u.valuation _)) := by + rcases lt_or_ge 1 (v X) with hlt | hge + /- Infinity case -/ + · have hv := valuation_isEquiv_inftyValuation_of_one_lt_valuation_X hlt + refine .inl ⟨hv, ?_⟩ + simp only [ExistsUnique, not_exists, not_and, not_forall] + intro pw hw + exact absurd (hw.symm.trans hv) (adicValuation_not_isEquiv_infty_valuation pw) + /- Prime case -/ + · obtain ⟨pw, hw⟩ := valuation_isEquiv_adic_of_valuation_X_le_one hge + exact .inr ⟨⟨pw, hw, fun pw' hw' ↦ eq_of_valuation_isEquiv_valuation (hw'.symm.trans hw)⟩, + fun hv ↦ absurd (hw.symm.trans hv) (adicValuation_not_isEquiv_infty_valuation pw)⟩ + +lemma valuation_isEquiv_adic_of_not_isEquiv_infty [DecidableEq (RatFunc K)] + (hni : ¬ v.IsEquiv (FunctionField.inftyValuation K)) : + ∃! (u : HeightOneSpectrum K[X]), v.IsEquiv (u.valuation _) := + valuation_isEquiv_infty_or_adic.or.resolve_left hni + +end IsTrivialOn + +end Discrete + +end RatFunc + +end diff --git a/Mathlib/Order/Category/PartOrd.lean b/Mathlib/Order/Category/PartOrd.lean index 3fbb07691f35ff..bdd52f5619ebe9 100644 --- a/Mathlib/Order/Category/PartOrd.lean +++ b/Mathlib/Order/Category/PartOrd.lean @@ -178,10 +178,12 @@ def preordToPartOrd : Preord.{u} ⥤ PartOrd where map f := PartOrd.ofHom f.hom.antisymmetrization map_id X := by ext x - exact Quotient.inductionOn' x fun x => Quotient.map'_mk'' _ (fun a b => id) _ + induction x using Quotient.inductionOn' + exact Quotient.map'_mk'' _ (fun a b ↦ id) _ map_comp f g := by ext x - exact Quotient.inductionOn' x fun x => OrderHom.antisymmetrization_apply_mk _ _ + induction x using Quotient.inductionOn' + exact OrderHom.antisymmetrization_apply_mk .. /-- `preordToPartOrd` is left adjoint to the forgetful functor, meaning it is the free functor from `Preord` to `PartOrd`. -/ diff --git a/Mathlib/Order/Cofinal.lean b/Mathlib/Order/Cofinal.lean index 72285133c9c932..3e87c8b846c0a9 100644 --- a/Mathlib/Order/Cofinal.lean +++ b/Mathlib/Order/Cofinal.lean @@ -52,7 +52,7 @@ theorem IsCofinal.mono {s t : Set α} (h : s ⊆ t) (hs : IsCofinal s) : IsCofin end LE section Preorder -variable [Preorder α] +variable [Preorder α] [Preorder β] theorem IsCofinal.univ : IsCofinal (@Set.univ α) := fun a ↦ ⟨a, ⟨⟩, le_rfl⟩ @@ -60,23 +60,34 @@ theorem IsCofinal.univ : IsCofinal (@Set.univ α) := instance : Inhabited {s : Set α // IsCofinal s} := ⟨_, .univ⟩ +theorem IsCofinal.image {f : α → β} {s : Set α} (hs : IsCofinal s) + (hf : Monotone f) (hf' : IsCofinal (.range f)) : IsCofinal (f '' s) := by + intro a + obtain ⟨_, ⟨b, rfl⟩, hb⟩ := hf' a + obtain ⟨c, hc, hc'⟩ := hs b + exact ⟨_, Set.mem_image_of_mem f hc, hb.trans (hf hc')⟩ + /-- A cofinal subset of a cofinal subset is cofinal. -/ theorem IsCofinal.trans {s : Set α} {t : Set s} (hs : IsCofinal s) (ht : IsCofinal t) : - IsCofinal (Subtype.val '' t) := by - intro a - obtain ⟨b, hb, hb'⟩ := hs a - obtain ⟨c, hc, hc'⟩ := ht ⟨b, hb⟩ - exact ⟨c, Set.mem_image_of_mem _ hc, hb'.trans hc'⟩ + IsCofinal (Subtype.val '' t) := + ht.image (Subtype.mono_coe _) (by simpa) -theorem GaloisConnection.map_cofinal [Preorder β] {f : β → α} {g : α → β} - (h : GaloisConnection f g) {s : Set α} (hs : IsCofinal s) : IsCofinal (g '' s) := by - intro a - obtain ⟨b, hb, hb'⟩ := hs (f a) - exact ⟨g b, Set.mem_image_of_mem _ hb, h.le_iff_le.1 hb'⟩ +theorem GaloisConnection.isCofinal_range {f : β → α} {g : α → β} (h : GaloisConnection f g) : + IsCofinal (.range g) := + fun a ↦ ⟨_, Set.mem_range_self _, le_u_l h a⟩ + +theorem GaloisConnection.map_isCofinal {f : β → α} {g : α → β} + (h : GaloisConnection f g) {s : Set α} (hs : IsCofinal s) : IsCofinal (g '' s) := + hs.image h.monotone_u h.isCofinal_range + +@[deprecated (since := "2026-03-15")] +alias GaloisConnection.map_cofinal := GaloisConnection.map_isCofinal + +theorem OrderIso.map_isCofinal (e : α ≃o β) {s : Set α} (hs : IsCofinal s) : IsCofinal (e '' s) := + e.symm.to_galoisConnection.map_isCofinal hs -theorem OrderIso.map_cofinal [Preorder β] (e : α ≃o β) {s : Set α} (hs : IsCofinal s) : - IsCofinal (e '' s) := - e.symm.to_galoisConnection.map_cofinal hs +@[deprecated (since := "2026-03-15")] +alias OrderIso.map_cofinal := OrderIso.map_isCofinal end Preorder diff --git a/Mathlib/Order/CompleteLattice/Basic.lean b/Mathlib/Order/CompleteLattice/Basic.lean index fe3fabeed110ff..27d2f682b3e2e5 100644 --- a/Mathlib/Order/CompleteLattice/Basic.lean +++ b/Mathlib/Order/CompleteLattice/Basic.lean @@ -42,40 +42,24 @@ open Function OrderDual Set variable {α β γ : Type*} {ι ι' : Sort*} {κ : ι → Sort*} {κ' : ι' → Sort*} -@[simp] lemma iSup_ulift {ι : Type*} [SupSet α] (f : ULift ι → α) : +@[to_dual (attr := simp)] lemma iSup_ulift {ι : Type*} [SupSet α] (f : ULift ι → α) : ⨆ i : ULift ι, f i = ⨆ i, f (.up i) := by simp only [iSup]; congr with x; simp -@[simp] lemma iInf_ulift {ι : Type*} [InfSet α] (f : ULift ι → α) : - ⨅ i : ULift ι, f i = ⨅ i, f (.up i) := by simp only [iInf]; congr with x; simp - section variable [CompleteSemilatticeSup α] {s t : Set α} {a b : α} +@[to_dual] theorem sSup_le_sSup_of_isCofinalFor (h : IsCofinalFor s t) : sSup s ≤ sSup t := IsLeast.mono (isLUB_sSup t) (isLUB_sSup s) <| upperBounds_mono_of_isCofinalFor h -- We will generalize this to conditionally complete lattices in `csSup_singleton`. -@[simp] +@[to_dual (attr := simp)] theorem sSup_singleton {a : α} : sSup {a} = a := isLUB_singleton.sSup_eq end -section - -variable [CompleteSemilatticeInf α] {s t : Set α} {a b : α} - -theorem sInf_le_sInf_of_isCoinitialFor (h : IsCoinitialFor s t) : sInf t ≤ sInf s := - IsGreatest.mono (isGLB_sInf t) (isGLB_sInf s) <| lowerBounds_mono_of_isCoinitialFor h - --- We will generalize this to conditionally complete lattices in `csInf_singleton`. -@[simp] -theorem sInf_singleton {a : α} : sInf {a} = a := - isGLB_singleton.sInf_eq - -end - open OrderDual section @@ -85,103 +69,71 @@ variable [CompleteLattice α] {s t : Set α} {b : α} theorem sInf_le_sSup (hs : s.Nonempty) : sInf s ≤ sSup s := isGLB_le_isLUB (isGLB_sInf s) (isLUB_sSup s) hs +@[to_dual] theorem sSup_union {s t : Set α} : sSup (s ∪ t) = sSup s ⊔ sSup t := ((isLUB_sSup s).union (isLUB_sSup t)).sSup_eq -theorem sInf_union {s t : Set α} : sInf (s ∪ t) = sInf s ⊓ sInf t := - ((isGLB_sInf s).union (isGLB_sInf t)).sInf_eq - +@[to_dual le_sInf_inter] theorem sSup_inter_le {s t : Set α} : sSup (s ∩ t) ≤ sSup s ⊓ sSup t := sSup_le fun _ hb => le_inf (le_sSup hb.1) (le_sSup hb.2) -theorem le_sInf_inter {s t : Set α} : sInf s ⊔ sInf t ≤ sInf (s ∩ t) := - @sSup_inter_le αᵒᵈ _ _ _ - -@[simp] +@[to_dual (attr := simp)] theorem sSup_empty : sSup ∅ = (⊥ : α) := (@isLUB_empty α _ _).sSup_eq -@[simp] -theorem sInf_empty : sInf ∅ = (⊤ : α) := - (@isGLB_empty α _ _).sInf_eq - -@[simp] +@[to_dual (attr := simp)] theorem sSup_univ : sSup univ = (⊤ : α) := (@isLUB_univ α _ _).sSup_eq -@[simp] -theorem sInf_univ : sInf univ = (⊥ : α) := - (@isGLB_univ α _ _).sInf_eq - -- TODO(Jeremy): get this automatically -@[simp] +@[to_dual (attr := simp)] theorem sSup_insert {a : α} {s : Set α} : sSup (insert a s) = a ⊔ sSup s := ((isLUB_sSup s).insert a).sSup_eq -@[simp] -theorem sInf_insert {a : α} {s : Set α} : sInf (insert a s) = a ⊓ sInf s := - ((isGLB_sInf s).insert a).sInf_eq - +@[to_dual] theorem sSup_le_sSup_of_subset_insert_bot (h : s ⊆ insert ⊥ t) : sSup s ≤ sSup t := (sSup_le_sSup h).trans_eq (sSup_insert.trans (bot_sup_eq _)) -theorem sInf_le_sInf_of_subset_insert_top (h : s ⊆ insert ⊤ t) : sInf t ≤ sInf s := - (sInf_le_sInf h).trans_eq' (sInf_insert.trans (top_inf_eq _)) - -@[simp] +@[to_dual (attr := simp)] theorem sSup_diff_singleton_bot (s : Set α) : sSup (s \ {⊥}) = sSup s := (sSup_le_sSup diff_subset).antisymm <| sSup_le_sSup_of_subset_insert_bot <| subset_insert_diff_singleton _ _ -@[simp] -theorem sInf_diff_singleton_top (s : Set α) : sInf (s \ {⊤}) = sInf s := - @sSup_diff_singleton_bot αᵒᵈ _ s - +@[to_dual] theorem sSup_pair {a b : α} : sSup {a, b} = a ⊔ b := (@isLUB_pair α _ a b).sSup_eq -theorem sInf_pair {a b : α} : sInf {a, b} = a ⊓ b := - (@isGLB_pair α _ a b).sInf_eq - -@[simp] +@[to_dual (attr := simp)] theorem sSup_eq_bot : sSup s = ⊥ ↔ ∀ a ∈ s, a = ⊥ := ⟨fun h _ ha => bot_unique <| h ▸ le_sSup ha, fun h => bot_unique <| sSup_le fun a ha => le_bot_iff.2 <| h a ha⟩ -@[simp] -theorem sInf_eq_top : sInf s = ⊤ ↔ ∀ a ∈ s, a = ⊤ := - @sSup_eq_bot αᵒᵈ _ _ - +@[to_dual] lemma sSup_eq_bot' {s : Set α} : sSup s = ⊥ ↔ s = ∅ ∨ s = {⊥} := by rw [sSup_eq_bot, ← subset_singleton_iff_eq, subset_singleton_iff] +@[to_dual] theorem eq_singleton_bot_of_sSup_eq_bot_of_nonempty {s : Set α} (h_sup : sSup s = ⊥) (hne : s.Nonempty) : s = {⊥} := by rw [Set.eq_singleton_iff_nonempty_unique_mem] rw [sSup_eq_bot] at h_sup exact ⟨hne, h_sup⟩ -theorem eq_singleton_top_of_sInf_eq_top_of_nonempty : sInf s = ⊤ → s.Nonempty → s = {⊤} := - @eq_singleton_bot_of_sSup_eq_bot_of_nonempty αᵒᵈ _ _ - /-- Introduction rule to prove that `b` is the supremum of `s`: it suffices to check that `b` is larger than all elements of `s`, and that this is not the case of any `w < b`. See `csSup_eq_of_forall_le_of_forall_lt_exists_gt` for a version in conditionally complete lattices. -/ +@[to_dual sInf_eq_of_forall_ge_of_forall_gt_exists_lt +/-- Introduction rule to prove that `b` is the infimum of `s`: it suffices to check that `b` +is smaller than all elements of `s`, and that this is not the case of any `w > b`. +See `csInf_eq_of_forall_ge_of_forall_gt_exists_lt` for a version in conditionally complete +lattices. -/] theorem sSup_eq_of_forall_le_of_forall_lt_exists_gt (h₁ : ∀ a ∈ s, a ≤ b) (h₂ : ∀ w, w < b → ∃ a ∈ s, w < a) : sSup s = b := (sSup_le h₁).eq_of_not_lt fun h => let ⟨_, ha, ha'⟩ := h₂ _ h ((le_sSup ha).trans_lt ha').false -/-- Introduction rule to prove that `b` is the infimum of `s`: it suffices to check that `b` -is smaller than all elements of `s`, and that this is not the case of any `w > b`. -See `csInf_eq_of_forall_ge_of_forall_gt_exists_lt` for a version in conditionally complete -lattices. -/ -theorem sInf_eq_of_forall_ge_of_forall_gt_exists_lt : - (∀ a ∈ s, b ≤ a) → (∀ w, b < w → ∃ a ∈ s, a < w) → sInf s = b := - @sSup_eq_of_forall_le_of_forall_lt_exists_gt αᵒᵈ _ _ _ - end /- @@ -191,37 +143,46 @@ section SupSet variable [SupSet α] {f g : ι → α} +@[to_dual] theorem sSup_range : sSup (range f) = iSup f := rfl +@[to_dual] theorem sSup_eq_iSup' (s : Set α) : sSup s = ⨆ a : s, (a : α) := by rw [iSup, Subtype.range_coe] +@[to_dual] theorem iSup_congr (h : ∀ i, f i = g i) : ⨆ i, f i = ⨆ i, g i := congr_arg _ <| funext h +@[to_dual] theorem biSup_congr {p : ι → Prop} (h : ∀ i, p i → f i = g i) : ⨆ (i) (_ : p i), f i = ⨆ (i) (_ : p i), g i := iSup_congr fun i ↦ iSup_congr (h i) +@[to_dual] theorem biSup_congr' {p : ι → Prop} {f g : (i : ι) → p i → α} (h : ∀ i (hi : p i), f i hi = g i hi) : ⨆ i, ⨆ (hi : p i), f i hi = ⨆ i, ⨆ (hi : p i), g i hi := by grind +@[to_dual] theorem Function.Surjective.iSup_comp {f : ι → ι'} (hf : Surjective f) (g : ι' → α) : ⨆ x, g (f x) = ⨆ y, g y := by simp only [iSup.eq_1] congr exact hf.range_comp g +@[to_dual] theorem Equiv.iSup_comp {g : ι' → α} (e : ι ≃ ι') : ⨆ x, g (e x) = ⨆ y, g y := e.surjective.iSup_comp _ +@[to_dual] protected theorem Function.Surjective.iSup_congr {g : ι' → α} (h : ι → ι') (h1 : Surjective h) (h2 : ∀ x, g (h x) = f x) : ⨆ x, f x = ⨆ y, g y := by convert h1.iSup_comp g exact (h2 _).symm +@[to_dual] protected theorem Equiv.iSup_congr {g : ι' → α} (e : ι ≃ ι') (h : ∀ x, g (e x) = f x) : ⨆ x, f x = ⨆ y, g y := e.surjective.iSup_congr _ h @@ -233,12 +194,15 @@ theorem iSup_congr_Prop {p q : Prop} {f₁ : p → α} {f₂ : q → α} (pq : p congr with x apply f +@[to_dual] theorem iSup_plift_up (f : PLift ι → α) : ⨆ i, f (PLift.up i) = ⨆ i, f i := (PLift.up_surjective.iSup_congr _) fun _ => rfl +@[to_dual] theorem iSup_plift_down (f : ι → α) : ⨆ i, f (PLift.down i) = ⨆ i, f i := (PLift.down_surjective.iSup_congr _) fun _ => rfl +@[to_dual] theorem iSup_range' (g : β → α) (f : ι → β) : ⨆ b : range f, g b = ⨆ i, g (f i) := by rw [iSup, iSup, ← image_eq_range, ← range_comp'] @@ -248,396 +212,228 @@ theorem sSup_image' {s : Set β} {f : β → α} : sSup (f '' s) = ⨆ a : s, f end SupSet -section InfSet - -variable [InfSet α] {f g : ι → α} - -theorem sInf_range : sInf (range f) = iInf f := - rfl - -theorem sInf_eq_iInf' (s : Set α) : sInf s = ⨅ a : s, (a : α) := - @sSup_eq_iSup' αᵒᵈ _ _ - -theorem iInf_congr (h : ∀ i, f i = g i) : ⨅ i, f i = ⨅ i, g i := - congr_arg _ <| funext h - -theorem biInf_congr {p : ι → Prop} (h : ∀ i, p i → f i = g i) : - ⨅ (i) (_ : p i), f i = ⨅ (i) (_ : p i), g i := - biSup_congr (α := αᵒᵈ) h - -theorem biInf_congr' {p : ι → Prop} {f g : (i : ι) → p i → α} - (h : ∀ i (hi : p i), f i hi = g i hi) : - ⨅ i, ⨅ (hi : p i), f i hi = ⨅ i, ⨅ (hi : p i), g i hi := by - grind - -theorem Function.Surjective.iInf_comp {f : ι → ι'} (hf : Surjective f) (g : ι' → α) : - ⨅ x, g (f x) = ⨅ y, g y := - @Function.Surjective.iSup_comp αᵒᵈ _ _ _ f hf g - -theorem Equiv.iInf_comp {g : ι' → α} (e : ι ≃ ι') : ⨅ x, g (e x) = ⨅ y, g y := - @Equiv.iSup_comp αᵒᵈ _ _ _ _ e - -protected theorem Function.Surjective.iInf_congr {g : ι' → α} (h : ι → ι') (h1 : Surjective h) - (h2 : ∀ x, g (h x) = f x) : ⨅ x, f x = ⨅ y, g y := - @Function.Surjective.iSup_congr αᵒᵈ _ _ _ _ _ h h1 h2 - -protected theorem Equiv.iInf_congr {g : ι' → α} (e : ι ≃ ι') (h : ∀ x, g (e x) = f x) : - ⨅ x, f x = ⨅ y, g y := - @Equiv.iSup_congr αᵒᵈ _ _ _ _ _ e h - -theorem iInf_plift_up (f : PLift ι → α) : ⨅ i, f (PLift.up i) = ⨅ i, f i := - (PLift.up_surjective.iInf_congr _) fun _ => rfl - -theorem iInf_plift_down (f : ι → α) : ⨅ i, f (PLift.down i) = ⨅ i, f i := - (PLift.down_surjective.iInf_congr _) fun _ => rfl - -theorem iInf_range' (g : β → α) (f : ι → β) : ⨅ b : range f, g b = ⨅ i, g (f i) := - @iSup_range' αᵒᵈ _ _ _ _ _ - -end InfSet - section variable [CompleteLattice α] {f g s : ι → α} {a b : α} +@[to_dual iInf_le] theorem le_iSup (f : ι → α) (i : ι) : f i ≤ iSup f := le_sSup ⟨i, rfl⟩ -theorem iInf_le (f : ι → α) (i : ι) : iInf f ≤ f i := - sInf_le ⟨i, rfl⟩ - lemma iInf_le_iSup [Nonempty ι] : ⨅ i, f i ≤ ⨆ i, f i := (iInf_le _ (Classical.arbitrary _)).trans <| le_iSup _ (Classical.arbitrary _) +@[to_dual] theorem isLUB_iSup : IsLUB (range f) (⨆ j, f j) := isLUB_sSup _ -theorem isGLB_iInf : IsGLB (range f) (⨅ j, f j) := - isGLB_sInf _ - +@[to_dual] theorem IsLUB.iSup_eq (h : IsLUB (range f) a) : ⨆ j, f j = a := h.sSup_eq -theorem IsGLB.iInf_eq (h : IsGLB (range f) a) : ⨅ j, f j = a := - h.sInf_eq - +@[to_dual iInf_le_of_le] theorem le_iSup_of_le (i : ι) (h : a ≤ f i) : a ≤ iSup f := h.trans <| le_iSup _ i -theorem iInf_le_of_le (i : ι) (h : f i ≤ a) : iInf f ≤ a := - (iInf_le _ i).trans h - +@[to_dual iInf₂_le] theorem le_iSup₂ {f : ∀ i, κ i → α} (i : ι) (j : κ i) : f i j ≤ ⨆ (i) (j), f i j := le_iSup_of_le i <| le_iSup (f i) j -theorem iInf₂_le {f : ∀ i, κ i → α} (i : ι) (j : κ i) : ⨅ (i) (j), f i j ≤ f i j := - iInf_le_of_le i <| iInf_le (f i) j - +@[to_dual iInf₂_le_of_le] theorem le_iSup₂_of_le {f : ∀ i, κ i → α} (i : ι) (j : κ i) (h : a ≤ f i j) : a ≤ ⨆ (i) (j), f i j := h.trans <| le_iSup₂ i j -theorem iInf₂_le_of_le {f : ∀ i, κ i → α} (i : ι) (j : κ i) (h : f i j ≤ a) : - ⨅ (i) (j), f i j ≤ a := - (iInf₂_le i j).trans h - +@[to_dual le_iInf] theorem iSup_le (h : ∀ i, f i ≤ a) : iSup f ≤ a := sSup_le fun _ ⟨i, Eq⟩ => Eq ▸ h i -theorem le_iInf (h : ∀ i, a ≤ f i) : a ≤ iInf f := - le_sInf fun _ ⟨i, Eq⟩ => Eq ▸ h i - +@[to_dual le_iInf₂] theorem iSup₂_le {f : ∀ i, κ i → α} (h : ∀ i j, f i j ≤ a) : ⨆ (i) (j), f i j ≤ a := iSup_le fun i => iSup_le <| h i -theorem le_iInf₂ {f : ∀ i, κ i → α} (h : ∀ i j, a ≤ f i j) : a ≤ ⨅ (i) (j), f i j := - le_iInf fun i => le_iInf <| h i - +@[to_dual iInf_le_iInf₂] theorem iSup₂_le_iSup (κ : ι → Sort*) (f : ι → α) : ⨆ (i) (_ : κ i), f i ≤ ⨆ i, f i := iSup₂_le fun i _ => le_iSup f i -theorem iInf_le_iInf₂ (κ : ι → Sort*) (f : ι → α) : ⨅ i, f i ≤ ⨅ (i) (_ : κ i), f i := - le_iInf₂ fun i _ => iInf_le f i - -@[gcongr] +@[to_dual (attr := gcongr)] theorem iSup_mono (h : ∀ i, f i ≤ g i) : iSup f ≤ iSup g := iSup_le fun i => le_iSup_of_le i <| h i -@[gcongr] -theorem iInf_mono (h : ∀ i, f i ≤ g i) : iInf f ≤ iInf g := - le_iInf fun i => iInf_le_of_le i <| h i - +@[to_dual] theorem iSup₂_mono {f g : ∀ i, κ i → α} (h : ∀ i j, f i j ≤ g i j) : ⨆ (i) (j), f i j ≤ ⨆ (i) (j), g i j := iSup_mono fun i => iSup_mono <| h i -theorem iInf₂_mono {f g : ∀ i, κ i → α} (h : ∀ i j, f i j ≤ g i j) : - ⨅ (i) (j), f i j ≤ ⨅ (i) (j), g i j := - iInf_mono fun i => iInf_mono <| h i - +@[to_dual] theorem iSup_mono' {g : ι' → α} (h : ∀ i, ∃ i', f i ≤ g i') : iSup f ≤ iSup g := iSup_le fun i => Exists.elim (h i) le_iSup_of_le -theorem iInf_mono' {g : ι' → α} (h : ∀ i', ∃ i, f i ≤ g i') : iInf f ≤ iInf g := - le_iInf fun i' => Exists.elim (h i') iInf_le_of_le - +@[to_dual] theorem iSup₂_mono' {f : ∀ i, κ i → α} {g : ∀ i', κ' i' → α} (h : ∀ i j, ∃ i' j', f i j ≤ g i' j') : ⨆ (i) (j), f i j ≤ ⨆ (i) (j), g i j := iSup₂_le fun i j => let ⟨i', j', h⟩ := h i j le_iSup₂_of_le i' j' h -theorem iInf₂_mono' {f : ∀ i, κ i → α} {g : ∀ i', κ' i' → α} (h : ∀ i j, ∃ i' j', f i' j' ≤ g i j) : - ⨅ (i) (j), f i j ≤ ⨅ (i) (j), g i j := - le_iInf₂ fun i j => - let ⟨i', j', h⟩ := h i j - iInf₂_le_of_le i' j' h - +@[to_dual] theorem iSup_const_mono (h : ι → ι') : ⨆ _ : ι, a ≤ ⨆ _ : ι', a := iSup_le <| le_iSup _ ∘ h -theorem iInf_const_mono (h : ι' → ι) : ⨅ _ : ι, a ≤ ⨅ _ : ι', a := - le_iInf <| iInf_le _ ∘ h - +@[to_dual none] theorem iSup_iInf_le_iInf_iSup (f : ι → ι' → α) : ⨆ i, ⨅ j, f i j ≤ ⨅ j, ⨆ i, f i j := iSup_le fun i => iInf_mono fun j => le_iSup (fun i => f i j) i +@[to_dual] theorem biSup_mono {p q : ι → Prop} (hpq : ∀ i, p i → q i) : ⨆ (i) (_ : p i), f i ≤ ⨆ (i) (_ : q i), f i := iSup_mono fun i => iSup_const_mono (hpq i) -theorem biInf_mono {p q : ι → Prop} (hpq : ∀ i, p i → q i) : - ⨅ (i) (_ : q i), f i ≤ ⨅ (i) (_ : p i), f i := - iInf_mono fun i => iInf_const_mono (hpq i) - -@[simp] +@[to_dual (attr := simp) le_iInf_iff] theorem iSup_le_iff : iSup f ≤ a ↔ ∀ i, f i ≤ a := (isLUB_le_iff isLUB_iSup).trans forall_mem_range -@[simp] -theorem le_iInf_iff : a ≤ iInf f ↔ ∀ i, a ≤ f i := - (le_isGLB_iff isGLB_iInf).trans forall_mem_range - +@[to_dual le_iInf₂_iff] theorem iSup₂_le_iff {f : ∀ i, κ i → α} : ⨆ (i) (j), f i j ≤ a ↔ ∀ i j, f i j ≤ a := by simp_rw [iSup_le_iff] -theorem le_iInf₂_iff {f : ∀ i, κ i → α} : (a ≤ ⨅ (i) (j), f i j) ↔ ∀ i j, a ≤ f i j := by - simp_rw [le_iInf_iff] - +@[to_dual lt_iInf_iff] theorem iSup_lt_iff : iSup f < a ↔ ∃ b, b < a ∧ ∀ i, f i ≤ b := ⟨fun h => ⟨iSup f, h, le_iSup f⟩, fun ⟨_, h, hb⟩ => (iSup_le hb).trans_lt h⟩ -theorem lt_iInf_iff : a < iInf f ↔ ∃ b, a < b ∧ ∀ i, b ≤ f i := - ⟨fun h => ⟨iInf f, h, iInf_le f⟩, fun ⟨_, h, hb⟩ => h.trans_le <| le_iInf hb⟩ - +@[to_dual] theorem sSup_eq_iSup {s : Set α} : sSup s = ⨆ a ∈ s, a := le_antisymm (sSup_le le_iSup₂) (iSup₂_le fun _ => le_sSup) -theorem sInf_eq_iInf {s : Set α} : sInf s = ⨅ a ∈ s, a := - @sSup_eq_iSup αᵒᵈ _ _ - +@[to_dual] lemma sSup_lowerBounds_eq_sInf (s : Set α) : sSup (lowerBounds s) = sInf s := (isLUB_sSup _).unique (isGLB_sInf _).isLUB -lemma sInf_upperBounds_eq_sSup (s : Set α) : sInf (upperBounds s) = sSup s := - (isGLB_sInf _).unique (isLUB_sSup _).isGLB - @[deprecated (since := "2026-02-01")] alias sInf_upperBounds_eq_csSup := sInf_upperBounds_eq_sSup +@[to_dual map_iInf_le] theorem Monotone.le_map_iSup [CompleteLattice β] {f : α → β} (hf : Monotone f) : ⨆ i, f (s i) ≤ f (iSup s) := iSup_le fun _ => hf <| le_iSup _ _ +@[to_dual map_iSup_le] theorem Antitone.le_map_iInf [CompleteLattice β] {f : α → β} (hf : Antitone f) : ⨆ i, f (s i) ≤ f (iInf s) := hf.dual_left.le_map_iSup +@[to_dual map_iInf₂_le] theorem Monotone.le_map_iSup₂ [CompleteLattice β] {f : α → β} (hf : Monotone f) (s : ∀ i, κ i → α) : ⨆ (i) (j), f (s i j) ≤ f (⨆ (i) (j), s i j) := iSup₂_le fun _ _ => hf <| le_iSup₂ _ _ +@[to_dual map_iSup₂_le] theorem Antitone.le_map_iInf₂ [CompleteLattice β] {f : α → β} (hf : Antitone f) (s : ∀ i, κ i → α) : ⨆ (i) (j), f (s i j) ≤ f (⨅ (i) (j), s i j) := hf.dual_left.le_map_iSup₂ _ +@[to_dual map_sInf_le] theorem Monotone.le_map_sSup [CompleteLattice β] {s : Set α} {f : α → β} (hf : Monotone f) : ⨆ a ∈ s, f a ≤ f (sSup s) := by rw [sSup_eq_iSup]; exact hf.le_map_iSup₂ _ +@[to_dual map_sSup_le] theorem Antitone.le_map_sInf [CompleteLattice β] {s : Set α} {f : α → β} (hf : Antitone f) : ⨆ a ∈ s, f a ≤ f (sInf s) := hf.dual_left.le_map_sSup +@[to_dual] theorem OrderIso.map_iSup [CompleteLattice β] (f : α ≃o β) (x : ι → α) : f (⨆ i, x i) = ⨆ i, f (x i) := eq_of_forall_ge_iff <| f.surjective.forall.2 fun x => by simp only [f.le_iff_le, iSup_le_iff] +@[to_dual] lemma OrderIso.map_iSup₂ [CompleteLattice β] (f : α ≃o β) (x : ∀ i, κ i → α) : f (⨆ i, ⨆ j, x i j) = ⨆ i, ⨆ j, f (x i j) := eq_of_forall_ge_iff <| f.surjective.forall.2 fun x => by simp only [f.le_iff_le, iSup_le_iff] -theorem OrderIso.map_iInf [CompleteLattice β] (f : α ≃o β) (x : ι → α) : - f (⨅ i, x i) = ⨅ i, f (x i) := - OrderIso.map_iSup f.dual _ - -theorem OrderIso.map_iInf₂ [CompleteLattice β] (f : α ≃o β) (x : ∀ i, κ i → α) : - f (⨅ i, ⨅ j, x i j) = ⨅ i, ⨅ j, f (x i j) := - OrderIso.map_iSup₂ f.dual _ - +@[to_dual] theorem OrderIso.map_sSup [CompleteLattice β] (f : α ≃o β) (s : Set α) : f (sSup s) = ⨆ a ∈ s, f a := by simp only [sSup_eq_iSup, OrderIso.map_iSup] -theorem OrderIso.map_sInf [CompleteLattice β] (f : α ≃o β) (s : Set α) : - f (sInf s) = ⨅ a ∈ s, f a := - OrderIso.map_sSup f.dual _ - +@[to_dual le_iInf_comp] theorem iSup_comp_le {ι' : Sort*} (f : ι' → α) (g : ι → ι') : ⨆ x, f (g x) ≤ ⨆ y, f y := iSup_mono' fun _ => ⟨_, le_rfl⟩ -theorem le_iInf_comp {ι' : Sort*} (f : ι' → α) (g : ι → ι') : ⨅ y, f y ≤ ⨅ x, f (g x) := - iInf_mono' fun _ => ⟨_, le_rfl⟩ - +@[to_dual] theorem Monotone.iSup_comp_eq [Preorder β] {f : β → α} (hf : Monotone f) {s : ι → β} (hs : ∀ x, ∃ i, x ≤ s i) : ⨆ x, f (s x) = ⨆ y, f y := le_antisymm (iSup_comp_le _ _) (iSup_mono' fun x => (hs x).imp fun _ hi => hf hi) -theorem Monotone.iInf_comp_eq [Preorder β] {f : β → α} (hf : Monotone f) {s : ι → β} - (hs : ∀ x, ∃ i, s i ≤ x) : ⨅ x, f (s x) = ⨅ y, f y := - le_antisymm (iInf_mono' fun x => (hs x).imp fun _ hi => hf hi) (le_iInf_comp _ _) - -theorem Antitone.map_iSup_le [CompleteLattice β] {f : α → β} (hf : Antitone f) : - f (iSup s) ≤ ⨅ i, f (s i) := - le_iInf fun _ => hf <| le_iSup _ _ - -theorem Monotone.map_iInf_le [CompleteLattice β] {f : α → β} (hf : Monotone f) : - f (iInf s) ≤ ⨅ i, f (s i) := - hf.dual_left.map_iSup_le - -theorem Antitone.map_iSup₂_le [CompleteLattice β] {f : α → β} (hf : Antitone f) (s : ∀ i, κ i → α) : - f (⨆ (i) (j), s i j) ≤ ⨅ (i) (j), f (s i j) := - hf.dual.le_map_iInf₂ _ - -theorem Monotone.map_iInf₂_le [CompleteLattice β] {f : α → β} (hf : Monotone f) (s : ∀ i, κ i → α) : - f (⨅ (i) (j), s i j) ≤ ⨅ (i) (j), f (s i j) := - hf.dual.le_map_iSup₂ _ - -theorem Antitone.map_sSup_le [CompleteLattice β] {s : Set α} {f : α → β} (hf : Antitone f) : - f (sSup s) ≤ ⨅ a ∈ s, f a := by - rw [sSup_eq_iSup] - exact hf.map_iSup₂_le _ - -theorem Monotone.map_sInf_le [CompleteLattice β] {s : Set α} {f : α → β} (hf : Monotone f) : - f (sInf s) ≤ ⨅ a ∈ s, f a := - hf.dual_left.map_sSup_le - +@[to_dual le_iInf_const] theorem iSup_const_le : ⨆ _ : ι, a ≤ a := iSup_le fun _ => le_rfl -theorem le_iInf_const : a ≤ ⨅ _ : ι, a := - le_iInf fun _ => le_rfl - -- We generalize this to conditionally complete lattices in `ciSup_const` and `ciInf_const`. +@[to_dual] theorem iSup_const [Nonempty ι] : ⨆ _ : ι, a = a := by rw [iSup, range_const, sSup_singleton] -theorem iInf_const [Nonempty ι] : ⨅ _ : ι, a = a := - @iSup_const αᵒᵈ _ _ a _ - +@[to_dual] lemma iSup_unique [Unique ι] (f : ι → α) : ⨆ i, f i = f default := by simp only [congr_arg f (Unique.eq_default _), iSup_const] -lemma iInf_unique [Unique ι] (f : ι → α) : ⨅ i, f i = f default := by - simp only [congr_arg f (Unique.eq_default _), iInf_const] - -@[simp] +@[to_dual (attr := simp)] theorem iSup_bot : (⨆ _ : ι, ⊥ : α) = ⊥ := bot_unique iSup_const_le -@[simp] -theorem iInf_top : (⨅ _ : ι, ⊤ : α) = ⊤ := - top_unique le_iInf_const - -@[simp] +@[to_dual (attr := simp)] theorem iSup_eq_bot : iSup s = ⊥ ↔ ∀ i, s i = ⊥ := sSup_eq_bot.trans forall_mem_range -@[simp] -theorem iInf_eq_top : iInf s = ⊤ ↔ ∀ i, s i = ⊤ := - sInf_eq_top.trans forall_mem_range - -@[simp] lemma bot_lt_iSup : ⊥ < ⨆ i, s i ↔ ∃ i, ⊥ < s i := by simp [bot_lt_iff_ne_bot] -@[simp] lemma iInf_lt_top : ⨅ i, s i < ⊤ ↔ ∃ i, s i < ⊤ := by simp [lt_top_iff_ne_top] +@[to_dual (attr := simp) iInf_lt_top] +lemma bot_lt_iSup : ⊥ < ⨆ i, s i ↔ ∃ i, ⊥ < s i := by simp [bot_lt_iff_ne_bot] +@[to_dual] theorem iSup₂_eq_bot {f : ∀ i, κ i → α} : ⨆ (i) (j), f i j = ⊥ ↔ ∀ i j, f i j = ⊥ := by simp -theorem iInf₂_eq_top {f : ∀ i, κ i → α} : ⨅ (i) (j), f i j = ⊤ ↔ ∀ i j, f i j = ⊤ := by - simp - -@[simp] +@[to_dual (attr := simp)] theorem iSup_pos {p : Prop} {f : p → α} (hp : p) : ⨆ h : p, f h = f hp := le_antisymm (iSup_le fun _ => le_rfl) (le_iSup _ _) -@[simp] -theorem iInf_pos {p : Prop} {f : p → α} (hp : p) : ⨅ h : p, f h = f hp := - le_antisymm (iInf_le _ _) (le_iInf fun _ => le_rfl) - -@[simp] +@[to_dual (attr := simp)] theorem iSup_neg {p : Prop} {f : p → α} (hp : ¬p) : ⨆ h : p, f h = ⊥ := le_antisymm (iSup_le fun h => (hp h).elim) bot_le -@[simp] -theorem iInf_neg {p : Prop} {f : p → α} (hp : ¬p) : ⨅ h : p, f h = ⊤ := - le_antisymm le_top <| le_iInf fun h => (hp h).elim - /-- Introduction rule to prove that `b` is the supremum of `f`: it suffices to check that `b` is larger than `f i` for all `i`, and that this is not the case of any `wb`. +See `ciInf_eq_of_forall_ge_of_forall_gt_exists_lt` for a version in conditionally complete +lattices. -/] theorem iSup_eq_of_forall_le_of_forall_lt_exists_gt {f : ι → α} (h₁ : ∀ i, f i ≤ b) (h₂ : ∀ w, w < b → ∃ i, w < f i) : ⨆ i : ι, f i = b := sSup_eq_of_forall_le_of_forall_lt_exists_gt (forall_mem_range.mpr h₁) fun w hw => exists_range_iff.mpr <| h₂ w hw -/-- Introduction rule to prove that `b` is the infimum of `f`: it suffices to check that `b` -is smaller than `f i` for all `i`, and that this is not the case of any `w>b`. -See `ciInf_eq_of_forall_ge_of_forall_gt_exists_lt` for a version in conditionally complete -lattices. -/ -theorem iInf_eq_of_forall_ge_of_forall_gt_exists_lt : - (∀ i, b ≤ f i) → (∀ w, b < w → ∃ i, f i < w) → ⨅ i, f i = b := - @iSup_eq_of_forall_le_of_forall_lt_exists_gt αᵒᵈ _ _ _ _ - +@[to_dual] theorem iSup_eq_dif {p : Prop} [Decidable p] (a : p → α) : ⨆ h : p, a h = if h : p then a h else ⊥ := by by_cases h : p <;> simp [h] +@[to_dual] theorem iSup_eq_if {p : Prop} [Decidable p] (a : α) : ⨆ _ : p, a = if p then a else ⊥ := iSup_eq_dif fun _ => a -theorem iInf_eq_dif {p : Prop} [Decidable p] (a : p → α) : - ⨅ h : p, a h = if h : p then a h else ⊤ := - @iSup_eq_dif αᵒᵈ _ _ _ _ - -theorem iInf_eq_if {p : Prop} [Decidable p] (a : α) : ⨅ _ : p, a = if p then a else ⊤ := - iInf_eq_dif fun _ => a - +@[to_dual] theorem iSup_comm {f : ι → ι' → α} : ⨆ (i) (j), f i j = ⨆ (j) (i), f i j := le_antisymm (iSup_le fun i => iSup_mono fun j => le_iSup (fun i => f i j) i) (iSup_le fun _ => iSup_mono fun _ => le_iSup _ _) -theorem iInf_comm {f : ι → ι' → α} : ⨅ (i) (j), f i j = ⨅ (j) (i), f i j := - @iSup_comm αᵒᵈ _ _ _ _ - +@[to_dual] theorem iSup₂_comm {ι₁ ι₂ : Sort*} {κ₁ : ι₁ → Sort*} {κ₂ : ι₂ → Sort*} (f : ∀ i₁, κ₁ i₁ → ∀ i₂, κ₂ i₂ → α) : ⨆ (i₁) (j₁) (i₂) (j₂), f i₁ j₁ i₂ j₂ = ⨆ (i₂) (j₂) (i₁) (j₁), f i₁ j₁ i₂ j₂ := by simp only [@iSup_comm _ (κ₁ _), @iSup_comm _ ι₁] -theorem iInf₂_comm {ι₁ ι₂ : Sort*} {κ₁ : ι₁ → Sort*} {κ₂ : ι₂ → Sort*} - (f : ∀ i₁, κ₁ i₁ → ∀ i₂, κ₂ i₂ → α) : - ⨅ (i₁) (j₁) (i₂) (j₂), f i₁ j₁ i₂ j₂ = ⨅ (i₂) (j₂) (i₁) (j₁), f i₁ j₁ i₂ j₂ := by - simp only [@iInf_comm _ (κ₁ _), @iInf_comm _ ι₁] - /- TODO: this is strange. In the proof below, we get exactly the desired among the equalities, but close does not get it. begin @@ -649,7 +445,7 @@ begin end end -/ -@[simp] +@[to_dual (attr := simp)] theorem iSup_iSup_eq_left {b : β} {f : ∀ x : β, x = b → α} : ⨆ x, ⨆ h : x = b, f x h = f b rfl := (@le_iSup₂ _ _ _ _ f b rfl).antisymm' (iSup_le fun c => @@ -657,69 +453,45 @@ theorem iSup_iSup_eq_left {b : β} {f : ∀ x : β, x = b → α} : ⨆ x, ⨆ h rintro rfl rfl) -@[simp] -theorem iInf_iInf_eq_left {b : β} {f : ∀ x : β, x = b → α} : ⨅ x, ⨅ h : x = b, f x h = f b rfl := - @iSup_iSup_eq_left αᵒᵈ _ _ _ _ - -@[simp] +@[to_dual (attr := simp)] theorem iSup_iSup_eq_right {b : β} {f : ∀ x : β, b = x → α} : ⨆ x, ⨆ h : b = x, f x h = f b rfl := (le_iSup₂ b rfl).antisymm' (iSup₂_le fun c => by rintro rfl rfl) -@[simp] -theorem iInf_iInf_eq_right {b : β} {f : ∀ x : β, b = x → α} : ⨅ x, ⨅ h : b = x, f x h = f b rfl := - @iSup_iSup_eq_right αᵒᵈ _ _ _ _ - +@[to_dual] theorem iSup_subtype {p : ι → Prop} {f : Subtype p → α} : iSup f = ⨆ (i) (h : p i), f ⟨i, h⟩ := le_antisymm (iSup_le fun ⟨i, h⟩ => @le_iSup₂ _ _ p _ (fun i h => f ⟨i, h⟩) i h) (iSup₂_le fun _ _ => le_iSup _ _) -theorem iInf_subtype : ∀ {p : ι → Prop} {f : Subtype p → α}, iInf f = ⨅ (i) (h : p i), f ⟨i, h⟩ := - @iSup_subtype αᵒᵈ _ _ - +@[to_dual] theorem iSup_subtype' {p : ι → Prop} {f : ∀ i, p i → α} : ⨆ (i) (h), f i h = ⨆ x : Subtype p, f x x.property := (@iSup_subtype _ _ _ p fun x => f x.val x.property).symm -theorem iInf_subtype' {p : ι → Prop} {f : ∀ i, p i → α} : - ⨅ (i) (h : p i), f i h = ⨅ x : Subtype p, f x x.property := - (@iInf_subtype _ _ _ p fun x => f x.val x.property).symm - +@[to_dual] theorem iSup_subtype'' {ι} (s : Set ι) (f : ι → α) : ⨆ i : s, f i = ⨆ (t : ι) (_ : t ∈ s), f t := iSup_subtype -theorem iInf_subtype'' {ι} (s : Set ι) (f : ι → α) : ⨅ i : s, f i = ⨅ (t : ι) (_ : t ∈ s), f t := - iInf_subtype - +@[to_dual] theorem biSup_const {a : α} {s : Set β} (hs : s.Nonempty) : ⨆ i ∈ s, a = a := by haveI : Nonempty s := Set.nonempty_coe_sort.mpr hs rw [← iSup_subtype'', iSup_const] -theorem biInf_const {a : α} {s : Set β} (hs : s.Nonempty) : ⨅ i ∈ s, a = a := - biSup_const (α := αᵒᵈ) hs - +@[to_dual] theorem iSup_sup_eq : ⨆ x, f x ⊔ g x = (⨆ x, f x) ⊔ ⨆ x, g x := le_antisymm (iSup_le fun _ => sup_le_sup (le_iSup _ _) <| le_iSup _ _) (sup_le (iSup_mono fun _ => le_sup_left) <| iSup_mono fun _ => le_sup_right) -theorem iInf_inf_eq : ⨅ x, f x ⊓ g x = (⨅ x, f x) ⊓ ⨅ x, g x := - @iSup_sup_eq αᵒᵈ _ _ _ _ - +@[to_dual] lemma Equiv.biSup_comp {ι ι' : Type*} {g : ι' → α} (e : ι ≃ ι') (s : Set ι') : ⨆ i ∈ e.symm '' s, g (e i) = ⨆ i ∈ s, g i := by simpa only [iSup_subtype'] using (image e.symm s).symm.iSup_comp (g := g ∘ (↑)) -lemma Equiv.biInf_comp {ι ι' : Type*} {g : ι' → α} (e : ι ≃ ι') (s : Set ι') : - ⨅ i ∈ e.symm '' s, g (e i) = ⨅ i ∈ s, g i := - e.biSup_comp s (α := αᵒᵈ) - -lemma biInf_le {ι : Type*} {s : Set ι} (f : ι → α) {i : ι} (hi : i ∈ s) : ⨅ i ∈ s, f i ≤ f i := - iInf₂_le i hi - +@[to_dual biInf_le] lemma le_biSup {ι : Type*} {s : Set ι} (f : ι → α) {i : ι} (hi : i ∈ s) : f i ≤ ⨆ i ∈ s, f i := - biInf_le (α := αᵒᵈ) f hi + le_iSup₂_of_le i hi le_rfl lemma biInf_le_biSup {ι : Type*} {s : Set ι} (hs : s.Nonempty) {f : ι → α} : ⨅ i ∈ s, f i ≤ ⨆ i ∈ s, f i := @@ -732,18 +504,15 @@ begin safe, pose h := f a ⊓ g a, begin [smt] ematch, ematch end end -/ +@[to_dual] theorem iSup_sup [Nonempty ι] {f : ι → α} {a : α} : (⨆ x, f x) ⊔ a = ⨆ x, f x ⊔ a := by rw [iSup_sup_eq, iSup_const] -theorem iInf_inf [Nonempty ι] {f : ι → α} {a : α} : (⨅ x, f x) ⊓ a = ⨅ x, f x ⊓ a := by - rw [iInf_inf_eq, iInf_const] - +@[to_dual] theorem sup_iSup [Nonempty ι] {f : ι → α} {a : α} : (a ⊔ ⨆ x, f x) = ⨆ x, a ⊔ f x := by rw [iSup_sup_eq, iSup_const] -theorem inf_iInf [Nonempty ι] {f : ι → α} {a : α} : (a ⊓ ⨅ x, f x) = ⨅ x, a ⊓ f x := by - rw [iInf_inf_eq, iInf_const] - +@[to_dual] theorem biSup_sup {p : ι → Prop} {f : ∀ i, p i → α} {a : α} (h : ∃ i, p i) : (⨆ (i) (h : p i), f i h) ⊔ a = ⨆ (i) (h : p i), f i h ⊔ a := by haveI : Nonempty { i // p i } := @@ -751,18 +520,12 @@ theorem biSup_sup {p : ι → Prop} {f : ∀ i, p i → α} {a : α} (h : ∃ i, ⟨⟨i, hi⟩⟩ rw [iSup_subtype', iSup_subtype', iSup_sup] +@[to_dual] theorem sup_biSup {p : ι → Prop} {f : ∀ i, p i → α} {a : α} (h : ∃ i, p i) : (a ⊔ ⨆ (i) (h : p i), f i h) = ⨆ (i) (h : p i), a ⊔ f i h := by simpa only [sup_comm] using @biSup_sup α _ _ p _ _ h -theorem biInf_inf {p : ι → Prop} {f : ∀ i, p i → α} {a : α} (h : ∃ i, p i) : - (⨅ (i) (h : p i), f i h) ⊓ a = ⨅ (i) (h : p i), f i h ⊓ a := - @biSup_sup αᵒᵈ ι _ p f _ h - -theorem inf_biInf {p : ι → Prop} {f : ∀ i, p i → α} {a : α} (h : ∃ i, p i) : - (a ⊓ ⨅ (i) (h : p i), f i h) = ⨅ (i) (h : p i), a ⊓ f i h := - @sup_biSup αᵒᵈ ι _ p f _ h - +@[to_dual (dont_translate := ι)] lemma biSup_lt_eq_iSup {ι : Type*} [LT ι] [NoMaxOrder ι] {f : ι → α} : ⨆ (i) (j < i), f j = ⨆ i, f i := by apply le_antisymm @@ -771,88 +534,67 @@ lemma biSup_lt_eq_iSup {ι : Type*} [LT ι] [NoMaxOrder ι] {f : ι → α} : obtain ⟨i, jlt⟩ := exists_gt j exact le_iSup_of_le i (le_iSup₂_of_le j jlt le_rfl) +@[to_dual (dont_translate := ι)] lemma biSup_le_eq_iSup {ι : Type*} [Preorder ι] {f : ι → α} : ⨆ (i) (j ≤ i), f j = ⨆ i, f i := by apply le_antisymm · exact iSup_le fun _ ↦ iSup₂_le fun _ _ ↦ le_iSup _ _ · exact iSup_le fun j ↦ le_iSup_of_le j (le_iSup₂_of_le j le_rfl le_rfl) -lemma biInf_lt_eq_iInf {ι : Type*} [LT ι] [NoMaxOrder ι] {f : ι → α} : - ⨅ (i) (j < i), f j = ⨅ i, f i := - biSup_lt_eq_iSup (α := αᵒᵈ) - -lemma biInf_le_eq_iInf {ι : Type*} [Preorder ι] {f : ι → α} : ⨅ (i) (j ≤ i), f j = ⨅ i, f i := - biSup_le_eq_iSup (α := αᵒᵈ) - +@[to_dual (dont_translate := ι)] lemma biSup_gt_eq_iSup {ι : Type*} [LT ι] [NoMinOrder ι] {f : ι → α} : - ⨆ (i) (j > i), f j = ⨆ i, f i := - biSup_lt_eq_iSup (ι := ιᵒᵈ) - -lemma biSup_ge_eq_iSup {ι : Type*} [Preorder ι] {f : ι → α} : ⨆ (i) (j ≥ i), f j = ⨆ i, f i := - biSup_le_eq_iSup (ι := ιᵒᵈ) - -lemma biInf_gt_eq_iInf {ι : Type*} [LT ι] [NoMinOrder ι] {f : ι → α} : - ⨅ (i) (j > i), f j = ⨅ i, f i := - biInf_lt_eq_iInf (ι := ιᵒᵈ) + ⨆ (i) (j > i), f j = ⨆ i, f i := by + apply le_antisymm + · exact iSup_le fun _ ↦ iSup₂_le fun _ _ ↦ le_iSup _ _ + · refine iSup_le fun j ↦ ?_ + obtain ⟨i, jlt⟩ := exists_lt j + exact le_iSup_of_le i (le_iSup₂_of_le j jlt le_rfl) -lemma biInf_ge_eq_iInf {ι : Type*} [Preorder ι] {f : ι → α} : ⨅ (i) (j ≥ i), f j = ⨅ i, f i := - biInf_le_eq_iInf (ι := ιᵒᵈ) +@[to_dual (dont_translate := ι)] +lemma biSup_ge_eq_iSup {ι : Type*} [Preorder ι] {f : ι → α} : ⨆ (i) (j ≥ i), f j = ⨆ i, f i := by + apply le_antisymm + · exact iSup_le fun _ ↦ iSup₂_le fun _ _ ↦ le_iSup _ _ + · exact iSup_le fun j ↦ le_iSup_of_le j (le_iSup₂_of_le j le_rfl le_rfl) +@[to_dual biInf_ge_eq_of_monotone] lemma biSup_le_eq_of_monotone [Preorder β] {f : β → α} (hf : Monotone f) (b : β) : ⨆ (b' ≤ b), f b' = f b := le_antisymm (iSup₂_le_iff.2 (fun _ hji ↦ hf hji)) (le_iSup_of_le b (ge_of_eq (iSup_pos le_rfl))) +@[to_dual biSup_ge_eq_of_antitone] lemma biInf_le_eq_of_antitone [Preorder β] {f : β → α} (hf : Antitone f) (b : β) : ⨅ (b' ≤ b), f b' = f b := - biSup_le_eq_of_monotone (α := αᵒᵈ) hf.dual_right b - -lemma biSup_ge_eq_of_antitone [Preorder β] {f : β → α} (hf : Antitone f) (b : β) : - ⨆ (b' ≥ b), f b' = f b := - biSup_le_eq_of_monotone (β := βᵒᵈ) hf.dual_left b - -lemma biInf_ge_eq_of_monotone [Preorder β] {f : β → α} (hf : Monotone f) (b : β) : - ⨅ (b' ≥ b), f b' = f b := - biInf_le_eq_of_antitone (β := βᵒᵈ) hf.dual_left b + le_antisymm (iInf₂_le_of_le b le_rfl le_rfl) + (le_iInf₂ fun _ hji ↦ hf hji) /-! ### `iSup` and `iInf` under `Prop` -/ +@[to_dual] theorem iSup_false {s : False → α} : iSup s = ⊥ := by simp -theorem iInf_false {s : False → α} : iInf s = ⊤ := by simp - +@[to_dual] theorem iSup_true {s : True → α} : iSup s = s trivial := iSup_pos trivial -theorem iInf_true {s : True → α} : iInf s = s trivial := - iInf_pos trivial - -@[simp] +@[to_dual (attr := simp)] theorem iSup_exists {p : ι → Prop} {f : Exists p → α} : ⨆ x, f x = ⨆ (i) (h), f ⟨i, h⟩ := le_antisymm (iSup_le fun ⟨i, h⟩ => @le_iSup₂ _ _ _ _ (fun _ _ => _) i h) (iSup₂_le fun _ _ => le_iSup _ _) -@[simp] -theorem iInf_exists {p : ι → Prop} {f : Exists p → α} : ⨅ x, f x = ⨅ (i) (h), f ⟨i, h⟩ := - @iSup_exists αᵒᵈ _ _ _ _ - +@[to_dual] theorem iSup_and {p q : Prop} {s : p ∧ q → α} : iSup s = ⨆ (h₁) (h₂), s ⟨h₁, h₂⟩ := le_antisymm (iSup_le fun ⟨i, h⟩ => @le_iSup₂ _ _ _ _ (fun _ _ => _) i h) (iSup₂_le fun _ _ => le_iSup _ _) -theorem iInf_and {p q : Prop} {s : p ∧ q → α} : iInf s = ⨅ (h₁) (h₂), s ⟨h₁, h₂⟩ := - @iSup_and αᵒᵈ _ _ _ _ - /-- The symmetric case of `iSup_and`, useful for rewriting into a supremum over a conjunction -/ +@[to_dual /-- The symmetric case of `iInf_and`, +useful for rewriting into an infimum over a conjunction. -/] theorem iSup_and' {p q : Prop} {s : p → q → α} : ⨆ (h₁ : p) (h₂ : q), s h₁ h₂ = ⨆ h : p ∧ q, s h.1 h.2 := Eq.symm iSup_and -/-- The symmetric case of `iInf_and`, useful for rewriting into an infimum over a conjunction -/ -theorem iInf_and' {p q : Prop} {s : p → q → α} : - ⨅ (h₁ : p) (h₂ : q), s h₁ h₂ = ⨅ h : p ∧ q, s h.1 h.2 := - Eq.symm iInf_and - +@[to_dual] theorem iSup_or {p q : Prop} {s : p ∨ q → α} : ⨆ x, s x = (⨆ i, s (Or.inl i)) ⊔ ⨆ j, s (Or.inr j) := le_antisymm @@ -862,14 +604,11 @@ theorem iSup_or {p q : Prop} {s : p ∨ q → α} : | Or.inr _ => le_sup_of_le_right <| le_iSup (fun _ => s _) _) (sup_le (iSup_comp_le _ _) (iSup_comp_le _ _)) -theorem iInf_or {p q : Prop} {s : p ∨ q → α} : - ⨅ x, s x = (⨅ i, s (Or.inl i)) ⊓ ⨅ j, s (Or.inr j) := - @iSup_or αᵒᵈ _ _ _ _ - section variable (p : ι → Prop) [DecidablePred p] +@[to_dual] theorem iSup_dite (f : ∀ i, p i → α) (g : ∀ i, ¬p i → α) : ⨆ i, (if h : p i then f i h else g i h) = (⨆ (i) (h : p i), f i h) ⊔ ⨆ (i) (h : ¬p i), g i h := by @@ -877,151 +616,105 @@ theorem iSup_dite (f : ∀ i, p i → α) (g : ∀ i, ¬p i → α) : congr 1 with i split_ifs with h <;> simp [h] -theorem iInf_dite (f : ∀ i, p i → α) (g : ∀ i, ¬p i → α) : - ⨅ i, (if h : p i then f i h else g i h) = (⨅ (i) (h : p i), f i h) ⊓ ⨅ (i) (h : ¬p i), g i h := - iSup_dite p (show ∀ i, p i → αᵒᵈ from f) g - +@[to_dual] theorem iSup_ite (f g : ι → α) : ⨆ i, (if p i then f i else g i) = (⨆ (i) (_ : p i), f i) ⊔ ⨆ (i) (_ : ¬p i), g i := iSup_dite _ _ _ -theorem iInf_ite (f g : ι → α) : - ⨅ i, (if p i then f i else g i) = (⨅ (i) (_ : p i), f i) ⊓ ⨅ (i) (_ : ¬p i), g i := - iInf_dite _ _ _ - end +@[to_dual] theorem iSup_range {g : β → α} {f : ι → β} : ⨆ b ∈ range f, g b = ⨆ i, g (f i) := by rw [← iSup_subtype'', iSup_range'] -theorem iInf_range : ∀ {g : β → α} {f : ι → β}, ⨅ b ∈ range f, g b = ⨅ i, g (f i) := - @iSup_range αᵒᵈ _ _ _ - +@[to_dual] theorem sSup_image {s : Set β} {f : β → α} : sSup (f '' s) = ⨆ a ∈ s, f a := by rw [← iSup_subtype'', sSup_image'] -theorem sInf_image {s : Set β} {f : β → α} : sInf (f '' s) = ⨅ a ∈ s, f a := - @sSup_image αᵒᵈ _ _ _ _ - +@[to_dual] theorem OrderIso.map_sSup_eq_sSup_symm_preimage [CompleteLattice β] (f : α ≃o β) (s : Set α) : f (sSup s) = sSup (f.symm ⁻¹' s) := by rw [map_sSup, ← sSup_image, f.image_eq_preimage_symm] -theorem OrderIso.map_sInf_eq_sInf_symm_preimage [CompleteLattice β] (f : α ≃o β) (s : Set α) : - f (sInf s) = sInf (f.symm ⁻¹' s) := by - rw [map_sInf, ← sInf_image, f.image_eq_preimage_symm] - /- ### iSup and iInf under set constructions -/ -theorem iSup_emptyset {f : β → α} : ⨆ x ∈ (∅ : Set β), f x = ⊥ := by simp -theorem iInf_emptyset {f : β → α} : ⨅ x ∈ (∅ : Set β), f x = ⊤ := by simp +@[to_dual] +theorem iSup_emptyset {f : β → α} : ⨆ x ∈ (∅ : Set β), f x = ⊥ := by simp +@[to_dual] theorem iSup_univ {f : β → α} : ⨆ x ∈ (univ : Set β), f x = ⨆ x, f x := by simp -theorem iInf_univ {f : β → α} : ⨅ x ∈ (univ : Set β), f x = ⨅ x, f x := by simp - +@[to_dual] theorem iSup_union {f : β → α} {s t : Set β} : ⨆ x ∈ s ∪ t, f x = (⨆ x ∈ s, f x) ⊔ ⨆ x ∈ t, f x := by simp_rw [mem_union, iSup_or, iSup_sup_eq] -theorem iInf_union {f : β → α} {s t : Set β} : ⨅ x ∈ s ∪ t, f x = (⨅ x ∈ s, f x) ⊓ ⨅ x ∈ t, f x := - @iSup_union αᵒᵈ _ _ _ _ _ - +@[to_dual] theorem iSup_split (f : β → α) (p : β → Prop) : ⨆ i, f i = (⨆ (i) (_ : p i), f i) ⊔ ⨆ (i) (_ : ¬p i), f i := by simpa [Classical.em] using @iSup_union _ _ _ f { i | p i } { i | ¬p i } -theorem iInf_split : - ∀ (f : β → α) (p : β → Prop), ⨅ i, f i = (⨅ (i) (_ : p i), f i) ⊓ ⨅ (i) (_ : ¬p i), f i := - @iSup_split αᵒᵈ _ _ - +@[to_dual] theorem iSup_split_single (f : β → α) (i₀ : β) : ⨆ i, f i = f i₀ ⊔ ⨆ (i) (_ : i ≠ i₀), f i := by convert iSup_split f (fun i => i = i₀) simp -theorem iInf_split_single (f : β → α) (i₀ : β) : ⨅ i, f i = f i₀ ⊓ ⨅ (i) (_ : i ≠ i₀), f i := - @iSup_split_single αᵒᵈ _ _ _ _ - +@[to_dual] theorem iSup_le_iSup_of_subset {f : β → α} {s t : Set β} : s ⊆ t → ⨆ x ∈ s, f x ≤ ⨆ x ∈ t, f x := biSup_mono -theorem iInf_le_iInf_of_subset {f : β → α} {s t : Set β} : s ⊆ t → ⨅ x ∈ t, f x ≤ ⨅ x ∈ s, f x := - biInf_mono - +@[to_dual] theorem iSup_insert {f : β → α} {s : Set β} {b : β} : ⨆ x ∈ insert b s, f x = f b ⊔ ⨆ x ∈ s, f x := by simp [iSup_or, iSup_sup_eq] -theorem iInf_insert {f : β → α} {s : Set β} {b : β} : - ⨅ x ∈ insert b s, f x = f b ⊓ ⨅ x ∈ s, f x := by - simp [iInf_or, iInf_inf_eq] - +@[to_dual] theorem iSup_singleton {f : β → α} {b : β} : ⨆ x ∈ (singleton b : Set β), f x = f b := by simp -theorem iInf_singleton {f : β → α} {b : β} : ⨅ x ∈ (singleton b : Set β), f x = f b := by simp - +@[to_dual] theorem iSup_pair {f : β → α} {a b : β} : ⨆ x ∈ ({a, b} : Set β), f x = f a ⊔ f b := by rw [iSup_insert, iSup_singleton] -theorem iInf_pair {f : β → α} {a b : β} : ⨅ x ∈ ({a, b} : Set β), f x = f a ⊓ f b := by - rw [iInf_insert, iInf_singleton] - +@[to_dual] theorem iSup_image {γ} {f : β → γ} {g : γ → α} {t : Set β} : ⨆ c ∈ f '' t, g c = ⨆ b ∈ t, g (f b) := by rw [← sSup_image, ← sSup_image, ← image_comp, comp_def] -theorem iInf_image : - ∀ {γ} {f : β → γ} {g : γ → α} {t : Set β}, ⨅ c ∈ f '' t, g c = ⨅ b ∈ t, g (f b) := - @iSup_image αᵒᵈ _ _ - +@[to_dual] theorem iSup_extend_bot {e : ι → β} (he : Injective e) (f : ι → α) : ⨆ j, extend e f ⊥ j = ⨆ i, f i := by rw [iSup_split _ fun j => ∃ i, e i = j] simp +contextual [he.extend_apply, extend_apply', @iSup_comm _ β ι] -theorem iInf_extend_top {e : ι → β} (he : Injective e) (f : ι → α) : - ⨅ j, extend e f ⊤ j = iInf f := - @iSup_extend_bot αᵒᵈ _ _ _ _ he _ - +@[to_dual] theorem Set.BijOn.iSup_comp {s : Set β} {t : Set γ} {f : β → γ} (g : γ → α) (hf : Set.BijOn f s t) : ⨆ x ∈ s, g (f x) = ⨆ y ∈ t, g y := by rw [← hf.image_eq, iSup_image] -theorem Set.BijOn.iInf_comp {s : Set β} {t : Set γ} {f : β → γ} (g : γ → α) - (hf : Set.BijOn f s t) : ⨅ x ∈ s, g (f x) = ⨅ y ∈ t, g y := by - rw [← hf.image_eq, iInf_image] - +@[to_dual] theorem Set.BijOn.iSup_congr {s : Set β} {t : Set γ} (f : β → α) (g : γ → α) {h : β → γ} (h1 : Set.BijOn h s t) (h2 : ∀ x, g (h x) = f x) : ⨆ x ∈ s, f x = ⨆ y ∈ t, g y := by simpa only [h2] using h1.iSup_comp g -theorem Set.BijOn.iInf_congr {s : Set β} {t : Set γ} (f : β → α) (g : γ → α) {h : β → γ} - (h1 : Set.BijOn h s t) (h2 : ∀ x, g (h x) = f x) : ⨅ x ∈ s, f x = ⨅ y ∈ t, g y := by - simpa only [h2] using h1.iInf_comp g - section le variable {ι : Type*} [PartialOrder ι] (f : ι → α) (i : ι) +@[to_dual (dont_translate := ι)] theorem biSup_le_eq_sup : (⨆ j ≤ i, f j) = (⨆ j < i, f j) ⊔ f i := by rw [iSup_split_single _ i] -- Squeezed for a ~10x speedup, though it's still reasonably fast unsqueezed. simp only [le_refl, iSup_pos, iSup_and', lt_iff_le_and_ne, and_comm, sup_comm] -theorem biInf_le_eq_inf : (⨅ j ≤ i, f j) = (⨅ j < i, f j) ⊓ f i := - biSup_le_eq_sup (α := αᵒᵈ) f i - +@[to_dual (dont_translate := ι)] theorem biSup_ge_eq_sup : (⨆ j ≥ i, f j) = f i ⊔ (⨆ j > i, f j) := by rw [iSup_split_single _ i] -- Squeezed for a ~10x speedup, though it's still reasonably fast unsqueezed. simp only [ge_iff_le, le_refl, iSup_pos, ne_comm, iSup_and', gt_iff_lt, lt_iff_le_and_ne, and_comm] -theorem biInf_ge_eq_inf : (⨅ j ≥ i, f j) = f i ⊓ (⨅ j > i, f j) := - biSup_ge_eq_sup (α := αᵒᵈ) f i - end le /-! @@ -1032,106 +725,73 @@ end le theorem iSup_of_empty' {α ι} [SupSet α] [IsEmpty ι] (f : ι → α) : iSup f = sSup (∅ : Set α) := congr_arg sSup (range_eq_empty f) +@[to_dual] theorem iSup_of_empty [IsEmpty ι] (f : ι → α) : iSup f = ⊥ := (iSup_of_empty' f).trans sSup_empty -theorem iInf_of_empty [IsEmpty ι] (f : ι → α) : iInf f = ⊤ := - @iSup_of_empty αᵒᵈ _ _ _ f - -theorem isGLB_biInf {s : Set β} {f : β → α} : IsGLB (f '' s) (⨅ x ∈ s, f x) := by - simpa only [range_comp, Subtype.range_coe, iInf_subtype'] using - @isGLB_iInf α s _ (f ∘ fun x => (x : β)) - +@[to_dual] theorem isLUB_biSup {s : Set β} {f : β → α} : IsLUB (f '' s) (⨆ x ∈ s, f x) := by simpa only [range_comp, Subtype.range_coe, iSup_subtype'] using @isLUB_iSup α s _ (f ∘ fun x => (x : β)) +@[to_dual] theorem iSup_sigma {p : β → Type*} {f : Sigma p → α} : ⨆ x, f x = ⨆ (i) (j), f ⟨i, j⟩ := eq_of_forall_ge_iff fun c => by simp only [iSup_le_iff, Sigma.forall] -theorem iInf_sigma {p : β → Type*} {f : Sigma p → α} : ⨅ x, f x = ⨅ (i) (j), f ⟨i, j⟩ := - @iSup_sigma αᵒᵈ _ _ _ _ - +@[to_dual] lemma iSup_sigma' {κ : β → Type*} (f : ∀ i, κ i → α) : (⨆ i, ⨆ j, f i j) = ⨆ x : Σ i, κ i, f x.1 x.2 := (iSup_sigma (f := fun x ↦ f x.1 x.2)).symm -lemma iInf_sigma' {κ : β → Type*} (f : ∀ i, κ i → α) : - (⨅ i, ⨅ j, f i j) = ⨅ x : Σ i, κ i, f x.1 x.2 := (iInf_sigma (f := fun x ↦ f x.1 x.2)).symm - +@[to_dual] lemma iSup_psigma {ι : Sort*} {κ : ι → Sort*} (f : (Σ' i, κ i) → α) : ⨆ ij, f ij = ⨆ i, ⨆ j, f ⟨i, j⟩ := eq_of_forall_ge_iff fun c ↦ by simp only [iSup_le_iff, PSigma.forall] -lemma iInf_psigma {ι : Sort*} {κ : ι → Sort*} (f : (Σ' i, κ i) → α) : - ⨅ ij, f ij = ⨅ i, ⨅ j, f ⟨i, j⟩ := - eq_of_forall_le_iff fun c ↦ by simp only [le_iInf_iff, PSigma.forall] - +@[to_dual] lemma iSup_psigma' {ι : Sort*} {κ : ι → Sort*} (f : ∀ i, κ i → α) : (⨆ i, ⨆ j, f i j) = ⨆ ij : Σ' i, κ i, f ij.1 ij.2 := (iSup_psigma fun x ↦ f x.1 x.2).symm -lemma iInf_psigma' {ι : Sort*} {κ : ι → Sort*} (f : ∀ i, κ i → α) : - (⨅ i, ⨅ j, f i j) = ⨅ ij : Σ' i, κ i, f ij.1 ij.2 := (iInf_psigma fun x ↦ f x.1 x.2).symm - +@[to_dual] theorem iSup_prod {f : β × γ → α} : ⨆ x, f x = ⨆ (i) (j), f (i, j) := eq_of_forall_ge_iff fun c => by simp only [iSup_le_iff, Prod.forall] -theorem iInf_prod {f : β × γ → α} : ⨅ x, f x = ⨅ (i) (j), f (i, j) := - @iSup_prod αᵒᵈ _ _ _ _ - +@[to_dual] lemma iSup_prod' (f : β → γ → α) : (⨆ i, ⨆ j, f i j) = ⨆ x : β × γ, f x.1 x.2 := (iSup_prod (f := fun x ↦ f x.1 x.2)).symm -lemma iInf_prod' (f : β → γ → α) : (⨅ i, ⨅ j, f i j) = ⨅ x : β × γ, f x.1 x.2 := -(iInf_prod (f := fun x ↦ f x.1 x.2)).symm - +@[to_dual] theorem biSup_prod {f : β × γ → α} {s : Set β} {t : Set γ} : ⨆ x ∈ s ×ˢ t, f x = ⨆ (a ∈ s) (b ∈ t), f (a, b) := by simp_rw [iSup_prod, mem_prod, iSup_and] exact iSup_congr fun _ => iSup_comm +@[to_dual] theorem biSup_prod' {f : β → γ → α} {s : Set β} {t : Set γ} : ⨆ x ∈ s ×ˢ t, f x.1 x.2 = ⨆ (a ∈ s) (b ∈ t), f a b := biSup_prod -theorem biInf_prod {f : β × γ → α} {s : Set β} {t : Set γ} : - ⨅ x ∈ s ×ˢ t, f x = ⨅ (a ∈ s) (b ∈ t), f (a, b) := - @biSup_prod αᵒᵈ _ _ _ _ _ _ - -theorem biInf_prod' {f : β → γ → α} {s : Set β} {t : Set γ} : - ⨅ x ∈ s ×ˢ t, f x.1 x.2 = ⨅ (a ∈ s) (b ∈ t), f a b := - biInf_prod - +@[to_dual] theorem iSup_image2 {γ δ} (f : β → γ → δ) (s : Set β) (t : Set γ) (g : δ → α) : ⨆ d ∈ image2 f s t, g d = ⨆ b ∈ s, ⨆ c ∈ t, g (f b c) := by rw [← image_prod, iSup_image, biSup_prod] -theorem iInf_image2 {γ δ} (f : β → γ → δ) (s : Set β) (t : Set γ) (g : δ → α) : - ⨅ d ∈ image2 f s t, g d = ⨅ b ∈ s, ⨅ c ∈ t, g (f b c) := - iSup_image2 f s t (toDual ∘ g) - +@[to_dual] theorem iSup_sum {f : β ⊕ γ → α} : ⨆ x, f x = (⨆ i, f (Sum.inl i)) ⊔ ⨆ j, f (Sum.inr j) := eq_of_forall_ge_iff fun c => by simp only [sup_le_iff, iSup_le_iff, Sum.forall] -theorem iInf_sum {f : β ⊕ γ → α} : ⨅ x, f x = (⨅ i, f (Sum.inl i)) ⊓ ⨅ j, f (Sum.inr j) := - @iSup_sum αᵒᵈ _ _ _ _ - +@[to_dual] theorem iSup_option (f : Option β → α) : ⨆ o, f o = f none ⊔ ⨆ b, f (Option.some b) := eq_of_forall_ge_iff fun c => by simp only [iSup_le_iff, sup_le_iff, Option.forall] -theorem iInf_option (f : Option β → α) : ⨅ o, f o = f none ⊓ ⨅ b, f (Option.some b) := - @iSup_option αᵒᵈ _ _ _ - /-- A version of `iSup_option` useful for rewriting right-to-left. -/ +@[to_dual /-- A version of `iInf_option` useful for rewriting right-to-left. -/] theorem iSup_option_elim (a : α) (f : β → α) : ⨆ o : Option β, o.elim a f = a ⊔ ⨆ b, f b := by simp [iSup_option] -/-- A version of `iInf_option` useful for rewriting right-to-left. -/ -theorem iInf_option_elim (a : α) (f : β → α) : ⨅ o : Option β, o.elim a f = a ⊓ ⨅ b, f b := - @iSup_option_elim αᵒᵈ _ _ _ _ - /-- When taking the supremum of `f : ι → α`, the elements of `ι` on which `f` gives `⊥` can be dropped, without changing the result. -/ -@[simp] +@[to_dual /-- When taking the infimum of `f : ι → α`, the elements of `ι` on which `f` gives `⊤` +can be dropped, without changing the result. -/, simp] theorem iSup_ne_bot_subtype (f : ι → α) : ⨆ i : { i // f i ≠ ⊥ }, f i = ⨆ i, f i := by by_cases! htriv : ∀ i, f i = ⊥ · simp only [iSup_bot, (funext htriv : f = _)] @@ -1142,35 +802,24 @@ theorem iSup_ne_bot_subtype (f : ι → α) : ⨆ i : { i // f i ≠ ⊥ }, f i exact ⟨⟨i₀, hi₀⟩, bot_le⟩ · exact ⟨⟨i, hi⟩, rfl.le⟩ -/-- When taking the infimum of `f : ι → α`, the elements of `ι` on which `f` gives `⊤` can be -dropped, without changing the result. -/ -theorem iInf_ne_top_subtype (f : ι → α) : ⨅ i : { i // f i ≠ ⊤ }, f i = ⨅ i, f i := - @iSup_ne_bot_subtype αᵒᵈ ι _ f - +@[to_dual] theorem sSup_image2 {f : β → γ → α} {s : Set β} {t : Set γ} : sSup (image2 f s t) = ⨆ (a ∈ s) (b ∈ t), f a b := by rw [← image_prod, sSup_image, biSup_prod] -theorem sInf_image2 {f : β → γ → α} {s : Set β} {t : Set γ} : - sInf (image2 f s t) = ⨅ (a ∈ s) (b ∈ t), f a b := by rw [← image_prod, sInf_image, biInf_prod] - end section CompleteLinearOrder variable [CompleteLinearOrder α] +@[to_dual] theorem iSup_eq_top (f : ι → α) : iSup f = ⊤ ↔ ∀ b < ⊤, ∃ i, b < f i := by simp only [← sSup_range, sSup_eq_top, Set.exists_range_iff] -theorem iInf_eq_bot (f : ι → α) : iInf f = ⊥ ↔ ∀ b > ⊥, ∃ i, f i < b := by - simp only [← sInf_range, sInf_eq_bot, Set.exists_range_iff] - +@[to_dual] lemma iSup₂_eq_top (f : ∀ i, κ i → α) : ⨆ i, ⨆ j, f i j = ⊤ ↔ ∀ b < ⊤, ∃ i j, b < f i j := by simp_rw [iSup_psigma', iSup_eq_top, PSigma.exists] -lemma iInf₂_eq_bot (f : ∀ i, κ i → α) : ⨅ i, ⨅ j, f i j = ⊥ ↔ ∀ b > ⊥, ∃ i j, f i j < b := by - simp_rw [iInf_psigma', iInf_eq_bot, PSigma.exists] - end CompleteLinearOrder /-! @@ -1208,47 +857,32 @@ theorem iSup_Prop_eq {p : ι → Prop} : ⨆ i, p i = ∃ i, p i := theorem iInf_Prop_eq {p : ι → Prop} : ⨅ i, p i = ∀ i, p i := le_antisymm (fun h i => h _ ⟨i, rfl⟩) fun h _ ⟨i, Eq⟩ => Eq ▸ h i +@[to_dual] instance Pi.supSet {α : Type*} {β : α → Type*} [∀ i, SupSet (β i)] : SupSet (∀ i, β i) := ⟨fun s i => ⨆ f : s, (f : ∀ i, β i) i⟩ -instance Pi.infSet {α : Type*} {β : α → Type*} [∀ i, InfSet (β i)] : InfSet (∀ i, β i) := - ⟨fun s i => ⨅ f : s, (f : ∀ i, β i) i⟩ - -@[simp] +@[to_dual (attr := simp)] theorem sSup_apply {α : Type*} {β : α → Type*} [∀ i, SupSet (β i)] {s : Set (∀ a, β a)} {a : α} : (sSup s) a = ⨆ f : s, (f : ∀ a, β a) a := rfl -@[simp] -theorem sInf_apply {α : Type*} {β : α → Type*} [∀ i, InfSet (β i)] {s : Set (∀ a, β a)} {a : α} : - sInf s a = ⨅ f : s, (f : ∀ a, β a) a := - rfl - +@[to_dual] theorem sSup_apply_eq_sSup_image {α : Type*} {β : α → Type*} [∀ i, SupSet (β i)] {s : Set (∀ a, β a)} {a : α} : sSup s a = sSup (eval a '' s) := by simp [sSup_apply, iSup, image_eq_range] -theorem sInf_apply_eq_sInf_image {α : Type*} {β : α → Type*} [∀ i, InfSet (β i)] - {s : Set (∀ a, β a)} {a : α} : - sInf s a = sInf (eval a '' s) := by - simp [sInf_apply, iInf, image_eq_range] - instance Pi.instCompleteLattice {α : Type*} {β : α → Type*} [∀ i, CompleteLattice (β i)] : CompleteLattice (∀ i, β i) where __ := instBoundedOrder isLUB_sSup _ := isLUB_pi.mpr fun _ ↦ by rw [sSup_apply_eq_sSup_image]; exact isLUB_sSup _ isGLB_sInf _ := isGLB_pi.mpr fun _ ↦ by rw [sInf_apply_eq_sInf_image]; exact isGLB_sInf _ -@[simp] +@[to_dual (attr := simp)] theorem iSup_apply {α : Type*} {β : α → Type*} {ι : Sort*} [∀ i, SupSet (β i)] {f : ι → ∀ a, β a} {a : α} : (⨆ i, f i) a = ⨆ i, f i a := by - rw [iSup, sSup_apply_eq_sSup_image, iSup, ← range_comp]; rfl - -@[simp] -theorem iInf_apply {α : Type*} {β : α → Type*} {ι : Sort*} [∀ i, InfSet (β i)] {f : ι → ∀ a, β a} - {a : α} : (⨅ i, f i) a = ⨅ i, f i a := - @iSup_apply α (fun i => (β i)ᵒᵈ) _ _ _ _ + rw [iSup, sSup_apply, iSup, iSup, ← image_eq_range (fun f : ∀ i, β i => f a) (range f), ← + range_comp]; rfl theorem unary_relation_sSup_iff {α : Type*} (s : Set (α → Prop)) {a : α} : sSup s a ↔ ∃ r ∈ s, r a := by @@ -1270,26 +904,21 @@ section CompleteLattice variable [Preorder α] [CompleteLattice β] {s : Set (α → β)} {f : ι → α → β} +@[to_dual] protected lemma Monotone.sSup (hs : ∀ f ∈ s, Monotone f) : Monotone (sSup s) := fun _ _ h ↦ iSup_mono fun f ↦ hs f f.2 h -protected lemma Monotone.sInf (hs : ∀ f ∈ s, Monotone f) : Monotone (sInf s) := - fun _ _ h ↦ iInf_mono fun f ↦ hs f f.2 h - +@[to_dual] protected lemma Antitone.sSup (hs : ∀ f ∈ s, Antitone f) : Antitone (sSup s) := fun _ _ h ↦ iSup_mono fun f ↦ hs f f.2 h -protected lemma Antitone.sInf (hs : ∀ f ∈ s, Antitone f) : Antitone (sInf s) := - fun _ _ h ↦ iInf_mono fun f ↦ hs f f.2 h - +@[to_dual] protected lemma Monotone.iSup (hf : ∀ i, Monotone (f i)) : Monotone (⨆ i, f i) := Monotone.sSup (by simpa) -protected lemma Monotone.iInf (hf : ∀ i, Monotone (f i)) : Monotone (⨅ i, f i) := - Monotone.sInf (by simpa) + +@[to_dual] protected lemma Antitone.iSup (hf : ∀ i, Antitone (f i)) : Antitone (⨆ i, f i) := Antitone.sSup (by simpa) -protected lemma Antitone.iInf (hf : ∀ i, Antitone (f i)) : Antitone (⨅ i, f i) := - Antitone.sInf (by simpa) end CompleteLattice @@ -1297,56 +926,38 @@ namespace Prod variable (α β) +@[to_dual] instance supSet [SupSet α] [SupSet β] : SupSet (α × β) := ⟨fun s => (sSup (Prod.fst '' s), sSup (Prod.snd '' s))⟩ -instance infSet [InfSet α] [InfSet β] : InfSet (α × β) := - ⟨fun s => (sInf (Prod.fst '' s), sInf (Prod.snd '' s))⟩ - variable {α β} -theorem fst_sInf [InfSet α] [InfSet β] (s : Set (α × β)) : (sInf s).fst = sInf (Prod.fst '' s) := - rfl - -theorem snd_sInf [InfSet α] [InfSet β] (s : Set (α × β)) : (sInf s).snd = sInf (Prod.snd '' s) := - rfl - -theorem swap_sInf [InfSet α] [InfSet β] (s : Set (α × β)) : (sInf s).swap = sInf (Prod.swap '' s) := - Prod.ext (congr_arg sInf <| image_comp Prod.fst swap s) - (congr_arg sInf <| image_comp Prod.snd swap s) - +@[to_dual] theorem fst_sSup [SupSet α] [SupSet β] (s : Set (α × β)) : (sSup s).fst = sSup (Prod.fst '' s) := rfl +@[to_dual] theorem snd_sSup [SupSet α] [SupSet β] (s : Set (α × β)) : (sSup s).snd = sSup (Prod.snd '' s) := rfl +@[to_dual] theorem swap_sSup [SupSet α] [SupSet β] (s : Set (α × β)) : (sSup s).swap = sSup (Prod.swap '' s) := Prod.ext (congr_arg sSup <| image_comp Prod.fst swap s) (congr_arg sSup <| image_comp Prod.snd swap s) -theorem fst_iInf [InfSet α] [InfSet β] (f : ι → α × β) : (iInf f).fst = ⨅ i, (f i).fst := - congr_arg sInf (range_comp _ _).symm - -theorem snd_iInf [InfSet α] [InfSet β] (f : ι → α × β) : (iInf f).snd = ⨅ i, (f i).snd := - congr_arg sInf (range_comp _ _).symm - -theorem swap_iInf [InfSet α] [InfSet β] (f : ι → α × β) : (iInf f).swap = ⨅ i, (f i).swap := by - simp_rw [iInf, swap_sInf, ← range_comp, comp_def] - -theorem iInf_mk [InfSet α] [InfSet β] (f : ι → α) (g : ι → β) : - ⨅ i, (f i, g i) = (⨅ i, f i, ⨅ i, g i) := - congr_arg₂ Prod.mk (fst_iInf _) (snd_iInf _) - +@[to_dual] theorem fst_iSup [SupSet α] [SupSet β] (f : ι → α × β) : (iSup f).fst = ⨆ i, (f i).fst := congr_arg sSup (range_comp _ _).symm +@[to_dual] theorem snd_iSup [SupSet α] [SupSet β] (f : ι → α × β) : (iSup f).snd = ⨆ i, (f i).snd := congr_arg sSup (range_comp _ _).symm +@[to_dual] theorem swap_iSup [SupSet α] [SupSet β] (f : ι → α × β) : (iSup f).swap = ⨆ i, (f i).swap := by simp_rw [iSup, swap_sSup, ← range_comp, comp_def] +@[to_dual] theorem iSup_mk [SupSet α] [SupSet β] (f : ι → α) (g : ι → β) : ⨆ i, (f i, g i) = (⨆ i, f i, ⨆ i, g i) := congr_arg₂ Prod.mk (fst_iSup _) (snd_iSup _) @@ -1358,10 +969,7 @@ instance instCompleteLattice [CompleteLattice α] [CompleteLattice β] : Complet end Prod -lemma sInf_prod [InfSet α] [InfSet β] {s : Set α} {t : Set β} (hs : s.Nonempty) (ht : t.Nonempty) : - sInf (s ×ˢ t) = (sInf s, sInf t) := -congr_arg₂ Prod.mk (congr_arg sInf <| fst_image_prod _ ht) (congr_arg sInf <| snd_image_prod hs _) - +@[to_dual] lemma sSup_prod [SupSet α] [SupSet β] {s : Set α} {t : Set β} (hs : s.Nonempty) (ht : t.Nonempty) : sSup (s ×ˢ t) = (sSup s, sSup t) := congr_arg₂ Prod.mk (congr_arg sSup <| fst_image_prod _ ht) (congr_arg sSup <| snd_image_prod hs _) diff --git a/Mathlib/Order/CompleteLattice/Defs.lean b/Mathlib/Order/CompleteLattice/Defs.lean index be394f3e71d233..b1fea3079e4abe 100644 --- a/Mathlib/Order/CompleteLattice/Defs.lean +++ b/Mathlib/Order/CompleteLattice/Defs.lean @@ -293,12 +293,11 @@ section CompleteLinearOrder variable [CompleteLinearOrder α] {s : Set α} {a b : α} +@[to_dual sInf_lt_iff] theorem lt_sSup_iff : b < sSup s ↔ ∃ a ∈ s, b < a := lt_isLUB_iff <| isLUB_sSup s -theorem sInf_lt_iff : sInf s < b ↔ ∃ a ∈ s, a < b := - isGLB_lt_iff <| isGLB_sInf s - +@[to_dual] theorem sSup_eq_top : sSup s = ⊤ ↔ ∀ b < ⊤, ∃ a ∈ s, b < a := ⟨fun h _ hb => lt_sSup_iff.1 <| hb.trans_eq h.symm, fun h => top_unique <| @@ -306,21 +305,14 @@ theorem sSup_eq_top : sSup s = ⊤ ↔ ∀ b < ⊤, ∃ a ∈ s, b < a := let ⟨_, ha, h⟩ := h _ h' (h.trans_le <| le_sSup ha).false⟩ -theorem sInf_eq_bot : sInf s = ⊥ ↔ ∀ b > ⊥, ∃ a ∈ s, a < b := - @sSup_eq_top αᵒᵈ _ _ - +@[to_dual iInf_lt_iff] theorem lt_iSup_iff {f : ι → α} : a < iSup f ↔ ∃ i, a < f i := lt_sSup_iff.trans exists_range_iff -theorem iInf_lt_iff {f : ι → α} : iInf f < a ↔ ∃ i, f i < a := - sInf_lt_iff.trans exists_range_iff - +@[to_dual] theorem lt_biSup_iff {s : Set β} {f : β → α} : a < ⨆ i ∈ s, f i ↔ ∃ i ∈ s, a < f i := by simp [lt_iSup_iff] -theorem biInf_lt_iff {s : Set β} {f : β → α} : ⨅ i ∈ s, f i < a ↔ ∃ i ∈ s, f i < a := by - simp [iInf_lt_iff] - end CompleteLinearOrder end diff --git a/Mathlib/Order/Filter/Bases/Basic.lean b/Mathlib/Order/Filter/Bases/Basic.lean index f6b4f1e335c357..8580820f544eb9 100644 --- a/Mathlib/Order/Filter/Bases/Basic.lean +++ b/Mathlib/Order/Filter/Bases/Basic.lean @@ -430,12 +430,7 @@ theorem hasBasis_biInf_of_directed' {ι : Type*} {ι' : ι → Sort _} {dom : Se s ii'.1 ii'.2 := by refine ⟨fun t => ?_⟩ rw [mem_biInf_of_directed h hdom, Sigma.exists] - refine exists_congr fun i => ⟨?_, ?_⟩ - · rintro ⟨hi, hti⟩ - rcases (hl i hi).mem_iff.mp hti with ⟨b, hb, hbt⟩ - exact ⟨b, ⟨hi, hb⟩, hbt⟩ - · rintro ⟨b, ⟨hi, hb⟩, hibt⟩ - exact ⟨hi, (hl i hi).mem_iff.mpr ⟨b, hb, hibt⟩⟩ + grind +splitIndPred theorem hasBasis_biInf_of_directed {ι : Type*} {ι' : Sort _} {dom : Set ι} (hdom : dom.Nonempty) {l : ι → Filter α} (s : ι → ι' → Set α) (p : ι → ι' → Prop) @@ -444,12 +439,7 @@ theorem hasBasis_biInf_of_directed {ι : Type*} {ι' : Sort _} {dom : Set ι} (h s ii'.1 ii'.2 := by refine ⟨fun t => ?_⟩ rw [mem_biInf_of_directed h hdom, Prod.exists] - refine exists_congr fun i => ⟨?_, ?_⟩ - · rintro ⟨hi, hti⟩ - rcases (hl i hi).mem_iff.mp hti with ⟨b, hb, hbt⟩ - exact ⟨b, ⟨hi, hb⟩, hbt⟩ - · rintro ⟨b, ⟨hi, hb⟩, hibt⟩ - exact ⟨hi, (hl i hi).mem_iff.mpr ⟨b, hb, hibt⟩⟩ + grind +splitIndPred lemma hasBasis_top : (⊤ : Filter α).HasBasis (fun _ : Unit ↦ True) (fun _ ↦ Set.univ) := diff --git a/Mathlib/Order/Filter/Basic.lean b/Mathlib/Order/Filter/Basic.lean index e57bdf046377c2..4c785e2440a714 100644 --- a/Mathlib/Order/Filter/Basic.lean +++ b/Mathlib/Order/Filter/Basic.lean @@ -982,8 +982,9 @@ theorem EventuallyEq.prodMk {l} {f f' : α → β} (hf : f =ᶠ[l] f') {g g' : intros simp only [*] --- See `EventuallyEq.comp_tendsto` further below for a similar statement w.r.t. --- composition on the right. +/-- See `EventuallyEq.comp_tendsto` in Mathlib.Order.Filter.Tendsto for a similar statement w.r.t. +composition on the right. -/ +@[gcongr] theorem EventuallyEq.fun_comp {f g : α → β} {l : Filter α} (H : f =ᶠ[l] g) (h : β → γ) : h ∘ f =ᶠ[l] h ∘ g := H.mono fun _ hx => congr_arg h hx diff --git a/Mathlib/Order/Filter/Germ/Basic.lean b/Mathlib/Order/Filter/Germ/Basic.lean index f3a9185fcbeb28..4e8ba5f2ac5edb 100644 --- a/Mathlib/Order/Filter/Germ/Basic.lean +++ b/Mathlib/Order/Filter/Germ/Basic.lean @@ -66,7 +66,7 @@ variable {α β γ δ : Type*} {l : Filter α} {f g h : α → β} theorem const_eventuallyEq' [NeBot l] {a b : β} : (∀ᶠ _ in l, a = b) ↔ a = b := eventually_const -theorem const_eventuallyEq [NeBot l] {a b : β} : ((fun _ => a) =ᶠ[l] fun _ => b) ↔ a = b := +@[simp] theorem const_eventuallyEq [NeBot l] {a b : β} : ((fun _ => a) =ᶠ[l] fun _ => b) ↔ a = b := @const_eventuallyEq' _ _ _ _ a b /-- Setoid used to define the space of germs. -/ diff --git a/Mathlib/Order/Heyting/Basic.lean b/Mathlib/Order/Heyting/Basic.lean index bd0d91aad97306..68ce150d96281a 100644 --- a/Mathlib/Order/Heyting/Basic.lean +++ b/Mathlib/Order/Heyting/Basic.lean @@ -144,6 +144,7 @@ class GeneralizedHeytingAlgebra (α : Type*) extends Lattice α, OrderTop α, HI difference operation `\` such that `(· \ a)` is left adjoint to `(· ⊔ a)`. This generalizes `CoheytingAlgebra` by not requiring a top element. -/ +@[to_dual] class GeneralizedCoheytingAlgebra (α : Type*) extends Lattice α, OrderBot α, SDiff α where /-- `(· \ a)` is left adjoint to `(· ⊔ a)` -/ sdiff_le_iff (a b c : α) : a \ b ≤ c ↔ a ≤ b ⊔ c @@ -156,6 +157,7 @@ class HeytingAlgebra (α : Type*) extends GeneralizedHeytingAlgebra α, OrderBot /-- A co-Heyting algebra is a bounded lattice with an additional binary difference operation `\` such that `(· \ a)` is left adjoint to `(· ⊔ a)`. -/ +@[to_dual] class CoheytingAlgebra (α : Type*) extends GeneralizedCoheytingAlgebra α, OrderTop α, HNot α where /-- `⊤ \ a` is `¬a` -/ top_sdiff (a : α) : ⊤ \ a = ¬a @@ -172,14 +174,12 @@ attribute [instance 100] GeneralizedHeytingAlgebra.toOrderTop attribute [instance 100] GeneralizedCoheytingAlgebra.toOrderBot -- See note [lower instance priority] +@[to_dual] instance (priority := 100) HeytingAlgebra.toBoundedOrder [HeytingAlgebra α] : BoundedOrder α := { bot_le := ‹HeytingAlgebra α›.bot_le } -- See note [lower instance priority] -instance (priority := 100) CoheytingAlgebra.toBoundedOrder [CoheytingAlgebra α] : BoundedOrder α := - { ‹CoheytingAlgebra α› with } - --- See note [lower instance priority] +@[to_dual existing] instance (priority := 100) BiheytingAlgebra.toCoheytingAlgebra [BiheytingAlgebra α] : CoheytingAlgebra α := { ‹BiheytingAlgebra α› with } diff --git a/Mathlib/Order/Hom/Basic.lean b/Mathlib/Order/Hom/Basic.lean index 1508d7c71c123d..eb4d58b4029ac5 100644 --- a/Mathlib/Order/Hom/Basic.lean +++ b/Mathlib/Order/Hom/Basic.lean @@ -8,6 +8,7 @@ module public import Mathlib.Order.Disjoint public import Mathlib.Order.RelIso.Basic public import Mathlib.Tactic.Monotonicity.Attr +public import Mathlib.Tactic.PPWithUniv /-! # Order homomorphisms diff --git a/Mathlib/Order/Interval/Set/LinearOrder.lean b/Mathlib/Order/Interval/Set/LinearOrder.lean index 26a2a8cf18a9d7..8d285c80970286 100644 --- a/Mathlib/Order/Interval/Set/LinearOrder.lean +++ b/Mathlib/Order/Interval/Set/LinearOrder.lean @@ -40,46 +40,26 @@ theorem compl_Iic : (Iic a)ᶜ = Ioi a := theorem compl_Iio : (Iio a)ᶜ = Ici a := ext fun _ => not_lt -@[simp] +@[to_dual (attr := simp)] theorem Ici_diff_Ici : Ici a \ Ici b = Ico a b := by rw [diff_eq, compl_Ici, Ici_inter_Iio] -@[simp] +@[to_dual (attr := simp)] theorem Ici_diff_Ioi : Ici a \ Ioi b = Icc a b := by rw [diff_eq, compl_Ioi, Ici_inter_Iic] -@[simp] +@[to_dual (attr := simp)] theorem Ioi_diff_Ioi : Ioi a \ Ioi b = Ioc a b := by rw [diff_eq, compl_Ioi, Ioi_inter_Iic] -@[simp] +@[to_dual (attr := simp)] theorem Ioi_diff_Ici : Ioi a \ Ici b = Ioo a b := by rw [diff_eq, compl_Ici, Ioi_inter_Iio] -@[simp] -theorem Iic_diff_Iic : Iic b \ Iic a = Ioc a b := by - rw [diff_eq, compl_Iic, inter_comm, Ioi_inter_Iic] - -@[simp] -theorem Iio_diff_Iic : Iio b \ Iic a = Ioo a b := by - rw [diff_eq, compl_Iic, inter_comm, Ioi_inter_Iio] - -@[simp] -theorem Iic_diff_Iio : Iic b \ Iio a = Icc a b := by - rw [diff_eq, compl_Iio, inter_comm, Ici_inter_Iic] - -@[simp] -theorem Iio_diff_Iio : Iio b \ Iio a = Ico a b := by - rw [diff_eq, compl_Iio, inter_comm, Ici_inter_Iio] - +@[to_dual] theorem Ioi_injective : Injective (Ioi : α → Set α) := fun _ _ => eq_of_forall_gt_iff ∘ Set.ext_iff.1 -theorem Iio_injective : Injective (Iio : α → Set α) := fun _ _ => - eq_of_forall_lt_iff ∘ Set.ext_iff.1 - +@[to_dual] theorem Ioi_inj : Ioi a = Ioi b ↔ a = b := Ioi_injective.eq_iff -theorem Iio_inj : Iio a = Iio b ↔ a = b := - Iio_injective.eq_iff - theorem Ico_subset_Ico_iff (h₁ : a₁ < b₁) : Ico a₁ b₁ ⊆ Ico a₂ b₂ ↔ a₂ ≤ a₁ ∧ b₁ ≤ b₂ := ⟨fun h => have : a₂ ≤ a₁ ∧ a₁ < b₂ := h ⟨le_rfl, h₁⟩ @@ -112,6 +92,7 @@ theorem Ioo_subset_Ioo_iff [DenselyOrdered α] (h₁ : a₁ < b₁) : exact lt_irrefl _ (h ⟨ab, h'⟩).2, fun ⟨h₁, h₂⟩ => Ioo_subset_Ioo h₁ h₂⟩ +@[to_dual] lemma Ici_eq_singleton_iff_isTop {x : α} : (Ici x = {x}) ↔ IsTop x := by refine ⟨fun h y ↦ ?_, fun h ↦ by ext y; simp [(h y).ge_iff_eq]⟩ by_contra! H @@ -119,41 +100,25 @@ lemma Ici_eq_singleton_iff_isTop {x : α} : (Ici x = {x}) ↔ IsTop x := by rw [h, mem_singleton_iff] at this exact lt_irrefl y (this.le.trans_lt H) -@[simp] +@[to_dual (attr := simp)] theorem Ioi_subset_Ioi_iff : Ioi b ⊆ Ioi a ↔ a ≤ b := by refine ⟨fun h => ?_, Ioi_subset_Ioi⟩ by_contra ba exact lt_irrefl _ (h (not_le.mp ba)) -@[simp] +@[to_dual (attr := simp)] theorem Ioi_ssubset_Ioi_iff : Ioi b ⊂ Ioi a ↔ a < b := by refine ⟨fun h => ?_, Ioi_ssubset_Ioi⟩ obtain ⟨_, c, ac, cb⟩ := ssubset_iff_exists.mp h exact ac.trans_le (le_of_not_gt cb) -@[simp] +@[to_dual (attr := simp)] theorem Ioi_subset_Ici_iff [DenselyOrdered α] : Ioi b ⊆ Ici a ↔ a ≤ b := by refine ⟨fun h => ?_, Ioi_subset_Ici⟩ by_contra ba obtain ⟨c, bc, ca⟩ : ∃ c, b < c ∧ c < a := exists_between (not_le.mp ba) exact lt_irrefl _ (ca.trans_le (h bc)) -@[simp] -theorem Iio_subset_Iio_iff : Iio a ⊆ Iio b ↔ a ≤ b := by - refine ⟨fun h => ?_, Iio_subset_Iio⟩ - by_contra ab - exact lt_irrefl _ (h (not_le.mp ab)) - -@[simp] -theorem Iio_ssubset_Iio_iff : Iio a ⊂ Iio b ↔ a < b := by - refine ⟨fun h => ?_, Iio_ssubset_Iio⟩ - obtain ⟨_, c, cb, ac⟩ := ssubset_iff_exists.mp h - exact (le_of_not_gt ac).trans_lt cb - -@[simp] -theorem Iio_subset_Iic_iff [DenselyOrdered α] : Iio a ⊆ Iic b ↔ a ≤ b := by - rw [← diff_eq_empty, Iio_diff_Iic, Ioo_eq_empty_iff, not_lt] - /-! ### Two infinite intervals -/ @[to_dual] @@ -498,35 +463,26 @@ theorem Ioo_subset_Ioo_union_Ioo (h₁ : a ≤ a₁) (h₂ : c < b) (h₃ : b₁ /-! ### Intersection, difference, complement -/ -@[simp] +@[to_dual (attr := simp)] theorem Ioi_inter_Ioi : Ioi a ∩ Ioi b = Ioi (a ⊔ b) := ext fun _ => sup_lt_iff.symm -@[simp] -theorem Iio_inter_Iio : Iio a ∩ Iio b = Iio (a ⊓ b) := - ext fun _ => lt_inf_iff.symm - +@[to_dual] theorem Ico_inter_Ico : Ico a₁ b₁ ∩ Ico a₂ b₂ = Ico (a₁ ⊔ a₂) (b₁ ⊓ b₂) := by grind -theorem Ioc_inter_Ioc : Ioc a₁ b₁ ∩ Ioc a₂ b₂ = Ioc (a₁ ⊔ a₂) (b₁ ⊓ b₂) := by - grind - +@[to_dual self] theorem Ioo_inter_Ioo : Ioo a₁ b₁ ∩ Ioo a₂ b₂ = Ioo (a₁ ⊔ a₂) (b₁ ⊓ b₂) := by grind +@[to_dual] theorem Ioo_inter_Iio : Ioo a b ∩ Iio c = Ioo a (min b c) := by grind +@[to_dual] theorem Iio_inter_Ioo : Iio a ∩ Ioo b c = Ioo b (min a c) := by grind -theorem Ioo_inter_Ioi : Ioo a b ∩ Ioi c = Ioo (max a c) b := by - grind - -theorem Ioi_inter_Ioo : Set.Ioi a ∩ Set.Ioo b c = Set.Ioo (max a b) c := by - grind - theorem Ioc_inter_Ioo_of_left_lt (h : b₁ < b₂) : Ioc a₁ b₁ ∩ Ioo a₂ b₂ = Ioc (max a₁ a₂) b₁ := by grind @@ -565,6 +521,10 @@ theorem compl_Ioc : (Ioc a b)ᶜ = Iic a ∪ Ioi b := by theorem Iic_diff_Ioc : Iic b \ Ioc a b = Iic (a ⊓ b) := by grind +@[simp] +theorem Ioi_diff_Ioc : Ioi a \ Ioc a b = Ioi (max a b) := by + grind + theorem Iic_diff_Ioc_self_of_le (hab : a ≤ b) : Iic b \ Ioc a b = Iic a := by grind diff --git a/Mathlib/Order/IsNormal.lean b/Mathlib/Order/IsNormal.lean index 70985261e08d5b..c51faa0e9e6ac8 100644 --- a/Mathlib/Order/IsNormal.lean +++ b/Mathlib/Order/IsNormal.lean @@ -107,6 +107,7 @@ theorem comp (hg : IsNormal g) (hf : IsNormal f) : IsNormal (g ∘ f) := by simpa [hg.le_iff_forall_le (hf.map_isSuccLimit ha), hf.lt_iff_exists_lt ha] using fun c d hd hc ↦ (hg.strictMono hc).le.trans (hb hd) +/-- Restrict a normal function `α → β` to a normal function `Iio a → Iio (f a)`. -/ theorem to_Iio (hf : IsNormal f) (a : α) : IsNormal (β := Iio (f a)) fun x : Iio a ↦ ⟨f x.1, hf.strictMono x.2⟩ := by rw [isNormal_iff] diff --git a/Mathlib/Order/RelClasses.lean b/Mathlib/Order/RelClasses.lean index 7b0640df822909..e443cc98b3fbdb 100644 --- a/Mathlib/Order/RelClasses.lean +++ b/Mathlib/Order/RelClasses.lean @@ -256,7 +256,14 @@ theorem wellFoundedGT_dual_iff (α : Type*) [LT α] : WellFoundedGT αᵒᵈ ↔ /-- A well order is a well-founded linear order. -/ class IsWellOrder (α : Type u) (r : α → α → Prop) : Prop - extends Std.Trichotomous r, IsTrans α r, IsWellFounded α r + extends IsWellFounded α r, Std.Trichotomous r + +instance (r) [IsWellOrder α r] : IsTrans α r where + trans a b c hab hbc := by + rcases trichotomous_of r a c with (hac | rfl | hca) + · exact hac + · exact asymm_of r hab hbc |>.elim + · exact IsWellFounded.wf.asymmetric₃ a b c hab hbc hca |>.elim -- see Note [lower instance priority] instance (priority := 100) {α} (r : α → α → Prop) [IsWellOrder α r] : @@ -312,20 +319,17 @@ def IsWellOrder.toHasWellFounded [LT α] [hwo : IsWellOrder α (· < ·)] : Well wf := hwo.wf -- This isn't made into an instance as it loops with `Std.Irrefl r`. -theorem Subsingleton.isWellOrder [Subsingleton α] (r : α → α → Prop) [hr : Std.Irrefl r] : - IsWellOrder α r := - { hr with - trichotomous := fun a b _ _ ↦ Subsingleton.elim a b, - trans := fun a b _ h => (not_rel_of_subsingleton r a b h).elim, - wf := ⟨fun a => ⟨_, fun y h => (not_rel_of_subsingleton r y a h).elim⟩⟩ } +theorem Subsingleton.isWellOrder [Subsingleton α] (r : α → α → Prop) [Std.Irrefl r] : + IsWellOrder α r where + wf := .intro fun a ↦ ⟨_, fun y h ↦ not_rel_of_subsingleton r y a h |>.elim⟩ + trichotomous a b _ _ := Subsingleton.elim a b instance [Subsingleton α] : IsWellOrder α emptyRelation := Subsingleton.isWellOrder _ instance (priority := 100) [IsEmpty α] (r : α → α → Prop) : IsWellOrder α r where - trichotomous := isEmptyElim - trans := isEmptyElim wf := wellFounded_of_isEmpty r + trichotomous := isEmptyElim instance Prod.Lex.instIsWellFounded [IsWellFounded α r] [IsWellFounded β s] : IsWellFounded (α × β) (Prod.Lex r s) := @@ -338,10 +342,6 @@ instance [IsWellOrder α r] [IsWellOrder β s] : IsWellOrder (α × β) (Prod.Le obtain rfl := Std.Trichotomous.trichotomous a₂ b₂ (mt (Prod.Lex.right a₁) hab) (mt (Prod.Lex.right a₁) hba) rfl - trans a b c h₁ h₂ := by - rcases h₁ with ⟨a₂, b₂, ab⟩ | ⟨a₁, ab⟩ <;> rcases h₂ with ⟨c₁, c₂, bc⟩ | ⟨c₂, bc⟩ - exacts [.left _ _ (_root_.trans ab bc), .left _ _ ab, .left _ _ bc, - .right _ (_root_.trans ab bc)] instance (r : α → α → Prop) [IsWellFounded α r] (f : β → α) : IsWellFounded _ (InvImage r f) := ⟨InvImage.wf f IsWellFounded.wf⟩ diff --git a/Mathlib/Order/RelIso/Basic.lean b/Mathlib/Order/RelIso/Basic.lean index 1999897997b33d..1db1ab857c77d3 100644 --- a/Mathlib/Order/RelIso/Basic.lean +++ b/Mathlib/Order/RelIso/Basic.lean @@ -392,8 +392,8 @@ def Quotient.mkRelHom {_ : Setoid α} {r : α → α → Prop} @[simps!] noncomputable def Quotient.outRelEmbedding {_ : Setoid α} {r : α → α → Prop} (H : ∀ (a₁ b₁ a₂ b₂ : α), a₁ ≈ a₂ → b₁ ≈ b₂ → r a₁ b₁ = r a₂ b₂) : Quotient.lift₂ r H ↪r r := - ⟨Embedding.quotientOut α, by - refine @fun x y => Quotient.inductionOn₂ x y fun a b => ?_ + ⟨Embedding.quotientOut α, fun {x y} ↦ by + induction x, y using Quotient.inductionOn₂ apply iff_iff_eq.2 (H _ _ _ _ _ _) <;> apply Quotient.mk_out⟩ @[simp] diff --git a/Mathlib/Probability/CondVar.lean b/Mathlib/Probability/CondVar.lean index 9261c0b82c11f2..287665ed244df8 100644 --- a/Mathlib/Probability/CondVar.lean +++ b/Mathlib/Probability/CondVar.lean @@ -155,6 +155,7 @@ lemma condVar_bot_ae_eq (X : Ω → ℝ) : exact eventually_bot · exact .of_forall <| congr_fun (condVar_bot' X) +@[simp] lemma condVar_bot [IsProbabilityMeasure μ] (hX : AEMeasurable X μ) : Var[X; μ | ⊥] = fun _ω ↦ Var[X; μ] := by simp [condVar_bot', average_eq_integral, variance_eq_integral hX] diff --git a/Mathlib/Probability/Distributions/Binomial.lean b/Mathlib/Probability/Distributions/Binomial.lean new file mode 100644 index 00000000000000..e99b93aad2f95a --- /dev/null +++ b/Mathlib/Probability/Distributions/Binomial.lean @@ -0,0 +1,86 @@ +/- +Copyright (c) 2025 Yaël Dillies. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yaël Dillies +-/ +module + +public import Mathlib.Probability.CondVar +public import Mathlib.Probability.Distributions.SetBernoulli +public import Mathlib.Probability.Moments.Variance +public import Mathlib.Probability.HasLaw + +import Mathlib.MeasureTheory.MeasurableSpace.NCard +import Mathlib.Order.Interval.Set.Nat +import Mathlib.Probability.Distributions.TwoValued +import Mathlib.Probability.Notation + +/-! +# Binomial random variables + +This file defines the binomial distribution and binomial random variables, +and computes their expectation and variance. + +## Main definitions + +* `ProbabilityTheory.binomial`: + Binomial distribution on an arbitrary semiring with parameters `n` and `p`. + +## Notation + +`Bin(n, p)` is the binomial distribution with parameters `n` and `p` in `ℕ`. +`Bin(R, n, p)` is the binomial distribution with parameters `n` and `p` in `R`. +-/ + +public section + +open MeasureTheory +open scoped NNReal ProbabilityTheory unitInterval + +namespace ProbabilityTheory +variable {R Ω : Type*} [MeasurableSpace R] [AddMonoidWithOne R] {m : MeasurableSpace Ω} + {P : Measure Ω} {X : Ω → R} {n : ℕ} {p : I} + +/-- The binomial probability distribution with parameter `p`. -/ +@[expose] +noncomputable def binomial (n : ℕ) (p : I) : Measure ℕ := setBer(Set.Iio n, p).map Set.ncard + +/-- The binomial probability distribution with parameter `p`. -/ +scoped notation3 "Bin(" n ", " p ")" => binomial n p + +/-- The binomial probability distribution with parameter `p` valued in the semiring `R`. -/ +scoped notation3 "Bin(" R ", " n ", " p ")" => (binomial n p).map (Nat.cast : ℕ → R) + +instance isProbabilityMeasure_binomial : IsProbabilityMeasure Bin(n, p) := + Measure.isProbabilityMeasure_map <| by fun_prop + +lemma ae_le_of_hasLaw_binomial {X : Ω → ℕ} (hX : HasLaw X Bin(n, p) P) : ∀ᵐ ω ∂P, X ω ≤ n := by + rw [hX.ae_iff (p := (· ≤ n)) <| by fun_prop, binomial, + ae_map_iff (by fun_prop) (Set.finite_Iic _).measurableSet] + filter_upwards [setBernoulli_ae_subset] with s hs + simpa using Set.ncard_le_ncard hs + +/-! ### Binomial random variables -/ + +variable {X : Ω → ℝ} + +/-- **Expectation of a binomial random variable**. + +The expectation of a binomial random variable with parameters `n` and `p` is `pn`. -/ +proof_wanted integral_of_hasLaw_binomial (hX : HasLaw X Bin(ℝ, n, p) P) : P[X] = p.val * n + +/-- **Variance of a binomial random variable**. + +The variance of a binomial random variable with parameters `n` and `p` is `p(1 - p)n`. -/ +proof_wanted variance_of_hasLaw_binomial (hX : HasLaw X Bin(ℝ, n, p) P) : + Var[X; P] = p * (1 - p) * n + +/-- **Conditional variance of a binomial random variable**. + +The conditional variance of a binomial random variable is the product of the conditional +probabilities that it's equal to `0` and that it's equal to `1`. -/ +proof_wanted condVar_of_hasLaw_binomial {m₀ : MeasurableSpace Ω} (hm : m ≤ m₀) {P : Measure[m₀] Ω} + (hX : HasLaw X Bin(ℝ, n, p) P) : + Var[X; P | m] =ᵐ[P] P[X | m] * P[1 - X | m] + +end ProbabilityTheory diff --git a/Mathlib/Probability/Distributions/Gaussian/IsGaussianProcess/Independence.lean b/Mathlib/Probability/Distributions/Gaussian/IsGaussianProcess/Independence.lean index fe0a12387a8f16..b790e91ebfad67 100644 --- a/Mathlib/Probability/Distributions/Gaussian/IsGaussianProcess/Independence.lean +++ b/Mathlib/Probability/Distributions/Gaussian/IsGaussianProcess/Independence.lean @@ -10,7 +10,7 @@ public import Mathlib.Probability.Distributions.Gaussian.IsGaussianProcess.Def import Mathlib.Probability.Distributions.Gaussian.HasGaussianLaw.Basic import Mathlib.Probability.Distributions.Gaussian.HasGaussianLaw.Independence import Mathlib.Probability.Distributions.Gaussian.IsGaussianProcess.Basic -import Mathlib.Probability.Independence.Process +import Mathlib.Probability.Independence.Process.Basic /-! # Independence of Gaussian processes diff --git a/Mathlib/Probability/Distributions/Gaussian/Multivariate.lean b/Mathlib/Probability/Distributions/Gaussian/Multivariate.lean index 500cafd39e6d34..777a7d08aa5875 100644 --- a/Mathlib/Probability/Distributions/Gaussian/Multivariate.lean +++ b/Mathlib/Probability/Distributions/Gaussian/Multivariate.lean @@ -115,7 +115,6 @@ instance isGaussian_stdGaussian : IsGaussian (stdGaussian E) := by lemma integral_strongDual_stdGaussian (L : StrongDual ℝ E) : (stdGaussian E)[L] = 0 := by rw [L.integral_comp_id_comm IsGaussian.integrable_id, integral_id_stdGaussian, map_zero] -set_option backward.isDefEq.respectTransparency false in lemma charFunDual_stdGaussian (L : StrongDual ℝ E) : charFunDual (stdGaussian E) L = exp (- ‖L‖ ^ 2 / 2) := by simp [IsGaussian.charFunDual_eq, integral_complex_ofReal, variance_dual_stdGaussian, neg_div] diff --git a/Mathlib/Probability/Distributions/TwoValued.lean b/Mathlib/Probability/Distributions/TwoValued.lean new file mode 100644 index 00000000000000..37fd9b9cd5d69a --- /dev/null +++ b/Mathlib/Probability/Distributions/TwoValued.lean @@ -0,0 +1,101 @@ +/- +Copyright (c) 2024 Yaël Dillies. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yaël Dillies +-/ +module + +public import Mathlib.MeasureTheory.Integral.Bochner.Basic +public import Mathlib.Probability.CondVar + +import Mathlib.Probability.Notation + +/-! +# Distributions on two values + +This file proves a few lemmas about random variables that take at most two values. +-/ + +public section + +open MeasureTheory +open scoped ProbabilityTheory + +namespace MeasureTheory +variable {Ω : Type*} {m : MeasurableSpace Ω} {X : Ω → ℝ} {μ : Measure Ω} + +/-- If an `AEMeasurable` function is ae equal to `0` or `1`, then its integral is equal to the +measure of the set where it equals `1`. -/ +lemma integral_of_ae_eq_zero_or_one (hXmeas : AEMeasurable X μ) (hX : ∀ᵐ ω ∂μ, X ω = 0 ∨ X ω = 1) : + μ[X] = μ.real {ω | X ω = 1} := by + refine (integral_map (f := id) hXmeas <| by fun_prop).symm.trans ?_ + rw [(Measure.ae_eq_or_eq_iff_map_eq_dirac_add_dirac hXmeas zero_ne_one).1 hX] + by_cases h : μ {ω | X ω = 1} = ⊤ + · simp [h, Measure.real, Set.preimage, integral_undef, Integrable, HasFiniteIntegral] + rw [integral_add_measure ⟨by fun_prop, by simp [HasFiniteIntegral]⟩ <| + .smul_measure (by simp [integrable_dirac]) h] + simp [Measure.real, Set.preimage] + +/-- If a random variable is ae equal to `0` or `1`, then one minus its expectation is equal to the +probability that it equals `0`. -/ +lemma integral_one_sub_of_ae_eq_zero_or_one (hXmeas : AEMeasurable X μ) + (hX : ∀ᵐ ω ∂μ, X ω = 0 ∨ X ω = 1) : ∫ ω, 1 - X ω ∂μ = μ.real {ω | X ω = 0} := by + calc + _ = μ.real {ω | 1 - X ω = 1} := + integral_of_ae_eq_zero_or_one (aemeasurable_const (b := 1).sub hXmeas) + (by simpa [sub_eq_zero, or_comm, eq_comm (a := (1 : ℝ))] using hX) + _ = μ.real {ω | X ω = 0} := by simp + +end MeasureTheory + + +namespace ProbabilityTheory +variable {Ω : Type*} {m : MeasurableSpace Ω} {X Y : Ω → ℝ} {μ : Measure ℝ} {P : Measure Ω} + +/-- If a random variable is ae equal to `0` or `1`, then its conditional variance is the product of +the conditional probabilities that it's equal to `0` and that it's equal to `1`. -/ +lemma condVar_of_ae_eq_zero_or_one {m₀ : MeasurableSpace Ω} (hm : m ≤ m₀) {μ : Measure[m₀] Ω} + [IsFiniteMeasure μ] (hXmeas : AEMeasurable[m₀] X μ) (hX : ∀ᵐ ω ∂μ, X ω = 0 ∨ X ω = 1) : + Var[X; μ | m] =ᵐ[μ] μ[X | m] * μ[1 - X | m] := by + wlog hXmeas : Measurable[m₀] X + · obtain ⟨Y, hYmeas, hXY⟩ := ‹AEMeasurable[m₀] X μ› + calc + Var[X; μ | m] + _ =ᵐ[μ] Var[Y; μ | m] := condVar_congr_ae hXY + _ =ᵐ[μ] μ[Y | m] * μ[1 - Y | m] := by + refine this hm hYmeas.aemeasurable ?_ hYmeas + filter_upwards [hX, hXY] with ω hXω hXYω + simp [hXω, ← hXYω] + _ =ᵐ[μ] μ[X | m] * μ[1 - X | m] := by + refine .mul ?_ ?_ <;> + exact condExp_congr_ae <| by filter_upwards [hXY] with ω hω; simp [hω] + calc + _ =ᵐ[μ] μ[X ^ 2 | m] - μ[X | m] ^ 2 := + condVar_ae_eq_condExp_sq_sub_sq_condExp hm <| .of_bound hXmeas.aestronglyMeasurable 1 <| by + filter_upwards [hX]; rintro ω (hω | hω) <;> simp [hω] + _ =ᵐ[μ] μ[X | m] - μ[X | m] ^ 2 := by + refine .sub ?_ ae_eq_rfl + exact condExp_congr_ae <| by filter_upwards [hX]; rintro ω (hω | hω) <;> simp [hω] + _ =ᵐ[μ] μ[X | m] * μ[1 - X | m] := by + rw [sq, ← one_sub_mul, mul_comm] + refine .mul ae_eq_rfl ?_ + calc + 1 - μ[X | m] + _ = μ[1 | m] - μ[X | m] := by simp [Pi.one_def, hm] + _ =ᵐ[μ] μ[1 - X | m] := by + refine (condExp_sub (integrable_const _) + (.of_bound (C := 1) hXmeas.aestronglyMeasurable ?_) _).symm + filter_upwards [hX] + rintro ω (hω | hω) <;> simp [hω] + +/-- If a random variable is ae equal to `0` or `1`, then its variance is the product of +the probabilities that it's equal to `0` and that it's equal to `1`. -/ +lemma variance_of_ae_eq_zero_or_one {μ : Measure Ω} [IsZeroOrProbabilityMeasure μ] + (hXmeas : AEMeasurable X μ) (hX : ∀ᵐ ω ∂μ, X ω = 0 ∨ X ω = 1) : + Var[X; μ] = μ.real {ω | X ω = 0} * μ.real {ω | X ω = 1} := by + obtain rfl | hμ := eq_zero_or_isProbabilityMeasure μ + · simp + simpa [Pi.mul_def, integral_of_ae_eq_zero_or_one, integral_one_sub_of_ae_eq_zero_or_one, mul_comm, + *] using condVar_of_ae_eq_zero_or_one bot_le hXmeas hX + +end ProbabilityTheory diff --git a/Mathlib/Probability/Independence/BoundedContinuousFunction.lean b/Mathlib/Probability/Independence/BoundedContinuousFunction.lean index 2726dfa2bbb8c8..ee5a8244a1c172 100644 --- a/Mathlib/Probability/Independence/BoundedContinuousFunction.lean +++ b/Mathlib/Probability/Independence/BoundedContinuousFunction.lean @@ -6,7 +6,7 @@ Authors: Etienne Marion module public import Mathlib.MeasureTheory.Measure.HasOuterApproxClosedProd -public import Mathlib.Probability.Independence.Process +public import Mathlib.Probability.Independence.Process.Basic public import Mathlib.Probability.Notation /-! diff --git a/Mathlib/Probability/Independence/Process.lean b/Mathlib/Probability/Independence/Process/Basic.lean similarity index 100% rename from Mathlib/Probability/Independence/Process.lean rename to Mathlib/Probability/Independence/Process/Basic.lean diff --git a/Mathlib/Probability/Independence/Process/HasIndepIncrements.lean b/Mathlib/Probability/Independence/Process/HasIndepIncrements.lean new file mode 100644 index 00000000000000..b62be7fb5b6801 --- /dev/null +++ b/Mathlib/Probability/Independence/Process/HasIndepIncrements.lean @@ -0,0 +1,132 @@ +/- +Copyright (c) 2025 Etienne Marion. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Etienne Marion, Joris van Winden +-/ +module + +public import Mathlib.Probability.Independence.Basic + +import Mathlib.MeasureTheory.Constructions.BorelSpace.ContinuousLinearMap + +/-! +# Stochastic processes with independent increments + +A stochastic process `X : T → Ω → E` has independent increments if for any `n ≥ 1` and +`t₁ ≤ ... ≤ tₙ`, the random variables `X t₂ - X t₁, ..., X tₙ - X tₙ₋₁` are independent. +Equivalently, for any monotone sequence `(tₙ)`, the random variables `(X tₙ₊₁ - X tₙ)` +are independent. + +## Main definition + +* `HasIndepIncrements`: A stochastic process `X : T → Ω → E` has independent increments if for any + `n ≥ 1` and `t₁ ≤ ... ≤ tₙ`, the random variables `X t₂ - X t₁, ..., X tₙ - X tₙ₋₁` are + independent. + +## Main statement + +* `hasIndepIncrements_iff_nat`: A stochastic process `X : T → Ω → E` has independent increments if + and only if for any monotone sequence `(tₙ)`, the random variables `(X tₙ₊₁ - X tₙ)` are + independent. + +## Tags + +independent increments +-/ + +@[expose] public section + +open MeasureTheory Filter + +namespace ProbabilityTheory + +variable {T Ω E : Type*} {mΩ : MeasurableSpace Ω} {P : Measure Ω} {X : T → Ω → E} + [Preorder T] [MeasurableSpace E] + +section Def + +variable [Sub E] + +/-- A stochastic process `X : T → Ω → E` has independent increments if for any `n ≥ 1` and +`t₁ ≤ ... ≤ tₙ`, the random variables `X t₂ - X t₁, ..., X tₙ - X tₙ₋₁` are independent. + +Although this corresponds to the standard definition, dealing with `Fin` might make things +complicated in some cases. Therefore we provide `HasIndepIncrements.of_nat` which instead requires +to prove that for any monotone sequence `(tₙ)` that is eventually constant, +the random variables `X tₙ₊₁ - X tₙ` are independent. -/ +def HasIndepIncrements (X : T → Ω → E) (P : Measure Ω := by volume_tac) : Prop := + ∀ n, ∀ t : Fin (n + 1) → T, Monotone t → + iIndepFun (fun (i : Fin n) ω ↦ X (t i.succ) ω - X (t i.castSucc) ω) P + +protected lemma HasIndepIncrements.nat + (hX : HasIndepIncrements X P) {t : ℕ → T} (ht : Monotone t) : + iIndepFun (fun i ω ↦ X (t (i + 1)) ω - X (t i) ω) P := by + refine iIndepFun_iff_finset.2 fun s ↦ ?_ + obtain rfl | hs := s.eq_empty_or_nonempty + · have := (hX 0 (fun _ ↦ t 0) (fun _ ↦ by grind)).isProbabilityMeasure + exact iIndepFun.of_subsingleton + · let g (x : s) : Fin (s.max' hs + 1) := ⟨x.1, Nat.lt_add_one_of_le (s.le_max' x.1 x.2)⟩ + refine iIndepFun.precomp (g := g) ?_ (hX (s.max' hs + 1) (fun m ↦ t m) ?_) + · simp [g, Function.Injective] + · exact ht.comp Fin.val_strictMono.monotone + +protected lemma HasIndepIncrements.of_nat + (h : ∀ t : ℕ → T, Monotone t → EventuallyConst t atTop → + iIndepFun (fun i ω ↦ X (t (i + 1)) ω - X (t i) ω) P) : + HasIndepIncrements X P := by + intro n t ht + let t' k := t ⟨min n k, by grind⟩ + convert (h t' ?_ ?_).precomp Fin.val_injective with i ω + · grind + · grind + · exact fun a b hab ↦ ht (by grind) + · exact eventuallyConst_atTop.2 ⟨n, by grind⟩ + +lemma hasIndepIncrements_iff_nat : + HasIndepIncrements X P ↔ + ∀ t : ℕ → T, Monotone t → iIndepFun (fun i ω ↦ X (t (i + 1)) ω - X (t i) ω) P where + mp h _ ht := h.nat ht + mpr h := .of_nat (fun t ht _ ↦ h t ht) + +end Def + +lemma HasIndepIncrements.indepFun_sub_sub [Sub E] (hX : HasIndepIncrements X P) {r s t : T} + (hrs : r ≤ s) (hst : s ≤ t) : + (X s - X r) ⟂ᵢ[P] (X t - X s) := by + let τ : ℕ → T + | 0 => r + | 1 => s + | _ => t + exact hX.nat (t := τ) (fun _ ↦ by grind) |>.indepFun (by grind : 0 ≠ 1) + +lemma HasIndepIncrements.indepFun_eval_sub [SubNegZeroMonoid E] (hX : HasIndepIncrements X P) + {r s t : T} (hrs : r ≤ s) (hst : s ≤ t) (h : ∀ᵐ ω ∂P, X r ω = 0) : + (X s) ⟂ᵢ[P] (X t - X s) := by + refine (hX.indepFun_sub_sub hrs hst).congr ?_ .rfl + filter_upwards [h] with ω hω using by simp [hω] + +protected lemma HasIndepIncrements.map' {F G : Type*} [MeasurableSpace G] [FunLike F E G] + [AddGroup E] [SubtractionMonoid G] [AddMonoidHomClass F E G] {f : F} (hf : Measurable f) + (hX : HasIndepIncrements X P) : + HasIndepIncrements (fun t ω ↦ f (X t ω)) P := by + intro n t ht + simp_rw [← map_sub] + exact (hX n t ht).comp (fun _ ↦ f) (fun _ ↦ hf) + +protected lemma HasIndepIncrements.map {R F : Type*} [Semiring R] [SeminormedAddCommGroup E] + [Module R E] [OpensMeasurableSpace E] [SeminormedAddCommGroup F] [Module R F] + [MeasurableSpace F] [BorelSpace F] (L : E →L[R] F) (hX : HasIndepIncrements X P) : + HasIndepIncrements (fun t ω ↦ L (X t ω)) P := + hX.map' L.measurable + +protected lemma HasIndepIncrements.smul {R : Type*} [AddGroup E] [DistribSMul R E] + [MeasurableConstSMul R E] (hX : HasIndepIncrements X P) (c : R) : + HasIndepIncrements (fun t ω ↦ c • (X t ω)) P := + hX.map' (f := DistribSMul.toAddMonoidHom E c) (MeasurableConstSMul.measurable_const_smul c) + +protected lemma HasIndepIncrements.neg [AddCommGroup E] [MeasurableNeg E] + (hX : HasIndepIncrements X P) : + HasIndepIncrements (-X) P := + hX.map' (f := negAddMonoidHom) measurable_neg + +end ProbabilityTheory diff --git a/Mathlib/Probability/Kernel/IonescuTulcea/PartialTraj.lean b/Mathlib/Probability/Kernel/IonescuTulcea/PartialTraj.lean index ea5c1dcb10452e..42ed3b300244a2 100644 --- a/Mathlib/Probability/Kernel/IonescuTulcea/PartialTraj.lean +++ b/Mathlib/Probability/Kernel/IonescuTulcea/PartialTraj.lean @@ -359,10 +359,7 @@ lemma measurable_lmarginalPartialTraj (a b : ℕ) {f : (Π n, X n) → ℝ≥0 let η : Kernel (Π n, X n) (Π i : Iic b, X i) := (partialTraj κ a b).comap (frestrictLe a) (measurable_frestrictLe _) change Measurable fun x₀ ↦ ∫⁻ z : (i : Iic b) → X i, g (z, x₀) ∂η x₀ - refine Measurable.lintegral_kernel_prod_left' <| hf.comp ?_ - simp only [updateFinset, measurable_pi_iff] - intro i - by_cases h : i ∈ Iic b <;> simp only [h, ↓reduceDIte] <;> fun_prop + fun_prop /-- Integrating `f` against `partialTraj κ a b` and then against `partialTraj κ b c` is the same as integrating `f` against `partialTraj κ a c`. -/ diff --git a/Mathlib/RepresentationTheory/FiniteIndex.lean b/Mathlib/RepresentationTheory/FiniteIndex.lean index 97df4216ae3c32..c2fe0320b6fd60 100644 --- a/Mathlib/RepresentationTheory/FiniteIndex.lean +++ b/Mathlib/RepresentationTheory/FiniteIndex.lean @@ -233,14 +233,12 @@ theorem instIsLeftAdjointSubtypeMemSubgroupCoindFunctorSubtype : (coindFunctor k S.subtype).IsLeftAdjoint := open scoped Classical in (coindResAdjunction k S).isLeftAdjoint -set_option backward.isDefEq.respectTransparency false in @[simp] lemma coindResAdjunction_counit_app (B : Rep k G) : (coindResAdjunction k S).counit.app B = (indCoindIso <| (Action.res _ S.subtype).obj B).inv ≫ (indResAdjunction k S.subtype).counit.app B := by rfl -set_option backward.isDefEq.respectTransparency false in @[simp] lemma coindResAdjunction_unit_app : (coindResAdjunction k S).unit.app A = (indResAdjunction k S.subtype).unit.app A ≫ diff --git a/Mathlib/RepresentationTheory/Homological/GroupCohomology/FiniteCyclic.lean b/Mathlib/RepresentationTheory/Homological/GroupCohomology/FiniteCyclic.lean index fdeeca6059da67..dddc48af6d3d2d 100644 --- a/Mathlib/RepresentationTheory/Homological/GroupCohomology/FiniteCyclic.lean +++ b/Mathlib/RepresentationTheory/Homological/GroupCohomology/FiniteCyclic.lean @@ -86,7 +86,6 @@ noncomputable def groupCohomologyIsoEven (i : ℕ) [h₀ : NeZero i] (hi : Even (by induction i generalizing h₀ with | zero => exact (NeZero.ne 0 rfl).elim | succ n _ => simp) (by simp) hi -set_option backward.isDefEq.respectTransparency false in /-- Given a finite cyclic group `G` generated by `g` and `A : Rep k G`, this is the quotient map `Ker(ρ(g) - Id(A)) ⟶ Ker(ρ(g) - Id(A))/Im(N) ≅ Hⁱ(G, A)` for any nonzero even `i`. -/ noncomputable abbrev groupCohomologyπEven (i : ℕ) [NeZero i] (hi : Even i) : @@ -119,7 +118,6 @@ noncomputable def groupCohomologyIsoOdd (i : ℕ) (hi : Odd i) : HomologicalComplex.alternatingConstHomologyIsoOdd A.V (by ext; simp) (by ext; simp) (by simp) (by rcases hi with ⟨j, rfl⟩; simp) (by simp) hi -set_option backward.isDefEq.respectTransparency false in /-- Given a finite cyclic group `G` generated by `g` and `A : Rep k G`, this is the quotient map `Ker(N) ⟶ Ker(N)/Im(ρ(g) - Id(A)) ≅ Hⁱ(G, A)` for any odd `i`. -/ noncomputable abbrev groupCohomologyπOdd (i : ℕ) (hi : Odd i) : diff --git a/Mathlib/RepresentationTheory/Homological/GroupHomology/FiniteCyclic.lean b/Mathlib/RepresentationTheory/Homological/GroupHomology/FiniteCyclic.lean index 6dd651d2af8d5b..ada1a8423af8ab 100644 --- a/Mathlib/RepresentationTheory/Homological/GroupHomology/FiniteCyclic.lean +++ b/Mathlib/RepresentationTheory/Homological/GroupHomology/FiniteCyclic.lean @@ -123,7 +123,6 @@ noncomputable def groupHomologyIsoOdd (hg : ∀ x, x ∈ Subgroup.zpowers g) (i HomologicalComplex.alternatingConstHomologyIsoOdd A.V (by ext; simp) (by ext; simp) (by aesop) (by simp) (by rcases hi with ⟨j, rfl⟩; simp) hi -set_option backward.isDefEq.respectTransparency false in /-- Given a finite cyclic group `G` generated by `g` and `A : Rep k G`, this is the quotient map `Ker(ρ(g) - Id(A)) ⟶ Ker(ρ(g) - Id(A))/Im(N) ≅ Hᵢ(G, A)` for any odd `i`. -/ noncomputable abbrev groupHomologyπOdd (hg : ∀ x, x ∈ Subgroup.zpowers g) (i : ℕ) (hi : Odd i) : diff --git a/Mathlib/RingTheory/AdicCompletion/Algebra.lean b/Mathlib/RingTheory/AdicCompletion/Algebra.lean index 2db1d261d7af38..f1e1fa9707c575 100644 --- a/Mathlib/RingTheory/AdicCompletion/Algebra.lean +++ b/Mathlib/RingTheory/AdicCompletion/Algebra.lean @@ -69,7 +69,6 @@ def transitionMapₐ {m n : ℕ} (hmn : m ≤ n) : R ⧸ (I ^ n • ⊤ : Ideal R) →ₐ[R] R ⧸ (I ^ m • ⊤ : Ideal R) := AlgHom.ofLinearMap (transitionMap I R hmn) rfl (transitionMap_map_mul I hmn) -set_option backward.isDefEq.respectTransparency false in /-- `AdicCompletion I R` is an `R`-subalgebra of `∀ n, R ⧸ (I ^ n • ⊤ : Ideal R)`. -/ def subalgebra : Subalgebra R (∀ n, R ⧸ (I ^ n • ⊤ : Ideal R)) := Submodule.toSubalgebra (submodule I R) (fun _ ↦ by simp [transitionMap_map_one I]) @@ -268,7 +267,7 @@ good definitional behaviour for the module instance on adic completions -/ instance : SMul (R ⧸ (I • ⊤ : Ideal R)) (M ⧸ (I • ⊤ : Submodule R M)) where smul r x := Quotient.liftOn r (· • x) fun b₁ b₂ h ↦ by - refine Quotient.inductionOn' x (fun x ↦ ?_) + induction x using Quotient.inductionOn' have h : b₁ - b₂ ∈ (I : Submodule R R) := by rwa [show I = I • ⊤ by simp, ← Submodule.quotientRel_def] rw [← sub_eq_zero, ← sub_smul, Submodule.Quotient.mk''_eq_mk, @@ -283,8 +282,7 @@ theorem mk_smul_mk (r : R) (x : M) : theorem val_smul_eq_evalₐ_smul (n : ℕ) (r : AdicCompletion I R) (x : M ⧸ (I ^ n • ⊤ : Submodule R M)) : r.val n • x = evalₐ I n r • x := by - apply induction_on I R r (fun r ↦ ?_) - exact Quotient.inductionOn' x (fun x ↦ rfl) + induction r using induction_on; rfl instance : Module (R ⧸ (I • ⊤ : Ideal R)) (M ⧸ (I • ⊤ : Submodule R M)) := Function.Surjective.moduleLeft (Ideal.Quotient.mk (I • ⊤ : Ideal R)) @@ -292,8 +290,7 @@ instance : Module (R ⧸ (I • ⊤ : Ideal R)) (M ⧸ (I • ⊤ : Submodule R instance : IsScalarTower R (R ⧸ (I • ⊤ : Ideal R)) (M ⧸ (I • ⊤ : Submodule R M)) where smul_assoc r s x := by - refine Quotient.inductionOn' s (fun s ↦ ?_) - refine Quotient.inductionOn' x (fun x ↦ ?_) + induction s, x using Quotient.inductionOn₂' with | _ s x simp only [Submodule.Quotient.mk''_eq_mk] rw [← Submodule.Quotient.mk_smul, Ideal.Quotient.mk_eq_mk, mk_smul_mk, smul_assoc] rfl diff --git a/Mathlib/RingTheory/AdicCompletion/Basic.lean b/Mathlib/RingTheory/AdicCompletion/Basic.lean index 5ce835a93b2eed..7617db184c1cdc 100644 --- a/Mathlib/RingTheory/AdicCompletion/Basic.lean +++ b/Mathlib/RingTheory/AdicCompletion/Basic.lean @@ -405,8 +405,8 @@ instance : IsHausdorff I (AdicCompletion I M) where haus' x h := ext fun n ↦ by refine smul_induction_on (SModEq.zero.1 <| h n) (fun r hr x _ ↦ ?_) (fun x y hx hy ↦ ?_) · simp only [val_smul_apply, val_zero] - exact Quotient.inductionOn' (x.val n) - (fun a ↦ SModEq.zero.2 <| smul_mem_smul hr mem_top) + induction x.val n using Quotient.inductionOn' with | _ a + exact SModEq.zero.2 <| smul_mem_smul hr mem_top · simp only [val_add_apply, hx, val_zero_apply, hy, add_zero] @[simp] diff --git a/Mathlib/RingTheory/AdicCompletion/Functoriality.lean b/Mathlib/RingTheory/AdicCompletion/Functoriality.lean index 8fc6e219a1a50f..7ece0b96685ed7 100644 --- a/Mathlib/RingTheory/AdicCompletion/Functoriality.lean +++ b/Mathlib/RingTheory/AdicCompletion/Functoriality.lean @@ -63,8 +63,7 @@ def reduceModIdeal (f : M →ₗ[R] N) : toFun := f.reduceModIdealAux I map_add' := by simp map_smul' r x := by - refine Quotient.inductionOn' r (fun r ↦ ?_) - refine Quotient.inductionOn' x (fun x ↦ ?_) + induction r, x using Quotient.inductionOn₂ with | _ r x simp only [Submodule.Quotient.mk''_eq_mk, Ideal.Quotient.mk_eq_mk, Module.Quotient.mk_smul_mk, Submodule.Quotient.mk_smul, LinearMapClass.map_smul, reduceModIdealAux_apply, RingHomCompTriple.comp_apply] diff --git a/Mathlib/RingTheory/Adjoin/Field.lean b/Mathlib/RingTheory/Adjoin/Field.lean index 8d028d84971af9..f81cd0b92fe5cc 100644 --- a/Mathlib/RingTheory/Adjoin/Field.lean +++ b/Mathlib/RingTheory/Adjoin/Field.lean @@ -32,7 +32,6 @@ section Embeddings variable (F : Type*) [Field F] -set_option backward.isDefEq.respectTransparency false in open AdjoinRoot in /-- If `p` is the minimal polynomial of `a` over `F` then `F[a] ≃ₐ[F] F[x]/(p)` -/ def AlgEquiv.adjoinSingletonEquivAdjoinRootMinpoly {R : Type*} [CommRing R] [Algebra F R] (x : R) : diff --git a/Mathlib/RingTheory/Adjoin/Polynomial/Bivariate.lean b/Mathlib/RingTheory/Adjoin/Polynomial/Bivariate.lean new file mode 100644 index 00000000000000..0a5a4dd866d326 --- /dev/null +++ b/Mathlib/RingTheory/Adjoin/Polynomial/Bivariate.lean @@ -0,0 +1,78 @@ +/- +Copyright (c) 2026 Xavier Généreux, María Inés de Frutos Fernández. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Xavier Généreux, María Inés de Frutos Fernández +-/ +module + +public import Mathlib.Algebra.Polynomial.Bivariate +public import Mathlib.Algebra.Ring.Defs + +/-! +# Bivariate polynomials and adjoining transcendental elements + +## Main results + +* `IsAlgebraic.adjoin_singleton`: + Given two transcendental elements `a`, `b` over `R`, if one of them, say `a`, is algebraic over + `R[b]` then `b` is algebraic over `R[a]`. +-/ + +@[expose] public noncomputable section + +namespace Polynomial.Bivariate + +open Polynomial Bivariate Algebra Transcendental + +variable {R A : Type*} [CommRing R] + +section Ring + +variable [Ring A] [Algebra R A] {x : A} + +/-- The `AlgEquiv` between `R[X][Y]` and `R[a][Y]` for some transcendental `a`. -/ +def Transcendental.algEquivAdjoin (hx : Transcendental R x) : + R[X][Y] ≃ₐ[R] (Algebra.adjoin R {x})[X] := + mapAlgEquiv (algEquivOfTranscendental _ x hx) + +theorem Transcendental.algEquivAdjoin_apply (hx : Transcendental R x) (p : R[X][Y]) : + hx.algEquivAdjoin p = mapAlgHom (aeval ⟨x, self_mem_adjoin_singleton R x⟩) p := + rfl + +attribute [local instance] algebra in +theorem Transcendental.algEquivAdjoin_swap_eq_aeval (hx : Transcendental R x) (p : R[X][Y]) : + hx.algEquivAdjoin (swap p) = aeval (C ⟨x, self_mem_adjoin_singleton R x⟩) p := by + simp [algEquivAdjoin, Bivariate.aveal_eq_map_swap] + +end Ring + +section CommRing + +variable [CommRing A] [Algebra R A] + +variable {B : Type*} [CommRing B] [Algebra A B] [Algebra R B] [IsScalarTower R A B] + +attribute [local instance] Polynomial.algebra in +theorem aeval_aeval_eq_aeval_algEquivAdjoin {x : A} (y : B) + (hx : Transcendental R x) (p : R[X][Y]) : + aeval (algebraMap A B x) (aeval (C (⟨y, self_mem_adjoin_singleton R y⟩ : + adjoin R {y})) p) = aeval y (hx.algEquivAdjoin p) := by + induction p using Polynomial.induction_on' with + | add p q hp hq => simp_all [map_add] + | monomial n a => + simp_all [aeval_algebraMap_apply, Transcendental.algEquivAdjoin, Subalgebra.algebraMap_def] + +set_option backward.isDefEq.respectTransparency false in +theorem _root_.IsAlgebraic.adjoin_singleton {x : A} {y : B} (hx : Transcendental R x) + (hy : Transcendental R y) (h : IsAlgebraic (adjoin R {x}) y) : + IsAlgebraic (adjoin R {y}) (algebraMap A B x) := by + obtain ⟨f, hnezero, halg⟩ := h + refine ⟨hy.algEquivAdjoin (swap (hx.algEquivAdjoin.symm f)), + by simpa only [map_ne_zero_iff _ (AlgEquiv.injective _)], ?_⟩ + simpa [Transcendental.algEquivAdjoin_swap_eq_aeval hy, aeval_aeval_eq_aeval_algEquivAdjoin y hx] + +end CommRing + +end Polynomial.Bivariate + +end diff --git a/Mathlib/RingTheory/Adjoin/PowerBasis.lean b/Mathlib/RingTheory/Adjoin/PowerBasis.lean index f3bb131c283bff..c5e24af181c673 100644 --- a/Mathlib/RingTheory/Adjoin/PowerBasis.lean +++ b/Mathlib/RingTheory/Adjoin/PowerBasis.lean @@ -24,7 +24,6 @@ variable {K S : Type*} [Field K] [CommRing S] [Algebra K S] namespace Algebra -set_option backward.isDefEq.respectTransparency false in /-- The elements `1, x, ..., x ^ (d - 1)` for a basis for the `K`-module `K[x]`, where `d` is the degree of the minimal polynomial of `x`. -/ noncomputable def adjoin.powerBasisAux {x : S} (hx : IsIntegral K x) : @@ -48,7 +47,6 @@ noncomputable def adjoin.powerBasisAux {x : S} (hx : IsIntegral K x) : ext exact aeval_algebraMap_apply S (⟨x, _⟩ : adjoin K {x}) _ -set_option backward.isDefEq.respectTransparency false in /-- The power basis `1, x, ..., x ^ (d - 1)` for `K[x]`, where `d` is the degree of the minimal polynomial of `x`. See `Algebra.adjoin.powerBasis'` for a version over a more general base ring. -/ @@ -60,7 +58,6 @@ noncomputable def adjoin.powerBasis {x : S} (hx : IsIntegral K x) : basis := adjoin.powerBasisAux hx basis_eq_pow i := by rw [adjoin.powerBasisAux, Basis.mk_apply] -set_option backward.isDefEq.respectTransparency false in /-- If `x` generates `S` over `K` and is integral over `K`, then it defines a power basis. See `PowerBasis.ofAdjoinEqTop'` for a version over a more general base ring. diff --git a/Mathlib/RingTheory/Adjoin/Tower.lean b/Mathlib/RingTheory/Adjoin/Tower.lean index e5630437ef1d04..6457c3a9595818 100644 --- a/Mathlib/RingTheory/Adjoin/Tower.lean +++ b/Mathlib/RingTheory/Adjoin/Tower.lean @@ -136,7 +136,6 @@ section Ring variable [CommRing A] [CommRing B] [CommRing C] variable [Algebra A B] [Algebra B C] [Algebra A C] [IsScalarTower A B C] -set_option backward.isDefEq.respectTransparency false in /-- **Artin--Tate lemma**: if A ⊆ B ⊆ C is a chain of subrings of commutative rings, and A is Noetherian, and C is algebra-finite over A, and C is module-finite over B, then B is algebra-finite over A. diff --git a/Mathlib/RingTheory/AdjoinRoot.lean b/Mathlib/RingTheory/AdjoinRoot.lean index dba9cd00c32893..d87ed68d96caac 100644 --- a/Mathlib/RingTheory/AdjoinRoot.lean +++ b/Mathlib/RingTheory/AdjoinRoot.lean @@ -783,7 +783,6 @@ variable [CommRing R] [CommRing S] [Algebra R S] (x : S) (R) open Algebra Polynomial -set_option backward.isDefEq.respectTransparency false in /-- The surjective algebra morphism `R[X]/(minpoly R x) → R[x]`. If `R` is an integrally closed domain and `x` is integral, this is an isomorphism, see `minpoly.equivAdjoin`. -/ @@ -793,7 +792,6 @@ def Minpoly.toAdjoin : AdjoinRoot (minpoly R x) →ₐ[R] adjoin R ({x} : Set S) variable {R x} -set_option backward.isDefEq.respectTransparency false in @[simp] theorem Minpoly.coe_toAdjoin : ⇑(Minpoly.toAdjoin R x) = liftAlgHom (minpoly R x) (Algebra.ofId R <| adjoin R {x}) diff --git a/Mathlib/RingTheory/Algebraic/Basic.lean b/Mathlib/RingTheory/Algebraic/Basic.lean index f2e92b38626679..931635f4a14083 100644 --- a/Mathlib/RingTheory/Algebraic/Basic.lean +++ b/Mathlib/RingTheory/Algebraic/Basic.lean @@ -327,41 +327,34 @@ theorem transcendental_algebraMap_iff {a : S} (h : Function.Injective (algebraMa namespace Subalgebra -set_option backward.isDefEq.respectTransparency false in theorem isAlgebraic_iff_isAlgebraic_val {S : Subalgebra R A} {x : S} : IsAlgebraic R x ↔ IsAlgebraic R x.1 := (isAlgebraic_algHom_iff S.val Subtype.val_injective).symm -set_option backward.isDefEq.respectTransparency false in theorem transcendental_iff_transcendental_val {S : Subalgebra R A} {x : S} : Transcendental R x ↔ Transcendental R x.1 := isAlgebraic_iff_isAlgebraic_val.not -set_option backward.isDefEq.respectTransparency false in theorem isAlgebraic_of_isAlgebraic_bot {x : S} (halg : IsAlgebraic (⊥ : Subalgebra R S) x) : IsAlgebraic R x := halg.of_ringHom_of_comp_eq (algebraMap R (⊥ : Subalgebra R S)) (RingHom.id S) (by rintro ⟨_, r, rfl⟩; exact ⟨r, rfl⟩) Function.injective_id rfl -set_option backward.isDefEq.respectTransparency false in theorem isAlgebraic_bot_iff (h : Function.Injective (algebraMap R S)) {x : S} : IsAlgebraic (⊥ : Subalgebra R S) x ↔ IsAlgebraic R x := isAlgebraic_ringHom_iff_of_comp_eq (Algebra.botEquivOfInjective h).symm (RingHom.id S) Function.injective_id (by rfl) -set_option backward.isDefEq.respectTransparency false in variable (R S) in theorem algebra_isAlgebraic_of_algebra_isAlgebraic_bot_left [Algebra.IsAlgebraic (⊥ : Subalgebra R S) S] : Algebra.IsAlgebraic R S := Algebra.IsAlgebraic.of_ringHom_of_comp_eq (algebraMap R (⊥ : Subalgebra R S)) (RingHom.id S) (by rintro ⟨_, r, rfl⟩; exact ⟨r, rfl⟩) Function.injective_id (by ext; rfl) -set_option backward.isDefEq.respectTransparency false in theorem algebra_isAlgebraic_bot_left_iff (h : Function.Injective (algebraMap R S)) : Algebra.IsAlgebraic (⊥ : Subalgebra R S) S ↔ Algebra.IsAlgebraic R S := by simp_rw [Algebra.isAlgebraic_def, isAlgebraic_bot_iff h] -set_option backward.isDefEq.respectTransparency false in instance algebra_isAlgebraic_bot_right [Nontrivial R] : Algebra.IsAlgebraic R (⊥ : Subalgebra R S) := ⟨by rintro ⟨_, x, rfl⟩; exact isAlgebraic_algebraMap _⟩ @@ -415,7 +408,6 @@ theorem IsAlgebraic.extendScalars (hinj : Function.Injective (algebraMap R S)) { ⟨p.map (algebraMap _ _), by rwa [Ne, ← degree_eq_bot, degree_map_eq_of_injective hinj, degree_eq_bot], by simpa⟩ -set_option backward.isDefEq.respectTransparency false in /-- A special case of `IsAlgebraic.extendScalars`. This is extracted as a theorem because in some cases `IsAlgebraic.extendScalars` will just runs out of memory. -/ theorem IsAlgebraic.tower_top_of_subalgebra_le @@ -430,7 +422,6 @@ theorem IsAlgebraic.tower_top_of_subalgebra_le theorem Transcendental.restrictScalars (hinj : Function.Injective (algebraMap R S)) {x : A} (h : Transcendental S x) : Transcendental R x := fun H ↦ h (H.extendScalars hinj) -set_option backward.isDefEq.respectTransparency false in /-- A special case of `Transcendental.restrictScalars`. This is extracted as a theorem because in some cases `Transcendental.restrictScalars` will just runs out of memory. -/ theorem Transcendental.of_tower_top_of_subalgebra_le @@ -586,7 +577,6 @@ theorem Algebra.IsAlgebraic.exists_smul_eq_mul [NoZeroDivisors S] [Algebra.IsAlg namespace Polynomial -set_option backward.isDefEq.respectTransparency false in /-- Given a transcendental element `s : S` over `R`, the `R`-algebra equivalence between `R[X]` and `Algebra.adjoin R {s}` given by sending `X` to `s`. -/ noncomputable def algEquivOfTranscendental (s : S) (h : Transcendental R s) : @@ -684,7 +674,6 @@ theorem Subalgebra.inv_mem_of_root_of_coeff_zero_ne_zero {x : A} {p : K[X]} rw [inv_eq_of_root_of_coeff_zero_ne_zero this coeff_zero_ne, div_eq_inv_mul, Algebra.smul_def, aeval_coe, map_inv₀, map_neg, inv_neg, neg_mul] -set_option backward.isDefEq.respectTransparency false in theorem Subalgebra.inv_mem_of_algebraic {x : A} (hx : IsAlgebraic K (x : L)) : (x⁻¹ : L) ∈ A := by obtain ⟨p, ne_zero, aeval_eq⟩ := hx diff --git a/Mathlib/RingTheory/Algebraic/Defs.lean b/Mathlib/RingTheory/Algebraic/Defs.lean index b186382c8cf0f3..8d8452d2f28d49 100644 --- a/Mathlib/RingTheory/Algebraic/Defs.lean +++ b/Mathlib/RingTheory/Algebraic/Defs.lean @@ -88,7 +88,6 @@ theorem Algebra.transcendental_iff_not_isAlgebraic : Algebra.Transcendental R A ↔ ¬ Algebra.IsAlgebraic R A := by simp [isAlgebraic_def, transcendental_def, Transcendental] -set_option backward.isDefEq.respectTransparency false in /-- A subalgebra is algebraic if and only if it is algebraic as an algebra. -/ theorem Subalgebra.isAlgebraic_iff (S : Subalgebra R A) : S.IsAlgebraic ↔ Algebra.IsAlgebraic R S := by diff --git a/Mathlib/RingTheory/Algebraic/Integral.lean b/Mathlib/RingTheory/Algebraic/Integral.lean index b0dca8898c1b51..413cb192228d9f 100644 --- a/Mathlib/RingTheory/Algebraic/Integral.lean +++ b/Mathlib/RingTheory/Algebraic/Integral.lean @@ -222,7 +222,6 @@ theorem restrictScalars_of_isIntegral [int : Algebra.IsIntegral R S] e, ← Algebra.smul_def, mul_comm, mul_smul] exact isIntegral_trans _ (int_s.smul _) -set_option backward.isDefEq.respectTransparency false in theorem restrictScalars [Algebra.IsAlgebraic R S] {a : A} (h : IsAlgebraic S a) : IsAlgebraic R a := by have ⟨p, hp, eval0⟩ := h @@ -379,7 +378,6 @@ theorem Subalgebra.algebraicClosure_eq_integralClosure {K} [Field K] [Algebra K algebraicClosure K S = integralClosure K S := SetLike.ext fun _ ↦ isAlgebraic_iff_isIntegral -set_option backward.isDefEq.respectTransparency false in instance [IsDomain R] : Algebra.IsAlgebraic R (Subalgebra.algebraicClosure R S) := (Subalgebra.isAlgebraic_iff _).mp fun _ ↦ id @@ -410,7 +408,6 @@ theorem IsAlgebraic.of_mul [NoZeroDivisors R] {y z : S} (hy : y ∈ nonZeroDivis rw [mul_right_comm, eq, ← Algebra.smul_def] at this exact this.of_smul (mem_nonZeroDivisors_of_ne_zero hr) -set_option backward.isDefEq.respectTransparency false in open Algebra in omit [Algebra R A] [IsScalarTower R S A] in theorem IsAlgebraic.adjoin_of_forall_isAlgebraic [NoZeroDivisors S] {s t : Set S} @@ -457,11 +454,9 @@ end variable [NoZeroDivisors S] {a : S} (ha : Transcendental R a) include ha -set_option backward.isDefEq.respectTransparency false in protected lemma integralClosure : Transcendental (integralClosure R S) a := ha.extendScalars_of_isIntegral _ -set_option backward.isDefEq.respectTransparency false in lemma subalgebraAlgebraicClosure [IsDomain R] : Transcendental (Subalgebra.algebraicClosure R S) a := ha.extendScalars _ diff --git a/Mathlib/RingTheory/Algebraic/MvPolynomial.lean b/Mathlib/RingTheory/Algebraic/MvPolynomial.lean index d8a93adc3cfb2a..338dc1662ab3fd 100644 --- a/Mathlib/RingTheory/Algebraic/MvPolynomial.lean +++ b/Mathlib/RingTheory/Algebraic/MvPolynomial.lean @@ -26,7 +26,6 @@ namespace MvPolynomial variable {σ : Type*} (R : Type*) [CommRing R] -set_option backward.isDefEq.respectTransparency false in theorem transcendental_supported_polynomial_aeval_X {i : σ} {s : Set σ} (h : i ∉ s) {f : R[X]} (hf : Transcendental R f) : Transcendental (supported R s) (Polynomial.aeval (X i : MvPolynomial σ R) f) := by @@ -63,7 +62,6 @@ theorem transcendental_supported_polynomial_aeval_X {i : σ} {s : Set σ} (h : i simpa only [h2, v, AlgEquiv.toAlgHom_eq_coe, AlgHom.coe_comp, AlgHom.coe_coe, EquivLike.injective_comp, AlgHom.coe_restrictScalars'] using hf -set_option backward.isDefEq.respectTransparency false in theorem transcendental_polynomial_aeval_X (i : σ) {f : R[X]} (hf : Transcendental R f) : Transcendental R (Polynomial.aeval (X i : MvPolynomial σ R) f) := by have := transcendental_supported_polynomial_aeval_X R (Set.notMem_empty i) hf @@ -78,7 +76,6 @@ theorem transcendental_polynomial_aeval_X_iff (i : σ) {f : R[X]} : simp_rw [Transcendental, not_imp_not] exact fun h ↦ h.algHom _ -set_option backward.isDefEq.respectTransparency false in theorem transcendental_supported_polynomial_aeval_X_iff [Nontrivial R] {i : σ} {s : Set σ} {f : R[X]} : Transcendental (supported R s) (Polynomial.aeval (X i : MvPolynomial σ R) f) ↔ @@ -94,7 +91,6 @@ theorem transcendental_supported_polynomial_aeval_X_iff simp_rw [← MvPolynomial.algebraMap_eq] exact congr($(heq).1) -set_option backward.isDefEq.respectTransparency false in theorem transcendental_supported_X {i : σ} {s : Set σ} (h : i ∉ s) : Transcendental (supported R s) (X i : MvPolynomial σ R) := by simpa using transcendental_supported_polynomial_aeval_X R h (Polynomial.transcendental_X R) @@ -102,7 +98,6 @@ theorem transcendental_supported_X {i : σ} {s : Set σ} (h : i ∉ s) : theorem transcendental_X (i : σ) : Transcendental R (X i : MvPolynomial σ R) := by simpa using transcendental_polynomial_aeval_X R i (Polynomial.transcendental_X R) -set_option backward.isDefEq.respectTransparency false in theorem transcendental_supported_X_iff [Nontrivial R] {i : σ} {s : Set σ} : Transcendental (supported R s) (X i : MvPolynomial σ R) ↔ i ∉ s := by simpa [Polynomial.transcendental_X] using diff --git a/Mathlib/RingTheory/AlgebraicIndependent/AlgebraicClosure.lean b/Mathlib/RingTheory/AlgebraicIndependent/AlgebraicClosure.lean index f0095015f7e274..9073a7c4c94a6d 100644 --- a/Mathlib/RingTheory/AlgebraicIndependent/AlgebraicClosure.lean +++ b/Mathlib/RingTheory/AlgebraicIndependent/AlgebraicClosure.lean @@ -36,7 +36,6 @@ include hx namespace AlgebraicIndependent -set_option backward.isDefEq.respectTransparency false in theorem extendScalars [alg : Algebra.IsAlgebraic R S] : AlgebraicIndependent S x := by refine algebraicIndependent_of_finite_type' (Algebra.IsAlgebraic.injective_tower_top S hx.algebraMap_injective) fun t fin ind i hi ↦ ?_ @@ -65,17 +64,14 @@ theorem extendScalars_of_isIntegral [Algebra.IsIntegral R S] : AlgebraicIndepend have := Module.nontrivial R S exact hx.extendScalars S -set_option backward.isDefEq.respectTransparency false in theorem subalgebraAlgebraicClosure [IsDomain R] [NoZeroDivisors A] : AlgebraicIndependent (Subalgebra.algebraicClosure R A) x := hx.extendScalars _ -set_option backward.isDefEq.respectTransparency false in protected theorem integralClosure [NoZeroDivisors A] : AlgebraicIndependent (integralClosure R A) x := hx.extendScalars_of_isIntegral _ -set_option backward.isDefEq.respectTransparency false in omit hx in protected theorem algebraicClosure {F E : Type*} [Field F] [Field E] [Algebra F E] {x : ι → E} (hx : AlgebraicIndependent F x) : AlgebraicIndependent (algebraicClosure F E) x := @@ -121,22 +117,18 @@ section Ring variable [Ring S] [Algebra E S] -set_option backward.isDefEq.respectTransparency false in theorem isAlgebraic_adjoin_iff {x : S} : IsAlgebraic (adjoin F s) x ↔ IsAlgebraic (Algebra.adjoin F s) x := (IsAlgebraic.isAlgebraic_iff ..).symm -set_option backward.isDefEq.respectTransparency false in theorem isAlgebraic_adjoin_iff_top : Algebra.IsAlgebraic (adjoin F s) S ↔ Algebra.IsAlgebraic (Algebra.adjoin F s) S := (IsAlgebraic.isAlgebraic_iff_top ..).symm -set_option backward.isDefEq.respectTransparency false in theorem isAlgebraic_adjoin_iff_bot : Algebra.IsAlgebraic R (adjoin F s) ↔ Algebra.IsAlgebraic R (Algebra.adjoin F s) := IsAlgebraic.isAlgebraic_iff_bot .. -set_option backward.isDefEq.respectTransparency false in theorem transcendental_adjoin_iff {x : S} : Transcendental (adjoin F s) x ↔ Transcendental (Algebra.adjoin F s) x := (IsAlgebraic.transcendental_iff ..).symm @@ -145,12 +137,10 @@ end Ring variable [CommRing S] [Algebra E S] -set_option backward.isDefEq.respectTransparency false in theorem algebraicIndependent_adjoin_iff {x : ι → S} : AlgebraicIndependent (adjoin F s) x ↔ AlgebraicIndependent (Algebra.adjoin F s) x := (Algebra.IsAlgebraic.algebraicIndependent_iff ..).symm -set_option backward.isDefEq.respectTransparency false in theorem isTranscendenceBasis_adjoin_iff {x : ι → S} : IsTranscendenceBasis (adjoin F s) x ↔ IsTranscendenceBasis (Algebra.adjoin F s) x := (Algebra.IsAlgebraic.isTranscendenceBasis_iff ..).symm diff --git a/Mathlib/RingTheory/AlgebraicIndependent/Basic.lean b/Mathlib/RingTheory/AlgebraicIndependent/Basic.lean index 3b685c7f2ef31b..98c5f6a36579b5 100644 --- a/Mathlib/RingTheory/AlgebraicIndependent/Basic.lean +++ b/Mathlib/RingTheory/AlgebraicIndependent/Basic.lean @@ -168,7 +168,6 @@ theorem isTranscendenceBasis_iff_of_subsingleton [Subsingleton R] (x : ι → A) (ciSup_le' fun s ↦ by simpa using Set.subsingleton_of_subsingleton).antisymm <| le_ciSup_of_le (Cardinal.bddAbove_range _) ⟨{0}, .of_subsingleton⟩ (by simp) -set_option backward.isDefEq.respectTransparency false in theorem algebraicIndependent_adjoin (hs : AlgebraicIndependent R x) : @AlgebraicIndependent ι R (adjoin R (range x)) (fun i : ι => ⟨x i, subset_adjoin (mem_range_self i)⟩) _ _ _ := diff --git a/Mathlib/RingTheory/AlgebraicIndependent/RankAndCardinality.lean b/Mathlib/RingTheory/AlgebraicIndependent/RankAndCardinality.lean index bb899bae17d801..80bc727c6eefde 100644 --- a/Mathlib/RingTheory/AlgebraicIndependent/RankAndCardinality.lean +++ b/Mathlib/RingTheory/AlgebraicIndependent/RankAndCardinality.lean @@ -42,7 +42,6 @@ open AlgebraicIndependent open Cardinal -set_option backward.isDefEq.respectTransparency false in theorem IsTranscendenceBasis.lift_cardinalMk_eq_max_lift {F : Type u} {E : Type v} [CommRing F] [Nontrivial F] [CommRing E] [IsDomain E] [Algebra F E] {ι : Type w} {x : ι → E} [Nonempty ι] (hx : IsTranscendenceBasis F x) : @@ -54,7 +53,6 @@ theorem IsTranscendenceBasis.lift_cardinalMk_eq_max_lift haveI : Infinite K := hx.1.aevalEquiv.infinite_iff.1 inferInstance simpa only [sup_eq_left.2 (aleph0_le_mk K)] using Algebra.IsAlgebraic.cardinalMk_le_max K E -set_option backward.isDefEq.respectTransparency false in theorem IsTranscendenceBasis.lift_rank_eq_max_lift {F : Type u} {E : Type v} [Field F] [Field E] [Algebra F E] {ι : Type w} {x : ι → E} [Nonempty ι] (hx : IsTranscendenceBasis F x) : @@ -74,7 +72,6 @@ theorem Algebra.Transcendental.rank_eq_cardinalMk haveI := hx.nonempty_iff_transcendental.2 ‹_› simpa [← hx.lift_cardinalMk_eq_max_lift] using hx.lift_rank_eq_max_lift -set_option backward.isDefEq.respectTransparency false in theorem IntermediateField.rank_sup_le {F : Type u} {E : Type v} [Field F] [Field E] [Algebra F E] (A B : IntermediateField F E) : Module.rank F ↥(A ⊔ B) ≤ Module.rank F A * Module.rank F B := by diff --git a/Mathlib/RingTheory/AlgebraicIndependent/TranscendenceBasis.lean b/Mathlib/RingTheory/AlgebraicIndependent/TranscendenceBasis.lean index 977b0b812981d0..5e8dbd6507ee8d 100644 --- a/Mathlib/RingTheory/AlgebraicIndependent/TranscendenceBasis.lean +++ b/Mathlib/RingTheory/AlgebraicIndependent/TranscendenceBasis.lean @@ -99,7 +99,6 @@ theorem AlgebraicIndependent.isTranscendenceBasis_iff [Nontrivial R] rw [← image_univ, image_image] at q simpa using q -set_option backward.isDefEq.respectTransparency false in theorem IsTranscendenceBasis.isAlgebraic [Nontrivial R] (hx : IsTranscendenceBasis R x) : Algebra.IsAlgebraic (adjoin R (range x)) A := by constructor @@ -120,7 +119,6 @@ theorem IsTranscendenceBasis.isAlgebraic [Nontrivial R] (hx : IsTranscendenceBas exact h₂ (hx.2 (Set.range fun o : Option ι => o.elim a x) ((algebraicIndependent_subtype_range ai.injective).2 ai) h₁) -set_option backward.isDefEq.respectTransparency false in theorem AlgebraicIndependent.isTranscendenceBasis_iff_isAlgebraic [Nontrivial R] (ind : AlgebraicIndependent R x) : IsTranscendenceBasis R x ↔ Algebra.IsAlgebraic (adjoin R (range x)) A := by @@ -132,14 +130,12 @@ theorem AlgebraicIndependent.isTranscendenceBasis_iff_isAlgebraic refine ind_s.transcendental_adjoin (s := range (inclusion hxs)) (i := ⟨a, has⟩) ?_ (alg.1 _) simpa using hax -set_option backward.isDefEq.respectTransparency false in theorem isTranscendenceBasis_iff_algebraicIndependent_isAlgebraic [Nontrivial R] : IsTranscendenceBasis R x ↔ AlgebraicIndependent R x ∧ Algebra.IsAlgebraic (adjoin R (range x)) A := ⟨fun h ↦ ⟨h.1, h.1.isTranscendenceBasis_iff_isAlgebraic.mp h⟩, fun ⟨ind, alg⟩ ↦ ind.isTranscendenceBasis_iff_isAlgebraic.mpr alg⟩ -set_option backward.isDefEq.respectTransparency false in lemma IsTranscendenceBasis.algebraMap_comp [Nontrivial R] [NoZeroDivisors S] [Algebra.IsAlgebraic S A] [FaithfulSMul S A] {x : ι → S} (hx : IsTranscendenceBasis R x) : IsTranscendenceBasis R (algebraMap S A ∘ x) := by @@ -155,7 +151,6 @@ lemma IsTranscendenceBasis.algebraMap_comp have : Algebra.IsAlgebraic Rx A := .trans _ S _ exact .extendScalars e.injective -set_option backward.isDefEq.respectTransparency false in lemma IsTranscendenceBasis.isAlgebraic_iff [IsDomain S] [NoZeroDivisors A] {ι : Type*} {v : ι → A} (hv : IsTranscendenceBasis R v) : Algebra.IsAlgebraic S A ↔ ∀ i, IsAlgebraic S (v i) := by @@ -198,7 +193,6 @@ theorem IsTranscendenceBasis.polynomial [Nonempty ι] [Subsingleton ι] : variable {ι R} -set_option backward.isDefEq.respectTransparency false in theorem IsTranscendenceBasis.sumElim_comp [NoZeroDivisors A] {x : ι → S} {y : ι' → A} (hx : IsTranscendenceBasis R x) (hy : IsTranscendenceBasis S y) : IsTranscendenceBasis R (Sum.elim y (algebraMap S A ∘ x)) := by @@ -244,7 +238,6 @@ theorem IsTranscendenceBasis.nonempty_iff_transcendental [Nontrivial R] Nonempty ι ↔ Algebra.Transcendental R A := by rw [← not_isEmpty_iff, Algebra.transcendental_iff_not_isAlgebraic, hx.isEmpty_iff_isAlgebraic] -set_option backward.isDefEq.respectTransparency false in theorem IsTranscendenceBasis.isAlgebraic_field {F E : Type*} {x : ι → E} [Field F] [Field E] [Algebra F E] (hx : IsTranscendenceBasis F x) : Algebra.IsAlgebraic (IntermediateField.adjoin F (range x)) E := by @@ -264,7 +257,6 @@ section variable [NoZeroDivisors A] -set_option backward.isDefEq.respectTransparency false in set_option backward.privateInPublic true in private def indepMatroid : IndepMatroid A where E := univ @@ -317,7 +309,6 @@ end variable {R A} -set_option backward.isDefEq.respectTransparency false in theorem matroid_isBasis_iff [IsDomain A] {s t : Set A} : (matroid R A).IsBasis s t ↔ AlgebraicIndepOn R id s ∧ s ⊆ t ∧ ∀ a ∈ t, IsAlgebraic (adjoin R s) a := by rw [Matroid.IsBasis, maximal_iff_forall_insert fun s t h hst ↦ ⟨h.1.subset hst, hst.trans h.2⟩] @@ -335,7 +326,6 @@ theorem matroid_isBasis_iff_of_subsingleton [Subsingleton A] {s t : Set A} : simp_rw [Matroid.IsBasis, matroid_indep_iff, of_subsingleton, true_and, matroid_e, subset_univ, and_true, ← le_iff_subset, maximal_le_iff] -set_option backward.isDefEq.respectTransparency false in theorem isAlgebraic_adjoin_iff_of_matroid_isBasis [NoZeroDivisors A] {s t : Set A} {a : A} (h : (matroid R A).IsBasis s t) : IsAlgebraic (adjoin R s) a ↔ IsAlgebraic (adjoin R t) a := by cases subsingleton_or_nontrivial A @@ -344,7 +334,6 @@ theorem isAlgebraic_adjoin_iff_of_matroid_isBasis [NoZeroDivisors A] {s t : Set exact ⟨(·.adjoin_of_forall_isAlgebraic fun x hx ↦ (hx.2 <| h.1.1.2 hx.1).elim), (·.adjoin_of_forall_isAlgebraic fun x hx ↦ (matroid_isBasis_iff.mp h).2.2 _ hx.1)⟩ -set_option backward.isDefEq.respectTransparency false in theorem matroid_closure_eq [IsDomain A] {s : Set A} : (matroid R A).closure s = algebraicClosure (adjoin R s) A := by have ⟨B, hB⟩ := (matroid R A).exists_isBasis s @@ -365,7 +354,6 @@ theorem matroid_isFlat_iff [IsDomain A] {s : Set A} : refine Set.ext fun a ↦ ⟨(hs _ <| adjoin_eq s ▸ ·), fun h ↦ ?_⟩ exact isAlgebraic_algebraMap (A := A) (by exact (⟨a, subset_adjoin h⟩ : adjoin R s)) -set_option backward.isDefEq.respectTransparency false in theorem matroid_spanning_iff [IsDomain A] {s : Set A} : (matroid R A).Spanning s ↔ Algebra.IsAlgebraic (adjoin R s) A := by simp_rw [Matroid.spanning_iff, matroid_e, subset_univ, and_true, eq_univ_iff_forall, @@ -389,7 +377,6 @@ theorem matroid_spanning_iff_of_subsingleton [Subsingleton A] {s : Set A} : end AlgebraicIndependent -set_option backward.isDefEq.respectTransparency false in /-- If `s ⊆ t` are subsets in an `R`-algebra `A` such that `s` is algebraically independent over `R`, and `A` is algebraic over the `R`-algebra generated by `t`, then there is a transcendence basis of `A` over `R` between `s` and `t`, provided that `A` is a domain. @@ -411,7 +398,6 @@ theorem exists_isTranscendenceBasis_between [NoZeroDivisors A] (s t : Set A) (hs have ⟨B, base, hsB, hBt⟩ := hs.exists_isBase_subset_spanning ht hst exact ⟨B, hsB, hBt, base⟩ -set_option backward.isDefEq.respectTransparency false in theorem exists_isTranscendenceBasis_subset [NoZeroDivisors A] [FaithfulSMul R A] (s : Set A) [Algebra.IsAlgebraic (adjoin R s) A] : ∃ t, t ⊆ s ∧ IsTranscendenceBasis R ((↑) : t → A) := by @@ -419,7 +405,6 @@ theorem exists_isTranscendenceBasis_subset [NoZeroDivisors A] [FaithfulSMul R A] ((algebraicIndependent_empty_iff ..).mpr <| FaithfulSMul.algebraMap_injective R A) exact ⟨t, ht⟩ -set_option backward.isDefEq.respectTransparency false in theorem isAlgebraic_iff_exists_isTranscendenceBasis_subset [IsDomain A] [FaithfulSMul R A] {s : Set A} : Algebra.IsAlgebraic (adjoin R s) A ↔ ∃ t, t ⊆ s ∧ IsTranscendenceBasis R ((↑) : t → A) := by @@ -479,13 +464,11 @@ variable (R x) (s : Set A) variable [NoZeroDivisors A] -set_option backward.isDefEq.respectTransparency false in lemma isDomain_of_adjoin_range [Algebra.IsAlgebraic (adjoin R s) A] : IsDomain A := have := Algebra.IsAlgebraic.nontrivial (adjoin R s) A (isDomain_iff_noZeroDivisors_and_nontrivial _).mpr ⟨‹_›, (Subtype.val_injective (p := (· ∈ adjoin R s))).nontrivial⟩ -set_option backward.isDefEq.respectTransparency false in theorem trdeg_le_cardinalMk [alg : Algebra.IsAlgebraic (adjoin R s) A] : trdeg R A ≤ #s := by by_cases h : Injective (algebraMap R A) on_goal 2 => simp [trdeg_eq_zero_of_not_injective h] @@ -496,7 +479,6 @@ theorem trdeg_le_cardinalMk [alg : Algebra.IsAlgebraic (adjoin R s) A] : trdeg R variable [FaithfulSMul R A] -set_option backward.isDefEq.respectTransparency false in theorem isTranscendenceBasis_of_lift_le_trdeg_of_finite [Finite ι] [alg : Algebra.IsAlgebraic (adjoin R (range x)) A] (le : lift.{w} #ι ≤ lift.{u} (trdeg R A)) : IsTranscendenceBasis R x := by @@ -507,20 +489,17 @@ theorem isTranscendenceBasis_of_lift_le_trdeg_of_finite rw [← matroid_spanning_iff, ← matroid_cRank_eq] at * exact alg.isBase_of_le_cRank_of_finite (lift_le.mp <| mk_range_le_lift.trans le) (finite_range x) -set_option backward.isDefEq.respectTransparency false in theorem isTranscendenceBasis_of_le_trdeg_of_finite {ι : Type w} [Finite ι] (x : ι → A) [Algebra.IsAlgebraic (adjoin R (range x)) A] (le : #ι ≤ trdeg R A) : IsTranscendenceBasis R x := isTranscendenceBasis_of_lift_le_trdeg_of_finite R x (by rwa [lift_id, lift_id]) -set_option backward.isDefEq.respectTransparency false in theorem isTranscendenceBasis_of_lift_le_trdeg [Algebra.IsAlgebraic (adjoin R (range x)) A] (fin : trdeg R A < ℵ₀) (le : lift.{w} #ι ≤ lift.{u} (trdeg R A)) : IsTranscendenceBasis R x := have := mk_lt_aleph0_iff.mp (lift_lt.mp <| le.trans_lt <| (lift_lt.mpr fin).trans_eq <| by simp) isTranscendenceBasis_of_lift_le_trdeg_of_finite R x le -set_option backward.isDefEq.respectTransparency false in theorem isTranscendenceBasis_of_le_trdeg {ι : Type w} (x : ι → A) [Algebra.IsAlgebraic (adjoin R (range x)) A] (fin : trdeg R A < ℵ₀) (le : #ι ≤ trdeg R A) : IsTranscendenceBasis R x := @@ -577,7 +556,6 @@ namespace IsTranscendenceBasis variable {R S} [FaithfulSMul R S] [NoZeroDivisors S] (s : Set ι) (i j : ι) (v : ι → S) -set_option backward.isDefEq.respectTransparency false in /-- If `s` is a transcendence basis and `j` is algebraic over `s ∪ {i} \ {j}`, then `s ∪ {i} \ {j}` is also a transcendence basis. -/ lemma of_isAlgebraic_adjoin_insert_diff (hj : j ∈ insert i s) @@ -615,7 +593,6 @@ lemma of_isAlgebraic_adjoin_insert_diff (hj : j ∈ insert i s) image_insert_eq] at H₂ ⊢ exact H'.isBase_insert_diff_of_mem_closure H₂ (.inr ⟨j, hj, rfl⟩) -set_option backward.isDefEq.respectTransparency false in lemma of_isAlgebraic_adjoin_image_compl (H₁ : IsTranscendenceBasis R fun x : {x // x ≠ i} ↦ v x) (H₂ : IsAlgebraic (Algebra.adjoin R (v '' {j}ᶜ)) (v j)) : diff --git a/Mathlib/RingTheory/AlgebraicIndependent/Transcendental.lean b/Mathlib/RingTheory/AlgebraicIndependent/Transcendental.lean index d3318e3f15c56d..1dd102c2cf7ce9 100644 --- a/Mathlib/RingTheory/AlgebraicIndependent/Transcendental.lean +++ b/Mathlib/RingTheory/AlgebraicIndependent/Transcendental.lean @@ -98,7 +98,6 @@ theorem trdeg_ne_zero_iff : trdeg R A ≠ 0 ↔ Algebra.Transcendental R A := by open AlgebraicIndependent -set_option backward.isDefEq.respectTransparency false in theorem AlgebraicIndependent.option_iff_transcendental (hx : AlgebraicIndependent R x) (a : A) : AlgebraicIndependent R (fun o : Option ι ↦ o.elim a x) ↔ Transcendental (adjoin R (range x)) a := by @@ -108,14 +107,12 @@ theorem AlgebraicIndependent.option_iff_transcendental (hx : AlgebraicIndependen exact Injective.of_comp_iff' (Polynomial.aeval a) (mvPolynomialOptionEquivPolynomialAdjoin hx).bijective -set_option backward.isDefEq.respectTransparency false in theorem AlgebraicIndependent.option_iff {a : A} : AlgebraicIndependent R (fun o : Option ι ↦ o.elim a x) ↔ AlgebraicIndependent R x ∧ Transcendental (adjoin R (range x)) a := ⟨fun h ↦ have := h.comp _ (Option.some_injective _); ⟨this, (this.option_iff_transcendental _).mp h⟩, fun h ↦ (h.1.option_iff_transcendental _).mpr h.2⟩ -set_option backward.isDefEq.respectTransparency false in theorem AlgebraicIndepOn.insert_iff {s : Set ι} {i : ι} (h : i ∉ s) : AlgebraicIndepOn R x (insert i s) ↔ AlgebraicIndepOn R x s ∧ Transcendental (adjoin R (x '' s)) (x i) := by @@ -125,7 +122,6 @@ theorem AlgebraicIndepOn.insert_iff {s : Set ι} {i : ι} (h : i ∉ s) : · ext (_ | _) <;> rfl · rw [Set.image_eq_range] -set_option backward.isDefEq.respectTransparency false in protected theorem AlgebraicIndepOn.insert {s : Set ι} {i : ι} (hs : AlgebraicIndepOn R x s) (hi : Transcendental (adjoin R (x '' s)) (x i)) : AlgebraicIndepOn R x (insert i s) := by nontriviality R @@ -133,7 +129,6 @@ protected theorem AlgebraicIndepOn.insert {s : Set ι} {i : ι} (hs : AlgebraicI exact (insert_iff fun h ↦ hi <| isAlgebraic_algebraMap (⟨_, subset_adjoin ⟨i, h, rfl⟩⟩ : adjoin R (x '' s))).mpr ⟨hs, hi⟩ -set_option backward.isDefEq.respectTransparency false in theorem algebraicIndependent_of_set_of_finite (s : Set ι) (ind : AlgebraicIndependent R fun i : s ↦ x i) (H : ∀ t : Set ι, t.Finite → AlgebraicIndependent R (fun i : t ↦ x i) → @@ -152,7 +147,6 @@ theorem algebraicIndependent_of_set_of_finite (s : Set ι) (Equiv.setCongr union_insert) (Equiv.injective _) with x by_cases h : ↑x = a <;> simp [h, Set.subtypeInsertEquivOption] -set_option backward.isDefEq.respectTransparency false in /-- Variant of `algebraicIndependent_of_finite_type` using `Transcendental`. -/ theorem algebraicIndependent_of_finite_type' (hinj : Injective (algebraMap R A)) @@ -162,7 +156,6 @@ theorem algebraicIndependent_of_finite_type' algebraicIndependent_of_set_of_finite ∅ (algebraicIndependent_empty_type_iff.mpr hinj) fun t ht ind i _ ↦ H t ht ind i -set_option backward.isDefEq.respectTransparency false in /-- Variant of `algebraicIndependent_of_finite` using `Transcendental`. -/ theorem algebraicIndependent_of_finite' (s : Set A) (hinj : Injective (algebraMap R A)) @@ -175,7 +168,6 @@ theorem algebraicIndependent_of_finite' (s : Set A) namespace AlgebraicIndependent -set_option backward.isDefEq.respectTransparency false in theorem sumElim_iff {ι'} {y : ι' → A} : AlgebraicIndependent R (Sum.elim y x) ↔ AlgebraicIndependent R x ∧ AlgebraicIndependent (adjoin R (range x)) y := by by_cases hx : AlgebraicIndependent R x; swap @@ -185,7 +177,6 @@ theorem sumElim_iff {ι'} {y : ι' → A} : AlgebraicIndependent R (Sum.elim y x ext (_ | _) <;> simp [e] simp_rw [hx, AlgebraicIndependent, this]; simp -set_option backward.isDefEq.respectTransparency false in theorem iff_adjoin_image (s : Set ι) : AlgebraicIndependent R x ↔ AlgebraicIndependent R (fun i : s ↦ x i) ∧ AlgebraicIndepOn (adjoin R (x '' s)) x sᶜ := by @@ -194,13 +185,11 @@ theorem iff_adjoin_image (s : Set ι) : classical apply algebraicIndependent_equiv' ((Equiv.sumComm ..).trans (Equiv.Set.sumCompl ..)) ext (_ | _) <;> rfl -set_option backward.isDefEq.respectTransparency false in theorem iff_adjoin_image_compl (s : Set ι) : AlgebraicIndependent R x ↔ AlgebraicIndependent R (fun i : ↥sᶜ ↦ x i) ∧ AlgebraicIndepOn (adjoin R (x '' sᶜ)) x s := by convert ← iff_adjoin_image _; apply compl_compl -set_option backward.isDefEq.respectTransparency false in theorem iff_transcendental_adjoin_image (i : ι) : AlgebraicIndependent R x ↔ AlgebraicIndependent R (fun j : {j // j ≠ i} ↦ x j) ∧ Transcendental (adjoin R (x '' {i}ᶜ)) (x i) := @@ -210,12 +199,10 @@ theorem iff_transcendental_adjoin_image (i : ι) : variable (hx : AlgebraicIndependent R x) include hx -set_option backward.isDefEq.respectTransparency false in theorem sumElim {ι'} {y : ι' → A} (hy : AlgebraicIndependent (adjoin R (range x)) y) : AlgebraicIndependent R (Sum.elim y x) := sumElim_iff.mpr ⟨hx, hy⟩ -set_option backward.isDefEq.respectTransparency false in theorem sumElim_of_tower {ι'} {y : ι' → A} (hxS : range x ⊆ range (algebraMap S A)) (hy : AlgebraicIndependent S y) : AlgebraicIndependent R (Sum.elim y x) := by let e := AlgEquiv.ofInjective (IsScalarTower.toAlgHom R S A) hy.algebraMap_injective @@ -232,12 +219,10 @@ theorem sumElim_comp {ι'} {x : ι → S} {y : ι' → A} (hx : AlgebraicIndepen (hx.map' (f := IsScalarTower.toAlgHom R S A) hy.algebraMap_injective).sumElim_of_tower (range_comp_subset_range ..) hy -set_option backward.isDefEq.respectTransparency false in theorem adjoin_of_disjoint {s t : Set ι} (h : Disjoint s t) : AlgebraicIndependent (adjoin R (x '' s)) fun i : t ↦ x i := ((iff_adjoin_image s).mp hx).2.comp (inclusion _) (inclusion_injective h.subset_compl_left) -set_option backward.isDefEq.respectTransparency false in theorem adjoin_iff_disjoint [Nontrivial A] {s t : Set ι} : (AlgebraicIndependent (adjoin R (x '' s)) fun i : t ↦ x i) ↔ Disjoint s t := by refine ⟨fun ind ↦ of_not_not fun ndisj ↦ ?_, adjoin_of_disjoint hx⟩ @@ -245,13 +230,11 @@ theorem adjoin_iff_disjoint [Nontrivial A] {s t : Set ι} : refine ind.transcendental ⟨i, ht⟩ (isAlgebraic_algebraMap (⟨_, subset_adjoin ?_⟩ : adjoin R _)) exact ⟨i, hs, rfl⟩ -set_option backward.isDefEq.respectTransparency false in theorem transcendental_adjoin {s : Set ι} {i : ι} (hi : i ∉ s) : Transcendental (adjoin R (x '' s)) (x i) := by convert ← hx.adjoin_of_disjoint (Set.disjoint_singleton_right.mpr hi) rw [algebraicIndependent_singleton_iff ⟨i, rfl⟩] -set_option backward.isDefEq.respectTransparency false in theorem transcendental_adjoin_iff [Nontrivial A] {s : Set ι} {i : ι} : Transcendental (adjoin R (x '' s)) (x i) ↔ i ∉ s := by rw [← Set.disjoint_singleton_right] diff --git a/Mathlib/RingTheory/Artinian/Algebra.lean b/Mathlib/RingTheory/Artinian/Algebra.lean index cc5bc86afeacb1..b9624e203d1394 100644 --- a/Mathlib/RingTheory/Artinian/Algebra.lean +++ b/Mathlib/RingTheory/Artinian/Algebra.lean @@ -24,7 +24,6 @@ variable [CommRing R] [IsArtinianRing R] [Ring A] [Algebra R A] open nonZeroDivisors -set_option backward.isDefEq.respectTransparency false in /-- In an `R`-algebra over an Artinian ring `R`, if an element is integral and is not a zero divisor, then it is a unit. -/ theorem isUnit_of_isIntegral_of_nonZeroDivisor {a : A} diff --git a/Mathlib/RingTheory/DedekindDomain/Basic.lean b/Mathlib/RingTheory/DedekindDomain/Basic.lean index d8344ebe9a1e92..b3edc4429365b2 100644 --- a/Mathlib/RingTheory/DedekindDomain/Basic.lean +++ b/Mathlib/RingTheory/DedekindDomain/Basic.lean @@ -76,7 +76,6 @@ theorem isIntegralClosure (B : Type*) [CommRing B] [IsDomain B] [Nontrivial R] [ IsIntegralClosure.isMaximal_of_isMaximal_comap (R := R) A p (Ideal.IsPrime.isMaximal inferInstance (IsIntegralClosure.comap_ne_bot A ne_bot)) -set_option backward.isDefEq.respectTransparency false in nonrec instance integralClosure [Nontrivial R] [IsDomain A] [Algebra R A] [DimensionLEOne R] : DimensionLEOne (integralClosure R A) := DimensionLEOne.isIntegralClosure R A (integralClosure R A) diff --git a/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean b/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean index 21f66039595257..4bc1663549a161 100644 --- a/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean +++ b/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean @@ -57,7 +57,6 @@ variable [Algebra K L] [Algebra A L] [IsScalarTower A K L] variable [Algebra C L] [IsIntegralClosure C A L] [Algebra A C] [IsScalarTower A C L] include K L -set_option backward.isDefEq.respectTransparency false in /-- If `L` is an algebraic extension of `K = Frac(A)` and `L` has no zero smul divisors by `A`, then `L` is the localization of the integral closure `C` of `A` in `L` at `A⁰`. -/ theorem IsIntegralClosure.isLocalization [IsDomain A] [Algebra.IsAlgebraic K L] : @@ -99,7 +98,6 @@ theorem IsIntegralClosure.range_le_span_dualBasis [Algebra.IsSeparable K L] {ι refine Submodule.mem_one.mpr <| IsIntegrallyClosed.isIntegral_iff.mp ?_ exact isIntegral_trace ((IsIntegralClosure.isIntegral A L y).algebraMap.mul (hb_int i)) -set_option backward.isDefEq.respectTransparency false in theorem integralClosure_le_span_dualBasis [Algebra.IsSeparable K L] {ι : Type*} [Finite ι] [DecidableEq ι] (b : Basis ι K L) (hb_int : ∀ i, IsIntegral A (b i)) [IsIntegrallyClosed A] : Subalgebra.toSubmodule (integralClosure A L) ≤ @@ -201,7 +199,6 @@ theorem IsIntegralClosure.rank [IsPrincipalIdealRing A] [IsTorsionFree A L] : variable {A K} -set_option backward.isDefEq.respectTransparency false in /-- If `L` is a finite separable extension of `K = Frac(A)`, where `A` is integrally closed and Noetherian, the integral closure of `A` in `L` is Noetherian. -/ @@ -226,7 +223,6 @@ theorem IsIntegralClosure.isDedekindDomain [IsDedekindDomain A] : IsDedekindDoma ⟨IsIntegralClosure.mk' C x (isIntegral_trans (R := A) _ hx), IsIntegralClosure.algebraMap_mk' _ _ _⟩ with : IsDedekindDomain C } -set_option backward.isDefEq.respectTransparency false in /-- If `L` is a finite separable extension of `K = Frac(A)`, where `A` is a Dedekind domain, the integral closure of `A` in `L` is a Dedekind domain. diff --git a/Mathlib/RingTheory/DedekindDomain/LinearDisjoint.lean b/Mathlib/RingTheory/DedekindDomain/LinearDisjoint.lean index 7eda72bd136f60..d802ebe4c6e5b9 100644 --- a/Mathlib/RingTheory/DedekindDomain/LinearDisjoint.lean +++ b/Mathlib/RingTheory/DedekindDomain/LinearDisjoint.lean @@ -32,8 +32,6 @@ and `Frac R` denotes the fraction field of a domain `R`. open FractionalIdeal nonZeroDivisors IntermediateField Algebra Module Submodule -set_option backward.isDefEq.respectTransparency false - variable (A B : Type*) {K L : Type*} [CommRing A] [Field K] [Algebra A K] [IsFractionRing A K] [CommRing B] [Field L] [Algebra B L] [Algebra A L] [Algebra K L] [FiniteDimensional K L] [IsScalarTower A K L] diff --git a/Mathlib/RingTheory/EssentialFiniteness.lean b/Mathlib/RingTheory/EssentialFiniteness.lean index 6a371c570c1c33..3d95b61c649c00 100644 --- a/Mathlib/RingTheory/EssentialFiniteness.lean +++ b/Mathlib/RingTheory/EssentialFiniteness.lean @@ -157,7 +157,6 @@ lemma EssFiniteType.comp [h₁ : EssFiniteType R S] [h₂ : EssFiniteType S T] : · rw [← mul_smul, mul_comm, smul_mul_assoc, mul_comm, mul_comm y, mul_smul, Algebra.smul_def] exact mul_mem (Algebra.mem_sup_left ⟨_, h₁, rfl⟩) h₆ -set_option backward.isDefEq.respectTransparency false in open EssFiniteType in lemma essFiniteType_iff_exists_subalgebra : EssFiniteType R S ↔ ∃ (S₀ : Subalgebra R S) (M : Submonoid S₀), FiniteType R S₀ ∧ IsLocalization M S := by diff --git a/Mathlib/RingTheory/Etale/Field.lean b/Mathlib/RingTheory/Etale/Field.lean index 7f84f6a0cd0612..6e5afd65c45e7b 100644 --- a/Mathlib/RingTheory/Etale/Field.lean +++ b/Mathlib/RingTheory/Etale/Field.lean @@ -95,7 +95,6 @@ theorem of_isSeparable_aux [Algebra.IsSeparable K L] [EssFiniteType K L] : apply Ideal.pow_mem_pow rw [← Ideal.Quotient.eq_zero_iff_mem, map_mul, hx', mul_zero] -set_option backward.isDefEq.respectTransparency false in open scoped IntermediateField in lemma of_isSeparable [Algebra.IsSeparable K L] : FormallyEtale K L := by -- We shall show that any `f : L → B/I` can be lifted to `L → B` if `I^2 = ⊥`. diff --git a/Mathlib/RingTheory/Etale/QuasiFinite.lean b/Mathlib/RingTheory/Etale/QuasiFinite.lean index 423b02a98dbda5..c67580eb3fa50e 100644 --- a/Mathlib/RingTheory/Etale/QuasiFinite.lean +++ b/Mathlib/RingTheory/Etale/QuasiFinite.lean @@ -201,7 +201,6 @@ lemma Algebra.exists_notMem_and_isIntegral_forall_mem_of_ne_of_liesOver · rw [map_pow]; exact Ideal.notMem_of_isUnit _ (.pow _ (IsLocalization.Away.algebraMap_isUnit _)) #adaptation_note /-- The maxHeartbeats bump is required after leanprover/lean4#12564. -/ -set_option backward.isDefEq.respectTransparency false in set_option maxHeartbeats 400000 in -- see adaptation note lemma Algebra.exists_etale_isIdempotentElem_forall_liesOver_eq_aux {R : Type u} {S : Type v} [CommRing R] [CommRing S] [Algebra R S] [Algebra.FiniteType R S] @@ -373,7 +372,6 @@ lemma Algebra.exists_etale_isIdempotentElem_forall_liesOver_eq_aux₂ simp only [← IsScalarTower.algebraMap_eq, RingHom.comp_assoc, AlgHom.comp_algebraMap_of_tower, Algebra.ofId_apply] -set_option backward.isDefEq.respectTransparency false in /-- Let `S` be a finite type `R`-algebra, and `q` a prime lying over `p` such that `S` is quasi-finite at `q`. diff --git a/Mathlib/RingTheory/Extension/Presentation/Core.lean b/Mathlib/RingTheory/Extension/Presentation/Core.lean index aa0400d25b4295..f1b6713ff7199a 100644 --- a/Mathlib/RingTheory/Extension/Presentation/Core.lean +++ b/Mathlib/RingTheory/Extension/Presentation/Core.lean @@ -94,7 +94,6 @@ lemma HasCoeffs.of_isScalarTower {R₁ : Type*} [CommRing R₁] [Algebra R₀ R refine ⟨subset_trans (P.coeffs_subset_range R₀) ?_⟩ simp [IsScalarTower.algebraMap_eq R₀ R₁ R, RingHom.coe_comp, Set.range_comp] -set_option backward.isDefEq.respectTransparency false in instance (s : Set R) : P.HasCoeffs (Algebra.adjoin R₀ s) := HasCoeffs.of_isScalarTower R₀ lemma HasCoeffs.coeffs_relation_mem_range (x : σ) : diff --git a/Mathlib/RingTheory/Filtration.lean b/Mathlib/RingTheory/Filtration.lean index 2fe5bd2b28bf80..d1ab6cfa3776ae 100644 --- a/Mathlib/RingTheory/Filtration.lean +++ b/Mathlib/RingTheory/Filtration.lean @@ -331,7 +331,6 @@ theorem submodule_eq_span_le_iff_stable_ge (n₀ : ℕ) : · rw [map_add] exact F'.add_mem hx hy -set_option backward.isDefEq.respectTransparency false in /-- If the components of a filtration are finitely generated, then the filtration is stable iff its associated submodule of is finitely generated. -/ theorem submodule_fg_iff_stable (hF' : ∀ i, (F.N i).FG) : F.submodule.FG ↔ F.Stable := by @@ -370,7 +369,6 @@ theorem submodule_fg_iff_stable (hF' : ∀ i, (F.N i).FG) : F.submodule.FG ↔ F variable {F} -set_option backward.isDefEq.respectTransparency false in theorem Stable.of_le [IsNoetherianRing R] [Module.Finite R M] (hF : F.Stable) {F' : I.Filtration M} (hf : F' ≤ F) : F'.Stable := by rw [← submodule_fg_iff_stable] at hF ⊢ diff --git a/Mathlib/RingTheory/Flat/Basic.lean b/Mathlib/RingTheory/Flat/Basic.lean index e2649f270f68ac..d63f1360a7cc86 100644 --- a/Mathlib/RingTheory/Flat/Basic.lean +++ b/Mathlib/RingTheory/Flat/Basic.lean @@ -591,7 +591,6 @@ theorem IsSMulRegular.of_flat {x : R} (reg : IsSMulRegular R x) : end IsSMulRegular -set_option backward.isDefEq.respectTransparency false in /-- Let `R` be a commutative semiring, let `C` be a commutative `R`-algebra, and let `A` be an `R`-algebra. If `C ⊗[R] B` is reduced for all finitely generated subalgebras `B` of `A`, then `C ⊗[R] A` is also reduced. -/ diff --git a/Mathlib/RingTheory/Flat/Equalizer.lean b/Mathlib/RingTheory/Flat/Equalizer.lean index c040345c47bf78..ca82f2a04f9233 100644 --- a/Mathlib/RingTheory/Flat/Equalizer.lean +++ b/Mathlib/RingTheory/Flat/Equalizer.lean @@ -248,7 +248,6 @@ variable (T : Type*) [CommRing T] [Algebra R T] [Algebra S T] [IsScalarTower R S variable {A B : Type*} [CommRing A] [CommRing B] [Algebra R A] [Algebra R B] (f g : A →ₐ[R] B) -set_option backward.isDefEq.respectTransparency false in set_option backward.privateInPublic true in private def AlgHom.tensorEqualizerAux : T ⊗[R] AlgHom.equalizer f g →ₗ[S] @@ -258,7 +257,6 @@ private def AlgHom.tensorEqualizerAux : private local instance : AddHomClass (A →ₐ[R] B) A B := inferInstance -set_option backward.isDefEq.respectTransparency false in @[simp] private lemma AlgHom.coe_tensorEqualizerAux (x : T ⊗[R] AlgHom.equalizer f g) : (AlgHom.tensorEqualizerAux S T f g x : T ⊗[R] A) = @@ -268,7 +266,6 @@ private lemma AlgHom.coe_tensorEqualizerAux (x : T ⊗[R] AlgHom.equalizer f g) | tmul => rfl | add x y hx hy => simp [hx, hy] -set_option backward.isDefEq.respectTransparency false in set_option backward.privateInPublic true in private lemma AlgHom.tensorEqualizerAux_mul (x y : T ⊗[R] AlgHom.equalizer f g) : AlgHom.tensorEqualizerAux S T f g (x * y) = @@ -278,7 +275,6 @@ private lemma AlgHom.tensorEqualizerAux_mul (x y : T ⊗[R] AlgHom.equalizer f g rw [AlgHom.coe_tensorEqualizerAux] simp -set_option backward.isDefEq.respectTransparency false in set_option backward.privateInPublic true in set_option backward.privateInPublic.warn false in /-- The canonical map `T ⊗[R] eq(f, g) →ₐ[S] eq (𝟙 ⊗ f, 𝟙 ⊗ g)`. -/ @@ -289,7 +285,6 @@ def AlgHom.tensorEqualizer : AlgHom.ofLinearMap (AlgHom.tensorEqualizerAux S T f g) rfl (AlgHom.tensorEqualizerAux_mul S T f g) -set_option backward.isDefEq.respectTransparency false in @[simp] lemma AlgHom.coe_tensorEqualizer (x : T ⊗[R] AlgHom.equalizer f g) : (AlgHom.tensorEqualizer S T f g x : T ⊗[R] A) = @@ -297,7 +292,6 @@ lemma AlgHom.coe_tensorEqualizer (x : T ⊗[R] AlgHom.equalizer f g) : AlgHom.coe_tensorEqualizerAux S T f g x #adaptation_note /-- After nightly-2026-02-23 we need this to avoid timeouts. -/ -set_option backward.isDefEq.respectTransparency false in set_option backward.privateInPublic true in set_option backward.privateInPublic.warn false in /-- If `T` is `R`-flat, the canonical map @@ -309,7 +303,6 @@ def AlgHom.tensorEqualizerEquiv [Module.Flat R T] : AlgEquiv.ofLinearEquiv (LinearMap.tensorEqLocusEquiv S T f.toLinearMap g.toLinearMap) rfl (AlgHom.tensorEqualizerAux_mul S T f g) -set_option backward.isDefEq.respectTransparency false in @[simp] lemma AlgHom.tensorEqualizerEquiv_apply [Module.Flat R T] (x : T ⊗[R] AlgHom.equalizer f g) : diff --git a/Mathlib/RingTheory/Ideal/GoingUp.lean b/Mathlib/RingTheory/Ideal/GoingUp.lean index 68fc477ca7eb94..69d5422b50f512 100644 --- a/Mathlib/RingTheory/Ideal/GoingUp.lean +++ b/Mathlib/RingTheory/Ideal/GoingUp.lean @@ -245,13 +245,11 @@ theorem IsIntegralClosure.eq_bot_of_comap_eq_bot [Nontrivial R] {I : Ideal A} : end IsIntegralClosure -set_option backward.isDefEq.respectTransparency false in theorem IntegralClosure.comap_lt_comap {I J : Ideal (integralClosure R S)} [I.IsPrime] (I_lt_J : I < J) : I.comap (algebraMap R (integralClosure R S)) < J.comap (algebraMap R (integralClosure R S)) := IsIntegralClosure.comap_lt_comap S I_lt_J -set_option backward.isDefEq.respectTransparency false in theorem IntegralClosure.isMaximal_of_isMaximal_comap (I : Ideal (integralClosure R S)) [I.IsPrime] (hI : IsMaximal (I.comap (algebraMap R (integralClosure R S)))) : IsMaximal I := IsIntegralClosure.isMaximal_of_isMaximal_comap S I hI @@ -260,12 +258,10 @@ section variable [IsDomain S] -set_option backward.isDefEq.respectTransparency false in theorem IntegralClosure.comap_ne_bot [Nontrivial R] {I : Ideal (integralClosure R S)} (I_ne_bot : I ≠ ⊥) : I.comap (algebraMap R (integralClosure R S)) ≠ ⊥ := IsIntegralClosure.comap_ne_bot S I_ne_bot -set_option backward.isDefEq.respectTransparency false in theorem IntegralClosure.eq_bot_of_comap_eq_bot [Nontrivial R] {I : Ideal (integralClosure R S)} : I.comap (algebraMap R (integralClosure R S)) = ⊥ → I = ⊥ := IsIntegralClosure.eq_bot_of_comap_eq_bot S diff --git a/Mathlib/RingTheory/Ideal/Norm/AbsNorm.lean b/Mathlib/RingTheory/Ideal/Norm/AbsNorm.lean index b972242031ac5c..07befae4818479 100644 --- a/Mathlib/RingTheory/Ideal/Norm/AbsNorm.lean +++ b/Mathlib/RingTheory/Ideal/Norm/AbsNorm.lean @@ -171,7 +171,7 @@ theorem cardQuot_pow_of_prime [IsDedekindDomain S] (hP : P ≠ ⊥) {i : ℕ} : simpa only [Submodule.Quotient.mk''_eq_mk, Submodule.Quotient.mk''_eq_mk, Submodule.Quotient.eq] using h · intro d' - refine Quotient.inductionOn' d' fun d => ?_ + induction d' using Quotient.inductionOn with | _ d have hd' := (mem_map (f := mkQ (P ^ i.succ))).mpr ⟨a * d, Ideal.mul_mem_right d _ a_mem, rfl⟩ refine ⟨⟨_, hd'⟩, ?_⟩ simp only [Submodule.Quotient.mk''_eq_mk, Ideal.Quotient.mk_eq_mk, Ideal.Quotient.eq] diff --git a/Mathlib/RingTheory/Ideal/Pure.lean b/Mathlib/RingTheory/Ideal/Pure.lean index bcdfee2024610f..caebfdb929a9bf 100644 --- a/Mathlib/RingTheory/Ideal/Pure.lean +++ b/Mathlib/RingTheory/Ideal/Pure.lean @@ -40,7 +40,6 @@ open TensorProduct PrimeSpectrum abbrev Ideal.Pure (I : Ideal R) : Prop := Module.Flat R (R ⧸ I) -set_option backward.isDefEq.respectTransparency false in lemma injective_lTensor_quotient_iff_inf_eq_mul (I J : Ideal R) : Function.Injective (J.subtype.lTensor (R ⧸ I)) ↔ I ⊓ J = I * J := by let f : J ⧸ (I • ⊤ : Submodule R J) →ₗ[R] R ⧸ I := diff --git a/Mathlib/RingTheory/Ideal/Quotient/HasFiniteQuotients.lean b/Mathlib/RingTheory/Ideal/Quotient/HasFiniteQuotients.lean index d3c942537bd1f6..3204ed617d44d2 100644 --- a/Mathlib/RingTheory/Ideal/Quotient/HasFiniteQuotients.lean +++ b/Mathlib/RingTheory/Ideal/Quotient/HasFiniteQuotients.lean @@ -19,7 +19,7 @@ quotient `R ⧸ I` is finite. - `Ring.HasFiniteQuotients.instIsNoetherianRing` : A ring with finite quotients is noetherian. - `Ring.HasFiniteQuotients.of_module_finite`: Assume that `R` has finite quotients and that `S` is a domain and a finite `R`-module. Then `S` has finite quotients. -- `Ring.HasFiniteQuotients.instOfIsDomainOfFiniteInt`: A domain that is also a finite `ℤ`-module +- `Ring.HasFiniteQuotients.instOfIsDomainOfFG`: A domain that is also a finite `ℤ`-module has finite quotients. -/ @@ -86,8 +86,8 @@ instance : HasFiniteQuotients ℤ where have : NeZero n := ⟨by simpa using hI⟩ exact inferInstanceAs <| Finite (ℤ ⧸ Ideal.span {n}) -/-- A domain that is also a finite `ℤ`-module has finite quotients. -/ -instance [IsDomain R] [Module.Finite ℤ R] : HasFiniteQuotients R := +/-- A domain that is finitely generated has finite quotients. -/ +instance [IsDomain R] [AddGroup.FG R] : HasFiniteQuotients R := of_module_finite ℤ R end Ring.HasFiniteQuotients diff --git a/Mathlib/RingTheory/Ideal/Quotient/Nilpotent.lean b/Mathlib/RingTheory/Ideal/Quotient/Nilpotent.lean index 58c5845359af41..20015431c51412 100644 --- a/Mathlib/RingTheory/Ideal/Quotient/Nilpotent.lean +++ b/Mathlib/RingTheory/Ideal/Quotient/Nilpotent.lean @@ -50,7 +50,6 @@ theorem Ideal.IsNilpotent.induction_on (hI : IsNilpotent I) · apply h₁ rw [← Ideal.map_pow, Ideal.map_quotient_self] -set_option backward.isDefEq.respectTransparency false in theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R} (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by refine ⟨?_, fun h => h.map <| Ideal.Quotient.mk I⟩ diff --git a/Mathlib/RingTheory/Ideal/Quotient/Operations.lean b/Mathlib/RingTheory/Ideal/Quotient/Operations.lean index da6dae5292d670..9f0ae55ec71f2d 100644 --- a/Mathlib/RingTheory/Ideal/Quotient/Operations.lean +++ b/Mathlib/RingTheory/Ideal/Quotient/Operations.lean @@ -495,7 +495,6 @@ theorem Quotient.span_singleton_one (I : Ideal A) [I.IsTwoSided] : rw [← map_one (mk _), ← Submodule.range_mkQ I, ← Submodule.map_top, ← Ideal.span_singleton_one, Ideal.span, Submodule.map_span, Set.image_singleton, Submodule.mkQ_apply, Quotient.mk_eq_mk] -set_option backward.isDefEq.respectTransparency false in open Pointwise in lemma Quotient.smul_top {R : Type*} [CommRing R] (a : R) (I : Ideal R) : (a • ⊤ : Submodule R (R ⧸ I)) = Submodule.span R {Submodule.Quotient.mk a} := by diff --git a/Mathlib/RingTheory/IntegralClosure/Algebra/Basic.lean b/Mathlib/RingTheory/IntegralClosure/Algebra/Basic.lean index 352f203af8b0b9..db421a4c667aed 100644 --- a/Mathlib/RingTheory/IntegralClosure/Algebra/Basic.lean +++ b/Mathlib/RingTheory/IntegralClosure/Algebra/Basic.lean @@ -32,7 +32,6 @@ variable {R A B S : Type*} variable [CommRing R] [CommRing A] [Ring B] [CommRing S] variable [Algebra R A] [Algebra R B] (f : R →+* S) -set_option backward.isDefEq.respectTransparency false in theorem Subalgebra.isIntegral_iff (S : Subalgebra R B) : Algebra.IsIntegral R S ↔ ∀ x ∈ S, IsIntegral R x := Algebra.isIntegral_def.trans <| .trans @@ -77,7 +76,6 @@ lemma Algebra.isIntegral_of_surjective (H : Function.Surjective (algebraMap R B) Algebra.IsIntegral R B := .of_surjective (Algebra.ofId R B) H -set_option backward.isDefEq.respectTransparency false in /-- If `S` is a sub-`R`-algebra of `A` and `S` is finitely-generated as an `R`-module, then all elements of `S` are integral over `R`. -/ theorem IsIntegral.of_mem_of_fg (S : Subalgebra R B) @@ -89,7 +87,6 @@ theorem isIntegral_of_submodule_noetherian (S : Subalgebra R B) (H : IsNoetherian R (Subalgebra.toSubmodule S)) (x : B) (hx : x ∈ S) : IsIntegral R x := .of_mem_of_fg _ ((Submodule.fg_top _).mp <| H.noetherian _) _ hx -set_option backward.isDefEq.respectTransparency false in /-- Suppose `A` is an `R`-algebra, `M` is an `A`-module such that `a • m ≠ 0` for all non-zero `a` and `m`. If `x : A` fixes a nontrivial f.g. `R`-submodule `N` of `M`, then `x` is `R`-integral. -/ theorem isIntegral_of_smul_mem_submodule [IsDomain A] {M : Type*} [AddCommGroup M] [Module R M] diff --git a/Mathlib/RingTheory/IntegralClosure/Algebra/Ideal.lean b/Mathlib/RingTheory/IntegralClosure/Algebra/Ideal.lean index a14e3b2a30c12a..a36162f63c4424 100644 --- a/Mathlib/RingTheory/IntegralClosure/Algebra/Ideal.lean +++ b/Mathlib/RingTheory/IntegralClosure/Algebra/Ideal.lean @@ -44,7 +44,6 @@ lemma coeff_mem_pow_of_mem_adjoin_C_mul_X {R : Type*} [CommRing R] obtain rfl : j₁ + j₂ = i := by simpa using hj exact pow_add I j₁ j₂ ▸ Ideal.mul_mem_mul (hx _) (hy _) -set_option backward.isDefEq.respectTransparency false in attribute [local instance] Polynomial.algebra in lemma exists_monic_aeval_eq_zero_forall_mem_pow_of_isIntegral {I : Ideal R} {x : S} @@ -71,7 +70,6 @@ lemma exists_monic_aeval_eq_zero_forall_mem_pow_of_isIntegral · rw [hq] simp [q, apply_ite, coeff_mem_pow_of_mem_adjoin_C_mul_X (p.coeff _).2] -set_option backward.isDefEq.respectTransparency false in lemma exists_monic_aeval_eq_zero_forall_mem_pow_of_mem_map [Algebra.IsIntegral R S] {I : Ideal R} {x : S} (hx : x ∈ I.map (algebraMap R S)) : ∃ p : R[X], p.Monic ∧ aeval x p = 0 ∧ ∀ i, p.coeff i ∈ I ^ (p.natDegree - i) := by diff --git a/Mathlib/RingTheory/IntegralClosure/IntegralRestrict.lean b/Mathlib/RingTheory/IntegralClosure/IntegralRestrict.lean index 468c03fe290e43..34c4d9145f9812 100644 --- a/Mathlib/RingTheory/IntegralClosure/IntegralRestrict.lean +++ b/Mathlib/RingTheory/IntegralClosure/IntegralRestrict.lean @@ -49,7 +49,6 @@ section galRestrict' variable {K L L₂ L₃} omit [IsFractionRing A K] -set_option backward.isDefEq.respectTransparency false in /-- A generalization of `galRestrictHom` beyond endomorphisms. -/ noncomputable def galRestrict' (f : L →ₐ[K] L₂) : (B →ₐ[A] B₂) := @@ -57,7 +56,6 @@ def galRestrict' (f : L →ₐ[K] L₂) : (B →ₐ[A] B₂) := (((f.restrictScalars A).comp (IsScalarTower.toAlgHom A B L)).codRestrict (integralClosure A L₂) (fun x ↦ IsIntegral.map _ (IsIntegralClosure.isIntegral A L x))) -set_option backward.isDefEq.respectTransparency false in @[simp] lemma algebraMap_galRestrict'_apply (σ : L →ₐ[K] L₂) (x : B) : algebraMap B₂ L₂ (galRestrict' A B B₂ σ x) = σ (algebraMap B L x) := by @@ -69,7 +67,6 @@ theorem galRestrict'_id : galRestrict' A B B (.id K L) = .id A B := by apply IsIntegralClosure.algebraMap_injective B A L simp -set_option backward.isDefEq.respectTransparency false in theorem galRestrict'_comp (σ : L →ₐ[K] L₂) (σ' : L₂ →ₐ[K] L₃) : galRestrict' A B B₃ (σ'.comp σ) = (galRestrict' A B₂ B₃ σ').comp (galRestrict' A B B₂ σ) := by ext x @@ -124,7 +121,6 @@ theorem galLift_comp [Algebra.IsAlgebraic K L₂] (σ : B →ₐ[A] B₂) (σ' : AlgHom.coe_ringHom_injective <| IsLocalization.ringHom_ext (Algebra.algebraMapSubmonoid B A⁰) <| RingHom.ext fun x ↦ by simp -set_option backward.isDefEq.respectTransparency false in @[simp] theorem galLift_galRestrict' (σ : L →ₐ[K] L₂) : galLift K L L₂ (galRestrict' A B B₂ σ) = σ := @@ -133,7 +129,6 @@ theorem galLift_galRestrict' (σ : L →ₐ[K] L₂) : AlgHom.coe_ringHom_injective <| IsLocalization.ringHom_ext (Algebra.algebraMapSubmonoid B A⁰) <| RingHom.ext fun x ↦ by simp [galRestrict', Subalgebra.algebraMap_eq, galLift] -set_option backward.isDefEq.respectTransparency false in @[simp] theorem galRestrict'_galLift (σ : B →ₐ[A] B₂) : galRestrict' A B B₂ (galLift K L L₂ σ) = σ := @@ -238,7 +233,6 @@ variable [IsLocalization (Algebra.algebraMapSubmonoid B M) Bₘ] section trace -set_option backward.isDefEq.respectTransparency false in /-- The restriction of the trace on `L/K` restricted onto `B/A` in an AKLB setup. See `Algebra.intTrace` instead. -/ noncomputable @@ -252,7 +246,6 @@ def Algebra.intTraceAux [IsIntegrallyClosed A] : variable {A K L B} -set_option backward.isDefEq.respectTransparency false in lemma Algebra.map_intTraceAux [IsIntegrallyClosed A] (x : B) : algebraMap A K (Algebra.intTraceAux A K L B x) = Algebra.trace K L (algebraMap B L x) := IsIntegralClosure.algebraMap_equiv A (integralClosure A K) K A _ diff --git a/Mathlib/RingTheory/IntegralClosure/IntegrallyClosed.lean b/Mathlib/RingTheory/IntegralClosure/IntegrallyClosed.lean index 908212b5a6a44f..e9501149b8e5fb 100644 --- a/Mathlib/RingTheory/IntegralClosure/IntegrallyClosed.lean +++ b/Mathlib/RingTheory/IntegralClosure/IntegrallyClosed.lean @@ -127,12 +127,10 @@ theorem isIntegrallyClosed_iff : simp [isIntegrallyClosed_iff_isIntegrallyClosedIn K, isIntegrallyClosedIn_iff, IsFractionRing.injective R K] -set_option backward.isDefEq.respectTransparency false in instance : IsIntegrallyClosedIn (integralClosure R A) A := isIntegrallyClosedIn_iff.mpr ⟨FaithfulSMul.algebraMap_injective _ _, fun h ↦ ⟨⟨_, isIntegral_trans _ h⟩, rfl⟩⟩ -set_option backward.isDefEq.respectTransparency false in instance : IsIntegrallyClosedIn (integralClosure R A).toSubring A := inferInstanceAs (IsIntegrallyClosedIn (integralClosure R A) A) @@ -185,7 +183,6 @@ theorem exists_algebraMap_eq_of_isIntegral_pow [IsIntegrallyClosedIn R A] (hx : IsIntegral R <| x ^ n) : ∃ y : R, algebraMap R A y = x := isIntegral_iff.mp <| hx.of_pow hn -set_option backward.isDefEq.respectTransparency false in theorem exists_algebraMap_eq_of_pow_mem_subalgebra {A : Type*} [CommRing A] [Algebra R A] {S : Subalgebra R A} [IsIntegrallyClosedIn S A] {x : A} {n : ℕ} (hn : 0 < n) (hx : x ^ n ∈ S) : ∃ y : S, algebraMap S A y = x := @@ -256,7 +253,6 @@ theorem exists_algebraMap_eq_of_isIntegral_pow [IsIntegrallyClosed R] {x : K} {n (hx : IsIntegral R <| x ^ n) : ∃ y : R, algebraMap R K y = x := IsIntegrallyClosedIn.exists_algebraMap_eq_of_isIntegral_pow hn hx -set_option backward.isDefEq.respectTransparency false in theorem exists_algebraMap_eq_of_pow_mem_subalgebra {K : Type*} [CommRing K] [Algebra R K] {S : Subalgebra R K} [IsIntegrallyClosed S] [IsFractionRing S K] {x : K} {n : ℕ} (hn : 0 < n) (hx : x ^ n ∈ S) : ∃ y : S, algebraMap S K y = x := @@ -367,7 +363,6 @@ variable (K : Type*) [Field K] [Algebra R K] variable [IsFractionRing R K] variable {L : Type*} [Field L] [Algebra K L] [Algebra R L] [IsScalarTower R K L] -set_option backward.isDefEq.respectTransparency false in -- Can't be an instance because you need to supply `K`. theorem isIntegrallyClosedOfFiniteExtension [IsDomain R] [FiniteDimensional K L] : IsIntegrallyClosed (integralClosure R L) := diff --git a/Mathlib/RingTheory/IntegralClosure/IsIntegral/AlmostIntegral.lean b/Mathlib/RingTheory/IntegralClosure/IsIntegral/AlmostIntegral.lean index 5d2fe4f01fee4e..91031e26fe3cd9 100644 --- a/Mathlib/RingTheory/IntegralClosure/IsIntegral/AlmostIntegral.lean +++ b/Mathlib/RingTheory/IntegralClosure/IsIntegral/AlmostIntegral.lean @@ -83,7 +83,6 @@ lemma integralClosure_le_completeIntegralClosure [IsFractionRing R S] : integralClosure R S ≤ completeIntegralClosure R S := fun _ h ↦ h.isAlmostIntegral -set_option backward.isDefEq.respectTransparency false in lemma IsAlmostIntegral.isIntegral_of_nonZeroDivisors_le_comap {s : S} (H : IsAlmostIntegral R s) [IsNoetherianRing R] (H' : R⁰ ≤ S⁰.comap (algebraMap R S)) : IsIntegral R s := by diff --git a/Mathlib/RingTheory/IntegralClosure/IsIntegral/Basic.lean b/Mathlib/RingTheory/IntegralClosure/IsIntegral/Basic.lean index 0fa212b83f3d05..fef2feb9d37219 100644 --- a/Mathlib/RingTheory/IntegralClosure/IsIntegral/Basic.lean +++ b/Mathlib/RingTheory/IntegralClosure/IsIntegral/Basic.lean @@ -223,17 +223,14 @@ theorem fg_adjoin_of_finite {s : Set A} (hfs : s.Finite) (his : ∀ x ∈ s, IsI (ih fun i hi => his i <| Set.mem_insert_of_mem a hi) (his a <| Set.mem_insert a s).fg_adjoin_singleton -set_option backward.isDefEq.respectTransparency false in theorem Algebra.finite_adjoin_of_finite_of_isIntegral {s : Set A} (hf : s.Finite) (hi : ∀ x ∈ s, IsIntegral R x) : Module.Finite R (adjoin R s) := .of_fg <| fg_adjoin_of_finite hf hi -set_option backward.isDefEq.respectTransparency false in theorem Algebra.finite_adjoin_simple_of_isIntegral {x : B} (hi : IsIntegral R x) : Module.Finite R (adjoin R {x}) := .of_fg hi.fg_adjoin_singleton -set_option backward.isDefEq.respectTransparency false in theorem isNoetherian_adjoin_finset [IsNoetherianRing R] (s : Finset A) (hs : ∀ x ∈ s, IsIntegral R x) : IsNoetherian R (Algebra.adjoin R (s : Set A)) := isNoetherian_of_fg_of_noetherian _ (fg_adjoin_of_finite s.finite_toSet hs) diff --git a/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean b/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean index 2d97a4ff5b953b..16960ee4d99a15 100644 --- a/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean +++ b/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean @@ -32,7 +32,6 @@ open Algebra variable {R S : Type*} -set_option backward.isDefEq.respectTransparency false in /-- A nonzero element in a domain integral over a field is a unit. -/ theorem IsIntegral.isUnit [Field R] [Ring S] [IsDomain S] [Algebra R S] {x : S} (int : IsIntegral R x) (h0 : x ≠ 0) : IsUnit x := @@ -52,7 +51,6 @@ theorem isField_of_isIntegral_of_isField' [CommRing R] [CommRing S] [IsDomain S] variable [Field R] [DivisionRing S] [Algebra R S] {x : S} {A : Subalgebra R S} -set_option backward.isDefEq.respectTransparency false in theorem IsIntegral.inv_mem_adjoin (int : IsIntegral R x) : x⁻¹ ∈ adjoin R {x} := by obtain rfl | h0 := eq_or_ne x 0 · rw [inv_zero]; exact Subalgebra.zero_mem _ @@ -66,7 +64,6 @@ theorem IsIntegral.inv_mem_adjoin (int : IsIntegral R x) : x⁻¹ ∈ adjoin R { theorem IsIntegral.inv_mem (int : IsIntegral R x) (hx : x ∈ A) : x⁻¹ ∈ A := adjoin_le (Set.singleton_subset_iff.mpr hx) int.inv_mem_adjoin -set_option backward.isDefEq.respectTransparency false in /-- An integral subalgebra of a division ring over a field is closed under inverses. -/ theorem Algebra.IsIntegral.inv_mem [Algebra.IsIntegral R A] (hx : x ∈ A) : x⁻¹ ∈ A := ((isIntegral_algHom_iff A.val Subtype.val_injective).mpr <| @@ -132,7 +129,6 @@ theorem adjoin_le_integralClosure {x : A} (hx : IsIntegral R x) : simp only [SetLike.mem_coe, Set.singleton_subset_iff] exact hx -set_option backward.isDefEq.respectTransparency false in theorem le_integralClosure_iff_isIntegral {S : Subalgebra R A} : S ≤ integralClosure R A ↔ Algebra.IsIntegral R S := SetLike.forall.symm.trans <| @@ -141,23 +137,19 @@ theorem le_integralClosure_iff_isIntegral {S : Subalgebra R A} : isIntegral_algebraMap_iff Subtype.coe_injective).trans Algebra.isIntegral_def.symm -set_option backward.isDefEq.respectTransparency false in theorem Algebra.IsIntegral.adjoin {S : Set A} (hS : ∀ x ∈ S, IsIntegral R x) : Algebra.IsIntegral R (adjoin R S) := le_integralClosure_iff_isIntegral.mp <| adjoin_le hS -set_option backward.isDefEq.respectTransparency false in theorem integralClosure_eq_top_iff : integralClosure R A = ⊤ ↔ Algebra.IsIntegral R A := by rw [← top_le_iff, le_integralClosure_iff_isIntegral, (Subalgebra.topEquiv (R := R) (A := A)).isIntegral_iff] -- explicit arguments for speedup -set_option backward.isDefEq.respectTransparency false in theorem Algebra.isIntegral_sup {S T : Subalgebra R A} : Algebra.IsIntegral R (S ⊔ T : Subalgebra R A) ↔ Algebra.IsIntegral R S ∧ Algebra.IsIntegral R T := by simp_rw [← le_integralClosure_iff_isIntegral, sup_le_iff] -set_option backward.isDefEq.respectTransparency false in theorem Algebra.isIntegral_iSup {ι} (S : ι → Subalgebra R A) : Algebra.IsIntegral R ↑(iSup S) ↔ ∀ i, Algebra.IsIntegral R (S i) := by simp_rw [← le_integralClosure_iff_isIntegral, iSup_le_iff] @@ -196,14 +188,12 @@ def AlgEquiv.mapIntegralClosure [Algebra R S] (f : A ≃ₐ[R] S) : theorem AlgEquiv.coe_mapIntegralClosure [Algebra R S] (f : A ≃ₐ[R] S) (x : integralClosure R A) : (f.mapIntegralClosure x : S) = f (x : A) := rfl -set_option backward.isDefEq.respectTransparency false in theorem integralClosure.isIntegral (x : integralClosure R A) : IsIntegral R x := let ⟨p, hpm, hpx⟩ := x.2 ⟨p, hpm, Subtype.ext <| by rwa [← aeval_def, ← Subalgebra.val_apply, aeval_algHom_apply] at hpx⟩ -set_option backward.isDefEq.respectTransparency false in instance integralClosure.AlgebraIsIntegral : Algebra.IsIntegral R (integralClosure R A) := ⟨integralClosure.isIntegral⟩ @@ -644,7 +634,6 @@ theorem Algebra.IsIntegral.isField_iff_isField [IsDomain S] end Algebra -set_option backward.isDefEq.respectTransparency false in theorem integralClosure_idem {R A : Type*} [CommRing R] [CommRing A] [Algebra R A] : integralClosure (integralClosure R A) A = ⊥ := letI := (integralClosure R A).algebra diff --git a/Mathlib/RingTheory/Invariant/Basic.lean b/Mathlib/RingTheory/Invariant/Basic.lean index f8c4eb2661ba3c..8682bb06205ee6 100644 --- a/Mathlib/RingTheory/Invariant/Basic.lean +++ b/Mathlib/RingTheory/Invariant/Basic.lean @@ -360,7 +360,7 @@ private theorem fixed_of_fixed2 (f : Gal(L/K)) (x : L) obtain ⟨_⟩ := nonempty_fintype G have : P.IsPrime := Ideal.over_def Q P ▸ Ideal.IsPrime.under A Q have : Algebra.IsIntegral A B := Algebra.IsInvariant.isIntegral A B G - obtain ⟨x, y, hy, rfl⟩ := IsFractionRing.div_surjective (A := B ⧸ Q) x + obtain ⟨x, y, hy, rfl⟩ := IsFractionRing.div_surjective (B ⧸ Q) x obtain ⟨b, a, ha, h⟩ := (Algebra.IsAlgebraic.isAlgebraic (R := A ⧸ P) y).exists_smul_eq_mul x hy replace ha : algebraMap (A ⧸ P) L a ≠ 0 := by rwa [Ne, algebraMap_apply (A ⧸ P) K L, algebraMap_eq_zero_iff, algebraMap_eq_zero_iff] diff --git a/Mathlib/RingTheory/Invariant/Profinite.lean b/Mathlib/RingTheory/Invariant/Profinite.lean index 5f2227b57c8437..25c40e3577fd8e 100644 --- a/Mathlib/RingTheory/Invariant/Profinite.lean +++ b/Mathlib/RingTheory/Invariant/Profinite.lean @@ -43,7 +43,6 @@ variable [IsTopologicalGroup G] [TopologicalSpace B] [DiscreteTopology B] [Conti open Pointwise CategoryTheory -set_option backward.isDefEq.respectTransparency false in include G in lemma Algebra.IsInvariant.isIntegral_of_profinite [Algebra.IsInvariant A B G] : Algebra.IsIntegral A B := by @@ -122,7 +121,6 @@ lemma Ideal.Quotient.stabilizerHomSurjectiveAuxFunctor_aux simpa only [Ideal.pointwise_smul_eq_comap, ← Ideal.comap_coe (F := RingEquiv _ _), Ideal.comap_comap] using hx -set_option backward.isDefEq.respectTransparency false in /-- (Implementation) The functor taking an open normal subgroup `N ≤ G` to the set of lifts of `σ` in `G ⧸ N`. We will show that its inverse limit is nonempty to conclude that there exists a lift in `G`. -/ @@ -155,7 +153,6 @@ instance (P : Ideal A) (Q : Ideal B) [Q.LiesOver P] dsimp [stabilizerHomSurjectiveAuxFunctor] infer_instance -set_option backward.isDefEq.respectTransparency false in open Ideal.Quotient in instance (P : Ideal A) (Q : Ideal B) [Q.IsPrime] [Q.LiesOver P] [Algebra.IsInvariant A B G] (σ : (B ⧸ Q) ≃ₐ[A ⧸ P] B ⧸ Q) (N : OpenNormalSubgroup G) : @@ -172,7 +169,6 @@ instance (P : Ideal A) (Q : Ideal B) [Q.IsPrime] [Q.LiesOver P] obtain ⟨x, rfl⟩ := Ideal.Quotient.mk_surjective x exact hσ' x -set_option backward.isDefEq.respectTransparency false in /-- The stabilizer subgroup of `Q` surjects onto `Aut((B/Q)/(A/P))`. -/ theorem Ideal.Quotient.stabilizerHom_surjective_of_profinite (P : Ideal A) (Q : Ideal B) [Q.IsPrime] [Q.LiesOver P] diff --git a/Mathlib/RingTheory/IsAdjoinRoot.lean b/Mathlib/RingTheory/IsAdjoinRoot.lean index ffbfb8034e96cf..bd15a7128f8f71 100644 --- a/Mathlib/RingTheory/IsAdjoinRoot.lean +++ b/Mathlib/RingTheory/IsAdjoinRoot.lean @@ -659,7 +659,6 @@ section Algebra open AdjoinRoot IsAdjoinRoot minpoly PowerBasis IsAdjoinRootMonic Algebra -set_option backward.isDefEq.respectTransparency false in theorem Algebra.adjoin.powerBasis'_minpoly_gen [IsDomain R] [IsDomain S] [IsTorsionFree R S] [IsIntegrallyClosed R] {x : S} (hx' : IsIntegral R x) : minpoly R x = minpoly R (Algebra.adjoin.powerBasis' hx').gen := by diff --git a/Mathlib/RingTheory/LinearDisjoint.lean b/Mathlib/RingTheory/LinearDisjoint.lean index 73d3a674b29208..918716757c5255 100644 --- a/Mathlib/RingTheory/LinearDisjoint.lean +++ b/Mathlib/RingTheory/LinearDisjoint.lean @@ -237,7 +237,6 @@ namespace LinearDisjoint variable (H : A.LinearDisjoint B) -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are subalgebras in a commutative algebra `S` over `R`, and if they are linearly disjoint, then there is the natural isomorphism `A ⊗[R] B ≃ₐ[R] A ⊔ B` induced by multiplication in `S`. -/ @@ -247,7 +246,6 @@ protected def mulMap := @[simp] theorem val_mulMap_tmul (a : A) (b : B) : (H.mulMap (a ⊗ₜ[R] b) : S) = a.1 * b.1 := rfl -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are linearly disjoint subalgebras in a commutative algebra `S` over `R` such that `A ⊔ B = S`, then this is the natural isomorphism @@ -265,7 +263,6 @@ noncomputable def mulMapLeftOfSupEqTop (H' : A ⊔ B = ⊤) : theorem mulMapLeftOfSupEqTop_tmul (H' : A ⊔ B = ⊤) (a : A) (b : B) : H.mulMapLeftOfSupEqTop H' (a ⊗ₜ[R] b) = (a : S) * (b : S) := rfl -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are linearly disjoint subalgebras in a commutative algebra `S` over `R` such that `A ⊔ B = S`, then any `R`-basis of `B` is also an `A`-basis of `S`. @@ -274,25 +271,21 @@ noncomputable def basisOfBasisRight (H' : A ⊔ B = ⊤) {ι : Type*} (b : Basis Basis ι A S := (b.baseChange A).map (H.mulMapLeftOfSupEqTop H').toLinearEquiv -set_option backward.isDefEq.respectTransparency false in @[simp] theorem algebraMap_basisOfBasisRight_apply (H' : A ⊔ B = ⊤) {ι : Type*} (b : Basis ι R B) (i : ι) : H.basisOfBasisRight H' b i = algebraMap B S (b i) := by simp [basisOfBasisRight] -set_option backward.isDefEq.respectTransparency false in @[simp] theorem mulMapLeftOfSupEqTop_symm_apply (H' : A ⊔ B = ⊤) (x : B) : (H.mulMapLeftOfSupEqTop H').symm x = 1 ⊗ₜ[R] x := (H.mulMapLeftOfSupEqTop H').symm_apply_eq.mpr (by simp) -set_option backward.isDefEq.respectTransparency false in theorem algebraMap_basisOfBasisRight_repr_apply (H' : A ⊔ B = ⊤) {ι : Type*} (b : Basis ι R B) (x : B) (i : ι) : algebraMap A S ((H.basisOfBasisRight H' b).repr x i) = algebraMap R S (b.repr x i) := by simp [basisOfBasisRight, Algebra.algebraMap_eq_smul_one] -set_option backward.isDefEq.respectTransparency false in theorem leftMulMatrix_basisOfBasisRight_algebraMap (H' : A ⊔ B = ⊤) {ι : Type*} [Fintype ι] [DecidableEq ι] (b : Basis ι R B) (x : B) : Algebra.leftMulMatrix (H.basisOfBasisRight H' b) (algebraMap B S x) = @@ -300,7 +293,6 @@ theorem leftMulMatrix_basisOfBasisRight_algebraMap (H' : A ⊔ B = ⊤) {ι : Ty ext simp [Algebra.leftMulMatrix_eq_repr_mul, ← H.algebraMap_basisOfBasisRight_repr_apply H'] -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are subalgebras in a commutative algebra `S` over `R`, and if they are linearly disjoint and such that `A ⊔ B = S`, then any `R`-basis of `A` is also a `B`-basis of `S`. @@ -319,21 +311,18 @@ theorem basisOfBasisLeft_repr_apply (H' : A ⊔ B = ⊤) {ι : Type*} (b : Basis algebraMap B S ((H.basisOfBasisLeft H' b).repr x i) = algebraMap R S (b.repr x i) := H.symm.algebraMap_basisOfBasisRight_repr_apply (by rwa [sup_comm]) b x i -set_option backward.isDefEq.respectTransparency false in include H in /-- If `A` and `B` are subalgebras in a commutative algebra `S` over `R`, and if they are linearly disjoint, and if they are free `R`-modules, then `A ⊔ B` is also a free `R`-module. -/ theorem sup_free_of_free [Module.Free R A] [Module.Free R B] : Module.Free R ↥(A ⊔ B) := Module.Free.of_equiv H.mulMap.toLinearEquiv -set_option backward.isDefEq.respectTransparency false in include H in /-- If `A` and `B` are subalgebras in a domain `S` over `R`, and if they are linearly disjoint, then `A ⊗[R] B` is also a domain. -/ theorem isDomain [IsDomain S] : IsDomain (A ⊗[R] B) := H.injective.isDomain (A.mulMap B).toRingHom -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are `R`-algebras, such that there exists a domain `S` over `R` such that `A` and `B` inject into it and their images are linearly disjoint, then `A ⊗[R] B` is also a domain. -/ @@ -357,7 +346,6 @@ variable [CommRing R] [Ring S] [Algebra R S] variable (A B : Subalgebra R S) -set_option backward.isDefEq.respectTransparency false in lemma mulLeftMap_ker_eq_bot_iff_linearIndependent_op {ι : Type*} (a : ι → A) : LinearMap.ker (Submodule.mulLeftMap (M := toSubmodule A) (toSubmodule B) a) = ⊥ ↔ LinearIndependent B.op (MulOpposite.op ∘ A.val ∘ a) := by @@ -378,7 +366,6 @@ lemma mulLeftMap_ker_eq_bot_iff_linearIndependent_op {ι : Type*} (a : ι → A) MulOpposite.unop_smul, MulOpposite.unop_op, i, j] exact Submodule.mulLeftMap_apply_single _ _ _ -set_option backward.isDefEq.respectTransparency false in variable {A B} in /-- If `A` and `B` are linearly disjoint, if `B` is a flat `R`-module, then for any family of `R`-linearly independent elements of `A`, they are also `B`-linearly independent @@ -389,7 +376,6 @@ theorem linearIndependent_left_op_of_flat (H : A.LinearDisjoint B) [Module.Flat have h := Submodule.LinearDisjoint.linearIndependent_left_of_flat H ha rwa [mulLeftMap_ker_eq_bot_iff_linearIndependent_op] at h -set_option backward.isDefEq.respectTransparency false in /-- If a basis of `A` is also `B`-linearly independent in the opposite ring, then `A` and `B` are linearly disjoint. -/ theorem of_basis_left_op {ι : Type*} (a : Basis ι R A) @@ -398,7 +384,6 @@ theorem of_basis_left_op {ι : Type*} (a : Basis ι R A) rw [← mulLeftMap_ker_eq_bot_iff_linearIndependent_op] at H exact Submodule.LinearDisjoint.of_basis_left _ _ a H -set_option backward.isDefEq.respectTransparency false in lemma mulRightMap_ker_eq_bot_iff_linearIndependent {ι : Type*} (b : ι → B) : LinearMap.ker (Submodule.mulRightMap (toSubmodule A) (N := toSubmodule B) b) = ⊥ ↔ LinearIndependent A (B.val ∘ b) := by @@ -411,7 +396,6 @@ lemma mulRightMap_ker_eq_bot_iff_linearIndependent {ι : Type*} (b : ι → B) : LinearMap.coe_restrictScalars, Finsupp.linearCombination_single, i, j] exact Submodule.mulRightMap_apply_single _ _ _ -set_option backward.isDefEq.respectTransparency false in variable {A B} in /-- If `A` and `B` are linearly disjoint, if `A` is a flat `R`-module, then for any family of `R`-linearly independent elements of `B`, they are also `A`-linearly independent. -/ @@ -421,14 +405,12 @@ theorem linearIndependent_right_of_flat (H : A.LinearDisjoint B) [Module.Flat R have h := Submodule.LinearDisjoint.linearIndependent_right_of_flat H hb rwa [mulRightMap_ker_eq_bot_iff_linearIndependent] at h -set_option backward.isDefEq.respectTransparency false in /-- If a basis of `B` is also `A`-linearly independent, then `A` and `B` are linearly disjoint. -/ theorem of_basis_right {ι : Type*} (b : Basis ι R B) (H : LinearIndependent A (B.val ∘ b)) : A.LinearDisjoint B := by rw [← mulRightMap_ker_eq_bot_iff_linearIndependent] at H exact Submodule.LinearDisjoint.of_basis_right _ _ b H -set_option backward.isDefEq.respectTransparency false in variable {A B} in /-- If `A` and `B` are linearly disjoint and their elements commute, if `B` is a flat `R`-module, then for any family of `R`-linearly independent elements of `A`, @@ -438,7 +420,6 @@ theorem linearIndependent_left_of_flat_of_commute (H : A.LinearDisjoint B) [Modu (hc : ∀ (a : A) (b : B), Commute a.1 b.1) : LinearIndependent B (A.val ∘ a) := (H.symm_of_commute hc).linearIndependent_right_of_flat ha -set_option backward.isDefEq.respectTransparency false in /-- If a basis of `A` is also `B`-linearly independent, if elements in `A` and `B` commute, then `A` and `B` are linearly disjoint. -/ theorem of_basis_left_of_commute {ι : Type*} (a : Basis ι R A) @@ -446,7 +427,6 @@ theorem of_basis_left_of_commute {ι : Type*} (a : Basis ι R A) A.LinearDisjoint B := (of_basis_right B A a H).symm_of_commute fun _ _ ↦ (hc _ _).symm -set_option backward.isDefEq.respectTransparency false in variable {A B} in /-- If `A` and `B` are linearly disjoint, if `A` is flat, then for any family of `R`-linearly independent elements `{ a_i }` of `A`, and any family of @@ -457,7 +437,6 @@ theorem linearIndependent_mul_of_flat_left (H : A.LinearDisjoint B) [Module.Flat (hb : LinearIndependent R b) : LinearIndependent R fun (i : κ × ι) ↦ (a i.1).1 * (b i.2).1 := Submodule.LinearDisjoint.linearIndependent_mul_of_flat_left H ha hb -set_option backward.isDefEq.respectTransparency false in variable {A B} in /-- If `A` and `B` are linearly disjoint, if `B` is flat, then for any family of `R`-linearly independent elements `{ a_i }` of `A`, and any family of @@ -468,7 +447,6 @@ theorem linearIndependent_mul_of_flat_right (H : A.LinearDisjoint B) [Module.Fla (hb : LinearIndependent R b) : LinearIndependent R fun (i : κ × ι) ↦ (a i.1).1 * (b i.2).1 := Submodule.LinearDisjoint.linearIndependent_mul_of_flat_right H ha hb -set_option backward.isDefEq.respectTransparency false in variable {A B} in /-- If `A` and `B` are linearly disjoint, if one of `A` and `B` is flat, then for any family of `R`-linearly independent elements `{ a_i }` of `A`, and any family of @@ -480,7 +458,6 @@ theorem linearIndependent_mul_of_flat (H : A.LinearDisjoint B) (hb : LinearIndependent R b) : LinearIndependent R fun (i : κ × ι) ↦ (a i.1).1 * (b i.2).1 := Submodule.LinearDisjoint.linearIndependent_mul_of_flat H hf ha hb -set_option backward.isDefEq.respectTransparency false in /-- If `{ a_i }` is an `R`-basis of `A`, if `{ b_j }` is an `R`-basis of `B`, such that the family `{ a_i * b_j }` in `S` is `R`-linearly independent, then `A` and `B` are linearly disjoint. -/ @@ -495,27 +472,22 @@ section variable (H : A.LinearDisjoint B) include H -set_option backward.isDefEq.respectTransparency false in theorem of_le_left_of_flat {A' : Subalgebra R S} (h : A' ≤ A) [Module.Flat R B] : A'.LinearDisjoint B := Submodule.LinearDisjoint.of_le_left_of_flat H h -set_option backward.isDefEq.respectTransparency false in theorem of_le_right_of_flat {B' : Subalgebra R S} (h : B' ≤ B) [Module.Flat R A] : A.LinearDisjoint B' := Submodule.LinearDisjoint.of_le_right_of_flat H h -set_option backward.isDefEq.respectTransparency false in theorem of_le_of_flat_right {A' B' : Subalgebra R S} (ha : A' ≤ A) (hb : B' ≤ B) [Module.Flat R B] [Module.Flat R A'] : A'.LinearDisjoint B' := (H.of_le_left_of_flat ha).of_le_right_of_flat hb -set_option backward.isDefEq.respectTransparency false in theorem of_le_of_flat_left {A' B' : Subalgebra R S} (ha : A' ≤ A) (hb : B' ≤ B) [Module.Flat R A] [Module.Flat R B'] : A'.LinearDisjoint B' := (H.of_le_right_of_flat hb).of_le_left_of_flat ha -set_option backward.isDefEq.respectTransparency false in theorem rank_inf_eq_one_of_commute_of_flat_of_inj (hf : Module.Flat R A ∨ Module.Flat R B) (hc : ∀ (a b : ↥(A ⊓ B)), Commute a.1 b.1) (hinj : Function.Injective (algebraMap R S)) : Module.rank R ↥(A ⊓ B) = 1 := by @@ -530,13 +502,11 @@ theorem rank_inf_eq_one_of_commute_of_flat_of_inj (hf : Module.Flat R A ∨ Modu Module.rank R (toSubmodule (A ⊓ B)) exact Submodule.rank_mono (bot_le : (⊥ : Subalgebra R S) ≤ A ⊓ B) -set_option backward.isDefEq.respectTransparency false in theorem rank_inf_eq_one_of_commute_of_flat_left_of_inj [Module.Flat R A] (hc : ∀ (a b : ↥(A ⊓ B)), Commute a.1 b.1) (hinj : Function.Injective (algebraMap R S)) : Module.rank R ↥(A ⊓ B) = 1 := H.rank_inf_eq_one_of_commute_of_flat_of_inj (Or.inl ‹_›) hc hinj -set_option backward.isDefEq.respectTransparency false in theorem rank_inf_eq_one_of_commute_of_flat_right_of_inj [Module.Flat R B] (hc : ∀ (a b : ↥(A ⊓ B)), Commute a.1 b.1) (hinj : Function.Injective (algebraMap R S)) : Module.rank R ↥(A ⊓ B) = 1 := @@ -544,7 +514,6 @@ theorem rank_inf_eq_one_of_commute_of_flat_right_of_inj [Module.Flat R B] end -set_option backward.isDefEq.respectTransparency false in theorem rank_eq_one_of_commute_of_flat_of_self_of_inj (H : A.LinearDisjoint A) [Module.Flat R A] (hc : ∀ (a b : A), Commute a.1 b.1) (hinj : Function.Injective (algebraMap R S)) : Module.rank R A = 1 := by @@ -563,7 +532,6 @@ variable [CommRing R] [CommRing S] [Algebra R S] variable {A B : Subalgebra R S} -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are subalgebras in a commutative algebra `S` over `R`, and if they are linearly disjoint and such that `A ⊔ B = S`, then `trace` and `algebraMap` commutes. @@ -576,7 +544,6 @@ theorem trace_algebraMap (H : A.LinearDisjoint B) (H' : A ⊔ B = ⊤) [Module.F Matrix.trace, map_sum, leftMulMatrix_basisOfBasisRight_algebraMap, RingHom.mapMatrix_apply, Matrix.diag_apply, Matrix.map_apply] -set_option backward.isDefEq.respectTransparency false in /-- If `A` and `B` are subalgebras in a commutative algebra `S` over `R`, and if they are linearly disjoint and such that `A ⊔ B = S`, then `norm` and `algebraMap` commutes. @@ -588,7 +555,6 @@ theorem norm_algebraMap (H : A.LinearDisjoint B) (H' : A ⊔ B = ⊤) [Module.Fr Algebra.norm_eq_matrix_det (H.basisOfBasisRight H' (Module.Free.chooseBasis R B)), leftMulMatrix_basisOfBasisRight_algebraMap, RingHom.map_det] -set_option backward.isDefEq.respectTransparency false in /-- In a commutative ring, if `A` and `B` are linearly disjoint, if `B` is a flat `R`-module, then for any family of `R`-linearly independent elements of `A`, they are also `B`-linearly independent. -/ @@ -596,7 +562,6 @@ theorem linearIndependent_left_of_flat (H : A.LinearDisjoint B) [Module.Flat R B {ι : Type*} {a : ι → A} (ha : LinearIndependent R a) : LinearIndependent B (A.val ∘ a) := H.linearIndependent_left_of_flat_of_commute ha fun _ _ ↦ mul_comm _ _ -set_option backward.isDefEq.respectTransparency false in variable (A B) in /-- In a commutative ring, if a basis of `A` is also `B`-linearly independent, then `A` and `B` are linearly disjoint. -/ @@ -624,7 +589,6 @@ theorem exists_field_of_isDomain_of_injective (A : Type v) [CommRing A] (B : Typ hi.comp (Algebra.TensorProduct.includeRight_injective ha), by simpa only [AlgHom.range_comp] using (include_range R A B).map i hi⟩ -set_option backward.isDefEq.respectTransparency false in /-- If `A ⊗[R] B` is a field, then `A` and `B` are linearly disjoint. -/ theorem of_isField (H : IsField (A ⊗[R] B)) : A.LinearDisjoint B := by nontriviality S @@ -634,7 +598,6 @@ theorem of_isField (H : IsField (A ⊗[R] B)) : A.LinearDisjoint B := by letI : NonAssocRing (A ⊗[R] B) := Ring.toNonAssocRing exact RingHom.injective _ -set_option backward.isDefEq.respectTransparency false in /-- If `A ⊗[R] B` is a field, then for any `R`-algebra `S` and injections of `A` and `B` into `S`, their images are linearly disjoint. -/ theorem of_isField' {A : Type v} [Ring A] {B : Type w} [Ring B] @@ -645,7 +608,6 @@ theorem of_isField' {A : Type v} [Ring A] {B : Type w} [Ring B] exact Algebra.TensorProduct.congr (AlgEquiv.ofInjective fa hfa) (AlgEquiv.ofInjective fb hfb) |>.symm.toMulEquiv.isField H -set_option backward.isDefEq.respectTransparency false in -- need to be in this file since it uses linearly disjoint open Cardinal Polynomial in variable (R) in @@ -712,30 +674,25 @@ theorem _root_.Algebra.TensorProduct.isAlgebraic_of_isField variable (H : A.LinearDisjoint B) -set_option backward.isDefEq.respectTransparency false in include H in theorem rank_inf_eq_one_of_flat_of_inj (hf : Module.Flat R A ∨ Module.Flat R B) (hinj : Function.Injective (algebraMap R S)) : Module.rank R ↥(A ⊓ B) = 1 := H.rank_inf_eq_one_of_commute_of_flat_of_inj hf (fun _ _ ↦ mul_comm _ _) hinj -set_option backward.isDefEq.respectTransparency false in include H in theorem rank_inf_eq_one_of_flat_left_of_inj [Module.Flat R A] (hinj : Function.Injective (algebraMap R S)) : Module.rank R ↥(A ⊓ B) = 1 := H.rank_inf_eq_one_of_commute_of_flat_left_of_inj (fun _ _ ↦ mul_comm _ _) hinj -set_option backward.isDefEq.respectTransparency false in include H in theorem rank_inf_eq_one_of_flat_right_of_inj [Module.Flat R B] (hinj : Function.Injective (algebraMap R S)) : Module.rank R ↥(A ⊓ B) = 1 := H.rank_inf_eq_one_of_commute_of_flat_right_of_inj (fun _ _ ↦ mul_comm _ _) hinj -set_option backward.isDefEq.respectTransparency false in theorem rank_eq_one_of_flat_of_self_of_inj (H : A.LinearDisjoint A) [Module.Flat R A] (hinj : Function.Injective (algebraMap R S)) : Module.rank R A = 1 := H.rank_eq_one_of_commute_of_flat_of_self_of_inj (fun _ _ ↦ mul_comm _ _) hinj -set_option backward.isDefEq.respectTransparency false in include H in /-- In a commutative ring, if subalgebras `A` and `B` are linearly disjoint and they are free modules, then the rank of `A ⊔ B` is equal to the product of the rank of `A` and `B`. -/ @@ -744,7 +701,6 @@ theorem rank_sup_of_free [Module.Free R A] [Module.Free R B] : nontriviality R rw [← rank_tensorProduct', H.mulMap.toLinearEquiv.rank_eq] -set_option backward.isDefEq.respectTransparency false in include H in /-- In a commutative ring, if subalgebras `A` and `B` are linearly disjoint and they are free modules, then the rank of `A ⊔ B` is equal to the product of the rank of `A` and `B`. -/ @@ -752,7 +708,6 @@ theorem finrank_sup_of_free [Module.Free R A] [Module.Free R B] : Module.finrank R ↥(A ⊔ B) = Module.finrank R A * Module.finrank R B := by simpa only [map_mul] using congr(Cardinal.toNat $(H.rank_sup_of_free)) -set_option backward.isDefEq.respectTransparency false in /-- In a commutative ring, if `A` and `B` are subalgebras which are free modules of finite rank, such that rank of `A ⊔ B` is equal to the product of the rank of `A` and `B`, then `A` and `B` are linearly disjoint. -/ @@ -772,7 +727,6 @@ theorem of_finrank_sup_of_free [Module.Free R A] [Module.Free R B] rw [linearDisjoint_iff, Submodule.linearDisjoint_iff] exact Subtype.val_injective.comp (OrzechProperty.injective_of_surjective_of_injective j' _ hj hf) -set_option backward.isDefEq.respectTransparency false in include H in /-- If `A` and `B` are linearly disjoint, if `A` is free and `B` is flat, then `[B[A] : B] = [A : R]`. See also `Subalgebra.adjoin_rank_le`. -/ @@ -785,7 +739,6 @@ theorem adjoin_rank_eq_rank_left [Module.Free R A] [Module.Flat R B] have := H.linearIndependent_left_of_flat (Module.Free.chooseBasis R A).linearIndependent rw [rank_span this, Cardinal.mk_range_eq _ this.injective] -set_option backward.isDefEq.respectTransparency false in include H in /-- If `A` and `B` are linearly disjoint, if `B` is free and `A` is flat, then `[A[B] : A] = [B : R]`. See also `Subalgebra.adjoin_rank_le`. -/ @@ -794,7 +747,6 @@ theorem adjoin_rank_eq_rank_right [Module.Free R B] [Module.Flat R A] Module.rank A (Algebra.adjoin A (B : Set S)) = Module.rank R B := H.symm.adjoin_rank_eq_rank_left -set_option backward.isDefEq.respectTransparency false in /-- If the rank of `A` and `B` are coprime, and they satisfy some freeness condition, then `A` and `B` are linearly disjoint. -/ theorem of_finrank_coprime_of_free [Module.Free R A] [Module.Free R B] @@ -821,7 +773,6 @@ theorem of_finrank_coprime_of_free [Module.Free R A] [Module.Free R B] variable (A B) -set_option backward.isDefEq.respectTransparency false in /-- If `A/R` is integral, such that `A'` and `B` are linearly disjoint for all subalgebras `A'` of `A` which are finitely generated `R`-modules, then `A` and `B` are linearly disjoint. -/ theorem of_linearDisjoint_finite_left [Algebra.IsIntegral R A] @@ -851,7 +802,6 @@ theorem of_linearDisjoint_finite_left [Algebra.IsIntegral R A] rw [← hx', ← hy']; congr exact (H A' hA).injective (by simp [← Submodule.mulMap_comp_rTensor _ hA, hx', hy', hxy]) -set_option backward.isDefEq.respectTransparency false in /-- If `B/R` is integral, such that `A` and `B'` are linearly disjoint for all subalgebras `B'` of `B` which are finitely generated `R`-modules, then `A` and `B` are linearly disjoint. -/ theorem of_linearDisjoint_finite_right [Algebra.IsIntegral R B] @@ -861,7 +811,6 @@ theorem of_linearDisjoint_finite_right [Algebra.IsIntegral R B] variable {A B} -set_option backward.isDefEq.respectTransparency false in /-- If `A/R` and `B/R` are integral, such that any finite subalgebras in `A` and `B` are linearly disjoint, then `A` and `B` are linearly disjoint. -/ theorem of_linearDisjoint_finite diff --git a/Mathlib/RingTheory/LocalProperties/InjectiveDimension.lean b/Mathlib/RingTheory/LocalProperties/InjectiveDimension.lean new file mode 100644 index 00000000000000..14aaa7566b210d --- /dev/null +++ b/Mathlib/RingTheory/LocalProperties/InjectiveDimension.lean @@ -0,0 +1,180 @@ +/- +Copyright (c) 2025 Nailin Guan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Nailin Guan +-/ +module + +public import Mathlib.Algebra.Category.Grp.Zero +public import Mathlib.Algebra.Category.ModuleCat.EnoughInjectives +public import Mathlib.Algebra.Category.ModuleCat.Localization +public import Mathlib.Algebra.Category.ModuleCat.Projective +public import Mathlib.Algebra.Homology.DerivedCategory.Ext.EnoughInjectives +public import Mathlib.Algebra.Homology.ShortComplex.ModuleCat +public import Mathlib.Algebra.Module.LocalizedModule.Exact +public import Mathlib.CategoryTheory.Abelian.Injective.Dimension +public import Mathlib.CategoryTheory.Preadditive.Injective.Preserves +public import Mathlib.LinearAlgebra.Dimension.Finite +public import Mathlib.RingTheory.LocalProperties.Injective + +/-! + +# Relation of Injective Dimension with Localizations + +-/ + +@[expose] public section + +universe v u + +namespace ModuleCat + +variable {R : Type u} [CommRing R] + +open CategoryTheory Limits + +set_option backward.isDefEq.respectTransparency false in +instance [Small.{v} R] [IsNoetherianRing R] (S : Submonoid R) : + (ModuleCat.localizedModuleFunctor.{v} S).PreservesInjectiveObjects where + injective_obj X {inj} := by + let _ : Small.{v, u} (Localization S) := small_of_surjective Localization.mkHom_surjective + rw [← Module.injective_iff_injective_object] at inj ⊢ + simpa [ModuleCat.localizedModuleFunctor] using + Module.injective_of_isLocalizedModule S (X.localizedModuleMkLinearMap S) + +lemma localizedModule_hasInjectiveDimensionLE [Small.{v, u} R] [IsNoetherianRing R] (n : ℕ) + (S : Submonoid R) (M : ModuleCat.{v} R) [HasInjectiveDimensionLE M n] : + HasInjectiveDimensionLE (M.localizedModule S) n := by + have : Small.{v} (Localization S) := small_of_surjective Localization.mkHom_surjective + induction n generalizing M with + | zero => + have injle : HasInjectiveDimensionLE M 0 := ‹_› + simp only [HasInjectiveDimensionLE, zero_add, ← injective_iff_hasInjectiveDimensionLT_one] + at injle ⊢ + rw [← Module.injective_iff_injective_object] at injle ⊢ + exact Module.injective_of_isLocalizedModule S (M.localizedModuleMkLinearMap S) + | succ n ih => + have ei : EnoughInjectives (ModuleCat.{v} R) := inferInstance + rcases ei.1 M with ⟨I, inj, f, monof⟩ + let T := ShortComplex.mk f (cokernel.π f) (cokernel.condition f) + have T_exact : T.ShortExact := { exact := ShortComplex.exact_cokernel f } + have T_exact' : Function.Exact (ConcreteCategory.hom T.f) (ConcreteCategory.hom T.g) := + (ShortComplex.ShortExact.moduleCat_exact_iff_function_exact _).mp T_exact.1 + have TS_exact' := IsLocalizedModule.map_exact S (T.X₁.localizedModuleMkLinearMap S) + (T.X₂.localizedModuleMkLinearMap S) (T.X₃.localizedModuleMkLinearMap S) _ _ T_exact' + let TS := T.map (ModuleCat.localizedModuleFunctor S) + have TS_exact : TS.ShortExact := T_exact.map_of_exact (ModuleCat.localizedModuleFunctor S) + let _ := (T_exact.hasInjectiveDimensionLT_X₃_iff n ‹_›).mpr ‹_› + let _ : Injective TS.X₂ := (ModuleCat.localizedModuleFunctor.{v} S).injective_obj _ + exact (TS_exact.hasInjectiveDimensionLT_X₃_iff n ‹_›).mp (ih T.X₃) + +open Limits in +lemma injectiveDimension_le_injectiveDimension_of_isLocalizedModule [Small.{v, u} R] + [IsNoetherianRing R] (S : Submonoid R) (M : ModuleCat.{v} R) : + injectiveDimension (M.localizedModule S) ≤ injectiveDimension M := by + have aux (n : ℕ) : injectiveDimension M ≤ n → injectiveDimension (M.localizedModule S) ≤ n := by + simp only [injectiveDimension_le_iff] + intro h + exact M.localizedModule_hasInjectiveDimensionLE n S + refine le_of_forall_ge (fun N ↦ ?_) + induction N with + | bot => + simp only [le_bot_iff, injectiveDimension_eq_bot_iff, ModuleCat.isZero_iff_subsingleton, + ModuleCat.localizedModule, ← Equiv.subsingleton_congr (equivShrink _)] + intro _ + apply LocalizedModule.instSubsingleton _ + | coe N => + induction N with + | top => simp + | coe n => simpa using aux n + +lemma hasInjectiveDimensionLE_iff_forall_maximalSpectrum [Small.{v, u} R] [IsNoetherianRing R] + (n : ℕ) (M : ModuleCat.{v} R) : HasInjectiveDimensionLE M n ↔ + ∀ (m : MaximalSpectrum R), HasInjectiveDimensionLE (M.localizedModule m.1.primeCompl) n := by + induction n generalizing M with + | zero => + simp only [HasInjectiveDimensionLE, zero_add, ← injective_iff_hasInjectiveDimensionLT_one] + refine ⟨fun h m ↦ ?_, fun h ↦ ?_⟩ + · let _ : Small.{v} (Localization m.1.primeCompl) := + small_of_surjective Localization.mkHom_surjective + let _ : Module.Injective R M := Module.injective_module_of_injective_object R M + rw [← Module.injective_iff_injective_object] + exact Module.injective_of_isLocalizedModule m.1.primeCompl + (M.localizedModuleMkLinearMap m.1.primeCompl) + · rw [← Module.injective_iff_injective_object] + apply Module.injective_of_localization_maximal (fun p hp ↦ ?_) + let : Small.{v} (Localization.AtPrime p) := small_of_surjective Localization.mkHom_surjective + have : Module.Injective (Localization.AtPrime p) (M.localizedModule p.primeCompl) := by + simpa [Module.injective_iff_injective_object] using h ⟨p, hp⟩ + rw [← Module.Baer.iff_injective] at this ⊢ + exact Module.Baer.of_equiv (LinearEquiv.extendScalarsOfIsLocalization p.primeCompl + (Localization.AtPrime p) (IsLocalizedModule.linearEquiv p.primeCompl + (M.localizedModuleMkLinearMap p.primeCompl) + (LocalizedModule.mkLinearMap p.primeCompl M))) this + | succ n ih => + have ei : EnoughInjectives (ModuleCat.{v} R) := inferInstance + rcases ei.1 M with ⟨I, inj, f, monof⟩ + let S := ShortComplex.mk f (cokernel.π f) (cokernel.condition f) + have S_exact : S.ShortExact := { exact := ShortComplex.exact_cokernel f } + let Sp (m : MaximalSpectrum R) := S.map (ModuleCat.localizedModuleFunctor m.1.primeCompl) + have Sp_exact (m : MaximalSpectrum R) : (Sp m).ShortExact := + S_exact.map_of_exact (ModuleCat.localizedModuleFunctor m.1.primeCompl) + have ih' := ih S.X₃ + simp only [HasInjectiveDimensionLE] at ih' ⊢ + rw [← S_exact.hasInjectiveDimensionLT_X₃_iff n inj, ih'] + have injp (m : MaximalSpectrum R) : Injective (Sp m).X₂ := + (ModuleCat.localizedModuleFunctor.{v} m.1.primeCompl).injective_obj _ + exact (forall_congr' (fun p ↦ (Sp_exact p).hasInjectiveDimensionLT_X₃_iff n (injp p))) + +lemma hasInjectiveDimensionLE_iff_forall_primeSpectrum [Small.{v, u} R] [IsNoetherianRing R] + (n : ℕ) (M : ModuleCat.{v} R) : HasInjectiveDimensionLE M n ↔ + ∀ (p : PrimeSpectrum R), HasInjectiveDimensionLE (M.localizedModule p.1.primeCompl) n := + ⟨fun _ p ↦ M.localizedModule_hasInjectiveDimensionLE n p.1.primeCompl, + fun h ↦ (M.hasInjectiveDimensionLE_iff_forall_maximalSpectrum n).mpr + fun m ↦ h ⟨m.1, Ideal.IsMaximal.isPrime' m.1⟩⟩ + +lemma injectiveDimension_eq_iSup_localizedModule_prime [Small.{v, u} R] [IsNoetherianRing R] + (M : ModuleCat.{v} R) : injectiveDimension M = + ⨆ (p : PrimeSpectrum R), injectiveDimension (M.localizedModule p.1.primeCompl) := by + have aux (n : ℕ) : injectiveDimension M ≤ n ↔ ⨆ (p : PrimeSpectrum R), injectiveDimension + (M.localizedModule p.1.primeCompl) ≤ n := by + simp only [injectiveDimension_le_iff, iSup_le_iff] + exact M.hasInjectiveDimensionLE_iff_forall_primeSpectrum n + refine eq_of_forall_ge_iff (fun N ↦ ?_) + induction N with + | bot => + simp only [le_bot_iff, injectiveDimension_eq_bot_iff, ModuleCat.isZero_iff_subsingleton, + iSup_eq_bot, ModuleCat.localizedModule, ← Equiv.subsingleton_congr (equivShrink _)] + refine ⟨fun h p ↦ LocalizedModule.instSubsingleton _, fun h ↦ ?_⟩ + apply Module.subsingleton_of_localization_maximal (R := R) + (fun p ↦ LocalizedModule p.primeCompl M) (fun p ↦ LocalizedModule.mkLinearMap p.primeCompl M) + intro p hp + exact h ⟨p, hp.isPrime⟩ + | coe N => + induction N with + | top => simp + | coe n => simpa using aux n + +lemma injectiveDimension_eq_iSup_localizedModule_maximal [Small.{v, u} R] [IsNoetherianRing R] + (M : ModuleCat.{v} R) : injectiveDimension M = + ⨆ (p : MaximalSpectrum R), injectiveDimension (M.localizedModule p.1.primeCompl) := by + have aux (n : ℕ) : injectiveDimension M ≤ n ↔ ⨆ (m : MaximalSpectrum R), injectiveDimension + (M.localizedModule m.1.primeCompl) ≤ n := by + simp only [injectiveDimension_le_iff, iSup_le_iff] + exact M.hasInjectiveDimensionLE_iff_forall_maximalSpectrum n + refine eq_of_forall_ge_iff (fun N ↦ ?_) + induction N with + | bot => + simp only [le_bot_iff, injectiveDimension_eq_bot_iff, ModuleCat.isZero_iff_subsingleton, + iSup_eq_bot, ModuleCat.localizedModule, ← Equiv.subsingleton_congr (equivShrink _)] + refine ⟨fun h p ↦ LocalizedModule.instSubsingleton _, fun h ↦ ?_⟩ + apply Module.subsingleton_of_localization_maximal (R := R) + (fun p ↦ LocalizedModule p.primeCompl M) (fun p ↦ LocalizedModule.mkLinearMap p.primeCompl M) + intro p hp + exact h ⟨p, hp⟩ + | coe N => + induction N with + | top => simp + | coe n => simpa using aux n + +end ModuleCat diff --git a/Mathlib/RingTheory/LocalProperties/IntegrallyClosed.lean b/Mathlib/RingTheory/LocalProperties/IntegrallyClosed.lean index 80e263f7677b6a..3c879444d5d9d8 100644 --- a/Mathlib/RingTheory/LocalProperties/IntegrallyClosed.lean +++ b/Mathlib/RingTheory/LocalProperties/IntegrallyClosed.lean @@ -28,7 +28,6 @@ open Localization Ideal IsLocalization variable {R K : Type*} [CommRing R] [Field K] [Algebra R K] [IsFractionRing R K] -set_option backward.isDefEq.respectTransparency false in theorem IsIntegrallyClosed.iInf {ι : Type*} (S : ι → Subalgebra R K) (h : ∀ i, IsIntegrallyClosed (S i)) : IsIntegrallyClosed (⨅ i, S i : Subalgebra R K) := by diff --git a/Mathlib/RingTheory/LocalProperties/ProjectiveDimension.lean b/Mathlib/RingTheory/LocalProperties/ProjectiveDimension.lean index 1f2bf5ad0aad5a..eef4f147c26335 100644 --- a/Mathlib/RingTheory/LocalProperties/ProjectiveDimension.lean +++ b/Mathlib/RingTheory/LocalProperties/ProjectiveDimension.lean @@ -41,11 +41,12 @@ instance [Small.{v} R] (S : Submonoid R) : open Limits in lemma localizedModule_hasProjectiveDimensionLE [Small.{v, u} R] (n : ℕ) (S : Submonoid R) - (M : ModuleCat.{v} R) [projle : HasProjectiveDimensionLE M n] : + (M : ModuleCat.{v} R) [HasProjectiveDimensionLE M n] : HasProjectiveDimensionLE (M.localizedModule S) n := by have : Small.{v} (Localization S) := small_of_surjective Localization.mkHom_surjective induction n generalizing M with | zero => + have projle : HasProjectiveDimensionLE M 0 := ‹_› simp only [HasProjectiveDimensionLE, zero_add] at projle ⊢ rw [← projective_iff_hasProjectiveDimensionLT_one, ← IsProjective.iff_projective] at projle ⊢ exact Module.projective_of_isLocalizedModule S (M.localizedModuleMkLinearMap S) @@ -53,13 +54,10 @@ lemma localizedModule_hasProjectiveDimensionLE [Small.{v, u} R] (n : ℕ) (S : S rcases ModuleCat.enoughProjectives.1 M with ⟨⟨P, f⟩⟩ let T := ShortComplex.mk (kernel.ι f) f (kernel.condition f) have T_exact : T.ShortExact := { exact := ShortComplex.exact_kernel f } - have TS_exact' := IsLocalizedModule.map_exact S (T.X₁.localizedModuleMkLinearMap S) - (T.X₂.localizedModuleMkLinearMap S) (T.X₃.localizedModuleMkLinearMap S) - _ _ ((ShortComplex.ShortExact.moduleCat_exact_iff_function_exact T).mp T_exact.1) let TS := T.map (ModuleCat.localizedModuleFunctor S) have TS_exact : TS.ShortExact := T_exact.map_of_exact (ModuleCat.localizedModuleFunctor S) have : Projective TS.X₂ := (ModuleCat.localizedModuleFunctor.{v} S).projective_obj _ - have := (T_exact.hasProjectiveDimensionLT_X₃_iff n ‹_›).mp projle + have := (T_exact.hasProjectiveDimensionLT_X₃_iff n ‹_›).mp ‹_› exact (TS_exact.hasProjectiveDimensionLT_X₃_iff n ‹_›).mpr (ih (kernel f)) lemma projectiveDimension_le_projectiveDimension_of_isLocalizedModule [Small.{v, u} R] @@ -88,7 +86,7 @@ lemma hasProjectiveDimensionLE_iff_forall_maximalSpectrum (n : ℕ) [Small.{v} R | zero => simp only [HasProjectiveDimensionLE, zero_add, ← projective_iff_hasProjectiveDimensionLT_one] refine ⟨fun h p ↦ ?_, fun h ↦ ?_⟩ - · have : Small.{v} (Localization p.asIdeal.primeCompl) := + · let : Small.{v} (Localization p.asIdeal.primeCompl) := small_of_surjective Localization.mkHom_surjective rw [← IsProjective.iff_projective] exact Module.projective_of_isLocalizedModule p.1.primeCompl @@ -97,10 +95,9 @@ lemma hasProjectiveDimensionLE_iff_forall_maximalSpectrum (n : ℕ) [Small.{v} R have : Module.FinitePresentation R M := Module.finitePresentation_of_finite R M apply Module.projective_of_localization_maximal (fun p hp ↦ ?_) have : Module.Projective (Localization.AtPrime p) (M.localizedModule p.primeCompl) := by - have : Small.{v} (Localization.AtPrime p) := + let : Small.{v} (Localization.AtPrime p) := small_of_surjective Localization.mkHom_surjective - rw [IsProjective.iff_projective] - exact h ⟨p, hp⟩ + simpa [IsProjective.iff_projective] using h ⟨p, hp⟩ exact Module.Projective.of_equiv (LinearEquiv.extendScalarsOfIsLocalization p.primeCompl (Localization.AtPrime p) (IsLocalizedModule.linearEquiv p.primeCompl (M.localizedModuleMkLinearMap p.primeCompl) diff --git a/Mathlib/RingTheory/LocalRing/RingHom/Basic.lean b/Mathlib/RingTheory/LocalRing/RingHom/Basic.lean index 3fe5b123aca1fb..15c4193e4dad8f 100644 --- a/Mathlib/RingTheory/LocalRing/RingHom/Basic.lean +++ b/Mathlib/RingTheory/LocalRing/RingHom/Basic.lean @@ -93,6 +93,9 @@ theorem local_hom_TFAE (f : R →+* S) : tfae_have 5 → 4 := fun h ↦ le_of_eq h.symm tfae_finish +lemma maximalIdeal_comap (f : R →+* S) [IsLocalHom f] : (maximalIdeal S).comap f = maximalIdeal R := + ((local_hom_TFAE _).out 0 4).mp ‹_› + end theorem of_surjective [CommSemiring R] [IsLocalRing R] [Semiring S] [Nontrivial S] (f : R →+* S) @@ -133,6 +136,16 @@ instance (priority := 100) {K R} [DivisionRing K] [CommRing R] [Nontrivial R] (f : K →+* R) : IsLocalHom f where map_nonunit r hr := by simpa only [isUnit_iff_ne_zero, ne_eq, map_eq_zero] using hr.ne_zero +lemma map_maximalIdeal_of_surjective [CommRing R] [CommRing S] [IsLocalRing R] [IsLocalRing S] + (f : R →+* S) (hf : Function.Surjective f) : (maximalIdeal R).map f = maximalIdeal S := by + let := IsLocalHom.of_surjective f hf + rw [← maximalIdeal_comap f, Ideal.map_comap_of_surjective f hf] + +@[simp] +lemma map_ringEquiv_maximalIdeal [CommRing R] [CommRing S] [IsLocalRing R] [IsLocalRing S] + (e : R ≃+* S) : (maximalIdeal R).map e = maximalIdeal S := + map_maximalIdeal_of_surjective (e : R →+* S) e.surjective + end IsLocalRing namespace RingEquiv diff --git a/Mathlib/RingTheory/Localization/AsSubring.lean b/Mathlib/RingTheory/Localization/AsSubring.lean index 2f9222eb274926..ea364019aa7163 100644 --- a/Mathlib/RingTheory/Localization/AsSubring.lean +++ b/Mathlib/RingTheory/Localization/AsSubring.lean @@ -69,7 +69,6 @@ instance isLocalization_range_mapToFractionRing (B : Type*) [CommRing B] [Algebr exact ⟨fun h => congr_arg _ (IsLocalization.injective _ hS h), fun h => congr_arg _ (IsFractionRing.injective A K h)⟩) -set_option backward.isDefEq.respectTransparency false in instance isFractionRing_range_mapToFractionRing (B : Type*) [CommRing B] [Algebra A B] [IsLocalization S B] (hS : S ≤ A⁰) : IsFractionRing (mapToFractionRing K S B hS).range K := IsFractionRing.isFractionRing_of_isLocalization S _ _ hS @@ -95,7 +94,6 @@ instance isLocalization_subalgebra : IsLocalization S (subalgebra K S hS) := by rw [Subalgebra.copy_eq] infer_instance -set_option backward.isDefEq.respectTransparency false in instance isFractionRing : IsFractionRing (subalgebra K S hS) K := IsFractionRing.isFractionRing_of_isLocalization S _ _ hS @@ -140,10 +138,9 @@ instance isLocalization_ofField : IsLocalization S (ofField K S hS) := by rw [ofField_eq] exact isLocalization_subalgebra K S hS -set_option backward.isDefEq.respectTransparency false in instance (S : Subalgebra A K) : IsFractionRing S K := by refine IsFractionRing.of_field S K fun z ↦ ?_ - rcases IsFractionRing.div_surjective (A := A) z with ⟨x, y, _, eq⟩ + rcases IsFractionRing.div_surjective A z with ⟨x, y, _, eq⟩ exact ⟨algebraMap A S x, algebraMap A S y, eq.symm⟩ instance isFractionRing_ofField : IsFractionRing (ofField K S hS) K := diff --git a/Mathlib/RingTheory/Localization/FractionRing.lean b/Mathlib/RingTheory/Localization/FractionRing.lean index 47c285a7ef6fd8..aeaaa2c4ca2aa5 100644 --- a/Mathlib/RingTheory/Localization/FractionRing.lean +++ b/Mathlib/RingTheory/Localization/FractionRing.lean @@ -250,6 +250,7 @@ theorem mk'_mk_eq_div {r s} (hs : s ∈ nonZeroDivisors A) : theorem mk'_eq_div {r} (s : nonZeroDivisors A) : mk' K r s = algebraMap A K r / algebraMap A K s := mk'_mk_eq_div s.2 +variable (A) in theorem div_surjective (z : K) : ∃ x y : A, y ∈ nonZeroDivisors A ∧ algebraMap _ _ x / algebraMap _ _ y = z := let ⟨x, ⟨y, hy⟩, h⟩ := exists_mk'_eq (nonZeroDivisors A) z @@ -286,7 +287,7 @@ omit [IsDomain B] theorem algHom_commutes (e : K₁ →ₐ[A] K₂) (f : L₁ →ₐ[B] L₂) (x : K₁) : algebraMap K₂ L₂ (e x) = f (algebraMap K₁ L₁ x) := by - obtain ⟨r, s, hs, rfl⟩ := IsFractionRing.div_surjective (A := A) x + obtain ⟨r, s, hs, rfl⟩ := IsFractionRing.div_surjective A x simp_rw [map_div₀, AlgHom.commutes, ← IsScalarTower.algebraMap_apply, IsScalarTower.algebraMap_apply A B L₁, AlgHom.commutes, ← IsScalarTower.algebraMap_apply] @@ -303,7 +304,7 @@ variable (A K) in the image of `algebraMap A K` is equal to the whole field `K`. -/ theorem closure_range_algebraMap : Subfield.closure (Set.range (algebraMap A K)) = ⊤ := top_unique fun z _ ↦ by - obtain ⟨_, _, -, rfl⟩ := div_surjective (A := A) z + obtain ⟨_, _, -, rfl⟩ := div_surjective A z apply div_mem <;> exact Subfield.subset_closure ⟨_, rfl⟩ variable {L : Type*} [Field L] {g : A →+* L} {f : K →+* L} @@ -343,7 +344,7 @@ theorem lift_unique (hg : Function.Injective g) {f : K →+* L} theorem ringHom_ext {f1 f2 : K →+* L} (hf : ∀ x : A, f1 (algebraMap A K x) = f2 (algebraMap A K x)) : f1 = f2 := by ext z - obtain ⟨x, y, hy, rfl⟩ := IsFractionRing.div_surjective (A := A) z + obtain ⟨x, y, hy, rfl⟩ := IsFractionRing.div_surjective A z rw [map_div₀, map_div₀, hf, hf] theorem injective_comp_algebraMap : @@ -474,7 +475,7 @@ variable {A B C D : Type*} noncomputable def fieldEquivOfAlgEquiv (f : B ≃ₐ[A] C) : FB ≃ₐ[FA] FC where __ := IsFractionRing.ringEquivOfRingEquiv f.toRingEquiv commutes' x := by - obtain ⟨x, y, -, rfl⟩ := IsFractionRing.div_surjective (A := A) x + obtain ⟨x, y, -, rfl⟩ := IsFractionRing.div_surjective A x simp_rw [map_div₀, ← IsScalarTower.algebraMap_apply, IsScalarTower.algebraMap_apply A B FB] simp [← IsScalarTower.algebraMap_apply A C FC] @@ -494,14 +495,14 @@ variable (A B) in lemma fieldEquivOfAlgEquiv_refl : fieldEquivOfAlgEquiv FA FB FB (AlgEquiv.refl : B ≃ₐ[A] B) = AlgEquiv.refl := by ext x - obtain ⟨x, y, -, rfl⟩ := IsFractionRing.div_surjective (A := B) x + obtain ⟨x, y, -, rfl⟩ := IsFractionRing.div_surjective B x simp lemma fieldEquivOfAlgEquiv_trans (f : B ≃ₐ[A] C) (g : C ≃ₐ[A] D) : fieldEquivOfAlgEquiv FA FB FD (f.trans g) = (fieldEquivOfAlgEquiv FA FB FC f).trans (fieldEquivOfAlgEquiv FA FC FD g) := by ext x - obtain ⟨x, y, -, rfl⟩ := IsFractionRing.div_surjective (A := B) x + obtain ⟨x, y, -, rfl⟩ := IsFractionRing.div_surjective B x simp end fieldEquivOfAlgEquiv diff --git a/Mathlib/RingTheory/Localization/Integral.lean b/Mathlib/RingTheory/Localization/Integral.lean index 6984e2c5b71340..f3b893496e87fa 100644 --- a/Mathlib/RingTheory/Localization/Integral.lean +++ b/Mathlib/RingTheory/Localization/Integral.lean @@ -278,7 +278,6 @@ lemma IsLocalization.exists_isIntegral_smul_of_isIntegral_map exact ⟨m, hm, by simpa [Algebra.smul_def, leadingCoeff_mul_monic hpm] using RingHom.isIntegralElem_leadingCoeff_mul (algebraMap R S) (C m * p) x (by simpa)⟩ -set_option backward.isDefEq.respectTransparency false in /-- If `t` is `R`-integral in `S[1/r]` where `r : S` is integral over `R`, then `r ^ n • t` is integral in `S` for some `n`. -/ lemma IsLocalization.Away.exists_isIntegral_mul_of_isIntegral_algebraMap @@ -307,7 +306,6 @@ lemma IsLocalization.Away.exists_isIntegral_mul_of_isIntegral_mk' convert (hr.pow n).algebraMap.mul hx exact (mk'_spec'_mk ..).symm -set_option backward.isDefEq.respectTransparency false in /-- If `t` is integral over `R[1/t]`, then it is integral over `R`. -/ lemma isIntegral_of_isIntegral_adjoin_of_mul_eq_one (t s : S) (hst : s * t = 1) (ht : IsIntegral (Algebra.adjoin R {s}) t) : @@ -409,7 +407,6 @@ variable {L : Type*} [Field K] [Field L] [Algebra A K] [IsFractionRing A K] open Algebra -set_option backward.isDefEq.respectTransparency false in /-- If the field `L` is an algebraic extension of the integral domain `A`, the integral closure of `A` in `L` has fraction field `L`. -/ theorem isFractionRing_of_algebraic [Algebra A L] [Algebra.IsAlgebraic A L] @@ -418,7 +415,6 @@ theorem isFractionRing_of_algebraic [Algebra A L] [Algebra.IsAlgebraic A L] variable (K L) -set_option backward.isDefEq.respectTransparency false in /-- If the field `L` is a finite extension of the fraction field of the integral domain `A`, the integral closure of `A` in `L` has fraction field `L`. -/ theorem isFractionRing_of_finite_extension [IsDomain A] [Algebra A L] [Algebra K L] @@ -432,7 +428,6 @@ section variable {Rf Sf : Type*} [CommRing Rf] [CommRing Sf] [Algebra R Rf] [Algebra S Sf] [Algebra Rf Sf] [Algebra R Sf] [IsScalarTower R S Sf] [IsScalarTower R Rf Sf] -set_option backward.isDefEq.respectTransparency false in /-- Taking integral closure commutes with localizations. -/ -- We take in an arbitrary `Algebra (integralClosure R S) (integralClosure Rf Sf)` instance -- so that it applies more easily. @@ -496,7 +491,7 @@ theorem isAlgebraic_iff' [Field K] [IsDomain R] [Algebra R K] [Algebra S K] letI := FractionRing.liftAlgebra R K have := FractionRing.isScalarTower_liftAlgebra R K rw [IsFractionRing.isAlgebraic_iff R (FractionRing R) K, isAlgebraic_iff_isIntegral] - obtain ⟨a : S, b, ha, rfl⟩ := div_surjective (A := S) x + obtain ⟨a : S, b, ha, rfl⟩ := div_surjective S x obtain ⟨f, hf₁, hf₂⟩ := h b rw [div_eq_mul_inv] refine .mul ?_ (.inv ?_) <;> exact isAlgebraic_iff_isIntegral.mp <| diff --git a/Mathlib/RingTheory/Localization/Submodule.lean b/Mathlib/RingTheory/Localization/Submodule.lean index 62a05c857a3bc0..85000ebbcf2ecb 100644 --- a/Mathlib/RingTheory/Localization/Submodule.lean +++ b/Mathlib/RingTheory/Localization/Submodule.lean @@ -87,7 +87,6 @@ instance {R} [CommRing R] [IsNoetherianRing R] (S : Submonoid R) : IsNoetherianRing (Localization S) := IsLocalization.isNoetherianRing S _ ‹_› -set_option backward.isDefEq.respectTransparency false in lemma _root_.Algebra.EssFiniteType.isNoetherianRing (R S : Type*) [CommRing R] [CommRing S] [Algebra R S] [Algebra.EssFiniteType R S] [IsNoetherianRing R] : IsNoetherianRing S := by diff --git a/Mathlib/RingTheory/MvPolynomial/Localization.lean b/Mathlib/RingTheory/MvPolynomial/Localization.lean index 30aa53ae0bb312..9102572ed657d0 100644 --- a/Mathlib/RingTheory/MvPolynomial/Localization.lean +++ b/Mathlib/RingTheory/MvPolynomial/Localization.lean @@ -82,7 +82,6 @@ private lemma auxHom_mk (p : MvPolynomial Unit R) : auxHom S r p = aeval (S₁ := S) (fun _ ↦ invSelf r) p := rfl -set_option backward.isDefEq.respectTransparency false in set_option backward.privateInPublic true in private noncomputable def auxInv : S →+* (MvPolynomial Unit R) ⧸ Ideal.span { C r * X () - 1 } := diff --git a/Mathlib/RingTheory/Norm/Basic.lean b/Mathlib/RingTheory/Norm/Basic.lean index 31f83ad46784e7..eda9b7589fe7ea 100644 --- a/Mathlib/RingTheory/Norm/Basic.lean +++ b/Mathlib/RingTheory/Norm/Basic.lean @@ -147,7 +147,6 @@ theorem _root_.IntermediateField.AdjoinSimple.norm_gen_eq_one {x : L} (hx : ¬Is · exact (Submodule.fg_iff_finiteDimensional _).mpr (b.finiteDimensional_of_finite) · exact IntermediateField.subset_adjoin K _ (Set.mem_singleton x) -set_option backward.isDefEq.respectTransparency false in theorem _root_.IntermediateField.AdjoinSimple.norm_gen_eq_prod_roots (x : L) (hf : ((minpoly K x).map (algebraMap K F)).Splits) : (algebraMap K F) (norm K (AdjoinSimple.gen K x)) = diff --git a/Mathlib/RingTheory/Norm/Transitivity.lean b/Mathlib/RingTheory/Norm/Transitivity.lean index 1e3464136e8c57..d573878929c064 100644 --- a/Mathlib/RingTheory/Norm/Transitivity.lean +++ b/Mathlib/RingTheory/Norm/Transitivity.lean @@ -210,7 +210,6 @@ open Module IntermediateField AdjoinSimple namespace Algebra -set_option backward.isDefEq.respectTransparency false in theorem isIntegral_norm [Algebra R L] [Algebra R K] [IsScalarTower R K L] {x : L} (hx : IsIntegral R x) : IsIntegral R (norm K x) := by by_cases h : FiniteDimensional K L @@ -227,7 +226,6 @@ theorem isIntegral_norm [Algebra R L] [Algebra R K] [IsScalarTower R K L] {x : L obtain ⟨P, hP⟩ := minpoly.dvd K x (show aeval x ((minpoly R x).map (algebraMap R K)) = 0 by simp) simp [hP, aeval_mul, (mem_aroots'.mp hy).2] -set_option backward.isDefEq.respectTransparency false in theorem norm_eq_norm_adjoin (x : L) : norm K x = norm K (AdjoinSimple.gen K x) ^ finrank K⟮x⟯ L := by by_cases h : FiniteDimensional K L @@ -259,7 +257,6 @@ theorem norm_eq_prod_roots {x : L} (hF : ((minpoly K x).map (algebraMap K F)).Sp variable [FiniteDimensional K L] -set_option backward.isDefEq.respectTransparency false in /-- For `L/K` a finite separable extension of fields and `E` an algebraically closed extension of `K`, the norm (down to `K`) of an element `x` of `L` is equal to the product of the images of `x` over all the `K`-embeddings `σ` of `L` into `E`. -/ diff --git a/Mathlib/RingTheory/NormalClosure.lean b/Mathlib/RingTheory/NormalClosure.lean index 680d35a688dbe9..38a10b72e07164 100644 --- a/Mathlib/RingTheory/NormalClosure.lean +++ b/Mathlib/RingTheory/NormalClosure.lean @@ -72,7 +72,6 @@ instance : Nontrivial T := inferInstanceAs (Nontrivial (integralClosure S E)) instance : Algebra S T := inferInstanceAs (Algebra S (integralClosure S E)) -set_option backward.isDefEq.respectTransparency false in /-- This is a local instance since it is only used in this file to construct `Ring.NormalClosure`. -/ @@ -80,7 +79,6 @@ local instance : Algebra T E := inferInstanceAs (Algebra (integralClosure S E) E instance : Algebra R T := ((algebraMap S T).comp (algebraMap R S)).toAlgebra -set_option backward.isDefEq.respectTransparency false in local instance : IsScalarTower S T E := inferInstanceAs (IsScalarTower S (integralClosure S E) E) @@ -106,10 +104,8 @@ instance : FaithfulSMul R T := variable [Module.Finite R S] -set_option backward.isDefEq.respectTransparency false in local instance : FiniteDimensional L E := Module.Finite.right K L E -set_option backward.isDefEq.respectTransparency false in local instance : IsFractionRing T E := integralClosure.isFractionRing_of_finite_extension L E diff --git a/Mathlib/RingTheory/Polynomial/GaussLemma.lean b/Mathlib/RingTheory/Polynomial/GaussLemma.lean index ae4f5ea4291d08..d4389cc1548fff 100644 --- a/Mathlib/RingTheory/Polynomial/GaussLemma.lean +++ b/Mathlib/RingTheory/Polynomial/GaussLemma.lean @@ -54,7 +54,6 @@ open IsIntegrallyClosed variable (K : Type*) [Field K] [Algebra R K] -set_option backward.isDefEq.respectTransparency false in theorem integralClosure.mem_lifts_of_monic_of_dvd_map {f : R[X]} (hf : f.Monic) {g : K[X]} (hg : g.Monic) (hd : g ∣ f.map (algebraMap R K)) : g ∈ lifts (algebraMap (integralClosure R K) K) := by diff --git a/Mathlib/RingTheory/Polynomial/GaussNorm.lean b/Mathlib/RingTheory/Polynomial/GaussNorm.lean index f62a6501a57d54..49e909fe532417 100644 --- a/Mathlib/RingTheory/Polynomial/GaussNorm.lean +++ b/Mathlib/RingTheory/Polynomial/GaussNorm.lean @@ -5,6 +5,7 @@ Authors: Fabrizio Barroero -/ module +public import Mathlib.Algebra.Order.Ring.IsNonarchimedean public import Mathlib.RingTheory.PowerSeries.GaussNorm /-! @@ -20,18 +21,23 @@ the Gauss norm corresponds to the maximum of the absolute values of the coeffici In the file `Mathlib/RingTheory/PowerSeries/GaussNorm.lean`, the Gauss norm is defined for power series. This is a generalization of the Gauss norm defined in this file in case `v` is a -non-negative function with `v 0 = 0` and `c ≥ 0`. +nonnegative function with `v 0 = 0` and `c ≥ 0`. ## Main Definitions and Results * `Polynomial.gaussNorm` is the supremum of the set of all values of `v (p.coeff i) * c ^ i` for all `i` in the support of `p`, where `p` is a polynomial in `R[X]`, `v : R → ℝ` is a function and `c` is a real number. -* `Polynomial.gaussNorm_coe_powerSeries`: if `v` is a non-negative function with `v 0 = 0` and `c` +* `Polynomial.gaussNorm_coe_powerSeries`: if `v` is a nonnegative function with `v 0 = 0` and `c` is nonnegative, the Gauss norm of a polynomial is equal to its Gauss norm as a power series. -* `Polynomial.gaussNorm_nonneg`: if `v` is a non-negative function, then the Gauss norm is - non-negative. -* `Polynomial.gaussNorm_eq_zero_iff`: if `v x = 0 ↔ x = 0` for all `x : R`, then the Gauss - norm is zero if and only if the polynomial is zero. +* `Polynomial.exists_min_eq_gaussNorm`: if `v` is a nonnegative function with `v 0 = 0` and `c` + is nonnegative, there exists a minimal index `i` such that the Gauss norm of `p` at `c` is + attained at `i`. +* `Polynomial.isNonarchimedean_gaussNorm`: if `v` is a nonnegative nonarchimedean function with + `v 0 = 0` and `c` is nonnegative, the Gauss norm is nonarchimedean. +* `Polynomial.gaussNorm_mul`: if `v` is a nonarchimedean absolute value, then the Gauss norm is + multiplicative. +* `Polynomial.gaussNorm_isAbsoluteValue`: if `v` is a nonarchimedean absolute value, then the + Gauss norm is an absolute value. -/ @[expose] public section @@ -50,8 +56,9 @@ def gaussNorm : ℝ := if h : p.support.Nonempty then p.support.sup' h fun i ↦ @[simp] lemma gaussNorm_zero : gaussNorm v c 0 = 0 := by simp [gaussNorm] -theorem exists_eq_gaussNorm [ZeroHomClass F R ℝ] : - ∃ i, p.gaussNorm v c = v (p.coeff i) * c ^ i := by +variable [ZeroHomClass F R ℝ] + +theorem exists_eq_gaussNorm : ∃ i, p.gaussNorm v c = v (p.coeff i) * c ^ i := by by_cases h_supp : p.support.Nonempty · simp only [gaussNorm, h_supp] obtain ⟨i, hi1, hi2⟩ := Finset.exists_mem_eq_sup' h_supp fun i ↦ (v (p.coeff i) * c ^ i) @@ -59,16 +66,17 @@ theorem exists_eq_gaussNorm [ZeroHomClass F R ℝ] : · simp_all @[simp] -lemma gaussNorm_C [ZeroHomClass F R ℝ] (r : R) : (C r).gaussNorm v c = v r := by +lemma gaussNorm_C (r : R) : (C r).gaussNorm v c = v r := by by_cases hr : r = 0 <;> simp [gaussNorm, support_C, hr] @[simp] -theorem gaussNorm_monomial [ZeroHomClass F R ℝ] (n : ℕ) (r : R) : +theorem gaussNorm_monomial (n : ℕ) (r : R) : (monomial n r).gaussNorm v c = v r * c ^ n := by by_cases hr : r = 0 <;> simp [gaussNorm, support_monomial, hr] variable {c} +omit [ZeroHomClass F R ℝ] in private lemma sup'_nonneg_of_ne_zero [NonnegHomClass F R ℝ] {p : R[X]} (h : p.support.Nonempty) (hc : 0 ≤ c) : 0 ≤ p.support.sup' h fun i ↦ (v (p.coeff i) * c ^ i) := by simp only [Finset.le_sup'_iff, mem_support_iff] @@ -77,7 +85,7 @@ private lemma sup'_nonneg_of_ne_zero [NonnegHomClass F R ℝ] {p : R[X]} (h : p. true_and] positivity -private lemma aux_bdd [ZeroHomClass F R ℝ] : BddAbove {x | ∃ i, v (p.coeff i) * c ^ i = x} := by +private lemma aux_bdd : BddAbove {x | ∃ i, v (p.coeff i) * c ^ i = x} := by let f : p.support → ℝ := fun i ↦ v (p.coeff i) * c ^ i.val have h_fin : (f '' ⊤ ∪ {0}).Finite := by apply Set.Finite.union _ <| Set.finite_singleton 0 @@ -89,9 +97,13 @@ private lemma aux_bdd [ZeroHomClass F R ℝ] : BddAbove {x | ∃ i, v (p.coeff i Set.mem_range, Subtype.exists, mem_support_iff] grind +variable [NonnegHomClass F R ℝ] + +/-- If `v` is a nonnegative function with `v 0 = 0` and `c` is nonnegative, the Gauss norm of a +polynomial is equal to its Gauss norm as a power series. -/ @[simp] -theorem gaussNorm_coe_powerSeries [ZeroHomClass F R ℝ] [NonnegHomClass F R ℝ] - (hc : 0 ≤ c) : (p.toPowerSeries).gaussNorm v c = p.gaussNorm v c := by +theorem gaussNorm_coe_powerSeries (hc : 0 ≤ c) : + (p.toPowerSeries).gaussNorm v c = p.gaussNorm v c := by by_cases hp : p = 0 · simp [hp] · simp only [PowerSeries.gaussNorm, coeff_coe, gaussNorm, support_nonempty, ne_eq, hp, @@ -107,23 +119,174 @@ theorem gaussNorm_coe_powerSeries [ZeroHomClass F R ℝ] [NonnegHomClass F R ℝ rw [hi] exact le_ciSup (aux_bdd v p) i +/-- If `v x = 0 → x = 0` for all `x : R` and `v` is nonnegative, then the Gauss norm is zero if and +only if the polynomial is zero. -/ @[simp] -theorem gaussNorm_eq_zero_iff [ZeroHomClass F R ℝ] [NonnegHomClass F R ℝ] - (h_eq_zero : ∀ x : R, v x = 0 → x = 0) (hc : 0 < c) : p.gaussNorm v c = 0 ↔ p = 0 := by +theorem gaussNorm_eq_zero_iff (h_eq_zero : ∀ x : R, v x = 0 → x = 0) (hc : 0 < c) : + p.gaussNorm v c = 0 ↔ p = 0 := by rw [← gaussNorm_coe_powerSeries _ _ (le_of_lt hc), PowerSeries.gaussNorm_eq_zero_iff h_eq_zero hc (by simpa only [coeff_coe] using aux_bdd v p), coe_eq_zero_iff] -theorem gaussNorm_nonneg (hc : 0 ≤ c) [NonnegHomClass F R ℝ] : 0 ≤ p.gaussNorm v c := by +omit [ZeroHomClass F R ℝ] in +/-- If `v` is a nonnegative function, then the Gauss norm is nonnegative. -/ +theorem gaussNorm_nonneg (hc : 0 ≤ c) : 0 ≤ p.gaussNorm v c := by by_cases hp : p.support.Nonempty <;> simp_all [gaussNorm, sup'_nonneg_of_ne_zero, -Finset.le_sup'_iff] -lemma le_gaussNorm [ZeroHomClass F R ℝ] [NonnegHomClass F R ℝ] (hc : 0 ≤ c) (i : ℕ) : - v (p.coeff i) * c ^ i ≤ p.gaussNorm v c := by +lemma le_gaussNorm (hc : 0 ≤ c) (i : ℕ) : v (p.coeff i) * c ^ i ≤ p.gaussNorm v c := by rw [← gaussNorm_coe_powerSeries _ _ hc, ← coeff_coe] apply PowerSeries.le_gaussNorm simpa using aux_bdd v p +@[simp] +lemma gaussNorm_zero_right : p.gaussNorm v 0 = v (p.coeff 0) := by + have : (fun i ↦ v (p.coeff i) * 0 ^ i) = fun i ↦ if i = 0 then v (p.coeff 0) else 0 := by + aesop + rcases eq_or_ne (p.coeff 0) 0 with _ | hcoeff0 + · simp_all [gaussNorm] + · apply le_antisymm + · aesop (add norm (by simp [gaussNorm, Finset.sup'_le_iff])) + · grind [p.le_gaussNorm v (le_refl 0) 0] + +/-- If `v` is a nonnegative function with `v 0 = 0` and `c` is nonnegative, there exists a minimal +index `i` such that the Gauss norm of `p` at `c` is attained at `i`. -/ +lemma exists_min_eq_gaussNorm (p : R[X]) (hc : 0 ≤ c) : + ∃ i, p.gaussNorm v c = v (p.coeff i) * c ^ i ∧ + ∀ j, j < i → v (p.coeff j) * c ^ j < p.gaussNorm v c := by + have h_nonempty : {i | gaussNorm v c p = v (p.coeff i) * c ^ i}.Nonempty := by + obtain ⟨i, hi⟩ := exists_eq_gaussNorm v c p + exact ⟨i, Set.mem_setOf.mpr hi⟩ + refine ⟨Nat.find h_nonempty, Nat.find_spec h_nonempty, ?_⟩ + intro j hj_lt + simp only [Nat.lt_find_iff, Set.mem_setOf_eq] at hj_lt + exact lt_of_le_of_ne (le_gaussNorm v _ hc j) fun a ↦ hj_lt j (Nat.le_refl j) a.symm + +/-- If `v` is a nonnegative nonarchimedean function with `v 0 = 0` and `c` is nonnegative, the +Gauss norm is nonarchimedean. -/ +theorem isNonarchimedean_gaussNorm (hna : IsNonarchimedean v) {c : ℝ} (hc : 0 ≤ c) : + IsNonarchimedean (gaussNorm v c) := by + intro p q + rcases eq_or_ne p 0 with hp | _ + · simp [hp] + rcases eq_or_ne q 0 with hq | _ + · simp [hq] + rcases eq_or_ne (p + q) 0 with hpq | hpq + · simp [hpq, hc, gaussNorm_nonneg] + simp only [gaussNorm, support_nonempty, ne_eq, hpq, not_false_eq_true, ↓reduceDIte, + Finset.sup'_le_iff] + intro i _ + calc + v ((p + q).coeff i) * c ^ i + ≤ max (v (p.coeff i)) (v (q.coeff i)) * c ^ i := by + rw [coeff_add] + gcongr + exact hna (p.coeff i) (q.coeff i) + _ = max (v (p.coeff i) * c ^ i) (v (q.coeff i) * c ^ i) := by + rw [max_mul_of_nonneg _ _ (pow_nonneg hc _)] + _ ≤ max (gaussNorm v c p) (gaussNorm v c q) := by + apply max_le_max <;> + exact le_gaussNorm v _ hc i + +open Finset in +/-- If `v` is a nonnegative nonarchimedean multiplicative function with `v 0 = 0` and `c` is +nonnegative, then the Gauss norm is submultiplicative. -/ +theorem gaussNorm_mul_le [MulHomClass F R ℝ] (hna : IsNonarchimedean v) (p q : R[X]) (hc : 0 ≤ c) : + (p * q).gaussNorm v c ≤ p.gaussNorm v c * q.gaussNorm v c := by + rcases eq_or_ne (p * q) 0 with hpq | hpq + · simp [hpq, hc, gaussNorm_nonneg, mul_nonneg] + have h_supp_p : p.support.Nonempty := support_nonempty.mpr <| left_ne_zero_of_mul hpq + have h_supp_q : q.support.Nonempty := support_nonempty.mpr <| right_ne_zero_of_mul hpq + simp only [gaussNorm, support_nonempty, ne_eq, hpq, not_false_eq_true, ↓reduceDIte, h_supp_p, + h_supp_q, sup'_le_iff, coeff_mul, Nat.sum_antidiagonal_eq_sum_range_succ_mk] + intro i _ + obtain ⟨j, _, _⟩ := IsNonarchimedean.finset_image_add_of_nonempty hna _ nonempty_range_add_one + calc + v (∑ j ∈ range (i + 1), p.coeff j * q.coeff (i - j)) * c ^ i + _ ≤ v (p.coeff j * q.coeff (i - j)) * c ^ i := by gcongr + _ = (v (p.coeff j) * c ^ j) * (v (q.coeff (i - j)) * c ^ (i - j)) := by + have : c ^ j * c ^ (i - j) = c ^ i := by simp_all [← pow_add] + grind + _ ≤ (p.support.sup' _ fun i ↦ v (p.coeff i) * c ^ i) + * q.support.sup' _ fun i ↦ v (q.coeff i) * c ^ i := by + have hp_le := p.le_gaussNorm v hc j + have hq_le := q.le_gaussNorm v hc (i - j) + have := p.gaussNorm_nonneg v hc + simp_all only [gaussNorm, ↓reduceDIte] + gcongr + +section AbsoluteValue + +variable {R : Type*} [Ring R] {v : AbsoluteValue R ℝ} (hna : IsNonarchimedean v) (hc : 0 < c) + +open Finset in +include hna hc in +private theorem mul_gaussNorm_le_gaussNorm_mul (p q : R[X]) : + p.gaussNorm v c * q.gaussNorm v c ≤ (p * q).gaussNorm v c := by + have hc0 : 0 ≤ c := le_of_lt hc + obtain ⟨i, hi_p, hlt_p⟩ := p.exists_min_eq_gaussNorm v hc0 + obtain ⟨j, hj_q, hlt_q⟩ := q.exists_min_eq_gaussNorm v hc0 + -- i and j are the minimal indices where the gauss norms are attained + wlog hvpq : v (p.coeff i) ≠ 0 ∧ v (q.coeff j) ≠ 0 + · grind [mul_mul_mul_comm, gaussNorm_nonneg] + have := hvpq.1 + have := hvpq.2 + apply le_of_eq_of_le _ <| (p * q).le_gaussNorm v hc0 (i + j) + -- gaussNorm v c p * gaussNorm v c q is actually equal to v ((p * q).coeff (i + j)) * c ^ (i + j) + rw [hi_p, hj_q, coeff_mul, Nat.sum_antidiagonal_eq_sum_range_succ_mk, + IsNonarchimedean.apply_sum_eq_of_lt hna (k := i) (by simp)] + /- IsNonarchimedean.apply_sum_eq_of_lt makes the goal almost trivial so we are left to prove + the hmax hypothesis -/ + · grind + intro x hx hneq + apply lt_of_mul_lt_mul_right _ <| pow_nonneg hc0 (i + j) + have : x + (i + j - x) = i + j := by simp_all + convert_to v (p.coeff x) * c ^ x * (v (q.coeff (i + j - x)) * c ^ (i + j - x)) < + v (p.coeff i) * c ^ i * (v (q.coeff j) * c ^ j) + · grind + · grind + -- we need to distinguish two cases depending on whether x < i or x > i + rcases lt_or_gt_of_ne hneq + · calc + v (p.coeff x) * c ^ x * (v (q.coeff (i + j - x)) * c ^ (i + j - x)) + _ ≤ v (p.coeff x) * c ^ x * gaussNorm v c q := by + gcongr + exact q.le_gaussNorm v hc0 (i + j - x) + _ = v (p.coeff x) * c ^ x * (v (q.coeff j) * c ^ j) := by + rw [hj_q] + _ < v (p.coeff i) * c ^ i * (v (q.coeff j) * c ^ j) := by + gcongr 1 + grind + · calc + v (p.coeff x) * c ^ x * (v (q.coeff (i + j - x)) * c ^ (i + j - x)) + _ ≤ gaussNorm v c p * (v (q.coeff (i + j - x)) * c ^ (i + j - x)) := by + gcongr + exact p.le_gaussNorm v hc0 x + _ = v (p.coeff i) * c ^ i * (v (q.coeff (i + j - x)) * c ^ (i + j - x)) := by + rw [hi_p] + _ < v (p.coeff i) * c ^ i * (v (q.coeff j) * c ^ j) := by + gcongr 1 + grind + +include hna hc in +/-- If `v` is a nonarchimedean absolute value, then the Gauss norm is multiplicative. -/ +theorem gaussNorm_mul (p q : R[X]) : + (p * q).gaussNorm v c = p.gaussNorm v c * q.gaussNorm v c := + le_antisymm (gaussNorm_mul_le v hna p q (le_of_lt hc)) + <| mul_gaussNorm_le_gaussNorm_mul hna hc p q + +include hna hc in +/-- If `v` is a nonarchimedean absolute value, then the Gauss norm is an absolute value. -/ +theorem gaussNorm_isAbsoluteValue : + IsAbsoluteValue (gaussNorm v c) where + abv_nonneg' p := p.gaussNorm_nonneg v <| le_of_lt hc + abv_eq_zero' := gaussNorm_eq_zero_iff v _ (fun _ hx ↦ (AbsoluteValue.eq_zero v).mp hx) hc + abv_add' p q := by + grind [isNonarchimedean_gaussNorm v hna (le_of_lt hc) p q, gaussNorm_nonneg] + abv_mul' p q := gaussNorm_mul hna hc p q + +end AbsoluteValue + end Polynomial namespace PowerSeries diff --git a/Mathlib/RingTheory/Polynomial/IsIntegral.lean b/Mathlib/RingTheory/Polynomial/IsIntegral.lean index 48f98dc0a0ad4f..06859698ad8d5d 100644 --- a/Mathlib/RingTheory/Polynomial/IsIntegral.lean +++ b/Mathlib/RingTheory/Polynomial/IsIntegral.lean @@ -167,7 +167,6 @@ theorem Polynomial.isIntegral_iff_isIntegral_coeff {f : S[X]} : simp only [← C_mul_X_pow_eq_monomial, ← map_X (algebraMap R S)] exact .sum _ fun i _ ↦ ((H i).map (CAlgHom (R := R))).tower_top.mul (.pow isIntegral_algebraMap _) -set_option backward.isDefEq.respectTransparency false in lemma IsIntegral.of_aeval_monic_of_isIntegral_coeff {R A : Type*} [CommRing R] [CommRing A] [Algebra R A] {x : A} {p : A[X]} (monic : p.Monic) (deg : p.natDegree ≠ 0) (hx : IsIntegral R (eval x p)) (hp : ∀ i, IsIntegral R (p.coeff i)) : IsIntegral R x := by diff --git a/Mathlib/RingTheory/Polynomial/Tower.lean b/Mathlib/RingTheory/Polynomial/Tower.lean index 5b8c9a196451d8..7308b6147a9592 100644 --- a/Mathlib/RingTheory/Polynomial/Tower.lean +++ b/Mathlib/RingTheory/Polynomial/Tower.lean @@ -75,7 +75,6 @@ section CommSemiring variable {R A} [CommSemiring R] [CommSemiring A] [Algebra R A] -set_option backward.isDefEq.respectTransparency false in @[simp] theorem aeval_coe (S : Subalgebra R A) (x : S) (p : R[X]) : aeval (x : A) p = aeval x p := aeval_algebraMap_apply A x p diff --git a/Mathlib/RingTheory/QuasiFinite/Basic.lean b/Mathlib/RingTheory/QuasiFinite/Basic.lean index 29b49e50ac37f5..a96c2e5d3e2f74 100644 --- a/Mathlib/RingTheory/QuasiFinite/Basic.lean +++ b/Mathlib/RingTheory/QuasiFinite/Basic.lean @@ -309,7 +309,6 @@ lemma iff_finite_primesOver [FiniteType R S] : simp [(PrimeSpectrum.equivSubtype S).exists_congr_left, PrimeSpectrum.ext_iff, eq_comm, PrimeSpectrum.equivSubtype, Ideal.primesOver, and_comm, Ideal.liesOver_iff, Ideal.under] -set_option backward.isDefEq.respectTransparency false in /-- If `T` is both a finite type `R`-algebra, and the localization of an integral `R`-algebra (away from an element), then `T` is quasi-finite over `R` -/ lemma of_isIntegral_of_finiteType [Algebra.IsIntegral R S] [Algebra.FiniteType R T] diff --git a/Mathlib/RingTheory/QuotSMulTop.lean b/Mathlib/RingTheory/QuotSMulTop.lean index 2e2ffa03a99999..5424636feabf94 100644 --- a/Mathlib/RingTheory/QuotSMulTop.lean +++ b/Mathlib/RingTheory/QuotSMulTop.lean @@ -144,4 +144,10 @@ noncomputable def algebraMapTensorEquivTensorQuotSMulTop (S : Type*) [CommRing S tensorQuotMapSMulEquivTensorQuot M S (Ideal.span {r}) ≪≫ₗ (Submodule.quotEquivOfEq _ _ (ideal_span_singleton_smul r _)).baseChange R S _ _ +set_option backward.isDefEq.respectTransparency false in +lemma mem_annihilator (x : R) : x ∈ Module.annihilator R (QuotSMulTop x M) := by + refine Module.mem_annihilator.mpr (fun m ↦ ?_) + rcases Submodule.Quotient.mk_surjective _ m with ⟨m', hm'⟩ + simpa [← hm', ← Submodule.Quotient.mk_smul] using Submodule.smul_mem_pointwise_smul m' x ⊤ trivial + end QuotSMulTop diff --git a/Mathlib/RingTheory/ReesAlgebra.lean b/Mathlib/RingTheory/ReesAlgebra.lean index 693539478ad844..148cfd9c7978ca 100644 --- a/Mathlib/RingTheory/ReesAlgebra.lean +++ b/Mathlib/RingTheory/ReesAlgebra.lean @@ -119,6 +119,5 @@ theorem reesAlgebra.fg (hI : I.FG) : (reesAlgebra I).FG := by instance [IsNoetherianRing R] : Algebra.FiniteType R (reesAlgebra I) := ⟨(reesAlgebra I).fg_top.mpr (reesAlgebra.fg <| IsNoetherian.noetherian I)⟩ -set_option backward.isDefEq.respectTransparency false in instance [IsNoetherianRing R] : IsNoetherianRing (reesAlgebra I) := Algebra.FiniteType.isNoetherianRing R _ diff --git a/Mathlib/RingTheory/Regular/RegularSequence.lean b/Mathlib/RingTheory/Regular/RegularSequence.lean index f0f6c9fb5e9eba..78cd1e8445a946 100644 --- a/Mathlib/RingTheory/Regular/RegularSequence.lean +++ b/Mathlib/RingTheory/Regular/RegularSequence.lean @@ -173,7 +173,7 @@ private lemma _root_.AddHom.map_smul_top_toAddSubgroup_of_surjective | @cons r s _ _ h _ ih => conv => congr <;> rw [Ideal.ofList_cons, sup_smul, sup_toAddSubgroup, ideal_span_singleton_smul, pointwise_smul_toAddSubgroup, - top_toAddSubgroup, pointwise_smul_def] + top_toAddSubgroup, AddSubgroup.pointwise_smul_def] apply DFunLike.ext (f.comp (toAddMonoidEnd R M r)) ((toAddMonoidEnd S M₂ s).comp f) at h rw [AddSubgroup.map_sup, ih, map_map, h, ← map_map, @@ -675,3 +675,23 @@ lemma _root_.IsLocalRing.isRegular_of_perm [IsLocalRing R] [IsNoetherian R M] exact Set.ext fun _ => h2.mem_iff end RingTheory.Sequence + +section IsLocalRing + +variable {R : Type*} [CommRing R] [IsLocalRing R] +variable (L : Type*) [AddCommGroup L] [Module R L] [Module.Finite R L] [Nontrivial L] + +open IsLocalRing + +lemma nontrivial_quotSMulTop_of_mem_maximalIdeal {x : R} (mem : x ∈ maximalIdeal R) : + Nontrivial (QuotSMulTop x L) := by + apply Submodule.Quotient.nontrivial_iff.mpr (Ne.symm _) + exact Submodule.top_ne_pointwise_smul_of_mem_jacobson_annihilator (maximalIdeal_le_jacobson _ mem) + +lemma RingTheory.Sequence.IsRegular.of_isWeaklyRegular_of_mem_maximalIdeal {rs : List R} + (mem : ∀ r ∈ rs, r ∈ maximalIdeal R) (reg : IsWeaklyRegular L rs) : + IsRegular L rs := + ⟨reg, Submodule.top_ne_ideal_smul_of_le_jacobson_annihilator + ((Ideal.span_le.mpr mem).trans (maximalIdeal_le_jacobson _))⟩ + +end IsLocalRing diff --git a/Mathlib/RingTheory/RootsOfUnity/AlgebraicallyClosed.lean b/Mathlib/RingTheory/RootsOfUnity/AlgebraicallyClosed.lean index 23d52a6feda8e5..00d1edb73a45e7 100644 --- a/Mathlib/RingTheory/RootsOfUnity/AlgebraicallyClosed.lean +++ b/Mathlib/RingTheory/RootsOfUnity/AlgebraicallyClosed.lean @@ -57,13 +57,11 @@ end AlgebraicClosure namespace SeparableClosure -set_option backward.isDefEq.respectTransparency false in instance hasEnoughRootsOfUnity : HasEnoughRootsOfUnity (SeparableClosure F) n := have : NeZero (n : SeparableClosure F) := ‹NeZero (n : F)›.of_injective (algebraMap F (SeparableClosure F)).injective inferInstance -set_option backward.isDefEq.respectTransparency false in instance hasEnoughRootsOfUnity_pow : HasEnoughRootsOfUnity (SeparableClosure F) (n ^ k) := have : NeZero (n : SeparableClosure F) := ‹NeZero (n : F)›.of_injective (algebraMap F (SeparableClosure F)).injective diff --git a/Mathlib/RingTheory/Smooth/Field.lean b/Mathlib/RingTheory/Smooth/Field.lean index b58792a58c3255..494eefd64a4fbb 100644 --- a/Mathlib/RingTheory/Smooth/Field.lean +++ b/Mathlib/RingTheory/Smooth/Field.lean @@ -21,7 +21,6 @@ In particular finitely generated field extensions over perfect fields are smooth variable {K L ι : Type*} [Field L] [Field K] [Algebra K L] -set_option backward.isDefEq.respectTransparency false in open scoped IntermediateField.algebraAdjoinAdjoin in lemma Algebra.FormallySmooth.adjoin_of_algebraicIndependent {v : ι → L} (hb : AlgebraicIndependent K v) : @@ -41,7 +40,6 @@ lemma Algebra.FormallySmooth.of_algebraicIndependent {v : ι → L} rw [hb'] at this exact .of_equiv IntermediateField.topEquiv -set_option backward.isDefEq.respectTransparency false in /-- Separably generated extensions are formally smooth. -/ lemma Algebra.FormallySmooth.of_algebraicIndependent_of_isSeparable [EssFiniteType K L] {v : ι → L} (hb : AlgebraicIndependent K v) @@ -54,7 +52,6 @@ lemma Algebra.FormallySmooth.of_algebraicIndependent_of_isSeparable [EssFiniteTy (FormallyEtale.iff_isSeparable _ _).mpr inferInstance exact .comp _ (IntermediateField.adjoin K (Set.range v)) _ -set_option backward.isDefEq.respectTransparency false in instance (priority := low) Algebra.FormallySmooth.of_perfectField [PerfectField K] [Algebra.EssFiniteType K L] : Algebra.FormallySmooth K L := by obtain ⟨s, hs, H⟩ := exists_isTranscendenceBasis_and_isSeparable_of_perfectField K L diff --git a/Mathlib/RingTheory/Smooth/IntegralClosure.lean b/Mathlib/RingTheory/Smooth/IntegralClosure.lean index 75039adbcd5a5f..a275c2eb7f25ff 100644 --- a/Mathlib/RingTheory/Smooth/IntegralClosure.lean +++ b/Mathlib/RingTheory/Smooth/IntegralClosure.lean @@ -33,7 +33,6 @@ open Polynomial TensorProduct variable {R S B : Type*} [CommRing R] [CommRing S] [Algebra R S] [CommRing B] [Algebra R B] -set_option backward.isDefEq.respectTransparency false in variable (R S) in /-- The comparison map from `S ⊗[R] integralClosure R B` to `integralClosure S (S ⊗[R] B)`. This is injective when `S` is `R`-flat, and (TODO) bijective when `S` is `R`-smooth. -/ @@ -49,7 +48,6 @@ def TensorProduct.toIntegralClosure (R := R) (A := S))).tower_top (A := S)).smul x simp [smul_tmul'] -set_option backward.isDefEq.respectTransparency false in lemma TensorProduct.toIntegralClosure_injective_of_flat [Module.Flat R S] : Function.Injective (toIntegralClosure R S B) := by refine Function.Injective.of_comp (f := (integralClosure _ _).val) ?_ @@ -57,7 +55,6 @@ lemma TensorProduct.toIntegralClosure_injective_of_flat [Module.Flat R S] : exact Module.Flat.lTensor_preserves_injective_linearMap (M := S) (integralClosure R B).val.toLinearMap Subtype.val_injective -set_option backward.isDefEq.respectTransparency false in /-- "Base change preserves integral closure" is stable under composition. -/ lemma TensorProduct.toIntegralClosure_bijective_of_tower {T : Type*} [CommRing T] [Algebra R T] [Algebra S T] [IsScalarTower R S T] @@ -73,7 +70,6 @@ lemma TensorProduct.toIntegralClosure_bijective_of_tower congr 1 ext; simp [e, toIntegralClosure] -set_option backward.isDefEq.respectTransparency false in /-- "Base change preserves integral closure" can be checked Zariski-locally. -/ lemma TensorProduct.toIntegralClosure_bijective_of_isLocalizationAway {s : Set S} (hs : Ideal.span s = ⊤) (Sᵣ : s → Type*) [∀ r, CommRing (Sᵣ r)] @@ -158,7 +154,6 @@ lemma TensorProduct.toIntegralClosure_mvPolynomial_bijective {σ : Type*} : MvPolynomial.scalarRTensorAlgEquiv] exact congr($this y) -set_option backward.isDefEq.respectTransparency false in attribute [local instance] Algebra.TensorProduct.rightAlgebra in /-- Localization preserves integral closure. -/ lemma TensorProduct.toIntegralClosure_bijective_of_isLocalization @@ -367,7 +362,6 @@ theorem mem_adjoin_map_integralClosure_of_isStandardEtale [Algebra.IsStandardEta exact sum_mem fun i hi ↦ Subalgebra.mul_mem _ (Algebra.subset_adjoin ⟨_, hRy _, rfl⟩) (pow_mem (Subalgebra.algebraMap_mem _ _) _) -set_option backward.isDefEq.respectTransparency false in -- Subsumed by `TensorProduct.toIntegralClosure_bijective_of_smooth` private theorem TensorProduct.toIntegralClosure_bijective_of_isStandardEtale [Algebra.IsStandardEtale R S] : Function.Bijective (toIntegralClosure R S B) := by diff --git a/Mathlib/RingTheory/Smooth/NoetherianDescent.lean b/Mathlib/RingTheory/Smooth/NoetherianDescent.lean index 3a17004f6836c6..adfa601aca59b3 100644 --- a/Mathlib/RingTheory/Smooth/NoetherianDescent.lean +++ b/Mathlib/RingTheory/Smooth/NoetherianDescent.lean @@ -213,7 +213,6 @@ public theorem exists_subalgebra_fg [Smooth A B] : D.fg_subalgebra R, ⟨.of_split _ σ₀ hσ₀, inferInstance⟩, ⟨(P.tensorModelOfHasCoeffsEquiv (D.subalgebra R)).symm⟩⟩ -set_option backward.isDefEq.respectTransparency false in @[deprecated exists_subalgebra_fg (since := "2026-01-07")] public theorem exists_subalgebra_finiteType [Smooth A B] : ∃ (A₀ : Subalgebra R A) (B₀ : Type u) (_ : CommRing B₀) (_ : Algebra A₀ B₀), @@ -221,7 +220,6 @@ public theorem exists_subalgebra_finiteType [Smooth A B] : obtain ⟨A₀, B₀, _, _, h0, h1, h2⟩ := exists_subalgebra_fg R A B exact ⟨A₀, B₀, inferInstance, inferInstance, (Subalgebra.fg_iff_finiteType A₀).mp h0, h1, h2⟩ -set_option backward.isDefEq.respectTransparency false in /-- Let `A` be an `R`-algebra. If `B` is a smooth `A`-algebra, there exists an `R`-algebra of finite type `A₀` and a smooth `A₀`-algebra `B₀` such that `B ≃ₐ A ⊗[A₀] B₀` @@ -238,7 +236,6 @@ public theorem exists_finiteType [Smooth A B] : use A₀, B₀, inferInstance, inferInstance, inferInstance, inferInstance, inferInstance, Subtype.val_injective, ⟨A₀.fg_top.mpr hA₀⟩, inferInstance -set_option backward.isDefEq.respectTransparency false in public theorem _root_.Algebra.IsStandardSmoothOfRelativeDimension.exists_subalgebra_fg (n : ℕ) [IsStandardSmoothOfRelativeDimension n A B] : ∃ (A₀ : Subalgebra R A) (B₀ : Type u) (_ : CommRing B₀) (_ : Algebra A₀ B₀), @@ -250,7 +247,6 @@ public theorem _root_.Algebra.IsStandardSmoothOfRelativeDimension.exists_subalge ⟨P.finite_coeffs.toFinset, by simp [A₀]⟩, ⟨_, _, _, inferInstance, P.ofHasCoeffs A₀, hP⟩, ⟨(P.tensorModelOfHasCoeffsEquiv A₀).symm⟩⟩ -set_option backward.isDefEq.respectTransparency false in /-- Let `A` be an `R`-algebra. If `B` is an etale `A`-algebra, there exists an `R`-subalgebra of finite type `A₀` of `A` and an etale `A₀`-algebra `B₀` such that diff --git a/Mathlib/RingTheory/TensorProduct/Basic.lean b/Mathlib/RingTheory/TensorProduct/Basic.lean index 1888cef5366947..e7ec44de33ee7f 100644 --- a/Mathlib/RingTheory/TensorProduct/Basic.lean +++ b/Mathlib/RingTheory/TensorProduct/Basic.lean @@ -546,7 +546,7 @@ lemma adjoin_one_tmul_image_eq_top [CommSemiring R] [CommSemiring A] [Semiring B] [Algebra R A] [Algebra R B] (s : Set B) (hs : adjoin R s = ⊤) : adjoin A (((1 : A) ⊗ₜ[R] ·) '' s) = ⊤ := by suffices h : adjoin A ((⊤ : Subalgebra R B).map (includeRight (A := A)) : Set (A ⊗[R] B)) = ⊤ by - simp [← h, ← hs, AlgHom.map_adjoin, -adjoin_toSubsemiring, adjoin_adjoin_of_tower] + simp [← h, ← hs, AlgHom.map_adjoin, adjoin_adjoin_of_tower] rw [← Algebra.toSubmodule_eq_top, ← top_le_iff, Algebra.map_top, ← Submodule.baseChange_top, Submodule.baseChange_eq_span, Submodule.map_top] exact span_le_adjoin _ _ diff --git a/Mathlib/RingTheory/TensorProduct/DirectLimitFG.lean b/Mathlib/RingTheory/TensorProduct/DirectLimitFG.lean index 34daf96073ec43..adce7e299190cf 100644 --- a/Mathlib/RingTheory/TensorProduct/DirectLimitFG.lean +++ b/Mathlib/RingTheory/TensorProduct/DirectLimitFG.lean @@ -254,7 +254,6 @@ theorem TensorProduct.Algebra.exists_of_fg : rw [← subtype_comp_inclusion P _ this, rTensor_comp] at hu exact range_comp_le_range _ _ hu -set_option backward.isDefEq.respectTransparency false in include hA in theorem TensorProduct.Algebra.eq_of_fg_of_subtype_eq (h : rTensor N A.val.toLinearMap t = rTensor N A.val.toLinearMap t') : @@ -323,7 +322,6 @@ theorem TensorProduct.Algebra.eq_of_fg_of_subtype_eq' {t' : A' ⊗[R] N} use B, le_trans le_sup_left hB_le, le_trans le_sup_right hB_le, hB simpa only [← rTensor_comp, ← comp_apply] using h -set_option backward.isDefEq.respectTransparency false in /-- Lift an element that maps to 0 -/ theorem Submodule.exists_fg_of_baseChange_eq_zero (f : M →ₗ[R] N) {t : S ⊗[R] M} (ht : f.baseChange S t = 0) : diff --git a/Mathlib/RingTheory/TensorProduct/Finite.lean b/Mathlib/RingTheory/TensorProduct/Finite.lean index 4a8002127c6036..ac982ef97f92ec 100644 --- a/Mathlib/RingTheory/TensorProduct/Finite.lean +++ b/Mathlib/RingTheory/TensorProduct/Finite.lean @@ -139,7 +139,6 @@ lemma Module.exists_surjective_quotient_of_finite : open TensorProduct -set_option backward.isDefEq.respectTransparency false in instance : Nontrivial (M ⊗[R] M) := by obtain ⟨I, ϕ, hI, hϕ⟩ := Module.exists_surjective_quotient_of_finite R M let ψ : M ⊗[R] M →ₗ[R] R ⧸ I := @@ -151,7 +150,6 @@ instance : Nontrivial (M ⊗[R] M) := by end NontrivialTensorProduct -set_option backward.isDefEq.respectTransparency false in theorem Subalgebra.finite_sup {K L : Type*} [CommSemiring K] [CommSemiring L] [Algebra K L] (E1 E2 : Subalgebra K L) [Module.Finite K E1] [Module.Finite K E2] : Module.Finite K ↥(E1 ⊔ E2) := by diff --git a/Mathlib/RingTheory/TensorProduct/Quotient.lean b/Mathlib/RingTheory/TensorProduct/Quotient.lean index 66be49ad35f7c5..dc8188cece987f 100644 --- a/Mathlib/RingTheory/TensorProduct/Quotient.lean +++ b/Mathlib/RingTheory/TensorProduct/Quotient.lean @@ -46,7 +46,6 @@ private lemma quotIdealMapEquivTensorQuotAux_mk (b : B) : (quotIdealMapEquivTensorQuotAux B I) b = b ⊗ₜ[A] 1 := rfl -set_option backward.isDefEq.respectTransparency false in set_option backward.privateInPublic true in set_option backward.privateInPublic.warn false in /-- `B ⊗[A] (A ⧸ I)` is isomorphic as an `A`-algebra to `B ⧸ I B`. -/ diff --git a/Mathlib/RingTheory/Trace/Basic.lean b/Mathlib/RingTheory/Trace/Basic.lean index 165fbbabaa71bd..993e4096ded6c1 100644 --- a/Mathlib/RingTheory/Trace/Basic.lean +++ b/Mathlib/RingTheory/Trace/Basic.lean @@ -107,7 +107,6 @@ theorem trace_gen_eq_zero {x : L} (hx : ¬IsIntegral K x) : · exact (Submodule.fg_iff_finiteDimensional _).mpr (b.finiteDimensional_of_finite) · exact subset_adjoin K _ (Set.mem_singleton x) -set_option backward.isDefEq.respectTransparency false in theorem trace_gen_eq_sum_roots (x : L) (hf : ((minpoly K x).map (algebraMap K F)).Splits) : algebraMap K F (trace K K⟮x⟯ (AdjoinSimple.gen K x)) = ((minpoly K x).aroots F).sum := by @@ -125,7 +124,6 @@ open IntermediateField variable (K) -set_option backward.isDefEq.respectTransparency false in theorem trace_eq_trace_adjoin [FiniteDimensional K L] (x : L) : trace K L x = finrank K⟮x⟯ L • trace K K⟮x⟯ (AdjoinSimple.gen K x) := by rw [← trace_trace (S := K⟮x⟯)] @@ -251,7 +249,6 @@ theorem sum_embeddings_eq_finrank_mul [FiniteDimensional K F] [Algebra.IsSeparab simp only [algHomEquivSigma, Equiv.coe_fn_mk, AlgHom.restrictDomain, AlgHom.comp_apply, IsScalarTower.coe_toAlgHom'] -set_option backward.isDefEq.respectTransparency false in theorem trace_eq_sum_embeddings [FiniteDimensional K L] [Algebra.IsSeparable K L] {x : L} : algebraMap K E (Algebra.trace K L x) = ∑ σ : L →ₐ[K] E, σ x := by have hx := Algebra.IsSeparable.isIntegral K x @@ -278,7 +275,6 @@ end EqSumEmbeddings section NotIsSeparable -set_option backward.isDefEq.respectTransparency false in lemma Algebra.trace_eq_zero_of_not_isSeparable (H : ¬ Algebra.IsSeparable K L) : trace K L = 0 := by obtain ⟨p, hp⟩ := ExpChar.exists K diff --git a/Mathlib/RingTheory/Unramified/Field.lean b/Mathlib/RingTheory/Unramified/Field.lean index 5f750df563dea4..2ae35da1b4e66f 100644 --- a/Mathlib/RingTheory/Unramified/Field.lean +++ b/Mathlib/RingTheory/Unramified/Field.lean @@ -199,7 +199,6 @@ theorem range_eq_top_of_isPurelyInseparable rw [map_mul, ← Algebra.smul_def, algebraMap_eq_smul_one, eq_neg_iff_add_eq_zero.mpr e, smul_neg, neg_smul, neg_neg, smul_smul, this.val_inv_mul, one_smul] -set_option backward.isDefEq.respectTransparency false in theorem isSeparable : Algebra.IsSeparable K L := by have := finite_of_free (R := K) (S := L) rw [← separableClosure.eq_top_iff] diff --git a/Mathlib/RingTheory/Unramified/LocalStructure.lean b/Mathlib/RingTheory/Unramified/LocalStructure.lean index c8a6bd0fbd707c..627e8d5b8022a0 100644 --- a/Mathlib/RingTheory/Unramified/LocalStructure.lean +++ b/Mathlib/RingTheory/Unramified/LocalStructure.lean @@ -247,7 +247,6 @@ lemma exists_notMem_forall_ne_mem_and_adjoin_eq_top refine adjoin_singleton_le ?_ exact Subalgebra.smul_mem _ (self_mem_adjoin_singleton _ _) _ -set_option backward.isDefEq.respectTransparency false in attribute [-instance] Subalgebra.instSMulSubtypeMem Subalgebra.toAlgebra Subalgebra.isScalarTower_left in /-- Let `S` be an finite `R`-algebra that is unramified at some prime `Q`. Then there exists some @@ -307,7 +306,6 @@ instance (priority := low) [Algebra.EssFiniteType R S] [Algebra.FormallyUnramified R S] : Algebra.QuasiFinite R S where finite_fiber _ _ := Algebra.FormallyUnramified.finite_of_free _ _ -set_option backward.isDefEq.respectTransparency false in lemma exists_hasStandardEtaleSurjectionOn (Q : Ideal S) [Q.IsPrime] [FiniteType R S] [IsUnramifiedAt R Q] : ∃ f ∉ Q, HasStandardEtaleSurjectionOn R f := by diff --git a/Mathlib/RingTheory/Valuation/AlgebraInstances.lean b/Mathlib/RingTheory/Valuation/AlgebraInstances.lean index 0e8d432c4d5b7b..462f36c7dae04e 100644 --- a/Mathlib/RingTheory/Valuation/AlgebraInstances.lean +++ b/Mathlib/RingTheory/Valuation/AlgebraInstances.lean @@ -39,12 +39,10 @@ instance : Algebra v.valuationSubring L := inferInstance theorem algebraMap_injective : Injective (algebraMap v.valuationSubring L) := (FaithfulSMul.algebraMap_injective K L).comp (IsFractionRing.injective _ _) -set_option backward.isDefEq.respectTransparency false in theorem isIntegral_of_mem_ringOfIntegers {x : L} (hx : x ∈ integralClosure v.valuationSubring L) : IsIntegral v.valuationSubring (⟨x, hx⟩ : integralClosure v.valuationSubring L) := integralClosure.isIntegral ⟨x, hx⟩ -set_option backward.isDefEq.respectTransparency false in theorem isIntegral_of_mem_ringOfIntegers' {x : integralClosure v.valuationSubring L} : IsIntegral v.valuationSubring (x : integralClosure v.valuationSubring L) := by apply isIntegral_of_mem_ringOfIntegers @@ -69,7 +67,6 @@ instance algebra : map_mul' := fun x y => Subtype.ext <| by simp only [Subalgebra.coe_mul, map_mul] } -set_option backward.isDefEq.respectTransparency false in /-- A ring equivalence between the integral closure of the valuation subring of `K` in `L` and a ring `R` satisfying `isIntegralClosure R v.valuationSubring L`. -/ protected noncomputable def equiv (R : Type*) [CommRing R] [Algebra v.valuationSubring R] @@ -78,7 +75,6 @@ protected noncomputable def equiv (R : Type*) [CommRing R] [Algebra v.valuationS (IsIntegralClosure.equiv v.valuationSubring R L (integralClosure v.valuationSubring L)).symm.toRingEquiv -set_option backward.isDefEq.respectTransparency false in theorem integralClosure_algebraMap_injective : Injective (algebraMap v.valuationSubring (integralClosure v.valuationSubring L)) := FaithfulSMul.algebraMap_injective .. diff --git a/Mathlib/RingTheory/Valuation/Discrete/Basic.lean b/Mathlib/RingTheory/Valuation/Discrete/Basic.lean index c3d98e183a1c47..5469fe4dcff8f1 100644 --- a/Mathlib/RingTheory/Valuation/Discrete/Basic.lean +++ b/Mathlib/RingTheory/Valuation/Discrete/Basic.lean @@ -466,7 +466,7 @@ open scoped WithZero theorem exists_lift_of_le_one {x : K} (H : ((maximalIdeal A).valuation K) x ≤ (1 : ℤᵐ⁰)) : ∃ a : A, algebraMap A K a = x := by obtain ⟨π, hπ⟩ := exists_irreducible A - obtain ⟨a, b, hb, h_frac⟩ := IsFractionRing.div_surjective (A := A) x + obtain ⟨a, b, hb, h_frac⟩ := IsFractionRing.div_surjective A x by_cases ha : a = 0 · rw [← h_frac] use 0 diff --git a/Mathlib/RingTheory/Valuation/LocalSubring.lean b/Mathlib/RingTheory/Valuation/LocalSubring.lean index 72196d82e10894..58b8b0a31a694c 100644 --- a/Mathlib/RingTheory/Valuation/LocalSubring.lean +++ b/Mathlib/RingTheory/Valuation/LocalSubring.lean @@ -56,7 +56,6 @@ lemma LocalSubring.map_maximalIdeal_eq_top_of_isMax {R : LocalSubring K} rw [Ideal.map_map]; rfl exact (hR.eq_of_le h_RleSₘ ▸ hS).not_ge (LocalSubring.le_ofPrime ..) -set_option backward.isDefEq.respectTransparency false in @[stacks 00IC] -- the conclusion could be `IsIntegrallyClosedIn R.toSubring K`, which has slightly worse defeq. lemma LocalSubring.mem_of_isMax_of_isIntegral {R : LocalSubring K} diff --git a/Mathlib/RingTheory/Valuation/ValuationRing.lean b/Mathlib/RingTheory/Valuation/ValuationRing.lean index 7905ac6158ba5a..c77af59613a0ea 100644 --- a/Mathlib/RingTheory/Valuation/ValuationRing.lean +++ b/Mathlib/RingTheory/Valuation/ValuationRing.lean @@ -129,8 +129,8 @@ variable [IsDomain A] [ValuationRing A] [IsFractionRing A K] protected theorem le_total (a b : ValueGroup A K) : a ≤ b ∨ b ≤ a := by rcases a with ⟨a⟩; rcases b with ⟨b⟩ - obtain ⟨xa, ya, hya, rfl⟩ : ∃ a b : A, _ := IsFractionRing.div_surjective a - obtain ⟨xb, yb, hyb, rfl⟩ : ∃ a b : A, _ := IsFractionRing.div_surjective b + obtain ⟨xa, ya, hya, rfl⟩ := IsFractionRing.div_surjective A a + obtain ⟨xb, yb, hyb, rfl⟩ := IsFractionRing.div_surjective A b have : (algebraMap A K) ya ≠ 0 := IsFractionRing.to_map_ne_zero_of_mem_nonZeroDivisors hya have : (algebraMap A K) yb ≠ 0 := IsFractionRing.to_map_ne_zero_of_mem_nonZeroDivisors hyb obtain ⟨c, h | h⟩ := ValuationRing.cond (xa * yb) (xb * ya) @@ -206,8 +206,8 @@ noncomputable def valuation : Valuation K (ValueGroup A K) where map_mul' _ _ := rfl map_add_le_max' := by intro a b - obtain ⟨xa, ya, hya, rfl⟩ : ∃ a b : A, _ := IsFractionRing.div_surjective a - obtain ⟨xb, yb, hyb, rfl⟩ : ∃ a b : A, _ := IsFractionRing.div_surjective b + obtain ⟨xa, ya, hya, rfl⟩ := IsFractionRing.div_surjective A a + obtain ⟨xb, yb, hyb, rfl⟩ := IsFractionRing.div_surjective A b have : (algebraMap A K) ya ≠ 0 := IsFractionRing.to_map_ne_zero_of_mem_nonZeroDivisors hya have : (algebraMap A K) yb ≠ 0 := IsFractionRing.to_map_ne_zero_of_mem_nonZeroDivisors hyb obtain ⟨c, h | h⟩ := ValuationRing.cond (xa * yb) (xb * ya) @@ -347,7 +347,7 @@ theorem iff_isInteger_or_isInteger : ValuationRing R ↔ ∀ x : K, IsLocalization.IsInteger R x ∨ IsLocalization.IsInteger R x⁻¹ := by constructor · intro H x - obtain ⟨x : R, y, hy, rfl⟩ := IsFractionRing.div_surjective (A := R) x + obtain ⟨x : R, y, hy, rfl⟩ := IsFractionRing.div_surjective R x have := (map_ne_zero_iff _ (IsFractionRing.injective R K)).mpr (nonZeroDivisors.ne_zero hy) obtain ⟨s, rfl | rfl⟩ := ValuationRing.cond x y · exact Or.inr diff --git a/Mathlib/RingTheory/ZariskisMainTheorem.lean b/Mathlib/RingTheory/ZariskisMainTheorem.lean index 6216c716ddd774..c6f90f2b32f686 100644 --- a/Mathlib/RingTheory/ZariskisMainTheorem.lean +++ b/Mathlib/RingTheory/ZariskisMainTheorem.lean @@ -138,7 +138,6 @@ section IsStronglyTranscendental variable (φ : R[X] →ₐ[R] S) (t : S) (p r : R[X]) -set_option backward.isDefEq.respectTransparency false in /-- Given a map `φ : R[X] →ₐ[R] S`. Suppose `t = φ r / φ p` is integral over `R[X]` where `p` is monic with `deg p > deg r`, then `t` is also integral over `R`. -/ lemma isIntegral_of_isIntegralElem_of_monic_of_natDegree_lt @@ -459,7 +458,6 @@ universe u variable {R S : Type u} [CommRing R] [CommRing S] [Algebra R S] -set_option backward.isDefEq.respectTransparency false in -- Subsumed by `ZariskisMainProperty.of_finiteType`. private lemma ZariskisMainProperty.of_adjoin_eq_top (p : Ideal S) [p.IsPrime] [Algebra.WeaklyQuasiFiniteAt R p] @@ -706,7 +704,6 @@ lemma QuasiFiniteAt.exists_fg_and_exists_notMem_and_awayMap_bijective ZariskisMainProperty.exists_fg_and_exists_notMem_and_awayMap_bijective _ (.of_finiteType_of_weaklyQuasiFiniteAt _) -set_option backward.isDefEq.respectTransparency false in lemma ZariskisMainProperty.quasiFiniteAt [Algebra.FiniteType R S] (p : Ideal S) [p.IsPrime] (H : ZariskisMainProperty R p) : Algebra.QuasiFiniteAt R p := by diff --git a/Mathlib/SetTheory/Cardinal/Cofinality.lean b/Mathlib/SetTheory/Cardinal/Cofinality.lean index 42c38a1fea5bc6..2b6841e25c6c6e 100644 --- a/Mathlib/SetTheory/Cardinal/Cofinality.lean +++ b/Mathlib/SetTheory/Cardinal/Cofinality.lean @@ -43,6 +43,7 @@ variable {α γ : Type u} {β : Type v} /-! ### Cofinality of orders -/ namespace Order +section Preorder variable [Preorder α] variable (α) in @@ -53,8 +54,13 @@ def cof : Cardinal := theorem cof_le {s : Set α} (h : IsCofinal s) : cof α ≤ #s := ciInf_le' (ι := {s : Set α // IsCofinal s}) _ ⟨s, h⟩ -theorem le_cof_iff {c : Cardinal} : c ≤ cof α ↔ ∀ s : Set α, IsCofinal s → c ≤ #s := - le_ciInf_iff'.trans (by simp) +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 @@ -100,6 +106,29 @@ theorem cof_eq_one_iff : cof α = 1 ↔ ∃ x : α, IsTop x := by theorem cof_eq_one [OrderTop α] : cof α = 1 := cof_eq_one_iff.2 ⟨⊤, isTop_top⟩ +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' + +end LinearOrder end Order section Congr @@ -107,10 +136,8 @@ 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 - simp_rw [Order.cof, lift_iInf, le_ciInf_iff'] - rintro ⟨s, hs⟩ - apply (csInf_le' _).trans (mk_image_le_lift (f := g)) - exact ⟨⟨g '' s, h.map_cofinal hs⟩, rfl⟩ + 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 @@ -183,11 +210,15 @@ theorem lift_cof (o : Ordinal.{u}) : Cardinal.lift.{v} (cof o) = cof (Ordinal.li rw [cof_type, ← type_lt_ulift, cof_type, ← Cardinal.lift_id'.{u, v} (Order.cof (ULift _)), ← Cardinal.lift_umax, ← ULift.orderIso.lift_cof_eq] +@[simp] +theorem cof_Iio (o : Ordinal.{u}) : Order.cof (Iio o) = cof (lift.{u + 1} o) := by + rw [← lift_cof, ← cof_toType, ← (@ToType.mk o).lift_cof_eq, Cardinal.lift_id'.{u, u + 1}] + theorem cof_le_card (o : Ordinal) : cof o ≤ card o := by - induction o using inductionOnWellOrder with | H α - simpa using cof_le_cardinalMk α + simpa using cof_le_cardinalMk o.ToType -theorem cof_ord_le (c : Cardinal) : c.ord.cof ≤ c := by simpa using cof_le_card c.ord +theorem cof_ord_le (c : Cardinal) : c.ord.cof ≤ c := by + simpa using cof_le_card c.ord theorem ord_cof_le (o : Ordinal) : o.cof.ord ≤ o := (ord_le_ord.2 (cof_le_card o)).trans (ord_card_le o) @@ -220,6 +251,41 @@ theorem cof_one : cof 1 = 1 := by theorem cof_succ (o) : cof (succ o) = 1 := cof_add_one o +theorem cof_iSup_Iio {f} (hf : StrictMono f) {a} (ha : IsSuccPrelimit a) : + cof (⨆ i : Iio a, f i.1) = cof a := by + have : StrictMono (β := Iio (⨆ i : Iio a, f i.1)) (fun i : Iio a ↦ ⟨f i, ?_⟩) := fun x y h ↦ hf h + · have := cof_congr_of_strictMono this ?_ + · simpa [← lift_cof] using this.symm + · intro ⟨b, hb⟩ + rw [mem_Iio, lt_ciSup_iff' (bddAbove_of_small _)] at hb + obtain ⟨i, hi⟩ := hb + exact ⟨_, Set.mem_range_self i, hi.le⟩ + · exact (hf (lt_add_one _)).trans_le <| + le_ciSup (ι := Iio a) (bddAbove_of_small _) ⟨_, ha.succ_lt i.2⟩ + +theorem cof_map_of_isNormal {f} (hf : IsNormal f) {a} (ha : IsSuccLimit a) : cof (f a) = cof a := by + rw [hf.apply_of_isSuccLimit ha, cof_iSup_Iio hf.strictMono ha.isSuccPrelimit] + +@[deprecated (since := "2026-03-19")] +alias cof_eq_of_isNormal := cof_map_of_isNormal + +@[deprecated (since := "2025-12-25")] +alias IsNormal.cof_eq := cof_eq_of_isNormal + +theorem le_cof_map_of_isNormal {f} (hf : IsNormal f) (a) : cof a ≤ cof (f a) := by + rcases zero_or_succ_or_isSuccLimit a with (rfl | ⟨b, rfl⟩ | ha) + · rw [cof_zero] + exact zero_le _ + · rw [cof_succ, Cardinal.one_le_iff_ne_zero, cof_eq_zero.ne, ← pos_iff_ne_zero] + exact (zero_le (f b)).trans_lt (hf.strictMono (lt_succ b)) + · rw [cof_map_of_isNormal hf ha] + +@[deprecated (since := "2026-03-19")] +alias cof_le_of_isNormal := le_cof_map_of_isNormal + +@[deprecated (since := "2025-12-25")] +alias IsNormal.cof_le := le_cof_map_of_isNormal + @[deprecated (since := "2026-02-18")] alias cof_eq_one_iff_is_succ := cof_eq_one_iff theorem ord_cof_eq (α : Type*) [LinearOrder α] [WellFoundedLT α] : @@ -253,7 +319,7 @@ theorem cof_eq_sInf_lsub (o : Ordinal.{u}) : cof o = sInf { a : Cardinal | ∃ (ι : Type u) (f : ι → Ordinal), lsub.{u, u} f = o ∧ #ι = a } := by refine le_antisymm (le_csInf (cof_lsub_def_nonempty o) ?_) (csInf_le' ?_) · rintro a ⟨ι, f, hf, rfl⟩ - rw [← type_toType o] + rw [← type_toType o, cof_type] refine (cof_le fun a => ?_).trans (@mk_le_of_injective _ _ @@ -556,30 +622,12 @@ theorem IsFundamentalSequence.of_isNormal {f : Ordinal.{u} → Ordinal.{u}} (hf @[deprecated (since := "2025-12-25")] alias IsNormal.isFundamentalSequence := IsFundamentalSequence.of_isNormal -theorem cof_eq_of_isNormal {f} (hf : IsNormal f) {a} (ha : IsSuccLimit a) : cof (f a) = cof a := - let ⟨_, hg⟩ := exists_fundamental_sequence a - ord_injective (IsFundamentalSequence.of_isNormal hf ha hg).cof_eq - -@[deprecated (since := "2025-12-25")] -alias IsNormal.cof_eq := cof_eq_of_isNormal - -theorem cof_le_of_isNormal {f} (hf : IsNormal f) (a) : cof a ≤ cof (f a) := by - rcases zero_or_succ_or_isSuccLimit a with (rfl | ⟨b, rfl⟩ | ha) - · rw [cof_zero] - exact zero_le _ - · rw [cof_succ, Cardinal.one_le_iff_ne_zero, cof_eq_zero.ne, ← pos_iff_ne_zero] - exact (zero_le (f b)).trans_lt (hf.strictMono (lt_succ b)) - · rw [cof_eq_of_isNormal hf ha] - -@[deprecated (since := "2025-12-25")] -alias IsNormal.cof_le := cof_le_of_isNormal - @[simp] theorem cof_add (a b : Ordinal) : b ≠ 0 → cof (a + b) = cof b := fun h => by rcases zero_or_succ_or_isSuccLimit b with (rfl | ⟨c, rfl⟩ | hb) · contradiction · rw [succ_eq_add_one, ← add_assoc, cof_add_one, cof_add_one] - · exact cof_eq_of_isNormal (isNormal_add_right a) hb + · exact cof_map_of_isNormal (isNormal_add_right a) hb theorem aleph0_le_cof {o} : ℵ₀ ≤ cof o ↔ IsSuccLimit o := by rcases zero_or_succ_or_isSuccLimit o with (rfl | ⟨o, rfl⟩ | l) @@ -602,11 +650,11 @@ theorem aleph0_le_cof {o} : ℵ₀ ≤ cof o ↔ IsSuccLimit o := by theorem cof_preOmega {o : Ordinal} (ho : IsSuccPrelimit o) : (preOmega o).cof = o.cof := by by_cases h : IsMin o · simp [h.eq_bot] - · exact cof_eq_of_isNormal isNormal_preOmega ⟨h, ho⟩ + · exact cof_map_of_isNormal isNormal_preOmega ⟨h, ho⟩ @[simp] theorem cof_omega {o : Ordinal} (ho : IsSuccLimit o) : (ω_ o).cof = o.cof := - cof_eq_of_isNormal isNormal_omega ho + cof_map_of_isNormal isNormal_omega ho @[simp] theorem cof_omega0 : cof ω = ℵ₀ := @@ -635,7 +683,7 @@ theorem cof_univ : cof univ.{u, v} = Cardinal.univ.{u, v} := rw [univ, ← lift_cof, ← Cardinal.lift_lift.{u + 1, v, u}, Cardinal.lift_lt, cof_type, ← Se] refine lt_of_not_ge fun h => ?_ obtain ⟨a, e⟩ := Cardinal.mem_range_lift_of_le h - refine Quotient.inductionOn a (fun α e => ?_) e + induction a using Quotient.inductionOn obtain ⟨f⟩ := Quotient.exact e have f := Equiv.ulift.symm.trans f let g a := (f a).1 diff --git a/Mathlib/SetTheory/Cardinal/Defs.lean b/Mathlib/SetTheory/Cardinal/Defs.lean index 65af241ee2ca8b..4d072f92f653b5 100644 --- a/Mathlib/SetTheory/Cardinal/Defs.lean +++ b/Mathlib/SetTheory/Cardinal/Defs.lean @@ -6,6 +6,7 @@ Authors: Johannes Hölzl, Mario Carneiro, Floris van Doorn module public import Mathlib.Data.ULift +public import Mathlib.Tactic.PPWithUniv public import Mathlib.Util.Delaborators /-! diff --git a/Mathlib/SetTheory/Cardinal/Ordinal.lean b/Mathlib/SetTheory/Cardinal/Ordinal.lean index e94b76f05ddf32..3cff87438107a9 100644 --- a/Mathlib/SetTheory/Cardinal/Ordinal.lean +++ b/Mathlib/SetTheory/Cardinal/Ordinal.lean @@ -143,52 +143,70 @@ theorem card_omega0_opow {a : Ordinal} (h : a ≠ 0) : card (ω ^ a) = max ℵ theorem card_opow_omega0 {a : Ordinal} (h : 1 < a) : card (a ^ ω) = max ℵ₀ a.card := by rw [card_opow_eq_of_omega0_le_right h le_rfl, card_omega0, max_comm] -theorem principal_opow_omega (o : Ordinal) : Principal (· ^ ·) (ω_ o) := by +theorem isPrincipal_opow_omega (o : Ordinal) : IsPrincipal (· ^ ·) (ω_ o) := by obtain rfl | ho := eq_zero_or_pos o · rw [omega_zero] - exact principal_opow_omega0 + exact isPrincipal_opow_omega0 · intro a b ha hb rw [lt_omega_iff_card_lt] at ha hb ⊢ apply (card_opow_le a b).trans_lt (max_lt _ (max_lt ha hb)) rwa [← aleph_zero, aleph_lt_aleph] -theorem IsInitial.principal_opow {o : Ordinal} (h : IsInitial o) (ho : ω ≤ o) : - Principal (· ^ ·) o := by +@[deprecated (since := "2026-03-18")] alias principal_opow_omega := isPrincipal_opow_omega + +theorem IsInitial.isPrincipal_opow {o : Ordinal} (h : IsInitial o) (ho : ω ≤ o) : + IsPrincipal (· ^ ·) o := by obtain ⟨a, rfl⟩ := mem_range_omega_iff.2 ⟨ho, h⟩ - exact principal_opow_omega a + exact isPrincipal_opow_omega a + +@[deprecated (since := "2026-03-18")] alias IsInitial.principal_opow := IsInitial.isPrincipal_opow -theorem principal_opow_ord {c : Cardinal} (hc : ℵ₀ ≤ c) : Principal (· ^ ·) c.ord := by - apply (isInitial_ord c).principal_opow +theorem isPrincipal_opow_ord {c : Cardinal} (hc : ℵ₀ ≤ c) : IsPrincipal (· ^ ·) c.ord := by + apply (isInitial_ord c).isPrincipal_opow rwa [omega0_le_ord] +@[deprecated (since := "2026-03-18")] alias principal_opow_ord := isPrincipal_opow_ord + /-! ### Initial ordinals are principal -/ -theorem principal_add_ord {c : Cardinal} (hc : ℵ₀ ≤ c) : Principal (· + ·) c.ord := by +theorem isPrincipal_add_ord {c : Cardinal} (hc : ℵ₀ ≤ c) : IsPrincipal (· + ·) c.ord := by intro a b ha hb rw [lt_ord, card_add] at * exact add_lt_of_lt hc ha hb -theorem IsInitial.principal_add {o : Ordinal} (h : IsInitial o) (ho : ω ≤ o) : - Principal (· + ·) o := by +@[deprecated (since := "2026-03-18")] alias principal_add_ord := isPrincipal_add_ord + +theorem IsInitial.isPrincipal_add {o : Ordinal} (h : IsInitial o) (ho : ω ≤ o) : + IsPrincipal (· + ·) o := by rw [← h.ord_card] - apply principal_add_ord + apply isPrincipal_add_ord rwa [aleph0_le_card] -theorem principal_add_omega (o : Ordinal) : Principal (· + ·) (ω_ o) := - (isInitial_omega o).principal_add (omega0_le_omega o) +@[deprecated (since := "2026-03-18")] alias IsInitial.principal_add := IsInitial.isPrincipal_add + +theorem isPrincipal_add_omega (o : Ordinal) : IsPrincipal (· + ·) (ω_ o) := + (isInitial_omega o).isPrincipal_add (omega0_le_omega o) -theorem principal_mul_ord {c : Cardinal} (hc : ℵ₀ ≤ c) : Principal (· * ·) c.ord := by +@[deprecated (since := "2026-03-18")] alias principal_add_omega := isPrincipal_add_omega + +theorem isPrincipal_mul_ord {c : Cardinal} (hc : ℵ₀ ≤ c) : IsPrincipal (· * ·) c.ord := by intro a b ha hb rw [lt_ord, card_mul] at * exact mul_lt_of_lt hc ha hb -theorem IsInitial.principal_mul {o : Ordinal} (h : IsInitial o) (ho : ω ≤ o) : - Principal (· * ·) o := by +@[deprecated (since := "2026-03-18")] alias principal_mul_ord := isPrincipal_mul_ord + +theorem IsInitial.isPrincipal_mul {o : Ordinal} (h : IsInitial o) (ho : ω ≤ o) : + IsPrincipal (· * ·) o := by rw [← h.ord_card] - apply principal_mul_ord + apply isPrincipal_mul_ord rwa [aleph0_le_card] -theorem principal_mul_omega (o : Ordinal) : Principal (· * ·) (ω_ o) := - (isInitial_omega o).principal_mul (omega0_le_omega o) +@[deprecated (since := "2026-03-18")] alias IsInitial.principal_mul := IsInitial.isPrincipal_mul + +theorem isPrincipal_mul_omega (o : Ordinal) : IsPrincipal (· * ·) (ω_ o) := + (isInitial_omega o).isPrincipal_mul (omega0_le_omega o) + +@[deprecated (since := "2026-03-18")] alias principal_mul_omega := isPrincipal_mul_omega end Ordinal diff --git a/Mathlib/SetTheory/Cardinal/ToNat.lean b/Mathlib/SetTheory/Cardinal/ToNat.lean index 83949ba3d507c5..987a4065a410ce 100644 --- a/Mathlib/SetTheory/Cardinal/ToNat.lean +++ b/Mathlib/SetTheory/Cardinal/ToNat.lean @@ -160,4 +160,14 @@ lemma natCast_toNat_le (a : Cardinal) : (toNat a : Cardinal) ≤ a := by · simp [cast_toNat_of_lt_aleph0 h] · simp [Cardinal.toNat_apply_of_aleph0_le h] +lemma toNat_le_iff_of_lt_aleph0 {a : Cardinal.{u}} (n : ℕ) (lt : a < Cardinal.aleph0) : + a.toNat ≤ n ↔ a ≤ n := by + nth_rw 1 [← Cardinal.toNat_natCast.{u} n, + Cardinal.toNat_le_iff_le_of_lt_aleph0 lt (Cardinal.natCast_lt_aleph0)] + +lemma toNat_eq_iff_of_lt_aleph0 {a : Cardinal.{u}} (n : ℕ) (lt : a < Cardinal.aleph0) : + a.toNat = n ↔ a = n := by + nth_rw 2 [← Cardinal.cast_toNat_of_lt_aleph0 lt] + exact Nat.cast_inj.symm + end Cardinal diff --git a/Mathlib/SetTheory/Ordinal/Arithmetic.lean b/Mathlib/SetTheory/Ordinal/Arithmetic.lean index 2becb7ca0ecdf3..4008e9b309788c 100644 --- a/Mathlib/SetTheory/Ordinal/Arithmetic.lean +++ b/Mathlib/SetTheory/Ordinal/Arithmetic.lean @@ -13,29 +13,27 @@ public import Mathlib.SetTheory.Ordinal.Basic /-! # Ordinal arithmetic -Ordinals have an addition (corresponding to disjoint union) that turns them into an additive +Ordinals have an addition (corresponding to the disjoint union) that turns them into an additive monoid, and a multiplication (corresponding to the lexicographic order on the product) that turns -them into a monoid. One can also define correspondingly a subtraction, a division, a successor -function, a power function and a logarithm function. +them into a monoid. One can also define (truncated) subtraction and division operators. -We also define limit ordinals and prove the basic induction principle on ordinals separating -successor ordinals and limit ordinals, in `limitRecOn`. +Ordinal powers and logarithms are defined in `Mathlib.SetTheory.Ordinal.Exponential`. ## Main definitions and results -* `o₁ + o₂` is the order on the disjoint union of `o₁` and `o₂` obtained by declaring that - every element of `o₁` is smaller than every element of `o₂`. -* `o₁ - o₂` is the unique ordinal `o` such that `o₂ + o = o₁`, when `o₂ ≤ o₁`. -* `o₁ * o₂` is the lexicographic order on `o₂ × o₁`. -* `o₁ / o₂` is the ordinal `o` such that `o₁ = o₂ * o + o'` with `o' < o₂`. We also define the +* `a + b` is the order type of the lexicographic sum `a ⊕ₗ b`. +* `a - b` is the unique ordinal `c` such that `b + c = a`, when `b ≤ a`. +* `a * b` is the order type of the lexicographic product `b ×ₗ a`. +* `a / b` is the ordinal `q` such that `a = b * q + r` with `r < b`. We also define the divisibility predicate, and a modulo operation. -* `limitRecOn` is the main induction principle of ordinals: if one can prove a property by - induction at successor ordinals and at limit ordinals, then it holds for all ordinals. +* `limitRecOn` is limit recursion on ordinals, i.e. well-founded recursion separating out the zero, + successor, and limit cases. We discuss the properties of casts of natural numbers of and of `ω` with respect to these operations. -Note that some basic functions and properties of ordinals have been generalized to other orders: +Note that some basic functions and properties of ordinals have been generalized to other orders, and +exist on other files: * `Order.succ o = o + 1` is the successor of `o`. * `Order.IsSuccLimit o`: an ordinal is a limit ordinal if it is neither `0` nor a successor. @@ -46,14 +44,11 @@ Note that some basic functions and properties of ordinals have been generalized Various other basic arithmetic results are given in `Principal.lean` instead. -/ -@[expose] public section +@[expose] public noncomputable section assert_not_exists Field Module -noncomputable section - open Function Cardinal Set Equiv Order -open scoped Ordinal universe u v w @@ -252,8 +247,9 @@ theorem bounded_singleton {r : α → α → Prop} [IsWellOrder α r] (hr : IsSu @[simp] theorem typein_ordinal (o : Ordinal.{u}) : @typein Ordinal (· < ·) _ o = Ordinal.lift.{u + 1} o := by - refine Quotient.inductionOn o ?_ - rintro ⟨α, r, wo⟩; apply Quotient.sound + induction o using Quotient.inductionOn with | _ w + obtain ⟨α, r, wo⟩ := w + apply Quotient.sound constructor; refine ((RelIso.preimage Equiv.ulift r).trans (enum r).symm).symm theorem mk_Iio_ordinal (o : Ordinal.{u}) : @@ -263,7 +259,7 @@ theorem mk_Iio_ordinal (o : Ordinal.{u}) : /-! ### The predecessor of an ordinal -/ -/-- The ordinal predecessor of `o` is `o'` if `o = succ o'`, and `o` otherwise. -/ +/-- The ordinal predecessor of `a` is `b` if `a = succ b`, and `a` otherwise. -/ def pred (o : Ordinal) : Ordinal := isSuccPrelimitRecOn o (fun a _ ↦ a) (fun a _ ↦ a) @@ -536,8 +532,8 @@ theorem isSuccLimit_sub {a b : Ordinal} (ha : IsSuccPrelimit a) (h : b < a) : /-! ### Multiplication of ordinals -/ -/-- The multiplication of ordinals `o₁` and `o₂` is the (well-founded) lexicographic order on -`o₂ × o₁`. -/ +/-- The multiplication of ordinals `a` and `b` is the order type of the lexicographic order on +`b × a`. -/ instance monoid : Monoid Ordinal.{u} where mul a b := Quotient.liftOn₂ a b diff --git a/Mathlib/SetTheory/Ordinal/Basic.lean b/Mathlib/SetTheory/Ordinal/Basic.lean index aa432515b8e794..0924a79c980b65 100644 --- a/Mathlib/SetTheory/Ordinal/Basic.lean +++ b/Mathlib/SetTheory/Ordinal/Basic.lean @@ -106,7 +106,7 @@ def Ordinal : Type (u + 1) := Quotient Ordinal.isEquivalent /-- A "canonical" type order-isomorphic to the ordinal `o`, living in the same universe. This is -defined through the axiom of choice. +defined through the axiom of choice; in particular, it has no useful def-eqs, and it is not exposed. Use this over `Iio o` only when it is paramount to have a `Type u` rather than a `Type (u + 1)`, and convert using @@ -116,23 +116,26 @@ Ordinal.ToType.mk : Iio o → o.ToType Ordinal.ToType.toOrd : o.ToType → Iio o ``` -/ +@[no_expose] def Ordinal.ToType (o : Ordinal.{u}) : Type u := o.out.α @[deprecated (since := "2025-12-04")] alias Ordinal.toType := Ordinal.ToType -instance hasWellFounded_toType (o : Ordinal) : WellFoundedRelation o.ToType := - ⟨o.out.r, o.out.wo.wf⟩ - +@[no_expose] instance linearOrder_toType (o : Ordinal) : LinearOrder o.ToType := @IsWellOrder.linearOrder _ o.out.r o.out.wo instance wellFoundedLT_toType (o : Ordinal) : WellFoundedLT o.ToType := o.out.wo.toIsWellFounded +instance hasWellFounded_toType (o : Ordinal) : WellFoundedRelation o.ToType := + WellFoundedLT.toWellFoundedRelation + namespace Ordinal +@[no_expose] noncomputable instance (o : Ordinal) : SuccOrder o.ToType := .ofLinearWellFoundedLT _ @@ -612,7 +615,7 @@ theorem card_one : card 1 = 1 := mk_eq_one _ variable (r) in /-- The cardinality of a set is an upper-bound for the cardinality of the order type of the set's -mex (minimum excluded value) -/ +mex (minimum excluded value). See `not_lt_enum_ord_mk_min_compl` for the `α` version. -/ theorem card_typein_min_le_mk [IsWellOrder α r] {s : Set α} (hs : sᶜ.Nonempty) : (typein r <| IsWellFounded.wf.min (r := r) sᶜ hs).card ≤ #s := IsWellFounded.wf.cardinalMk_subtype_lt_min_compl_le hs @@ -1077,6 +1080,7 @@ theorem mk_toType (o : Ordinal) : #o.ToType = o.card := /-- The ordinal corresponding to a cardinal `c` is the least ordinal whose cardinal is `c`. For the order-embedding version, see `ord.order_embedding`. -/ +@[no_expose] def ord (c : Cardinal) : Ordinal := Quot.liftOn c (fun α : Type u => ⨅ r : { r // IsWellOrder α r }, @type α r.1 r.2) <| by rintro α β ⟨f⟩ @@ -1085,8 +1089,10 @@ def ord (c : Cardinal) : Ordinal := refine ⟨⟨_, RelIso.IsWellOrder.preimage r ?_⟩, type_preimage _ _⟩ exacts [f.symm, f] -theorem ord_eq_Inf (α : Type u) : ord #α = ⨅ r : { r // IsWellOrder α r }, @type α r.1 r.2 := - rfl +theorem ord_eq_iInf (α : Type u) : ord #α = ⨅ r : { r // IsWellOrder α r }, @type α r.1 r.2 := + (rfl) + +@[deprecated (since := "2026-03-15")] alias ord_eq_Inf := ord_eq_iInf /-- There exists a well-order on `α` whose order type is exactly `ord #α`. -/ theorem ord_eq (α) : ∃ (r : α → α → Prop) (wo : IsWellOrder α r), ord #α = @type α r wo := @@ -1438,12 +1444,33 @@ theorem card_eq_ofNat {o} {n : ℕ} [n.AtLeastTwo] : card o = ofNat(n) ↔ o = OfNat.ofNat n := card_eq_nat +variable (r) in @[simp] -theorem type_fintype (r : α → α → Prop) [IsWellOrder α r] [Fintype α] : +theorem type_fintype [IsWellOrder α r] [Fintype α] : type r = Fintype.card α := by rw [← card_eq_nat, card_type, mk_fintype] theorem type_fin (n : ℕ) : typeLT (Fin n) = n := by simp +variable (r) in +theorem ord_mk_le_type [IsWellOrder α r] (s : Set α) : (#s).ord ≤ type r := by + grw [← ord_le_type, ord_le_ord, le_mk_iff_exists_set] + use s + +variable (r) in +theorem ord_mk_lt_type [IsWellOrder α r] {s : Set α} (hfin : s.Finite) (h : sᶜ.Nonempty) : + (#s).ord < type r := by + grw [← ord_le_type, ord_lt_ord, ← mk_univ (α := α)] + exact card_lt_card_of_left_finite hfin h.ssubset_univ + +variable (r) in +/-- The `#s`-th element of `α` is an upper-bound for the set's mex (minimum excluded value), +ordered by `r`, when `s` is finite. See `card_typein_min_le_mk` for the `Ordinal` version. -/ +theorem not_lt_enum_ord_mk_min_compl [IsWellOrder α r] {s : Set α} (hfin : s.Finite) + (h : sᶜ.Nonempty) : + ¬r (enum r ⟨#s |>.ord, ord_mk_lt_type r hfin h⟩) (IsWellFounded.wf.min (r := r) sᶜ h) := by + grw [← typein_le_typein, typein_enum, Cardinal.le_ord_iff_card_le_of_lt_aleph0 _ hfin.lt_aleph0, + card_typein_min_le_mk] + end Ordinal /-! ### Sorted lists -/ diff --git a/Mathlib/SetTheory/Ordinal/Exponential.lean b/Mathlib/SetTheory/Ordinal/Exponential.lean index 71dbc58d0752b5..5f625b798aae6a 100644 --- a/Mathlib/SetTheory/Ordinal/Exponential.lean +++ b/Mathlib/SetTheory/Ordinal/Exponential.lean @@ -15,9 +15,7 @@ related by the lemma `Ordinal.opow_le_iff_le_log : b ^ c ≤ x ↔ c ≤ log b x `b`, `c`. -/ -@[expose] public section - -noncomputable section +public noncomputable section open Function Set Equiv Order open scoped Cardinal Ordinal @@ -29,6 +27,7 @@ namespace Ordinal /-- The ordinal exponential, defined by transfinite recursion. We call this `opow` in theorems in order to disambiguate from other exponentials. -/ +@[no_expose] instance instPow : Pow Ordinal Ordinal := ⟨fun a b ↦ if a = 0 then 1 - b else limitRecOn b 1 (fun _ x ↦ x * a) fun o _ f ↦ ⨆ x : Iio o, f x.1 x.2⟩ diff --git a/Mathlib/SetTheory/Ordinal/Notation.lean b/Mathlib/SetTheory/Ordinal/Notation.lean index 37a11941333e46..975447cddd6bc8 100644 --- a/Mathlib/SetTheory/Ordinal/Notation.lean +++ b/Mathlib/SetTheory/Ordinal/Notation.lean @@ -716,7 +716,7 @@ theorem split_add_lt {o e n a m} [NF o] (h : split o = (oadd e n a, m)) : repr a + m < ω ^ repr e := by obtain ⟨h₁, h₂⟩ := nf_repr_split h obtain ⟨e0, d⟩ := h₁.of_dvd_omega0 (split_dvd h) - apply principal_add_omega0_opow _ h₁.snd'.repr_lt (lt_of_lt_of_le (natCast_lt_omega0 _) _) + apply isPrincipal_add_omega0_opow _ h₁.snd'.repr_lt (lt_of_lt_of_le (natCast_lt_omega0 _) _) simpa using opow_le_opow_right omega0_pos (one_le_iff_ne_zero.2 e0) @[simp] @@ -783,7 +783,7 @@ theorem repr_opow_aux₁ {e a} [Ne : NF e] [Na : NF a] {a' : Ordinal} (e0 : repr · exact omega0_pos · exact succ_le_iff.2 <| by gcongr; exact isSuccLimit_omega0.succ_lt l · exact omega0_pos - · grw [show _ * _ < _ from principal_mul_omega0 (isSuccLimit_omega0.succ_lt h) l] + · grw [show _ * _ < _ from isPrincipal_mul_omega0 (isSuccLimit_omega0.succ_lt h) l] · simpa using mul_le_mul_left (one_le_iff_ne_zero.2 e0) ω · exact omega0_pos @@ -828,7 +828,7 @@ theorem repr_opow_aux₂ {a0 a'} [N0 : NF a0] [Na' : NF a'] (m : ℕ) (d : ω · rw [RR, ← opow_mul _ _ (succ k.succ)] have e0 := pos_iff_ne_zero.2 e0 have rr0 : 0 < repr a0 + repr a0 := lt_of_lt_of_le e0 le_add_self - apply principal_add_omega0_opow + apply isPrincipal_add_omega0_opow · simp only [Nat.cast_add_one, opow_add_one, opow_mul, opow_succ, mul_assoc] gcongr ?_ * ?_ rw [← Ordinal.opow_add] @@ -855,7 +855,7 @@ theorem repr_opow_aux₂ {a0 a'} [N0 : NF a0] [Na' : NF a'] (m : ℕ) (d : ω add_mul_of_isSuccLimit _ ⟨α0, isSuccPrelimit_iff_omega0_dvd.2 αd⟩, mul_assoc, @mul_omega0_dvd n (Nat.cast_pos'.2 n.pos) (natCast_lt_omega0 _) _ αd] apply @add_absorp _ (repr a0 * succ ↑k) - · refine principal_add_omega0_opow _ ?_ Rl + · refine isPrincipal_add_omega0_opow _ ?_ Rl rw [opow_mul, opow_succ] gcongr exact No.snd'.repr_lt diff --git a/Mathlib/SetTheory/Ordinal/Principal.lean b/Mathlib/SetTheory/Ordinal/Principal.lean index 892111754c0106..a95c3d89d8d9af 100644 --- a/Mathlib/SetTheory/Ordinal/Principal.lean +++ b/Mathlib/SetTheory/Ordinal/Principal.lean @@ -14,12 +14,12 @@ We define principal or indecomposable ordinals, and we prove the standard proper ## Main definitions and results -* `Principal`: A principal or indecomposable ordinal under some binary operation. We include 0 and +* `IsPrincipal`: A principal or indecomposable ordinal under some binary operation. We include 0 and any other typically excluded edge cases for simplicity. -* `not_bddAbove_principal`: Principal ordinals (under any operation) are unbounded. -* `principal_add_iff_zero_or_omega0_opow`: The main characterization theorem for additive principal - ordinals. -* `principal_mul_iff_le_two_or_omega0_opow_opow`: The main characterization theorem for +* `not_bddAbove_setOf_isPrincipal`: Principal ordinals (under any operation) are unbounded. +* `isPrincipal_add_iff_zero_or_omega0_opow`: The main characterization theorem for additive + principal ordinals. +* `isPrincipal_mul_iff_le_two_or_omega0_opow_opow`: The main characterization theorem for multiplicative principal ordinals. ## TODO @@ -49,76 +49,113 @@ ordinals less than it is closed under that operation. In standard mathematical u almost exclusively used for additive and multiplicative principal ordinals. For simplicity, we break usual convention and regard `0` as principal. -/ -def Principal (op : Ordinal → Ordinal → Ordinal) (o : Ordinal) : Prop := +def IsPrincipal (op : Ordinal → Ordinal → Ordinal) (o : Ordinal) : Prop := ∀ ⦃a b⦄, a < o → b < o → op a b < o -theorem principal_swap_iff : Principal (Function.swap op) o ↔ Principal op o := by +@[deprecated (since := "2026-03-17")] +alias Principal := IsPrincipal + +theorem isPrincipal_swap_iff : IsPrincipal (Function.swap op) o ↔ IsPrincipal op o := by constructor <;> exact fun h a b ha hb => h hb ha -theorem not_principal_iff : ¬ Principal op o ↔ ∃ a < o, ∃ b < o, o ≤ op a b := by - simp [Principal] +@[deprecated (since := "2026-03-17")] +alias principal_swap_iff := isPrincipal_swap_iff + +theorem not_isPrincipal_iff : ¬ IsPrincipal op o ↔ ∃ a < o, ∃ b < o, o ≤ op a b := by + simp [IsPrincipal] + +@[deprecated (since := "2026-03-17")] +alias not_principal_iff := not_isPrincipal_iff -theorem principal_iff_of_monotone +theorem isPrincipal_iff_of_monotone (h₁ : ∀ a, Monotone (op a)) (h₂ : ∀ a, Monotone (Function.swap op a)) : - Principal op o ↔ ∀ a < o, op a a < o := by + IsPrincipal op o ↔ ∀ a < o, op a a < o := by use fun h a ha => h ha ha intro H a b ha hb obtain hab | hba := le_or_gt a b · exact (h₂ b hab).trans_lt <| H b hb · exact (h₁ a hba.le).trans_lt <| H a ha -theorem not_principal_iff_of_monotone +@[deprecated (since := "2026-03-17")] +alias principal_iff_of_monotone := isPrincipal_iff_of_monotone + +theorem not_isPrincipal_iff_of_monotone (h₁ : ∀ a, Monotone (op a)) (h₂ : ∀ a, Monotone (Function.swap op a)) : - ¬ Principal op o ↔ ∃ a < o, o ≤ op a a := by - simp [principal_iff_of_monotone h₁ h₂] + ¬ IsPrincipal op o ↔ ∃ a < o, o ≤ op a a := by + simp [isPrincipal_iff_of_monotone h₁ h₂] + +@[deprecated (since := "2026-03-17")] +alias not_principal_iff_of_monotone := not_isPrincipal_iff_of_monotone -@[simp] lemma principal_zero : Principal op 0 := by simp [Principal] +@[simp] lemma isPrincipal_zero : IsPrincipal op 0 := by simp [IsPrincipal] + +@[deprecated (since := "2026-03-17")] +alias principal_zero := isPrincipal_zero @[simp] -theorem principal_one_iff : Principal op 1 ↔ op 0 0 = 0 := by +theorem isPrincipal_one_iff : IsPrincipal op 1 ↔ op 0 0 = 0 := by refine ⟨fun h => ?_, fun h a b ha hb => ?_⟩ · rw [← lt_one_iff_zero] exact h zero_lt_one zero_lt_one · rwa [lt_one_iff_zero, ha, hb] at * -theorem Principal.iterate_lt (hao : a < o) (ho : Principal op o) (n : ℕ) : (op a)^[n] a < o := by +@[deprecated (since := "2026-03-17")] +alias principal_one_iff := isPrincipal_one_iff + +theorem IsPrincipal.iterate_lt (hao : a < o) (ho : IsPrincipal op o) (n : ℕ) : + (op a)^[n] a < o := by induction n with | zero => rwa [Function.iterate_zero] | succ n hn => rw [Function.iterate_succ'] exact ho hao hn -theorem op_eq_self_of_principal (hao : a < o) (H : IsNormal (op a)) - (ho : Principal op o) (ho' : IsSuccLimit o) : op a o = o := by +@[deprecated (since := "2026-03-17")] +alias Principal.iterate_lt := IsPrincipal.iterate_lt + +theorem op_eq_self_of_isPrincipal (hao : a < o) (H : IsNormal (op a)) + (ho : IsPrincipal op o) (ho' : IsSuccLimit o) : op a o = o := by apply H.strictMono.le_apply.antisymm' rw [H.apply_of_isSuccLimit ho', Ordinal.iSup_le_iff] exact fun ⟨b, hbo⟩ ↦ (ho hao hbo).le -theorem nfp_le_of_principal (hao : a < o) (ho : Principal op o) : nfp (op a) a ≤ o := +@[deprecated (since := "2026-03-17")] +alias op_eq_self_of_principal := op_eq_self_of_isPrincipal + +theorem nfp_le_of_isPrincipal (hao : a < o) (ho : IsPrincipal op o) : nfp (op a) a ≤ o := nfp_le fun n => (ho.iterate_lt hao n).le -protected theorem Principal.sSup {s : Set Ordinal} (H : ∀ x ∈ s, Principal op x) : - Principal op (sSup s) := by - have : Principal op (sSup ∅) := by simp +@[deprecated (since := "2026-03-17")] +alias nfp_le_of_principal := nfp_le_of_isPrincipal + +protected theorem IsPrincipal.sSup {s : Set Ordinal} (H : ∀ x ∈ s, IsPrincipal op x) : + IsPrincipal op (sSup s) := by + have : IsPrincipal op (sSup ∅) := by simp by_cases hs : BddAbove s · obtain rfl | hs' := s.eq_empty_or_nonempty · assumption - simp only [Principal, lt_csSup_iff hs hs', forall_exists_index, and_imp] + simp only [IsPrincipal, lt_csSup_iff hs hs', forall_exists_index, and_imp] intro x y a has ha b hbs hb have h : max a b ∈ s := max_rec' _ has hbs exact ⟨_, h, H (max a b) h (lt_max_of_lt_left ha) (lt_max_of_lt_right hb)⟩ · rwa [csSup_of_not_bddAbove hs] -protected theorem Principal.iSup {ι} {f : ι → Ordinal} (H : ∀ i, Principal op (f i)) : - Principal op (⨆ i, f i) := Principal.sSup (by simpa) +@[deprecated (since := "2026-03-17")] +protected alias Principal.sSup := IsPrincipal.sSup + +protected theorem IsPrincipal.iSup {ι} {f : ι → Ordinal} (H : ∀ i, IsPrincipal op (f i)) : + IsPrincipal op (⨆ i, f i) := IsPrincipal.sSup (by simpa) + +@[deprecated (since := "2026-03-17")] +protected alias Principal.iSup := IsPrincipal.iSup end Arbitrary /-! ### Principal ordinals are unbounded -/ /-- We give an explicit construction for a principal ordinal larger or equal than `o`. -/ -private theorem principal_nfp_iSup (op : Ordinal → Ordinal → Ordinal) (o : Ordinal) : - Principal op (nfp (fun x ↦ ⨆ y : Set.Iio x ×ˢ Set.Iio x, succ (op y.1.1 y.1.2)) o) := by +private theorem isPrincipal_nfp_iSup (op : Ordinal → Ordinal → Ordinal) (o : Ordinal) : + IsPrincipal op (nfp (fun x ↦ ⨆ y : Set.Iio x ×ˢ Set.Iio x, succ (op y.1.1 y.1.2)) o) := by intro a b ha hb rw [lt_nfp_iff] at * obtain ⟨m, ha⟩ := ha @@ -138,30 +175,43 @@ private theorem principal_nfp_iSup (op : Ordinal → Ordinal → Ordinal) (o : O ⟨_, Set.mk_mem_prod ha (hb.trans_le h)⟩ /-- Principal ordinals under any operation are unbounded. -/ -theorem not_bddAbove_principal (op : Ordinal → Ordinal → Ordinal) : - ¬ BddAbove { o | Principal op o } := by +theorem not_bddAbove_setOf_isPrincipal (op : Ordinal → Ordinal → Ordinal) : + ¬ BddAbove { o | IsPrincipal op o } := by rintro ⟨a, ha⟩ - exact ((le_nfp _ _).trans (ha (principal_nfp_iSup op (succ a)))).not_gt (lt_succ a) + exact ((le_nfp _ _).trans (ha (isPrincipal_nfp_iSup op (succ a)))).not_gt (lt_succ a) + +@[deprecated (since := "2026-03-17")] +alias not_bddAbove_principal := not_bddAbove_setOf_isPrincipal /-! #### Additive principal ordinals -/ -theorem principal_add_one : Principal (· + ·) 1 := - principal_one_iff.2 <| zero_add 0 +theorem isPrincipal_add_one : IsPrincipal (· + ·) 1 := + isPrincipal_one_iff.2 <| zero_add 0 + +@[deprecated (since := "2026-03-17")] +alias principal_add_one := isPrincipal_add_one -theorem principal_add_of_le_one (ho : o ≤ 1) : Principal (· + ·) o := by +theorem isPrincipal_add_of_le_one (ho : o ≤ 1) : IsPrincipal (· + ·) o := by rcases le_one_iff.1 ho with (rfl | rfl) - · exact principal_zero - · exact principal_add_one + · exact isPrincipal_zero + · exact isPrincipal_add_one -theorem isSuccLimit_of_principal_add (ho₁ : 1 < o) (ho : Principal (· + ·) o) : IsSuccLimit o := by +@[deprecated (since := "2026-03-17")] +alias principal_add_of_le_one := isPrincipal_add_of_le_one + +theorem isSuccLimit_of_isPrincipal_add (ho₁ : 1 < o) (ho : IsPrincipal (· + ·) o) : + IsSuccLimit o := by rw [isSuccLimit_iff, isSuccPrelimit_iff_succ_lt] exact ⟨ho₁.ne_bot, fun _ ha ↦ ho ha ho₁⟩ -theorem principal_add_iff_add_left_eq_self : Principal (· + ·) o ↔ ∀ a < o, a + o = o := by +@[deprecated (since := "2026-03-17")] +alias isSuccLimit_of_principal_add := isSuccLimit_of_isPrincipal_add + +theorem isPrincipal_add_iff_add_left_eq_self : IsPrincipal (· + ·) o ↔ ∀ a < o, a + o = o := by refine ⟨fun ho a hao => ?_, fun h a b hao hbo => ?_⟩ · rcases lt_or_ge 1 o with ho₁ | ho₁ - · exact op_eq_self_of_principal hao (isNormal_add_right a) ho - (isSuccLimit_of_principal_add ho₁ ho) + · exact op_eq_self_of_isPrincipal hao (isNormal_add_right a) ho + (isSuccLimit_of_isPrincipal_add ho₁ ho) · rcases le_one_iff.1 ho₁ with (rfl | rfl) · exact (not_lt_zero hao).elim · rw [lt_one_iff_zero] at hao @@ -169,23 +219,35 @@ theorem principal_add_iff_add_left_eq_self : Principal (· + ·) o ↔ ∀ a < o · rw [← h a hao] exact (isNormal_add_right a).strictMono hbo -theorem exists_lt_add_of_not_principal_add (ha : ¬ Principal (· + ·) a) : +@[deprecated (since := "2026-03-17")] +alias principal_add_iff_add_left_eq_self := isPrincipal_add_iff_add_left_eq_self + +theorem exists_lt_add_of_not_isPrincipal_add (ha : ¬ IsPrincipal (· + ·) a) : ∃ b < a, ∃ c < a, b + c = a := by - rw [not_principal_iff] at ha + rw [not_isPrincipal_iff] at ha rcases ha with ⟨b, hb, c, hc, H⟩ refine ⟨b, hb, _, lt_of_le_of_ne (sub_le_self a b) fun hab => ?_, Ordinal.add_sub_cancel_of_le hb.le⟩ rw [← sub_le, hab] at H exact H.not_gt hc -theorem principal_add_iff_add_lt_ne_self : Principal (· + ·) a ↔ ∀ b < a, ∀ c < a, b + c ≠ a := +@[deprecated (since := "2026-03-17")] +alias exists_lt_add_of_not_principal_add := exists_lt_add_of_not_isPrincipal_add + +theorem isPrincipal_add_iff_add_lt_ne_self : IsPrincipal (· + ·) a ↔ ∀ b < a, ∀ c < a, b + c ≠ a := ⟨fun ha _ hb _ hc => (ha hb hc).ne, fun H => by by_contra ha - rcases exists_lt_add_of_not_principal_add ha with ⟨b, hb, c, hc, rfl⟩ + rcases exists_lt_add_of_not_isPrincipal_add ha with ⟨b, hb, c, hc, rfl⟩ exact (H b hb c hc).irrefl⟩ -theorem principal_add_omega0 : Principal (· + ·) ω := - principal_add_iff_add_left_eq_self.2 fun _ => add_omega0 +@[deprecated (since := "2026-03-17")] +alias principal_add_iff_add_lt_ne_self := isPrincipal_add_iff_add_lt_ne_self + +theorem isPrincipal_add_omega0 : IsPrincipal (· + ·) ω := + isPrincipal_add_iff_add_left_eq_self.2 fun _ => add_omega0 + +@[deprecated (since := "2026-03-17")] +alias principal_add_omega0 := isPrincipal_add_omega0 theorem add_omega0_opow (h : a < ω ^ b) : a + ω ^ b = ω ^ b := by refine le_antisymm ?_ le_add_self @@ -205,15 +267,18 @@ theorem add_omega0_opow (h : a < ω ^ b) : a + ω ^ b = ω ^ b := by _ ≤ ω ^ b := opow_le_opow_right omega0_pos <| (max_lt xb yb).le -theorem principal_add_omega0_opow (o : Ordinal) : Principal (· + ·) (ω ^ o) := - principal_add_iff_add_left_eq_self.2 fun _ => add_omega0_opow +theorem isPrincipal_add_omega0_opow (o : Ordinal) : IsPrincipal (· + ·) (ω ^ o) := + isPrincipal_add_iff_add_left_eq_self.2 fun _ => add_omega0_opow + +@[deprecated (since := "2026-03-17")] +alias principal_add_omega0_opow := isPrincipal_add_omega0_opow /-- The main characterization theorem for additive principal ordinals. -/ -theorem principal_add_iff_zero_or_omega0_opow : - Principal (· + ·) o ↔ o = 0 ∨ o ∈ Set.range (ω ^ · : Ordinal → Ordinal) := by +theorem isPrincipal_add_iff_zero_or_omega0_opow : + IsPrincipal (· + ·) o ↔ o = 0 ∨ o ∈ Set.range (ω ^ · : Ordinal → Ordinal) := by rcases eq_or_ne o 0 with (rfl | ho) - · simp only [principal_zero, Or.inl] - · rw [principal_add_iff_add_left_eq_self] + · simp only [isPrincipal_zero, Or.inl] + · rw [isPrincipal_add_iff_add_left_eq_self] simp only [ho, false_or] refine ⟨fun H => ⟨_, ((lt_or_eq_of_le (opow_log_le_self _ ho)).resolve_left fun h => ?_)⟩, @@ -232,73 +297,98 @@ theorem principal_add_iff_zero_or_omega0_opow : | zero => simp [Nat.cast_zero, mul_zero, zero_add] | succ n IH => simp only [Nat.cast_succ, mul_add_one, add_assoc, this, IH] -theorem principal_add_opow_of_principal_add {a} (ha : Principal (· + ·) a) (b : Ordinal) : - Principal (· + ·) (a ^ b) := by - rcases principal_add_iff_zero_or_omega0_opow.1 ha with (rfl | ⟨c, rfl⟩) +@[deprecated (since := "2026-03-17")] +alias principal_add_iff_zero_or_omega0_opow := isPrincipal_add_iff_zero_or_omega0_opow + +theorem isPrincipal_add_opow_of_isPrincipal_add {a} (ha : IsPrincipal (· + ·) a) (b : Ordinal) : + IsPrincipal (· + ·) (a ^ b) := by + rcases isPrincipal_add_iff_zero_or_omega0_opow.1 ha with (rfl | ⟨c, rfl⟩) · rcases eq_or_ne b 0 with (rfl | hb) · rw [opow_zero] - exact principal_add_one + exact isPrincipal_add_one · rwa [zero_opow hb] · rw [← opow_mul] - exact principal_add_omega0_opow _ + exact isPrincipal_add_omega0_opow _ + +@[deprecated (since := "2026-03-17")] +alias principal_add_opow_of_principal_add := isPrincipal_add_opow_of_isPrincipal_add theorem add_absorp (h₁ : a < ω ^ b) (h₂ : ω ^ b ≤ c) : a + c = c := by rw [← Ordinal.add_sub_cancel_of_le h₂, ← add_assoc, add_omega0_opow h₁] -theorem principal_add_mul_of_principal_add (a : Ordinal.{u}) {b : Ordinal.{u}} (hb₁ : b ≠ 1) - (hb : Principal (· + ·) b) : Principal (· + ·) (a * b) := by +theorem isPrincipal_add_mul_of_isPrincipal_add (a : Ordinal.{u}) {b : Ordinal.{u}} (hb₁ : b ≠ 1) + (hb : IsPrincipal (· + ·) b) : IsPrincipal (· + ·) (a * b) := by rcases eq_zero_or_pos a with (rfl | _) · rw [zero_mul] - exact principal_zero + exact isPrincipal_zero · rcases eq_zero_or_pos b with (rfl | hb₁') · rw [mul_zero] - exact principal_zero + exact isPrincipal_zero · rw [← one_le_iff_pos] at hb₁' intro c d hc hd rw [lt_mul_iff_of_isSuccLimit - (isSuccLimit_of_principal_add (lt_of_le_of_ne hb₁' hb₁.symm) hb)] at * + (isSuccLimit_of_isPrincipal_add (lt_of_le_of_ne hb₁' hb₁.symm) hb)] at * rcases hc with ⟨x, hx, hx'⟩ rcases hd with ⟨y, hy, hy'⟩ use x + y, hb hx hy rw [mul_add] exact Left.add_lt_add hx' hy' +@[deprecated (since := "2026-03-17")] +alias principal_add_mul_of_principal_add := isPrincipal_add_mul_of_isPrincipal_add + /-! #### Multiplicative principal ordinals -/ -theorem principal_mul_one : Principal (· * ·) 1 := by - rw [principal_one_iff] +theorem isPrincipal_mul_one : IsPrincipal (· * ·) 1 := by + rw [isPrincipal_one_iff] exact zero_mul _ -theorem principal_mul_two : Principal (· * ·) 2 := by +@[deprecated (since := "2026-03-17")] +alias principal_mul_one := isPrincipal_mul_one + +theorem isPrincipal_mul_two : IsPrincipal (· * ·) 2 := by intro a b ha hb rw [← one_add_one_eq_two, lt_add_one_iff] at * convert mul_le_mul' ha hb exact (mul_one 1).symm -theorem principal_mul_of_le_two (ho : o ≤ 2) : Principal (· * ·) o := by +@[deprecated (since := "2026-03-17")] +alias principal_mul_two := isPrincipal_mul_two + +theorem isPrincipal_mul_of_le_two (ho : o ≤ 2) : IsPrincipal (· * ·) o := by rcases lt_or_eq_of_le ho with (ho | rfl) · rw [← one_add_one_eq_two, lt_add_one_iff] at ho rcases lt_or_eq_of_le ho with (ho | rfl) · rw [lt_one_iff_zero.1 ho] - exact principal_zero - · exact principal_mul_one - · exact principal_mul_two + exact isPrincipal_zero + · exact isPrincipal_mul_one + · exact isPrincipal_mul_two + +@[deprecated (since := "2026-03-17")] +alias principal_mul_of_le_two := isPrincipal_mul_of_le_two -theorem principal_add_of_principal_mul (ho : Principal (· * ·) o) (ho₂ : o ≠ 2) : - Principal (· + ·) o := by +theorem isPrincipal_add_of_isPrincipal_mul (ho : IsPrincipal (· * ·) o) (ho₂ : o ≠ 2) : + IsPrincipal (· + ·) o := by rcases lt_or_gt_of_ne ho₂ with ho₁ | ho₂ · rw [← one_add_one_eq_two, lt_add_one_iff] at ho₁ - exact principal_add_of_le_one ho₁ + exact isPrincipal_add_of_le_one ho₁ · refine fun a b hao hbo => lt_of_le_of_lt ?_ (ho (max_lt hao hbo) ho₂) dsimp only rw [← one_add_one_eq_two, mul_add, mul_one] exact add_le_add (le_max_left a b) (le_max_right a b) -theorem isSuccLimit_of_principal_mul (ho₂ : 2 < o) (ho : Principal (· * ·) o) : IsSuccLimit o := - isSuccLimit_of_principal_add (one_lt_two.trans ho₂) - (principal_add_of_principal_mul ho (ne_of_gt ho₂)) +@[deprecated (since := "2026-03-17")] +alias principal_add_of_principal_mul := isPrincipal_add_of_isPrincipal_mul -theorem principal_mul_iff_mul_left_eq : Principal (· * ·) o ↔ ∀ a, 0 < a → a < o → a * o = o := by +theorem isSuccLimit_of_isPrincipal_mul (ho₂ : 2 < o) (ho : IsPrincipal (· * ·) o) : IsSuccLimit o := + isSuccLimit_of_isPrincipal_add (one_lt_two.trans ho₂) + (isPrincipal_add_of_isPrincipal_mul ho (ne_of_gt ho₂)) + +@[deprecated (since := "2026-03-17")] +alias isSuccLimit_of_principal_mul := isSuccLimit_of_isPrincipal_mul + +theorem isPrincipal_mul_iff_mul_left_eq : + IsPrincipal (· * ·) o ↔ ∀ a, 0 < a → a < o → a * o = o := by refine ⟨fun h a ha₀ hao => ?_, fun h a b hao hbo => ?_⟩ · rcases le_or_gt o 2 with ho | ho · convert one_mul o @@ -306,22 +396,28 @@ theorem principal_mul_iff_mul_left_eq : Principal (· * ·) o ↔ ∀ a, 0 < a · rw [← lt_add_one_iff, one_add_one_eq_two] exact hao.trans_le ho · rwa [one_le_iff_pos] - · exact op_eq_self_of_principal hao (isNormal_mul_right ha₀) h - (isSuccLimit_of_principal_mul ho h) + · exact op_eq_self_of_isPrincipal hao (isNormal_mul_right ha₀) h + (isSuccLimit_of_isPrincipal_mul ho h) · rcases eq_or_ne a 0 with (rfl | ha) · dsimp only; rwa [zero_mul] rw [← pos_iff_ne_zero] at ha rw [← h a ha hao] exact (isNormal_mul_right ha).strictMono hbo -theorem principal_mul_omega0 : Principal (· * ·) ω := fun a b ha hb => +@[deprecated (since := "2026-03-17")] +alias principal_mul_iff_mul_left_eq := isPrincipal_mul_iff_mul_left_eq + +theorem isPrincipal_mul_omega0 : IsPrincipal (· * ·) ω := fun a b ha hb => match a, b, lt_omega0.1 ha, lt_omega0.1 hb with | _, _, ⟨m, rfl⟩, ⟨n, rfl⟩ => by dsimp only; rw [← natCast_mul] apply natCast_lt_omega0 +@[deprecated (since := "2026-03-17")] +alias principal_mul_omega0 := isPrincipal_mul_omega0 + theorem mul_omega0 (a0 : 0 < a) (ha : a < ω) : a * ω = ω := - principal_mul_iff_mul_left_eq.1 principal_mul_omega0 a a0 ha + isPrincipal_mul_iff_mul_left_eq.1 isPrincipal_mul_omega0 a a0 ha theorem natCast_mul_omega0 {n : ℕ} (hn : 0 < n) : n * ω = ω := mul_omega0 (mod_cast hn) (natCast_lt_omega0 n) @@ -334,7 +430,7 @@ theorem mul_lt_omega0_opow (c0 : 0 < c) (ha : a < ω ^ c) (hb : b < ω) : a * b ((isNormal_mul_right <| opow_pos _ omega0_pos).lt_iff_exists_lt isSuccLimit_omega0).1 ha grw [an, opow_succ, mul_assoc] gcongr - exacts [opow_pos _ omega0_pos, principal_mul_omega0 hn hb] + exacts [opow_pos _ omega0_pos, isPrincipal_mul_omega0 hn hb] · rcases ((isNormal_opow one_lt_omega0).lt_iff_exists_lt l).1 ha with ⟨x, hx, ax⟩ refine (mul_le_mul' (le_of_lt ax) (le_of_lt hb)).trans_lt ?_ rw [← opow_succ, opow_lt_opow_iff_right one_lt_omega0] @@ -351,40 +447,49 @@ theorem mul_omega0_opow_opow (a0 : 0 < a) (h : a < ω ^ ω ^ b) : a * ω ^ ω ^ · conv_lhs => rw [← one_mul (ω ^ _)] grw [one_le_iff_pos.2 a0] -theorem principal_mul_omega0_opow_opow (o : Ordinal) : Principal (· * ·) (ω ^ ω ^ o) := - principal_mul_iff_mul_left_eq.2 fun _ => mul_omega0_opow_opow +theorem isPrincipal_mul_omega0_opow_opow (o : Ordinal) : IsPrincipal (· * ·) (ω ^ ω ^ o) := + isPrincipal_mul_iff_mul_left_eq.2 fun _ => mul_omega0_opow_opow -theorem principal_add_of_principal_mul_opow (hb : 1 < b) (ho : Principal (· * ·) (b ^ o)) : - Principal (· + ·) o := by +@[deprecated (since := "2026-03-17")] +alias principal_mul_omega0_opow_opow := isPrincipal_mul_omega0_opow_opow + +theorem isPrincipal_add_of_isPrincipal_mul_opow (hb : 1 < b) (ho : IsPrincipal (· * ·) (b ^ o)) : + IsPrincipal (· + ·) o := by intro x y hx hy have := ho ((opow_lt_opow_iff_right hb).2 hx) ((opow_lt_opow_iff_right hb).2 hy) dsimp only at * rwa [← opow_add, opow_lt_opow_iff_right hb] at this +@[deprecated (since := "2026-03-17")] +alias principal_add_of_principal_mul_opow := isPrincipal_add_of_isPrincipal_mul_opow + /-- The main characterization theorem for multiplicative principal ordinals. -/ -theorem principal_mul_iff_le_two_or_omega0_opow_opow : - Principal (· * ·) o ↔ o ≤ 2 ∨ o ∈ Set.range (ω ^ ω ^ · : Ordinal → Ordinal) := by +theorem isPrincipal_mul_iff_le_two_or_omega0_opow_opow : + IsPrincipal (· * ·) o ↔ o ≤ 2 ∨ o ∈ Set.range (ω ^ ω ^ · : Ordinal → Ordinal) := by refine ⟨fun ho => ?_, ?_⟩ · rcases le_or_gt o 2 with ho₂ | ho₂ · exact Or.inl ho₂ - · rcases principal_add_iff_zero_or_omega0_opow.1 (principal_add_of_principal_mul ho ho₂.ne') - with (rfl | ⟨a, rfl⟩) + · rcases isPrincipal_add_iff_zero_or_omega0_opow.1 + (isPrincipal_add_of_isPrincipal_mul ho ho₂.ne') with (rfl | ⟨a, rfl⟩) · exact (not_lt_zero ho₂).elim - · rcases principal_add_iff_zero_or_omega0_opow.1 - (principal_add_of_principal_mul_opow one_lt_omega0 ho) with (rfl | ⟨b, rfl⟩) + · rcases isPrincipal_add_iff_zero_or_omega0_opow.1 + (isPrincipal_add_of_isPrincipal_mul_opow one_lt_omega0 ho) with (rfl | ⟨b, rfl⟩) · simp · exact Or.inr ⟨b, rfl⟩ · rintro (ho₂ | ⟨a, rfl⟩) - · exact principal_mul_of_le_two ho₂ - · exact principal_mul_omega0_opow_opow a + · exact isPrincipal_mul_of_le_two ho₂ + · exact isPrincipal_mul_omega0_opow_opow a + +@[deprecated (since := "2026-03-17")] +alias principal_mul_iff_le_two_or_omega0_opow_opow := isPrincipal_mul_iff_le_two_or_omega0_opow_opow theorem mul_omega0_dvd (a0 : 0 < a) (ha : a < ω) : ∀ {b}, ω ∣ b → a * b = b | _, ⟨b, rfl⟩ => by rw [← mul_assoc, mul_omega0 a0 ha] -theorem mul_eq_opow_log_succ (ha : a ≠ 0) (hb : Principal (· * ·) b) (hb₂ : 2 < b) : +theorem mul_eq_opow_log_succ (ha : a ≠ 0) (hb : IsPrincipal (· * ·) b) (hb₂ : 2 < b) : a * b = b ^ succ (log b a) := by apply le_antisymm - · have hbl := isSuccLimit_of_principal_mul hb₂ hb + · have hbl := isSuccLimit_of_isPrincipal_mul hb₂ hb rw [(isNormal_mul_right (pos_iff_ne_zero.2 ha)).apply_of_isSuccLimit hbl, Ordinal.iSup_le_iff] intro ⟨c, hcb⟩ @@ -400,13 +505,16 @@ theorem mul_eq_opow_log_succ (ha : a ≠ 0) (hb : Principal (· * ·) b) (hb₂ /-! #### Exponential principal ordinals -/ -theorem principal_opow_omega0 : Principal (· ^ ·) ω := fun a b ha hb => +theorem isPrincipal_opow_omega0 : IsPrincipal (· ^ ·) ω := fun a b ha hb => match a, b, lt_omega0.1 ha, lt_omega0.1 hb with | _, _, ⟨m, rfl⟩, ⟨n, rfl⟩ => by simp [← natCast_pow] +@[deprecated (since := "2026-03-17")] +alias principal_opow_omega0 := isPrincipal_opow_omega0 + theorem opow_omega0 (a1 : 1 < a) (h : a < ω) : a ^ ω = ω := ((opow_le_of_isSuccLimit (one_le_iff_ne_zero.1 <| le_of_lt a1) isSuccLimit_omega0).2 fun _ hb => - (principal_opow_omega0 h hb).le).antisymm + (isPrincipal_opow_omega0 h hb).le).antisymm (right_le_opow _ a1) theorem natCast_opow_omega0 {n : ℕ} (hn : 1 < n) : n ^ ω = ω := diff --git a/Mathlib/SetTheory/ZFC/Ordinal.lean b/Mathlib/SetTheory/ZFC/Ordinal.lean index 34b0e2c7a5fc30..58a963acaac0d4 100644 --- a/Mathlib/SetTheory/ZFC/Ordinal.lean +++ b/Mathlib/SetTheory/ZFC/Ordinal.lean @@ -230,7 +230,6 @@ alias _root_.ZFSet.isOrdinal_iff_isTrichotomous := _root_.ZFSet.isOrdinal_iff_tr protected theorem isWellOrder (h : x.IsOrdinal) : IsWellOrder _ (Subrel (· ∈ ·) (· ∈ x)) where wf := (Subrel.relEmbedding _ _).wellFounded mem_wf - trans := h.isTrans.1 trichotomous := h.trichotomous.1 /-- An ordinal is a transitive set, well-ordered under membership. -/ diff --git a/Mathlib/Tactic/ArithMult.lean b/Mathlib/Tactic/ArithMult.lean index 3ab626dfcb7226..4427ba7e055a5a 100644 --- a/Mathlib/Tactic/ArithMult.lean +++ b/Mathlib/Tactic/ArithMult.lean @@ -5,9 +5,7 @@ Authors: Arend Mellendijk -/ module -public meta import Mathlib.Tactic.Basic public import Mathlib.Tactic.ArithMult.Init -public import Mathlib.Tactic.Basic /-! # Multiplicativity diff --git a/Mathlib/Tactic/Choose.lean b/Mathlib/Tactic/Choose.lean index b14abfb4d25d2c..9cc7b1d59cf62b 100644 --- a/Mathlib/Tactic/Choose.lean +++ b/Mathlib/Tactic/Choose.lean @@ -6,7 +6,6 @@ Authors: Johannes Hölzl, Floris van Doorn, Mario Carneiro, Reid Barton, Johan C module public import Mathlib.Logic.Function.Basic -public meta import Mathlib.Tactic.Basic /-! # `choose` tactic diff --git a/Mathlib/Tactic/CongrM.lean b/Mathlib/Tactic/CongrM.lean index 825b8d79ffe8c6..2dbe7a7ad7779c 100644 --- a/Mathlib/Tactic/CongrM.lean +++ b/Mathlib/Tactic/CongrM.lean @@ -5,6 +5,7 @@ Authors: Moritz Doll, Gabriel Ebner, Damiano Testa, Kyle Miller -/ module +public meta import Lean.Meta.Tactic.Rfl public import Mathlib.Tactic.TermCongr /-! diff --git a/Mathlib/Tactic/DefEqTransformations.lean b/Mathlib/Tactic/DefEqTransformations.lean index 8cf395eb1e2cc0..bb7d3fa2711370 100644 --- a/Mathlib/Tactic/DefEqTransformations.lean +++ b/Mathlib/Tactic/DefEqTransformations.lean @@ -5,8 +5,8 @@ Authors: Kyle Miller -/ module -public meta import Mathlib.Tactic.Basic -public import Mathlib.Tactic.Basic +public import Mathlib.Init +public meta import Lean.Elab.Tactic.Conv.Basic /-! # Tactics that transform types into definitionally equal types diff --git a/Mathlib/Tactic/Ext.lean b/Mathlib/Tactic/Ext.lean index 152c59847d2bf3..6ca0251ecdb324 100644 --- a/Mathlib/Tactic/Ext.lean +++ b/Mathlib/Tactic/Ext.lean @@ -5,7 +5,8 @@ Authors: Eric Wieser -/ module -public import Mathlib.Tactic.Basic +public import Mathlib.Init +public import Batteries.Util.LibraryNote /-! # Documentation for `ext` tactic diff --git a/Mathlib/Tactic/FastInstance.lean b/Mathlib/Tactic/FastInstance.lean index 1f4176c362918a..a9f056386e47e3 100644 --- a/Mathlib/Tactic/FastInstance.lean +++ b/Mathlib/Tactic/FastInstance.lean @@ -91,9 +91,14 @@ partial def makeFastInstance (inst expectedType : Expr) (trace : Array Name := # let argExpectedType ← instantiateMVars mvarDecl.type let arg := args[i]! if ← isProp argExpectedType then - -- For proofs, create an auxiliary theorem of the expected type. - if ← withDefault <| isDefEq argExpectedType (← inferType arg) then - mvarId.assign <| ← mkAuxTheorem argExpectedType arg (zetaDelta := true) + let actualType ← inferType arg + if ← withDefault <| isDefEq argExpectedType actualType then + if ← withTransparency .instances <| isDefEq argExpectedType actualType then + mvarId.assign arg + else + -- Wrap in an aux theorem if the types differ at instances transparency, + -- indicating a binder type mismatch that needs fixing. + mvarId.assign <| ← mkAuxTheorem argExpectedType arg (zetaDelta := true) else throwError "Proof `{arg}` does not have expected type `{argExpectedType}`" -- Recurse into instance arguments of the constructor diff --git a/Mathlib/Tactic/FunProp/Types.lean b/Mathlib/Tactic/FunProp/Types.lean index b6a25152366db5..d14f4b636e5d47 100644 --- a/Mathlib/Tactic/FunProp/Types.lean +++ b/Mathlib/Tactic/FunProp/Types.lean @@ -5,10 +5,7 @@ Authors: Tomáš Skřivan -/ module -public meta import Mathlib.Tactic.FunProp.FunctionData public meta import Mathlib.Lean.Meta.RefinedDiscrTree.Basic -public import Lean -public import Mathlib.Lean.Meta.RefinedDiscrTree.Basic public import Mathlib.Tactic.FunProp.FunctionData /-! diff --git a/Mathlib/Tactic/GCongr/Core.lean b/Mathlib/Tactic/GCongr/Core.lean index 091061d162e5ed..e9f87a9dc43e7f 100644 --- a/Mathlib/Tactic/GCongr/Core.lean +++ b/Mathlib/Tactic/GCongr/Core.lean @@ -5,17 +5,18 @@ Authors: Mario Carneiro, Heather Macbeth, Jovan Gerbscheid -/ module -public meta import Lean public meta import Batteries.Lean.Except -public meta import Mathlib.Tactic.GCongr.ForwardAttr -import all Lean.Meta.Tactic.Apply public import Batteries.Tactic.Exact +public meta import Lean.Meta.Tactic.Rfl +public meta import Lean.Meta.Tactic.Symm public import Mathlib.Order.Defs.Unbundled public import Mathlib.Tactic.Core public import Mathlib.Tactic.GCongr.ForwardAttr public import Mathlib.Tactic.Lemma public import Mathlib.Tactic.TypeStar +import all Lean.Meta.Tactic.Apply + /-! # The `gcongr` ("generalized congruence") tactic diff --git a/Mathlib/Tactic/GRewrite/Core.lean b/Mathlib/Tactic/GRewrite/Core.lean index 8b11008f18a17e..55b1b08da1825f 100644 --- a/Mathlib/Tactic/GRewrite/Core.lean +++ b/Mathlib/Tactic/GRewrite/Core.lean @@ -5,7 +5,7 @@ Authors: Sebastian Zimmer, Mario Carneiro, Heather Macbeth, Jovan Gerbscheid -/ module -public import Lean +public meta import Lean.Meta.Tactic.Rewrite public import Mathlib.Tactic.GCongr.Core /-! diff --git a/Mathlib/Tactic/GRewrite/Elab.lean b/Mathlib/Tactic/GRewrite/Elab.lean index f9a32cf2d8b3db..00f8b5c7e4b8ef 100644 --- a/Mathlib/Tactic/GRewrite/Elab.lean +++ b/Mathlib/Tactic/GRewrite/Elab.lean @@ -5,7 +5,7 @@ Authors: Sebastian Zimmer, Mario Carneiro, Heather Macbeth, Jovan Gerbscheid -/ module -public meta import Mathlib.Tactic.GRewrite.Core +public meta import Lean.Elab.Tactic.Rewrite public import Mathlib.Tactic.GRewrite.Core /-! diff --git a/Mathlib/Tactic/IrreducibleDef.lean b/Mathlib/Tactic/IrreducibleDef.lean index 4cd39fa8f13982..a6eb7bc8296a91 100644 --- a/Mathlib/Tactic/IrreducibleDef.lean +++ b/Mathlib/Tactic/IrreducibleDef.lean @@ -5,9 +5,7 @@ Authors: Gabriel Ebner -/ module -public import Mathlib.Tactic.Basic public import Mathlib.Tactic.Eqns -public meta import Mathlib.Tactic.Simps.Basic public import Mathlib.Util.TermReduce /-! diff --git a/Mathlib/Tactic/Lift.lean b/Mathlib/Tactic/Lift.lean index ea4cecc9bd520d..c8746ed165379f 100644 --- a/Mathlib/Tactic/Lift.lean +++ b/Mathlib/Tactic/Lift.lean @@ -5,10 +5,10 @@ Authors: Floris van Doorn -/ module -public meta import Mathlib.Tactic.Basic public meta import Batteries.Lean.Expr public meta import Batteries.Lean.Meta.UnusedNames -public import Mathlib.Tactic.Basic +public meta import Lean.Elab.Tactic.RCases +public import Mathlib.Tactic.TypeStar /-! # lift tactic @@ -73,39 +73,15 @@ namespace Mathlib.Tactic open Lean Parser Elab Tactic Meta -/-- Lift an expression to another type. -* Usage: `'lift' expr 'to' expr ('using' expr)? ('with' id (id id?)?)?`. -* If `n : ℤ` and `hn : n ≥ 0` then the tactic `lift n to ℕ using hn` creates a new - constant of type `ℕ`, also named `n` and replaces all occurrences of the old variable `(n : ℤ)` - with `↑n` (where `n` in the new variable). It will clear `n` from the context and - try to clear `hn` from the context. - + So for example the tactic `lift n to ℕ using hn` transforms the goal - `n : ℤ, hn : n ≥ 0, h : P n ⊢ n = 3` to `n : ℕ, h : P ↑n ⊢ ↑n = 3` - (here `P` is some term of type `ℤ → Prop`). -* The argument `using hn` is optional, the tactic `lift n to ℕ` does the same, but also creates a - new subgoal that `n ≥ 0` (where `n` is the old variable). - This subgoal will be placed at the top of the goal list. - + So for example the tactic `lift n to ℕ` transforms the goal - `n : ℤ, h : P n ⊢ n = 3` to two goals - `n : ℤ, h : P n ⊢ n ≥ 0` and `n : ℕ, h : P ↑n ⊢ ↑n = 3`. -* You can also use `lift n to ℕ using e` where `e` is any expression of type `n ≥ 0`. -* Use `lift n to ℕ with k` to specify the name of the new variable. -* Use `lift n to ℕ with k hk` to also specify the name of the equality `↑k = n`. In this case, `n` - will remain in the context. You can use `rfl` for the name of `hk` to substitute `n` away - (i.e. the default behavior). -* You can also use `lift e to ℕ with k hk` where `e` is any expression of type `ℤ`. - In this case, the `hk` will always stay in the context, but it will be used to rewrite `e` in - all hypotheses and the target. - + So for example the tactic `lift n + 3 to ℕ using hn with k hk` transforms the goal - `n : ℤ, hn : n + 3 ≥ 0, h : P (n + 3) ⊢ n + 3 = 2 * n` to the goal - `n : ℤ, k : ℕ, hk : ↑k = n + 3, h : P ↑k ⊢ ↑k = 2 * n`. -* The tactic `lift n to ℕ using h` will remove `h` from the context. If you want to keep it, - specify it again as the third argument to `with`, like this: `lift n to ℕ using h with n rfl h`. -* More generally, this can lift an expression from `α` to `β` assuming that there is an instance - of `CanLift α β`. In this case the proof obligation is specified by `CanLift.prf`. -* Given an instance `CanLift β γ`, it can also lift `α → β` to `α → γ`; more generally, given - `β : Π a : α, Type*`, `γ : Π a : α, Type*`, and `[Π a : α, CanLift (β a) (γ a)]`, it - automatically generates an instance `CanLift (Π a, β a) (Π a, γ a)`. +/-- +`lift e to t with x` lifts the expression `e` to the type `t` by introducing a new variable `x : t` +such that `↑x = e`, and then replacing occurrences of `e` with `↑x`. `lift` requires an instance of +the class `CanLift t' t coe cond`, where `t'` is the type of `e`, and creates a side goal for the +lifting condition, of the form `⊢ cond x`, placing this on top of the goal stack. + +Given an instance `CanLift β γ`, `lift` can also lift `α → β` to `α → γ`; more generally, given +`β : Π a : α, Type*`, `γ : Π a : α, Type*`, and `[Π a : α, CanLift (β a) (γ a)]`, it +automatically generates an instance `CanLift (Π a, β a) (Π a, γ a)`. `lift` is in some sense dual to the `zify` tactic. `lift (z : ℤ) to ℕ` will change the type of an integer `z` (in the supertype) to `ℕ` (the subtype), given a proof that `z ≥ 0`; @@ -113,6 +89,58 @@ propositions concerning `z` will still be over `ℤ`. `zify` changes proposition subtype) to propositions about `ℤ` (the supertype), without changing the type of any variable. The `norm_cast` tactic can be used after `lift` to normalize introduced casts. + +* `lift e to t using h with x` uses the expression `h` to prove the lifting condition `cond e`. + If `h` is a variable, `lift` will try to clear it from the context. If you want to keep `h` in + the context, write `lift e to t using h with x rfl h` (see below). +* If `e` is a variable, `lift e to t` is equivalent to `lift e to t with e`. The original variable + `e` will be cleared from the context. +* `lift e to t with x hx` adds `hx : ↑x = e` to the context (and if `e` is a variable, does not + clear it). +* `lift e to t with x hx h` adds `hx : ↑x = e` and `h : cond e` to the context (and if `e` is a + variable, does not clear it). In particular, `lift e to t using h with x hx h`, where `h` is a + variable, keeps `h` in the context. +* `lift e to t with x rfl h` adds `h : cond e` to the context (and if `e` is a variable, does not + clear it). In particular, `lift e to t using h with x rfl h`, where `h` is a variable, keeps `h` + in the context. + +Examples: +``` +def P (n : ℤ) : Prop := n = 3 + +example (n : ℤ) (h : P n) : n = 3 := by + lift n to ℕ + /- + Two goals: + n : ℤ, h : P n ⊢ n ≥ 0 + n : ℕ, h : P ↑n ⊢ ↑n = 3 + -/ + · unfold P at h; linarith + · exact h + +example (n : ℤ) (hn : n ≥ 0) (h : P n) : n = 3 := by + lift n to ℕ using hn + /- + One goal: + n : ℕ + h : P ↑n + ⊢ ↑n = 3 + -/ + exact h + +example (n : ℤ) (hn : n + 3 ≥ 0) (h : P (n + 3)) : + n + 3 = n * 2 + 3 := by + lift n + 3 to ℕ using hn with k hk + /- + One goal: + n : ℤ + k : ℕ + hk : ↑k = n + 3 + h : P ↑k + ⊢ ↑k = 2 * n + 3 + -/ + unfold P at h; linarith +``` -/ syntax (name := lift) "lift " term " to " term (" using " term)? (" with " ident (ppSpace colGt ident)? (ppSpace colGt ident)?)? : tactic diff --git a/Mathlib/Tactic/ModCases.lean b/Mathlib/Tactic/ModCases.lean index 5100e69d216ee1..d57edea9e6a4d2 100644 --- a/Mathlib/Tactic/ModCases.lean +++ b/Mathlib/Tactic/ModCases.lean @@ -174,14 +174,12 @@ def modCases (h : TSyntax `Lean.binderIdent) (e : Q(ℕ)) (n : ℕ) : TacticM Un end NatMod /-- -* The tactic `mod_cases h : e % 3` will perform a case disjunction on `e`. - If `e : ℤ`, then it will yield subgoals containing the assumptions - `h : e ≡ 0 [ZMOD 3]`, `h : e ≡ 1 [ZMOD 3]`, `h : e ≡ 2 [ZMOD 3]` - respectively. If `e : ℕ` instead, then it works similarly, except with - `[MOD 3]` instead of `[ZMOD 3]`. -* In general, `mod_cases h : e % n` works - when `n` is a positive numeral and `e` is an expression of type `ℕ` or `ℤ`. -* If `h` is omitted as in `mod_cases e % n`, it will be default-named `H`. +`mod_cases h : e % n`, where `n` is a positive numeral and `e` is an expression of type `ℕ` or `ℤ`, +performs a case disjunction on the value of `e` modulo `n`. If `e : ℤ`, the goal is split into +`n` subgoals containing the new hypotheses `h : e ≡ 0 [ZMOD n]`, ..., `h : e ≡ n-1 [ZMOD n]` +respectively. If `e : ℕ` instead, then the hypotheses contain `[MOD n]` instead of `[ZMOD n]`. + +* `mod_cases e % n`, with `h` omitted, gives the default name `H` to the new hypotheses. -/ syntax "mod_cases " (atomic(binderIdent ":"))? term:71 " % " num : tactic diff --git a/Mathlib/Tactic/MoveAdd.lean b/Mathlib/Tactic/MoveAdd.lean index ecb2b89da606f7..7d92b88c0f7233 100644 --- a/Mathlib/Tactic/MoveAdd.lean +++ b/Mathlib/Tactic/MoveAdd.lean @@ -88,7 +88,7 @@ needs to have inbuilt the lemmas asserting the analogues of `add_comm, add_assoc, add_left_comm` for the new operation. Currently, `move_oper` supports `HAdd.hAdd`, `HMul.hMul`, `And`, `Or`, `Max.max`, `Min.min`. -These lemmas should be added to `Mathlib.MoveAdd.move_oper_simpCtx`. +These lemmas should be added to `Mathlib.MoveAdd.moveOperSimpCtx`. See `MathlibTest/MoveAdd.lean` for sample usage of `move_oper`. @@ -339,7 +339,7 @@ def pairUp : List (Expr × Bool × Syntax) → List Expr → return ((d, m.2.1)::found, unfound) | _, _ => return ([], []) -/-- `move_oper_simpCtx` is the `Simp.Context` for the reordering internal to `move_oper`. +/-- `moveOperSimpCtx` is the `Simp.Context` for the reordering internal to `move_oper`. To support a new binary operation, extend the list in this definition, so that it contains enough lemmas to allow `simp` to close a generic permutation goal for the new binary operation. -/ @@ -426,20 +426,22 @@ def parseArrows : TSyntax `Lean.Parser.Tactic.rwRuleSeq → TermElabM (Array (Ex initialize registerTraceClass `Tactic.move_oper -/-- The tactic `move_add` rearranges summands of expressions. -Calling `move_add [a, ← b, ...]` matches `a, b,...` with summands in the main goal. -It then moves `a` to the far right and `b` to the far left of each addition in which they appear. -The side to which the summands are moved is determined by the presence or absence of the arrow `←`. +/-- `move_oper op [a]` repeatedly moves `a` to the far right hand side in applications of `op`. +Here the constant `op` refers to a binary associative commutative operation, and `a` is any term +(potentially with underscores). -The inputs `a, b,...` can be any terms, also with underscores. -The tactic uses the first "new" summand that unifies with each one of the given inputs. +If `a` contains underscores, they are filled in by unification with the first matching occurrence. +Subterms with different values for the underscores are not matched, unless you repeat `a`. -There is a multiplicative variant, called `move_mul`. +Currently, `move_oper` supports the operators `HAdd.hAdd` (`· + ·`), `HMul.hMul` (`· * ·`), +`And` (`· ∧ ·`), `Or` (`· ∨ ·`), `Max.max` and `Min.min`. To support more operations, add them to +`Mathlib.MoveAdd.moveOperSimpCtx`. -There is also a general tactic for a "binary associative commutative operation": `move_oper`. -In this case the syntax requires providing first a term whose head symbol is the operation. -E.g. `move_oper HAdd.hAdd [...]` is the same as `move_add`, while `move_oper Max.max [...]` -rearranges `max`s. +* `move_add [...]` uses addition as the operation: it abbreviates `move_oper HAdd.add [...]`. +* `move_mul [...]` uses multiplication as the operation: it abbreviates `move_oper HMul.mul [...]`. +* `move_oper op [← a]` moves the atoms matching `a` to the far left hand side instead of the right. +* `move_oper op [a, b, ← c, ← d, ...]` moves multiple atoms simultaneously, in the order indicated + by the arguments: `c` will appear to the left of `d` and `a` will appear to the left of `b`. -/ elab (name := moveOperTac) "move_oper" id:ident rws:rwRuleSeq : tactic => withMainContext do -- parse the operation diff --git a/Mathlib/Tactic/NormNum/Irrational.lean b/Mathlib/Tactic/NormNum/Irrational.lean index 2476a0ac319ab4..14472588aac6ed 100644 --- a/Mathlib/Tactic/NormNum/Irrational.lean +++ b/Mathlib/Tactic/NormNum/Irrational.lean @@ -49,47 +49,20 @@ private theorem irrational_rpow_rat_of_not_power {q : ℚ} {a b : ℕ} rw [hx, ← Real.rpow_mul_natCast (by simpa), div_mul_cancel₀ _ (by simp; lia)] simp -private theorem not_power_nat_pow {n p q : ℕ} - (h_coprime : p.Coprime q) - (hq : 0 < q) - (h : ∀ m, n ≠ m ^ q) (m : ℕ) : - n ^ p ≠ m ^ q := by - by_cases hn : n = 0 - · specialize h 0 - simp [hn, zero_pow hq.ne.symm] at h +private theorem not_power_nat_pow {n p q : ℕ} (h_coprime : p.Coprime q) (hq : 0 < q) + (h : ∀ m, n ≠ m ^ q) (m : ℕ) : n ^ p ≠ m ^ q := by + rcases eq_or_ne n 0 with (rfl | hn) + · simpa [hq.ne'] using h 0 contrapose! h - apply_fun Nat.factorization at h - simp only [Nat.factorization_pow] at h - suffices ∃ f : ℕ →₀ ℕ, n.factorization = q • f by - obtain ⟨f, hf⟩ := this - have : f = (f.prod fun x1 x2 => x1 ^ x2).factorization := by - rw [Nat.prod_pow_factorization_eq_self] - intro z hz - apply_fun Finsupp.support at hf - rw [Finsupp.support_smul_eq (by lia)] at hf - rw [← hf] at hz - exact Nat.prime_of_mem_primeFactors hz - have hf0 : f 0 = 0 := by - apply_fun (· 0) at hf - simp only [Nat.factorization_zero_right, Finsupp.coe_smul, Pi.smul_apply, smul_eq_mul, - zero_eq_mul] at hf - cases hf - · lia - · assumption - rw [this, ← Nat.factorization_pow] at hf - apply Nat.factorization_inj at hf - · use f.prod (· ^ ·) - · exact hn - · simp only [ne_eq, Set.mem_setOf_eq, pow_eq_zero_iff', Finsupp.prod_eq_zero_iff, - Finsupp.mem_support_iff, existsAndEq, true_and, and_self, not_and, Decidable.not_not] - tauto - use n.factorization.mapRange (fun e ↦ e / q) (by simp) + let f := n.factorization.mapRange (· / q) <| by simp + suffices hf : n.factorization = q • f by + have hf0 : f 0 = 0 := by simpa [hq.ne'] using congr($hf 0) + refine ⟨f.prod (· ^ ·), Nat.factorization_inj hn (by simp [hf0]) ?_⟩ + rwa [Nat.factorization_pow, n.factorization_prod_pow_eq_self_of_le_factorization ?_] + exact hf ▸ le_self_nsmul (zero_le f) (by lia) ext z - apply_fun (· z) at h - simp only [Finsupp.coe_smul, Pi.smul_apply, smul_eq_mul, Finsupp.mapRange_apply] at h ⊢ - rw [Nat.mul_div_cancel'] - apply Nat.Coprime.dvd_of_dvd_mul_left _ ⟨_, h⟩ - rwa [Nat.coprime_comm] + rw [Finsupp.smul_apply, smul_eq_mul, Finsupp.mapRange_apply, Nat.mul_div_cancel'] + simpa using h_coprime.symm.dvd_of_dvd_mul_left ⟨_, by simpa using congr(Nat.factorization $h z)⟩ private theorem not_power_nat_of_bounds {n k d : ℕ} (h_left : k ^ d < n) (h_right : n < (k + 1) ^ d) {m : ℕ} : diff --git a/Mathlib/Tactic/Push.lean b/Mathlib/Tactic/Push.lean index b80924833aac5a..87169020cd1987 100644 --- a/Mathlib/Tactic/Push.lean +++ b/Mathlib/Tactic/Push.lean @@ -6,9 +6,8 @@ Jireh Loreaux -/ module -public meta import Lean.Elab.Tactic.Location +public meta import Lean.Elab.Tactic.Conv.Simp public import Mathlib.Logic.Basic -public meta import Mathlib.Tactic.Basic public import Mathlib.Tactic.Conv public import Mathlib.Tactic.Push.Attr public import Mathlib.Util.AtLocation diff --git a/Mathlib/Tactic/Qify.lean b/Mathlib/Tactic/Qify.lean index d9e12af8d166e6..4b8de5c07f0211 100644 --- a/Mathlib/Tactic/Qify.lean +++ b/Mathlib/Tactic/Qify.lean @@ -5,7 +5,6 @@ Authors: Moritz Doll, Mario Carneiro, Robert Y. Lewis -/ module -public meta import Mathlib.Tactic.Basic public import Mathlib.Algebra.Order.Ring.Cast public import Mathlib.Algebra.Order.Ring.Unbundled.Rat public import Mathlib.Algebra.Ring.Rat diff --git a/Mathlib/Tactic/RSuffices.lean b/Mathlib/Tactic/RSuffices.lean index 9b1f9c9ffe59b5..d22a6ae46b9390 100644 --- a/Mathlib/Tactic/RSuffices.lean +++ b/Mathlib/Tactic/RSuffices.lean @@ -5,8 +5,7 @@ Authors: Moritz Doll -/ module -public meta import Mathlib.Tactic.Basic -public import Mathlib.Tactic.Basic +public import Mathlib.Init /-! # `rsuffices` tactic diff --git a/Mathlib/Tactic/SetLike.lean b/Mathlib/Tactic/SetLike.lean index 98a889cb881d28..bb1830fdd13420 100644 --- a/Mathlib/Tactic/SetLike.lean +++ b/Mathlib/Tactic/SetLike.lean @@ -7,7 +7,7 @@ module public import Aesop.Frontend public meta import Batteries.Util.LibraryNote -public import Mathlib.Tactic.Basic +public import Mathlib.Init /-! # SetLike Rule Set diff --git a/Mathlib/Tactic/Simps/Basic.lean b/Mathlib/Tactic/Simps/Basic.lean index 3c2f3d7fdf5915..73ff3e497eb3a1 100644 --- a/Mathlib/Tactic/Simps/Basic.lean +++ b/Mathlib/Tactic/Simps/Basic.lean @@ -8,9 +8,7 @@ module public meta import Lean.Elab.Tactic.Simp public meta import Lean.Elab.App public meta import Mathlib.Lean.Expr.Basic -public meta import Mathlib.Tactic.Basic public import Mathlib.Util.AddRelatedDecl -public import Mathlib.Tactic.Basic public import Mathlib.Tactic.Simps.NotationClass public import Mathlib.Tactic.Translate.Attributes diff --git a/Mathlib/Tactic/Subsingleton.lean b/Mathlib/Tactic/Subsingleton.lean index fa4100db19142b..708d1f1c92443d 100644 --- a/Mathlib/Tactic/Subsingleton.lean +++ b/Mathlib/Tactic/Subsingleton.lean @@ -5,8 +5,8 @@ Authors: Kyle Miller -/ module +public meta import Lean.Meta.Tactic.Refl public import Mathlib.Logic.Basic -public meta import Mathlib.Tactic.Basic /-! # `subsingleton` tactic diff --git a/Mathlib/Tactic/TermCongr.lean b/Mathlib/Tactic/TermCongr.lean index 2b5a3c56a04792..07dfbf4317141d 100644 --- a/Mathlib/Tactic/TermCongr.lean +++ b/Mathlib/Tactic/TermCongr.lean @@ -5,10 +5,7 @@ Authors: Kyle Miller -/ module -public meta import Mathlib.Lean.Expr.Basic -public meta import Mathlib.Lean.Meta.CongrTheorems -public meta import Mathlib.Logic.Basic -public import Mathlib.Tactic.Basic +public import Mathlib.Lean.Meta.CongrTheorems /-! # `congr(...)` congruence quotations diff --git a/Mathlib/Tactic/ToFun.lean b/Mathlib/Tactic/ToFun.lean index dfc3f0d161a41f..65977c70626fe5 100644 --- a/Mathlib/Tactic/ToFun.lean +++ b/Mathlib/Tactic/ToFun.lean @@ -37,11 +37,11 @@ Use the `to_fun (attr := ...)` syntax to add the same attribute to both declarat syntax (name := to_fun) "to_fun" optAttrArg : attr def toFunImpl (src : Name) (stx : Syntax) (kind : AttributeKind) : AttrM Name := do - let `(attr| to_fun $optAttr) := stx | throwUnsupportedSyntax + let `(attr| to_fun%$tk $optAttr) := stx | throwUnsupportedSyntax if (kind != AttributeKind.global) then throwError "`to_fun` can only be used as a global attribute" let tgt := (src.appendBefore "fun_") - MetaM.run' <| addRelatedDecl src tgt stx optAttr + MetaM.run' <| addRelatedDecl src tgt tk optAttr (docstringPrefix? := s!"Eta-expanded form of `{src}`") (hoverInfo := true) fun value levels => do let type ← inferType value diff --git a/Mathlib/Tactic/Translate/Core.lean b/Mathlib/Tactic/Translate/Core.lean index cdaafa42ce94d0..cbcc505dad36ed 100644 --- a/Mathlib/Tactic/Translate/Core.lean +++ b/Mathlib/Tactic/Translate/Core.lean @@ -545,10 +545,17 @@ where return tmpLCtx.mkLambda (usedLetOnly := false) fvars e /-- Rename binder names in pi type. -/ -def renameBinderNames (t : TranslateData) (renameFun : Name → Option Name) (src : Expr) : Expr := - src.mapForallBinderNames fun n => (renameFun n).getD <| +def renameBinderNames (t : TranslateData) (rename : NameMap Name) (src : Expr) : Expr := + src.mapForallBinderNames fun n => (rename.get? n).getD <| match n with - | .str p s => .str p (GuessName.guessName t.guessNameData s) + | .str p s => .str p <| + let s' := GuessName.guessName t.guessNameData 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 + else + s | n => n /-- Run `applyReplacementFun` on an expression `∀ x₁ .. xₙ, e`, @@ -614,7 +621,7 @@ 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.get? type + let (type', relevantArg₂) ← applyReplacementForall t dont <| renameBinderNames t rename type type ← reorderForall reorder type' if let some b := unfoldBoundaries? then type ← b.unfoldInsertions type diff --git a/Mathlib/Tactic/Translate/GuessName.lean b/Mathlib/Tactic/Translate/GuessName.lean index ea7c6bdf58b356..f3b8355f8cab56 100644 --- a/Mathlib/Tactic/Translate/GuessName.lean +++ b/Mathlib/Tactic/Translate/GuessName.lean @@ -58,7 +58,7 @@ def endCapitalNames : TreeMap String (List String) compare := open String in /-- This function takes a String and splits it into separate parts based on the following -[naming conventions](https://github.com/leanprover-community/mathlib4/wiki#naming-convention). +[naming conventions](https://leanprover-community.github.io/contribute/naming.html). E.g. `#eval "InvHMulLEConjugate₂SMul_ne_top".splitCase` yields `["Inv", "HMul", "LE", "Conjugate₂", "SMul", "_", "ne", "_", "top"]`. -/ diff --git a/Mathlib/Tactic/Translate/ToDual.lean b/Mathlib/Tactic/Translate/ToDual.lean index 16e5cf54d06088..2402bcf26352cf 100644 --- a/Mathlib/Tactic/Translate/ToDual.lean +++ b/Mathlib/Tactic/Translate/ToDual.lean @@ -147,6 +147,8 @@ def nameDict : Std.HashMap String (List String) := .ofList [ ("bot", ["Top"]), ("inf", ["Sup"]), ("sup", ["Inf"]), + ("inf₂", ["Sup₂"]), + ("sup₂", ["Inf₂"]), ("min", ["Max"]), ("max", ["Min"]), ("untop", ["Unbot"]), @@ -181,6 +183,8 @@ def nameDict : Std.HashMap String (List String) := .ofList [ ("l", ["U"]), ("next", ["Prev"]), ("prev", ["Next"]), + ("heyting", ["Coheyting"]), + ("coheyting", ["Heyting"]), ("epi", ["Mono"]), /- `mono` can also refer to monotone, so we don't translate it. -/ diff --git a/Mathlib/Tactic/Widget/CongrM.lean b/Mathlib/Tactic/Widget/CongrM.lean index 7450d5531aafe2..b0a95a8fe42028 100644 --- a/Mathlib/Tactic/Widget/CongrM.lean +++ b/Mathlib/Tactic/Widget/CongrM.lean @@ -5,8 +5,6 @@ Authors: Patrick Massot -/ module -public import Mathlib.Tactic.Basic -public meta import Mathlib.Tactic.Basic public import Mathlib.Tactic.Widget.SelectPanelUtils public import ProofWidgets.Component.Basic public import ProofWidgets.Component.OfRpcMethod diff --git a/Mathlib/Tactic/Widget/GCongr.lean b/Mathlib/Tactic/Widget/GCongr.lean index 786144281a7ec2..62fec0f49afe17 100644 --- a/Mathlib/Tactic/Widget/GCongr.lean +++ b/Mathlib/Tactic/Widget/GCongr.lean @@ -5,8 +5,6 @@ Authors: Patrick Massot -/ module -public import Mathlib.Tactic.Basic -public meta import Mathlib.Tactic.Basic public import Mathlib.Tactic.Widget.SelectPanelUtils public import ProofWidgets.Component.Basic public import ProofWidgets.Component.OfRpcMethod diff --git a/Mathlib/Tactic/Widget/StringDiagram.lean b/Mathlib/Tactic/Widget/StringDiagram.lean index 2ff7c06e66546a..bad77fefb482f8 100644 --- a/Mathlib/Tactic/Widget/StringDiagram.lean +++ b/Mathlib/Tactic/Widget/StringDiagram.lean @@ -7,6 +7,7 @@ module public meta import ProofWidgets.Component.PenroseDiagram public meta import ProofWidgets.Component.Panel.Basic +public meta import Mathlib.Data.List.Defs public import Mathlib.Tactic.CategoryTheory.Bicategory.Normalize public meta import Mathlib.Tactic.CategoryTheory.Coherence.Normalize public import Mathlib.Tactic.CategoryTheory.Monoidal.Normalize @@ -209,14 +210,12 @@ def NormalExpr.nodes (e : NormalExpr) : CoherenceM ρ (List (List Node)) := | NormalExpr.nil _ _ => return [] | NormalExpr.cons _ _ η _ => return (← topNodes η) :: (← e.nodesAux 1) -/-- `pairs [a, b, c, d]` is `[(a, b), (b, c), (c, d)]`. -/ -def pairs {α : Type} : List α → List (α × α) := - fun l => l.zip (l.drop 1) +@[deprecated (since := "2026-02-26")] alias pairs := List.consecutivePairs /-- The list of strands associated with a 2-morphism. -/ def NormalExpr.strands (e : NormalExpr) : CoherenceM ρ (List (List Strand)) := do let l ← e.nodes - (pairs l).mapM fun (x, y) ↦ do + (l.consecutivePairs).mapM fun (x, y) ↦ do let xs := (x.map (fun n ↦ n.tarList)).flatten let ys := (y.map (fun n ↦ n.srcList)).flatten -- sanity check @@ -278,10 +277,10 @@ def mkStringDiagram (nodes : List (List Node)) (strands : List (List Strand)) : | .id _ => do addPenroseVar "Id" x.toPenroseVar /- Add constraints. -/ for l in nodes do - for (x₁, x₂) in pairs l do + for (x₁, x₂) in l.consecutivePairs do addInstruction s!"Left({x₁.toPenroseVar}, {x₂.toPenroseVar})" /- Add constraints. -/ - for (l₁, l₂) in pairs nodes do + for (l₁, l₂) in nodes.consecutivePairs do if let some x₁ := l₁.head? then if let some x₂ := l₂.head? then addInstruction s!"Above({x₁.toPenroseVar}, {x₂.toPenroseVar})" diff --git a/Mathlib/Tactic/Zify.lean b/Mathlib/Tactic/Zify.lean index b3732295f8c9ee..25eb81edfa667d 100644 --- a/Mathlib/Tactic/Zify.lean +++ b/Mathlib/Tactic/Zify.lean @@ -5,7 +5,6 @@ Authors: Moritz Doll, Mario Carneiro, Robert Y. Lewis -/ module -public meta import Mathlib.Tactic.Basic public import Mathlib.Data.Int.Cast.Basic public import Mathlib.Order.Basic public meta import Mathlib.Tactic.ToAdditive diff --git a/Mathlib/Topology/Algebra/Algebra.lean b/Mathlib/Topology/Algebra/Algebra.lean index 2cfa0f29d2451e..04af38b4223ee4 100644 --- a/Mathlib/Topology/Algebra/Algebra.lean +++ b/Mathlib/Topology/Algebra/Algebra.lean @@ -235,7 +235,9 @@ theorem ext_on [T2Space B] {s : Set A} (hs : Dense (Algebra.adjoin R s : Set A)) ext fun x => eqOn_closure_adjoin h (hs x) /-- Interpret a `ContinuousAlgHom` as a `ContinuousLinearMap`. -/ -def toContinuousLinearMap (e : A →A[R] B) : A →L[R] B where toLinearMap := e.toAlgHom.toLinearMap +def toContinuousLinearMap (e : A →A[R] B) : A →L[R] B where + toLinearMap := e.toAlgHom.toLinearMap + cont := by dsimp; fun_prop @[simp] theorem coe_toContinuousLinearMap (e : A →A[R] B) : ⇑e.toContinuousLinearMap = e := rfl diff --git a/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Basic.lean b/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Basic.lean index 81fdd94a603c71..ba577d748421d4 100644 --- a/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Basic.lean +++ b/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Basic.lean @@ -231,7 +231,7 @@ def ofFiniteGrp (G : FiniteGrp) : ProfiniteGrp := @[to_additive /-- A morphism of `FiniteAddGrp` induces a morphism of the associated profinite additive groups. -/] def ofFiniteGrpHom {G H : FiniteGrp.{u}} (f : G ⟶ H) : ofFiniteGrp G ⟶ ofFiniteGrp H := - ConcreteCategory.ofHom ⟨f.hom.hom, by continuity⟩ + ConcreteCategory.ofHom ⟨f.hom.hom, by fun_prop⟩ set_option backward.privateInPublic true in set_option backward.privateInPublic.warn false in diff --git a/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Completion.lean b/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Completion.lean index 2e28e91d8a8bd0..814e936a5ae50c 100644 --- a/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Completion.lean +++ b/Mathlib/Topology/Algebra/Category/ProfiniteGrp/Completion.lean @@ -5,7 +5,8 @@ Authors: Adam Topaz -/ module -public import Mathlib.GroupTheory.FiniteIndexNormalSubgroup +public import Mathlib.Algebra.Category.Grp.EpiMono +public import Mathlib.GroupTheory.ResiduallyFinite public import Mathlib.Topology.Algebra.Category.ProfiniteGrp.Limits /-! @@ -78,6 +79,18 @@ def eta : G ⟶ GrpCat.of (completion G) := GrpCat.ofHom { map_mul' _ _ := rfl } +set_option backward.isDefEq.respectTransparency false in +theorem mono_eta_iff_residuallyFinite : Mono (eta G) ↔ Group.ResiduallyFinite G := by + rw [GrpCat.mono_iff_injective, injective_iff_map_eq_one, + Group.residuallyFinite_iff_forall_finiteIndexNormalSubgroup] + refine forall_congr' fun g ↦ imp_congr_left ?_ + rw [Subtype.ext_iff, funext_iff] + exact forall_congr' fun H ↦ QuotientGroup.eq_one_iff g + +theorem etaFn_injective_iff_residuallyFinite : + Function.Injective (etaFn G) ↔ Group.ResiduallyFinite G := + (GrpCat.mono_iff_injective (eta G)).symm.trans (mono_eta_iff_residuallyFinite G) + set_option backward.isDefEq.respectTransparency false in lemma denseRange : DenseRange (etaFn G) := by apply dense_iff_inter_open.mpr diff --git a/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean b/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean index a0418bca3a6302..a7d19908ba5858 100644 --- a/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean +++ b/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean @@ -111,7 +111,8 @@ into a `ContinuousMonoidHom`. This is declared as the default coercion from `F` `AddMonoidHomClass F A B` and `ContinuousMapClass F A B` into a `ContinuousAddMonoidHom`. This is declared as the default coercion from `F` to `ContinuousAddMonoidHom A B`. -/] def toContinuousMonoidHom [MonoidHomClass F A B] [ContinuousMapClass F A B] (f : F) : A →ₜ* B := - { MonoidHomClass.toMonoidHom f with } + { MonoidHomClass.toMonoidHom f with + continuous_toFun := by dsimp; fun_prop } /-- Any type satisfying `MonoidHomClass` and `ContinuousMapClass` can be cast into `ContinuousMonoidHom` via `ContinuousMonoidHom.toContinuousMonoidHom`. -/ diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Module.lean b/Mathlib/Topology/Algebra/InfiniteSum/Module.lean index 1d07e5a2b0ac94..e964ee24c6ada2 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Module.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Module.lean @@ -208,8 +208,7 @@ lemma MulAction.automorphize_smul_left [Group α] [MulAction α β] (f : β → MulAction.automorphize ((g ∘ (@Quotient.mk' _ (_))) • f) = g • (MulAction.automorphize f : Quotient (MulAction.orbitRel α β) → M) := by ext x - apply @Quotient.inductionOn' β (MulAction.orbitRel α β) _ x _ - intro b + induction x using Quotient.inductionOn with | _ b simp only [automorphize, Pi.smul_apply', comp_apply] set π : β → Quotient (MulAction.orbitRel α β) := Quotient.mk (MulAction.orbitRel α β) have H₁ : ∀ a : α, π (a • b) = π b := by @@ -227,8 +226,7 @@ lemma AddAction.automorphize_smul_left [AddGroup α] [AddAction α β] (f : β AddAction.automorphize ((g ∘ (@Quotient.mk' _ (_))) • f) = g • (AddAction.automorphize f : Quotient (AddAction.orbitRel α β) → M) := by ext x - apply @Quotient.inductionOn' β (AddAction.orbitRel α β) _ x _ - intro b + induction x using Quotient.inductionOn with | _ b simp only [automorphize, Pi.smul_apply', comp_apply] set π : β → Quotient (AddAction.orbitRel α β) := Quotient.mk (AddAction.orbitRel α β) have H₁ : ∀ a : α, π (a +ᵥ b) = π b := by diff --git a/Mathlib/Topology/Algebra/Module/Equiv.lean b/Mathlib/Topology/Algebra/Module/Equiv.lean index eb05d7a3087fc1..fe882749890bb1 100644 --- a/Mathlib/Topology/Algebra/Module/Equiv.lean +++ b/Mathlib/Topology/Algebra/Module/Equiv.lean @@ -33,8 +33,8 @@ structure ContinuousLinearEquiv {R : Type*} {S : Type*} [Semiring R] [Semiring S {σ' : S →+* R} [RingHomInvPair σ σ'] [RingHomInvPair σ' σ] (M : Type*) [TopologicalSpace M] [AddCommMonoid M] (M₂ : Type*) [TopologicalSpace M₂] [AddCommMonoid M₂] [Module R M] [Module S M₂] extends M ≃ₛₗ[σ] M₂ where - continuous_toFun : Continuous toFun := by continuity - continuous_invFun : Continuous invFun := by continuity + continuous_toFun : Continuous toFun := by first | fun_prop | dsimp; fun_prop + continuous_invFun : Continuous invFun := by first | fun_prop | dsimp; fun_prop attribute [inherit_doc ContinuousLinearEquiv] ContinuousLinearEquiv.continuous_toFun ContinuousLinearEquiv.continuous_invFun @@ -55,8 +55,8 @@ class ContinuousSemilinearEquivClass (F : Type*) {R : outParam Type*} {S : outPa [RingHomInvPair σ σ'] [RingHomInvPair σ' σ] (M : outParam Type*) [TopologicalSpace M] [AddCommMonoid M] (M₂ : outParam Type*) [TopologicalSpace M₂] [AddCommMonoid M₂] [Module R M] [Module S M₂] [EquivLike F M M₂] : Prop extends SemilinearEquivClass F σ M M₂ where - map_continuous : ∀ f : F, Continuous f := by continuity - inv_continuous : ∀ f : F, Continuous (EquivLike.inv f) := by continuity + map_continuous : ∀ f : F, Continuous f := by first | fun_prop | dsimp; fun_prop + inv_continuous : ∀ f : F, Continuous (EquivLike.inv f) := by first | fun_prop | dsimp; fun_prop attribute [inherit_doc ContinuousSemilinearEquivClass] ContinuousSemilinearEquivClass.map_continuous @@ -1019,6 +1019,21 @@ theorem equivOfRightInverse_symm_apply (f₁ : M →L[R] M₂) (f₂ : M₂ →L end Ring +section RestrictScalars + +/-- If M is an `R`-module and `S`-module and `R`-module structure is defined by an action of `R` on +`S` (formally, we have two scalar towers), then any `S`-linear equivalence on `M` is an `R`-linear +equivalence. -/ +@[simps! toLinearEquiv apply symm_apply] +def restrictScalars (R : Type*) {S : Type*} {M : Type*} + [Semiring R] [Semiring S] [AddCommMonoid M] [Module R M] [Module S M] [TopologicalSpace M] + [LinearMap.CompatibleSMul M M R S] (f : M ≃L[S] M) : M ≃L[R] M where + toLinearEquiv := f.toLinearEquiv.restrictScalars R + continuous_invFun := f.continuous_invFun + continuous_toFun := f.continuous_toFun + +end RestrictScalars + end ContinuousLinearEquiv namespace ContinuousLinearMap diff --git a/Mathlib/Topology/Algebra/Module/LinearMap.lean b/Mathlib/Topology/Algebra/Module/LinearMap.lean index aae3e0d848ca25..678879b33ada6a 100644 --- a/Mathlib/Topology/Algebra/Module/LinearMap.lean +++ b/Mathlib/Topology/Algebra/Module/LinearMap.lean @@ -37,7 +37,7 @@ ring `R`. -/ structure ContinuousLinearMap {R : Type*} {S : Type*} [Semiring R] [Semiring S] (σ : R →+* S) (M : Type*) [TopologicalSpace M] [AddCommMonoid M] (M₂ : Type*) [TopologicalSpace M₂] [AddCommMonoid M₂] [Module R M] [Module S M₂] extends M →ₛₗ[σ] M₂ where - cont : Continuous toFun := by continuity + cont : Continuous toFun := by fun_prop attribute [inherit_doc ContinuousLinearMap] ContinuousLinearMap.cont @@ -118,6 +118,10 @@ theorem coe_mk' (f : M₁ →ₛₗ[σ₁₂] M₂) (h) : (mk f h : M₁ → M protected theorem continuous (f : M₁ →SL[σ₁₂] M₂) : Continuous f := f.2 +@[continuity, fun_prop] +protected theorem continuous_toLinearMap (f : M₁ →SL[σ₁₂] M₂) : Continuous f.toLinearMap := + f.2 + @[simp] protected theorem uniformContinuous {E₁ E₂ : Type*} [UniformSpace E₁] [UniformSpace E₂] [AddCommGroup E₁] [AddCommGroup E₂] [Module R₁ E₁] [Module R₂ E₂] [IsUniformAddGroup E₁] diff --git a/Mathlib/Topology/Algebra/Module/StrongTopology.lean b/Mathlib/Topology/Algebra/Module/StrongTopology.lean index 898eeb05598dd0..6aa97f99b8c0ee 100644 --- a/Mathlib/Topology/Algebra/Module/StrongTopology.lean +++ b/Mathlib/Topology/Algebra/Module/StrongTopology.lean @@ -324,7 +324,7 @@ theorem tendsto_iff_tendstoUniformlyOn {ι : Type*} {p : Filter ι} [UniformSpac variable {F} in theorem isUniformInducing_postcomp - {G : Type*} [AddCommGroup G] [UniformSpace G] [IsUniformAddGroup G] + [AddCommGroup G] [UniformSpace G] [IsUniformAddGroup G] {𝕜₃ : Type*} [NormedField 𝕜₃] [Module 𝕜₃ G] {τ : 𝕜₂ →+* 𝕜₃} {ρ : 𝕜₁ →+* 𝕜₃} [RingHomCompTriple σ τ ρ] [UniformSpace F] [IsUniformAddGroup F] (g : F →SL[τ] G) (hg : IsUniformInducing g) (𝔖 : Set (Set E)) : @@ -335,7 +335,7 @@ theorem isUniformInducing_postcomp variable {F} in theorem isUniformEmbedding_postcomp - {G : Type*} [AddCommGroup G] [UniformSpace G] [IsUniformAddGroup G] + [AddCommGroup G] [UniformSpace G] [IsUniformAddGroup G] {𝕜₃ : Type*} [NormedField 𝕜₃] [Module 𝕜₃ G] {τ : 𝕜₂ →+* 𝕜₃} {ρ : 𝕜₁ →+* 𝕜₃} [RingHomCompTriple σ τ ρ] [UniformSpace F] [IsUniformAddGroup F] (g : F →SL[τ] G) (hg : IsUniformEmbedding g) (𝔖 : Set (Set E)) : @@ -372,6 +372,38 @@ theorem topologicalSpace_mono [TopologicalSpace F] [IsTopologicalAddGroup F] (h simp_rw [← uniformity_toTopologicalSpace_eq] exact UniformSpace.toTopologicalSpace_mono (uniformSpace_mono σ F h) +variable {𝕜₁ : Type*} [NontriviallyNormedField 𝕜₁] {σ : 𝕜₁ →+* 𝕜₂} [Module 𝕜₁ E] in +variable {F} in +/-- Let `𝔖` be a family of bounded subsets of `F`, and `B : E × F → G` a bilinear map. +If `B` is (jointly) continuous, then it is `𝔖`-**hypocontinuous**: +in curried form, it defines a continuous linear map `E →L[𝕜] (UniformConvergenceCLM (.id 𝕜) G 𝔖)`. + +Note that, in full generality, the converse is not true. +See also `ContinuousLinearMap.continuous_of_continuous_uncurry`. -/ +protected theorem continuous_of_continuous_uncurry [AddCommGroup G] + {𝕜₃ : Type*} [NormedField 𝕜₃] [Module 𝕜₃ G] + {τ : 𝕜₃ →+* 𝕜₂} [RingHomSurjective τ] + [TopologicalSpace F] [IsTopologicalAddGroup F] [ContinuousConstSMul 𝕜₂ F] + [TopologicalSpace G] [IsTopologicalAddGroup G] [ContinuousConstSMul 𝕜₃ G] + {𝔖 : Set (Set E)} (h𝔖 : ∀ s ∈ 𝔖, IsVonNBounded 𝕜₁ s) + (B : G →ₛₗ[τ] (UniformConvergenceCLM σ F 𝔖)) + (hB : Continuous (fun p : G × E ↦ B p.1 p.2)) : + Continuous B := by + apply continuous_of_tendsto_nhds_zero + suffices ∀ s ∈ 𝔖, ∀ U ∈ 𝓝 0, ∀ᶠ (g : G) in 𝓝 0, ∀ e ∈ s, B g e ∈ U by + simpa [UniformConvergenceCLM.nhds_zero_eq, MapsTo] + intro S hS U hU + rcases mem_nhds_prod_iff.mp <| hB.tendsto' (0 : G × E) 0 (by simp) hU + with ⟨V, hV, W, hW, hVW⟩ + rcases (h𝔖 S hS) hW |>.eventually_nhdsNE_zero.and eventually_mem_nhdsWithin |>.exists with + ⟨c, hc, c_ne : c ≠ 0⟩ + rcases RingHom.surjective τ (σ c) with ⟨d, hd⟩ + have d_ne : d ≠ 0 := by rwa [← map_ne_zero τ, hd, map_ne_zero σ] + filter_upwards [(set_smul_mem_nhds_zero_iff d_ne).mpr hV] + rintro _ ⟨a, ha, rfl⟩ x hx + rw [map_smulₛₗ, hd, UniformConvergenceCLM.smul_apply, ← map_smulₛₗ] + exact @hVW ⟨_, _⟩ ⟨ha, hc hx⟩ + section Equiv variable [TopologicalSpace F] [IsTopologicalAddGroup F] [ContinuousConstSMul 𝕜₂ F] (𝔖 : Set (Set E)) @@ -628,6 +660,21 @@ lemma toUniformConvergenceCLM_continuous [IsTopologicalAddGroup F] Continuous (ContinuousLinearMap.toUniformConvergenceCLM σ F 𝔖) := continuous_id_of_le <| UniformConvergenceCLM.topologicalSpace_mono _ _ h +/-- A bilinear map `B : E × F → G` which is (jointly) continuous is **hypocontinuous**: +in curried form, it defines a continuous linear map `E →L[𝕜] F →L[𝕜] G`. + +In the normed setting, the converse is true, see `ContinuousLinearMap.continuous₂`. +In general, however, hypocontinuity is a strictly weaker condition than joint continuity. -/ +theorem continuous_of_continuous_uncurry + {𝕜₁ : Type*} [NontriviallyNormedField 𝕜₁] {σ : 𝕜₁ →+* 𝕜₂} [Module 𝕜₁ E] + {τ : 𝕜₃ →+* 𝕜₂} [RingHomSurjective τ] + [IsTopologicalAddGroup G] [ContinuousConstSMul 𝕜₃ G] + [IsTopologicalAddGroup F] [ContinuousConstSMul 𝕜₂ F] + (B : G →ₛₗ[τ] (E →SL[σ] F)) + (hB : Continuous (fun p : G × E ↦ B p.1 p.2)) : + Continuous B := + UniformConvergenceCLM.continuous_of_continuous_uncurry (fun _ ↦ id) B hB + end BoundedSets section BilinearMaps @@ -830,19 +877,8 @@ variable {𝕜 E : Type*} [NontriviallyNormedField 𝕜] [AddCommGroup E] [Modul @[simps!] def toSpanSingletonCLE : E ≃L[𝕜] (𝕜 →L[𝕜] E) where toLinearEquiv := toSpanSingletonLE .. - continuous_toFun := by - apply continuous_of_tendsto_nhds_zero (toSpanSingletonLE _ _ _) - suffices ∀ s : Set 𝕜, IsVonNBounded 𝕜 s → ∀ U ∈ 𝓝 0, ∀ᶠ (a : E) in 𝓝 0, ∀ x ∈ s, x • a ∈ U by - simpa [ContinuousLinearMap.nhds_zero_eq, MapsTo] - intro s hsb U hU - rcases mem_nhds_prod_iff.mp <| continuous_smul.tendsto' (0 : 𝕜 × E) 0 (by simp) hU - with ⟨V, hV, W, hW, hVW⟩ - rcases (eventually_cobounded_mapsTo <| hsb hV).and (eventually_ne_cobounded 0) |>.exists - with ⟨c, hc, hc₀⟩ - filter_upwards [(set_smul_mem_nhds_zero_iff <| inv_ne_zero hc₀).mpr hW] - rintro _ ⟨a, ha, rfl⟩ x hx - rw [smul_comm x c⁻¹, ← smul_assoc] - exact @hVW (_, _) ⟨hc hx, ha⟩ + continuous_toFun := continuous_of_continuous_uncurry _ <| + continuous_snd.smul continuous_fst continuous_invFun := continuous_eval_const 1 end ContinuousLinearMap diff --git a/Mathlib/Topology/Algebra/SeparationQuotient/Basic.lean b/Mathlib/Topology/Algebra/SeparationQuotient/Basic.lean index 3e21dbd2feef47..20e0f6b22a9016 100644 --- a/Mathlib/Topology/Algebra/SeparationQuotient/Basic.lean +++ b/Mathlib/Topology/Algebra/SeparationQuotient/Basic.lean @@ -399,6 +399,7 @@ noncomputable def liftCLM {σ : R →+* S} (f : M →SL[σ] N) (hf : ∀ x y, In toFun := SeparationQuotient.lift f hf map_add' := Quotient.ind₂ <| map_add f map_smul' {r} := Quotient.ind <| map_smulₛₗ f r + cont := by continuity @[simp] theorem liftCLM_mk {σ : R →+* S} (f : M →SL[σ] N) (hf : ∀ x y, Inseparable x y → f x = f y) diff --git a/Mathlib/Topology/Algebra/SeparationQuotient/Section.lean b/Mathlib/Topology/Algebra/SeparationQuotient/Section.lean index cd6d39e3c3685c..f7b3a297855f13 100644 --- a/Mathlib/Topology/Algebra/SeparationQuotient/Section.lean +++ b/Mathlib/Topology/Algebra/SeparationQuotient/Section.lean @@ -79,7 +79,7 @@ variable (K E : Type*) [DivisionRing K] [AddCommGroup E] [Module K E] [UniformSpace E] [IsUniformAddGroup E] [ContinuousConstSMul K E] theorem outCLM_isUniformInducing : IsUniformInducing (outCLM K E) := by - rw [← isUniformInducing_mk.isUniformInducing_comp_iff, mk_comp_outCLM] + rw [← isUniformInducing_mk.of_comp_iff, mk_comp_outCLM] exact .id theorem outCLM_isUniformEmbedding : IsUniformEmbedding (outCLM K E) where diff --git a/Mathlib/Topology/Algebra/Valued/WithVal.lean b/Mathlib/Topology/Algebra/Valued/WithVal.lean index e2287e192c7d48..ec8facf7bd1c98 100644 --- a/Mathlib/Topology/Algebra/Valued/WithVal.lean +++ b/Mathlib/Topology/Algebra/Valued/WithVal.lean @@ -188,7 +188,6 @@ section CommRing variable [CommRing R] (v : Valuation R Γ₀) -set_option backward.isDefEq.respectTransparency false in instance : CommRing (WithVal v) := fast_instance% (equiv v).commRing instance : ValuativeRel (WithVal v) := .ofValuation (valuation v) @@ -318,10 +317,8 @@ section Field variable [Field R] (v : Valuation R Γ₀) -set_option backward.isDefEq.respectTransparency false in instance : Field (WithVal v) := fast_instance% (equiv v).field -set_option backward.isDefEq.respectTransparency false in instance [NumberField R] : NumberField (WithVal v) where @[simp] lemma toVal_div (x y : R) : toVal v (x / y) = toVal v x / toVal v y := rfl diff --git a/Mathlib/Topology/Category/LightProfinite/AsLimit.lean b/Mathlib/Topology/Category/LightProfinite/AsLimit.lean index 8e47a96ff8ef2b..86129668f74a34 100644 --- a/Mathlib/Topology/Category/LightProfinite/AsLimit.lean +++ b/Mathlib/Topology/Category/LightProfinite/AsLimit.lean @@ -60,7 +60,6 @@ def asLimitAux : IsLimit S.asLimitConeAux := S.toLightDiagram.isLimit.ofIsoLimit S.isoMapCone.symm isLimitOfReflects lightToProfinite hc -set_option backward.isDefEq.respectTransparency false in /-- A cone over `S.diagram` whose cone point is `S`. -/ def asLimitCone : Cone S.diagram where pt := S diff --git a/Mathlib/Topology/Category/Profinite/CofilteredLimit.lean b/Mathlib/Topology/Category/Profinite/CofilteredLimit.lean index 4606b701404f4e..9b09b85cd308de 100644 --- a/Mathlib/Topology/Category/Profinite/CofilteredLimit.lean +++ b/Mathlib/Topology/Category/Profinite/CofilteredLimit.lean @@ -50,7 +50,7 @@ theorem exists_isClopen_of_cofiltered {U : Set C.pt} (hC : IsLimit C) (hU : IsCl change TopologicalSpace.IsTopologicalBasis {W : Set (F.obj i) | IsClopen W} apply isTopologicalBasis_isClopen · rintro i j f V (hV : IsClopen _) - refine ⟨hV.1.preimage ?_, hV.2.preimage ?_⟩ <;> continuity + refine ⟨hV.1.preimage ?_, hV.2.preimage ?_⟩ <;> fun_prop -- Using this, since `U` is open, we can write `U` as a union of clopen sets all of which -- are preimages of clopens from the factors in the limit. obtain ⟨S, hS, h⟩ := hB.open_eq_sUnion hU.2 diff --git a/Mathlib/Topology/Category/TopCat/Limits/Products.lean b/Mathlib/Topology/Category/TopCat/Limits/Products.lean index 09dca0ba48e68a..06bbd410349680 100644 --- a/Mathlib/Topology/Category/TopCat/Limits/Products.lean +++ b/Mathlib/Topology/Category/TopCat/Limits/Products.lean @@ -230,7 +230,7 @@ end Prod /-- The binary coproduct cofan in `TopCat`. -/ protected def binaryCofan (X Y : TopCat.{u}) : BinaryCofan X Y := - BinaryCofan.mk (ofHom ⟨Sum.inl, by continuity⟩) (ofHom ⟨Sum.inr, by continuity⟩) + BinaryCofan.mk (ofHom ⟨Sum.inl, by fun_prop⟩) (ofHom ⟨Sum.inr, by fun_prop⟩) /-- The constructed binary coproduct cofan in `TopCat` is the coproduct. -/ def binaryCofanIsColimit (X Y : TopCat.{u}) : IsColimit (TopCat.binaryCofan X Y) := by diff --git a/Mathlib/Topology/Category/TopCat/OpenNhds.lean b/Mathlib/Topology/Category/TopCat/OpenNhds.lean index d07e60155e5bd8..b49b50a781b108 100644 --- a/Mathlib/Topology/Category/TopCat/OpenNhds.lean +++ b/Mathlib/Topology/Category/TopCat/OpenNhds.lean @@ -47,6 +47,8 @@ variable {x : X} {U V W : OpenNhds x} instance partialOrder (x : X) : PartialOrder (OpenNhds x) := inferInstanceAs (PartialOrder { U : Opens X // x ∈ U }) +theorem le_def (U V : OpenNhds x) : U ≤ V ↔ U.1 ≤ V.1 := Iff.rfl + instance (x : X) : Lattice (OpenNhds x) := { inf := fun U V => ⟨U.1 ⊓ V.1, ⟨U.2, V.2⟩⟩ le_inf := fun U V W => @le_inf _ _ U.1.1 V.1.1 W.1.1 @@ -59,7 +61,9 @@ instance (x : X) : Lattice (OpenNhds x) := instance (x : X) : OrderTop (OpenNhds x) where top := ⟨⊤, trivial⟩ - le_top _ := by simp [LE.le] + le_top x := by + cases x + simp [le_def] instance (x : X) : Inhabited (OpenNhds x) := ⟨⊤⟩ diff --git a/Mathlib/Topology/Category/TopCat/ULift.lean b/Mathlib/Topology/Category/TopCat/ULift.lean index 8db1c01fc7ade9..8e584508bacac7 100644 --- a/Mathlib/Topology/Category/TopCat/ULift.lean +++ b/Mathlib/Topology/Category/TopCat/ULift.lean @@ -58,7 +58,7 @@ def uliftFunctorCompForgetIso : uliftFunctor.{v, u} ⋙ forget TopCat.{max u v} /-- The `ULift` functor on categories of topological spaces is fully faithful. -/ def uliftFunctorFullyFaithful : uliftFunctor.{v, u}.FullyFaithful where - preimage f := ofHom ⟨ULift.down ∘ f ∘ ULift.up, by continuity⟩ + preimage f := ofHom ⟨ULift.down ∘ f ∘ ULift.up, by fun_prop⟩ instance : uliftFunctor.{v, u}.Full := uliftFunctorFullyFaithful.full diff --git a/Mathlib/Topology/Compactness/Compact.lean b/Mathlib/Topology/Compactness/Compact.lean index 56b38d9d613411..2a3b92c151dbed 100644 --- a/Mathlib/Topology/Compactness/Compact.lean +++ b/Mathlib/Topology/Compactness/Compact.lean @@ -539,7 +539,7 @@ theorem isCompact_generateFrom [T : TopologicalSpace X] have hSF : ∀ x ∈ s, ∃ t, x ∈ t ∧ t ∈ S ∧ t ∉ F := by simpa [nhds_generateFrom] using hF choose! U hxU hSU hUF using hSF obtain ⟨Q, hQU, hQ, hsQ⟩ := h (U '' s) (by simpa [Set.subset_def]) - (fun x hx ↦ Set.mem_sUnion_of_mem (hxU _ hx) (by aesop)) + (fun x hx ↦ Set.mem_sUnion_of_mem (hxU _ hx) (by grind)) have : ∀ s ∈ Q, s ∉ F := fun s hsQ ↦ (hQU hsQ).choose_spec.2 ▸ hUF _ (hQU hsQ).choose_spec.1 have hQF : ⋂₀ (compl '' Q) ∈ F.sets := by simpa [Filter.biInter_mem hQ, F.compl_mem_iff_notMem] have : ⋃₀ Q ∉ F := by diff --git a/Mathlib/Topology/ContinuousMap/Algebra.lean b/Mathlib/Topology/ContinuousMap/Algebra.lean index 2c1d8bf8cda483..4ea423a587f40c 100644 --- a/Mathlib/Topology/ContinuousMap/Algebra.lean +++ b/Mathlib/Topology/ContinuousMap/Algebra.lean @@ -742,7 +742,6 @@ def Set.SeparatesPointsStrongly (s : Set C(α, 𝕜)) : Prop := variable [Field 𝕜] [IsTopologicalRing 𝕜] -set_option backward.isDefEq.respectTransparency false in /-- Working in continuous functions into a topological field, a subalgebra of functions that separates points also separates points strongly. diff --git a/Mathlib/Topology/ContinuousMap/Basic.lean b/Mathlib/Topology/ContinuousMap/Basic.lean index f7bfaa95f78196..f9aee2b0b3522a 100644 --- a/Mathlib/Topology/ContinuousMap/Basic.lean +++ b/Mathlib/Topology/ContinuousMap/Basic.lean @@ -219,6 +219,7 @@ each term. This is `Sigma.uncurry` for continuous maps. @[simps] def sigma (f : ∀ i, C(X i, A)) : C((Σ i, X i), A) where toFun ig := f ig.fst ig.snd + continuous_toFun := by continuity variable (A X) in /-- diff --git a/Mathlib/Topology/ContinuousMap/Defs.lean b/Mathlib/Topology/ContinuousMap/Defs.lean index fd9c5a033f8a98..b04f1a021bfac3 100644 --- a/Mathlib/Topology/ContinuousMap/Defs.lean +++ b/Mathlib/Topology/ContinuousMap/Defs.lean @@ -34,7 +34,7 @@ structure ContinuousMap (X Y : Type*) [TopologicalSpace X] [TopologicalSpace Y] /-- The function `X → Y` -/ protected toFun : X → Y /-- Proposition that `toFun` is continuous -/ - protected continuous_toFun : Continuous toFun := by continuity + protected continuous_toFun : Continuous toFun := by fun_prop /-- `C(X, Y)` is the type of continuous maps from `X` to `Y`. -/ notation "C(" X ", " Y ")" => ContinuousMap X Y diff --git a/Mathlib/Topology/Defs/Filter.lean b/Mathlib/Topology/Defs/Filter.lean index 0be587a14e8a85..7b96de027f3295 100644 --- a/Mathlib/Topology/Defs/Filter.lean +++ b/Mathlib/Topology/Defs/Filter.lean @@ -244,12 +244,12 @@ section Lim /-- If `f` is a filter, then `Filter.lim f` is a limit of the filter, if it exists. -/ -noncomputable def lim [Nonempty X] (f : Filter X) : X := +noncomputable def Filter.lim [Nonempty X] (f : Filter X) : X := Classical.epsilon fun x => f ≤ 𝓝 x -/-- If `f` is a filter in `α` and `g : α → X` is a function, then `limUnder f g` is a limit of `g` -at `f`, if it exists. -/ -noncomputable def limUnder {α : Type*} [Nonempty X] (f : Filter α) (g : α → X) : X := +/-- If `f` is a filter in `α` and `g : α → X` is a function, then `Filter.limUnder f g` is a limit +of `g` at `f`, if it exists. -/ +noncomputable def Filter.limUnder {α : Type*} [Nonempty X] (f : Filter α) (g : α → X) : X := lim (f.map g) end Lim diff --git a/Mathlib/Topology/FiberPartition.lean b/Mathlib/Topology/FiberPartition.lean index a6b0d28cd536a1..54603bfbbacf12 100644 --- a/Mathlib/Topology/FiberPartition.lean +++ b/Mathlib/Topology/FiberPartition.lean @@ -34,6 +34,7 @@ variable [TopologicalSpace S] @[simps apply] def sigmaIsoHom : C((x : Fiber f) × x.val, S) where toFun | ⟨a, x⟩ => x.val + continuous_toFun := by continuity lemma sigmaIsoHom_inj : Function.Injective (sigmaIsoHom f) := by rintro ⟨⟨_, _, rfl⟩, ⟨_, hx⟩⟩ ⟨⟨_, _, rfl⟩, ⟨_, hy⟩⟩ h diff --git a/Mathlib/Topology/Homotopy/Basic.lean b/Mathlib/Topology/Homotopy/Basic.lean index 4f3ebd06f2f0fc..4b461a4d91c552 100644 --- a/Mathlib/Topology/Homotopy/Basic.lean +++ b/Mathlib/Topology/Homotopy/Basic.lean @@ -69,7 +69,7 @@ namespace ContinuousMap /-- `ContinuousMap.Homotopy f₀ f₁` is the type of homotopies from `f₀` to `f₁`. -When possible, instead of parametrizing results over `(f : Homotopy f₀ f₁)`, +When possible, instead of parametrizing results over `(f : ContinuousMap.Homotopy f₀ f₁)`, you should parametrize over `{F : Type*} [HomotopyLike F f₀ f₁] (f : F)`. When you extend this structure, make sure to extend `ContinuousMap.HomotopyLike`. -/ @@ -190,7 +190,8 @@ protected theorem congr_arg (F : Homotopy f₀ f₁) {x y : I × X} (h : x = y) end -/-- Given a continuous function `f`, we can define a `Homotopy f f` by `F (t, x) = f x` +/-- Given a continuous function `f`, we can define a `ContinuousMap.Homotopy f f` by +`F (t, x) = f x` -/ @[simps] def refl (f : C(X, Y)) : Homotopy f f where @@ -201,7 +202,8 @@ def refl (f : C(X, Y)) : Homotopy f f where instance : Inhabited (Homotopy (ContinuousMap.id X) (ContinuousMap.id X)) := ⟨Homotopy.refl _⟩ -/-- Given a `Homotopy f₀ f₁`, we can define a `Homotopy f₁ f₀` by reversing the homotopy. +/-- Given a `ContinuousMap.Homotopy f₀ f₁`, we can define a `ContinuousMap.Homotopy f₁ f₀` by +reversing the homotopy. -/ @[simps] def symm {f₀ f₁ : C(X, Y)} (F : Homotopy f₀ f₁) : Homotopy f₁ f₀ where @@ -219,8 +221,9 @@ theorem symm_bijective {f₀ f₁ : C(X, Y)} : Function.bijective_iff_has_inverse.mpr ⟨_, symm_symm, symm_symm⟩ /-- -Given `Homotopy f₀ f₁` and `Homotopy f₁ f₂`, we can define a `Homotopy f₀ f₂` by putting the first -homotopy on `[0, 1/2]` and the second on `[1/2, 1]`. +Given `ContinuousMap.Homotopy f₀ f₁` and `ContinuousMap.Homotopy f₁ f₂`, we can define a +`ContinuousMap.Homotopy f₀ f₂` by putting the first homotopy on `[0, 1/2]` and the second +on `[1/2, 1]`. -/ def trans {f₀ f₁ f₂ : C(X, Y)} (F : Homotopy f₀ f₁) (G : Homotopy f₁ f₂) : Homotopy f₀ f₂ where toFun x := if (x.1 : ℝ) ≤ 1 / 2 then F.extend (2 * x.1) x.2 else G.extend (2 * x.1 - 1) x.2 @@ -261,7 +264,8 @@ theorem symm_trans {f₀ f₁ f₂ : C(X, Y)} (F : Homotopy f₀ f₁) (G : Homo · exfalso linarith -/-- Casting a `Homotopy f₀ f₁` to a `Homotopy g₀ g₁` where `f₀ = g₀` and `f₁ = g₁`. +/-- Casting a `ContinuousMap.Homotopy f₀ f₁` to a `ContinuousMap.Homotopy g₀ g₁` where `f₀ = g₀` +and `f₁ = g₁`. -/ @[simps] def cast {f₀ f₁ g₀ g₁ : C(X, Y)} (F : Homotopy f₀ f₁) (h₀ : f₀ = g₀) (h₁ : f₁ = g₁) : @@ -270,8 +274,8 @@ def cast {f₀ f₁ g₀ g₁ : C(X, Y)} (F : Homotopy f₀ f₁) (h₀ : f₀ = map_zero_left := by simp [← h₀] map_one_left := by simp [← h₁] -/-- If we have a `Homotopy g₀ g₁` and a `Homotopy f₀ f₁`, then we can compose them and get a -`Homotopy (g₀.comp f₀) (g₁.comp f₁)`. +/-- If we have a `ContinuousMap.Homotopy g₀ g₁` and a `ContinuousMap.Homotopy f₀ f₁`, then we can +compose them and get a `ContinuousMap.Homotopy (g₀.comp f₀) (g₁.comp f₁)`. -/ @[simps] def comp {f₀ f₁ : C(X, Y)} {g₀ g₁ : C(Y, Z)} (G : Homotopy g₀ g₁) (F : Homotopy f₀ f₁) : @@ -280,8 +284,8 @@ def comp {f₀ f₁ : C(X, Y)} {g₀ g₁ : C(Y, Z)} (G : Homotopy g₀ g₁) (F map_zero_left := by simp map_one_left := by simp -/-- Composition of a `Homotopy g₀ g₁` and `f : C(X, Y)` as a homotopy between `g₀.comp f` and -`g₁.comp f`. -/ +/-- Composition of a `ContinuousMap.Homotopy g₀ g₁` and `f : C(X, Y)` as a homotopy between +`g₀.comp f` and `g₁.comp f`. -/ @[simps!] def compContinuousMap {g₀ g₁ : C(Y, Z)} (G : Homotopy g₀ g₁) (f : C(X, Y)) : Homotopy (g₀.comp f) (g₁.comp f) := @@ -322,7 +326,7 @@ protected def piMap {X Y : ι → Type*} [∀ i, TopologicalSpace (X i)] [∀ i, end Homotopy /-- Given continuous maps `f₀` and `f₁`, we say `f₀` and `f₁` are homotopic if there exists a -`Homotopy f₀ f₁`. +`ContinuousMap.Homotopy f₀ f₁`. -/ def Homotopic (f₀ f₁ : C(X, Y)) : Prop := Nonempty (Homotopy f₀ f₁) diff --git a/Mathlib/Topology/MetricSpace/Pseudo/Defs.lean b/Mathlib/Topology/MetricSpace/Pseudo/Defs.lean index e0d3373e8ad282..5ba5ca04ce4bae 100644 --- a/Mathlib/Topology/MetricSpace/Pseudo/Defs.lean +++ b/Mathlib/Topology/MetricSpace/Pseudo/Defs.lean @@ -1141,6 +1141,9 @@ theorem Real.Icc_eq_closedBall (x y : ℝ) : Icc x y = closedBall ((x + y) / 2) rw [Real.closedBall_eq_Icc, ← sub_div, add_comm, ← sub_add, add_sub_cancel_left, add_self_div_two, ← add_div, add_assoc, add_sub_cancel, add_self_div_two] +lemma Real.sphere_eq_pair (x : ℝ) {r : ℝ} (hr : 0 ≤ r) : sphere x r = {x - r, x + r} := by + ext; simp [dist_eq]; grind + theorem Metric.uniformity_eq_comap_nhds_zero : 𝓤 α = comap (fun p : α × α => dist p.1 p.2) (𝓝 (0 : ℝ)) := by ext s diff --git a/Mathlib/Topology/Order/Hom/Esakia.lean b/Mathlib/Topology/Order/Hom/Esakia.lean index 35eb6faf849c9a..a06bcabc694e24 100644 --- a/Mathlib/Topology/Order/Hom/Esakia.lean +++ b/Mathlib/Topology/Order/Hom/Esakia.lean @@ -55,7 +55,7 @@ section You should extend this class when you extend `PseudoEpimorphism`. -/ class PseudoEpimorphismClass (F : Type*) (α β : outParam Type*) [Preorder α] [Preorder β] [FunLike F α β] : Prop - extends RelHomClass F ((· ≤ ·) : α → α → Prop) ((· ≤ ·) : β → β → Prop) where + extends OrderHomClass F α β where exists_map_eq_of_map_le (f : F) ⦃a : α⦄ ⦃b : β⦄ : f a ≤ b → ∃ c, a ≤ c ∧ f c = b /-- `EsakiaHomClass F α β` states that `F` is a type of lattice morphisms. diff --git a/Mathlib/Topology/Sets/CompactOpenCovered.lean b/Mathlib/Topology/Sets/CompactOpenCovered.lean index f91e918c54fe46..047f37915ffcfc 100644 --- a/Mathlib/Topology/Sets/CompactOpenCovered.lean +++ b/Mathlib/Topology/Sets/CompactOpenCovered.lean @@ -111,7 +111,7 @@ lemma of_isCompact_of_forall_exists_isCompactOpenCovered [TopologicalSpace S] {U refine of_biUnion_eq_of_isCompact hU { Us x h | (x : S) (h : x ∈ U) } ?_ ?_ · refine subset_antisymm (fun x ↦ ?_) fun x hx ↦ ?_ · simp [Opens.forall] - aesop + grind · simpa using ⟨⟨Us x hx, hUo _ _⟩, ⟨x, by simpa⟩, hUx _ _⟩ · grind diff --git a/Mathlib/Topology/Sheaves/Skyscraper.lean b/Mathlib/Topology/Sheaves/Skyscraper.lean index 31d17be71129b7..2665ac95fc7aa4 100644 --- a/Mathlib/Topology/Sheaves/Skyscraper.lean +++ b/Mathlib/Topology/Sheaves/Skyscraper.lean @@ -298,7 +298,6 @@ lemma germ_fromStalk {𝓕 : Presheaf C X} {c : C} (f : 𝓕 ⟶ skyscraperPresh 𝓕.germ U p₀ hU ≫ fromStalk p₀ f = f.app (op U) ≫ eqToHom (if_pos hU) := colimit.ι_desc _ _ -set_option backward.isDefEq.respectTransparency false in theorem to_skyscraper_fromStalk {𝓕 : Presheaf C X} {c : C} (f : 𝓕 ⟶ skyscraperPresheaf p₀ c) : toSkyscraperPresheaf p₀ (fromStalk _ f) = f := by apply NatTrans.ext diff --git a/Mathlib/Topology/UniformSpace/Closeds.lean b/Mathlib/Topology/UniformSpace/Closeds.lean index c0690ba8398c76..64aca9a8f9a785 100644 --- a/Mathlib/Topology/UniformSpace/Closeds.lean +++ b/Mathlib/Topology/UniformSpace/Closeds.lean @@ -425,7 +425,7 @@ instance : T0Space (Closeds α) := by exact ⟨(x, y), hxy, y, rfl, hy⟩ theorem isUniformInducing_closure : IsUniformInducing (Closeds.closure (α := α)) := - isUniformEmbedding_coe.isUniformInducing_comp_iff.mp + isUniformEmbedding_coe.isUniformInducing.of_comp_iff.mp UniformSpace.hausdorff.isUniformInducing_closure theorem uniformContinuous_closure : UniformContinuous (Closeds.closure (α := α)) := diff --git a/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean b/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean index cfc0576c0ffc83..59c35a54a8d7ea 100644 --- a/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean +++ b/Mathlib/Topology/UniformSpace/UniformConvergenceTopology.lean @@ -1187,13 +1187,13 @@ theorem UniformContinuousOn.comp_tendstoUniformly_eventually let F' : ι → α → β := fun i x => if i ∈ s' then F i x else f x have hF : F =ᶠ[p] F' := by rw [eventuallyEq_iff_exists_mem] - refine ⟨s', hs', fun y hy => by aesop⟩ + refine ⟨s', hs', fun y hy => by grind⟩ have h' : TendstoUniformly F' f p := by rwa [tendstoUniformly_congr hF] at h apply (tendstoUniformly_congr _).mpr - (UniformContinuousOn.comp_tendstoUniformly (by aesop) hf hg h') + (UniformContinuousOn.comp_tendstoUniformly (by grind) hf hg h') rw [eventuallyEq_iff_exists_mem] - refine ⟨s', hs', fun i hi => by aesop⟩ + refine ⟨s', hs', fun i hi => by grind⟩ theorem UniformContinuousOn.comp_tendstoUniformlyOn_eventually {t : Set α} (hF : ∀ᶠ i in p, ∀ x ∈ t, F i x ∈ s) (hf : ∀ x ∈ t, f x ∈ s) diff --git a/Mathlib/Topology/UniformSpace/UniformEmbedding.lean b/Mathlib/Topology/UniformSpace/UniformEmbedding.lean index f5fa76e161f419..b5e36e009fe392 100644 --- a/Mathlib/Topology/UniformSpace/UniformEmbedding.lean +++ b/Mathlib/Topology/UniformSpace/UniformEmbedding.lean @@ -89,9 +89,8 @@ theorem IsUniformInducing.uniformContinuous_iff {f : α → β} {g : β → γ} dsimp only [UniformContinuous, Tendsto] simp only [← hg.comap_uniformity, ← map_le_iff_le_comap, Filter.map_map, Function.comp_def] -protected theorem IsUniformInducing.isUniformInducing_comp_iff {f : α → β} {g : β → γ} - (hg : IsUniformInducing g) : IsUniformInducing (g ∘ f) ↔ IsUniformInducing f := by - simp only [isUniformInducing_iff, ← hg.comap_uniformity, comap_comap, Function.comp_def] +@[deprecated (since := "2026-03-17")] +alias IsUniformInducing.isUniformInducing_comp_iff := IsUniformInducing.of_comp_iff theorem IsUniformInducing.uniformContinuousOn_iff {f : α → β} {g : β → γ} {S : Set α} (hg : IsUniformInducing g) : @@ -162,6 +161,10 @@ theorem IsUniformEmbedding.of_comp_iff {g : β → γ} (hg : IsUniformEmbedding IsUniformEmbedding (g ∘ f) ↔ IsUniformEmbedding f := by simp_rw [isUniformEmbedding_iff, hg.isUniformInducing.of_comp_iff, hg.injective.of_comp_iff f] +theorem IsUniformEmbedding.of_comp {f : α → β} {g : β → γ} (hf : UniformContinuous f) + (hg : UniformContinuous g) (hgf : IsUniformEmbedding (g ∘ f)) : IsUniformEmbedding f := + ⟨.of_comp hf hg hgf.isUniformInducing, .of_comp hgf.injective⟩ + theorem Equiv.isUniformEmbedding {α β : Type*} [UniformSpace α] [UniformSpace β] (f : α ≃ β) (h₁ : UniformContinuous f) (h₂ : UniformContinuous f.symm) : IsUniformEmbedding f := isUniformEmbedding_iff'.2 ⟨f.injective, h₁, by rwa [← Equiv.prodCongr_apply, ← map_equiv_symm]⟩ @@ -521,7 +524,7 @@ theorem UniformContinuous.rangeFactorization {f : α → β} (hf : UniformContin @[simp] theorem isUniformInducing_rangeFactorization_iff {f : α → β} : IsUniformInducing (rangeFactorization f) ↔ IsUniformInducing f := - (isUniformInducing_val (range f)).isUniformInducing_comp_iff.symm + (isUniformInducing_val (range f)).of_comp_iff.symm theorem IsUniformInducing.rangeFactorization {f : α → β} (hf : IsUniformInducing f) : IsUniformInducing (rangeFactorization f) := @@ -592,7 +595,7 @@ lemma IsDenseInducing.isUniformInducing_extend {γ : Type*} [UniformSpace γ] funext x simpa using (hid.inseparable_extend h.uniformContinuous.continuous.continuousAt) suffices Subtype.val ∘ fwd = SeparationQuotient.mk ∘ hid.extend f by - rw [← SeparationQuotient.isUniformInducing_mk.isUniformInducing_comp_iff, ← this] + rw [← SeparationQuotient.isUniformInducing_mk.of_comp_iff, ← this] exact (isUniformInducing_val _).comp hfu rw [← coe_comp_rangeFactorization (SeparationQuotient.mk ∘ hid.extend f), ← val_comp_inclusion hrr, Function.comp_assoc, Subtype.val_injective.comp_left.eq_iff] diff --git a/MathlibTest/CalcQuestionMark.lean b/MathlibTest/CalcQuestionMark.lean index fe6a24e0e75d76..42ce4d7f8ddd2c 100644 --- a/MathlibTest/CalcQuestionMark.lean +++ b/MathlibTest/CalcQuestionMark.lean @@ -1,3 +1,4 @@ +module import Mathlib.Tactic.Widget.Calc /-! diff --git a/MathlibTest/ComputeDegree.lean b/MathlibTest/ComputeDegree.lean index 5c7ba4841a8fb9..28b41f2a3180df 100644 --- a/MathlibTest/ComputeDegree.lean +++ b/MathlibTest/ComputeDegree.lean @@ -1,3 +1,4 @@ +module import Mathlib.Tactic.ComputeDegree open Polynomial diff --git a/MathlibTest/DeriveFintype.lean b/MathlibTest/DeriveFintype.lean index c4cc532c0516ef..9e18b7a194c081 100644 --- a/MathlibTest/DeriveFintype.lean +++ b/MathlibTest/DeriveFintype.lean @@ -1,3 +1,4 @@ +module import Mathlib.Tactic.DeriveFintype import Mathlib.Data.Fintype.Prod import Mathlib.Data.Fintype.Pi diff --git a/MathlibTest/ExistsI.lean b/MathlibTest/ExistsI.lean index 3e09714e23cec5..2759a260aa6fba 100644 --- a/MathlibTest/ExistsI.lean +++ b/MathlibTest/ExistsI.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Moritz Doll. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Moritz Doll -/ - +module import Mathlib.Tactic.ExistsI example : ∃ x : Nat, x = x := by diff --git a/MathlibTest/GalNotation.lean b/MathlibTest/GalNotation.lean index 2a79f81b270250..7f404d5010988d 100644 --- a/MathlibTest/GalNotation.lean +++ b/MathlibTest/GalNotation.lean @@ -3,6 +3,7 @@ Copyright (c) 2025 Andrew Yang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ +module import Mathlib.FieldTheory.Galois.Notation import Mathlib.Algebra.Field.Rat import Mathlib.Algebra.Field.ULift diff --git a/MathlibTest/Group.lean b/MathlibTest/Group.lean index 6cbf7b1a410df8..f3ea48efc052a1 100644 --- a/MathlibTest/Group.lean +++ b/MathlibTest/Group.lean @@ -1,3 +1,4 @@ +module import Mathlib.Tactic.Group variable {G : Type} [Group G] diff --git a/MathlibTest/Have.lean b/MathlibTest/Have.lean index 9911ab70d1d520..7d74be3a35ea1d 100644 --- a/MathlibTest/Have.lean +++ b/MathlibTest/Have.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Arthur Paulino. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Arthur Paulino -/ +module import Mathlib.Tactic.Have example : Nat := by diff --git a/MathlibTest/Inhabit.lean b/MathlibTest/Inhabit.lean index 009ff821059760..5d7c980ac3fa90 100644 --- a/MathlibTest/Inhabit.lean +++ b/MathlibTest/Inhabit.lean @@ -1,3 +1,4 @@ +module import Mathlib.Tactic.Inhabit namespace InhabitTests diff --git a/MathlibTest/Qify.lean b/MathlibTest/Qify.lean index f37e63804a3a2e..fa5ac123a27321 100644 --- a/MathlibTest/Qify.lean +++ b/MathlibTest/Qify.lean @@ -1,3 +1,4 @@ +module import Mathlib.Algebra.Order.Field.Rat import Mathlib.Data.Int.CharZero import Mathlib.Tactic.Qify diff --git a/MathlibTest/Rify.lean b/MathlibTest/Rify.lean index 996c1c627c8226..130512819ec177 100644 --- a/MathlibTest/Rify.lean +++ b/MathlibTest/Rify.lean @@ -1,3 +1,4 @@ +module import Mathlib.Tactic.Linarith import Mathlib.Tactic.Rify import Mathlib.Data.NNReal.Basic diff --git a/MathlibTest/Split.lean b/MathlibTest/Split.lean index 7b48b0d7d01fcf..44f1e57e7029f3 100644 --- a/MathlibTest/Split.lean +++ b/MathlibTest/Split.lean @@ -1,3 +1,4 @@ +module import Mathlib.Tactic.Basic example : (α : Type) × List α := by diff --git a/MathlibTest/Tauto.lean b/MathlibTest/Tauto.lean index a4e570e610fa0a..ad405e69135777 100644 --- a/MathlibTest/Tauto.lean +++ b/MathlibTest/Tauto.lean @@ -3,6 +3,7 @@ Copyright (c) 2018 Simon Hudon. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Simon Hudon, David Renshaw -/ +module import Mathlib.Tactic.Tauto import Mathlib.Tactic.SplitIfs import Mathlib.Data.Part diff --git a/MathlibTest/TautoSet.lean b/MathlibTest/TautoSet.lean index 6fb50960b88400..baaa6f7e7e2891 100644 --- a/MathlibTest/TautoSet.lean +++ b/MathlibTest/TautoSet.lean @@ -3,7 +3,7 @@ Copyright (c) 2025 Lenny Taelman. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Lenny Taelman -/ - +module import Mathlib.Tactic.TautoSet variable {α : Type} {A B C D E : Set α} diff --git a/MathlibTest/TermCongr.lean b/MathlibTest/TermCongr.lean index da0864e52e86a6..6265d179ac2638 100644 --- a/MathlibTest/TermCongr.lean +++ b/MathlibTest/TermCongr.lean @@ -1,4 +1,6 @@ import Mathlib.Tactic.TermCongr +import Mathlib.Tactic.Basic +import Batteries.Logic /-! `congr(...)` tests needing no additional imports diff --git a/MathlibTest/ToDual.lean b/MathlibTest/ToDual.lean index 16c8da69968d4b..e308f71bbd6a64 100644 --- a/MathlibTest/ToDual.lean +++ b/MathlibTest/ToDual.lean @@ -371,3 +371,14 @@ info: renameTest' {α : Type} [Bot α] [Top α] (y : α) {P : α → Prop} (Pbot -/ #guard_msgs in #check renameTest' + +-- Test translation of binder names starting with `h`: `hmax` turns into `hmin`. +@[to_dual] +theorem eq_of_min_of_max (hmax : ∀ x, x ≤ a) (hmin : ∀ x, a ≤ x) : a = b := + le_antisymm (hmin b) (hmax b) + +/-- +info: eq_of_max_of_min {α : Type} [PartialOrder α] (a b : α) (hmin : ∀ (x : α), a ≤ x) (hmax : ∀ (x : α), x ≤ a) : a = b +-/ +#guard_msgs in +#check eq_of_max_of_min diff --git a/MathlibTest/Use.lean b/MathlibTest/Use.lean index 2e0252058f5261..fff31cbe869580 100644 --- a/MathlibTest/Use.lean +++ b/MathlibTest/Use.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Arthur Paulino. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Arthur Paulino -/ - +module import Mathlib.Tactic.Use import Mathlib.Tactic.Basic import Mathlib.Logic.Equiv.Defs diff --git a/MathlibTest/abel.lean b/MathlibTest/abel.lean index a3b588b7248ece..a49fd5d1231349 100644 --- a/MathlibTest/abel.lean +++ b/MathlibTest/abel.lean @@ -1,3 +1,4 @@ +module import Mathlib.Tactic.Abel set_option linter.unusedVariables false diff --git a/MathlibTest/borelize.lean b/MathlibTest/borelize.lean index b1c24d7ed7ce75..8ecd4a4796f8b3 100644 --- a/MathlibTest/borelize.lean +++ b/MathlibTest/borelize.lean @@ -1,3 +1,4 @@ +module import Mathlib.MeasureTheory.Constructions.BorelSpace.Basic set_option autoImplicit true diff --git a/MathlibTest/casesm.lean b/MathlibTest/casesm.lean index d8d1862d4560f4..d6fc0ddc0d58ca 100644 --- a/MathlibTest/casesm.lean +++ b/MathlibTest/casesm.lean @@ -1,3 +1,4 @@ +module import Mathlib.Tactic.CasesM set_option autoImplicit true diff --git a/MathlibTest/choose.lean b/MathlibTest/choose.lean index d4880bf41cc414..854f8fc82ddcbb 100644 --- a/MathlibTest/choose.lean +++ b/MathlibTest/choose.lean @@ -1,3 +1,4 @@ +module import Batteries.Util.ExtendedBinder import Mathlib.Tactic.Choose diff --git a/MathlibTest/fail_if_no_progress.lean b/MathlibTest/fail_if_no_progress.lean index 4dfd88bab15c54..2077241c9c9c28 100644 --- a/MathlibTest/fail_if_no_progress.lean +++ b/MathlibTest/fail_if_no_progress.lean @@ -1,3 +1,4 @@ +module import Mathlib.Tactic.FailIfNoProgress import Mathlib.Tactic.Basic diff --git a/MathlibTest/fast_instance.lean b/MathlibTest/fast_instance.lean index 5a2bc6c49e55ab..18b79b2cecf508 100644 --- a/MathlibTest/fast_instance.lean +++ b/MathlibTest/fast_instance.lean @@ -117,7 +117,7 @@ abbrev dec1 : Decidable It := isTrue sorry #guard_msgs in def dec2 : Decidable It := isTrue sorry -/-- info: @Dec.mk It (@isTrue It dec2._proof_1) : Dec It -/ +/-- info: @Dec.mk It (@isTrue It dec1._proof_1) : Dec It -/ #guard_msgs in set_option pp.explicit true in #check fast_instance% { dec := dec1 : Dec It } @@ -138,3 +138,18 @@ info: @Dec.mk It dec2 : Dec It #guard_msgs in set_option pp.explicit true in #check fast_instance% { dec := dec2 : Dec It } + +/-! +Checking that proof fields whose types already match at instances transparency +are used directly, without wrapping in an auxiliary theorem. +-/ + +class Pointed (α : Type) where + val : α + h : True + +abbrev myPointed : Pointed Nat := ⟨0, trivial⟩ + +/-- info: { val := 0, h := trivial } : Pointed Nat -/ +#guard_msgs in +#check fast_instance% (myPointed : Pointed Nat) diff --git a/MathlibTest/module.lean b/MathlibTest/module.lean index 7f547320f8d092..93788e913b7f0c 100644 --- a/MathlibTest/module.lean +++ b/MathlibTest/module.lean @@ -3,6 +3,7 @@ Copyright (c) 2024 Heather Macbeth. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Heather Macbeth -/ +module import Mathlib.Tactic.FieldSimp import Mathlib.Tactic.LinearCombination import Mathlib.Tactic.Module diff --git a/MathlibTest/nomatch.lean b/MathlibTest/nomatch.lean index c72aa78211d8cd..0f81f7e00dd01c 100644 --- a/MathlibTest/nomatch.lean +++ b/MathlibTest/nomatch.lean @@ -1,3 +1,5 @@ +module + set_option autoImplicit true example : False → α := nofun example : False → α := by nofun diff --git a/MathlibTest/order.lean b/MathlibTest/order.lean index 9fd625c98a6541..64b53207465804 100644 --- a/MathlibTest/order.lean +++ b/MathlibTest/order.lean @@ -1,3 +1,4 @@ +module import Mathlib.LinearAlgebra.Matrix.Rank import Mathlib.Tactic.Order diff --git a/MathlibTest/peel.lean b/MathlibTest/peel.lean index 131e9bb76231dc..b513b495c64151 100644 --- a/MathlibTest/peel.lean +++ b/MathlibTest/peel.lean @@ -1,3 +1,4 @@ +module import Mathlib.Tactic.Peel import Mathlib.Topology.Instances.Real.Lemmas diff --git a/MathlibTest/pnat_to_nat.lean b/MathlibTest/pnat_to_nat.lean index 1c10bd5a2cf6e6..430a363b4ee597 100644 --- a/MathlibTest/pnat_to_nat.lean +++ b/MathlibTest/pnat_to_nat.lean @@ -1,3 +1,4 @@ +module import Mathlib.Tactic.PNatToNat example (a b : PNat) (h : a < b) : 1 < b := by diff --git a/MathlibTest/rsuffices.lean b/MathlibTest/rsuffices.lean index c8f1a13d360a0c..d22bee29f42e4a 100644 --- a/MathlibTest/rsuffices.lean +++ b/MathlibTest/rsuffices.lean @@ -1,3 +1,4 @@ +module import Mathlib.Tactic.RSuffices import Mathlib.Tactic.ExistsI import Mathlib.Algebra.Ring.Nat diff --git a/MathlibTest/spread.lean b/MathlibTest/spread.lean index 4ea6090b4f5fd7..63d8bbc0a69e8c 100644 --- a/MathlibTest/spread.lean +++ b/MathlibTest/spread.lean @@ -1,3 +1,4 @@ +module import Mathlib.Tactic.Spread set_option autoImplicit true diff --git a/MathlibTest/tfae.lean b/MathlibTest/tfae.lean index 248748f65406cb..cf4f13ded2b6b0 100644 --- a/MathlibTest/tfae.lean +++ b/MathlibTest/tfae.lean @@ -1,3 +1,4 @@ +module import Mathlib.Tactic.TFAE import Mathlib.Tactic.SuccessIfFailWithMsg diff --git a/docs/1000.yaml b/docs/1000.yaml index 1a4c3a297db446..88c13448812ca7 100644 --- a/docs/1000.yaml +++ b/docs/1000.yaml @@ -2266,8 +2266,10 @@ Q2916568: Q2919401: title: Ostrowski's theorem - decl: Rat.AbsoluteValue.equiv_real_or_padic - authors: David Kurniadi Angdinata, Fabrizio Barroero, Laura Capuano, Nirvana Coppola, María Inés de Frutos-Fernández, Sam van Gool, Silvain Rideau-Kikuchi, Amos Turchet, Francesco Veneziano + decls: + - Rat.AbsoluteValue.equiv_real_or_padic + - RatFunc.valuation_isEquiv_infty_or_adic + authors: David Kurniadi Angdinata, Fabrizio Barroero, Laura Capuano, Nirvana Coppola, María Inés de Frutos-Fernández, Sam van Gool, Silvain Rideau-Kikuchi, Amos Turchet, Francesco Veneziano, Xavier Généreux date: 2024 Q2981012: diff --git a/docs/references.bib b/docs/references.bib index 6834e0fa99dfe5..47ffaebdad1117 100644 --- a/docs/references.bib +++ b/docs/references.bib @@ -109,6 +109,18 @@ @Misc{ aignerhorev2012infinite archiveprefix = {arXiv} } +@Book{ Albiac_Kalton_2016, + author = {Albiac, Fernando. and Kalton, Nigel J.}, + title = {Topics in Banach Space Theory}, + edition = {2nd ed. 2016.}, + isbn = {3-319-31557-9}, + keywords = {Functional analysis. ; Functional Analysis.}, + language = {eng}, + publisher = {Springer International Publishing}, + series = {Graduate Texts in Mathematics, 233}, + year = {2016} +} + @Article{ alfseneffros1972, author = {Erik M. {Alfsen} and Edward G. {Effros}}, title = {{Structure in real Banach spaces. I and II}}, @@ -1479,6 +1491,19 @@ @Book{ davey_priestley url = {https://doi.org/10.1017/CBO9780511809088} } +@Article{ daws2024, + author = {Daws, Matthew}, + journal = {Communications of the American Mathematical Society}, + number = {1}, + title = {Quantum graphs: different perspectives, homomorphisms and + quantum automorphisms}, + volume = {4}, + pages = {117-181}, + year = {2024}, + url = {https://arxiv.org/abs/2203.08716}, + mrnumber = {4706978} +} + @Article{ day1972, author = {Day, Brian}, title = {A reflection theorem for closed categories}, @@ -3659,6 +3684,14 @@ @Article{ markowsky1976 pages = {53-68} } +@Book{ MartiJurg1969, + title = {Introduction to the theory of bases}, + author = {Marti, Jürg T}, + publisher = {Springer-Verlag}, + series = {Springer tracts in natural philosophy, v. 18}, + year = {1969} +} + @Article{ mason2017, title = {Vertex rings and Pierce bundles}, author = {Geoffrey Mason}, @@ -5012,6 +5045,19 @@ @Book{ simon2011 collection = {Cambridge Tracts in Mathematics} } +@Book{ Singer_1970, + author = {Singer, Ivan}, + title = {Bases in Banach spaces}, + keywords = {Banach spaces. ; Banach spaces ; Banach-Raum}, + language = {eng}, + lccn = {75099014}, + publisher = {Springer-Verlag}, + series = {Die Grundlehren der mathematischen Wissenschaften in + Einzeldarstellungen mit besonderer Berücksichtigung der + Anwendungsgebiete ; Bd. 154}, + year = {1970} +} + @Article{ skoda2006, author = {{\v{S}}koda, Zoran}, title = {Noncommutative localization in noncommutative geometry}, diff --git a/docs/undergrad.yaml b/docs/undergrad.yaml index 6295168a54236f..a3209e4fdbdd97 100644 --- a/docs/undergrad.yaml +++ b/docs/undergrad.yaml @@ -24,7 +24,7 @@ Linear algebra: dual vector space: 'Module.Dual' dual basis: 'Module.Basis.dualBasis' transpose of a linear map: 'Module.Dual.transpose' - orthogonality: 'https://en.wikipedia.org/wiki/Dual_space#Quotient_spaces_and_annihilators' + orthogonality: 'Submodule.dualAnnihilator' Finite-dimensional vector spaces: finite-dimensionality : 'FiniteDimensional' isomorphism with $K^n$: 'Module.Basis.equivFun' @@ -36,7 +36,7 @@ Linear algebra: multilinear map: 'MultilinearMap' determinant of vectors: 'Module.Basis.det' determinant of endomorphisms: 'LinearMap.det' - special linear group: 'https://en.wikipedia.org/wiki/Special_linear_group' + special linear group: 'Matrix.SpecialLinearGroup' orientation of a $\R$-vector space: 'Orientation' Matrices: commutative-ring-valued matrices: 'Matrix' @@ -48,7 +48,7 @@ Linear algebra: invertibility: 'Matrix.inv' elementary row operations: 'https://en.wikipedia.org/wiki/Elementary_matrix#Operations' elementary column operations: 'https://en.wikipedia.org/wiki/Elementary_matrix#Operations' - Gaussian elimination: 'https://en.wikipedia.org/wiki/Gaussian_elimination' + Gaussian elimination: 'Matrix.Pivot.exists_list_transvec_mul_mul_list_transvec_eq_diagonal' row-reduced matrices: 'https://en.wikipedia.org/wiki/Row_echelon_form#Reduced_row_echelon_form' Endomorphism polynomials: annihilating polynomials: 'Polynomial.annIdeal' @@ -60,13 +60,13 @@ Linear algebra: eigenvector: 'Module.End.HasEigenvector' diagonalization: 'https://en.wikipedia.org/wiki/Diagonalizable_matrix' triangularization: 'https://en.wikipedia.org/wiki/Triangular_matrix#Triangularisability' - invariant subspaces of an endomorphism: 'https://en.wikipedia.org/wiki/Invariant_subspace' + invariant subspaces of an endomorphism: 'Module.End.invtSubmodule' generalized eigenspaces: 'Module.End.genEigenspace' kernels lemma: 'https://fr.wikipedia.org/wiki/Lemme_des_noyaux' Jordan-Chevalley-Dunford decomposition: 'Module.End.exists_isNilpotent_isSemisimple' Jordan normal form: 'https://en.wikipedia.org/wiki/Jordan_normal_form' Linear representations: - irreducible representation: 'https://en.wikipedia.org/wiki/Irreducible_representation' + irreducible representation: 'Representation.IsIrreducible' Schur's lemma: 'FDRep.finrank_hom_simple_simple' examples: '' Exponential: @@ -105,9 +105,9 @@ Group Theory: general linear group: 'Matrix.GeneralLinearGroup' special linear group: 'Matrix.SpecialLinearGroup' orthogonal group: 'Matrix.orthogonalGroup' - special orthogonal group: 'https://en.wikipedia.org/wiki/Orthogonal_group#SO(n)' + special orthogonal group: 'Matrix.specialOrthogonalGroup' unitary group: 'Matrix.unitaryGroup' - special unitary group: 'https://en.wikipedia.org/wiki/Special_unitary_group' + special unitary group: 'Matrix.specialUnitaryGroup' Representation theory of finite groups: representations of abelian groups: 'https://proofwiki.org/wiki/Irreducible_Representations_of_Abelian_Group' dual groups: 'https://kconrad.math.uconn.edu/blurbs/grouptheory/charthy.pdf' @@ -206,9 +206,10 @@ Bilinear and Quadratic Forms Over a Vector Space: Orthogonality: orthogonal elements: 'LinearMap.BilinForm.IsOrtho' adjoint endomorphism: 'LinearMap.BilinForm.leftAdjointOfNondegenerate' - Sylvester's law of inertia: 'https://en.wikipedia.org/wiki/Sylvester%27s_law_of_inertia' - real classification: 'https://en.wikipedia.org/wiki/Sylvester%27s_law_of_inertia' - complex classification: '' + Sylvester's law of inertia (existence): 'QuadraticForm.equivalent_one_zero_neg_one_weighted_sum_squared' + Sylvester's law of inertia (uniqueness): 'QuadraticForm.sigPos_of_equiv_weightedSumSquares' + real classification: 'QuadraticForm.equivalent_one_zero_neg_one_weighted_sum_squared' + complex classification: 'QuadraticForm.equivalent_weightedSumSquares_of_isAlgClosed' Gram-Schmidt orthogonalisation: 'InnerProductSpace.gramSchmidt_orthogonal' Euclidean and Hermitian spaces: Euclidean vector spaces: 'InnerProductSpace' @@ -221,10 +222,10 @@ Bilinear and Quadratic Forms Over a Vector Space: Endomorphisms: orthogonal group: 'Matrix.orthogonalGroup' unitary group: 'Matrix.unitaryGroup' - special orthogonal group: '' - special unitary group: '' + special orthogonal group: 'Matrix.specialOrthogonalGroup' + special unitary group: 'Matrix.specialUnitaryGroup' self-adjoint endomorphism: 'IsSelfAdjoint' - normal endomorphism: 'https://en.wikipedia.org/wiki/Normal_operator' + normal endomorphism: 'IsStarNormal' diagonalization of a self-adjoint endomorphism: 'LinearMap.IsSymmetric.eigenvectorBasis_apply_self_apply' diagonalization of normal endomorphisms: 'https://en.wikipedia.org/wiki/Spectral_theorem#Normal_matrices' simultaneous diagonalization of two real quadratic forms, with one positive-definite: 'https://fr.wikipedia.org/wiki/Th%C3%A9or%C3%A8me_spectral#Formalisation_alg%C3%A9brique' @@ -262,7 +263,7 @@ Affine and Euclidean Geometry: classification of isometries in two and three dimensions: '' angles between vectors: 'InnerProductGeometry.angle' angles between planes: '' - inscribed angle theorem: '' + inscribed angle theorem: 'Orientation.two_zsmul_oangle_sub_eq_two_zsmul_oangle_sub_of_norm_eq' cocyclicity: 'EuclideanGeometry.Concyclic' group of isometries stabilizing a subset of the plane or of space: '' regular polygons: '' diff --git a/push_proofs.sh b/push_proofs.sh new file mode 100644 index 00000000000000..e92d222a8e958a --- /dev/null +++ b/push_proofs.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -e + +# create file via EOF +mkdir -p Mathlib/Algebra +cat > Mathlib/Algebra/MyNewProofs.lean << 'EOF' +import Mathlib.Algebra.Group.Basic +import Mathlib.Algebra.Ring.Basic + +theorem my_add_comm (a b : Nat) : a + b = b + a := + Nat.add_comm a b +EOF + +# git workflow +git checkout -b feature/your-proofs || git checkout feature/your-proofs +git add . +git commit -m "feat: add MyNewProofs automatically via Termux EOF" +git push -u origin feature/your-proofs + +# open PR +gh pr create --base leanprover-community:master \ + --head batmeezy918:feature/your-proofs \ + --title "Add MyNewProofs" \ + --body "Automated PR from Termux using EOF-generated file" diff --git a/scripts/autolabel.lean b/scripts/autolabel.lean index 5848c5cf2d6dda..9a006caabb4c4b 100644 --- a/scripts/autolabel.lean +++ b/scripts/autolabel.lean @@ -184,7 +184,8 @@ def mathlibLabelData : (l : Label) → LabelData l | .«t-algebraic-geometry» => { dirs := #[ "Mathlib" / "AlgebraicGeometry", - "Mathlib" / "Geometry" / "RingedSpace"] } + "Mathlib" / "Geometry" / "RingedSpace"], + dependencies := #[.«t-ring-theory»] } | .«t-algebraic-topology» => {} | .«t-analysis» => {} | .«t-category-theory» => {} @@ -200,7 +201,8 @@ def mathlibLabelData : (l : Label) → LabelData l | .«t-differential-geometry» => { dirs := #[ "Mathlib" / "Geometry" / "Diffeology", - "Mathlib" / "Geometry" / "Manifold"] } + "Mathlib" / "Geometry" / "Manifold"], + dependencies := #[.«t-analysis», .«t-topology»] } | .«t-dynamics» => {} | .«t-euclidean-geometry» => { dirs := #[ diff --git a/scripts/bench/build/README.md b/scripts/bench/build/README.md index 014b5db75556fd..eab2e8e62d9be6 100644 --- a/scripts/bench/build/README.md +++ b/scripts/bench/build/README.md @@ -9,7 +9,7 @@ The following metrics are collected by a wrapper around the entire build process - `build//task-clock` - `build//wall-clock` -The following metrics are collected from `leanc --profile` and summed across all modules: +The following metrics are collected from `lean --profile` and summed across all modules: - `build/profile///wall-clock` diff --git a/scripts/bench/build/fake-root/bin/lean b/scripts/bench/build/fake-root/bin/lean index 8d2b778e65d7f8..5dbe6a8c9551ba 100755 --- a/scripts/bench/build/fake-root/bin/lean +++ b/scripts/bench/build/fake-root/bin/lean @@ -12,6 +12,9 @@ REPO = Path() BENCH = REPO / "scripts" / "bench" OUTFILE = REPO / "measurements.jsonl" +sys.path.append(str(BENCH)) +import measure # noqa: E402 + def save_result(metric: str, value: float, unit: str | None = None) -> None: data = {"metric": metric, "value": value} @@ -27,15 +30,6 @@ def run(*command: str) -> None: sys.exit(result.returncode) -def run_stderr(*command: str) -> str: - result = subprocess.run(command, capture_output=True, encoding="utf-8") - if result.returncode != 0: - print(result.stdout, end="", file=sys.stdout) - print(result.stderr, end="", file=sys.stderr) - sys.exit(result.returncode) - return result.stderr - - def get_module(setup: Path) -> str: with open(setup) as f: return json.load(f)["name"] @@ -48,13 +42,13 @@ def count_lines(module: str, path: Path) -> None: def run_lean(module: str) -> None: - stderr = run_stderr( - f"{BENCH}/measure.py", - *("-t", f"{NAME}/module/{module}"), - *("-m", "instructions"), - "--", - *("lean", "--profile", "-Dprofiler.threshold=9999999"), - *sys.argv[1:], + _, stderr = measure.main( + cmd=["lean", "--profile", "-Dprofiler.threshold=9999999", *sys.argv[1:]], + output=OUTFILE, + topics=[f"{NAME}/module/{module}"], + metrics={"instructions"}, + append=True, + capture=True, ) for line in stderr.splitlines(): diff --git a/scripts/bench/build/run b/scripts/bench/build/run index a92d65dbff1575..e489dff0a0b30f 100755 --- a/scripts/bench/build/run +++ b/scripts/bench/build/run @@ -11,8 +11,7 @@ rm -f .lake/packages/batteries/.lake/build/bin/runLinter # Run build LAKE_OVERRIDE_LEAN=true LEAN=$(realpath "$BENCH/build/fake-root/bin/lean") \ - "$BENCH/measure.py" -t build \ - -m instructions -m maxrss -m task-clock -m wall-clock -- \ + "$BENCH/measure.py" --append -t build -d -- \ lakeprof record lake build --no-cache # Analyze lakeprof data diff --git a/scripts/bench/lint/run b/scripts/bench/lint/run index bc96fa1ed7a7a3..f9b487052707cf 100755 --- a/scripts/bench/lint/run +++ b/scripts/bench/lint/run @@ -4,6 +4,5 @@ set -euxo pipefail BENCH="scripts/bench" lake build runLinter -LEAN_ABORT_ON_PANIC=1 "$BENCH/measure.py" -t lint \ - -m instructions -m maxrss -m task-clock -m wall-clock -- \ +LEAN_ABORT_ON_PANIC=1 "$BENCH/measure.py" --append -t lint -d -- \ lake exe runLinter Mathlib diff --git a/scripts/bench/measure.py b/scripts/bench/measure.py index 072f4cdde6fc4f..c01a8a1267543b 100755 --- a/scripts/bench/measure.py +++ b/scripts/bench/measure.py @@ -7,10 +7,10 @@ import subprocess import sys import tempfile +from argparse import Namespace from dataclasses import dataclass from pathlib import Path - -OUTFILE = Path() / "measurements.jsonl" +from typing import Tuple @dataclass @@ -27,10 +27,24 @@ class RusageMetric: unit: str | None = None +@dataclass +class Result: + category: str + value: float + unit: str | None + + def fmt(self, topic: str) -> str: + data = {"metric": f"{topic}//{self.category}", "value": self.value} + if self.unit is not None: + data["unit"] = self.unit + return json.dumps(data) + + PERF_METRICS = { "task-clock": PerfMetric("task-clock", factor=1e-9, unit="s"), "wall-clock": PerfMetric("duration_time", factor=1e-9, unit="s"), "instructions": PerfMetric("instructions"), + "cycles": PerfMetric("cycles"), } PERF_UNITS = { @@ -43,118 +57,202 @@ class RusageMetric: } ALL_METRICS = {**PERF_METRICS, **RUSAGE_METRICS} +DEFAULT_METRICS = {"instructions", "maxrss", "task-clock", "wall-clock"} -def measure_perf(cmd: list[str], events: list[str]) -> dict[str, tuple[float, str]]: - with tempfile.NamedTemporaryFile() as tmp: - cmd = [ - *["perf", "stat", "-j", "-o", tmp.name], - *[arg for event in events for arg in ["-e", event]], - *["--", *cmd], - ] +def resolve_metrics(metrics: set[str]) -> Tuple[set[str], set[str]]: + perf = set() + rusage = set() + unknown = set() - # Execute command - env = os.environ.copy() - env["LC_ALL"] = "C" # or else perf may output syntactically invalid json - result = subprocess.run(cmd, env=env) - if result.returncode != 0: - sys.exit(result.returncode) + for metric in metrics: + if metric in PERF_METRICS: + perf.add(metric) + elif metric in RUSAGE_METRICS: + rusage.add(metric) + else: + unknown.add(metric) - # Collect results - perf = {} - for line in tmp: - data = json.loads(line) - if "event" in data and "counter-value" in data: - perf[data["event"]] = float(data["counter-value"]), data["unit"] + if unknown: + raise SystemExit(f"unknown metrics: {', '.join(unknown)}") - return perf + return perf, rusage @dataclass -class Result: - category: str +class PerfResult: value: float - unit: str | None + unit: str - def fmt(self, topic: str) -> str: - metric = f"{topic}//{self.category}" - if self.unit is None: - return json.dumps({"metric": metric, "value": self.value}) - return json.dumps({"metric": metric, "value": self.value, "unit": self.unit}) +type PerfResults = dict[str, PerfResult] -def measure(cmd: list[str], metrics: list[str]) -> list[Result]: - # Check args - unknown_metrics = [] - for metric in metrics: - if metric not in RUSAGE_METRICS and metric not in PERF_METRICS: - unknown_metrics.append(metric) - if unknown_metrics: - raise Exception(f"unknown metrics: {', '.join(unknown_metrics)}") - # Prepare perf events - events: list[str] = [] - for metric in metrics: - if info := PERF_METRICS.get(metric): - events.append(info.event) +@dataclass +class MeasureResult: + perf: PerfResults + stdout: str + stderr: str + + +def measure_perf(cmd: list[str], events: set[str], capture: bool) -> MeasureResult: + with tempfile.NamedTemporaryFile() as tmp: + env = os.environ.copy() + env["LC_ALL"] = "C" # or perf may output syntactically invalid JSON + + # On NixOS, perf effectively prepends /usr/bin to the PATH, but in this + # test suite, we often use the PATH to specify the binaries under test. + # Hence, we reset the PATH inside of perf using env. + cmd = [ + *("perf", "stat", "-j", "-o", tmp.name), + *(arg for event in sorted(events) for arg in ["-e", event]), + "--", + *("env", f"PATH={env['PATH']}"), + *cmd, + ] - # Measure - perf = measure_perf(cmd, events) + # Execute command + result = subprocess.run(cmd, env=env, capture_output=capture, encoding="utf-8") + if result.returncode != 0: + if capture: + print(result.stdout, end="", file=sys.stdout) + print(result.stderr, end="", file=sys.stderr) + raise SystemExit(result.returncode) + + # Collect results + perf: PerfResults = {} + for line in tmp: + data = json.loads(line) + if "event" in data and "counter-value" in data: + perf[data["event"]] = PerfResult( + value=float(data["counter-value"]), + unit=data["unit"], + ) + + return MeasureResult( + perf=perf, + stdout=result.stdout or "", + stderr=result.stderr or "", + ) + + +def get_perf_result(perf: PerfResults, metric: str) -> Result: + info = PERF_METRICS[metric] + if info.event in perf: + result = perf[info.event] + else: + # Without the corresponding permissions, + # we only get access to the userspace versions of the counters. + result = perf[f"{info.event}:u"] + + value = result.value * PERF_UNITS.get(result.unit, info.factor) + return Result(category=metric, value=value, unit=info.unit) + + +def get_rusage_result(rusage: resource.struct_rusage, metric: str) -> Result: + info = RUSAGE_METRICS[metric] + value = getattr(rusage, info.name) * info.factor + return Result(category=metric, value=value, unit=info.unit) + + +def main( + cmd: list[str], + output: Path, + topics: list[str], + metrics: set[str], + append: bool = True, + capture: bool = False, +) -> tuple[str, str]: + perf_metrics, rusage_metrics = resolve_metrics(metrics) + perf_events = {PERF_METRICS[metric].event for metric in perf_metrics} + + measured = measure_perf(cmd, perf_events, capture=capture) + perf = measured.perf rusage = resource.getrusage(resource.RUSAGE_CHILDREN) - # Extract results results = [] - for metric in metrics: - if info := PERF_METRICS.get(metric): - if info.event in perf: - value, unit = perf[info.event] - else: - # Without the corresponding permissions, - # we only get access to the userspace versions of the counters. - value, unit = perf[f"{info.event}:u"] + for metric in perf_metrics: + results.append(get_perf_result(perf, metric)) + for metric in rusage_metrics: + results.append(get_rusage_result(rusage, metric)) + + with open(output, "a" if append else "w") as f: + for result in results: + for topic in topics: + f.write(f"{result.fmt(topic)}\n") - value *= PERF_UNITS.get(unit, info.factor) - results.append(Result(metric, value, info.unit)) + return measured.stdout, measured.stderr - if info := RUSAGE_METRICS.get(metric): - value = getattr(rusage, info.name) * info.factor - results.append(Result(metric, value, info.unit)) - return results +@dataclass +class Args(Namespace): + topic: list[str] + metric: list[str] + default_metrics: bool + output: Path + append: bool + cmd: str + args: list[str] if __name__ == "__main__": parser = argparse.ArgumentParser( - description=f"Measure resource usage of a command using perf and rusage. The results are appended to {OUTFILE.name}.", + description="Measure resource usage of a command using perf and rusage.", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) parser.add_argument( - "-t", "--topic", + "-t", action="append", default=[], help="topic prefix for the metrics", ) parser.add_argument( - "-m", "--metric", + "-m", action="append", default=[], help=f"metrics to measure. Can be specified multiple times. Available metrics: {', '.join(sorted(ALL_METRICS))}", ) + parser.add_argument( + "--default-metrics", + "-d", + action="store_true", + help=f"measure a default set of metrics: {', '.join(sorted(DEFAULT_METRICS))}", + ) + parser.add_argument( + "--output", + "-o", + type=Path, + default=Path() / "measurements.jsonl", + help="output file to write measurements to, in the JSON Lines format", + ) + parser.add_argument( + "--append", + "-a", + action="store_true", + help="append to the output file instead of overwriting it", + ) parser.add_argument( "cmd", - nargs="*", help="command to measure the resource usage of", ) - args = parser.parse_args() - - topics: list[str] = args.topic - metrics: list[str] = args.metric - cmd: list[str] = args.cmd - - results = measure(cmd, metrics) - - with open(OUTFILE, "a+") as f: - for result in results: - for topic in topics: - f.write(f"{result.fmt(topic)}\n") + parser.add_argument( + "args", + nargs="*", + default=[], + help="arguments to pass to the command", + ) + args = parser.parse_args(namespace=Args) + + metrics = set(args.metric) + if args.default_metrics: + metrics |= DEFAULT_METRICS + + main( + cmd=[args.cmd] + args.args, + output=args.output, + topics=args.topic, + metrics=metrics, + append=args.append, + ) diff --git a/scripts/bench/open-mathlib/run b/scripts/bench/open-mathlib/run index 470543a9d5b49d..e48cb2c693ab35 100755 --- a/scripts/bench/open-mathlib/run +++ b/scripts/bench/open-mathlib/run @@ -4,5 +4,5 @@ set -euxo pipefail BENCH="scripts/bench" "$BENCH/repeatedly.py" -n 5 -- \ - "$BENCH/measure.py" -t open-mathlib -m instructions -m maxrss -m task-clock -m wall-clock -- \ + "$BENCH/measure.py" --append -t open-mathlib -d -- \ lake lean Mathlib.lean