From 6f59d7777cceba0fff1030042be3c612bb738da7 Mon Sep 17 00:00:00 2001 From: Paul Lezeau <72892199+Paul-Lez@users.noreply.github.com> Date: Wed, 13 Apr 2022 08:59:52 +0000 Subject: [PATCH 001/373] feat(order/bounded_order): Basic API for `subtype.order_bot` and `subtype.order_top` (#12904) A few `simp` lemmas that were needed for `subtype.order_bot` and `subtype.order_top`. --- src/order/bounded_order.lean | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/order/bounded_order.lean b/src/order/bounded_order.lean index d2cf233428e0d..b0da1d2e30e4a 100644 --- a/src/order/bounded_order.lean +++ b/src/order/bounded_order.lean @@ -1041,6 +1041,22 @@ congr_arg coe (mk_bot hbot).symm lemma coe_top [order_top α] [order_top (subtype p)] (htop : p ⊤) : ((⊤ : subtype p) : α) = ⊤ := congr_arg coe (mk_top htop).symm +@[simp] lemma coe_eq_bot_iff [order_bot α] [order_bot (subtype p)] (hbot : p ⊥) {x : {x // p x}} : + (x : α) = ⊥ ↔ x = ⊥ := +by rw [←coe_bot hbot, ext_iff] + +@[simp] lemma coe_eq_top_iff [order_top α] [order_top (subtype p)] (htop : p ⊤) {x : {x // p x}} : + (x : α) = ⊤ ↔ x = ⊤ := +by rw [←coe_top htop, ext_iff] + +@[simp] lemma mk_eq_bot_iff [order_bot α] [order_bot (subtype p)] (hbot : p ⊥) {x : α} (hx : p x) : + (⟨x, hx⟩ : subtype p) = ⊥ ↔ x = ⊥ := +(coe_eq_bot_iff hbot).symm + +@[simp] lemma mk_eq_top_iff [order_top α] [order_top (subtype p)] (htop : p ⊤) {x : α} (hx : p x) : + (⟨x, hx⟩ : subtype p) = ⊤ ↔ x = ⊤ := +(coe_eq_top_iff htop).symm + end subtype namespace order_dual From 647aa5be0bcdc8179a664b379e62c7bcbbd9a076 Mon Sep 17 00:00:00 2001 From: Aaron Anderson Date: Wed, 13 Apr 2022 10:56:40 +0000 Subject: [PATCH 002/373] =?UTF-8?q?feat(model=5Ftheory/fraisse):=20Defines?= =?UTF-8?q?=20ultrahomogeneous=20structures,=20fixes=20Fra=C3=AFss=C3=A9?= =?UTF-8?q?=20limit=20definition=20(#12994)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Defines ultrahomogeneous structures Fixes the definition of a Fraïssé limit to require ultrahomogeneity Completes the characterization of when a class is the age of a countable structure. --- src/model_theory/fraisse.lean | 99 +++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 22 deletions(-) diff --git a/src/model_theory/fraisse.lean b/src/model_theory/fraisse.lean index 0dbaee797a46b..d4cd022be841e 100644 --- a/src/model_theory/fraisse.lean +++ b/src/model_theory/fraisse.lean @@ -16,7 +16,7 @@ class of all finitely-generated structures that embed into it. Of particular interest are Fraïssé classes, which are exactly the ages of countable ultrahomogeneous structures. To each is associated a unique (up to nonunique isomorphism) -Fraïssé limit - the countable structure with that age. +Fraïssé limit - the countable ultrahomogeneous structure with that age. ## Main Definitions * `first_order.language.age` is the class of finitely-generated structures that embed into a @@ -30,7 +30,7 @@ of a structure `M` in `K` into other structures in `K`, those two structures can fourth structure in `K` such that the resulting square of embeddings commutes. * `first_order.language.is_fraisse` indicates that a class is nonempty, isomorphism-invariant, essentially countable, and satisfies the hereditary, joint embedding, and amalgamation properties. -* `first_order.language.fraisse_limit` noncomputably constructs a Fraïssé limit for any Fraïssé +* `first_order.language.is_fraisse_limit` indicates that a structure is a Fraïssé limit for a given class. ## Main Results @@ -38,8 +38,8 @@ class. joint-embedding properties. * `first_order.language.age.countable_quotient` shows that the age of any countable structure is essentially countable. -* `first_order.language.exists_cg_is_age_of` constructs a countably-generated structure with a -particular age. +* `first_order.language.exists_countable_is_age_of_iff` gives necessary and sufficient conditions +for a class to be the age of a countable structure in a language with countably many functions. ## Implementation Notes * Classes of structures are formalized with `set (bundled L.Structure)`. @@ -51,10 +51,7 @@ structures. In the case of a language with countably many function symbols, thes - [K. Tent, M. Ziegler, *A Course in Model Theory*][Tent_Ziegler] ## TODO -* Define ultrahomogeneous structures -* Show that any two Fraïssé limits of a Fraïssé class are isomorphic -* Show that any Fraïssé limit is ultrahomogeneous -* Show that the age of any ultrahomogeneous countable structure is Fraïssé +* Show existence and uniqueness of Fraïssé limits -/ @@ -133,6 +130,10 @@ lemma hereditary.is_equiv_invariant_of_fg (h : hereditary K) variable (M) +lemma age.nonempty : (L.age M).nonempty := +⟨bundled.of (substructure.closure L (∅ : set M)), + (fg_iff_Structure_fg _).1 (fg_closure set.finite_empty), ⟨substructure.subtype _⟩⟩ + lemma age.hereditary : hereditary (L.age M) := λ N hN P hP, hN.2.some.age_subset_age hP @@ -220,23 +221,77 @@ begin { exact (hFP _ n).some } end -variable (K) +theorem exists_countable_is_age_of_iff [L.countable_functions] : + (∃ (M : bundled.{w} L.Structure), (univ : set M).countable ∧ L.age M = K) ↔ + K.nonempty ∧ + (∀ (M N : bundled.{w} L.Structure), nonempty (M ≃[L] N) → (M ∈ K ↔ N ∈ K)) ∧ + (quotient.mk '' K).countable ∧ + (∀ (M : bundled.{w} L.Structure), M ∈ K → Structure.fg L M) ∧ + hereditary K ∧ + joint_embedding K := +begin + split, + { rintros ⟨M, h1, h2, rfl⟩, + resetI, + refine ⟨age.nonempty M, age.is_equiv_invariant L M, age.countable_quotient M h1, λ N hN, hN.1, + age.hereditary M, age.joint_embedding M⟩, }, + { rintros ⟨Kn, eqinv, cq, hfg, hp, jep⟩, + obtain ⟨M, hM, rfl⟩ := exists_cg_is_age_of Kn eqinv cq hfg hp jep, + haveI := ((Structure.cg_iff_countable).1 hM).some, + refine ⟨M, countable_encodable _, rfl⟩, } +end + +variables {K} (L) (M) + +/-- A structure `M` is ultrahomogeneous if every embedding of a finitely generated substructure +into `M` extends to an automorphism of `M`. -/ +def is_ultrahomogeneous : Prop := +∀ (S : L.substructure M) (hs : S.fg) (f : S ↪[L] M), + ∃ (g : M ≃[L] M), f = g.to_embedding.comp S.subtype + +variables {L} (K) + +/-- A structure `M` is a Fraïssé limit for a class `K` if it is countably generated, +ultrahomogeneous, and has age `K`. -/ +structure is_fraisse_limit [countable_functions L] : Prop := +(ultrahomogeneous : is_ultrahomogeneous L M) +(countable : (univ : set M).countable) +(age : L.age M = K) + +variables {L} {M} + +lemma is_ultrahomogeneous.amalgamation_age (h : L.is_ultrahomogeneous M) : + amalgamation (L.age M) := +begin + rintros N P Q NP NQ ⟨Nfg, ⟨NM⟩⟩ ⟨Pfg, ⟨PM⟩⟩ ⟨Qfg, ⟨QM⟩⟩, + obtain ⟨g, hg⟩ := h ((PM.comp NP).to_hom.range) (Nfg.range _) + ((QM.comp NQ).comp (PM.comp NP).equiv_range.symm.to_embedding), + let s := (g.to_hom.comp PM.to_hom).range ⊔ QM.to_hom.range, + refine ⟨bundled.of s, embedding.comp (substructure.inclusion le_sup_left) + ((g.to_embedding.comp PM).equiv_range).to_embedding, + embedding.comp (substructure.inclusion le_sup_right) QM.equiv_range.to_embedding, + ⟨(fg_iff_Structure_fg _).1 (fg.sup (Pfg.range _) (Qfg.range _)), ⟨substructure.subtype _⟩⟩, _⟩, + ext n, + have hgn := (embedding.ext_iff.1 hg) ((PM.comp NP).equiv_range n), + simp only [embedding.comp_apply, equiv.coe_to_embedding, equiv.symm_apply_apply, + substructure.coe_subtype, embedding.equiv_range_apply] at hgn, + simp only [embedding.comp_apply, equiv.coe_to_embedding, substructure.coe_inclusion, + set.coe_inclusion, embedding.equiv_range_apply, hgn], +end + +lemma is_ultrahomogeneous.age_is_fraisse (hc : (univ : set M).countable) + (h : L.is_ultrahomogeneous M) : + is_fraisse (L.age M) := +⟨age.nonempty M, λ _ hN, hN.1, age.is_equiv_invariant L M, age.countable_quotient M hc, + age.hereditary M, age.joint_embedding M, h.amalgamation_age⟩ -/-- A Fraïssé limit of a Fraïssé class, constructed as a direct limit. -/ -noncomputable def fraisse_limit [h : is_fraisse K] : bundled L.Structure := -classical.some (exists_cg_is_age_of - h.is_nonempty - h.is_equiv_invariant - h.is_essentially_countable - h.fg h.hereditary h.joint_embedding) +namespace is_fraisse_limit -instance cg_fraisse_limit [h : is_fraisse K] : Structure.cg L (fraisse_limit K) := -(classical.some_spec (exists_cg_is_age_of h.is_nonempty h.is_equiv_invariant - h.is_essentially_countable h.fg h.hereditary h.joint_embedding)).1 +/-- If a class has a Fraïssé limit, it must be Fraïssé. -/ +theorem is_fraisse [countable_functions L] (h : is_fraisse_limit K M) : is_fraisse K := +(congr rfl h.age).mp (h.ultrahomogeneous.age_is_fraisse h.countable) -theorem age_fraisse_limit [h : is_fraisse K] : L.age (fraisse_limit K) = K := -(classical.some_spec (exists_cg_is_age_of h.is_nonempty h.is_equiv_invariant - h.is_essentially_countable h.fg h.hereditary h.joint_embedding)).2 +end is_fraisse_limit end language end first_order From 50ff59adea78a1bc90ee50c543251d55ca95b51a Mon Sep 17 00:00:00 2001 From: Aaron Anderson Date: Wed, 13 Apr 2022 10:56:41 +0000 Subject: [PATCH 003/373] feat(model_theory/skolem, satisfiability): A weak Downward Loewenheim Skolem (#13141) Defines a language and structure with built-in Skolem functions for a particular language Proves a weak form of Downward Loewenheim Skolem: every structure has a small (in the universe sense) elementary substructure Shows that `T` having a model in any universe implies `T.is_satisfiable`. --- src/model_theory/bundled.lean | 4 ++ src/model_theory/language_map.lean | 10 ++++ src/model_theory/satisfiability.lean | 5 +- src/model_theory/semantics.lean | 9 +-- src/model_theory/skolem.lean | 84 ++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+), 10 deletions(-) create mode 100644 src/model_theory/skolem.lean diff --git a/src/model_theory/bundled.lean b/src/model_theory/bundled.lean index 0b6b44a884004..85d48a2a09cee 100644 --- a/src/model_theory/bundled.lean +++ b/src/model_theory/bundled.lean @@ -110,5 +110,9 @@ end Theory def elementary_substructure.to_Model {M : T.Model} (S : L.elementary_substructure M) : T.Model := Theory.Model.of T S +instance {M : T.Model} (S : L.elementary_substructure M) [h : small S] : + small (S.to_Model T) := +h + end language end first_order diff --git a/src/model_theory/language_map.lean b/src/model_theory/language_map.lean index b8752af15ce14..3e5fadf355954 100644 --- a/src/model_theory/language_map.lean +++ b/src/model_theory/language_map.lean @@ -195,6 +195,16 @@ instance sum_map_is_expansion_on {L₁ L₂ : language} (ψ : L₁ →ᴸ L₂) (ϕ.sum_map ψ).is_expansion_on M := ⟨λ _ f _, sum.cases_on f (by simp) (by simp), λ _ R _, sum.cases_on R (by simp) (by simp)⟩ +instance sum_inl_is_expansion_on (M : Type*) + [L.Structure M] [L'.Structure M] : + (Lhom.sum_inl : L →ᴸ L.sum L').is_expansion_on M := +⟨λ _ f _, rfl, λ _ R _, rfl⟩ + +instance sum_inr_is_expansion_on (M : Type*) + [L.Structure M] [L'.Structure M] : + (Lhom.sum_inr : L' →ᴸ L.sum L').is_expansion_on M := +⟨λ _ f _, rfl, λ _ R _, rfl⟩ + end Lhom /-- A language equivalence maps the symbols of one language to symbols of another bijectively. -/ diff --git a/src/model_theory/satisfiability.lean b/src/model_theory/satisfiability.lean index db1a509d942e0..73be35b1914ff 100644 --- a/src/model_theory/satisfiability.lean +++ b/src/model_theory/satisfiability.lean @@ -5,6 +5,7 @@ Authors: Aaron Anderson -/ import model_theory.ultraproducts import model_theory.bundled +import model_theory.skolem /-! # First-Order Satisfiability @@ -49,9 +50,9 @@ def is_finitely_satisfiable : Prop := variables {T} {T' : L.Theory} -lemma model.is_satisfiable (M : Type (max u v)) [n : nonempty M] +lemma model.is_satisfiable (M : Type w) [n : nonempty M] [S : L.Structure M] [M ⊨ T] : T.is_satisfiable := -⟨Model.of T M⟩ +⟨((⊥ : substructure _ (Model.of T M)).elementary_skolem₁_reduct.to_Model T).shrink⟩ lemma is_satisfiable.mono (h : T'.is_satisfiable) (hs : T ⊆ T') : T.is_satisfiable := diff --git a/src/model_theory/semantics.lean b/src/model_theory/semantics.lean index c714ecfcb6556..6af58349d3bbf 100644 --- a/src/model_theory/semantics.lean +++ b/src/model_theory/semantics.lean @@ -531,14 +531,7 @@ Theory.model.realize_of_mem φ h @[simp] lemma Lhom.on_Theory_model [L'.Structure M] (φ : L →ᴸ L') [φ.is_expansion_on M] (T : L.Theory) : M ⊨ φ.on_Theory T ↔ M ⊨ T := -begin - split; introI, - { exact ⟨λ ψ hψ, (φ.realize_on_sentence M _).1 - ((φ.on_Theory T).realize_sentence_of_mem (set.mem_image_of_mem φ.on_sentence hψ))⟩ }, - { refine ⟨λ ψ hψ, _⟩, - obtain ⟨ψ₀, hψ₀, rfl⟩ := Lhom.mem_on_Theory.1 hψ, - exact (φ.realize_on_sentence M _).2 (T.realize_sentence_of_mem hψ₀) }, -end +by simp [Theory.model_iff, Lhom.on_Theory] variables {M} {T} diff --git a/src/model_theory/skolem.lean b/src/model_theory/skolem.lean new file mode 100644 index 0000000000000..f26e7c3eb8180 --- /dev/null +++ b/src/model_theory/skolem.lean @@ -0,0 +1,84 @@ +/- +Copyright (c) 2022 Aaron Anderson. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Aaron Anderson +-/ +import model_theory.elementary_maps + +/-! +# Skolem Functions and Downward Löwenheim–Skolem + +## Main Definitions +* `first_order.language.skolem₁` is a language consisting of Skolem functions for another language. + +## Main Results +* `first_order.language.exists_small_elementary_substructure` is a weak version of +Downward Löwenheim–Skolem, showing that any `L`-structure admits a small `L`-elementary +substructure. + +## TODO +* Bound the cardinality of `L.bounded_formula empty (n + 1)`, and based on that, bound the +cardinality of `(⊥ : (L.sum L.skolem₁).substructure M)` well enough to prove +Downward Löwenheim–Skolem. +* Use `skolem₁` recursively to construct an actual Skolemization of a language. + +-/ + +universes u v w + + + +namespace first_order +namespace language +open Structure + +variables (L : language.{u v}) {M : Type w} [nonempty M] [L.Structure M] + +/-- A language consisting of Skolem functions for another language. +Called `skolem₁` because it is the first step in building a Skolemization of a language. -/ +def skolem₁ : language := ⟨λ n, L.bounded_formula empty (n + 1), λ _, empty⟩ + +variables {L} + +/-- The structure assigning each function symbol of `L.skolem₁` to a skolem function generated with +choice. -/ +noncomputable instance skolem₁_Structure : L.skolem₁.Structure M := +⟨λ n φ x, classical.epsilon (λ a, φ.realize default (fin.snoc x a : _ → M)), λ _ r, empty.elim r⟩ + +lemma substructure.skolem₁_reduct_is_elementary (S : (L.sum L.skolem₁).substructure M) : + (Lhom.sum_inl.substructure_reduct S).is_elementary := +begin + apply (Lhom.sum_inl.substructure_reduct S).is_elementary_of_exists, + intros n φ x a h, + let φ' : (L.sum L.skolem₁).functions n := (Lhom.sum_inr.on_function φ), + exact ⟨⟨fun_map φ' (coe ∘ x), S.fun_mem (Lhom.sum_inr.on_function φ) (coe ∘ x) (λ i, (x i).2)⟩, + classical.epsilon_spec ⟨a, h⟩⟩, +end + +/-- Any `L.sum L.skolem₁`-substructure is an elementary `L`-substructure. -/ +noncomputable def substructure.elementary_skolem₁_reduct (S : (L.sum L.skolem₁).substructure M) : + L.elementary_substructure M := +⟨Lhom.sum_inl.substructure_reduct S, λ _, S.skolem₁_reduct_is_elementary⟩ + +lemma substructure.coe_sort_elementary_skolem₁_reduct + (S : (L.sum L.skolem₁).substructure M) : + (S.elementary_skolem₁_reduct : Type w) = S := +rfl + +open cardinal +open_locale cardinal + +variables (L) (M) + +instance : small (⊥ : (L.sum L.skolem₁).substructure M).elementary_skolem₁_reduct := +begin + rw [substructure.coe_sort_elementary_skolem₁_reduct], + apply_instance, +end + +theorem exists_small_elementary_substructure : + ∃ (S : L.elementary_substructure M), small.{max u v} S := +⟨substructure.elementary_skolem₁_reduct ⊥, infer_instance⟩ + +end language +end first_order From 0c3f75bb3c9a9797ad394b77d9df5771d94c05ec Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Wed, 13 Apr 2022 10:56:42 +0000 Subject: [PATCH 004/373] =?UTF-8?q?feat(analysis/normed=5Fspace/basic):=20?= =?UTF-8?q?normed=20division=20algebras=20over=20=E2=84=9D=20are=20also=20?= =?UTF-8?q?normed=20algebras=20over=20=E2=84=9A=20(#13384)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This results shows that `algebra_rat` respects the norm in ` ℝ`-algebras that respect the norm. The new instance carries no new data, as the norm and algebra structure are already defined elsewhere. Probably there is a weaker requirement for compatibility, but I have no idea what it is, and the weakening can come later. --- src/analysis/normed_space/basic.lean | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/analysis/normed_space/basic.lean b/src/analysis/normed_space/basic.lean index 7b72d439e5bf6..140c3a472a96d 100644 --- a/src/analysis/normed_space/basic.lean +++ b/src/analysis/normed_space/basic.lean @@ -419,6 +419,16 @@ end lemma normed_algebra.nontrivial : nontrivial 𝕜' := ⟨⟨0, 1, normed_algebra.zero_ne_one 𝕜 𝕜'⟩⟩ +/-- Any normed characteristic-zero division ring that is a normed_algebra over the reals is also a +normed algebra over the rationals. + +Phrased another way, if `𝕜` is a normed algebra over the reals, then `algebra_rat` respects that +norm. -/ +instance normed_algebra_rat {𝕜} [normed_division_ring 𝕜] [char_zero 𝕜] [normed_algebra ℝ 𝕜] : + normed_algebra ℚ 𝕜 := +{ norm_algebra_map_eq := λ q, + by simpa only [ring_hom.map_rat_algebra_map] using norm_algebra_map_eq 𝕜 (algebra_map _ ℝ q) } + end normed_algebra section restrict_scalars From 991386042dcdf32785cb71f08cc7b6aaf47790b8 Mon Sep 17 00:00:00 2001 From: Alex J Best Date: Wed, 13 Apr 2022 16:27:43 +0000 Subject: [PATCH 005/373] feat(ring_theory/tensor_product): add assoc for tensor product as an algebra homomorphism (#13309) By speeding up a commented out def, this goes from from ~100s to ~7s on my machine . Co-authored-by: Scott Morrison --- src/ring_theory/tensor_product.lean | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/ring_theory/tensor_product.lean b/src/ring_theory/tensor_product.lean index 2257a1b25af18..95948ab5228f1 100644 --- a/src/ring_theory/tensor_product.lean +++ b/src/ring_theory/tensor_product.lean @@ -664,23 +664,21 @@ lemma assoc_aux_2 (r : R) : (tensor_product.assoc R A B C) (((algebra_map R A) r ⊗ₜ[R] 1) ⊗ₜ[R] 1) = (algebra_map R (A ⊗ (B ⊗ C))) r := rfl --- variables (R A B C) +variables (R A B C) --- -- local attribute [elab_simple] alg_equiv_of_linear_equiv_triple_tensor_product +/-- The associator for tensor product of R-algebras, as an algebra isomorphism. -/ +protected def assoc : ((A ⊗[R] B) ⊗[R] C) ≃ₐ[R] (A ⊗[R] (B ⊗[R] C)) := +alg_equiv_of_linear_equiv_triple_tensor_product + (tensor_product.assoc.{u v₁ v₂ v₃} R A B C : (A ⊗ B ⊗ C) ≃ₗ[R] (A ⊗ (B ⊗ C))) + (@algebra.tensor_product.assoc_aux_1.{u v₁ v₂ v₃} R _ A _ _ B _ _ C _ _) + (@algebra.tensor_product.assoc_aux_2.{u v₁ v₂ v₃} R _ A _ _ B _ _ C _ _) --- /-- The associator for tensor product of R-algebras, as an algebra isomorphism. -/ --- -- FIXME This is _really_ slow to compile. :-( --- protected def assoc : ((A ⊗[R] B) ⊗[R] C) ≃ₐ[R] (A ⊗[R] (B ⊗[R] C)) := --- alg_equiv_of_linear_equiv_triple_tensor_product --- (tensor_product.assoc R A B C) --- assoc_aux_1 assoc_aux_2 - --- variables {R A B C} +variables {R A B C} --- @[simp] theorem assoc_tmul (a : A) (b : B) (c : C) : --- ((tensor_product.assoc R A B C) : --- (A ⊗[R] B) ⊗[R] C → A ⊗[R] (B ⊗[R] C)) ((a ⊗ₜ b) ⊗ₜ c) = a ⊗ₜ (b ⊗ₜ c) := --- rfl +@[simp] theorem assoc_tmul (a : A) (b : B) (c : C) : + ((tensor_product.assoc R A B C) : + (A ⊗[R] B) ⊗[R] C → A ⊗[R] (B ⊗[R] C)) ((a ⊗ₜ b) ⊗ₜ c) = a ⊗ₜ (b ⊗ₜ c) := +rfl end From da13598ddd7a8191b786860dad88e7071938360e Mon Sep 17 00:00:00 2001 From: Aaron Anderson Date: Wed, 13 Apr 2022 17:31:46 +0000 Subject: [PATCH 006/373] feat(model_theory/encoding): Bundled encoding of terms (#13226) Bundles `term.list_encode` and `term.list_decode` into a `computability.encoding` --- src/model_theory/encoding.lean | 40 ++++++++++++++++------------ src/set_theory/cardinal_ordinal.lean | 10 +++++++ 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/model_theory/encoding.lean b/src/model_theory/encoding.lean index c1fd9dab3aa06..9a731f1687f25 100644 --- a/src/model_theory/encoding.lean +++ b/src/model_theory/encoding.lean @@ -6,6 +6,7 @@ Authors: Aaron Anderson import model_theory.syntax import set_theory.cardinal_ordinal +import computability.encoding /-! # Encodings and Cardinality of First-Order Syntax @@ -18,7 +19,6 @@ import set_theory.cardinal_ordinal `# (α ⊕ Σ i, L.functions i) + ω`. ## TODO -* Bundle `term.list_encode` and `term.list_decode` together with `computability.encoding`. * An encoding for formulas * `fin_encoding`s for terms and formulas, based on the `encoding`s * Computability facts about these `fin_encoding`s, to set up a computability approach to @@ -35,19 +35,19 @@ variables {L : language.{u v}} variables {M : Type w} {N P : Type*} [L.Structure M] [L.Structure N] [L.Structure P] variables {α : Type u'} {β : Type v'} open_locale first_order cardinal -open list Structure cardinal fin +open computability list Structure cardinal fin namespace term /-- Encodes a term as a list of variables and function symbols. -/ -def list_encode : L.term α → list (α ⊕ (Σ i, L.functions i)) +def list_encode : L.term α → list (α ⊕ Σ i, L.functions i) | (var i) := [sum.inl i] | (func f ts) := ((sum.inr (⟨_, f⟩ : Σ i, L.functions i)) :: ((list.fin_range _).bind (λ i, (ts i).list_encode))) /-- Decodes a list of variables and function symbols as a list of terms. -/ def list_decode [inhabited (L.term α)] : - list (α ⊕ (Σ i, L.functions i)) → list (L.term α) + list (α ⊕ Σ i, L.functions i) → list (L.term α) | [] := [] | ((sum.inl a) :: l) := var a :: list_decode l | ((sum.inr ⟨n, f⟩) :: l) := func f (λ i, ((list_decode l).nth i).iget) :: ((list_decode l).drop n) @@ -55,7 +55,7 @@ def list_decode [inhabited (L.term α)] : @[simp] theorem list_decode_encode_list [inhabited (L.term α)] (l : list (L.term α)) : list_decode (l.bind list_encode) = l := begin - suffices h : ∀ (t : L.term α) (l : list (α ⊕ (Σ i, L.functions i))), + suffices h : ∀ (t : L.term α) (l : list (α ⊕ Σ i, L.functions i)), list_decode (t.list_encode ++ l) = t :: list_decode l, { induction l with t l lih, { refl }, @@ -84,26 +84,32 @@ begin rw [length_map, length_fin_range] } } } end +/-- An encoding of terms as lists. -/ +@[simps] protected def encoding [inhabited (L.term α)] : encoding (L.term α) := +{ Γ := α ⊕ Σ i, L.functions i, + encode := list_encode, + decode := λ l, (list_decode l).head', + decode_encode := λ t, begin + have h := list_decode_encode_list [t], + rw [bind_singleton] at h, + rw [h, head'], + end } + lemma list_encode_injective : - function.injective (list_encode : L.term α → list (α ⊕ (Σ i, L.functions i))) := + function.injective (list_encode : L.term α → list (α ⊕ Σ i, L.functions i)) := begin - cases is_empty_or_nonempty (L.term α) with he hne, + casesI is_empty_or_nonempty (L.term α) with he hne, { exact he.elim }, - { resetI, - inhabit (L.term α), - intros t1 t2 h, - have h' : (list_decode ([t1].bind (list_encode))) = (list_decode ([t2].bind (list_encode))), - { rw [bind_singleton, h, bind_singleton] }, - rw [list_decode_encode_list, list_decode_encode_list] at h', - exact head_eq_of_cons_eq h' } + { inhabit (L.term α), + exact term.encoding.encode_injective } end -theorem card_le : # (L.term α) ≤ # (α ⊕ (Σ i, L.functions i)) + ω := +theorem card_le : # (L.term α) ≤ # (α ⊕ Σ i, L.functions i) + ω := begin have h := (mk_le_of_injective list_encode_injective), refine h.trans _, - casesI fintype_or_infinite (α ⊕ (Σ i, L.functions i)) with ft inf, - { haveI := fintype.encodable (α ⊕ (Σ i, L.functions i)), + casesI fintype_or_infinite (α ⊕ Σ i, L.functions i) with ft inf, + { haveI := fintype.encodable (α ⊕ Σ i, L.functions i), exact le_add_left (encodable_iff.1 ⟨encodable.list⟩) }, { rw mk_list_eq_mk, exact le_self_add } diff --git a/src/set_theory/cardinal_ordinal.lean b/src/set_theory/cardinal_ordinal.lean index f346d6c2ce4d1..0a87039e7e20a 100644 --- a/src/set_theory/cardinal_ordinal.lean +++ b/src/set_theory/cardinal_ordinal.lean @@ -662,6 +662,16 @@ calc #(list α) theorem mk_list_eq_omega (α : Type u) [encodable α] [nonempty α] : #(list α) = ω := mk_le_omega.antisymm (omega_le_mk _) +theorem mk_list_eq_max_mk_omega (α : Type u) [nonempty α] : #(list α) = max (#α) ω := +begin + casesI fintype_or_infinite α, + { haveI : encodable α := fintype.encodable α, + rw [mk_list_eq_omega, eq_comm, max_eq_right], + exact mk_le_omega }, + { rw [mk_list_eq_mk, eq_comm, max_eq_left], + exact omega_le_mk α } +end + theorem mk_list_le_max (α : Type u) : #(list α) ≤ max ω (#α) := begin casesI fintype_or_infinite α, From 76c969b744a3a81d5a15782b94bb43edff47d7b6 Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Wed, 13 Apr 2022 18:43:15 +0000 Subject: [PATCH 007/373] chore(algebra/polynomial/big_operators): drop some nontrivial assumptions (#13428) --- src/algebra/polynomial/big_operators.lean | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/algebra/polynomial/big_operators.lean b/src/algebra/polynomial/big_operators.lean index 71d3f0fa4cf89..a0a3f285921e0 100644 --- a/src/algebra/polynomial/big_operators.lean +++ b/src/algebra/polynomial/big_operators.lean @@ -186,9 +186,10 @@ lemma nat_degree_prod' (h : ∏ i in s, (f i).leading_coeff ≠ 0) : (∏ i in s, f i).nat_degree = ∑ i in s, (f i).nat_degree := by simpa using nat_degree_multiset_prod' (s.1.map f) (by simpa using h) -lemma nat_degree_multiset_prod_of_monic [nontrivial R] (h : ∀ f ∈ t, monic f) : +lemma nat_degree_multiset_prod_of_monic (h : ∀ f ∈ t, monic f) : t.prod.nat_degree = (t.map nat_degree).sum := begin + nontriviality R, apply nat_degree_multiset_prod', suffices : (t.map (λ f, leading_coeff f)).prod = 1, { rw this, simp }, convert prod_repeat (1 : R) t.card, @@ -199,7 +200,7 @@ begin { simp } end -lemma nat_degree_prod_of_monic [nontrivial R] (h : ∀ i ∈ s, (f i).monic) : +lemma nat_degree_prod_of_monic (h : ∀ i ∈ s, (f i).monic) : (∏ i in s, f i).nat_degree = ∑ i in s, (f i).nat_degree := by simpa using nat_degree_multiset_prod_of_monic (s.1.map f) (by simpa using h) @@ -285,18 +286,20 @@ the sum of the degrees. See `polynomial.nat_degree_prod'` (with a `'`) for a version for commutative semirings, where additionally, the product of the leading coefficients must be nonzero. -/ -lemma nat_degree_prod [nontrivial R] (h : ∀ i ∈ s, f i ≠ 0) : +lemma nat_degree_prod (h : ∀ i ∈ s, f i ≠ 0) : (∏ i in s, f i).nat_degree = ∑ i in s, (f i).nat_degree := begin + nontriviality R, apply nat_degree_prod', rw prod_ne_zero_iff, intros x hx, simp [h x hx] end -lemma nat_degree_multiset_prod [nontrivial R] (s : multiset R[X]) +lemma nat_degree_multiset_prod (s : multiset R[X]) (h : (0 : R[X]) ∉ s) : nat_degree s.prod = (s.map nat_degree).sum := begin + nontriviality R, rw nat_degree_multiset_prod', simp_rw [ne.def, multiset.prod_eq_zero_iff, multiset.mem_map, leading_coeff_eq_zero], rintro ⟨_, h, rfl⟩, From 6f401acf4faec3ab9ab13a42789c4f68064a61cd Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Wed, 13 Apr 2022 22:15:36 +0000 Subject: [PATCH 008/373] feat(data/polynomial/*): suggestions from the generalization linter (#13342) Co-authored-by: negiizhao Co-authored-by: Scott Morrison --- src/data/complex/exponential.lean | 20 +++-- src/data/polynomial/algebra_map.lean | 6 +- src/data/polynomial/cancel_leads.lean | 7 +- src/data/polynomial/degree/definitions.lean | 16 ++++ src/data/polynomial/derivative.lean | 6 +- src/data/polynomial/div.lean | 15 ---- src/data/polynomial/eval.lean | 74 +++++++++++------ src/data/polynomial/field_division.lean | 22 ++--- .../polynomial/integral_normalization.lean | 2 +- src/data/polynomial/monic.lean | 83 ++++++++++--------- src/data/polynomial/reverse.lean | 4 +- src/data/polynomial/ring_division.lean | 26 ++++-- 12 files changed, 166 insertions(+), 115 deletions(-) diff --git a/src/data/complex/exponential.lean b/src/data/complex/exponential.lean index bae3c251cb0ec..5f26576b36824 100644 --- a/src/data/complex/exponential.lean +++ b/src/data/complex/exponential.lean @@ -110,10 +110,9 @@ is_cau_series_of_abv_le_cau 0 (λ n h, le_rfl) end no_archimedean section -variables {α : Type*} {β : Type*} [ring β] - [linear_ordered_field α] [archimedean α] {abv : β → α} [is_absolute_value abv] +variables {α : Type*} [linear_ordered_field α] [archimedean α] -lemma is_cau_geo_series {β : Type*} [field β] {abv : β → α} [is_absolute_value abv] +lemma is_cau_geo_series {β : Type*} [ring β] [nontrivial β] {abv : β → α} [is_absolute_value abv] (x : β) (hx1 : abv x < 1) : is_cau_seq abv (λ n, ∑ m in range n, x ^ m) := have hx1' : abv x ≠ 1 := λ h, by simpa [h, lt_irrefl] using hx1, is_cau_series_of_abv_cau @@ -146,6 +145,8 @@ have is_cau_seq abs (λ m, a * ∑ n in range m, x ^ n) := (cau_seq.const abs a * ⟨_, is_cau_geo_series x hx1⟩).2, by simpa only [mul_sum] +variables {β : Type*} [ring β] {abv : β → α} [is_absolute_value abv] + lemma series_ratio_test {f : ℕ → β} (n : ℕ) (r : α) (hr0 : 0 ≤ r) (hr1 : r < 1) (h : ∀ m, n ≤ m → abv (f m.succ) ≤ r * abv (f m)) : is_cau_seq abv (λ m, ∑ n in range m, f n) := @@ -200,8 +201,10 @@ by rw [sum_sigma', sum_sigma']; exact sum_bij end section no_archimedean -variables {α : Type*} {β : Type*} [ring β] - [linear_ordered_field α] {abv : β → α} [is_absolute_value abv] +variables {α : Type*} {β : Type*} [linear_ordered_field α] {abv : β → α} + +section +variables [semiring β] [is_absolute_value abv] lemma abv_sum_le_sum_abv {γ : Type*} (f : γ → β) (s : finset γ) : abv (∑ k in s, f k) ≤ ∑ k in s, abv (f k) := @@ -210,6 +213,11 @@ finset.induction_on s (by simp [abv_zero abv]) (λ a s has ih, by rw [sum_insert has, sum_insert has]; exact le_trans (abv_add abv _ _) (add_le_add_left ih _)) +end + +section +variables [ring β] [is_absolute_value abv] + lemma cauchy_product {a b : ℕ → β} (ha : is_cau_seq abs (λ m, ∑ n in range m, abv (a n))) (hb : is_cau_seq abv (λ m, ∑ n in range m, b n)) (ε : α) (ε0 : 0 < ε) : @@ -293,6 +301,8 @@ begin (nat.le_succ_of_le (le_max_right _ _)))) end⟩ +end + end no_archimedean end diff --git a/src/data/polynomial/algebra_map.lean b/src/data/polynomial/algebra_map.lean index 11270a59ed0d9..53bd9cf0ee2b9 100644 --- a/src/data/polynomial/algebra_map.lean +++ b/src/data/polynomial/algebra_map.lean @@ -20,7 +20,7 @@ open_locale big_operators polynomial namespace polynomial universes u v w z variables {R : Type u} {S : Type v} {T : Type w} {A : Type z} {A' B' : Type*} {a b : R} {n : ℕ} -variables [comm_semiring A'] [comm_semiring B'] +variables [comm_semiring A'] [semiring B'] section comm_semiring variables [comm_semiring R] {p q r : R[X]} @@ -105,7 +105,7 @@ end⟩⟩ @[simp] lemma alg_hom_eval₂_algebra_map - {R A B : Type*} [comm_ring R] [ring A] [ring B] [algebra R A] [algebra R B] + {R A B : Type*} [comm_semiring R] [semiring A] [semiring B] [algebra R A] [algebra R B] (p : R[X]) (f : A →ₐ[R] B) (a : A) : f (eval₂ (algebra_map R A) a p) = eval₂ (algebra_map R B) (f a) p := begin @@ -115,7 +115,7 @@ begin end @[simp] -lemma eval₂_algebra_map_X {R A : Type*} [comm_ring R] [ring A] [algebra R A] +lemma eval₂_algebra_map_X {R A : Type*} [comm_semiring R] [semiring A] [algebra R A] (p : R[X]) (f : R[X] →ₐ[R] A) : eval₂ (algebra_map R A) (f X) p = f p := begin diff --git a/src/data/polynomial/cancel_leads.lean b/src/data/polynomial/cancel_leads.lean index 9a039b05c0f79..377db80acaa79 100644 --- a/src/data/polynomial/cancel_leads.lean +++ b/src/data/polynomial/cancel_leads.lean @@ -24,7 +24,7 @@ open_locale polynomial variables {R : Type*} section comm_ring -variables [comm_ring R] (p q : R[X]) +variables [ring R] (p q : R[X]) /-- `cancel_leads p q` is formed by multiplying `p` and `q` by monomials so that they have the same leading term, and then subtracting. -/ @@ -36,6 +36,11 @@ variables {p q} @[simp] lemma neg_cancel_leads : - p.cancel_leads q = q.cancel_leads p := neg_sub _ _ +end comm_ring + +section comm_ring +variables [comm_ring R] {p q : R[X]} + lemma dvd_cancel_leads_of_dvd_of_dvd {r : R[X]} (pq : p ∣ q) (pr : p ∣ r) : p ∣ q.cancel_leads r := dvd_sub (pr.trans (dvd.intro_left _ rfl)) (pq.trans (dvd.intro_left _ rfl)) diff --git a/src/data/polynomial/degree/definitions.lean b/src/data/polynomial/degree/definitions.lean index 9a39e2b3878a0..e646f136c8d5b 100644 --- a/src/data/polynomial/degree/definitions.lean +++ b/src/data/polynomial/degree/definitions.lean @@ -267,6 +267,22 @@ lemma sum_over_range [add_comm_monoid S] (p : R[X]) {f : ℕ → R → S} (h : p.sum f = ∑ (a : ℕ) in range (p.nat_degree + 1), f a (coeff p a) := sum_over_range' p h (p.nat_degree + 1) (lt_add_one _) +-- TODO this is essentially a duplicate of `sum_over_range`, and should be removed. +lemma sum_fin [add_comm_monoid S] + (f : ℕ → R → S) (hf : ∀ i, f i 0 = 0) {n : ℕ} {p : R[X]} (hn : p.degree < n) : + ∑ (i : fin n), f i (p.coeff i) = p.sum f := +begin + by_cases hp : p = 0, + { rw [hp, sum_zero_index, finset.sum_eq_zero], intros i _, exact hf i }, + rw [degree_eq_nat_degree hp, with_bot.coe_lt_coe] at hn, + calc ∑ (i : fin n), f i (p.coeff i) + = ∑ i in finset.range n, f i (p.coeff i) : fin.sum_univ_eq_sum_range (λ i, f i (p.coeff i)) _ + ... = ∑ i in p.support, f i (p.coeff i) : (finset.sum_subset + (supp_subset_range_nat_degree_succ.trans (finset.range_subset.mpr hn)) + (λ i _ hi, show f i (p.coeff i) = 0, by rw [not_mem_support_iff.mp hi, hf])).symm + ... = p.sum f : p.sum_def _ +end + lemma as_sum_range' (p : R[X]) (n : ℕ) (w : p.nat_degree < n) : p = ∑ i in range n, monomial i (coeff p i) := p.sum_monomial_eq.symm.trans $ p.sum_over_range' monomial_zero_right _ w diff --git a/src/data/polynomial/derivative.lean b/src/data/polynomial/derivative.lean index a5afc3a7270e8..21431e6bed47a 100644 --- a/src/data/polynomial/derivative.lean +++ b/src/data/polynomial/derivative.lean @@ -359,8 +359,8 @@ end end comm_ring -section is_domain -variables [ring R] [is_domain R] +section no_zero_divisors +variables [ring R] [no_zero_divisors R] lemma mem_support_derivative [char_zero R] (p : R[X]) (n : ℕ) : n ∈ (derivative p).support ↔ n + 1 ∈ p.support := @@ -388,7 +388,7 @@ begin exact hp } end -end is_domain +end no_zero_divisors end derivative end polynomial diff --git a/src/data/polynomial/div.lean b/src/data/polynomial/div.lean index b57458f35c7da..dbf72602e0694 100644 --- a/src/data/polynomial/div.lean +++ b/src/data/polynomial/div.lean @@ -389,21 +389,6 @@ lemma eval₂_mod_by_monic_eq_self_of_root [comm_ring S] {f : R →+* S} (p %ₘ q).eval₂ f x = p.eval₂ f x := by rw [mod_by_monic_eq_sub_mul_div p hq, eval₂_sub, eval₂_mul, hx, zero_mul, sub_zero] -lemma sum_fin [add_comm_monoid S] (f : ℕ → R → S) (hf : ∀ i, f i 0 = 0) - {n : ℕ} (hn : p.degree < n) : - ∑ (i : fin n), f i (p.coeff i) = p.sum f := -begin - by_cases hp : p = 0, - { rw [hp, sum_zero_index, finset.sum_eq_zero], intros i _, exact hf i }, - rw [degree_eq_nat_degree hp, with_bot.coe_lt_coe] at hn, - calc ∑ (i : fin n), f i (p.coeff i) - = ∑ i in finset.range n, f i (p.coeff i) : fin.sum_univ_eq_sum_range (λ i, f i (p.coeff i)) _ - ... = ∑ i in p.support, f i (p.coeff i) : (finset.sum_subset - (supp_subset_range_nat_degree_succ.trans (finset.range_subset.mpr hn)) - (λ i _ hi, show f i (p.coeff i) = 0, by rw [not_mem_support_iff.mp hi, hf])).symm - ... = p.sum f : p.sum_def _ -end - lemma sum_mod_by_monic_coeff (hq : q.monic) {n : ℕ} (hn : q.degree ≤ n) : ∑ (i : fin n), monomial i ((p %ₘ q).coeff i) = p %ₘ q := begin diff --git a/src/data/polynomial/eval.lean b/src/data/polynomial/eval.lean index 8217f59a26ed1..a2d31a2ea3e5a 100644 --- a/src/data/polynomial/eval.lean +++ b/src/data/polynomial/eval.lean @@ -186,8 +186,26 @@ as long as target ring is commutative (even if the source ring is not). -/ section eval₂ -variables [comm_semiring S] -variables (f : R →+* S) (x : S) + +section +variables [semiring S] (f : R →+* S) (x : S) + +lemma eval₂_eq_sum_range : + p.eval₂ f x = ∑ i in finset.range (p.nat_degree + 1), f (p.coeff i) * x^i := +trans (congr_arg _ p.as_sum_range) (trans (eval₂_finset_sum f _ _ x) (congr_arg _ (by simp))) + +lemma eval₂_eq_sum_range' (f : R →+* S) {p : R[X]} {n : ℕ} (hn : p.nat_degree < n) (x : S) : + eval₂ f x p = ∑ i in finset.range n, f (p.coeff i) * x ^ i := +begin + rw [eval₂_eq_sum, p.sum_over_range' _ _ hn], + intro i, + rw [f.map_zero, zero_mul] +end + +end + +section +variables [comm_semiring S] (f : R →+* S) (x : S) @[simp] lemma eval₂_mul : (p * q).eval₂ f x = p.eval₂ f x * q.eval₂ f x := eval₂_mul_noncomm _ _ $ λ k, commute.all _ _ @@ -216,18 +234,6 @@ def eval₂_ring_hom (f : R →+* S) (x : S) : R[X] →+* S := lemma eval₂_pow (n : ℕ) : (p ^ n).eval₂ f x = p.eval₂ f x ^ n := (eval₂_ring_hom _ _).map_pow _ _ -lemma eval₂_eq_sum_range : - p.eval₂ f x = ∑ i in finset.range (p.nat_degree + 1), f (p.coeff i) * x^i := -trans (congr_arg _ p.as_sum_range) (trans (eval₂_finset_sum f _ _ x) (congr_arg _ (by simp))) - -lemma eval₂_eq_sum_range' (f : R →+* S) {p : R[X]} {n : ℕ} (hn : p.nat_degree < n) (x : S) : - eval₂ f x p = ∑ i in finset.range n, f (p.coeff i) * x ^ i := -begin - rw [eval₂_eq_sum, p.sum_over_range' _ _ hn], - intro i, - rw [f.map_zero, zero_mul] -end - lemma eval₂_dvd : p ∣ q → eval₂ f x p ∣ eval₂ f x q := (eval₂_ring_hom f x).map_dvd @@ -239,6 +245,8 @@ lemma eval₂_list_prod (l : list R[X]) (x : S) : eval₂ f x l.prod = (l.map (eval₂ f x)).prod := map_list_prod (eval₂_ring_hom f x) l +end + end eval₂ section eval @@ -725,12 +733,27 @@ section comm_semiring section eval -variables [comm_semiring R] {p q : R[X]} {x : R} [comm_semiring S] (f : R →+* S) +section +variables [semiring R] {p q : R[X]} {x : R} [semiring S] (f : R →+* S) + +lemma eval₂_hom (x : R) : + p.eval₂ f (f x) = f (p.eval x) := +(ring_hom.comp_id f) ▸ (hom_eval₂ p (ring_hom.id R) f x).symm + +end + +section +variables [semiring R] {p q : R[X]} {x : R} [comm_semiring S] (f : R →+* S) lemma eval₂_comp {x : S} : eval₂ f x (p.comp q) = eval₂ f (eval₂ f x q) p := by rw [comp, p.as_sum_range]; simp [eval₂_finset_sum, eval₂_pow] +end + +section +variables [comm_semiring R] {p q : R[X]} {x : R} [comm_semiring S] (f : R →+* S) + @[simp] lemma eval_mul : (p * q).eval x = p.eval x * q.eval x := eval₂_mul _ _ /-- `eval r`, regarded as a ring homomorphism from `polynomial R` to `R`. -/ @@ -752,10 +775,6 @@ end def comp_ring_hom : R[X] → R[X] →+* R[X] := eval₂_ring_hom C -lemma eval₂_hom (x : R) : - p.eval₂ f (f x) = f (p.eval x) := -(ring_hom.comp_id f) ▸ (hom_eval₂ p (ring_hom.id R) f x).symm - lemma root_mul_left_of_is_root (p : R[X]) {q : R[X]} : is_root q a → is_root (p * q) a := λ H, by rw [is_root, eval_mul, is_root.def.1 H, mul_zero] @@ -808,6 +827,8 @@ eval₂_eq_zero_of_dvd_of_eval₂_eq_zero _ _ lemma eval_geom_sum {R} [comm_semiring R] {n : ℕ} {x : R} : eval x (geom_sum X n) = geom_sum x n := by simp [geom_sum_def, eval_finset_sum] +end + end eval section map @@ -816,6 +837,14 @@ section map lemma map_dvd {R S} [semiring R] [comm_semiring S] (f : R →+* S) {x y : R[X]} : x ∣ y → x.map f ∣ y.map f := eval₂_dvd _ _ +lemma support_map_subset [semiring R] [comm_semiring S] (f : R →+* S) (p : R[X]) : + (map f p).support ⊆ p.support := +begin + intros x, + contrapose!, + simp { contextual := tt }, +end + variables [comm_semiring R] [comm_semiring S] (f : R →+* S) protected lemma map_multiset_prod (m : multiset R[X]) : m.prod.map f = (m.map $ map f).prod := @@ -825,13 +854,6 @@ protected lemma map_prod {ι : Type*} (g : ι → R[X]) (s : finset ι) : (∏ i in s, g i).map f = ∏ i in s, (g i).map f := (map_ring_hom f).map_prod _ _ -lemma support_map_subset (p : R[X]) : (map f p).support ⊆ p.support := -begin - intros x, - contrapose!, - simp { contextual := tt }, -end - lemma is_root.map {f : R →+* S} {x : R} {p : R[X]} (h : is_root p x) : is_root (p.map f) (f x) := by rw [is_root, eval_map, eval₂_hom, h.eq_zero, f.map_zero] diff --git a/src/data/polynomial/field_division.lean b/src/data/polynomial/field_division.lean index fed5309b91d0b..d2ad1a0f19ade 100644 --- a/src/data/polynomial/field_division.lean +++ b/src/data/polynomial/field_division.lean @@ -147,6 +147,13 @@ have h₁ : (leading_coeff q)⁻¹ ≠ 0 := inv_ne_zero (mt leading_coeff_eq_zero.1 h), by rw [degree_mul, degree_C h₁, add_zero] +@[simp] lemma map_eq_zero [semiring S] [nontrivial S] (f : R →+* S) : + p.map f = 0 ↔ p = 0 := +by simp only [polynomial.ext_iff, f.map_eq_zero, coeff_map, coeff_zero] + +lemma map_ne_zero [semiring S] [nontrivial S] {f : R →+* S} (hp : p ≠ 0) : p.map f ≠ 0 := +mt (map_eq_zero f).1 hp + end division_ring section field @@ -268,19 +275,19 @@ by rw [div_def, mul_comm, degree_mul_leading_coeff_inv _ hq0]; exact degree_div_by_monic_lt _ (monic_mul_leading_coeff_inv hq0) hp (by rw degree_mul_leading_coeff_inv _ hq0; exact hq) -@[simp] lemma degree_map [field k] (p : R[X]) (f : R →+* k) : +@[simp] lemma degree_map [division_ring k] (p : R[X]) (f : R →+* k) : degree (p.map f) = degree p := p.degree_map_eq_of_injective f.injective -@[simp] lemma nat_degree_map [field k] (f : R →+* k) : +@[simp] lemma nat_degree_map [division_ring k] (f : R →+* k) : nat_degree (p.map f) = nat_degree p := nat_degree_eq_of_degree_eq (degree_map _ f) -@[simp] lemma leading_coeff_map [field k] (f : R →+* k) : +@[simp] lemma leading_coeff_map [division_ring k] (f : R →+* k) : leading_coeff (p.map f) = f (leading_coeff p) := by simp only [← coeff_nat_degree, coeff_map f, nat_degree_map] -theorem monic_map_iff [field k] {f : R →+* k} {p : R[X]} : +theorem monic_map_iff [division_ring k] {f : R →+* k} {p : R[X]} : (p.map f).monic ↔ p.monic := by rw [monic, leading_coeff_map, ← f.map_one, function.injective.eq_iff f.injective, monic] @@ -339,13 +346,6 @@ theorem is_coprime_map [field k] (f : R →+* k) : is_coprime (p.map f) (q.map f) ↔ is_coprime p q := by rw [← euclidean_domain.gcd_is_unit_iff, ← euclidean_domain.gcd_is_unit_iff, gcd_map, is_unit_map] -@[simp] lemma map_eq_zero [semiring S] [nontrivial S] (f : R →+* S) : - p.map f = 0 ↔ p = 0 := -by simp only [polynomial.ext_iff, f.map_eq_zero, coeff_map, coeff_zero] - -lemma map_ne_zero [semiring S] [nontrivial S] {f : R →+* S} (hp : p ≠ 0) : p.map f ≠ 0 := -mt (map_eq_zero f).1 hp - lemma mem_roots_map [field k] {f : R →+* k} {x : k} (hp : p ≠ 0) : x ∈ (p.map f).roots ↔ p.eval₂ f x = 0 := begin diff --git a/src/data/polynomial/integral_normalization.lean b/src/data/polynomial/integral_normalization.lean index f4414eefc061a..21b207a18e9b4 100644 --- a/src/data/polynomial/integral_normalization.lean +++ b/src/data/polynomial/integral_normalization.lean @@ -90,7 +90,7 @@ end is_domain section is_domain variables [comm_ring R] [is_domain R] -variables [comm_ring S] +variables [comm_semiring S] lemma integral_normalization_eval₂_eq_zero {p : R[X]} (f : R →+* S) {z : S} (hz : eval₂ f z p = 0) (inj : ∀ (x : R), f x = 0 → x = 0) : diff --git a/src/data/polynomial/monic.lean b/src/data/polynomial/monic.lean index 6bc8fd0a268b0..e7b2c97a39360 100644 --- a/src/data/polynomial/monic.lean +++ b/src/data/polynomial/monic.lean @@ -275,44 +275,8 @@ monic.next_coeff_multiset_prod s.1 f h end comm_semiring -section ring -variables [ring R] {p : R[X]} - -theorem monic_X_sub_C (x : R) : monic (X - C x) := -by simpa only [sub_eq_add_neg, C_neg] using monic_X_add_C (-x) - -theorem monic_X_pow_sub {n : ℕ} (H : degree p ≤ n) : monic (X ^ (n+1) - p) := -by simpa [sub_eq_add_neg] using monic_X_pow_add (show degree (-p) ≤ n, by rwa ←degree_neg p at H) - -/-- `X ^ n - a` is monic. -/ -lemma monic_X_pow_sub_C {R : Type u} [ring R] (a : R) {n : ℕ} (h : n ≠ 0) : (X ^ n - C a).monic := -begin - obtain ⟨k, hk⟩ := nat.exists_eq_succ_of_ne_zero h, - convert monic_X_pow_sub _, - exact le_trans degree_C_le nat.with_bot.coe_nonneg, -end - -lemma not_is_unit_X_pow_sub_one (R : Type*) [comm_ring R] [nontrivial R] (n : ℕ) : - ¬ is_unit (X ^ n - 1 : R[X]) := -begin - intro h, - rcases eq_or_ne n 0 with rfl | hn, - { simpa using h }, - apply hn, - rwa [← @nat_degree_X_pow_sub_C _ _ _ n (1 : R), - eq_one_of_is_unit_of_monic (monic_X_pow_sub_C (1 : R) hn), - nat_degree_one] -end - -lemma monic_sub_of_left {p q : R[X]} (hp : monic p) (hpq : degree q < degree p) : - monic (p - q) := -by { rw sub_eq_add_neg, apply hp.add_of_left, rwa degree_neg } - -lemma monic_sub_of_right {p q : R[X]} - (hq : q.leading_coeff = -1) (hpq : degree p < degree q) : monic (p - q) := -have (-q).coeff (-q).nat_degree = 1 := -by rw [nat_degree_neg, coeff_neg, show q.coeff q.nat_degree = -1, from hq, neg_neg], -by { rw sub_eq_add_neg, apply monic.add_of_right this, rwa degree_neg } +section semiring +variables [semiring R] @[simp] lemma monic.nat_degree_map [semiring S] [nontrivial S] {P : polynomial R} (hmo : P.monic) @@ -380,8 +344,49 @@ begin end end injective -end ring +end semiring + +section ring +variables [ring R] {p : R[X]} + +theorem monic_X_sub_C (x : R) : monic (X - C x) := +by simpa only [sub_eq_add_neg, C_neg] using monic_X_add_C (-x) + +theorem monic_X_pow_sub {n : ℕ} (H : degree p ≤ n) : monic (X ^ (n+1) - p) := +by simpa [sub_eq_add_neg] using monic_X_pow_add (show degree (-p) ≤ n, by rwa ←degree_neg p at H) + +/-- `X ^ n - a` is monic. -/ +lemma monic_X_pow_sub_C {R : Type u} [ring R] (a : R) {n : ℕ} (h : n ≠ 0) : (X ^ n - C a).monic := +begin + obtain ⟨k, hk⟩ := nat.exists_eq_succ_of_ne_zero h, + convert monic_X_pow_sub _, + exact le_trans degree_C_le nat.with_bot.coe_nonneg, +end + +lemma not_is_unit_X_pow_sub_one (R : Type*) [comm_ring R] [nontrivial R] (n : ℕ) : + ¬ is_unit (X ^ n - 1 : R[X]) := +begin + intro h, + rcases eq_or_ne n 0 with rfl | hn, + { simpa using h }, + apply hn, + rwa [← @nat_degree_X_pow_sub_C _ _ _ n (1 : R), + eq_one_of_is_unit_of_monic (monic_X_pow_sub_C (1 : R) hn), + nat_degree_one] +end + +lemma monic_sub_of_left {p q : R[X]} (hp : monic p) (hpq : degree q < degree p) : + monic (p - q) := +by { rw sub_eq_add_neg, apply hp.add_of_left, rwa degree_neg } + +lemma monic_sub_of_right {p q : R[X]} + (hq : q.leading_coeff = -1) (hpq : degree p < degree q) : monic (p - q) := +have (-q).coeff (-q).nat_degree = 1 := +by rw [nat_degree_neg, coeff_neg, show q.coeff q.nat_degree = -1, from hq, neg_neg], +by { rw sub_eq_add_neg, apply monic.add_of_right this, rwa degree_neg } + +end ring section nonzero_semiring variables [semiring R] [nontrivial R] {p q : R[X]} diff --git a/src/data/polynomial/reverse.lean b/src/data/polynomial/reverse.lean index 9beaa3540eaf7..38373d31395af 100644 --- a/src/data/polynomial/reverse.lean +++ b/src/data/polynomial/reverse.lean @@ -281,7 +281,7 @@ begin rw [nat_degree_mul' fg, reflect_mul f g rfl.le rfl.le], end -@[simp] lemma reverse_mul_of_domain {R : Type*} [ring R] [is_domain R] (f g : R[X]) : +@[simp] lemma reverse_mul_of_domain {R : Type*} [ring R] [no_zero_divisors R] (f g : R[X]) : reverse (f * g) = reverse f * reverse g := begin by_cases f0 : f=0, @@ -291,7 +291,7 @@ begin simp [reverse_mul, *], end -lemma trailing_coeff_mul {R : Type*} [ring R] [is_domain R] (p q : R[X]) : +lemma trailing_coeff_mul {R : Type*} [ring R] [no_zero_divisors R] (p q : R[X]) : (p * q).trailing_coeff = p.trailing_coeff * q.trailing_coeff := by rw [←reverse_leading_coeff, reverse_mul_of_domain, leading_coeff_mul, reverse_leading_coeff, reverse_leading_coeff] diff --git a/src/data/polynomial/ring_division.lean b/src/data/polynomial/ring_division.lean index f9a9693410ded..d794849bb6dd3 100644 --- a/src/data/polynomial/ring_division.lean +++ b/src/data/polynomial/ring_division.lean @@ -26,7 +26,8 @@ variables {R : Type u} {S : Type v} {T : Type w} {A : Type z} {a b : R} {n : ℕ section comm_ring variables [comm_ring R] {p q : R[X]} -variables [ring S] +section +variables [semiring S] lemma nat_degree_pos_of_aeval_root [algebra R S] {p : R[X]} (hp : p ≠ 0) {z : S} (hz : aeval z p = 0) (inj : ∀ (x : R), algebra_map R S x = 0 → x = 0) : @@ -38,12 +39,6 @@ lemma degree_pos_of_aeval_root [algebra R S] {p : R[X]} (hp : p ≠ 0) 0 < p.degree := nat_degree_pos_iff_degree_pos.mp (nat_degree_pos_of_aeval_root hp hz inj) -lemma aeval_mod_by_monic_eq_self_of_root [algebra R S] - {p q : R[X]} (hq : q.monic) {x : S} (hx : aeval x q = 0) : - aeval x (p %ₘ q) = aeval x p := --- `eval₂_mod_by_monic_eq_self_of_root` doesn't work here as it needs commutativity -by rw [mod_by_monic_eq_sub_mul_div p hq, _root_.map_sub, _root_.map_mul, hx, zero_mul, sub_zero] - lemma mod_by_monic_eq_of_dvd_sub (hq : q.monic) {p₁ p₂ : R[X]} (h : q ∣ (p₁ - p₂)) : p₁ %ₘ q = p₂ %ₘ q := @@ -84,10 +79,23 @@ def mod_by_monic_hom (q : R[X]) : R[X] →ₗ[R] R[X] := map_add' := add_mod_by_monic, map_smul' := smul_mod_by_monic } +end + +section +variables [ring S] + +lemma aeval_mod_by_monic_eq_self_of_root [algebra R S] + {p q : R[X]} (hq : q.monic) {x : S} (hx : aeval x q = 0) : + aeval x (p %ₘ q) = aeval x p := +-- `eval₂_mod_by_monic_eq_self_of_root` doesn't work here as it needs commutativity +by rw [mod_by_monic_eq_sub_mul_div p hq, _root_.map_sub, _root_.map_mul, hx, zero_mul, sub_zero] + +end + end comm_ring section no_zero_divisors -variables [ring R] [no_zero_divisors R] {p q : R[X]} +variables [semiring R] [no_zero_divisors R] {p q : R[X]} instance : no_zero_divisors R[X] := { eq_zero_or_eq_zero_of_mul_eq_zero := λ a b h, begin @@ -136,7 +144,7 @@ end end no_zero_divisors section no_zero_divisors -variables [comm_ring R] [no_zero_divisors R] {p q : R[X]} +variables [comm_semiring R] [no_zero_divisors R] {p q : R[X]} lemma root_mul : is_root (p * q) a ↔ is_root p a ∨ is_root q a := by simp_rw [is_root, eval_mul, mul_eq_zero] From 0765994dbf07dfa81622be12ef255dbe3fbcf7e7 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Wed, 13 Apr 2022 23:29:58 +0000 Subject: [PATCH 009/373] chore(order/category/Preorder): reduce imports (#13301) Because `punit_instances` comes at the very end of the algebraic import hierarchy, we were requiring the entire algebraic hierarchy before we could begin compiling the theory of categorical limits. This tweak substantially reduces the import dependencies. Co-authored-by: Scott Morrison --- .../normed/group/SemiNormedGroup.lean | 1 + src/category_theory/Fintype.lean | 2 +- src/category_theory/category/preorder.lean | 22 ++----------------- src/category_theory/differential_object.lean | 2 ++ src/category_theory/graded_object.lean | 4 +++- ...iltered_colimit_commutes_finite_limit.lean | 1 + .../limits/shapes/pullbacks.lean | 8 +++---- src/category_theory/shift.lean | 8 ------- src/category_theory/subobject/basic.lean | 1 + src/category_theory/triangulated/basic.lean | 1 + src/order/category/Preorder.lean | 19 ++++++++++++++++ 11 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/analysis/normed/group/SemiNormedGroup.lean b/src/analysis/normed/group/SemiNormedGroup.lean index a40b12d788e38..3681388833d59 100644 --- a/src/analysis/normed/group/SemiNormedGroup.lean +++ b/src/analysis/normed/group/SemiNormedGroup.lean @@ -5,6 +5,7 @@ Authors: Johan Commelin, Riccardo Brasca -/ import analysis.normed.group.hom import category_theory.limits.shapes.zero +import category_theory.concrete_category.bundled_hom /-! # The category of seminormed groups diff --git a/src/category_theory/Fintype.lean b/src/category_theory/Fintype.lean index 7492fd6bce378..88859580d7d56 100644 --- a/src/category_theory/Fintype.lean +++ b/src/category_theory/Fintype.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Bhavik Mehta, Adam Topaz -/ -import category_theory.concrete_category.bundled +import category_theory.concrete_category.basic import category_theory.full_subcategory import category_theory.skeletal import data.fin.basic diff --git a/src/category_theory/category/preorder.lean b/src/category_theory/category/preorder.lean index 5dda1ff4b7558..2013da60208c6 100644 --- a/src/category_theory/category/preorder.lean +++ b/src/category_theory/category/preorder.lean @@ -3,9 +3,8 @@ Copyright (c) 2017 Scott Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Stephen Morgan, Scott Morrison, Johannes Hölzl, Reid Barton -/ - -import category_theory.category.Cat -import order.category.Preorder +import category_theory.adjunction.basic +import order.galois_connection /-! @@ -130,23 +129,6 @@ lemma adjunction.gc {L : X ⥤ Y} {R : Y ⥤ X} (adj : L ⊣ R) : galois_connection L.obj R.obj := λ x y, ⟨λ h, ((adj.hom_equiv x y).to_fun h.hom).le, λ h, ((adj.hom_equiv x y).inv_fun h.hom).le⟩ -/-- -The embedding of `Preorder` into `Cat`. --/ -@[simps] -def Preorder_to_Cat : Preorder.{u} ⥤ Cat := -{ obj := λ X, Cat.of X.1, - map := λ X Y f, f.monotone.functor, - map_id' := λ X, begin apply category_theory.functor.ext, tidy end, - map_comp' := λ X Y Z f g, begin apply category_theory.functor.ext, tidy end } - -instance : faithful Preorder_to_Cat.{u} := -{ map_injective' := λ X Y f g h, begin ext x, exact functor.congr_obj h x end } - -instance : full Preorder_to_Cat.{u} := -{ preimage := λ X Y f, ⟨f.obj, f.monotone⟩, - witness' := λ X Y f, begin apply category_theory.functor.ext, tidy end } - end preorder section partial_order diff --git a/src/category_theory/differential_object.lean b/src/category_theory/differential_object.lean index 59fea9d89fc58..51fd5fe0428d8 100644 --- a/src/category_theory/differential_object.lean +++ b/src/category_theory/differential_object.lean @@ -3,7 +3,9 @@ Copyright (c) 2020 Scott Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Scott Morrison -/ +import data.int.basic import category_theory.shift +import category_theory.concrete_category.basic /-! # Differential objects in a category. diff --git a/src/category_theory/graded_object.lean b/src/category_theory/graded_object.lean index 5c264694a7157..f6cd0e02615f7 100644 --- a/src/category_theory/graded_object.lean +++ b/src/category_theory/graded_object.lean @@ -3,9 +3,11 @@ Copyright (c) 2020 Scott Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Scott Morrison -/ -import algebra.group.basic +import data.int.basic +import algebra.group_power.lemmas import category_theory.pi.basic import category_theory.shift +import category_theory.concrete_category.basic /-! # The category of graded objects diff --git a/src/category_theory/limits/filtered_colimit_commutes_finite_limit.lean b/src/category_theory/limits/filtered_colimit_commutes_finite_limit.lean index 71c73bfcd1c21..e38d5c1d26f94 100644 --- a/src/category_theory/limits/filtered_colimit_commutes_finite_limit.lean +++ b/src/category_theory/limits/filtered_colimit_commutes_finite_limit.lean @@ -8,6 +8,7 @@ import category_theory.limits.preserves.functor_category import category_theory.limits.preserves.finite import category_theory.limits.shapes.finite_limits import category_theory.limits.preserves.filtered +import category_theory.concrete_category.basic /-! # Filtered colimits commute with finite limits. diff --git a/src/category_theory/limits/shapes/pullbacks.lean b/src/category_theory/limits/shapes/pullbacks.lean index f013868e4d998..c295cde288723 100644 --- a/src/category_theory/limits/shapes/pullbacks.lean +++ b/src/category_theory/limits/shapes/pullbacks.lean @@ -1272,7 +1272,7 @@ end variables (i : Z ⟶ W) [mono i] instance has_pullback_of_right_factors_mono (f : X ⟶ Z) : has_pullback i (f ≫ i) := -by { nth_rewrite 0 ← category.id_comp i, apply_instance } +by { conv { congr, rw ←category.id_comp i, }, apply_instance } instance pullback_snd_iso_of_right_factors_mono (f : X ⟶ Z) : is_iso (pullback.snd : pullback i (f ≫ i) ⟶ _) := @@ -1334,7 +1334,7 @@ end variables (i : Z ⟶ W) [mono i] instance has_pullback_of_left_factors_mono (f : X ⟶ Z) : has_pullback (f ≫ i) i := -by { nth_rewrite 1 ← category.id_comp i, apply_instance } +by { conv { congr, skip, rw ←category.id_comp i, }, apply_instance } instance pullback_snd_iso_of_left_factors_mono (f : X ⟶ Z) : is_iso (pullback.fst : pullback (f ≫ i) i ⟶ _) := @@ -1407,7 +1407,7 @@ end variables (h : W ⟶ X) [epi h] instance has_pushout_of_right_factors_epi (f : X ⟶ Y) : has_pushout h (h ≫ f) := -by { nth_rewrite 0 ← category.comp_id h, apply_instance } +by { conv { congr, rw ←category.comp_id h, }, apply_instance } instance pushout_inr_iso_of_right_factors_epi (f : X ⟶ Y) : is_iso (pushout.inr : _ ⟶ pushout h (h ≫ f)) := @@ -1469,7 +1469,7 @@ end variables (h : W ⟶ X) [epi h] instance has_pushout_of_left_factors_epi (f : X ⟶ Y) : has_pushout (h ≫ f) h := -by { nth_rewrite 1 ← category.comp_id h, apply_instance } +by { conv { congr, skip, rw ←category.comp_id h, }, apply_instance } instance pushout_inl_iso_of_left_factors_epi (f : X ⟶ Y) : is_iso (pushout.inl : _ ⟶ pushout (h ≫ f) h) := diff --git a/src/category_theory/shift.lean b/src/category_theory/shift.lean index 29aa3277013ef..ef3d372d349bb 100644 --- a/src/category_theory/shift.lean +++ b/src/category_theory/shift.lean @@ -137,14 +137,6 @@ notation f`⟦`n`⟧'`:80 := (shift_functor _ n).map f end defs -section examples -variables [has_shift C ℤ] - -example {X Y : C} (f : X ⟶ Y) : X⟦(1 : ℤ)⟧ ⟶ Y⟦1⟧ := f⟦1⟧' -example {X Y : C} (f : X ⟶ Y) : X⟦(-2 : ℤ)⟧ ⟶ Y⟦-2⟧ := f⟦-2⟧' - -end examples - section add_monoid variables {C A} [add_monoid A] [has_shift C A] (X Y : C) (f : X ⟶ Y) diff --git a/src/category_theory/subobject/basic.lean b/src/category_theory/subobject/basic.lean index 5a23060cab273..5a8913a0d8811 100644 --- a/src/category_theory/subobject/basic.lean +++ b/src/category_theory/subobject/basic.lean @@ -6,6 +6,7 @@ Authors: Bhavik Mehta, Scott Morrison import category_theory.subobject.mono_over import category_theory.skeletal import tactic.elementwise +import tactic.apply_fun /-! # Subobjects diff --git a/src/category_theory/triangulated/basic.lean b/src/category_theory/triangulated/basic.lean index e4af0a0f31578..5fc085cc9759f 100644 --- a/src/category_theory/triangulated/basic.lean +++ b/src/category_theory/triangulated/basic.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Luke Kershaw. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Luke Kershaw -/ +import data.int.basic import category_theory.shift /-! diff --git a/src/order/category/Preorder.lean b/src/order/category/Preorder.lean index f1546ce554492..5517cfe0644f8 100644 --- a/src/order/category/Preorder.lean +++ b/src/order/category/Preorder.lean @@ -6,6 +6,8 @@ Authors: Johan Commelin import category_theory.concrete_category.bundled_hom import algebra.punit_instances import order.hom.basic +import category_theory.category.Cat +import category_theory.category.preorder /-! # Category of preorders @@ -59,3 +61,20 @@ equivalence.mk dual dual (nat_iso.of_components (λ X, iso.mk $ order_iso.dual_dual X) $ λ X Y f, rfl) end Preorder + +/-- +The embedding of `Preorder` into `Cat`. +-/ +@[simps] +def Preorder_to_Cat : Preorder.{u} ⥤ Cat := +{ obj := λ X, Cat.of X.1, + map := λ X Y f, f.monotone.functor, + map_id' := λ X, begin apply category_theory.functor.ext, tidy end, + map_comp' := λ X Y Z f g, begin apply category_theory.functor.ext, tidy end } + +instance : faithful Preorder_to_Cat.{u} := +{ map_injective' := λ X Y f g h, begin ext x, exact functor.congr_obj h x end } + +instance : full Preorder_to_Cat.{u} := +{ preimage := λ X Y f, ⟨f.obj, f.monotone⟩, + witness' := λ X Y f, begin apply category_theory.functor.ext, tidy end } From b62626e5d00c3b229c6b0d2a6cb1ce66599b6bc2 Mon Sep 17 00:00:00 2001 From: Eric Rodriguez Date: Thu, 14 Apr 2022 02:07:07 +0000 Subject: [PATCH 010/373] feat(complex/arg): arg_eq_zero_iff (#13432) --- src/analysis/special_functions/complex/arg.lean | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/analysis/special_functions/complex/arg.lean b/src/analysis/special_functions/complex/arg.lean index 7a70640ffefaf..2b1de2b67080f 100644 --- a/src/analysis/special_functions/complex/arg.lean +++ b/src/analysis/special_functions/complex/arg.lean @@ -187,6 +187,16 @@ end lemma arg_of_real_of_nonneg {x : ℝ} (hx : 0 ≤ x) : arg x = 0 := by simp [arg, hx] +lemma arg_eq_zero_iff {z : ℂ} : arg z = 0 ↔ 0 ≤ z.re ∧ z.im = 0 := +begin + refine ⟨λ h, _, _⟩, + { rw [←abs_mul_cos_add_sin_mul_I z, h], + simp [abs_nonneg] }, + { cases z with x y, + rintro ⟨h, rfl : y = 0⟩, + exact arg_of_real_of_nonneg h } +end + lemma arg_eq_pi_iff {z : ℂ} : arg z = π ↔ z.re < 0 ∧ z.im = 0 := begin by_cases h₀ : z = 0, { simp [h₀, lt_irrefl, real.pi_ne_zero.symm] }, From a5654710c05b560092e24548d91d9a59459ab648 Mon Sep 17 00:00:00 2001 From: leanprover-community-bot Date: Thu, 14 Apr 2022 03:43:29 +0000 Subject: [PATCH 011/373] chore(scripts): update nolints.txt (#13438) I am happy to remove some nolints for you! --- scripts/nolints.txt | 9 --------- 1 file changed, 9 deletions(-) diff --git a/scripts/nolints.txt b/scripts/nolints.txt index 101eef31ec2a5..60259371d6d32 100644 --- a/scripts/nolints.txt +++ b/scripts/nolints.txt @@ -631,24 +631,15 @@ apply_nolint order.ideal.is_prime.is_maximal fails_quickly -- ring_theory/witt_vector/basic.lean apply_nolint witt_vector.comm_ring check_reducibility --- set_theory/cofinality.lean -apply_nolint strict_order.cof doc_blame - --- set_theory/game.lean -apply_nolint pgame.inv_ty has_inhabited_instance - -- set_theory/lists.lean apply_nolint finsets doc_blame -- set_theory/pgame.lean -apply_nolint pgame.left_moves has_inhabited_instance apply_nolint pgame.relabelling has_inhabited_instance apply_nolint pgame.restricted has_inhabited_instance -apply_nolint pgame.right_moves has_inhabited_instance -- set_theory/zfc.lean apply_nolint Set.map_definable_aux unused_arguments -apply_nolint pSet.type has_inhabited_instance -- tactic/abel.lean apply_nolint tactic.abel.eval doc_blame From 2249a240e5a2419cc17901ad240f8fc5435520b2 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 14 Apr 2022 06:30:11 +0000 Subject: [PATCH 012/373] chore(*): suggestions from the generalisation linter (#13092) Prompted by zulip discussion at https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/An.20example.20of.20why.20formalization.20is.20useful These are the "reasonable" suggestions from @alexjbest's generalisation linter up to `algebra.group.basic`. Co-authored-by: Scott Morrison --- src/algebra/group/basic.lean | 12 +++++------- src/order/basic.lean | 6 +++--- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/algebra/group/basic.lean b/src/algebra/group/basic.lean index 2f2477fd769dd..f284d8504570b 100644 --- a/src/algebra/group/basic.lean +++ b/src/algebra/group/basic.lean @@ -206,6 +206,10 @@ lemma mul_div_assoc' (a b c : G) : a * (b / c) = (a * b) / c := @[simp, to_additive] lemma one_div (a : G) : 1 / a = a⁻¹ := (inv_eq_one_div a).symm +@[to_additive] +lemma mul_div (a b c : G) : a * (b / c) = a * b / c := +by simp only [mul_assoc, div_eq_mul_inv] + end div_inv_monoid section group @@ -220,7 +224,7 @@ lemma one_inv : 1⁻¹ = (1 : G) := inv_eq_of_mul_eq_one (one_mul 1) @[to_additive] -theorem left_inverse_inv (G) [group G] : +theorem left_inverse_inv (G) [has_involutive_inv G] : function.left_inverse (λ a : G, a⁻¹) (λ a, a⁻¹) := inv_inv @@ -366,12 +370,6 @@ mt eq_of_div_eq_one' h lemma div_inv_eq_mul (a b : G) : a / (b⁻¹) = a * b := by rw [div_eq_mul_inv, inv_inv] -local attribute [simp] mul_assoc - -@[to_additive] -lemma mul_div (a b c : G) : a * (b / c) = a * b / c := -by simp only [mul_assoc, div_eq_mul_inv] - @[to_additive] lemma div_mul_eq_div_div_swap (a b c : G) : a / (b * c) = a / c / b := by simp only [mul_assoc, mul_inv_rev , div_eq_mul_inv] diff --git a/src/order/basic.lean b/src/order/basic.lean index 6e829e6026d6e..142ec8804ba70 100644 --- a/src/order/basic.lean +++ b/src/order/basic.lean @@ -96,9 +96,9 @@ protected lemma ge [preorder α] {x y : α} (h : x = y) : y ≤ x := h.symm.le lemma trans_le [preorder α] {x y z : α} (h1 : x = y) (h2 : y ≤ z) : x ≤ z := h1.le.trans h2 -lemma not_lt [partial_order α] {x y : α} (h : x = y) : ¬(x < y) := λ h', h'.ne h +lemma not_lt [preorder α] {x y : α} (h : x = y) : ¬(x < y) := λ h', h'.ne h -lemma not_gt [partial_order α] {x y : α} (h : x = y) : ¬(y < x) := h.symm.not_lt +lemma not_gt [preorder α] {x y : α} (h : x = y) : ¬(y < x) := h.symm.not_lt end eq @@ -205,7 +205,7 @@ lemma ne.le_iff_lt [partial_order α] {a b : α} (h : a ≠ b) : a ≤ b ↔ a < ⟨λ h', lt_of_le_of_ne h' h, λ h, h.le⟩ -- See Note [decidable namespace] -protected lemma decidable.ne_iff_lt_iff_le [partial_order α] [@decidable_rel α (≤)] +protected lemma decidable.ne_iff_lt_iff_le [partial_order α] [decidable_eq α] {a b : α} : (a ≠ b ↔ a < b) ↔ a ≤ b := ⟨λ h, decidable.by_cases le_of_eq (le_of_lt ∘ h.mp), λ h, ⟨lt_of_le_of_ne h, ne_of_lt⟩⟩ From 1378eabf1a6d2c1e4eec37d4eb30eb8454214379 Mon Sep 17 00:00:00 2001 From: Eric Rodriguez Date: Thu, 14 Apr 2022 08:28:58 +0000 Subject: [PATCH 013/373] feat(complex/roots_of_unity): extensionality (#13431) Primitive roots are equal iff their arguments are equal. Adds some useful specialisations, too. --- src/analysis/complex/roots_of_unity.lean | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/analysis/complex/roots_of_unity.lean b/src/analysis/complex/roots_of_unity.lean index 50577d05f5f5f..281acf808f4ab 100644 --- a/src/analysis/complex/roots_of_unity.lean +++ b/src/analysis/complex/roots_of_unity.lean @@ -97,3 +97,17 @@ end complex lemma is_primitive_root.nnnorm_eq_one {ζ : ℂ} {n : ℕ} (h : is_primitive_root ζ n) (hn : n ≠ 0) : ∥ζ∥ = 1 := complex.norm_eq_one_of_pow_eq_one h.pow_eq_one hn + +lemma is_primitive_root.arg_ext {n m : ℕ} {ζ μ : ℂ} (hζ : is_primitive_root ζ n) + (hμ : is_primitive_root μ m) (hn : n ≠ 0) (hm : m ≠ 0) (h : ζ.arg = μ.arg) : ζ = μ := +complex.ext_abs_arg ((hζ.nnnorm_eq_one hn).trans (hμ.nnnorm_eq_one hm).symm) h + +lemma is_primitive_root.arg_eq_zero_iff {n : ℕ} {ζ : ℂ} (hζ : is_primitive_root ζ n) + (hn : n ≠ 0) : ζ.arg = 0 ↔ ζ = 1 := +⟨λ h, hζ.arg_ext is_primitive_root.one hn one_ne_zero (h.trans complex.arg_one.symm), + λ h, h.symm ▸ complex.arg_one⟩ + +lemma is_primitive_root.arg_eq_pi_iff {n : ℕ} {ζ : ℂ} (hζ : is_primitive_root ζ n) + (hn : n ≠ 0) : ζ.arg = real.pi ↔ ζ = -1 := +⟨λ h, hζ.arg_ext (is_primitive_root.neg_one 0 two_ne_zero.symm) hn two_ne_zero + (h.trans complex.arg_neg_one.symm), λ h, h.symm ▸ complex.arg_neg_one⟩ From dac4f18f4723082699b571c9bbf7887f5a815760 Mon Sep 17 00:00:00 2001 From: Alex J Best Date: Thu, 14 Apr 2022 08:29:00 +0000 Subject: [PATCH 014/373] feat(data/mv_polynomial): add support_X_pow (#13435) A simple lemma to match the `polynomial` API from flt-regular --- src/data/mv_polynomial/basic.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/data/mv_polynomial/basic.lean b/src/data/mv_polynomial/basic.lean index acd2545856a28..eff152a5f063b 100644 --- a/src/data/mv_polynomial/basic.lean +++ b/src/data/mv_polynomial/basic.lean @@ -401,6 +401,10 @@ lemma support_add : (p + q).support ⊆ p.support ∪ q.support := finsupp.suppo lemma support_X [nontrivial R] : (X n : mv_polynomial σ R).support = {single n 1} := by rw [X, support_monomial, if_neg]; exact one_ne_zero +lemma support_X_pow [nontrivial R] (s : σ) (n : ℕ) : + (X s ^ n : mv_polynomial σ R).support = {finsupp.single s n} := +by rw [X_pow_eq_monomial, support_monomial, if_neg (@one_ne_zero R _ _)] + @[simp] lemma support_zero : (0 : mv_polynomial σ R).support = ∅ := rfl lemma support_sum {α : Type*} {s : finset α} {f : α → mv_polynomial σ R} : From 87f8076f2edee7d522a86d31b11850d7bb53fb83 Mon Sep 17 00:00:00 2001 From: Eric Rodriguez <37984851+ericrbg@users.noreply.github.com> Date: Thu, 14 Apr 2022 08:29:02 +0000 Subject: [PATCH 015/373] chore(data/nat/factorial): tidy (#13436) I noticed this file had non-terminal simps, so I tidied it a little whilst removing them. --- src/data/nat/factorial/basic.lean | 63 +++++++++++++++---------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/src/data/nat/factorial/basic.lean b/src/data/nat/factorial/basic.lean index 8bfe1ea691c53..9e577b6247914 100644 --- a/src/data/nat/factorial/basic.lean +++ b/src/data/nat/factorial/basic.lean @@ -51,10 +51,10 @@ theorem factorial_ne_zero (n : ℕ) : n! ≠ 0 := ne_of_gt (factorial_pos _) theorem factorial_dvd_factorial {m n} (h : m ≤ n) : m! ∣ n! := begin - induction n with n IH; simp, - { have := nat.eq_zero_of_le_zero h, subst m, simp }, - obtain he | hl := h.eq_or_lt, - { subst m, simp }, + induction n with n IH, + { simp [nat.eq_zero_of_le_zero h] }, + obtain rfl | hl := h.eq_or_lt, + { simp }, exact (IH (le_of_lt_succ hl)).mul_left _, end @@ -75,39 +75,36 @@ lemma monotone_factorial : monotone factorial := λ n m, factorial_le lemma factorial_lt (hn : 0 < n) : n! < m! ↔ n < m := begin - split; intro h, - { rw [← not_le], intro hmn, apply not_le_of_lt h (factorial_le hmn) }, - have : ∀ n, 0 < n → n! < n.succ!, - { intros k hk, rw [factorial_succ, succ_mul, lt_add_iff_pos_left], - apply mul_pos hk (factorial_pos k) }, - induction h with k hnk generalizing hn, - { exact this _ hn, }, - refine lt_trans (h_ih hn) (this _ _), - exact lt_trans hn (lt_of_succ_le hnk), + refine ⟨λ h, not_le.mp $ λ hmn, not_le_of_lt h (factorial_le hmn), λ h, _⟩, + have : ∀ {n}, 0 < n → n! < n.succ!, + { intros k hk, + rw [factorial_succ, succ_mul, lt_add_iff_pos_left], + exact mul_pos hk k.factorial_pos }, + induction h with k hnk ih generalizing hn, + { exact this hn, }, + { exact (ih hn).trans (this $ hn.trans $ lt_of_succ_le hnk) } end lemma one_lt_factorial : 1 < n! ↔ 1 < n := -by { convert factorial_lt _, refl, exact one_pos } +factorial_lt one_pos lemma factorial_eq_one : n! = 1 ↔ n ≤ 1 := begin - split; intro h, - { rw [← not_lt, ← one_lt_factorial, h], - apply lt_irrefl }, - cases h with h h, refl, cases h, refl, + refine ⟨λ h, _, by rintro (_ | ⟨_, _ | _⟩); refl⟩, + rw [← not_lt, ← one_lt_factorial, h], + apply lt_irrefl end lemma factorial_inj (hn : 1 < n!) : n! = m! ↔ n = m := begin - split; intro h, - { obtain hnm | hnm | hnm := lt_trichotomy n m, - { exfalso, rw [← factorial_lt, h] at hnm, exact lt_irrefl _ hnm, - rw [one_lt_factorial] at hn, exact lt_trans one_pos hn }, - { exact hnm }, - exfalso, - rw [h, one_lt_factorial] at hn, - rw [←factorial_lt (lt_trans one_pos hn), h] at hnm, exact lt_irrefl _ hnm, }, - { rw h }, + refine ⟨λ h, _, congr_arg _⟩, + obtain hnm | rfl | hnm := lt_trichotomy n m, + { rw [← factorial_lt $ pos_of_gt $ one_lt_factorial.mp hn, h] at hnm, + cases lt_irrefl _ hnm }, + { refl }, + rw [h, one_lt_factorial] at hn, + rw [←factorial_lt (lt_trans one_pos hn), h] at hnm, + cases lt_irrefl _ hnm end lemma self_le_factorial : ∀ n : ℕ, n ≤ n! @@ -146,8 +143,7 @@ lemma add_factorial_succ_le_factorial_add_succ (i : ℕ) (n : ℕ) : begin obtain i2 | (_ | ⟨_, i0⟩) := le_or_lt 2 i, { exact (n.add_factorial_succ_lt_factorial_add_succ i2).le }, - { change 1 + (n + 1)! ≤ (1 + n + 1) * (1 + n)!, - rw [add_mul, one_mul, add_comm 1 n], + { rw [←add_assoc, factorial_succ (1 + n), add_mul, one_mul, add_comm 1 n], exact (add_le_add_iff_right _).mpr (one_le_mul (nat.le_add_left 1 n) (n + 1).factorial_pos) }, rw [nat.le_zero_iff.mp (nat.succ_le_succ_iff.mp i0), zero_add, zero_add] end @@ -166,7 +162,7 @@ begin { apply trans _ this, rw mul_le_mul_left, apply pow_le_pow_of_le_left (zero_le n) (le_succ n), - exact factorial_pos n,}, + exact factorial_pos n }, convert nat.factorial_mul_pow_le_factorial, exact (add_tsub_cancel_of_le hnm).symm, end @@ -189,8 +185,9 @@ def asc_factorial (n : ℕ) : ℕ → ℕ @[simp] lemma zero_asc_factorial (k : ℕ) : (0 : ℕ).asc_factorial k = k! := begin - induction k with t ht, refl, - unfold asc_factorial, rw [ht, zero_add, nat.factorial_succ], + induction k with t ht, + { refl }, + rw [asc_factorial, ht, zero_add, nat.factorial_succ], end lemma asc_factorial_succ {n k : ℕ} : n.asc_factorial k.succ = (n + k + 1) * n.asc_factorial k := rfl @@ -211,7 +208,7 @@ theorem factorial_mul_asc_factorial (n : ℕ) : ∀ k, n! * n.asc_factorial k = /-- Avoid in favor of `nat.factorial_mul_asc_factorial` if you can. ℕ-division isn't worth it. -/ lemma asc_factorial_eq_div (n k : ℕ) : n.asc_factorial k = (n + k)! / n! := begin - apply mul_left_cancel₀ (factorial_ne_zero n), + apply mul_left_cancel₀ n.factorial_ne_zero, rw factorial_mul_asc_factorial, exact (nat.mul_div_cancel' $ factorial_dvd_factorial $ le.intro rfl).symm end From eb2780b6dc19f50b1d25a45e80db6dc2d50d35e3 Mon Sep 17 00:00:00 2001 From: Floris van Doorn Date: Thu, 14 Apr 2022 10:16:38 +0000 Subject: [PATCH 016/373] feat(topology/unit_interval): add lemmas (#13344) * also change the statement of `unit_interval.mul_mem` * from the sphere eversion project --- src/topology/unit_interval.lean | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/topology/unit_interval.lean b/src/topology/unit_interval.lean index c9182c0dc2f14..7a858b6b679e0 100644 --- a/src/topology/unit_interval.lean +++ b/src/topology/unit_interval.lean @@ -19,7 +19,7 @@ We provide basic instances, as well as a custom tactic for discharging noncomputable theory open_locale classical topological_space filter -open set +open set int /-! ### The unit interval -/ @@ -30,13 +30,25 @@ localized "notation `I` := unit_interval" in unit_interval namespace unit_interval +lemma zero_mem : (0 : ℝ) ∈ I := ⟨le_rfl, zero_le_one⟩ + +lemma one_mem : (1 : ℝ) ∈ I := ⟨zero_le_one, le_rfl⟩ + +lemma mul_mem {x y : ℝ} (hx : x ∈ I) (hy : y ∈ I) : x * y ∈ I := +⟨mul_nonneg hx.1 hy.1, (mul_le_mul hx.2 hy.2 hy.1 zero_le_one).trans_eq $ one_mul 1⟩ + +lemma div_mem {x y : ℝ} (hx : 0 ≤ x) (hy : 0 ≤ y) (hxy : x ≤ y) : x / y ∈ I := +⟨div_nonneg hx hy, div_le_one_of_le hxy hy⟩ + +lemma fract_mem (x : ℝ) : fract x ∈ I := ⟨fract_nonneg _, (fract_lt_one _).le⟩ + lemma mem_iff_one_sub_mem {t : ℝ} : t ∈ I ↔ 1 - t ∈ I := begin rw [mem_Icc, mem_Icc], split ; intro ; split ; linarith end -instance has_zero : has_zero I := ⟨⟨0, by split ; norm_num⟩⟩ +instance has_zero : has_zero I := ⟨⟨0, zero_mem⟩⟩ @[simp, norm_cast] lemma coe_zero : ((0 : I) : ℝ) = 0 := rfl @@ -62,10 +74,7 @@ not_iff_not.mpr coe_eq_one instance : nonempty I := ⟨0⟩ -lemma mul_mem (x y : I) : (x : ℝ) * y ∈ I := -⟨mul_nonneg x.2.1 y.2.1, (mul_le_mul x.2.2 y.2.2 y.2.1 zero_le_one).trans_eq $ one_mul 1⟩ - -instance : has_mul I := ⟨λ x y, ⟨x * y, mul_mem x y⟩⟩ +instance : has_mul I := ⟨λ x y, ⟨x * y, mul_mem x.2 y.2⟩⟩ @[simp, norm_cast] lemma coe_mul {x y : I} : ((x * y : I) : ℝ) = x * y := rfl @@ -78,7 +87,7 @@ lemma mul_le_right {x y : I} : x * y ≤ y := subtype.coe_le_coe.mp $ (mul_le_mul_of_nonneg_right x.2.2 y.2.1).trans_eq $ one_mul y /-- Unit interval central symmetry. -/ -def symm : I → I := λ t, ⟨1 - t.val, mem_iff_one_sub_mem.mp t.property⟩ +def symm : I → I := λ t, ⟨1 - t, mem_iff_one_sub_mem.mp t.prop⟩ localized "notation `σ` := unit_interval.symm" in unit_interval From 2693ab58387d4ca25307385aa1044f57e8f39fb9 Mon Sep 17 00:00:00 2001 From: MichaelStollBayreuth Date: Thu, 14 Apr 2022 10:16:39 +0000 Subject: [PATCH 017/373] feat(number_theory/legendre_symbol): add directory legendre_symbol and move quadratic_reciprocity.lean into it (#13441) In preparation of adding more code in a structured way, this sets up a new directory `legendre_symbol` below `number_theory` and moves the file `quadratic_reciprocity.lean` there. The imports in `src/number_theory/zsqrtd/gaussian_int.lean` and `archive/imo/imp2008_q3.lean` are changed accordingly. --- archive/imo/imo2008_q3.lean | 2 +- .../{ => legendre_symbol}/quadratic_reciprocity.lean | 0 src/number_theory/zsqrtd/gaussian_int.lean | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/number_theory/{ => legendre_symbol}/quadratic_reciprocity.lean (100%) diff --git a/archive/imo/imo2008_q3.lean b/archive/imo/imo2008_q3.lean index 284921ebe878f..fe9e04c0d0ffc 100644 --- a/archive/imo/imo2008_q3.lean +++ b/archive/imo/imo2008_q3.lean @@ -7,7 +7,7 @@ import data.real.basic import data.real.sqrt import data.nat.prime import number_theory.primes_congruent_one -import number_theory.quadratic_reciprocity +import number_theory.legendre_symbol.quadratic_reciprocity import tactic.linear_combination /-! diff --git a/src/number_theory/quadratic_reciprocity.lean b/src/number_theory/legendre_symbol/quadratic_reciprocity.lean similarity index 100% rename from src/number_theory/quadratic_reciprocity.lean rename to src/number_theory/legendre_symbol/quadratic_reciprocity.lean diff --git a/src/number_theory/zsqrtd/gaussian_int.lean b/src/number_theory/zsqrtd/gaussian_int.lean index 408f76723e7ca..0f90dba67c414 100644 --- a/src/number_theory/zsqrtd/gaussian_int.lean +++ b/src/number_theory/zsqrtd/gaussian_int.lean @@ -6,7 +6,7 @@ Authors: Chris Hughes import number_theory.zsqrtd.basic import data.complex.basic import ring_theory.principal_ideal_domain -import number_theory.quadratic_reciprocity +import number_theory.legendre_symbol.quadratic_reciprocity /-! # Gaussian integers From 7bb10813cac2c0eb023ba30fcc077beab4595097 Mon Sep 17 00:00:00 2001 From: Jakob von Raumer Date: Thu, 14 Apr 2022 11:12:32 +0000 Subject: [PATCH 018/373] feat(category_theory): turn a split mono with cokernel into a biproduct (#13184) --- .../limits/shapes/biproducts.lean | 102 +++++++++++++++++- .../limits/shapes/equalizers.lean | 19 ++-- .../limits/shapes/kernels.lean | 32 ++++-- src/category_theory/preadditive/default.lean | 22 +++- 4 files changed, 155 insertions(+), 20 deletions(-) diff --git a/src/category_theory/limits/shapes/biproducts.lean b/src/category_theory/limits/shapes/biproducts.lean index 00121c67478bd..b97b77328f837 100644 --- a/src/category_theory/limits/shapes/biproducts.lean +++ b/src/category_theory/limits/shapes/biproducts.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2019 Scott Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Scott Morrison +Authors: Scott Morrison, Jakob von Raumer -/ import algebra.group.ext import category_theory.limits.shapes.finite_products @@ -1539,6 +1539,106 @@ lemma biprod.map_eq [has_binary_biproducts C] {W X Y Z : C} {f : W ⟶ Y} {g : X biprod.map f g = biprod.fst ≫ f ≫ biprod.inl + biprod.snd ≫ g ≫ biprod.inr := by apply biprod.hom_ext; apply biprod.hom_ext'; simp +/-- +Every split mono `f` with a cokernel induces a binary bicone with `f` as its `inl` and +the cokernel map as its `snd`. +We will show in `is_bilimit_binary_bicone_of_split_mono_of_cokernel` that this binary bicone is in +fact already a biproduct. -/ +@[simps] +def binary_bicone_of_split_mono_of_cokernel {X Y : C} {f : X ⟶ Y} [split_mono f] + {c : cokernel_cofork f} (i : is_colimit c) : binary_bicone X c.X := +{ X := Y, + fst := retraction f, + snd := c.π, + inl := f, + inr := + let c' : cokernel_cofork (𝟙 Y - (𝟙 Y - retraction f ≫ f)) := + cokernel_cofork.of_π (cofork.π c) (by simp) in + let i' : is_colimit c' := is_cokernel_epi_comp i (retraction f) (by simp) in + let i'' := is_colimit_cofork_of_cokernel_cofork i' in + (split_epi_of_idempotent_of_is_colimit_cofork C (by simp) i'').section_, + inl_fst' := by simp, + inl_snd' := by simp, + inr_fst' := + begin + dsimp only, + rw [split_epi_of_idempotent_of_is_colimit_cofork_section_, + is_colimit_cofork_of_cokernel_cofork_desc, is_cokernel_epi_comp_desc], + dsimp only [cokernel_cofork_of_cofork_of_π], + letI := epi_of_is_colimit_parallel_pair i, + apply zero_of_epi_comp c.π, + simp only [sub_comp, category.comp_id, category.assoc, split_mono.id, is_colimit.fac_assoc, + cofork.of_π_ι_app, category.id_comp, cofork.π_of_π], + apply sub_eq_zero_of_eq, + apply category.id_comp + end, + inr_snd' := by apply split_epi.id } + +/-- The bicone constructed in `binary_bicone_of_split_mono_of_cokernel` is a bilimit. +This is a version of the splitting lemma that holds in all preadditive categories. -/ +def is_bilimit_binary_bicone_of_split_mono_of_cokernel {X Y : C} {f : X ⟶ Y} [split_mono f] + {c : cokernel_cofork f} (i : is_colimit c) : + (binary_bicone_of_split_mono_of_cokernel i).is_bilimit := +is_binary_bilimit_of_total _ +begin + simp only [binary_bicone_of_split_mono_of_cokernel_fst, + binary_bicone_of_split_mono_of_cokernel_inr, binary_bicone_of_split_mono_of_cokernel_snd, + split_epi_of_idempotent_of_is_colimit_cofork_section_], + dsimp only [binary_bicone_of_split_mono_of_cokernel_X], + rw [is_colimit_cofork_of_cokernel_cofork_desc, is_cokernel_epi_comp_desc], + simp only [cofork.is_colimit.π_desc_of_π, cokernel_cofork_of_cofork_π, + cofork.π_of_π, binary_bicone_of_split_mono_of_cokernel_inl, add_sub_cancel'_right], +end + +/-- +Every split epi `f` with a kernel induces a binary bicone with `f` as its `snd` and +the kernel map as its `inl`. +We will show in `binary_bicone_of_split_mono_of_cokernel` that this binary bicone is in fact +already a biproduct. -/ +@[simps] +def binary_bicone_of_split_epi_of_kernel {X Y : C} {f : X ⟶ Y} [split_epi f] + {c : kernel_fork f} (i : is_limit c) : binary_bicone c.X Y := +{ X := X, + fst := + let c' : kernel_fork (𝟙 X - (𝟙 X - f ≫ section_ f)) := + kernel_fork.of_ι (fork.ι c) (by simp) in + let i' : is_limit c' := is_kernel_comp_mono i (section_ f) (by simp) in + let i'' := is_limit_fork_of_kernel_fork i' in + (split_mono_of_idempotent_of_is_limit_fork C (by simp) i'').retraction, + snd := f, + inl := c.ι, + inr := section_ f, + inl_fst' := by apply split_mono.id, + inl_snd' := by simp, + inr_fst' := + begin + dsimp only, + rw [split_mono_of_idempotent_of_is_limit_fork_retraction, + is_limit_fork_of_kernel_fork_lift, is_kernel_comp_mono_lift], + dsimp only [kernel_fork_of_fork_ι], + letI := mono_of_is_limit_parallel_pair i, + apply zero_of_comp_mono c.ι, + simp only [comp_sub, category.comp_id, category.assoc, sub_self, fork.ι_eq_app_zero, + fork.is_limit.lift_of_ι_ι, fork.of_ι_π_app, split_epi.id_assoc] + end, + inr_snd' := by simp } + +/-- The bicone constructed in `binary_bicone_of_split_epi_of_kernel` is a bilimit. +This is a version of the splitting lemma that holds in all preadditive categories. -/ +def is_bilimit_binary_bicone_of_split_epi_of_kernel {X Y : C} {f : X ⟶ Y} [split_epi f] + {c : kernel_fork f} (i : is_limit c) : + (binary_bicone_of_split_epi_of_kernel i).is_bilimit := +is_binary_bilimit_of_total _ +begin + simp only [binary_bicone_of_split_epi_of_kernel_fst, binary_bicone_of_split_epi_of_kernel_inl, + binary_bicone_of_split_epi_of_kernel_inr, binary_bicone_of_split_epi_of_kernel_snd, + split_mono_of_idempotent_of_is_limit_fork_retraction], + dsimp only [binary_bicone_of_split_epi_of_kernel_X], + rw [is_limit_fork_of_kernel_fork_lift, is_kernel_comp_mono_lift], + simp only [fork.ι_eq_app_zero, kernel_fork.condition, comp_zero, zero_comp, eq_self_iff_true, + fork.is_limit.lift_of_ι_ι, kernel_fork_of_fork_ι, fork.of_ι_π_app, sub_add_cancel] +end + end section diff --git a/src/category_theory/limits/shapes/equalizers.lean b/src/category_theory/limits/shapes/equalizers.lean index 793c0399539c4..a14c6643b41bb 100644 --- a/src/category_theory/limits/shapes/equalizers.lean +++ b/src/category_theory/limits/shapes/equalizers.lean @@ -359,6 +359,7 @@ fork.is_limit.mk t /-- This is a slightly more convenient method to verify that a cofork is a colimit cocone. It only asks for a proof of facts that carry any mathematical content -/ +@[simps] def cofork.is_colimit.mk (t : cofork f g) (desc : Π (s : cofork f g), t.X ⟶ s.X) (fac : ∀ (s : cofork f g), cofork.π t ≫ desc s = cofork.π s) @@ -940,19 +941,20 @@ lemma has_equalizer_comp_mono [has_equalizer f g] {Z : C} (h : Y ⟶ Z) [mono h] ⟨⟨{ cone := _, is_limit := is_equalizer_comp_mono (limit.is_limit _) h }⟩⟩ /-- An equalizer of an idempotent morphism and the identity is split mono. -/ +@[simps] def split_mono_of_idempotent_of_is_limit_fork {X : C} {f : X ⟶ X} (hf : f ≫ f = f) - {c : fork f (𝟙 X)} (i : is_limit c) : split_mono c.ι := + {c : fork (𝟙 X) f} (i : is_limit c) : split_mono c.ι := { retraction := i.lift (fork.of_ι f (by simp [hf])), id' := begin letI := mono_of_is_limit_parallel_pair i, - rw [← cancel_mono_id c.ι, category.assoc, fork.is_limit.lift_of_ι_ι, c.condition], + rw [←cancel_mono_id c.ι, category.assoc, fork.is_limit.lift_of_ι_ι, ←c.condition], exact category.comp_id c.ι end } /-- The equalizer of an idempotent morphism and the identity is split mono. -/ def split_mono_of_idempotent_equalizer {X : C} {f : X ⟶ X} (hf : f ≫ f = f) - [has_equalizer f (𝟙 X)] : split_mono (equalizer.ι f (𝟙 X)) := + [has_equalizer (𝟙 X) f] : split_mono (equalizer.ι (𝟙 X) f) := split_mono_of_idempotent_of_is_limit_fork _ hf (limit.is_limit _) section @@ -990,12 +992,12 @@ def split_epi_of_coequalizer {X Y : C} {f : X ⟶ Y} {s : Y ⟶ X} (hs : f ≫ s variables {C f g} -/-- The cofork obtained by precomposing a coequalizer cofork with an epimorphism is +/-- The cofork obtained by precomposing a coequalizer cofork with an epimorphism is a coequalizer. -/ def is_coequalizer_epi_comp {c : cofork f g} (i : is_colimit c) {W : C} (h : W ⟶ X) [hm : epi h] : is_colimit (cofork.of_π c.π (by simp) : cofork (h ≫ f) (h ≫ g)) := cofork.is_colimit.mk' _ $ λ s, - let s' : cofork f g := cofork.of_π s.π + let s' : cofork f g := cofork.of_π s.π (by apply hm.left_cancellation; simp_rw [←category.assoc, s.condition]) in let l := cofork.is_colimit.desc' i s'.π s'.condition in ⟨l.1, l.2, @@ -1008,19 +1010,20 @@ lemma has_coequalizer_epi_comp [has_coequalizer f g] {W : C} (h : W ⟶ X) [hm : variables (C f g) /-- A coequalizer of an idempotent morphism and the identity is split epi. -/ +@[simps] def split_epi_of_idempotent_of_is_colimit_cofork {X : C} {f : X ⟶ X} (hf : f ≫ f = f) - {c : cofork f (𝟙 X)} (i : is_colimit c) : split_epi c.π := + {c : cofork (𝟙 X) f} (i : is_colimit c) : split_epi c.π := { section_ := i.desc (cofork.of_π f (by simp [hf])), id' := begin letI := epi_of_is_colimit_parallel_pair i, - rw [← cancel_epi_id c.π, ← category.assoc, cofork.is_colimit.π_desc_of_π, c.condition], + rw [← cancel_epi_id c.π, ← category.assoc, cofork.is_colimit.π_desc_of_π, ← c.condition], exact category.id_comp _, end } /-- The coequalizer of an idempotent morphism and the identity is split epi. -/ def split_epi_of_idempotent_coequalizer {X : C} {f : X ⟶ X} (hf : f ≫ f = f) - [has_coequalizer f (𝟙 X)] : split_epi (coequalizer.π f (𝟙 X)) := + [has_coequalizer (𝟙 X) f] : split_epi (coequalizer.π (𝟙 X) f) := split_epi_of_idempotent_of_is_colimit_cofork _ hf (colimit.is_colimit _) end category_theory.limits diff --git a/src/category_theory/limits/shapes/kernels.lean b/src/category_theory/limits/shapes/kernels.lean index 40d00bc14718f..74f6e34418893 100644 --- a/src/category_theory/limits/shapes/kernels.lean +++ b/src/category_theory/limits/shapes/kernels.lean @@ -136,13 +136,19 @@ def is_limit.of_ι {W : C} (g : W ⟶ X) (eq : g ≫ f = 0) is_limit_aux _ (λ s, lift s.ι s.condition) (λ s, fac s.ι s.condition) (λ s, uniq s.ι s.condition) /-- Every kernel of `f` induces a kernel of `f ≫ g` if `g` is mono. -/ -def is_kernel_comp_mono {c : kernel_fork f} (i : is_limit c) {Z} (g : Y ⟶ Z) [hg : mono g] : - is_limit (kernel_fork.of_ι c.ι (by simp) : kernel_fork (f ≫ g)) := +def is_kernel_comp_mono {c : kernel_fork f} (i : is_limit c) {Z} (g : Y ⟶ Z) [hg : mono g] + {h : X ⟶ Z} (hh : h = f ≫ g) : + is_limit (kernel_fork.of_ι c.ι (by simp [hh]) : kernel_fork h) := fork.is_limit.mk' _ $ λ s, - let s' : kernel_fork f := fork.of_ι s.ι (by apply hg.right_cancellation; simp [s.condition]) in + let s' : kernel_fork f := fork.of_ι s.ι (by rw [←cancel_mono g]; simp [←hh, s.condition]) in let l := kernel_fork.is_limit.lift' i s'.ι s'.condition in ⟨l.1, l.2, λ m hm, by apply fork.is_limit.hom_ext i; rw fork.ι_of_ι at hm; rw hm; exact l.2.symm⟩ +lemma is_kernel_comp_mono_lift {c : kernel_fork f} (i : is_limit c) {Z} (g : Y ⟶ Z) [hg : mono g] + {h : X ⟶ Z} (hh : h = f ≫ g) (s : kernel_fork h) : + (is_kernel_comp_mono i g hh).lift s + = i.lift (fork.of_ι s.ι (by { rw [←cancel_mono g, category.assoc, ←hh], simp })) := rfl + end section @@ -283,7 +289,7 @@ lemma kernel_not_iso_of_nonzero (w : f ≠ 0) : (is_iso (kernel.ι f)) → false instance has_kernel_comp_mono {X Y Z : C} (f : X ⟶ Y) [has_kernel f] (g : Y ⟶ Z) [mono g] : has_kernel (f ≫ g) := -⟨⟨{ cone := _, is_limit := is_kernel_comp_mono (limit.is_limit _) g }⟩⟩ +⟨⟨{ cone := _, is_limit := is_kernel_comp_mono (limit.is_limit _) g rfl }⟩⟩ /-- When `g` is a monomorphism, the kernel of `f ≫ g` is isomorphic to the kernel of `f`. @@ -452,15 +458,22 @@ def is_colimit.of_π {Z : C} (g : Y ⟶ Z) (eq : f ≫ g = 0) is_colimit_aux _ (λ s, desc s.π s.condition) (λ s, fac s.π s.condition) (λ s, uniq s.π s.condition) /-- Every cokernel of `f` induces a cokernel of `g ≫ f` if `g` is epi. -/ -def is_cokernel_epi_comp {c : cokernel_cofork f} (i : is_colimit c) {W} (g : W ⟶ X) [hg : epi g] : - is_colimit (cokernel_cofork.of_π c.π (by simp) : cokernel_cofork (g ≫ f)) := +def is_cokernel_epi_comp {c : cokernel_cofork f} (i : is_colimit c) {W} (g : W ⟶ X) [hg : epi g] + {h : W ⟶ Y} (hh : h = g ≫ f) : + is_colimit (cokernel_cofork.of_π c.π (by rw [hh]; simp) : cokernel_cofork h) := cofork.is_colimit.mk' _ $ λ s, let s' : cokernel_cofork f := cofork.of_π s.π - (by apply hg.left_cancellation; simp [←category.assoc, s.condition]) in + (by { apply hg.left_cancellation, rw [←category.assoc, ←hh, s.condition], simp }) in let l := cokernel_cofork.is_colimit.desc' i s'.π s'.condition in ⟨l.1, l.2, λ m hm, by apply cofork.is_colimit.hom_ext i; rw cofork.π_of_π at hm; rw hm; exact l.2.symm⟩ +@[simp] +lemma is_cokernel_epi_comp_desc {c : cokernel_cofork f} (i : is_colimit c) {W} + (g : W ⟶ X) [hg : epi g] {h : W ⟶ Y} (hh : h = g ≫ f) (s : cokernel_cofork h) : + (is_cokernel_epi_comp i g hh).desc s + = i.desc (cofork.of_π s.π (by { rw [←cancel_epi g, ←category.assoc, ←hh], simp })) := rfl + end section @@ -625,14 +638,13 @@ def cokernel_comp_is_iso {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z) [has_cokernel f instance has_cokernel_epi_comp {X Y : C} (f : X ⟶ Y) [has_cokernel f] {W} (g : W ⟶ X) [epi g] : has_cokernel (g ≫ f) := -⟨⟨{ cocone := _, is_colimit := is_cokernel_epi_comp (colimit.is_colimit _) g }⟩⟩ +⟨⟨{ cocone := _, is_colimit := is_cokernel_epi_comp (colimit.is_colimit _) g rfl }⟩⟩ /-- When `f` is an epimorphism, the cokernel of `f ≫ g` is isomorphic to the cokernel of `g`. -/ @[simps] -def cokernel_epi_comp {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z) - [epi f] [has_cokernel g] : +def cokernel_epi_comp {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z) [epi f] [has_cokernel g] : cokernel (f ≫ g) ≅ cokernel g := { hom := cokernel.desc _ (cokernel.π g) (by simp), inv := cokernel.desc _ (cokernel.π (f ≫ g)) (by { rw [←cancel_epi f, ←category.assoc], simp, }), } diff --git a/src/category_theory/preadditive/default.lean b/src/category_theory/preadditive/default.lean index df1679038c20d..cfa2ddd21cb06 100644 --- a/src/category_theory/preadditive/default.lean +++ b/src/category_theory/preadditive/default.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2020 Markus Himmel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Markus Himmel +Authors: Markus Himmel, Jakob von Raumer -/ import algebra.big_operators.basic import algebra.hom.group @@ -233,6 +233,11 @@ fork.of_ι c.ι $ by rw [← sub_eq_zero, ← comp_sub, c.condition] def kernel_fork_of_fork (c : fork f g) : kernel_fork (f - g) := fork.of_ι c.ι $ by rw [comp_sub, comp_zero, sub_eq_zero, c.condition] +@[simp] lemma kernel_fork_of_fork_ι (c : fork f g) : (kernel_fork_of_fork c).ι = c.ι := rfl + +@[simp] lemma kernel_fork_of_fork_of_ι {P : C} (ι : P ⟶ X) (w : ι ≫ f = ι ≫ g) : + (kernel_fork_of_fork (fork.of_ι ι w)) = kernel_fork.of_ι ι (by simp [w]) := rfl + /-- A kernel of `f - g` is an equalizer of `f` and `g`. -/ def is_limit_fork_of_kernel_fork {c : kernel_fork (f - g)} (i : is_limit c) : is_limit (fork_of_kernel_fork c) := @@ -240,6 +245,10 @@ fork.is_limit.mk' _ $ λ s, ⟨i.lift (kernel_fork_of_fork s), i.fac _ _, λ m h, by { apply fork.is_limit.hom_ext i, rw [i.fac], exact h }⟩ +@[simp] +lemma is_limit_fork_of_kernel_fork_lift {c : kernel_fork (f - g)} (i : is_limit c) (s : fork f g) : + (is_limit_fork_of_kernel_fork i).lift s = i.lift (kernel_fork_of_fork s) := rfl + /-- An equalizer of `f` and `g` is a kernel of `f - g`. -/ def is_limit_kernel_fork_of_fork {c : fork f g} (i : is_limit c) : is_limit (kernel_fork_of_fork c) := @@ -269,6 +278,12 @@ cofork.of_π c.π $ by rw [← sub_eq_zero, ← sub_comp, c.condition] def cokernel_cofork_of_cofork (c : cofork f g) : cokernel_cofork (f - g) := cofork.of_π c.π $ by rw [sub_comp, zero_comp, sub_eq_zero, c.condition] +@[simp] lemma cokernel_cofork_of_cofork_π (c : cofork f g) : + (cokernel_cofork_of_cofork c).π = c.π := rfl + +@[simp] lemma cokernel_cofork_of_cofork_of_π {P : C} (π : Y ⟶ P) (w : f ≫ π = g ≫ π) : + (cokernel_cofork_of_cofork (cofork.of_π π w)) = cokernel_cofork.of_π π (by simp [w]) := rfl + /-- A cokernel of `f - g` is a coequalizer of `f` and `g`. -/ def is_colimit_cofork_of_cokernel_cofork {c : cokernel_cofork (f - g)} (i : is_colimit c) : is_colimit (cofork_of_cokernel_cofork c) := @@ -276,6 +291,11 @@ cofork.is_colimit.mk' _ $ λ s, ⟨i.desc (cokernel_cofork_of_cofork s), i.fac _ _, λ m h, by { apply cofork.is_colimit.hom_ext i, rw [i.fac], exact h }⟩ +@[simp] +lemma is_colimit_cofork_of_cokernel_cofork_desc {c : cokernel_cofork (f - g)} + (i : is_colimit c) (s : cofork f g) : + (is_colimit_cofork_of_cokernel_cofork i).desc s = i.desc (cokernel_cofork_of_cofork s) := rfl + /-- A coequalizer of `f` and `g` is a cokernel of `f - g`. -/ def is_colimit_cokernel_cofork_of_cofork {c : cofork f g} (i : is_colimit c) : is_colimit (cokernel_cofork_of_cofork c) := From 3676f11db6ed591759a2351ac8008652bb40783f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Thu, 14 Apr 2022 11:12:33 +0000 Subject: [PATCH 019/373] chore(order/complete_lattice): General cleanup (#13323) --- src/order/complete_lattice.lean | 139 +++++++++++++++----------------- 1 file changed, 64 insertions(+), 75 deletions(-) diff --git a/src/order/complete_lattice.lean b/src/order/complete_lattice.lean index 3bda16172b7ce..12910501ad2e5 100644 --- a/src/order/complete_lattice.lean +++ b/src/order/complete_lattice.lean @@ -78,15 +78,15 @@ Nevertheless it is sometimes a useful intermediate step in constructions. -/ @[ancestor partial_order has_Sup] class complete_semilattice_Sup (α : Type*) extends partial_order α, has_Sup α := -(le_Sup : ∀s, ∀a∈s, a ≤ Sup s) -(Sup_le : ∀s a, (∀b∈s, b ≤ a) → Sup s ≤ a) +(le_Sup : ∀ s, ∀ a ∈ s, a ≤ Sup s) +(Sup_le : ∀ s a, (∀ b ∈ s, b ≤ a) → Sup s ≤ a) section variables [complete_semilattice_Sup α] {s t : set α} {a b : α} @[ematch] theorem le_Sup : a ∈ s → a ≤ Sup s := complete_semilattice_Sup.le_Sup s a -theorem Sup_le : (∀b∈s, b ≤ a) → Sup s ≤ a := complete_semilattice_Sup.Sup_le s a +theorem Sup_le : (∀ b ∈ s, b ≤ a) → Sup s ≤ a := complete_semilattice_Sup.Sup_le s a lemma is_lub_Sup (s : set α) : is_lub s (Sup s) := ⟨λ x, le_Sup, λ x, Sup_le⟩ @@ -98,7 +98,7 @@ le_trans h (le_Sup hb) theorem Sup_le_Sup (h : s ⊆ t) : Sup s ≤ Sup t := (is_lub_Sup s).mono (is_lub_Sup t) h -@[simp] theorem Sup_le_iff : Sup s ≤ a ↔ ∀b ∈ s, b ≤ a := +@[simp] theorem Sup_le_iff : Sup s ≤ a ↔ ∀ b ∈ s, b ≤ a := is_lub_le_iff (is_lub_Sup s) lemma le_Sup_iff : a ≤ Sup s ↔ ∀ b ∈ upper_bounds s, a ≤ b := @@ -124,8 +124,8 @@ Nevertheless it is sometimes a useful intermediate step in constructions. -/ @[ancestor partial_order has_Inf] class complete_semilattice_Inf (α : Type*) extends partial_order α, has_Inf α := -(Inf_le : ∀s, ∀a∈s, Inf s ≤ a) -(le_Inf : ∀s a, (∀b∈s, a ≤ b) → a ≤ Inf s) +(Inf_le : ∀ s, ∀ a ∈ s, Inf s ≤ a) +(le_Inf : ∀ s a, (∀ b ∈ s, a ≤ b) → a ≤ Inf s) section @@ -133,7 +133,7 @@ variables [complete_semilattice_Inf α] {s t : set α} {a b : α} @[ematch] theorem Inf_le : a ∈ s → Inf s ≤ a := complete_semilattice_Inf.Inf_le s a -theorem le_Inf : (∀b∈s, a ≤ b) → a ≤ Inf s := complete_semilattice_Inf.le_Inf s a +theorem le_Inf : (∀ b ∈ s, a ≤ b) → a ≤ Inf s := complete_semilattice_Inf.le_Inf s a lemma is_glb_Inf (s : set α) : is_glb s (Inf s) := ⟨λ a, Inf_le, λ a, le_Inf⟩ @@ -145,21 +145,20 @@ le_trans (Inf_le hb) h theorem Inf_le_Inf (h : s ⊆ t) : Inf t ≤ Inf s := (is_glb_Inf s).mono (is_glb_Inf t) h -@[simp] theorem le_Inf_iff : a ≤ Inf s ↔ (∀b ∈ s, a ≤ b) := +@[simp] theorem le_Inf_iff : a ≤ Inf s ↔ ∀ b ∈ s, a ≤ b := le_is_glb_iff (is_glb_Inf s) -lemma Inf_le_iff : - Inf s ≤ a ↔ (∀ b ∈ lower_bounds s, b ≤ a) := +lemma Inf_le_iff : Inf s ≤ a ↔ ∀ b ∈ lower_bounds s, b ≤ a := ⟨λ h b hb, le_trans (le_Inf hb) h, λ hb, hb _ (λ x, Inf_le)⟩ -lemma infi_le_iff {s : ι → α} : infi s ≤ a ↔ (∀ b, (∀ i, b ≤ s i) → b ≤ a) := +lemma infi_le_iff {s : ι → α} : infi s ≤ a ↔ ∀ b, (∀ i, b ≤ s i) → b ≤ a := by simp [infi, Inf_le_iff, lower_bounds] theorem Inf_le_Inf_of_forall_exists_le (h : ∀ x ∈ s, ∃ y ∈ t, y ≤ x) : Inf t ≤ Inf s := le_of_forall_le begin simp only [le_Inf_iff], introv h₀ h₁, - rcases h _ h₁ with ⟨y,hy,hy'⟩, + rcases h _ h₁ with ⟨y, hy, hy'⟩, solve_by_elim [le_trans _ hy'] end @@ -169,8 +168,7 @@ is_glb_singleton.Inf_eq end -/-- A complete lattice is a bounded lattice which - has suprema and infima for every subset. -/ +/-- A complete lattice is a bounded lattice which has suprema and infima for every subset. -/ @[protect_proj, ancestor lattice complete_semilattice_Sup complete_semilattice_Inf has_top has_bot] class complete_lattice (α : Type*) extends lattice α, complete_semilattice_Sup α, complete_semilattice_Inf α, has_top α, has_bot α := @@ -347,7 +345,7 @@ theorem Sup_pair {a b : α} : Sup {a, b} = a ⊔ b := theorem Inf_pair {a b : α} : Inf {a, b} = a ⊓ b := (@is_glb_pair α _ a b).Inf_eq -@[simp] theorem Inf_eq_top : Inf s = ⊤ ↔ (∀a∈s, a = ⊤) := +@[simp] theorem Inf_eq_top : Inf s = ⊤ ↔ (∀ a ∈ s, a = ⊤) := iff.intro (λ h a ha, top_unique $ h ▸ Inf_le ha) (λ h, top_unique $ le_Inf $ λ a ha, top_le_iff.2 $ h a ha) @@ -356,7 +354,7 @@ lemma eq_singleton_top_of_Inf_eq_top_of_nonempty {s : set α} (h_inf : Inf s = ⊤) (hne : s.nonempty) : s = {⊤} := by { rw set.eq_singleton_iff_nonempty_unique_mem, rw Inf_eq_top at h_inf, exact ⟨hne, h_inf⟩, } -@[simp] theorem Sup_eq_bot : Sup s = ⊥ ↔ (∀a∈s, a = ⊥) := +@[simp] theorem Sup_eq_bot : Sup s = ⊥ ↔ (∀ a ∈ s, a = ⊥) := @Inf_eq_top (order_dual α) _ _ lemma eq_singleton_bot_of_Sup_eq_bot_of_nonempty {s : set α} @@ -370,10 +368,9 @@ lattices. -/ theorem Sup_eq_of_forall_le_of_forall_lt_exists_gt (_ : ∀a∈s, a ≤ b) (H : ∀w, w < b → (∃a∈s, w < a)) : Sup s = b := have h : (Sup s < b) ∨ (Sup s = b) := lt_or_eq_of_le (Sup_le ‹∀a∈s, a ≤ b›), -have ¬(Sup s < b) := - assume : Sup s < b, - let ⟨a, _, _⟩ := (H (Sup s) ‹Sup s < b›) in /- a ∈ s, Sup s < a-/ - have Sup s < Sup s := lt_of_lt_of_le ‹Sup s < a› (le_Sup ‹a ∈ s›), +have ¬(Sup s < b) := λ hb, + let ⟨a, ha, ha'⟩ := H (Sup s) hb in /- a ∈ s, Sup s < a-/ + have Sup s < Sup s := lt_of_lt_of_le ha' (le_Sup ha), show false, from lt_irrefl _ this, show Sup s = b, from or.resolve_left h this @@ -381,9 +378,9 @@ show Sup s = b, from or.resolve_left h this is smaller than all elements of `s`, and that this is not the case of any `w > b`. See `cInf_eq_of_forall_ge_of_forall_gt_exists_lt` for a version in conditionally complete lattices. -/ -theorem Inf_eq_of_forall_ge_of_forall_gt_exists_lt (_ : ∀a∈s, b ≤ a) - (H : ∀w, b < w → (∃a∈s, a < w)) : Inf s = b := -@Sup_eq_of_forall_le_of_forall_lt_exists_gt (order_dual α) _ _ ‹_› ‹_› ‹_› +theorem Inf_eq_of_forall_ge_of_forall_gt_exists_lt : (∀ a ∈ s, b ≤ a) → + (∀ w, b < w → (∃ a ∈ s, a < w)) → Inf s = b := +@Sup_eq_of_forall_le_of_forall_lt_exists_gt (order_dual α) _ _ ‹_› end @@ -393,14 +390,14 @@ variables [complete_linear_order α] {s t : set α} {a b : α} lemma Inf_lt_iff : Inf s < b ↔ ∃ a ∈ s, a < b := is_glb_lt_iff $ is_glb_Inf s lemma lt_Sup_iff : b < Sup s ↔ ∃ a ∈ s, b < a := lt_is_lub_iff $ is_lub_Sup s -lemma Sup_eq_top : Sup s = ⊤ ↔ (∀b<⊤, ∃a∈s, b < a) := +lemma Sup_eq_top : Sup s = ⊤ ↔ (∀ b < ⊤, ∃ a ∈ s, b < a) := iff.intro (λ (h : Sup s = ⊤) b hb, by rwa [←h, lt_Sup_iff] at hb) (λ h, top_unique $ le_of_not_gt $ λ h', let ⟨a, ha, h⟩ := h _ h' in lt_irrefl a $ lt_of_le_of_lt (le_Sup ha) h) -lemma Inf_eq_bot : Inf s = ⊥ ↔ (∀b>⊥, ∃a∈s, a < b) := +lemma Inf_eq_bot : Inf s = ⊥ ↔ (∀ b > ⊥, ∃ a ∈ s, a < b) := @Sup_eq_top (order_dual α) _ _ lemma lt_supr_iff {f : ι → α} : a < supr f ↔ ∃ i, a < f i := lt_Sup_iff.trans exists_range_iff @@ -425,8 +422,7 @@ lemma function.surjective.supr_comp {f : ι → ι'} (hf : surjective f) (g : ι by simp only [supr, hf.range_comp] protected lemma function.surjective.supr_congr {g : ι' → α} (h : ι → ι') (h1 : surjective h) - (h2 : ∀ x, g (h x) = f x) : - (⨆ x, f x) = ⨆ y, g y := + (h2 : ∀ x, g (h x) = f x) : (⨆ x, f x) = ⨆ y, g y := by { convert h1.supr_comp g, exact (funext h2).symm } @[congr] lemma supr_congr_Prop {p q : Prop} {f₁ : p → α} {f₂ : q → α} (pq : p ↔ q) @@ -608,7 +604,7 @@ calc (⨆ i j, f (s i j)) ≤ (⨆ i, f (⨆ j, s i j)) : ... ≤ f (⨆ i j, s i j) : hf.le_map_supr lemma monotone.le_map_Sup [complete_lattice β] {s : set α} {f : α → β} (hf : monotone f) : - (⨆a∈s, f a) ≤ f (Sup s) := + (⨆ a ∈ s, f a) ≤ f (Sup s) := by rw [Sup_eq_supr]; exact hf.le_map_supr₂ _ lemma antitone.le_map_infi [complete_lattice β] {f : α → β} (hf : antitone f) : @@ -632,13 +628,11 @@ lemma order_iso.map_Sup [complete_lattice β] (f : α ≃o β) (s : set α) : f (Sup s) = ⨆ a ∈ s, f a := by simp only [Sup_eq_supr, order_iso.map_supr] -lemma supr_comp_le {ι' : Sort*} (f : ι' → α) (g : ι → ι') : - (⨆ x, f (g x)) ≤ ⨆ y, f y := +lemma supr_comp_le {ι' : Sort*} (f : ι' → α) (g : ι → ι') : (⨆ x, f (g x)) ≤ ⨆ y, f y := supr_mono' $ λ x, ⟨_, le_rfl⟩ lemma monotone.supr_comp_eq [preorder β] {f : β → α} (hf : monotone f) - {s : ι → β} (hs : ∀ x, ∃ i, x ≤ s i) : - (⨆ x, f (s x)) = ⨆ y, f y := + {s : ι → β} (hs : ∀ x, ∃ i, x ≤ s i) : (⨆ x, f (s x)) = ⨆ y, f y := le_antisymm (supr_comp_le _ _) (supr_mono' $ λ x, (hs x).imp $ λ i hi, hf hi) lemma monotone.map_infi_le [complete_lattice β] {f : α → β} (hf : monotone f) : @@ -650,7 +644,7 @@ lemma monotone.map_infi₂_le [complete_lattice β] {f : α → β} (hf : monoto hf.dual.le_map_supr₂ _ lemma monotone.map_Inf_le [complete_lattice β] {s : set α} {f : α → β} (hf : monotone f) : - f (Inf s) ≤ ⨅ a∈s, f a := + f (Inf s) ≤ ⨅ a ∈ s, f a := by rw [Inf_eq_infi]; exact hf.map_infi₂_le _ lemma antitone.map_supr_le [complete_lattice β] {f : α → β} (hf : antitone f) : @@ -673,13 +667,11 @@ lemma order_iso.map_Inf [complete_lattice β] (f : α ≃o β) (s : set α) : f (Inf s) = ⨅ a ∈ s, f a := order_iso.map_Sup f.dual _ -lemma le_infi_comp {ι' : Sort*} (f : ι' → α) (g : ι → ι') : - (⨅ y, f y) ≤ ⨅ x, f (g x) := +lemma le_infi_comp {ι' : Sort*} (f : ι' → α) (g : ι → ι') : (⨅ y, f y) ≤ ⨅ x, f (g x) := infi_mono' $ λ x, ⟨_, le_rfl⟩ lemma monotone.infi_comp_eq [preorder β] {f : β → α} (hf : monotone f) - {s : ι → β} (hs : ∀ x, ∃ i, s i ≤ x) : - (⨅ x, f (s x)) = ⨅ y, f y := + {s : ι → β} (hs : ∀ x, ∃ i, s i ≤ x) : (⨅ x, f (s x)) = ⨅ y, f y := le_antisymm (infi_mono' $ λ x, (hs x).imp $ λ i hi, hf hi) (le_infi_comp _ _) lemma supr_const_le {x : α} : (⨆ (h : ι), x) ≤ x := @@ -689,11 +681,11 @@ lemma le_infi_const {x : α} : x ≤ (⨅ (h : ι), x) := le_infi (λ _, le_rfl) -- We will generalize this to conditionally complete lattices in `cinfi_const`. -theorem infi_const [nonempty ι] {a : α} : (⨅ b:ι, a) = a := +theorem infi_const [nonempty ι] {a : α} : (⨅ b : ι, a) = a := by rw [infi, range_const, Inf_singleton] -- We will generalize this to conditionally complete lattices in `csupr_const`. -theorem supr_const [nonempty ι] {a : α} : (⨆ b:ι, a) = a := +theorem supr_const [nonempty ι] {a : α} : (⨆ b : ι, a) = a := @infi_const (order_dual α) _ _ _ _ @[simp] lemma infi_top : (⨅ i:ι, ⊤ : α) = ⊤ := @@ -741,19 +733,19 @@ theorem infi_eq_of_forall_ge_of_forall_gt_exists_lt {f : ι → α} (h₁ : ∀ @supr_eq_of_forall_le_of_forall_lt_exists_gt (order_dual α) _ _ _ ‹_› ‹_› ‹_› lemma supr_eq_dif {p : Prop} [decidable p] (a : p → α) : - (⨆h:p, a h) = (if h : p then a h else ⊥) := + (⨆ h : p, a h) = if h : p then a h else ⊥ := by by_cases p; simp [h] lemma supr_eq_if {p : Prop} [decidable p] (a : α) : - (⨆h:p, a) = (if p then a else ⊥) := + (⨆ h : p, a) = if p then a else ⊥ := supr_eq_dif (λ _, a) lemma infi_eq_dif {p : Prop} [decidable p] (a : p → α) : - (⨅h:p, a h) = (if h : p then a h else ⊤) := + (⨅ h : p, a h) = if h : p then a h else ⊤ := @supr_eq_dif (order_dual α) _ _ _ _ lemma infi_eq_if {p : Prop} [decidable p] (a : α) : - (⨅h:p, a) = (if p then a else ⊤) := + (⨅ h : p, a) = if p then a else ⊤ := infi_eq_dif (λ _, a) -- TODO: should this be @[simp]? @@ -778,29 +770,29 @@ begin end -/ -@[simp] theorem infi_infi_eq_left {b : β} {f : Πx:β, x = b → α} : - (⨅x, ⨅h:x = b, f x h) = f b rfl := +@[simp] theorem infi_infi_eq_left {b : β} {f : Π x : β, x = b → α} : + (⨅ x, ⨅ h : x = b, f x h) = f b rfl := le_antisymm (infi₂_le _ rfl) (le_infi $ λ b', le_infi $ λ eq, match b', eq with ._, rfl := le_rfl end) -@[simp] theorem infi_infi_eq_right {b : β} {f : Πx:β, b = x → α} : - (⨅x, ⨅h:b = x, f x h) = f b rfl := +@[simp] theorem infi_infi_eq_right {b : β} {f : Π x : β, b = x → α} : + (⨅ x, ⨅ h : b = x, f x h) = f b rfl := le_antisymm (infi₂_le _ rfl) (le_infi₂ $ λ b' eq, match b', eq with ._, rfl := le_rfl end) -@[simp] theorem supr_supr_eq_left {b : β} {f : Πx:β, x = b → α} : - (⨆x, ⨆h : x = b, f x h) = f b rfl := +@[simp] theorem supr_supr_eq_left {b : β} {f : Π x : β, x = b → α} : + (⨆ x, ⨆ h : x = b, f x h) = f b rfl := @infi_infi_eq_left (order_dual α) _ _ _ _ -@[simp] theorem supr_supr_eq_right {b : β} {f : Πx:β, b = x → α} : - (⨆x, ⨆h : b = x, f x h) = f b rfl := +@[simp] theorem supr_supr_eq_right {b : β} {f : Π x : β, b = x → α} : + (⨆ x, ⨆ h : b = x, f x h) = f b rfl := @infi_infi_eq_right (order_dual α) _ _ _ _ attribute [ematch] le_refl -theorem infi_subtype {p : ι → Prop} {f : subtype p → α} : (⨅ x, f x) = (⨅ i (h:p i), f ⟨i, h⟩) := +theorem infi_subtype {p : ι → Prop} {f : subtype p → α} : (⨅ x, f x) = (⨅ i (h : p i), f ⟨i, h⟩) := le_antisymm (le_infi₂ $ λ i h, infi_le _ _) (le_infi $ λ ⟨i, h⟩, infi₂_le _ _) lemma infi_subtype' {p : ι → Prop} {f : ∀ i, p i → α} : @@ -825,10 +817,10 @@ begin end -/ -lemma infi_inf [h : nonempty ι] {f : ι → α} {a : α} : (⨅x, f x) ⊓ a = (⨅ x, f x ⊓ a) := +lemma infi_inf [h : nonempty ι] {f : ι → α} {a : α} : (⨅ x, f x) ⊓ a = (⨅ x, f x ⊓ a) := by rw [infi_inf_eq, infi_const] -lemma inf_infi [nonempty ι] {f : ι → α} {a : α} : a ⊓ (⨅x, f x) = (⨅ x, a ⊓ f x) := +lemma inf_infi [nonempty ι] {f : ι → α} {a : α} : a ⊓ (⨅ x, f x) = (⨅ x, a ⊓ f x) := by rw [inf_comm, infi_inf]; simp [inf_comm] lemma binfi_inf {p : ι → Prop} {f : Π i (hi : p i), α} {a : α} (h : ∃ i, p i) : @@ -965,7 +957,8 @@ theorem infi_le_infi_of_subset {f : β → α} {s t : set β} (h : s ⊆ t) : (⨅ x ∈ t, f x) ≤ (⨅ x ∈ s, f x) := by rw [(union_eq_self_of_subset_left h).symm, infi_union]; exact inf_le_left -theorem supr_union {f : β → α} {s t : set β} : (⨆ x ∈ s ∪ t, f x) = (⨆x∈s, f x) ⊔ (⨆x∈t, f x) := +theorem supr_union {f : β → α} {s t : set β} : + (⨆ x ∈ s ∪ t, f x) = (⨆ x ∈ s, f x) ⊔ (⨆ x ∈ t, f x) := @infi_union (order_dual α) _ _ _ _ _ lemma supr_split (f : β → α) (p : β → Prop) : @@ -981,12 +974,12 @@ theorem supr_le_supr_of_subset {f : β → α} {s t : set β} (h : s ⊆ t) : @infi_le_infi_of_subset (order_dual α) _ _ _ _ _ h theorem infi_insert {f : β → α} {s : set β} {b : β} : - (⨅ x ∈ insert b s, f x) = f b ⊓ (⨅x∈s, f x) := -eq.trans infi_union $ congr_arg (λx:α, x ⊓ (⨅x∈s, f x)) infi_infi_eq_left + (⨅ x ∈ insert b s, f x) = f b ⊓ (⨅ x ∈ s, f x) := +eq.trans infi_union $ congr_arg (λ x, x ⊓ (⨅ x ∈ s, f x)) infi_infi_eq_left theorem supr_insert {f : β → α} {s : set β} {b : β} : - (⨆ x ∈ insert b s, f x) = f b ⊔ (⨆x∈s, f x) := -eq.trans supr_union $ congr_arg (λx:α, x ⊔ (⨆x∈s, f x)) supr_supr_eq_left + (⨆ x ∈ insert b s, f x) = f b ⊔ (⨆ x ∈ s, f x) := +eq.trans supr_union $ congr_arg (λ x, x ⊔ (⨆ x ∈ s, f x)) supr_supr_eq_left theorem infi_singleton {f : β → α} {b : β} : (⨅ x ∈ (singleton b : set β), f x) = f b := by simp @@ -1015,7 +1008,6 @@ begin simp [extend_apply he, extend_apply', @supr_comm _ β ι] { contextual := tt } end - /-! ### `supr` and `infi` under `Type` -/ @@ -1063,10 +1055,10 @@ supr_subtype lemma is_lub_bsupr {s : set β} {f : β → α} : is_lub (f '' s) (⨆ x ∈ s, f x) := by simpa only [range_comp, subtype.range_coe, supr_subtype'] using @is_lub_supr α s _ (f ∘ coe) -theorem infi_sigma {p : β → Type*} {f : sigma p → α} : (⨅ x, f x) = (⨅ i (h:p i), f ⟨i, h⟩) := +theorem infi_sigma {p : β → Type*} {f : sigma p → α} : (⨅ x, f x) = (⨅ i (h : p i), f ⟨i, h⟩) := eq_of_forall_le_iff $ λ c, by simp only [le_infi_iff, sigma.forall] -theorem supr_sigma {p : β → Type*} {f : sigma p → α} : (⨆ x, f x) = (⨆ i (h:p i), f ⟨i, h⟩) := +theorem supr_sigma {p : β → Type*} {f : sigma p → α} : (⨆ x, f x) = (⨆ i (h : p i), f ⟨i, h⟩) := @infi_sigma (order_dual α) _ _ _ _ theorem infi_prod {γ : Type*} {f : β × γ → α} : (⨅ x, f x) = (⨅ i j, f (i, j)) := @@ -1163,10 +1155,10 @@ end section complete_linear_order variables [complete_linear_order α] -lemma supr_eq_top (f : ι → α) : supr f = ⊤ ↔ (∀b<⊤, ∃i, b < f i) := +lemma supr_eq_top (f : ι → α) : supr f = ⊤ ↔ (∀ b <⊤, ∃ i, b < f i) := by simp only [← Sup_range, Sup_eq_top, set.exists_range_iff] -lemma infi_eq_bot (f : ι → α) : infi f = ⊥ ↔ (∀b>⊥, ∃i, f i < b) := +lemma infi_eq_bot (f : ι → α) : infi f = ⊥ ↔ (∀ b > ⊥, ∃ i, f i < b) := by simp only [← Inf_range, Inf_eq_bot, set.exists_range_iff] end complete_linear_order @@ -1176,10 +1168,10 @@ end complete_linear_order -/ instance Prop.complete_lattice : complete_lattice Prop := -{ Sup := λs, ∃a∈s, a, +{ Sup := λ s, ∃ a ∈ s, a, le_Sup := λ s a h p, ⟨a, h, p⟩, Sup_le := λ s a h ⟨b, h', p⟩, h b h' p, - Inf := λs, ∀a:Prop, a∈s → a, + Inf := λ s, ∀ a, a ∈ s → a, Inf_le := λ s a h p, p a h, le_Inf := λ s a h p b hb, h b hb p, .. Prop.bounded_order, @@ -1212,17 +1204,15 @@ instance pi.complete_lattice {α : Type*} {β : α → Type*} [∀ i, complete_l .. pi.lattice } lemma Inf_apply {α : Type*} {β : α → Type*} [Π i, has_Inf (β i)] - {s : set (Πa, β a)} {a : α} : - (Inf s) a = (⨅ f : s, (f : Πa, β a) a) := + {s : set (Π a, β a)} {a : α} : (Inf s) a = (⨅ f : s, (f : Π a, β a) a) := rfl @[simp] lemma infi_apply {α : Type*} {β : α → Type*} {ι : Sort*} [Π i, has_Inf (β i)] - {f : ι → Πa, β a} {a : α} : - (⨅ i, f i) a = ⨅ i, f i a := + {f : ι → Π a, β a} {a : α} : (⨅ i, f i) a = ⨅ i, f i a := by rw [infi, Inf_apply, infi, infi, ← image_eq_range (λ f : Π i, β i, f a) (range f), ← range_comp] lemma Sup_apply {α : Type*} {β : α → Type*} [Π i, has_Sup (β i)] {s : set (Πa, β a)} {a : α} : - (Sup s) a = (⨆f:s, (f : Πa, β a) a) := + (Sup s) a = (⨆ f : s, (f : Π a, β a) a) := rfl lemma unary_relation_Sup_iff {α : Type*} (s : set (α → Prop)) {a : α} : @@ -1234,17 +1224,16 @@ lemma binary_relation_Sup_iff {α β : Type*} (s : set (α → β → Prop)) {a by { change (∃ _, _) ↔ _, simp [-eq_iff_iff] } @[simp] lemma supr_apply {α : Type*} {β : α → Type*} {ι : Sort*} [Π i, has_Sup (β i)] - {f : ι → Πa, β a} {a : α} : - (⨆ i, f i) a = (⨆ i, f i a) := + {f : ι → Π a, β a} {a : α} : (⨆ i, f i) a = (⨆ i, f i a) := @infi_apply α (λ i, order_dual (β i)) _ _ f a section complete_lattice variables [preorder α] [complete_lattice β] -theorem monotone_Sup_of_monotone {s : set (α → β)} (m_s : ∀f∈s, monotone f) : monotone (Sup s) := +theorem monotone_Sup_of_monotone {s : set (α → β)} (m_s : ∀ f ∈ s, monotone f) : monotone (Sup s) := λ x y h, supr_mono $ λ f, m_s f f.2 h -theorem monotone_Inf_of_monotone {s : set (α → β)} (m_s : ∀f∈s, monotone f) : monotone (Inf s) := +theorem monotone_Inf_of_monotone {s : set (α → β)} (m_s : ∀ f ∈ s, monotone f) : monotone (Inf s) := λ x y h, infi_mono $ λ f, m_s f f.2 h end complete_lattice From 769ec8c8f414d83b06289b2dd744bce179372b25 Mon Sep 17 00:00:00 2001 From: tb65536 Date: Thu, 14 Apr 2022 11:12:34 +0000 Subject: [PATCH 020/373] feat(group_theory/group_action/basic): Right multiplication satisfies the `quotient_action` axiom (#13362) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds an instance stating that the right multiplication action of `H.normalizer.opposite` on `G` satisfies the `quotient_action` axiom. In particular, we automatically get the induced action of `H.normalizer.opposite` on `G ⧸ H`, so we can delete the existing instance. (Technically, the existing instance was stated in terms of `H.normalizerᵐᵒᵖ`, but I think `H.normalizer.opposite` is a more natural way to write it). --- src/group_theory/group_action/basic.lean | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/group_theory/group_action/basic.lean b/src/group_theory/group_action/basic.lean index 87999c2fb98eb..56f3c5c7f5305 100644 --- a/src/group_theory/group_action/basic.lean +++ b/src/group_theory/group_action/basic.lean @@ -296,6 +296,8 @@ variables [group α] section quotient_action +open subgroup mul_opposite + variables (β) [monoid β] [mul_action β α] (H : subgroup α) /-- A typeclass for when a `mul_action β α` descends to the quotient `α ⧸ H`. -/ @@ -312,6 +314,10 @@ attribute [to_additive add_action.quotient_action] mul_action.quotient_action @[to_additive] instance left_quotient_action : quotient_action α H := ⟨λ _ _ _ _, by rwa [smul_eq_mul, smul_eq_mul, mul_inv_rev, mul_assoc, inv_mul_cancel_left]⟩ +@[to_additive] instance right_quotient_action : quotient_action H.normalizer.opposite H := +⟨λ b c _ _, by rwa [smul_def, smul_def, smul_eq_mul_unop, smul_eq_mul_unop, mul_inv_rev, ←mul_assoc, + mem_normalizer_iff'.mp b.prop, mul_assoc, mul_inv_cancel_left]⟩ + @[to_additive] instance quotient [quotient_action β H] : mul_action β (α ⧸ H) := { smul := λ b, quotient.map' ((•) b) (λ a a' h, quotient_action.inv_mul_mem b h), one_smul := λ q, quotient.induction_on' q (λ a, congr_arg quotient.mk' (one_smul β a)), @@ -333,19 +339,6 @@ open quotient_group mul_action I (α ⧸ H) := mul_action.comp_hom (α ⧸ H) (subgroup.subtype I) -@[to_additive] instance quotient' (H : subgroup α) : mul_action H.normalizerᵐᵒᵖ (α ⧸ H) := -{ smul := λ g, quotient.map' (* g.unop) (λ a b, (congr_arg (∈ H) (by rw [subtype.val_eq_coe, - subgroup.coe_inv, inv_inv, ←mul_assoc, ←mul_inv_rev, mul_assoc])).mp ∘ (g.unop⁻¹.2 _).mp), - one_smul := λ a, quotient.induction_on' a (λ a, congr_arg quotient.mk' (mul_one a)), - mul_smul := λ x y a, quotient.induction_on' a - (λ a, congr_arg quotient.mk' (mul_assoc a y.unop x.unop).symm) } - -@[simp, to_additive] lemma quotient'.smul_mk (H : subgroup α) (a : H.normalizerᵐᵒᵖ) (x : α) : - (a • quotient_group.mk x : α ⧸ H) = quotient_group.mk (x * a.unop) := rfl - -@[simp, to_additive] lemma quotient'.smul_coe (H : subgroup α) (a : H.normalizerᵐᵒᵖ) (x : α) : - (a • x : α ⧸ H) = ↑(x * a.unop) := rfl - variables (α) {β} [mul_action α β] (x : β) /-- The canonical map from the quotient of the stabilizer to the set. -/ From 15b764d8386d8e114a6fd3a899afb4736a21fa5f Mon Sep 17 00:00:00 2001 From: tb65536 Date: Thu, 14 Apr 2022 11:12:35 +0000 Subject: [PATCH 021/373] feat(group_theory/complement): Add more API for the action on left transversals (#13363) This PR adds more API for the action on left transversals. --- src/group_theory/complement.lean | 8 ++++++++ src/group_theory/schur_zassenhaus.lean | 11 ++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/group_theory/complement.lean b/src/group_theory/complement.lean index f6316ad9d1134..cfbed9e1e8300 100644 --- a/src/group_theory/complement.lean +++ b/src/group_theory/complement.lean @@ -315,6 +315,14 @@ subtype.ext_iff.mp $ @unique_of_exists_unique ↥(f • T) (λ s, (↑s)⁻¹ * ⟨f • to_fun T.2 g, set.smul_mem_smul_set (subtype.coe_prop _)⟩ (to_fun (f • T).2 (f • g)) (quotient_action.inv_mul_mem f (inv_to_fun_mul_mem T.2 g)) (inv_to_fun_mul_mem (f • T).2 (f • g)) +@[to_additive] lemma smul_to_equiv (f : F) (T : left_transversals (H : set G)) (q : G ⧸ H) : + f • (to_equiv T.2 q : G) = to_equiv (f • T).2 (f • q) := +quotient.induction_on' q (λ g, smul_to_fun f T g) + +@[to_additive] lemma smul_apply_eq_smul_apply_inv_smul (f : F) (T : left_transversals (H : set G)) + (q : G ⧸ H) : (to_equiv (f • T).2 q : G) = f • (to_equiv T.2 (f⁻¹ • q) : G) := +by rw [smul_to_equiv, smul_inv_smul] + end action @[to_additive] instance : inhabited (left_transversals (H : set G)) := diff --git a/src/group_theory/schur_zassenhaus.lean b/src/group_theory/schur_zassenhaus.lean index c2f32cd19e2f9..24a778e3d0987 100644 --- a/src/group_theory/schur_zassenhaus.lean +++ b/src/group_theory/schur_zassenhaus.lean @@ -33,13 +33,6 @@ open mem_left_transversals variables {G : Type*} [group G] {H : subgroup G} -lemma smul_symm_apply_eq_mul_symm_apply_inv_smul - (g : G) (α : left_transversals (H : set G)) (q : G ⧸ H) : - ↑(to_equiv (g • α).2 q) = g * (to_equiv α.2 (g⁻¹ • q : G ⧸ H)) := -(subtype.ext_iff.mp (by exact (to_equiv (g • α).2).apply_eq_iff_eq_symm_apply.mpr - ((congr_arg _ ((to_equiv α.2).symm_apply_apply _)).trans (smul_inv_smul g q)).symm)).trans - (subtype.coe_mk _ (mem_left_coset g (subtype.mem _))) - variables [is_commutative H] [fintype (G ⧸ H)] variables (α β γ : left_transversals (H : set G)) @@ -72,7 +65,7 @@ begin (λ q _, subtype.ext _) (λ q _, ↑g * q) (λ _ _, finset.mem_univ _) (λ q _, mul_inv_cancel_left g q) (λ q _, inv_mul_cancel_left g q)) (ϕ.map_prod _ _).symm, change _ * _ = g * (_ * _) * g⁻¹, - simp_rw [smul_symm_apply_eq_mul_symm_apply_inv_smul, mul_inv_rev, mul_assoc], + simp_rw [smul_apply_eq_smul_apply_inv_smul, smul_eq_mul, mul_inv_rev, mul_assoc], refl, end @@ -82,7 +75,7 @@ begin rw [diff, diff, index_eq_card, ←finset.card_univ, ←finset.prod_const, ←finset.prod_mul_distrib], refine finset.prod_congr rfl (λ q _, _), rw [subtype.ext_iff, coe_mul, coe_mk, coe_mk, ←mul_assoc, mul_right_cancel_iff], - rw [show h • α = (h : G) • α, from rfl, smul_symm_apply_eq_mul_symm_apply_inv_smul], + rw [smul_def, smul_apply_eq_smul_apply_inv_smul, smul_eq_mul], rw [mul_left_cancel_iff, ←subtype.ext_iff, equiv.apply_eq_iff_eq, inv_smul_eq_iff], exact self_eq_mul_left.mpr ((quotient_group.eq_one_iff _).mpr h.2), end From dd34ffaff0b06278ffe0814b68243fa5f46e039a Mon Sep 17 00:00:00 2001 From: tb65536 Date: Thu, 14 Apr 2022 11:12:36 +0000 Subject: [PATCH 022/373] refactor(group_theory/schur_zassenhaus): Golf using `is_complement'_stabilizer` (#13392) This PR golfs the proof of the abelian case of Schur-Zassenhaus using the new lemma `is_complement'_stabilizer`. --- src/group_theory/schur_zassenhaus.lean | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/src/group_theory/schur_zassenhaus.lean b/src/group_theory/schur_zassenhaus.lean index 24a778e3d0987..638fbc71d6a70 100644 --- a/src/group_theory/schur_zassenhaus.lean +++ b/src/group_theory/schur_zassenhaus.lean @@ -123,27 +123,14 @@ lemma smul_left_injective [H.normal] (α : H.quotient_diff) exact (pow_coprime hH).injective hα, end -lemma is_complement'_stabilizer_of_coprime [fintype G] [H.normal] {α : H.quotient_diff} - (hH : nat.coprime (fintype.card H) H.index) : - is_complement' H (mul_action.stabilizer G α) := -begin - classical, - let ϕ : H ≃ mul_action.orbit G α := equiv.of_bijective (λ h, ⟨h • α, h, rfl⟩) - ⟨λ h₁ h₂ hh, smul_left_injective α hH (subtype.ext_iff.mp hh), - λ β, exists_imp_exists (λ h hh, subtype.ext hh) (exists_smul_eq α β hH)⟩, - have key := card_eq_card_quotient_mul_card_subgroup (mul_action.stabilizer G α), - rw ← fintype.card_congr (ϕ.trans (mul_action.orbit_equiv_quotient_stabilizer G α)) at key, - apply is_complement'_of_coprime key.symm, - rw [card_eq_card_quotient_mul_card_subgroup H, mul_comm, mul_right_inj'] at key, - { rwa [←key, ←index_eq_card] }, - { rw [←pos_iff_ne_zero, fintype.card_pos_iff], - apply_instance }, -end +lemma is_complement'_stabilizer_of_coprime [H.normal] {α : H.quotient_diff} + (hH : nat.coprime (fintype.card H) H.index) : is_complement' H (mul_action.stabilizer G α) := +is_complement'_stabilizer α (λ h hh, smul_left_injective α hH (hh.trans (one_smul H α).symm)) + (λ g, exists_smul_eq (g • α) α hH) /-- Do not use this lemma: It is made obsolete by `exists_right_complement'_of_coprime` -/ -private lemma exists_right_complement'_of_coprime_aux [fintype G] [H.normal] - (hH : nat.coprime (fintype.card H) H.index) : - ∃ K : subgroup G, is_complement' H K := +private lemma exists_right_complement'_of_coprime_aux [H.normal] + (hH : nat.coprime (fintype.card H) H.index) : ∃ K : subgroup G, is_complement' H K := nonempty_of_inhabited.elim (λ α : H.quotient_diff, ⟨mul_action.stabilizer G α, is_complement'_stabilizer_of_coprime hH⟩) From 88ba31c99b69ad482a754971d053a9a87355d499 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Thu, 14 Apr 2022 11:12:37 +0000 Subject: [PATCH 023/373] feat(measure_theory/constructions/pi): more `measure_preserving` lemmas (#13404) * Reformulate `map_pi_equiv_pi_subtype_prod` in terms of `measure_preserving`. * Add more equivalences (bare equivalences, order isomorphisms, and measurable equivalences) on pi types. --- src/logic/equiv/fin.lean | 17 +++++ src/logic/equiv/set.lean | 13 ++++ src/measure_theory/constructions/pi.lean | 85 +++++++++++++----------- src/measure_theory/measurable_space.lean | 23 +++++++ src/measure_theory/measure/lebesgue.lean | 35 +++++----- 5 files changed, 114 insertions(+), 59 deletions(-) diff --git a/src/logic/equiv/fin.lean b/src/logic/equiv/fin.lean index 2adff0aa9f136..5a5222974af04 100644 --- a/src/logic/equiv/fin.lean +++ b/src/logic/equiv/fin.lean @@ -209,6 +209,23 @@ fin_succ_equiv'_symm_some_below i.2 fin_succ_equiv_last.symm none = fin.last n := fin_succ_equiv'_symm_none _ +/-- Equivalence between `Π j : fin (n + 1), α j` and `α i × Π j : fin n, α (fin.succ_above i j)`. -/ +@[simps { fully_applied := ff}] +def equiv.pi_fin_succ_above_equiv {n : ℕ} (α : fin (n + 1) → Type u) (i : fin (n + 1)) : + (Π j, α j) ≃ α i × (Π j, α (i.succ_above j)) := +{ to_fun := λ f, (f i, λ j, f (i.succ_above j)), + inv_fun := λ f, i.insert_nth f.1 f.2, + left_inv := λ f, by simp [fin.insert_nth_eq_iff], + right_inv := λ f, by simp } + +/-- Order isomorphism between `Π j : fin (n + 1), α j` and +`α i × Π j : fin n, α (fin.succ_above i j)`. -/ +def order_iso.pi_fin_succ_above_iso {n : ℕ} (α : fin (n + 1) → Type u) [Π i, has_le (α i)] + (i : fin (n + 1)) : + (Π j, α j) ≃o α i × (Π j, α (i.succ_above j)) := +{ to_equiv := equiv.pi_fin_succ_above_equiv α i, + map_rel_iff' := λ f g, i.forall_iff_succ_above.symm } + /-- Equivalence between `fin m ⊕ fin n` and `fin (m + n)` -/ def fin_sum_fin_equiv : fin m ⊕ fin n ≃ fin (m + n) := { to_fun := sum.elim (fin.cast_add n) (fin.nat_add m), diff --git a/src/logic/equiv/set.lean b/src/logic/equiv/set.lean index 175d81228a0ab..fe94870a70fc1 100644 --- a/src/logic/equiv/set.lean +++ b/src/logic/equiv/set.lean @@ -500,6 +500,19 @@ protected lemma preimage_sUnion {α β} (f : α ≃ β) {s : set (set β)} : f ⁻¹' (⋃₀ s) = ⋃₀ (_root_.set.image f ⁻¹' s) := by { ext x, simp [(equiv.set.congr f).symm.exists_congr_left] } +lemma preimage_pi_equiv_pi_subtype_prod_symm_pi {α : Type*} {β : α → Type*} + (p : α → Prop) [decidable_pred p] (s : Π i, set (β i)) : + (pi_equiv_pi_subtype_prod p β).symm ⁻¹' set.pi univ s = + (set.pi univ (λ i : {i // p i}, s i)) ×ˢ (set.pi univ (λ i : {i // ¬p i}, s i)) := +begin + ext ⟨f, g⟩, + simp only [mem_preimage, mem_univ_pi, prod_mk_mem_set_prod_eq, subtype.forall, + ← forall_and_distrib], + refine forall_congr (λ i, _), + dsimp only [subtype.coe_mk], + by_cases hi : p i; simp [hi] +end + end equiv /-- If a function is a bijection between two sets `s` and `t`, then it induces an diff --git a/src/measure_theory/constructions/pi.lean b/src/measure_theory/constructions/pi.lean index e7e23eca8f5a3..b6ee3eba3155a 100644 --- a/src/measure_theory/constructions/pi.lean +++ b/src/measure_theory/constructions/pi.lean @@ -18,11 +18,11 @@ In this file we define and prove properties about finite products of measures Given `μ : Π i : ι, measure (α i)` for `[fintype ι]` it has type `measure (Π i : ι, α i)`. To apply Fubini along some subset of the variables, use -`measure_theory.measure.map_pi_equiv_pi_subtype_prod` to reduce to the situation of a product -of two measures: this lemma states that the bijection `equiv.pi_equiv_pi_subtype_prod p α` -between `(Π i : ι, α i)` and `(Π i : {i // p i}, α i) × (Π i : {i // ¬ p i}, α i)` maps a product -measure to a direct product of product measures, to which one can apply the usual Fubini for -direct product of measures. +`measure_theory.measure_preserving_pi_equiv_pi_subtype_prod` to reduce to the situation of a product +of two measures: this lemma states that the bijection +`measurable_equiv.pi_equiv_pi_subtype_prod α p` between `(Π i : ι, α i)` and +`(Π i : {i // p i}, α i) × (Π i : {i // ¬ p i}, α i)` maps a product measure to a direct product of +product measures, to which one can apply the usual Fubini for direct product of measures. ## Implementation Notes @@ -507,40 +507,6 @@ end variable (μ) -/-- Separating the indices into those that satisfy a predicate `p` and those that don't maps -a product measure to a product of product measures. This is useful to apply Fubini to some subset -of the variables. The converse is `measure_theory.measure.map_pi_equiv_pi_subtype_prod`. -/ -lemma map_pi_equiv_pi_subtype_prod_symm (p : ι → Prop) [decidable_pred p] : - map (equiv.pi_equiv_pi_subtype_prod p α).symm - (measure.prod (measure.pi (λ i, μ i)) (measure.pi (λ i, μ i))) = measure.pi μ := -begin - refine (measure.pi_eq (λ s hs, _)).symm, - have A : (equiv.pi_equiv_pi_subtype_prod p α).symm ⁻¹' (set.pi set.univ (λ (i : ι), s i)) = - (set.pi set.univ (λ i : {i // p i}, s i)) ×ˢ (set.pi set.univ (λ i : {i // ¬p i}, s i)), - { ext x, - simp only [equiv.pi_equiv_pi_subtype_prod_symm_apply, mem_prod, mem_univ_pi, mem_preimage, - subtype.forall], - split, - { exact λ h, ⟨λ i hi, by simpa [dif_pos hi] using h i, - λ i hi, by simpa [dif_neg hi] using h i⟩ }, - { assume h i, - by_cases hi : p i, - { simpa only [dif_pos hi] using h.1 i hi }, - {simpa only [dif_neg hi] using h.2 i hi } } }, - rw [measure.map_apply (measurable_pi_equiv_pi_subtype_prod_symm _ p) - (measurable_set.univ_pi_fintype hs), A, - measure.prod_prod, pi_pi, pi_pi, ← fintype.prod_subtype_mul_prod_subtype p (λ i, μ i (s i))], -end - -lemma map_pi_equiv_pi_subtype_prod (p : ι → Prop) [decidable_pred p] : - map (equiv.pi_equiv_pi_subtype_prod p α) (measure.pi μ) = - measure.prod (measure.pi (λ i, μ i)) (measure.pi (λ i, μ i)) := -begin - rw [← map_pi_equiv_pi_subtype_prod_symm μ p, measure.map_map - (measurable_pi_equiv_pi_subtype_prod _ p) (measurable_pi_equiv_pi_subtype_prod_symm _ p)], - simp only [equiv.self_comp_symm, map_id] -end - @[to_additive] instance pi.is_mul_left_invariant [∀ i, group (α i)] [∀ i, has_measurable_mul (α i)] [∀ i, is_mul_left_invariant (μ i)] : is_mul_left_invariant (measure.pi μ) := begin @@ -614,6 +580,47 @@ measures of corresponding sets (images or preimages) have equal measures and fun section measure_preserving +lemma measure_preserving_pi_equiv_pi_subtype_prod {ι : Type u} {α : ι → Type v} [fintype ι] + {m : Π i, measurable_space (α i)} (μ : Π i, measure (α i)) [∀ i, sigma_finite (μ i)] + (p : ι → Prop) [decidable_pred p] : + measure_preserving (measurable_equiv.pi_equiv_pi_subtype_prod α p) (measure.pi μ) + ((measure.pi $ λ i : subtype p, μ i).prod (measure.pi $ λ i, μ i)) := +begin + set e := (measurable_equiv.pi_equiv_pi_subtype_prod α p).symm, + suffices : measure_preserving e _ _, from this.symm, + refine ⟨e.measurable, (pi_eq $ λ s hs, _).symm⟩, + have : e ⁻¹' (pi univ s) = + (pi univ (λ i : {i // p i}, s i)) ×ˢ (pi univ (λ i : {i // ¬p i}, s i)), + from equiv.preimage_pi_equiv_pi_subtype_prod_symm_pi p s, + rw [e.map_apply, this, prod_prod, pi_pi, pi_pi], + exact fintype.prod_subtype_mul_prod_subtype p (λ i, μ i (s i)) +end + +lemma volume_preserving_pi_equiv_pi_subtype_prod {ι : Type*} (α : ι → Type*) [fintype ι] + [Π i, measure_space (α i)] [∀ i, sigma_finite (volume : measure (α i))] + (p : ι → Prop) [decidable_pred p] : + measure_preserving (measurable_equiv.pi_equiv_pi_subtype_prod α p) := +measure_preserving_pi_equiv_pi_subtype_prod (λ i, volume) p + +lemma measure_preserving_pi_fin_succ_above_equiv {n : ℕ} {α : fin (n + 1) → Type u} + {m : Π i, measurable_space (α i)} (μ : Π i, measure (α i)) [∀ i, sigma_finite (μ i)] + (i : fin (n + 1)) : + measure_preserving (measurable_equiv.pi_fin_succ_above_equiv α i) (measure.pi μ) + ((μ i).prod $ measure.pi $ λ j, μ (i.succ_above j)) := +begin + set e := (measurable_equiv.pi_fin_succ_above_equiv α i).symm, + suffices : measure_preserving e _ _, from this.symm, + refine ⟨e.measurable, (pi_eq $ λ s hs, _).symm⟩, + rw [e.map_apply, i.prod_univ_succ_above _, ← pi_pi, ← prod_prod], + congr' 1 with ⟨x, f⟩, + simp [i.forall_iff_succ_above] +end + +lemma volume_preserving_pi_fin_succ_above_equiv {n : ℕ} (α : fin (n + 1) → Type u) + [Π i, measure_space (α i)] [∀ i, sigma_finite (volume : measure (α i))] (i : fin (n + 1)) : + measure_preserving (measurable_equiv.pi_fin_succ_above_equiv α i) := +measure_preserving_pi_fin_succ_above_equiv (λ _, volume) i + lemma measure_preserving_fun_unique {β : Type u} {m : measurable_space β} (μ : measure β) (α : Type v) [unique α] : measure_preserving (measurable_equiv.fun_unique α β) (measure.pi (λ a : α, μ)) μ := diff --git a/src/measure_theory/measurable_space.lean b/src/measure_theory/measurable_space.lean index 4d81f0a963572..8e230a3f2a916 100644 --- a/src/measure_theory/measurable_space.lean +++ b/src/measure_theory/measurable_space.lean @@ -1251,6 +1251,29 @@ def pi_measurable_equiv_tprod [decidable_eq δ'] /-- The space `fin 2 → α` is measurably equivalent to `α × α`. -/ @[simps {fully_applied := ff}] def fin_two_arrow : (fin 2 → α) ≃ᵐ α × α := pi_fin_two (λ _, α) +/-- Measurable equivalence between `Π j : fin (n + 1), α j` and +`α i × Π j : fin n, α (fin.succ_above i j)`. -/ +@[simps {fully_applied := ff}] +def pi_fin_succ_above_equiv {n : ℕ} (α : fin (n + 1) → Type*) [Π i, measurable_space (α i)] + (i : fin (n + 1)) : + (Π j, α j) ≃ᵐ α i × (Π j, α (i.succ_above j)) := +{ to_equiv := pi_fin_succ_above_equiv α i, + measurable_to_fun := (measurable_pi_apply i).prod_mk $ measurable_pi_iff.2 $ + λ j, measurable_pi_apply _, + measurable_inv_fun := by simp [measurable_pi_iff, i.forall_iff_succ_above, measurable_fst, + (measurable_pi_apply _).comp measurable_snd] } + +variable (π) + +/-- Measurable equivalence between (dependent) functions on a type and pairs of functions on +`{i // p i}` and `{i // ¬p i}`. See also `equiv.pi_equiv_pi_subtype_prod`. -/ +@[simps {fully_applied := ff}] +def pi_equiv_pi_subtype_prod (p : δ' → Prop) [decidable_pred p] : + (Π i, π i) ≃ᵐ ((Π i : subtype p, π i) × (Π i : {i // ¬p i}, π i)) := +{ to_equiv := pi_equiv_pi_subtype_prod p π, + measurable_to_fun := measurable_pi_equiv_pi_subtype_prod π p, + measurable_inv_fun := measurable_pi_equiv_pi_subtype_prod_symm π p } + end measurable_equiv namespace measurable_embedding diff --git a/src/measure_theory/measure/lebesgue.lean b/src/measure_theory/measure/lebesgue.lean index 395b3658d0efa..ff19fb7c172dd 100644 --- a/src/measure_theory/measure/lebesgue.lean +++ b/src/measure_theory/measure/lebesgue.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Johannes Hölzl, Yury Kudryashov +Authors: Johannes Hölzl, Sébastien Gouëzel, Yury Kudryashov -/ import dynamics.ergodic.measure_preserving import linear_algebra.determinant @@ -296,28 +296,27 @@ begin end /-- A transvection preserves Lebesgue measure. -/ -lemma map_transvection_volume_pi [decidable_eq ι] (t : transvection_struct ι ℝ) : - measure.map (t.to_matrix.to_lin') volume = volume := +lemma volume_preserving_transvection_struct [decidable_eq ι] (t : transvection_struct ι ℝ) : + measure_preserving (t.to_matrix.to_lin') := begin /- We separate the coordinate along which there is a shearing from the other ones, and apply Fubini. Along this coordinate (and when all the other coordinates are fixed), it acts like a translation, and therefore preserves Lebesgue. -/ - suffices H : measure_preserving t.to_matrix.to_lin' volume volume, by exact H.2, let p : ι → Prop := λ i, i ≠ t.i, let α : Type* := {x // p x}, let β : Type* := {x // ¬ (p x)}, let g : (α → ℝ) → (β → ℝ) → (β → ℝ) := λ a b, (λ x, t.c * a ⟨t.j, t.hij.symm⟩) + b, let F : (α → ℝ) × (β → ℝ) → (α → ℝ) × (β → ℝ) := λ p, (id p.1, g p.1 p.2), - let e := equiv.pi_equiv_pi_subtype_prod p (λ (i : ι), ℝ), + let e : (ι → ℝ) ≃ᵐ (α → ℝ) × (β → ℝ) := measurable_equiv.pi_equiv_pi_subtype_prod (λ i : ι, ℝ) p, have : (t.to_matrix.to_lin' : (ι → ℝ) → (ι → ℝ)) = e.symm ∘ F ∘ e, { cases t, ext f k, simp only [linear_equiv.map_smul, dite_eq_ite, linear_map.id_coe, p, ite_not, algebra.id.smul_eq_mul, one_mul, dot_product, std_basis_matrix, - equiv.pi_equiv_pi_subtype_prod_symm_apply, id.def, transvection, + measurable_equiv.pi_equiv_pi_subtype_prod_symm_apply, id.def, transvection, pi.add_apply, zero_mul, linear_map.smul_apply, function.comp_app, - equiv.pi_equiv_pi_subtype_prod_apply, matrix.transvection_struct.to_matrix_mk, + measurable_equiv.pi_equiv_pi_subtype_prod_apply, matrix.transvection_struct.to_matrix_mk, matrix.mul_vec, linear_equiv.map_add, ite_mul, e, matrix.to_lin'_apply, pi.smul_apply, subtype.coe_mk, g, linear_map.add_apply, finset.sum_congr, matrix.to_lin'_one], by_cases h : t_i = k, @@ -325,27 +324,23 @@ begin one_apply, boole_mul, add_comm], }, { simp only [h, ne.symm h, add_zero, if_false, finset.sum_const_zero, false_and, mul_zero] } }, rw this, - have A : measure_preserving e volume volume := - ⟨ measurable_pi_equiv_pi_subtype_prod (λ i, ℝ) _, - (measure.map_pi_equiv_pi_subtype_prod (λ i, (volume : measure ℝ)) p : _) ⟩, - have B : measure_preserving F volume volume, + have A : measure_preserving e, + { convert volume_preserving_pi_equiv_pi_subtype_prod (λ i : ι, ℝ) p }, + have B : measure_preserving F, { have g_meas : measurable (function.uncurry g), { have : measurable (λ (c : (α → ℝ)), c ⟨t.j, t.hij.symm⟩) := measurable_pi_apply ⟨t.j, t.hij.symm⟩, - refine measurable.add (measurable_pi_lambda _ (λ i, measurable.const_mul _ _)) measurable_snd, + refine (measurable_pi_lambda _ (λ i, measurable.const_mul _ _)).add measurable_snd, exact this.comp measurable_fst }, - exact measure_preserving.skew_product (measure_preserving.id _) g_meas + exact (measure_preserving.id _).skew_product g_meas (eventually_of_forall (λ a, map_add_left_eq_self _ _)) }, - have C : measure_preserving e.symm volume volume := - ⟨ (measurable_pi_equiv_pi_subtype_prod_symm (λ (i : ι), ℝ) p : _), - (measure.map_pi_equiv_pi_subtype_prod_symm (λ (i : ι), volume) p : _) ⟩, - exact (C.comp B).comp A, + exact (A.symm.comp B).comp A, end /-- Any invertible matrix rescales Lebesgue measure through the absolute value of its determinant. -/ lemma map_matrix_volume_pi_eq_smul_volume_pi [decidable_eq ι] {M : matrix ι ι ℝ} (hM : det M ≠ 0) : - measure.map (M.to_lin') volume = ennreal.of_real (abs (det M)⁻¹) • volume := + measure.map M.to_lin' volume = ennreal.of_real (abs (det M)⁻¹) • volume := begin -- This follows from the cases we have already proved, of diagonal matrices and transvections, -- as these matrices generate all invertible matrices. @@ -354,8 +349,8 @@ begin { conv_rhs { rw [← smul_map_diagonal_volume_pi hD] }, rw [smul_smul, ← ennreal.of_real_mul (abs_nonneg _), ← abs_mul, inv_mul_cancel hD, abs_one, ennreal.of_real_one, one_smul] }, - { simp only [matrix.transvection_struct.det, ennreal.of_real_one, map_transvection_volume_pi, - one_smul, _root_.inv_one, abs_one] }, + { simp only [matrix.transvection_struct.det, ennreal.of_real_one, + (volume_preserving_transvection_struct _).map_eq, one_smul, _root_.inv_one, abs_one] }, { rw [to_lin'_mul, det_mul, linear_map.coe_comp, ← measure.map_map, IHB, measure.map_smul, IHA, smul_smul, ← ennreal.of_real_mul (abs_nonneg _), ← abs_mul, mul_comm, mul_inv₀], { apply continuous.measurable, From 9631a91350d11015b554ef1c553efc24c13691f9 Mon Sep 17 00:00:00 2001 From: Bolton Bailey Date: Thu, 14 Apr 2022 11:12:38 +0000 Subject: [PATCH 024/373] feat(ring_theory/multiplicity): int.nat_abs (#13420) Spinning off of #12454 --- src/ring_theory/multiplicity.lean | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ring_theory/multiplicity.lean b/src/ring_theory/multiplicity.lean index 5917a2e7fe01c..64b509ce77a60 100644 --- a/src/ring_theory/multiplicity.lean +++ b/src/ring_theory/multiplicity.lean @@ -289,6 +289,13 @@ part.ext' (by simp only [multiplicity, enat.find, dvd_neg]) eq.symm (unique ((dvd_neg _ _).2 (pow_multiplicity_dvd _)) (mt (dvd_neg _ _).1 (is_greatest' _ (lt_succ_self _)))))) +theorem int.nat_abs (a : ℕ) (b : ℤ) : multiplicity a b.nat_abs = multiplicity (a : ℤ) b := +begin + cases int.nat_abs_eq b with h h; conv_rhs { rw h }, + { rw [int.coe_nat_multiplicity], }, + { rw [multiplicity.neg, int.coe_nat_multiplicity], }, +end + lemma multiplicity_add_of_gt {p a b : α} (h : multiplicity p b < multiplicity p a) : multiplicity p (a + b) = multiplicity p b := begin From 936eb7eec6d83b64445274beb55dc351c96d4ae7 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Thu, 14 Apr 2022 11:12:39 +0000 Subject: [PATCH 025/373] feat(analysis/normed_space/finite_dimension): a finite dimensional affine subspace is closed (#13440) --- src/analysis/normed_space/add_torsor.lean | 16 ++++++-- .../normed_space/finite_dimension.lean | 37 +++++++++++++++++-- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/analysis/normed_space/add_torsor.lean b/src/analysis/normed_space/add_torsor.lean index fd7179edb1239..3d57b8dd8422e 100644 --- a/src/analysis/normed_space/add_torsor.lean +++ b/src/analysis/normed_space/add_torsor.lean @@ -6,6 +6,7 @@ Authors: Joseph Myers, Yury Kudryashov import analysis.normed_space.basic import analysis.normed.group.add_torsor import linear_algebra.affine_space.midpoint +import linear_algebra.affine_space.affine_subspace import topology.instances.real_vector_space /-! @@ -21,14 +22,23 @@ open filter variables {α V P : Type*} [semi_normed_group V] [pseudo_metric_space P] [normed_add_torsor V P] variables {W Q : Type*} [normed_group W] [metric_space Q] [normed_add_torsor W Q] -include V - section normed_space variables {𝕜 : Type*} [normed_field 𝕜] [normed_space 𝕜 V] open affine_map +lemma affine_subspace.is_closed_direction_iff [normed_space 𝕜 W] (s : affine_subspace 𝕜 Q) : + is_closed (s.direction : set W) ↔ is_closed (s : set Q) := +begin + rcases s.eq_bot_or_nonempty with rfl|⟨x, hx⟩, { simp [is_closed_singleton] }, + rw [← (isometric.vadd_const x).to_homeomorph.symm.is_closed_image, + affine_subspace.coe_direction_eq_vsub_set_right hx], + refl +end + +include V + @[simp] lemma dist_center_homothety (p₁ p₂ : P) (c : 𝕜) : dist p₁ (homothety p₁ c p₂) = ∥c∥ * dist p₁ p₂ := by simp [homothety_def, norm_smul, ← dist_eq_norm_vsub, dist_comm] @@ -118,7 +128,7 @@ lemma dist_midpoint_midpoint_le (p₁ p₂ p₃ p₄ : V) : dist (midpoint ℝ p₁ p₂) (midpoint ℝ p₃ p₄) ≤ (dist p₁ p₃ + dist p₂ p₄) / 2 := by simpa using dist_midpoint_midpoint_le' p₁ p₂ p₃ p₄ -include W +include V W /-- A continuous map between two normed affine spaces is an affine map provided that it sends midpoints to midpoints. -/ diff --git a/src/analysis/normed_space/finite_dimension.lean b/src/analysis/normed_space/finite_dimension.lean index 6c7207746a1d9..4a3014994f5e7 100644 --- a/src/analysis/normed_space/finite_dimension.lean +++ b/src/analysis/normed_space/finite_dimension.lean @@ -238,11 +238,37 @@ begin rw [basis.equiv_fun_symm_apply, basis.sum_repr] end -theorem affine_map.continuous_of_finite_dimensional {PE PF : Type*} - [metric_space PE] [normed_add_torsor E PE] [metric_space PF] [normed_add_torsor F PF] - [finite_dimensional 𝕜 E] (f : PE →ᵃ[𝕜] PF) : continuous f := +section affine + +variables {PE PF : Type*} [metric_space PE] [normed_add_torsor E PE] [metric_space PF] + [normed_add_torsor F PF] [finite_dimensional 𝕜 E] + +include E F + +theorem affine_map.continuous_of_finite_dimensional (f : PE →ᵃ[𝕜] PF) : continuous f := affine_map.continuous_linear_iff.1 f.linear.continuous_of_finite_dimensional +theorem affine_equiv.continuous_of_finite_dimensional (f : PE ≃ᵃ[𝕜] PF) : continuous f := +f.to_affine_map.continuous_of_finite_dimensional + +/-- Reinterpret an affine equivalence as a homeomorphism. -/ +def affine_equiv.to_homeomorph_of_finite_dimensional (f : PE ≃ᵃ[𝕜] PF) : PE ≃ₜ PF := +{ to_equiv := f.to_equiv, + continuous_to_fun := f.continuous_of_finite_dimensional, + continuous_inv_fun := + begin + haveI : finite_dimensional 𝕜 F, from f.linear.finite_dimensional, + exact f.symm.continuous_of_finite_dimensional + end } + +@[simp] lemma affine_equiv.coe_to_homeomorph_of_finite_dimensional (f : PE ≃ᵃ[𝕜] PF) : + ⇑f.to_homeomorph_of_finite_dimensional = f := rfl + +@[simp] lemma affine_equiv.coe_to_homeomorph_of_finite_dimensional_symm (f : PE ≃ᵃ[𝕜] PF) : + ⇑f.to_homeomorph_of_finite_dimensional.symm = f.symm := rfl + +end affine + lemma continuous_linear_map.continuous_det : continuous (λ (f : E →L[𝕜] E), f.det) := begin @@ -593,6 +619,11 @@ lemma submodule.closed_of_finite_dimensional (s : submodule 𝕜 E) [finite_dime is_closed (s : set E) := s.complete_of_finite_dimensional.is_closed +lemma affine_subspace.closed_of_finite_dimensional {P : Type*} [metric_space P] + [normed_add_torsor E P] (s : affine_subspace 𝕜 P) [finite_dimensional 𝕜 s.direction] : + is_closed (s : set P) := +s.is_closed_direction_iff.mp s.direction.closed_of_finite_dimensional + section riesz /-- In an infinite dimensional space, given a finite number of points, one may find a point From adfe9c7fc6e377377776d72f3d45bebecf66af2a Mon Sep 17 00:00:00 2001 From: Floris van Doorn Date: Thu, 14 Apr 2022 13:04:58 +0000 Subject: [PATCH 026/373] feat(topology/algebra/order/compact): Sup is continuous (#13347) * Prove that the `Sup` of a binary function over a compact set is continuous in the second variable * Some other lemmas about `Sup` * Move and generalize `is_compact.bdd_[above|below]_image` * from the sphere eversion project --- src/topology/algebra/order/basic.lean | 12 ++++ src/topology/algebra/order/compact.lean | 74 ++++++++++++++++++++----- 2 files changed, 72 insertions(+), 14 deletions(-) diff --git a/src/topology/algebra/order/basic.lean b/src/topology/algebra/order/basic.lean index 80ec1e3f155ef..64608f0e67d8f 100644 --- a/src/topology/algebra/order/basic.lean +++ b/src/topology/algebra/order/basic.lean @@ -2188,6 +2188,18 @@ lemma is_compact.bdd_above {α : Type u} [topological_space α] [linear_order α [order_closed_topology α] : Π [nonempty α] {s : set α}, is_compact s → bdd_above s := @is_compact.bdd_below (order_dual α) _ _ _ +/-- A continuous function is bounded below on a compact set. -/ +lemma is_compact.bdd_below_image {α : Type u} [topological_space α] [linear_order α] + [order_closed_topology α] [nonempty α] [topological_space γ] {f : γ → α} {K : set γ} + (hK : is_compact K) (hf : continuous_on f K) : bdd_below (f '' K) := +(hK.image_of_continuous_on hf).bdd_below + +/-- A continuous function is bounded above on a compact set. -/ +lemma is_compact.bdd_above_image {α : Type u} [topological_space α] [linear_order α] + [order_closed_topology α] [nonempty α] [topological_space γ] {f : γ → α} {K : set γ} + (hK : is_compact K) (hf : continuous_on f K) : bdd_above (f '' K) := +@is_compact.bdd_below_image _ (order_dual α) _ _ _ _ _ _ _ hK hf + end order_topology section densely_ordered diff --git a/src/topology/algebra/order/compact.lean b/src/topology/algebra/order/compact.lean index baf74787b18f2..95a4b8238fb59 100644 --- a/src/topology/algebra/order/compact.lean +++ b/src/topology/algebra/order/compact.lean @@ -132,8 +132,8 @@ end ### Min and max elements of a compact set -/ -variables {α β : Type*} [conditionally_complete_linear_order α] [topological_space α] - [order_topology α] [topological_space β] +variables {α β γ : Type*} [conditionally_complete_linear_order α] [topological_space α] + [order_topology α] [topological_space β] [topological_space γ] lemma is_compact.Inf_mem {s : set α} (hs : is_compact s) (ne_s : s.nonempty) : Inf s ∈ s := @@ -175,11 +175,22 @@ lemma is_compact.exists_is_lub {s : set α} (hs : is_compact s) (ne_s : s.nonemp ∃ x ∈ s, is_lub s x := ⟨_, hs.Sup_mem ne_s, hs.is_lub_Sup ne_s⟩ +lemma is_compact.exists_Inf_image_eq_and_le {s : set β} (hs : is_compact s) (ne_s : s.nonempty) + {f : β → α} (hf : continuous_on f s) : + ∃ x ∈ s, Inf (f '' s) = f x ∧ ∀ y ∈ s, f x ≤ f y := +let ⟨x, hxs, hx⟩ := (hs.image_of_continuous_on hf).Inf_mem (ne_s.image f) +in ⟨x, hxs, hx.symm, λ y hy, + hx.trans_le $ cInf_le (hs.image_of_continuous_on hf).bdd_below $ mem_image_of_mem f hy⟩ + +lemma is_compact.exists_Sup_image_eq_and_ge {s : set β} (hs : is_compact s) (ne_s : s.nonempty) + {f : β → α} (hf : continuous_on f s) : + ∃ x ∈ s, Sup (f '' s) = f x ∧ ∀ y ∈ s, f y ≤ f x := +@is_compact.exists_Inf_image_eq_and_le (order_dual α) _ _ _ _ _ _ hs ne_s _ hf + lemma is_compact.exists_Inf_image_eq {s : set β} (hs : is_compact s) (ne_s : s.nonempty) {f : β → α} (hf : continuous_on f s) : ∃ x ∈ s, Inf (f '' s) = f x := -let ⟨x, hxs, hx⟩ := (hs.image_of_continuous_on hf).Inf_mem (ne_s.image f) -in ⟨x, hxs, hx.symm⟩ +let ⟨x, hxs, hx, _⟩ := hs.exists_Inf_image_eq_and_le ne_s hf in ⟨x, hxs, hx⟩ lemma is_compact.exists_Sup_image_eq : ∀ {s : set β}, is_compact s → s.nonempty → ∀ {f : β → α}, continuous_on f s → @@ -245,6 +256,23 @@ lemma continuous.exists_forall_ge [nonempty β] {f : β → α} ∃ x, ∀ y, f y ≤ f x := @continuous.exists_forall_le (order_dual α) _ _ _ _ _ _ _ hf hlim +lemma is_compact.Sup_lt_iff_of_continuous {f : β → α} + {K : set β} (hK : is_compact K) (h0K : K.nonempty) (hf : continuous_on f K) (y : α) : + Sup (f '' K) < y ↔ ∀ x ∈ K, f x < y := +begin + refine ⟨λ h x hx, (le_cSup (hK.bdd_above_image hf) $ mem_image_of_mem f hx).trans_lt h, λ h, _⟩, + obtain ⟨x, hx, h2x⟩ := hK.exists_forall_ge h0K hf, + refine (cSup_le (h0K.image f) _).trans_lt (h x hx), + rintro _ ⟨x', hx', rfl⟩, exact h2x x' hx' +end + +lemma is_compact.lt_Inf_iff_of_continuous {α β : Type*} + [conditionally_complete_linear_order α] [topological_space α] + [order_topology α] [topological_space β] {f : β → α} + {K : set β} (hK : is_compact K) (h0K : K.nonempty) (hf : continuous_on f K) (y : α) : + y < Inf (f '' K) ↔ ∀ x ∈ K, y < f x := +@is_compact.Sup_lt_iff_of_continuous (order_dual α) β _ _ _ _ _ _ hK h0K hf y + /-- A continuous function with compact support has a global minimum. -/ @[to_additive] lemma _root_.continuous.exists_forall_le_of_has_compact_mul_support [nonempty β] [has_one α] @@ -285,19 +313,37 @@ lemma continuous.bdd_above_range_of_has_compact_mul_support [has_one α] bdd_above (range f) := @continuous.bdd_below_range_of_has_compact_mul_support (order_dual α) _ _ _ _ _ _ _ hf h -/-- A continuous function is bounded below on a compact set. -/ -lemma is_compact.bdd_below_image {f : β → α} {K : set β} - (hK : is_compact K) (hf : continuous_on f K) : bdd_below (f '' K) := +lemma is_compact.continuous_Sup {f : γ → β → α} + {K : set β} (hK : is_compact K) (hf : continuous ↿f) : + continuous (λ x, Sup (f x '' K)) := begin - rcases eq_empty_or_nonempty K with rfl|h, { rw [image_empty], exact bdd_below_empty }, - obtain ⟨c, -, hc⟩ := hK.exists_forall_le h hf, - refine ⟨f c, _⟩, rintro _ ⟨x, hx, rfl⟩, exact hc x hx + rcases eq_empty_or_nonempty K with rfl|h0K, + { simp_rw [image_empty], exact continuous_const }, + rw [continuous_iff_continuous_at], + intro x, + obtain ⟨y, hyK, h2y, hy⟩ := + hK.exists_Sup_image_eq_and_ge h0K + (show continuous (λ y, f x y), from hf.comp $ continuous.prod.mk x).continuous_on, + rw [continuous_at, h2y, tendsto_order], + have := tendsto_order.mp ((show continuous (λ x, f x y), from + hf.comp $ continuous_id.prod_mk continuous_const).tendsto x), + refine ⟨λ z hz, _, λ z hz, _⟩, + { refine (this.1 z hz).mono (λ x' hx', hx'.trans_le $ le_cSup _ $ mem_image_of_mem (f x') hyK), + exact hK.bdd_above_image (hf.comp $ continuous.prod.mk x').continuous_on }, + { have h : ({x} : set γ) ×ˢ K ⊆ ↿f ⁻¹' (Iio z), + { rintro ⟨x', y'⟩ ⟨hx', hy'⟩, cases hx', exact (hy y' hy').trans_lt hz }, + obtain ⟨u, v, hu, hv, hxu, hKv, huv⟩ := + generalized_tube_lemma is_compact_singleton hK (is_open_Iio.preimage hf) h, + refine eventually_of_mem (hu.mem_nhds (singleton_subset_iff.mp hxu)) (λ x' hx', _), + rw [hK.Sup_lt_iff_of_continuous h0K + (show continuous (f x'), from (hf.comp $ continuous.prod.mk x')).continuous_on], + exact λ y' hy', huv (mk_mem_prod hx' (hKv hy')) } end -/-- A continuous function is bounded above on a compact set. -/ -lemma is_compact.bdd_above_image {f : β → α} {K : set β} - (hK : is_compact K) (hf : continuous_on f K) : bdd_above (f '' K) := -@is_compact.bdd_below_image (order_dual α) _ _ _ _ _ _ _ hK hf +lemma is_compact.continuous_Inf {f : γ → β → α} + {K : set β} (hK : is_compact K) (hf : continuous ↿f) : + continuous (λ x, Inf (f x '' K)) := +@is_compact.continuous_Sup (order_dual α) β γ _ _ _ _ _ _ _ hK hf namespace continuous_on /-! From fecdd4b2008feb7e5fe584821227547367dd30ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Thu, 14 Apr 2022 14:09:05 +0000 Subject: [PATCH 027/373] feat(measure_theory/card_measurable_space): `generate_measurable_rec s` gives precisely the generated sigma-algebra (#12462) Co-authored-by: sgouezel --- src/measure_theory/card_measurable_space.lean | 174 ++++++++++-------- src/set_theory/cardinal_ordinal.lean | 3 + 2 files changed, 104 insertions(+), 73 deletions(-) diff --git a/src/measure_theory/card_measurable_space.lean b/src/measure_theory/card_measurable_space.lean index dafc5d432d5db..2cd06e1192312 100644 --- a/src/measure_theory/card_measurable_space.lean +++ b/src/measure_theory/card_measurable_space.lean @@ -20,7 +20,8 @@ In particular, if `#s ≤ 𝔠`, then the generated sigma-algebra has cardinalit For the proof, we rely on an explicit inductive construction of the sigma-algebra generated by `s` (instead of the inductive predicate `generate_measurable`). This transfinite inductive construction is parameterized by an ordinal `< ω₁`, and the cardinality bound is preserved along -each step of the construction. +each step of the construction. We show in `measurable_space.generate_measurable_eq_rec` that this +indeed generates this sigma-algebra. -/ universe u @@ -29,21 +30,61 @@ variables {α : Type u} open_locale cardinal open cardinal set -local notation `ω₁`:= (aleph 1 : cardinal.{u}).ord.out.α +local notation `ω₁` := (aleph 1 : cardinal.{u}).ord.out.α namespace measurable_space /-- Transfinite induction construction of the sigma-algebra generated by a set of sets `s`. At each step, we add all elements of `s`, the empty set, the complements of already constructed sets, and countable unions of already constructed sets. We index this construction by an ordinal `< ω₁`, as -this will be enough to generate all sets in the sigma-algebra. -/ +this will be enough to generate all sets in the sigma-algebra. + +This construction is very similar to that of the Borel hierarchy. -/ def generate_measurable_rec (s : set (set α)) : ω₁ → set (set α) | i := let S := ⋃ j : {j // j < i}, generate_measurable_rec j.1 in - s ∪ {∅} ∪ compl '' S ∪ (set.range (λ (f : ℕ → S), ⋃ n, (f n).1)) + s ∪ {∅} ∪ compl '' S ∪ set.range (λ (f : ℕ → S), ⋃ n, (f n).1) using_well_founded {dec_tac := `[exact j.2]} -/-- At each step of the inductive construction, the cardinality bound `≤ (max (#s) 2) ^ ω` -holds. -/ +theorem self_subset_generate_measurable_rec (s : set (set α)) (i : ω₁) : + s ⊆ generate_measurable_rec s i := +begin + unfold generate_measurable_rec, + apply_rules [subset_union_of_subset_left], + exact subset_rfl +end + +theorem empty_mem_generate_measurable_rec (s : set (set α)) (i : ω₁) : + ∅ ∈ generate_measurable_rec s i := +begin + unfold generate_measurable_rec, + exact mem_union_left _ (mem_union_left _ (mem_union_right _ (mem_singleton ∅))) +end + +theorem compl_mem_generate_measurable_rec {s : set (set α)} {i j : ω₁} (h : j < i) {t : set α} + (ht : t ∈ generate_measurable_rec s j) : tᶜ ∈ generate_measurable_rec s i := +begin + unfold generate_measurable_rec, + exact mem_union_left _ (mem_union_right _ ⟨t, mem_Union.2 ⟨⟨j, h⟩, ht⟩, rfl⟩) +end + +theorem Union_mem_generate_measurable_rec {s : set (set α)} {i : ω₁} + {f : ℕ → set α} (hf : ∀ n, ∃ j < i, f n ∈ generate_measurable_rec s j) : + (⋃ n, f n) ∈ generate_measurable_rec s i := +begin + unfold generate_measurable_rec, + exact mem_union_right _ ⟨λ n, ⟨f n, let ⟨j, hj, hf⟩ := hf n in mem_Union.2 ⟨⟨j, hj⟩, hf⟩⟩, rfl⟩ +end + +theorem generate_measurable_rec_subset (s : set (set α)) {i j : ω₁} (h : i ≤ j) : + generate_measurable_rec s i ⊆ generate_measurable_rec s j := +λ x hx, begin + rcases eq_or_lt_of_le h with rfl | h, + { exact hx }, + { convert Union_mem_generate_measurable_rec (λ n, ⟨i, h, hx⟩), + exact (Union_const x).symm } +end + +/-- At each step of the inductive construction, the cardinality bound `≤ (max (#s) 2) ^ ω` holds. -/ lemma cardinal_generate_measurable_rec_le (s : set (set α)) (i : ω₁) : #(generate_measurable_rec s i) ≤ (max (#s) 2) ^ omega.{u} := begin @@ -52,14 +93,12 @@ begin have A := omega_le_aleph 1, have B : aleph 1 ≤ (max (#s) 2) ^ omega.{u} := aleph_one_le_continuum.trans (power_le_power_right (le_max_right _ _)), - have C : omega.{u} ≤ (max (#s) 2) ^ omega.{u} := A.trans B, + have C : ω ≤ (max (#s) 2) ^ omega.{u} := A.trans B, have J : #(⋃ (j : {j // j < i}), generate_measurable_rec s j.1) ≤ (max (#s) 2) ^ omega.{u}, { apply (mk_Union_le _).trans, - have D : # {j // j < i} ≤ aleph 1 := (mk_subtype_le _).trans (le_of_eq (aleph 1).mk_ord_out), - have E : cardinal.sup.{u u} - (λ (j : {j // j < i}), #(generate_measurable_rec s j.1)) ≤ (max (#s) 2) ^ omega.{u} := - cardinal.sup_le (λ ⟨j, hj⟩, IH j hj), - apply (mul_le_mul' D E).trans, + have D : cardinal.sup.{u u} (λ (j : {j // j < i}), #(generate_measurable_rec s j.1)) ≤ _ := + cardinal.sup_le (λ ⟨j, hj⟩, IH j hj), + apply (mul_le_mul' ((mk_subtype_le _).trans (aleph 1).mk_ord_out.le) D).trans, rw mul_eq_max A C, exact max_le B le_rfl }, rw [generate_measurable_rec], @@ -69,15 +108,54 @@ begin exact one_lt_omega.le.trans C }, { apply mk_range_le.trans, simp only [mk_pi, subtype.val_eq_coe, prod_const, lift_uzero, mk_denumerable, lift_omega], - have := @power_le_power_right _ _ omega.{u} J, + have := @power_le_power_right _ _ ω J, rwa [← power_mul, omega_mul_omega] at this } end -lemma cardinal_Union_generate_measurable_rec_le (s : set (set α)) : - #(⋃ i, generate_measurable_rec s i) ≤ (max (#s) 2) ^ omega.{u} := +/-- `generate_measurable_rec s` generates precisely the smallest sigma-algebra containing `s`. -/ +theorem generate_measurable_eq_rec (s : set (set α)) : + {t | generate_measurable s t} = ⋃ i, generate_measurable_rec s i := begin + ext t, refine ⟨λ ht, _, λ ht, _⟩, + { inhabit ω₁, + induction ht with u hu u hu IH f hf IH, + { exact mem_Union.2 ⟨default, self_subset_generate_measurable_rec s _ hu⟩ }, + { exact mem_Union.2 ⟨default, empty_mem_generate_measurable_rec s _⟩ }, + { rcases mem_Union.1 IH with ⟨i, hi⟩, + obtain ⟨j, hj⟩ := exists_gt i, + exact mem_Union.2 ⟨j, compl_mem_generate_measurable_rec hj hi⟩ }, + { have : ∀ n, ∃ i, f n ∈ generate_measurable_rec s i := λ n, by simpa using IH n, + choose I hI using this, + refine mem_Union.2 ⟨ordinal.enum (<) (ordinal.lsub (λ n, ordinal.typein.{u} (<) (I n))) _, + Union_mem_generate_measurable_rec (λ n, ⟨I n, _, hI n⟩)⟩, + { rw ordinal.type_lt, + refine ordinal.lsub_lt_ord_lift _ (λ i, ordinal.typein_lt_self _), + rw [mk_denumerable, lift_omega, is_regular_aleph_one.2], + exact omega_lt_aleph_one }, + { rw [←ordinal.typein_lt_typein (<), ordinal.typein_enum], + apply ordinal.lt_lsub (λ n : ℕ, _) } } }, + { rcases ht with ⟨t, ⟨i, rfl⟩, hx⟩, + revert t, + apply (aleph 1).ord.out.wo.wf.induction i, + intros j H t ht, + unfold generate_measurable_rec at ht, + rcases ht with (((h | h) | ⟨u, ⟨-, ⟨⟨k, hk⟩, rfl⟩, hu⟩, rfl⟩) | ⟨f, rfl⟩), + { exact generate_measurable.basic t h }, + { convert generate_measurable.empty }, + { exact generate_measurable.compl u (H k hk u hu) }, + { apply generate_measurable.union _ (λ n, _), + obtain ⟨-, ⟨⟨k, hk⟩, rfl⟩, hf⟩ := (f n).prop, + exact H k hk _ hf } } +end + +/-- If a sigma-algebra is generated by a set of sets `s`, then the sigma-algebra has cardinality at +most `(max (#s) 2) ^ ω`. -/ +theorem cardinal_generate_measurable_le (s : set (set α)) : + #{t | generate_measurable s t} ≤ (max (#s) 2) ^ omega.{u} := +begin + rw generate_measurable_eq_rec, apply (mk_Union_le _).trans, - rw [(aleph 1).mk_ord_out], + rw (aleph 1).mk_ord_out, refine le_trans (mul_le_mul' aleph_one_le_continuum (cardinal.sup_le (λ i, cardinal_generate_measurable_rec_le s i))) _, have := power_le_power_right (le_max_right (#s) 2), @@ -85,54 +163,6 @@ begin exact max_le this le_rfl end -/-- A set in the sigma-algebra generated by a set of sets `s` is constructed at some step of the -transfinite induction defining `generate_measurable_rec`. -The other inclusion is also true, but not proved here as it is not needed for the cardinality -bounds.-/ -theorem generate_measurable_subset_rec (s : set (set α)) ⦃t : set α⦄ - (ht : generate_measurable s t) : - t ∈ ⋃ i, generate_measurable_rec s i := -begin - inhabit ω₁, - induction ht with u hu u hu IH f hf IH, - { refine mem_Union.2 ⟨default, _⟩, - rw generate_measurable_rec, - simp only [hu, mem_union_eq, true_or] }, - { refine mem_Union.2 ⟨default, _⟩, - rw generate_measurable_rec, - simp only [union_singleton, mem_union_eq, mem_insert_iff, eq_self_iff_true, true_or] }, - { rcases mem_Union.1 IH with ⟨i, hi⟩, - obtain ⟨j, hj⟩ : ∃ j, i < j := ordinal.has_succ_of_type_succ_lt - (by { rw ordinal.type_lt, exact (ord_aleph_is_limit 1).2 }) _, - apply mem_Union.2 ⟨j, _⟩, - rw generate_measurable_rec, - have : ∃ a, (a < j) ∧ u ∈ generate_measurable_rec s a := ⟨i, hj, hi⟩, - simp [this] }, - { have : ∀ n, ∃ i, f n ∈ generate_measurable_rec s i := λ n, by simpa using IH n, - choose I hI using this, - obtain ⟨j, hj⟩ : ∃ j, ∀ k, k ∈ range I → (k < j), - { apply ordinal.lt_cof_type, - simp only [is_regular_aleph_one.2, mk_singleton, ordinal.type_lt], - have : #(range I) = lift.{0} (#(range I)), by simp only [lift_uzero], - rw this, - apply mk_range_le_lift.trans_lt _, - simp [omega_lt_aleph_one] }, - apply mem_Union.2 ⟨j, _⟩, - rw generate_measurable_rec, - have : ∃ (g : ℕ → (↥⋃ (i : {i // i < j}), generate_measurable_rec s i.1)), - (⋃ (n : ℕ), ↑(g n)) = (⋃ n, f n), - { refine ⟨λ n, ⟨f n, _⟩, rfl⟩, - exact mem_Union.2 ⟨⟨I n, hj (I n) (mem_range_self _)⟩, hI n⟩ }, - simp [this] } -end - -/-- If a sigma-algebra is generated by a set of sets `s`, then the sigma -algebra has cardinality at most `(max (#s) 2) ^ ω`. -/ -theorem cardinal_generate_measurable_le (s : set (set α)) : - #{t | generate_measurable s t} ≤ (max (#s) 2) ^ omega.{u} := -(mk_subtype_le_of_subset (generate_measurable_subset_rec s)).trans - (cardinal_Union_generate_measurable_rec_le s) - /-- If a sigma-algebra is generated by a set of sets `s`, then the sigma algebra has cardinality at most `(max (#s) 2) ^ ω`. -/ theorem cardinal_measurable_set_le (s : set (set α)) : @@ -143,17 +173,15 @@ cardinal_generate_measurable_le s then the sigma algebra has the same cardinality bound. -/ theorem cardinal_generate_measurable_le_continuum {s : set (set α)} (hs : #s ≤ 𝔠) : #{t | generate_measurable s t} ≤ 𝔠 := -calc -#{t | generate_measurable s t} - ≤ (max (#s) 2) ^ omega.{u} : cardinal_generate_measurable_le s -... ≤ 𝔠 ^ omega.{u} : - by exact_mod_cast power_le_power_right (max_le hs (nat_lt_continuum 2).le) -... = 𝔠 : continuum_power_omega +(cardinal_generate_measurable_le s).trans begin + rw ←continuum_power_omega, + exact_mod_cast power_le_power_right (max_le hs (nat_lt_continuum 2).le) +end /-- If a sigma-algebra is generated by a set of sets `s` with cardinality at most the continuum, then the sigma algebra has the same cardinality bound. -/ -theorem cardinal_measurable_set_le_continuum {s : set (set α)} (hs : #s ≤ 𝔠) : - #{t | @measurable_set α (generate_from s) t} ≤ 𝔠 := -cardinal_generate_measurable_le_continuum hs +theorem cardinal_measurable_set_le_continuum {s : set (set α)} : + #s ≤ 𝔠 → #{t | @measurable_set α (generate_from s) t} ≤ 𝔠 := +cardinal_generate_measurable_le_continuum end measurable_space diff --git a/src/set_theory/cardinal_ordinal.lean b/src/set_theory/cardinal_ordinal.lean index 0a87039e7e20a..f308dc381a89d 100644 --- a/src/set_theory/cardinal_ordinal.lean +++ b/src/set_theory/cardinal_ordinal.lean @@ -229,6 +229,9 @@ end theorem ord_aleph_is_limit (o : ordinal) : is_limit (aleph o).ord := ord_is_limit $ omega_le_aleph _ +instance (o : ordinal) : no_max_order (aleph o).ord.out.α := +ordinal.out_no_max_of_succ_lt (ord_aleph_is_limit o).2 + theorem exists_aleph {c : cardinal} : ω ≤ c ↔ ∃ o, c = aleph o := ⟨λ h, ⟨aleph_idx c - ordinal.omega, by rw [aleph, ordinal.add_sub_cancel_of_le, aleph'_aleph_idx]; From 8bbc5ac4435372b888eeae07255e3e3a7226b0c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Thu, 14 Apr 2022 15:31:40 +0000 Subject: [PATCH 028/373] feat(combinatorics/additive/salem_spencer): Salem-Spencer sets under images (#13279) A set `s` is Salem-Spencer iff its image under an injective Freiman hom is. --- src/algebra/big_operators/multiset.lean | 4 ++ src/algebra/hom/freiman.lean | 11 +++- src/combinatorics/additive/salem_spencer.lean | 64 ++++++++++++++----- src/data/multiset/basic.lean | 3 + 4 files changed, 64 insertions(+), 18 deletions(-) diff --git a/src/algebra/big_operators/multiset.lean b/src/algebra/big_operators/multiset.lean index 42c7186b54625..e9a011c13650e 100644 --- a/src/algebra/big_operators/multiset.lean +++ b/src/algebra/big_operators/multiset.lean @@ -58,6 +58,10 @@ lemma prod_cons (a : α) (s) : prod (a ::ₘ s) = a * prod s := foldr_cons _ _ _ lemma prod_singleton (a : α) : prod {a} = a := by simp only [mul_one, prod_cons, singleton_eq_cons, eq_self_iff_true, prod_zero] +@[to_additive] +lemma prod_pair (a b : α) : ({a, b} : multiset α).prod = a * b := +by rw [insert_eq_cons, prod_cons, prod_singleton] + @[simp, to_additive] lemma prod_add (s t : multiset α) : prod (s + t) = prod s * prod t := quotient.induction_on₂ s t $ λ l₁ l₂, by simp diff --git a/src/algebra/hom/freiman.lean b/src/algebra/hom/freiman.lean index f1448f26179a3..8a68912793ea7 100644 --- a/src/algebra/hom/freiman.lean +++ b/src/algebra/hom/freiman.lean @@ -92,7 +92,7 @@ variables [fun_like F α (λ _, β)] section comm_monoid variables [comm_monoid α] [comm_monoid β] [comm_monoid γ] [comm_monoid δ] [comm_group G] {A : set α} - {B : set β} {C : set γ} {n : ℕ} + {B : set β} {C : set γ} {n : ℕ} {a b c d : α} @[to_additive] lemma map_prod_eq_map_prod [freiman_hom_class F A β n] (f : F) {s t : multiset α} @@ -101,6 +101,15 @@ lemma map_prod_eq_map_prod [freiman_hom_class F A β n] (f : F) {s t : multiset (s.map f).prod = (t.map f).prod := freiman_hom_class.map_prod_eq_map_prod' f hsA htA hs ht h +@[to_additive] +lemma map_mul_map_eq_map_mul_map [freiman_hom_class F A β 2] (f : F) (ha : a ∈ A) (hb : b ∈ A) + (hc : c ∈ A) (hd : d ∈ A) (h : a * b = c * d) : + f a * f b = f c * f d := +begin + simp_rw ←prod_pair at ⊢ h, + refine map_prod_eq_map_prod f _ _ (card_pair _ _) (card_pair _ _) h; simp [ha, hb, hc, hd], +end + namespace freiman_hom @[to_additive] diff --git a/src/combinatorics/additive/salem_spencer.lean b/src/combinatorics/additive/salem_spencer.lean index 6edea1f2cd34c..4a86aae85b7b3 100644 --- a/src/combinatorics/additive/salem_spencer.lean +++ b/src/combinatorics/additive/salem_spencer.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Yaël Dillies, Bhavik Mehta. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies, Bhavik Mehta -/ +import algebra.hom.freiman import analysis.asymptotics.asymptotics import analysis.convex.strict_convex_space @@ -29,18 +30,23 @@ the size of the biggest Salem-Spencer subset of `{0, ..., n - 1}`. ## TODO -Can `add_salem_spencer_iff_eq_right` be made more general? +* Can `add_salem_spencer_iff_eq_right` be made more general? +* Generalize `mul_salem_spencer.image` to Freiman homs ## Tags Salem-Spencer, Roth, arithmetic progression, average, three-free -/ -open finset metric nat +open finset function metric nat +open_locale pointwise -variables {α β 𝕜 E : Type*} +variables {F α β 𝕜 E : Type*} section salem_spencer + +open set + section monoid variables [monoid α] [monoid β] (s t : set α) @@ -72,9 +78,9 @@ lemma set.subsingleton.mul_salem_spencer (hs : s.subsingleton) : mul_salem_spenc @[simp, to_additive] lemma mul_salem_spencer_singleton (a : α) : mul_salem_spencer ({a} : set α) := -set.subsingleton_singleton.mul_salem_spencer +subsingleton_singleton.mul_salem_spencer -@[to_additive] +@[to_additive add_salem_spencer.prod] lemma mul_salem_spencer.prod {t : set β} (hs : mul_salem_spencer s) (ht : mul_salem_spencer t) : mul_salem_spencer (s ×ˢ t) := λ a b c ha hb hc h, @@ -83,11 +89,33 @@ lemma mul_salem_spencer.prod {t : set β} (hs : mul_salem_spencer s) (ht : mul_s @[to_additive] lemma mul_salem_spencer_pi {ι : Type*} {α : ι → Type*} [Π i, monoid (α i)] {s : Π i, set (α i)} (hs : ∀ i, mul_salem_spencer (s i)) : - mul_salem_spencer ((set.univ : set ι).pi s) := + mul_salem_spencer ((univ : set ι).pi s) := λ a b c ha hb hc h, funext $ λ i, hs i (ha i trivial) (hb i trivial) (hc i trivial) $ congr_fun h i end monoid +section comm_monoid +variables [comm_monoid α] [comm_monoid β] {s : set α} {a : α} + +@[to_additive] +lemma mul_salem_spencer.of_image [fun_like F α (λ _, β)] [freiman_hom_class F s β 2] (f : F) + (hf : s.inj_on f) (h : mul_salem_spencer (f '' s)) : + mul_salem_spencer s := +λ a b c ha hb hc habc, hf ha hb $ h (mem_image_of_mem _ ha) (mem_image_of_mem _ hb) + (mem_image_of_mem _ hc) $ map_mul_map_eq_map_mul_map f ha hb hc hc habc + +-- TODO: Generalize to Freiman homs +@[to_additive] +lemma mul_salem_spencer.image [mul_hom_class F α β] (f : F) (hf : (s * s).inj_on f) + (h : mul_salem_spencer s) : + mul_salem_spencer (f '' s) := +begin + rintro _ _ _ ⟨a, ha, rfl⟩ ⟨b, hb, rfl⟩ ⟨c, hc, rfl⟩ habc, + rw h ha hb hc (hf (mul_mem_mul ha hb) (mul_mem_mul hc hc) $ by rwa [map_mul, map_mul]), +end + +end comm_monoid + section cancel_comm_monoid variables [cancel_comm_monoid α] {s : set α} {a : α} @@ -97,11 +125,11 @@ lemma mul_salem_spencer_insert : (∀ ⦃b c⦄, b ∈ s → c ∈ s → a * b = c * c → a = b) ∧ ∀ ⦃b c⦄, b ∈ s → c ∈ s → b * c = a * a → b = c := begin - refine ⟨λ hs, ⟨hs.mono (set.subset_insert _ _), + refine ⟨λ hs, ⟨hs.mono (subset_insert _ _), λ b c hb hc, hs (or.inl rfl) (or.inr hb) (or.inr hc), λ b c hb hc, hs (or.inr hb) (or.inr hc) (or.inl rfl)⟩, _⟩, rintro ⟨hs, ha, ha'⟩ b c d hb hc hd h, - rw set.mem_insert_iff at hb hc hd, + rw mem_insert_iff at hb hc hd, obtain rfl | hb := hb; obtain rfl | hc := hc, { refl }, @@ -143,8 +171,8 @@ end @[to_additive] lemma mul_salem_spencer_mul_left_iff : mul_salem_spencer ((*) a '' s) ↔ mul_salem_spencer s := -⟨λ hs b c d hb hc hd h, mul_left_cancel (hs (set.mem_image_of_mem _ hb) (set.mem_image_of_mem _ hc) - (set.mem_image_of_mem _ hd) $ by rw [mul_mul_mul_comm, h, mul_mul_mul_comm]), +⟨λ hs b c d hb hc hd h, mul_left_cancel (hs (mem_image_of_mem _ hb) (mem_image_of_mem _ hc) + (mem_image_of_mem _ hd) $ by rw [mul_mul_mul_comm, h, mul_mul_mul_comm]), mul_salem_spencer.mul_left⟩ @[to_additive] @@ -247,6 +275,8 @@ end end salem_spencer +open finset + section roth_number variables [decidable_eq α] @@ -256,7 +286,7 @@ variables [monoid α] [decidable_eq β] [monoid β] (s t : finset α) /-- The multiplicative Roth number of a finset is the cardinality of its biggest multiplicative Salem-Spencer subset. -/ @[to_additive "The additive Roth number of a finset is the cardinality of its biggest additive -Salem-Spencer subset. The usual Roth number corresponds to `roth_number (finset.range n)`, see +Salem-Spencer subset. The usual Roth number corresponds to `add_roth_number (finset.range n)`, see `roth_number_nat`. "] def mul_roth_number : finset α →o ℕ := ⟨λ s, nat.find_greatest (λ m, ∃ t ⊆ s, t.card = m ∧ mul_salem_spencer (t : set α)) s.card, @@ -372,11 +402,11 @@ variables {s : finset ℕ} {k n : ℕ} /-- The Roth number of a natural `N` is the largest integer `m` for which there is a subset of `range N` of size `m` with no arithmetic progression of length 3. -Trivially, `roth_number N ≤ N`, but Roth's theorem (proved in 1953) shows that -`roth_number N = o(N)` and the construction by Behrend gives a lower bound of the form -`N * exp(-C sqrt(log(N))) ≤ roth_number N`. +Trivially, `roth_number_nat N ≤ N`, but Roth's theorem (proved in 1953) shows that +`roth_number_nat N = o(N)` and the construction by Behrend gives a lower bound of the form +`N * exp(-C sqrt(log(N))) ≤ roth_number_nat N`. A significant refinement of Roth's theorem by Bloom and Sisask announced in 2020 gives -`roth_number N = O(N / (log N)^(1+c))` for an absolute constant `c`. -/ +`roth_number_nat N = O(N / (log N)^(1+c))` for an absolute constant `c`. -/ def roth_number_nat : ℕ →o ℕ := ⟨λ n, add_roth_number (range n), add_roth_number.mono.comp range_mono⟩ @@ -397,7 +427,7 @@ lemma add_salem_spencer.le_roth_number_nat (s : finset ℕ) (hs : add_salem_spen hsk.ge.trans $ hs.le_add_roth_number $ λ x hx, mem_range.2 $ hsn x hx /-- The Roth number is a subadditive function. Note that by Fekete's lemma this shows that -the limit `roth_number N / N` exists, but Roth's theorem gives the stronger result that this +the limit `roth_number_nat N / N` exists, but Roth's theorem gives the stronger result that this limit is actually `0`. -/ lemma roth_number_nat_add_le (M N : ℕ) : roth_number_nat (M + N) ≤ roth_number_nat M + roth_number_nat N := @@ -426,7 +456,7 @@ lemma roth_number_nat_is_O_with_id : is_O_with.of_bound $ by simpa only [one_mul, real.norm_coe_nat, nat.cast_le] using eventually_of_forall roth_number_nat_le -/-- The Roth number has the trivial bound `roth_number N = O(N)`. -/ +/-- The Roth number has the trivial bound `roth_number_nat N = O(N)`. -/ lemma roth_number_nat_is_O_id : is_O (λ N, (roth_number_nat N : ℝ)) (λ N, (N : ℝ)) at_top := roth_number_nat_is_O_with_id.is_O diff --git a/src/data/multiset/basic.lean b/src/data/multiset/basic.lean index b69aa0b740ac9..f9c3d755e7fc1 100644 --- a/src/data/multiset/basic.lean +++ b/src/data/multiset/basic.lean @@ -493,6 +493,9 @@ quot.induction_on s $ λ l, rfl @[simp] theorem card_singleton (a : α) : card ({a} : multiset α) = 1 := by simp only [singleton_eq_cons, card_zero, eq_self_iff_true, zero_add, card_cons] +lemma card_pair (a b : α) : ({a, b} : multiset α).card = 2 := +by rw [insert_eq_cons, card_cons, card_singleton] + theorem card_eq_one {s : multiset α} : card s = 1 ↔ ∃ a, s = {a} := ⟨quot.induction_on s $ λ l h, (list.length_eq_one.1 h).imp $ λ a, congr_arg coe, From 251bd842ce7eba6c2fa7091c277bc3715f744063 Mon Sep 17 00:00:00 2001 From: tb65536 Date: Thu, 14 Apr 2022 15:31:41 +0000 Subject: [PATCH 029/373] feat(group_theory/subgroup/basic): One more `mem_normalizer_iff` lemma (#13395) This PR golfs `mem_normalizer_iff'` and adds `mem_normalizer_iff''`. There are not so easy to deduce from each other, so it's nice to have these variations available. --- src/group_theory/subgroup/basic.lean | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/group_theory/subgroup/basic.lean b/src/group_theory/subgroup/basic.lean index 2f27617d09bca..bec98f8438bf0 100644 --- a/src/group_theory/subgroup/basic.lean +++ b/src/group_theory/subgroup/basic.lean @@ -1675,16 +1675,16 @@ let ⟨y, hy⟩ := this in conj_injective hy.2 ▸ hy.1⟩ variable {H} @[to_additive] lemma mem_normalizer_iff {g : G} : - g ∈ normalizer H ↔ ∀ n, n ∈ H ↔ g * n * g⁻¹ ∈ H := iff.rfl + g ∈ H.normalizer ↔ ∀ h, h ∈ H ↔ g * h * g⁻¹ ∈ H := +iff.rfl -@[to_additive] lemma mem_normalizer_iff' {g : G} : g ∈ normalizer H ↔ ∀ n, n * g ∈ H ↔ g * n ∈ H := -begin - refine ⟨λ h n, _, λ h n, _⟩, - { specialize h (n * g), - rwa [mul_assoc, mul_inv_cancel_right] at h }, - { specialize h (n * g⁻¹), - rwa [inv_mul_cancel_right, ←mul_assoc] at h }, -end +@[to_additive] lemma mem_normalizer_iff'' {g : G} : + g ∈ H.normalizer ↔ ∀ h : G, h ∈ H ↔ g⁻¹ * h * g ∈ H := +by rw [←inv_mem_iff, mem_normalizer_iff, inv_inv] + +@[to_additive] lemma mem_normalizer_iff' {g : G} : g ∈ H.normalizer ↔ ∀ n, n * g ∈ H ↔ g * n ∈ H := +⟨λ h n, by rw [h, mul_assoc, mul_inv_cancel_right], + λ h n, by rw [mul_assoc, ←h, inv_mul_cancel_right]⟩ @[to_additive] lemma le_normalizer : H ≤ normalizer H := λ x xH n, by rw [H.mul_mem_cancel_right (H.inv_mem xH), H.mul_mem_cancel_left xH] From cbf3062bbc75ad2ca7757e1196690721d6f6b5e8 Mon Sep 17 00:00:00 2001 From: Kyle Miller Date: Thu, 14 Apr 2022 17:32:49 +0000 Subject: [PATCH 030/373] feat(combinatorics/simple_graph/connectivity): define connected components (#12766) --- .../simple_graph/connectivity.lean | 66 ++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/src/combinatorics/simple_graph/connectivity.lean b/src/combinatorics/simple_graph/connectivity.lean index b582e5ca141e5..32409689aa3dc 100644 --- a/src/combinatorics/simple_graph/connectivity.lean +++ b/src/combinatorics/simple_graph/connectivity.lean @@ -52,6 +52,9 @@ counterparts in [Chou1994]. * `simple_graph.subgraph.connected` gives subgraphs the connectivity predicate via `simple_graph.subgraph.coe`. +* `simple_graph.connected_component` is the type of connected components of + a given graph. + ## Tags walks, trails, paths, circuits, cycles @@ -988,11 +991,70 @@ structure connected : Prop := instance : has_coe_to_fun G.connected (λ _, Π (u v : V), G.reachable u v) := ⟨λ h, h.preconnected⟩ -/-- A subgraph is connected if it is connected as a simple graph. -/ -abbreviation subgraph.connected {G : simple_graph V} (H : G.subgraph) : Prop := H.coe.connected +/-- The quotient of `V` by the `simple_graph.reachable` relation gives the connected +components of a graph. -/ +def connected_component := quot G.reachable + +/-- Gives the connected component containing a particular vertex. -/ +def connected_component_mk (v : V) : G.connected_component := quot.mk G.reachable v +instance connected_component.inhabited [inhabited V] : inhabited G.connected_component := +⟨G.connected_component_mk default⟩ + +section connected_component variables {G} +@[elab_as_eliminator] +protected lemma connected_component.ind {β : G.connected_component → Prop} + (h : ∀ (v : V), β (G.connected_component_mk v)) (c : G.connected_component) : β c := +quot.ind h c + +@[elab_as_eliminator] +protected lemma connected_component.ind₂ {β : G.connected_component → G.connected_component → Prop} + (h : ∀ (v w : V), β (G.connected_component_mk v) (G.connected_component_mk w)) + (c d : G.connected_component) : β c d := +quot.induction_on₂ c d h + +protected lemma connected_component.sound {v w : V} : + G.reachable v w → G.connected_component_mk v = G.connected_component_mk w := quot.sound + +protected lemma connected_component.exact {v w : V} : + G.connected_component_mk v = G.connected_component_mk w → G.reachable v w := +@quotient.exact _ G.reachable_setoid _ _ + +@[simp] protected lemma connected_component.eq {v w : V} : + G.connected_component_mk v = G.connected_component_mk w ↔ G.reachable v w := +@quotient.eq _ G.reachable_setoid _ _ + +/-- The `connected_component` specialization of `quot.lift`. Provides the stronger +assumption that the vertices are connected by a path. -/ +protected def connected_component.lift {β : Sort*} (f : V → β) + (h : ∀ (v w : V) (p : G.walk v w), p.is_path → f v = f w) : G.connected_component → β := +quot.lift f (λ v w (h' : G.reachable v w), h'.elim_path (λ hp, h v w hp hp.2)) + +@[simp] protected lemma connected_component.lift_mk {β : Sort*} {f : V → β} + {h : ∀ (v w : V) (p : G.walk v w), p.is_path → f v = f w} {v : V} : + connected_component.lift f h (G.connected_component_mk v) = f v := rfl + +protected lemma connected_component.«exists» {p : G.connected_component → Prop} : + (∃ (c : G.connected_component), p c) ↔ ∃ v, p (G.connected_component_mk v) := +(surjective_quot_mk G.reachable).exists + +protected lemma connected_component.«forall» {p : G.connected_component → Prop} : + (∀ (c : G.connected_component), p c) ↔ ∀ v, p (G.connected_component_mk v) := +(surjective_quot_mk G.reachable).forall + +lemma preconnected.subsingleton_connected_component (h : G.preconnected) : + subsingleton G.connected_component := +⟨connected_component.ind₂ (λ v w, connected_component.sound (h v w))⟩ + +end connected_component + +variables {G} + +/-- A subgraph is connected if it is connected as a simple graph. -/ +abbreviation subgraph.connected (H : G.subgraph) : Prop := H.coe.connected + lemma preconnected.set_univ_walk_nonempty (hconn : G.preconnected) (u v : V) : (set.univ : set (G.walk u v)).nonempty := by { rw ← set.nonempty_iff_univ_nonempty, exact hconn u v } From 1506335dfb497c13e35430b320ca4ac897cd3380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Thu, 14 Apr 2022 20:31:11 +0000 Subject: [PATCH 031/373] chore(number_theory/zsqrtd/*): Missing docstrings and cleanups (#13445) Add docstrings to `gaussian_int` and `zsqrtd.norm` and inline definitions which did not have a docstring nor deserved one. --- src/number_theory/pell.lean | 8 +- src/number_theory/zsqrtd/basic.lean | 129 ++++++++------------- src/number_theory/zsqrtd/gaussian_int.lean | 14 +-- 3 files changed, 59 insertions(+), 92 deletions(-) diff --git a/src/number_theory/pell.lean b/src/number_theory/pell.lean index 9db398469b62e..dfb7feb2e244f 100644 --- a/src/number_theory/pell.lean +++ b/src/number_theory/pell.lean @@ -217,7 +217,7 @@ lemma eq_pell_lem : ∀n (b:ℤ√d), 1 ≤ b → is_pell b → b ≤ pell_zd n theorem eq_pell_zd (b : ℤ√d) (b1 : 1 ≤ b) (hp : is_pell b) : ∃n, b = pell_zd n := let ⟨n, h⟩ := @zsqrtd.le_arch d b in -eq_pell_lem n b b1 hp $ zsqrtd.le_trans h $ by rw zsqrtd.coe_nat_val; exact +eq_pell_lem n b b1 hp $ h.trans $ by rw zsqrtd.coe_nat_val; exact zsqrtd.le_of_le_le (int.coe_nat_le_coe_nat_of_le $ le_of_lt $ n_lt_xn _ _) (int.coe_zero_le _) @@ -252,11 +252,11 @@ by rw [add_tsub_cancel_of_le h] at t; rw [t, mul_comm (pell_zd _ n) _, mul_assoc, (is_pell_norm _).1 (is_pell_pell_zd _ _), mul_one] theorem xz_sub {m n} (h : n ≤ m) : xz (m - n) = xz m * xz n - d * yz m * yz n := -by injection (pell_zd_sub _ h) with h _; repeat {rw mul_neg at h}; exact h +by { rw [sub_eq_add_neg, ←mul_neg], exact congr_arg zsqrtd.re (pell_zd_sub a1 h) } theorem yz_sub {m n} (h : n ≤ m) : yz (m - n) = xz n * yz m - xz m * yz n := -by injection (pell_zd_sub a1 h) with _ h; repeat {rw mul_neg at h}; - rw [add_comm, mul_comm] at h; exact h +by { rw [sub_eq_add_neg, ←mul_neg, mul_comm, add_comm], + exact congr_arg zsqrtd.im (pell_zd_sub a1 h) } theorem xy_coprime (n) : (xn n).coprime (yn n) := nat.coprime_of_dvd' $ λk kp kx ky, diff --git a/src/number_theory/zsqrtd/basic.lean b/src/number_theory/zsqrtd/basic.lean index e3704505f7e96..6c9c148a04b84 100644 --- a/src/number_theory/zsqrtd/basic.lean +++ b/src/number_theory/zsqrtd/basic.lean @@ -45,16 +45,14 @@ theorem of_int_re (n : ℤ) : (of_int n).re = n := rfl theorem of_int_im (n : ℤ) : (of_int n).im = 0 := rfl /-- The zero of the ring -/ -def zero : ℤ√d := of_int 0 -instance : has_zero ℤ√d := ⟨zsqrtd.zero⟩ +instance : has_zero ℤ√d := ⟨of_int 0⟩ @[simp] theorem zero_re : (0 : ℤ√d).re = 0 := rfl @[simp] theorem zero_im : (0 : ℤ√d).im = 0 := rfl instance : inhabited ℤ√d := ⟨0⟩ /-- The one of the ring -/ -def one : ℤ√d := of_int 1 -instance : has_one ℤ√d := ⟨zsqrtd.one⟩ +instance : has_one ℤ√d := ⟨of_int 1⟩ @[simp] theorem one_re : (1 : ℤ√d).re = 1 := rfl @[simp] theorem one_im : (1 : ℤ√d).im = 0 := rfl @@ -64,39 +62,26 @@ def sqrtd : ℤ√d := ⟨0, 1⟩ @[simp] theorem sqrtd_im : (sqrtd : ℤ√d).im = 1 := rfl /-- Addition of elements of `ℤ√d` -/ -def add : ℤ√d → ℤ√d → ℤ√d -| ⟨x, y⟩ ⟨x', y'⟩ := ⟨x + x', y + y'⟩ -instance : has_add ℤ√d := ⟨zsqrtd.add⟩ -@[simp] theorem add_def (x y x' y' : ℤ) : - (⟨x, y⟩ + ⟨x', y'⟩ : ℤ√d) = ⟨x + x', y + y'⟩ := rfl -@[simp] theorem add_re : ∀ z w : ℤ√d, (z + w).re = z.re + w.re -| ⟨x, y⟩ ⟨x', y'⟩ := rfl -@[simp] theorem add_im : ∀ z w : ℤ√d, (z + w).im = z.im + w.im -| ⟨x, y⟩ ⟨x', y'⟩ := rfl - -@[simp] theorem bit0_re (z) : (bit0 z : ℤ√d).re = bit0 z.re := add_re _ _ -@[simp] theorem bit0_im (z) : (bit0 z : ℤ√d).im = bit0 z.im := add_im _ _ - -@[simp] theorem bit1_re (z) : (bit1 z : ℤ√d).re = bit1 z.re := by simp [bit1] +instance : has_add ℤ√d := ⟨λ z w, ⟨z.1 + w.1, z.2 + w.2⟩⟩ +@[simp] lemma add_def (x y x' y' : ℤ) : (⟨x, y⟩ + ⟨x', y'⟩ : ℤ√d) = ⟨x + x', y + y'⟩ := rfl +@[simp] lemma add_re (z w : ℤ√d) : (z + w).re = z.re + w.re := rfl +@[simp] lemma add_im (z w : ℤ√d) : (z + w).im = z.im + w.im := rfl + +@[simp] lemma bit0_re (z) : (bit0 z : ℤ√d).re = bit0 z.re := rfl +@[simp] lemma bit0_im (z) : (bit0 z : ℤ√d).im = bit0 z.im := rfl + +@[simp] theorem bit1_re (z) : (bit1 z : ℤ√d).re = bit1 z.re := rfl @[simp] theorem bit1_im (z) : (bit1 z : ℤ√d).im = bit0 z.im := by simp [bit1] /-- Negation in `ℤ√d` -/ -def neg : ℤ√d → ℤ√d -| ⟨x, y⟩ := ⟨-x, -y⟩ -instance : has_neg ℤ√d := ⟨zsqrtd.neg⟩ -@[simp] theorem neg_re : ∀ z : ℤ√d, (-z).re = -z.re -| ⟨x, y⟩ := rfl -@[simp] theorem neg_im : ∀ z : ℤ√d, (-z).im = -z.im -| ⟨x, y⟩ := rfl +instance : has_neg ℤ√d := ⟨λ z, ⟨-z.1, -z.2⟩⟩ +@[simp] lemma neg_re (z : ℤ√d) : (-z).re = -z.re := rfl +@[simp] lemma neg_im (z : ℤ√d) : (-z).im = -z.im := rfl /-- Multiplication in `ℤ√d` -/ -def mul : ℤ√d → ℤ√d → ℤ√d -| ⟨x, y⟩ ⟨x', y'⟩ := ⟨x * x' + d * y * y', x * y' + y * x'⟩ -instance : has_mul ℤ√d := ⟨zsqrtd.mul⟩ -@[simp] theorem mul_re : ∀ z w : ℤ√d, (z * w).re = z.re * w.re + d * z.im * w.im -| ⟨x, y⟩ ⟨x', y'⟩ := rfl -@[simp] theorem mul_im : ∀ z w : ℤ√d, (z * w).im = z.re * w.im + z.im * w.re -| ⟨x, y⟩ ⟨x', y'⟩ := rfl +instance : has_mul ℤ√d := ⟨λ z w, ⟨z.1 * w.1 + d * z.2 * w.2, z.1 * w.2 + z.2 * w.1⟩⟩ +@[simp] lemma mul_re (z w : ℤ√d) : (z * w).re = z.re * w.re + d * z.im * w.im := rfl +@[simp] lemma mul_im (z w : ℤ√d) : (z * w).im = z.re * w.im + z.im * w.re := rfl instance : comm_ring ℤ√d := by refine_struct @@ -108,7 +93,7 @@ by refine_struct one := 1, npow := @npow_rec (ℤ√d) ⟨1⟩ ⟨(*)⟩, nsmul := @nsmul_rec (ℤ√d) ⟨0⟩ ⟨(+)⟩, - zsmul := @zsmul_rec (ℤ√d) ⟨0⟩ ⟨(+)⟩ ⟨zsqrtd.neg⟩ }; + zsmul := @zsmul_rec (ℤ√d) ⟨0⟩ ⟨(+)⟩ ⟨has_neg.neg⟩ }; intros; try { refl }; simp [ext, add_mul, mul_add, add_comm, add_left_comm, mul_comm, mul_left_comm] instance : add_comm_monoid ℤ√d := by apply_instance @@ -125,12 +110,9 @@ instance : ring ℤ√d := by apply_instance instance : distrib ℤ√d := by apply_instance /-- Conjugation in `ℤ√d`. The conjugate of `a + b √d` is `a - b √d`. -/ -def conj : ℤ√d → ℤ√d -| ⟨x, y⟩ := ⟨x, -y⟩ -@[simp] theorem conj_re : ∀ z : ℤ√d, (conj z).re = z.re -| ⟨x, y⟩ := rfl -@[simp] theorem conj_im : ∀ z : ℤ√d, (conj z).im = -z.im -| ⟨x, y⟩ := rfl +def conj (z : ℤ√d) : ℤ√d := ⟨z.1, -z.2⟩ +@[simp] lemma conj_re (z : ℤ√d) : (conj z).re = z.re := rfl +@[simp] lemma conj_im (z : ℤ√d) : (conj z).im = -z.im := rfl /-- `conj` as an `add_monoid_hom`. -/ def conj_hom : ℤ√d →+ ℤ√d := @@ -145,8 +127,7 @@ conj_hom.map_zero by simp only [zsqrtd.ext, zsqrtd.conj_re, zsqrtd.conj_im, zsqrtd.one_im, neg_zero, eq_self_iff_true, and_self] -@[simp] lemma conj_neg (x : ℤ√d) : (-x).conj = -x.conj := -conj_hom.map_neg x +@[simp] lemma conj_neg (x : ℤ√d) : (-x).conj = -x.conj := rfl @[simp] lemma conj_add (x y : ℤ√d) : (x + y).conj = x.conj + y.conj := conj_hom.map_add x y @@ -366,6 +347,7 @@ cast nonnegg_comm (nonnegg_cases_right h) section norm +/-- The norm of an element of `ℤ[√d]`. -/ def norm (n : ℤ√d) : ℤ := n.re * n.re - d * n.im * n.im lemma norm_def (n : ℤ√d) : n.norm = n.re * n.re - d * n.im * n.im := rfl @@ -458,13 +440,8 @@ parameter {d : ℕ} /-- Nonnegativity of an element of `ℤ√d`. -/ def nonneg : ℤ√d → Prop | ⟨a, b⟩ := nonnegg d 1 a b -protected def le (a b : ℤ√d) : Prop := nonneg (b - a) - -instance : has_le ℤ√d := ⟨zsqrtd.le⟩ - -protected def lt (a b : ℤ√d) : Prop := ¬(b ≤ a) - -instance : has_lt ℤ√d := ⟨zsqrtd.lt⟩ +instance : has_le ℤ√d := ⟨λ a b, nonneg (b - a)⟩ +instance : has_lt ℤ√d := ⟨λ a b, ¬ b ≤ a⟩ instance decidable_nonnegg (c d a b) : decidable (nonnegg c d a b) := by cases a; cases b; repeat {rw int.of_nat_eq_coe}; unfold nonnegg sq_le; apply_instance @@ -472,7 +449,7 @@ by cases a; cases b; repeat {rw int.of_nat_eq_coe}; unfold nonnegg sq_le; apply_ instance decidable_nonneg : Π (a : ℤ√d), decidable (nonneg a) | ⟨a, b⟩ := zsqrtd.decidable_nonnegg _ _ _ _ -instance decidable_le (a b : ℤ√d) : decidable (a ≤ b) := decidable_nonneg _ +instance decidable_le : @decidable_rel (ℤ√d) (≤) := λ _ _, decidable_nonneg _ theorem nonneg_cases : Π {a : ℤ√d}, nonneg a → ∃ x y : ℕ, a = ⟨x, y⟩ ∨ a = ⟨x, -y⟩ ∨ a = ⟨-x, y⟩ | ⟨(x : ℕ), (y : ℕ)⟩ h := ⟨x, y, or.inl rfl⟩ @@ -498,10 +475,10 @@ have nonneg ⟨int.sub_nat_nat x z, int.sub_nat_nat w y⟩, from int.sub_nat_nat show nonneg ⟨_, _⟩, by rw [neg_add_eq_sub]; rwa [int.sub_nat_nat_eq_coe,int.sub_nat_nat_eq_coe] at this -theorem nonneg_add {a b : ℤ√d} (ha : nonneg a) (hb : nonneg b) : nonneg (a + b) := +lemma nonneg.add {a b : ℤ√d} (ha : nonneg a) (hb : nonneg b) : nonneg (a + b) := begin rcases nonneg_cases ha with ⟨x, y, rfl|rfl|rfl⟩; - rcases nonneg_cases hb with ⟨z, w, rfl|rfl|rfl⟩; dsimp [add, nonneg] at ha hb ⊢, + rcases nonneg_cases hb with ⟨z, w, rfl|rfl|rfl⟩, { trivial }, { refine nonnegg_cases_right (λi h, sq_le_of_le _ _ (nonnegg_pos_neg.1 hb)), { exact int.coe_nat_le.1 (le_of_neg_le_neg (@int.le.intro _ _ y (by simp [add_comm, *]))) }, @@ -518,17 +495,11 @@ begin { refine nonnegg_cases_left (λi h, sq_le_of_le _ _ (nonnegg_neg_pos.1 ha)), { exact int.coe_nat_le.1 (le_of_neg_le_neg (int.le.intro h)) }, { apply nat.le_add_right } }, - { rw [add_comm, add_comm ↑y], exact nonneg_add_lem hb ha }, + { dsimp, rw [add_comm, add_comm ↑y], exact nonneg_add_lem hb ha }, { simpa [add_comm] using nonnegg_neg_pos.2 (sq_le_add (nonnegg_neg_pos.1 ha) (nonnegg_neg_pos.1 hb)) }, end -theorem le_refl (a : ℤ√d) : a ≤ a := show nonneg (a - a), by simp - -protected theorem le_trans {a b c : ℤ√d} (ab : a ≤ b) (bc : b ≤ c) : a ≤ c := -have nonneg (b - a + (c - b)), from nonneg_add ab bc, -by simpa [sub_add_sub_cancel'] - theorem nonneg_iff_zero_le {a : ℤ√d} : nonneg a ↔ 0 ≤ a := show _ ↔ nonneg _, by simp theorem le_of_le_le {x y z w : ℤ} (xz : x ≤ z) (yw : y ≤ w) : (⟨x, y⟩ : ℤ√d) ≤ ⟨z, w⟩ := @@ -536,6 +507,25 @@ show nonneg ⟨z - x, w - y⟩, from match z - x, w - y, int.le.dest_sub xz, int.le.dest_sub yw with ._, ._, ⟨a, rfl⟩, ⟨b, rfl⟩ := trivial end +protected theorem nonneg_total : Π (a : ℤ√d), nonneg a ∨ nonneg (-a) +| ⟨(x : ℕ), (y : ℕ)⟩ := or.inl trivial +| ⟨-[1+ x], -[1+ y]⟩ := or.inr trivial +| ⟨0, -[1+ y]⟩ := or.inr trivial +| ⟨-[1+ x], 0⟩ := or.inr trivial +| ⟨(x+1:ℕ), -[1+ y]⟩ := nat.le_total +| ⟨-[1+ x], (y+1:ℕ)⟩ := nat.le_total + +protected theorem le_total (a b : ℤ√d) : a ≤ b ∨ b ≤ a := +let t := nonneg_total (b - a) in by rw [show -(b-a) = a-b, from neg_sub b a] at t; exact t + +instance : preorder ℤ√d := +{ le := (≤), + le_refl := λ a, show nonneg (a - a), by simp only [sub_self], + le_trans := λ a b c hab hbc, by simpa [sub_add_sub_cancel'] using hab.add hbc, + lt := (<), + lt_iff_le_not_le := λ a b, + (and_iff_right_of_imp (zsqrtd.le_total _ _).resolve_left).symm } + theorem le_arch (a : ℤ√d) : ∃n : ℕ, a ≤ n := let ⟨x, y, (h : a ≤ ⟨x, y⟩)⟩ := show ∃x y : ℕ, nonneg (⟨x, y⟩ + -a), from match -a with | ⟨int.of_nat x, int.of_nat y⟩ := ⟨0, 0, trivial⟩ @@ -543,7 +533,7 @@ let ⟨x, y, (h : a ≤ ⟨x, y⟩)⟩ := show ∃x y : ℕ, nonneg (⟨x, y⟩ | ⟨-[1+ x], int.of_nat y⟩ := ⟨x+1, 0, by simp [int.neg_succ_of_nat_coe, add_assoc]⟩ | ⟨-[1+ x], -[1+ y]⟩ := ⟨x+1, y+1, by simp [int.neg_succ_of_nat_coe, add_assoc]⟩ end in begin - refine ⟨x + d*y, zsqrtd.le_trans h _⟩, + refine ⟨x + d*y, h.trans _⟩, rw [← int.cast_coe_nat, ← of_int_eq_coe], change nonneg ⟨(↑x + d*y) - ↑x, 0-↑y⟩, cases y with y, @@ -555,25 +545,6 @@ end in begin exact h (y+1) end -protected theorem nonneg_total : Π (a : ℤ√d), nonneg a ∨ nonneg (-a) -| ⟨(x : ℕ), (y : ℕ)⟩ := or.inl trivial -| ⟨-[1+ x], -[1+ y]⟩ := or.inr trivial -| ⟨0, -[1+ y]⟩ := or.inr trivial -| ⟨-[1+ x], 0⟩ := or.inr trivial -| ⟨(x+1:ℕ), -[1+ y]⟩ := nat.le_total -| ⟨-[1+ x], (y+1:ℕ)⟩ := nat.le_total - -protected theorem le_total (a b : ℤ√d) : a ≤ b ∨ b ≤ a := -let t := nonneg_total (b - a) in by rw [show -(b-a) = a-b, from neg_sub b a] at t; exact t - -instance : preorder ℤ√d := -{ le := zsqrtd.le, - le_refl := zsqrtd.le_refl, - le_trans := @zsqrtd.le_trans, - lt := zsqrtd.lt, - lt_iff_le_not_le := λ a b, - (and_iff_right_of_imp (zsqrtd.le_total _ _).resolve_left).symm } - protected theorem add_le_add_left (a b : ℤ√d) (ab : a ≤ b) (c : ℤ√d) : c + a ≤ c + b := show nonneg _, by rw add_sub_add_left_eq_sub; exact ab @@ -606,7 +577,7 @@ end theorem nonneg_mul_lem {x y : ℕ} {a : ℤ√d} (ha : nonneg a) : nonneg (⟨x, y⟩ * a) := have (⟨x, y⟩ * a : ℤ√d) = x * a + sqrtd * (y * a), by rw [decompose, right_distrib, mul_assoc]; refl, -by rw this; exact nonneg_add (nonneg_smul ha) (nonneg_muld $ nonneg_smul ha) +by rw this; exact (nonneg_smul ha).add (nonneg_muld $ nonneg_smul ha) theorem nonneg_mul {a b : ℤ√d} (ha : nonneg a) (hb : nonneg b) : nonneg (a * b) := match a, b, nonneg_cases ha, nonneg_cases hb, ha, hb with diff --git a/src/number_theory/zsqrtd/gaussian_int.lean b/src/number_theory/zsqrtd/gaussian_int.lean index 0f90dba67c414..b9a527cb7f8a4 100644 --- a/src/number_theory/zsqrtd/gaussian_int.lean +++ b/src/number_theory/zsqrtd/gaussian_int.lean @@ -37,6 +37,7 @@ and definitions about `zsqrtd` can easily be used. open zsqrtd complex +/-- The Gaussian integers, defined as `ℤ√(-1)`. -/ @[reducible] def gaussian_int : Type := zsqrtd (-1) local notation `ℤ[i]` := gaussian_int @@ -106,12 +107,9 @@ lemma nat_abs_norm_eq (x : ℤ[i]) : x.norm.nat_abs = x.re.nat_abs * x.re.nat_abs + x.im.nat_abs * x.im.nat_abs := int.coe_nat_inj $ begin simp, simp [norm] end -protected def div (x y : ℤ[i]) : ℤ[i] := -let n := (rat.of_int (norm y))⁻¹ in let c := y.conj in -⟨round (rat.of_int (x * c).re * n : ℚ), - round (rat.of_int (x * c).im * n : ℚ)⟩ - -instance : has_div ℤ[i] := ⟨gaussian_int.div⟩ +instance : has_div ℤ[i] := +⟨λ x y, let n := (rat.of_int (norm y))⁻¹, c := y.conj in + ⟨round (rat.of_int (x * c).re * n : ℚ), round (rat.of_int (x * c).im * n : ℚ)⟩⟩ lemma div_def (x y : ℤ[i]) : x / y = ⟨round ((x * conj y).re / norm y : ℚ), round ((x * conj y).im / norm y : ℚ)⟩ := @@ -149,9 +147,7 @@ calc ((x / y : ℂ) - ((x / y : ℤ[i]) : ℂ)).norm_sq = simpa using abs_sub_round (x / y : ℂ).im) ... < 1 : by simp [norm_sq]; norm_num -protected def mod (x y : ℤ[i]) : ℤ[i] := x - y * (x / y) - -instance : has_mod ℤ[i] := ⟨gaussian_int.mod⟩ +instance : has_mod ℤ[i] := ⟨λ x y, x - y * (x / y)⟩ lemma mod_def (x y : ℤ[i]) : x % y = x - y * (x / y) := rfl From d81cedb1d1d9f2ecfd13335f1095a090c9a22d92 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Fri, 15 Apr 2022 02:47:13 +0000 Subject: [PATCH 032/373] feat(topology/algebra/module/multilinear): relax requirements for `continuous_multilinear_map.mk_pi_algebra` (#13426) `continuous_multilinear_map.mk_pi_algebra` and `continuous_multilinear_map.mk_pi_algebra_fin` do not need a norm on either the algebra or base ring; all they need is a topology on the algebra compatible with multiplication. The much weaker typeclasses cause some elaboration issues in a few places, as the normed space can no longer be found by unification. Adding a non-dependent version of `continuous_multilinear_map.has_op_norm` largely resolves this, although a few API proofs about `mk_pi_algebra` and `mk_pi_algebra_fin` end up quite underscore heavy. This is the first step in being able to define `exp` without first choosing a `norm`. --- src/analysis/normed_space/multilinear.lean | 96 +++++++++----------- src/topology/algebra/module/multilinear.lean | 44 +++++++++ 2 files changed, 85 insertions(+), 55 deletions(-) diff --git a/src/analysis/normed_space/multilinear.lean b/src/analysis/normed_space/multilinear.lean index d852dba93b817..69f74d4ea2a1d 100644 --- a/src/analysis/normed_space/multilinear.lean +++ b/src/analysis/normed_space/multilinear.lean @@ -285,6 +285,11 @@ open real def op_norm := Inf {c | 0 ≤ (c : ℝ) ∧ ∀ m, ∥f m∥ ≤ c * ∏ i, ∥m i∥} instance has_op_norm : has_norm (continuous_multilinear_map 𝕜 E G) := ⟨op_norm⟩ +/-- An alias of `continuous_multilinear_map.has_op_norm` with non-dependent types to help typeclass +search. -/ +instance has_op_norm' : has_norm (continuous_multilinear_map 𝕜 (λ (i : ι), G) G') := +continuous_multilinear_map.has_op_norm + lemma norm_def : ∥f∥ = Inf {c | 0 ≤ (c : ℝ) ∧ ∀ m, ∥f m∥ ≤ c * ∏ i, ∥m i∥} := rfl -- So that invocations of `le_cInf` make sense: we show that the set of @@ -669,43 +674,28 @@ end section -variables (𝕜 ι) (A : Type*) [normed_comm_ring A] [normed_algebra 𝕜 A] - -/-- The continuous multilinear map on `A^ι`, where `A` is a normed commutative algebra -over `𝕜`, associating to `m` the product of all the `m i`. - -See also `continuous_multilinear_map.mk_pi_algebra_fin`. -/ -protected def mk_pi_algebra : continuous_multilinear_map 𝕜 (λ i : ι, A) A := -multilinear_map.mk_continuous - (multilinear_map.mk_pi_algebra 𝕜 ι A) (if nonempty ι then 1 else ∥(1 : A)∥) $ - begin - intro m, - casesI is_empty_or_nonempty ι with hι hι, - { simp [eq_empty_of_is_empty univ, not_nonempty_iff.2 hι] }, - { simp [norm_prod_le' univ univ_nonempty, hι] } - end - -variables {A 𝕜 ι} - -@[simp] lemma mk_pi_algebra_apply (m : ι → A) : - continuous_multilinear_map.mk_pi_algebra 𝕜 ι A m = ∏ i, m i := -rfl +variables {𝕜 ι} {A : Type*} [normed_comm_ring A] [normed_algebra 𝕜 A] +@[simp] lemma norm_mk_pi_algebra_le [nonempty ι] : ∥continuous_multilinear_map.mk_pi_algebra 𝕜 ι A∥ ≤ 1 := -calc ∥continuous_multilinear_map.mk_pi_algebra 𝕜 ι A∥ ≤ if nonempty ι then 1 else ∥(1 : A)∥ : - multilinear_map.mk_continuous_norm_le _ (by split_ifs; simp [zero_le_one]) _ -... = _ : if_pos ‹_› +begin + have := λ f, @op_norm_le_bound 𝕜 ι (λ i, A) A _ _ _ _ _ _ _ f _ zero_le_one, + refine this _ _, + intros m, + simp only [continuous_multilinear_map.mk_pi_algebra_apply, one_mul], + exact norm_prod_le' _ univ_nonempty _, +end lemma norm_mk_pi_algebra_of_empty [is_empty ι] : ∥continuous_multilinear_map.mk_pi_algebra 𝕜 ι A∥ = ∥(1 : A)∥ := begin apply le_antisymm, - calc ∥continuous_multilinear_map.mk_pi_algebra 𝕜 ι A∥ ≤ if nonempty ι then 1 else ∥(1 : A)∥ : - multilinear_map.mk_continuous_norm_le _ (by split_ifs; simp [zero_le_one]) _ - ... = ∥(1 : A)∥ : if_neg (not_nonempty_iff.mpr ‹_›), - convert ratio_le_op_norm _ (λ _, (1 : A)), - simp [eq_empty_of_is_empty (univ : finset ι)], + { have := λ f, @op_norm_le_bound 𝕜 ι (λ i, A) A _ _ _ _ _ _ _ f _ (norm_nonneg (1 : A)), + refine this _ _, + simp, }, + { convert ratio_le_op_norm _ (λ _, (1 : A)), + simp [eq_empty_of_is_empty (univ : finset ι)], }, end @[simp] lemma norm_mk_pi_algebra [norm_one_class A] : @@ -722,42 +712,38 @@ end section -variables (𝕜 n) (A : Type*) [normed_ring A] [normed_algebra 𝕜 A] - -/-- The continuous multilinear map on `A^n`, where `A` is a normed algebra over `𝕜`, associating to -`m` the product of all the `m i`. - -See also: `multilinear_map.mk_pi_algebra`. -/ -protected def mk_pi_algebra_fin : continuous_multilinear_map 𝕜 (λ i : fin n, A) A := -multilinear_map.mk_continuous - (multilinear_map.mk_pi_algebra_fin 𝕜 n A) (nat.cases_on n ∥(1 : A)∥ (λ _, 1)) $ - begin - intro m, - cases n, - { simp }, - { have : @list.of_fn A n.succ m ≠ [] := by simp, - simpa [← fin.prod_of_fn] using list.norm_prod_le' this } - end - -variables {A 𝕜 n} - -@[simp] lemma mk_pi_algebra_fin_apply (m : fin n → A) : - continuous_multilinear_map.mk_pi_algebra_fin 𝕜 n A m = (list.of_fn m).prod := -rfl +variables {𝕜 n} {A : Type*} [normed_ring A] [normed_algebra 𝕜 A] lemma norm_mk_pi_algebra_fin_succ_le : ∥continuous_multilinear_map.mk_pi_algebra_fin 𝕜 n.succ A∥ ≤ 1 := -multilinear_map.mk_continuous_norm_le _ zero_le_one _ +begin + have := λ f, @op_norm_le_bound 𝕜 (fin n.succ) (λ i, A) A _ _ _ _ _ _ _ f _ zero_le_one, + refine this _ _, + intros m, + simp only [continuous_multilinear_map.mk_pi_algebra_fin_apply, one_mul, list.of_fn_eq_map, + fin.univ_def, finset.fin_range, finset.prod, multiset.coe_map, multiset.coe_prod], + refine (list.norm_prod_le' _).trans_eq _, + { rw [ne.def, list.map_eq_nil, list.fin_range_eq_nil], + exact nat.succ_ne_zero _, }, + rw list.map_map, +end lemma norm_mk_pi_algebra_fin_le_of_pos (hn : 0 < n) : ∥continuous_multilinear_map.mk_pi_algebra_fin 𝕜 n A∥ ≤ 1 := -by cases n; [exact hn.false.elim, exact norm_mk_pi_algebra_fin_succ_le] +begin + obtain ⟨n, rfl⟩ := nat.exists_eq_succ_of_ne_zero hn.ne', + exact norm_mk_pi_algebra_fin_succ_le +end lemma norm_mk_pi_algebra_fin_zero : ∥continuous_multilinear_map.mk_pi_algebra_fin 𝕜 0 A∥ = ∥(1 : A)∥ := begin - refine le_antisymm (multilinear_map.mk_continuous_norm_le _ (norm_nonneg _) _) _, - convert ratio_le_op_norm _ (λ _, 1); [simp, apply_instance] + refine le_antisymm _ _, + { have := λ f, @op_norm_le_bound 𝕜 (fin 0) (λ i, A) A _ _ _ _ _ _ _ f _ (norm_nonneg (1 : A)), + refine this _ _, + simp, }, + { convert ratio_le_op_norm _ (λ _, (1 : A)), + simp } end @[simp] lemma norm_mk_pi_algebra_fin [norm_one_class A] : diff --git a/src/topology/algebra/module/multilinear.lean b/src/topology/algebra/module/multilinear.lean index 028e90b60064c..de11e05b4035e 100644 --- a/src/topology/algebra/module/multilinear.lean +++ b/src/topology/algebra/module/multilinear.lean @@ -409,4 +409,48 @@ def pi_linear_equiv {ι' : Type*} {M' : ι' → Type*} end module +section comm_algebra + +variables (R ι) (A : Type*) [fintype ι] [comm_semiring R] [comm_semiring A] [algebra R A] + [topological_space A] [has_continuous_mul A] + +/-- The continuous multilinear map on `A^ι`, where `A` is a normed commutative algebra +over `𝕜`, associating to `m` the product of all the `m i`. + +See also `continuous_multilinear_map.mk_pi_algebra_fin`. -/ +protected def mk_pi_algebra : continuous_multilinear_map R (λ i : ι, A) A := +{ cont := continuous_finset_prod _ $ λ i hi, continuous_apply _, + to_multilinear_map := multilinear_map.mk_pi_algebra R ι A} + +@[simp] lemma mk_pi_algebra_apply (m : ι → A) : + continuous_multilinear_map.mk_pi_algebra R ι A m = ∏ i, m i := +rfl + +end comm_algebra + +section algebra + +variables (R n) (A : Type*) [comm_semiring R] [semiring A] [algebra R A] + [topological_space A] [has_continuous_mul A] + +/-- The continuous multilinear map on `A^n`, where `A` is a normed algebra over `𝕜`, associating to +`m` the product of all the `m i`. + +See also: `continuous_multilinear_map.mk_pi_algebra`. -/ +protected def mk_pi_algebra_fin : A [×n]→L[R] A := +{ cont := begin + change continuous (λ m, (list.of_fn m).prod), + simp_rw list.of_fn_eq_map, + exact continuous_list_prod _ (λ i hi, continuous_apply _), + end, + to_multilinear_map := multilinear_map.mk_pi_algebra_fin R n A} + +variables {R n A} + +@[simp] lemma mk_pi_algebra_fin_apply (m : fin n → A) : + continuous_multilinear_map.mk_pi_algebra_fin R n A m = (list.of_fn m).prod := +rfl + +end algebra + end continuous_multilinear_map From 6a5764b3a0ab1506fd7204f11e58591b19fc8edd Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 15 Apr 2022 03:41:29 +0000 Subject: [PATCH 033/373] chore(analysis/normed_space/multilinear): use notation (#13452) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * use notation `A [×n]→L[𝕜] B`; * use `A → B` instead of `Π x : A, B`. --- src/analysis/normed_space/multilinear.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/analysis/normed_space/multilinear.lean b/src/analysis/normed_space/multilinear.lean index 69f74d4ea2a1d..b7771c2f0721e 100644 --- a/src/analysis/normed_space/multilinear.lean +++ b/src/analysis/normed_space/multilinear.lean @@ -660,8 +660,8 @@ namespace continuous_multilinear_map these variables, and fixing the other ones equal to a given value `z`. It is denoted by `f.restr s hk z`, where `hk` is a proof that the cardinality of `s` is `k`. The implicit identification between `fin k` and `s` that we use is the canonical (increasing) bijection. -/ -def restr {k n : ℕ} (f : (G [×n]→L[𝕜] G' : _)) - (s : finset (fin n)) (hk : s.card = k) (z : G) : G [×k]→L[𝕜] G' := +def restr {k n : ℕ} (f : (G [×n]→L[𝕜] G' : _)) (s : finset (fin n)) (hk : s.card = k) (z : G) : + G [×k]→L[𝕜] G' := (f.to_multilinear_map.restr s hk z).mk_continuous (∥f∥ * ∥z∥^(n-k)) $ λ v, multilinear_map.restr_norm_le _ _ _ _ f.le_op_norm _ @@ -1189,11 +1189,11 @@ variables {n 𝕜 G Ei G'} (continuous_multilinear_curry_right_equiv 𝕜 Ei G).symm f v x = f (snoc v x) := rfl @[simp] lemma continuous_multilinear_curry_right_equiv_apply' - (f : G [×n]→L[𝕜] (G →L[𝕜] G')) (v : Π (i : fin n.succ), G) : + (f : G [×n]→L[𝕜] (G →L[𝕜] G')) (v : fin (n + 1) → G) : continuous_multilinear_curry_right_equiv' 𝕜 n G G' f v = f (init v) (v (last n)) := rfl @[simp] lemma continuous_multilinear_curry_right_equiv_symm_apply' - (f : G [×n.succ]→L[𝕜] G') (v : Π (i : fin n), G) (x : G) : + (f : G [×n.succ]→L[𝕜] G') (v : fin n → G) (x : G) : (continuous_multilinear_curry_right_equiv' 𝕜 n G G').symm f v x = f (snoc v x) := rfl @[simp] lemma continuous_multilinear_map.curry_right_norm From d6a46b79e3d840f8a07bdc7df58752af963ae93d Mon Sep 17 00:00:00 2001 From: leanprover-community-bot Date: Fri, 15 Apr 2022 04:32:08 +0000 Subject: [PATCH 034/373] chore(scripts): update nolints.txt (#13455) I am happy to remove some nolints for you! --- scripts/nolints.txt | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/scripts/nolints.txt b/scripts/nolints.txt index 60259371d6d32..754a7bbc1e0fb 100644 --- a/scripts/nolints.txt +++ b/scripts/nolints.txt @@ -612,16 +612,6 @@ apply_nolint tactic.mono doc_blame -- number_theory/dioph.lean apply_nolint poly has_inhabited_instance --- number_theory/zsqrtd/basic.lean -apply_nolint zsqrtd.le doc_blame -apply_nolint zsqrtd.lt doc_blame -apply_nolint zsqrtd.norm doc_blame - --- number_theory/zsqrtd/gaussian_int.lean -apply_nolint gaussian_int doc_blame -apply_nolint gaussian_int.div doc_blame -apply_nolint gaussian_int.mod doc_blame - -- order/filter/at_top_bot.lean apply_nolint filter.map_at_top_finset_prod_le_of_prod_eq to_additive_doc From dd51529f58cfbe33f3320231d3561bd4b2e8e2c1 Mon Sep 17 00:00:00 2001 From: Kyle Miller Date: Fri, 15 Apr 2022 09:02:46 +0000 Subject: [PATCH 035/373] feat(combinatorics/simple_graph/subgraph): delete_edges (#13306) Construct a subgraph from another by deleting edges. --- src/combinatorics/simple_graph/basic.lean | 6 +- src/combinatorics/simple_graph/subgraph.lean | 87 +++++++++++++++++++- 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/src/combinatorics/simple_graph/basic.lean b/src/combinatorics/simple_graph/basic.lean index 82dcca3306abf..1216aff11901e 100644 --- a/src/combinatorics/simple_graph/basic.lean +++ b/src/combinatorics/simple_graph/basic.lean @@ -597,8 +597,10 @@ end incidence /-! ## Edge deletion -/ -/-- Given a set of vertex pairs, remove all of the corresponding edges from the edge set. -It is fine to delete edges outside the edge set. -/ +/-- Given a set of vertex pairs, remove all of the corresponding edges from the +graph's edge set, if present. + +See also: `simple_graph.subgraph.delete_edges`. -/ def delete_edges (s : set (sym2 V)) : simple_graph V := { adj := G.adj \ sym2.to_rel s, symm := λ a b, by simp [adj_comm, sym2.eq_swap] } diff --git a/src/combinatorics/simple_graph/subgraph.lean b/src/combinatorics/simple_graph/subgraph.lean index 943b22372c0be..c74b205190a7d 100644 --- a/src/combinatorics/simple_graph/subgraph.lean +++ b/src/combinatorics/simple_graph/subgraph.lean @@ -74,7 +74,7 @@ lemma adj_comm (G' : subgraph G) (v w : V) : G'.adj v w ↔ G'.adj w v := @[symm] lemma adj_symm (G' : subgraph G) {u v : V} (h : G'.adj u v) : G'.adj v u := G'.symm h /-- Coercion from `G' : subgraph G` to a `simple_graph ↥G'.verts`. -/ -@[simps] def coe (G' : subgraph G) : simple_graph G'.verts := +@[simps] protected def coe (G' : subgraph G) : simple_graph G'.verts := { adj := λ v w, G'.adj v w, symm := λ v w h, G'.symm h, loopless := λ v h, loopless G v (G'.adj_sub h) } @@ -91,7 +91,7 @@ set.eq_univ_iff_forall.symm /-- Coercion from `subgraph G` to `simple_graph V`. If `G'` is a spanning subgraph, then `G'.spanning_coe` yields an isomorphic graph. In general, this adds in all vertices from `V` as isolated vertices. -/ -@[simps] def spanning_coe (G' : subgraph G) : simple_graph V := +@[simps] protected def spanning_coe (G' : subgraph G) : simple_graph V := { adj := G'.adj, symm := G'.symm, loopless := λ v hv, G.loopless v (G'.adj_sub hv) } @@ -432,6 +432,89 @@ begin simp only [set.mem_to_finset, mem_neighbor_set], end +/-! ## Edge deletion -/ + +/-- Given a subgraph `G'` and a set of vertex pairs, remove all of the corresponding edges +from its edge set, if present. + +See also: `simple_graph.delete_edges`. -/ +def delete_edges (G' : G.subgraph) (s : set (sym2 V)) : G.subgraph := +{ verts := G'.verts, + adj := G'.adj \ sym2.to_rel s, + adj_sub := λ a b h', G'.adj_sub h'.1, + edge_vert := λ a b h', G'.edge_vert h'.1, + symm := λ a b, by simp [G'.adj_comm, sym2.eq_swap] } + +section delete_edges +variables {G' : G.subgraph} (s : set (sym2 V)) + +@[simp] lemma delete_edges_verts : (G'.delete_edges s).verts = G'.verts := rfl + +@[simp] lemma delete_edges_adj (v w : V) : + (G'.delete_edges s).adj v w ↔ G'.adj v w ∧ ¬ ⟦(v, w)⟧ ∈ s := iff.rfl + +@[simp] lemma delete_edges_delete_edges (s s' : set (sym2 V)) : + (G'.delete_edges s).delete_edges s' = G'.delete_edges (s ∪ s') := +by ext; simp [and_assoc, not_or_distrib] + +@[simp] lemma delete_edges_empty_eq : G'.delete_edges ∅ = G' := +by ext; simp + +@[simp] lemma delete_edges_spanning_coe_eq : + G'.spanning_coe.delete_edges s = (G'.delete_edges s).spanning_coe := +by { ext, simp } + +lemma delete_edges_coe_eq (s : set (sym2 G'.verts)) : + G'.coe.delete_edges s = (G'.delete_edges (sym2.map coe '' s)).coe := +begin + ext ⟨v, hv⟩ ⟨w, hw⟩, + simp only [simple_graph.delete_edges_adj, coe_adj, subtype.coe_mk, delete_edges_adj, + set.mem_image, not_exists, not_and, and.congr_right_iff], + intro h, + split, + { intros hs, + refine sym2.ind _, + rintro ⟨v', hv'⟩ ⟨w', hw'⟩, + simp only [sym2.map_pair_eq, subtype.coe_mk, quotient.eq], + contrapose!, + rintro (_ | _); simpa [sym2.eq_swap], }, + { intros h' hs, + exact h' _ hs rfl, }, +end + +lemma coe_delete_edges_eq (s : set (sym2 V)) : + (G'.delete_edges s).coe = G'.coe.delete_edges (sym2.map coe ⁻¹' s) := +by { ext ⟨v, hv⟩ ⟨w, hw⟩, simp } + +lemma delete_edges_le : G'.delete_edges s ≤ G' := +by split; simp { contextual := tt } + +lemma delete_edges_le_of_le {s s' : set (sym2 V)} (h : s ⊆ s') : + G'.delete_edges s' ≤ G'.delete_edges s := +begin + split; + simp only [delete_edges_verts, delete_edges_adj, true_and, and_imp] {contextual := tt}, + exact λ v w hvw hs' hs, hs' (h hs), +end + +@[simp] lemma delete_edges_inter_edge_set_left_eq : + G'.delete_edges (G'.edge_set ∩ s) = G'.delete_edges s := +by ext; simp [imp_false] { contextual := tt } + +@[simp] lemma delete_edges_inter_edge_set_right_eq : + G'.delete_edges (s ∩ G'.edge_set) = G'.delete_edges s := +by ext; simp [imp_false] { contextual := tt } + +lemma coe_delete_edges_le : + (G'.delete_edges s).coe ≤ (G'.coe : simple_graph G'.verts) := +λ v w, by simp { contextual := tt } + +lemma spanning_coe_delete_edges_le (G' : G.subgraph) (s : set (sym2 V)) : + (G'.delete_edges s).spanning_coe ≤ G'.spanning_coe := +spanning_coe_le_of_le (delete_edges_le s) + +end delete_edges + end subgraph end simple_graph From d13f291b4f9194b0cc1e49e5fe356a7ff9ea0972 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Fri, 15 Apr 2022 10:39:09 +0000 Subject: [PATCH 036/373] feat(group_theory/group_action/conj_act): conjugation by the units of a monoid (#13439) I suspect we can make this even more general in future by introducing a compatibility typeclass, but this is good enough for me for now. This also adds a stronger typeclass for the existing action of `conj_act K` where `K` is a `division_ring`. --- src/group_theory/group_action/conj_act.lean | 62 ++++++++++++++++++--- 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/src/group_theory/group_action/conj_act.lean b/src/group_theory/group_action/conj_act.lean index a6fedd77833b8..a24437af312be 100644 --- a/src/group_theory/group_action/conj_act.lean +++ b/src/group_theory/group_action/conj_act.lean @@ -5,6 +5,7 @@ Authors: Chris Hughes -/ import group_theory.group_action.basic import group_theory.subgroup.basic +import algebra.group_ring_action /-! # Conjugation action of a group on itself @@ -16,6 +17,10 @@ the definition of conjugation as a homomorphism into the automorphism group. A type alias `conj_act G` is introduced for a group `G`. The group `conj_act G` acts on `G` by conjugation. The group `conj_act G` also acts on any normal subgroup of `G` by conjugation. +As a generalization, this also allows: +* `conj_act Mˣ` to act on `M`, when `M` is a `monoid` +* `conj_act G₀` to act on `G₀`, when `G₀` is a `group_with_zero` + ## Implementation Notes The scalar action in defined in this file can also be written using `mul_aut.conj g • h`. This @@ -25,7 +30,7 @@ is that some theorems about the group actions will not apply when since this -/ -variables (G : Type*) +variables (M G G₀ R K : Type*) /-- A type alias for a group `G`. `conj_act G` acts on `G` by conjugation -/ def conj_act : Type* := G @@ -33,7 +38,7 @@ def conj_act : Type* := G namespace conj_act open mul_action subgroup -variable {G} +variables {M G G₀ R K} instance : Π [group G], group (conj_act G) := id instance : Π [div_inv_monoid G], div_inv_monoid (conj_act G) := id @@ -80,20 +85,63 @@ lemma smul_def (g : conj_act G) (h : G) : g • h = of_conj_act g * h * (of_conj end div_inv_monoid -section group_with_zero +section units + +section monoid +variables [monoid M] + +instance has_units_scalar : has_scalar (conj_act Mˣ) M := +{ smul := λ g h, of_conj_act g * h * ↑(of_conj_act g)⁻¹ } + +lemma units_smul_def (g : conj_act Mˣ) (h : M) : g • h = of_conj_act g * h * ↑(of_conj_act g)⁻¹ := +rfl + +instance units_mul_distrib_mul_action : mul_distrib_mul_action (conj_act Mˣ) M := +{ smul := (•), + one_smul := by simp [units_smul_def], + mul_smul := by simp [units_smul_def, mul_assoc, mul_inv_rev₀], + smul_mul := by simp [units_smul_def, mul_assoc], + smul_one := by simp [units_smul_def], } + +end monoid + +section semiring +variables [semiring R] -variable [group_with_zero G] +instance units_mul_semiring_action : mul_semiring_action (conj_act Rˣ) R := +{ smul := (•), + smul_zero := by simp [units_smul_def], + smul_add := by simp [units_smul_def, mul_add, add_mul], + ..conj_act.units_mul_distrib_mul_action} + +end semiring + +end units + +section group_with_zero +variable [group_with_zero G₀] -@[simp] lemma of_conj_act_zero : of_conj_act (0 : conj_act G) = 0 := rfl -@[simp] lemma to_conj_act_zero : to_conj_act (0 : G) = 0 := rfl +@[simp] lemma of_conj_act_zero : of_conj_act (0 : conj_act G₀) = 0 := rfl +@[simp] lemma to_conj_act_zero : to_conj_act (0 : G₀) = 0 := rfl -instance : mul_action (conj_act G) G := +instance mul_action₀ : mul_action (conj_act G₀) G₀ := { smul := (•), one_smul := by simp [smul_def], mul_smul := by simp [smul_def, mul_assoc, mul_inv_rev₀] } end group_with_zero +section division_ring +variables [division_ring K] + +instance distrib_mul_action₀ : distrib_mul_action (conj_act K) K := +{ smul := (•), + smul_zero := by simp [smul_def], + smul_add := by simp [smul_def, mul_add, add_mul], + ..conj_act.mul_action₀ } + +end division_ring + variables [group G] instance : mul_distrib_mul_action (conj_act G) G := From ebc8b441f8f602d8b0cf28c201056bfc0c86bc9c Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Fri, 15 Apr 2022 11:12:38 +0000 Subject: [PATCH 037/373] feat(analysis/normed_space/basic): `pi` and `prod` are `normed_algebra`s (#13442) Note that over an empty index type, `pi` is not a normed_algebra since it is trivial as a ring. --- src/analysis/normed_space/basic.lean | 24 +++++++++++++++++++ src/measure_theory/measure/haar_lebesgue.lean | 5 ++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/analysis/normed_space/basic.lean b/src/analysis/normed_space/basic.lean index 140c3a472a96d..2c50fa293e94b 100644 --- a/src/analysis/normed_space/basic.lean +++ b/src/analysis/normed_space/basic.lean @@ -348,6 +348,10 @@ class normed_algebra (𝕜 : Type*) (𝕜' : Type*) [normed_field 𝕜] [semi_no [h : normed_algebra 𝕜 𝕜'] (x : 𝕜) : ∥algebra_map 𝕜 𝕜' x∥ = ∥x∥ := normed_algebra.norm_algebra_map_eq _ +@[simp] lemma nnorm_algebra_map_eq {𝕜 : Type*} (𝕜' : Type*) [normed_field 𝕜] [semi_normed_ring 𝕜'] + [h : normed_algebra 𝕜 𝕜'] (x : 𝕜) : ∥algebra_map 𝕜 𝕜' x∥₊ = ∥x∥₊ := +subtype.ext $ normed_algebra.norm_algebra_map_eq _ + /-- In a normed algebra, the inclusion of the base field in the extended field is an isometry. -/ lemma algebra_map_isometry (𝕜 : Type*) (𝕜' : Type*) [normed_field 𝕜] [semi_normed_ring 𝕜'] [normed_algebra 𝕜 𝕜'] : isometry (algebra_map 𝕜 𝕜') := @@ -429,6 +433,26 @@ instance normed_algebra_rat {𝕜} [normed_division_ring 𝕜] [char_zero 𝕜] { norm_algebra_map_eq := λ q, by simpa only [ring_hom.map_rat_algebra_map] using norm_algebra_map_eq 𝕜 (algebra_map _ ℝ q) } +/-- The product of two normed algebras is a normed algebra, with the sup norm. -/ +instance prod.normed_algebra {E F : Type*} [semi_normed_ring E] [semi_normed_ring F] + [normed_algebra 𝕜 E] [normed_algebra 𝕜 F] : + normed_algebra 𝕜 (E × F) := +{ norm_algebra_map_eq := λ x, begin + dsimp [prod.norm_def], + rw [norm_algebra_map_eq, norm_algebra_map_eq, max_self], + end } + +/-- The product of finitely many normed algebras is a normed algebra, with the sup norm. -/ +instance pi.normed_algebra {E : ι → Type*} [fintype ι] [nonempty ι] + [Π i, semi_normed_ring (E i)] [Π i, normed_algebra 𝕜 (E i)] : + normed_algebra 𝕜 (Π i, E i) := +{ norm_algebra_map_eq := λ x, begin + dsimp [has_norm.norm], + simp_rw [pi.algebra_map_apply ι E, nnorm_algebra_map_eq, ←coe_nnnorm], + rw finset.sup_const (@finset.univ_nonempty ι _ _) _, + end, + .. pi.algebra _ E } + end normed_algebra section restrict_scalars diff --git a/src/measure_theory/measure/haar_lebesgue.lean b/src/measure_theory/measure/haar_lebesgue.lean index 557c3a7ed4763..6d9e86eb8b61c 100644 --- a/src/measure_theory/measure/haar_lebesgue.lean +++ b/src/measure_theory/measure/haar_lebesgue.lean @@ -195,9 +195,8 @@ begin /- We have already proved the result for the Lebesgue product measure, using matrices. We deduce it for any Haar measure by uniqueness (up to scalar multiplication). -/ have := add_haar_measure_unique μ (pi_Icc01 ι), - rw this, - simp [add_haar_measure_eq_volume_pi, real.map_linear_map_volume_pi_eq_smul_volume_pi hf, - smul_smul, mul_comm], + rw [this, add_haar_measure_eq_volume_pi, map_smul, + real.map_linear_map_volume_pi_eq_smul_volume_pi hf, smul_comm], end lemma map_linear_map_add_haar_eq_smul_add_haar From bbbea1c17a0d4c4b3898b7fb8be93c7ddcb8421a Mon Sep 17 00:00:00 2001 From: Alex J Best Date: Fri, 15 Apr 2022 13:10:57 +0000 Subject: [PATCH 038/373] chore(*): clean up unnecessary uses of nat.cases_on (#13454) --- src/algebra/group_power/lemmas.lean | 5 ++--- src/algebra/group_with_zero/power.lean | 5 ++--- src/algebra/homology/augment.lean | 14 +++++++------- src/data/int/basic.lean | 18 ++++++------------ src/data/list/rotate.lean | 2 +- src/data/nat/basic.lean | 4 +--- src/data/nat/log.lean | 5 ++--- src/data/polynomial/inductions.lean | 2 +- src/group_theory/specific_groups/dihedral.lean | 8 +++----- .../specific_groups/quaternion.lean | 8 +++----- src/logic/equiv/fin.lean | 2 +- src/ring_theory/polynomial/pochhammer.lean | 8 +++----- src/set_theory/surreal/dyadic.lean | 4 ++-- 13 files changed, 34 insertions(+), 51 deletions(-) diff --git a/src/algebra/group_power/lemmas.lean b/src/algebra/group_power/lemmas.lean index 66945fed82301..1c1443ed08cfc 100644 --- a/src/algebra/group_power/lemmas.lean +++ b/src/algebra/group_power/lemmas.lean @@ -110,9 +110,8 @@ by cases n; simp @[to_additive add_one_zsmul] lemma zpow_add_one (a : G) : ∀ n : ℤ, a ^ (n + 1) = a ^ n * a | (of_nat n) := by simp [← int.coe_nat_succ, pow_succ'] -| -[1+0] := by simp [int.neg_succ_of_nat_eq] -| -[1+(n+1)] := by rw [int.neg_succ_of_nat_eq, zpow_neg, neg_add, neg_add_cancel_right, zpow_neg, - ← int.coe_nat_succ, zpow_coe_nat, zpow_coe_nat, pow_succ _ (n + 1), mul_inv_rev, +| -[1+n] := by rw [int.neg_succ_of_nat_eq, zpow_neg, neg_add, neg_add_cancel_right, zpow_neg, + ← int.coe_nat_succ, zpow_coe_nat, zpow_coe_nat, pow_succ _ n, mul_inv_rev, inv_mul_cancel_right] @[to_additive zsmul_sub_one] diff --git a/src/algebra/group_with_zero/power.lean b/src/algebra/group_with_zero/power.lean index 747c297e37398..fc8779c1291ca 100644 --- a/src/algebra/group_with_zero/power.lean +++ b/src/algebra/group_with_zero/power.lean @@ -111,9 +111,8 @@ theorem inv_zpow₀ (a : G₀) : ∀n:ℤ, a⁻¹ ^ n = (a ^ n)⁻¹ lemma zpow_add_one₀ {a : G₀} (ha : a ≠ 0) : ∀ n : ℤ, a ^ (n + 1) = a ^ n * a | (n : ℕ) := by simp [← int.coe_nat_succ, pow_succ'] -| -[1+0] := by simp [int.neg_succ_of_nat_eq, ha] -| -[1+(n+1)] := by rw [int.neg_succ_of_nat_eq, zpow_neg₀, neg_add, neg_add_cancel_right, zpow_neg₀, - ← int.coe_nat_succ, zpow_coe_nat, zpow_coe_nat, pow_succ _ (n + 1), mul_inv_rev₀, mul_assoc, +| -[1+n] := by rw [int.neg_succ_of_nat_eq, zpow_neg₀, neg_add, neg_add_cancel_right, zpow_neg₀, + ← int.coe_nat_succ, zpow_coe_nat, zpow_coe_nat, pow_succ _ n, mul_inv_rev₀, mul_assoc, inv_mul_cancel ha, mul_one] lemma zpow_sub_one₀ {a : G₀} (ha : a ≠ 0) (n : ℤ) : a ^ (n - 1) = a ^ n * a⁻¹ := diff --git a/src/algebra/homology/augment.lean b/src/algebra/homology/augment.lean index 3b4d1154223f8..1b26ec1f02249 100644 --- a/src/algebra/homology/augment.lean +++ b/src/algebra/homology/augment.lean @@ -101,8 +101,8 @@ def truncate_augment (C : chain_complex V ℕ) {X : V} (f : C.X 0 ⟶ X) (w : C. { hom := { f := λ i, 𝟙 _, }, inv := - { f := λ i, by { cases i; exact 𝟙 _, }, - comm' := λ i j, by { cases i; cases j; { dsimp, simp, }, }, }, + { f := λ i, by { exact 𝟙 _, }, + comm' := λ i j, by { cases j; { dsimp, simp, }, }, }, hom_inv_id' := by { ext i, cases i; { dsimp, simp, }, }, inv_hom_id' := by { ext i, cases i; { dsimp, simp, }, }, }. @@ -112,7 +112,7 @@ def truncate_augment (C : chain_complex V ℕ) {X : V} (f : C.X 0 ⟶ X) (w : C. @[simp] lemma truncate_augment_inv_f (C : chain_complex V ℕ) {X : V} (f : C.X 0 ⟶ X) (w : C.d 1 0 ≫ f = 0) (i : ℕ) : (truncate_augment C f w).inv.f i = 𝟙 ((truncate.obj (augment C f w)).X i) := -by { cases i; refl, } +rfl @[simp] lemma chain_complex_d_succ_succ_zero (C : chain_complex V ℕ) (i : ℕ) : C.d (i+2) 0 = 0 := @@ -230,7 +230,7 @@ def augment (C : cochain_complex V ℕ) {X : V} (f : X ⟶ C.X 0) (w : f ≫ C.d @[simp] lemma augment_d_succ_succ (C : cochain_complex V ℕ) {X : V} (f : X ⟶ C.X 0) (w : f ≫ C.d 0 1 = 0) (i j : ℕ) : (augment C f w).d (i+1) (j+1) = C.d i j := -by { dsimp [augment], rcases i with _|i, refl, refl, } +rfl /-- Truncating an augmented cochain complex is isomorphic (with components the identity) @@ -241,8 +241,8 @@ def truncate_augment (C : cochain_complex V ℕ) {X : V} (f : X ⟶ C.X 0) (w : { hom := { f := λ i, 𝟙 _, }, inv := - { f := λ i, by { cases i; exact 𝟙 _, }, - comm' := λ i j, by { cases i; cases j; { dsimp, simp, }, }, }, + { f := λ i, by { exact 𝟙 _, }, + comm' := λ i j, by { cases j; { dsimp, simp, }, }, }, hom_inv_id' := by { ext i, cases i; { dsimp, simp, }, }, inv_hom_id' := by { ext i, cases i; { dsimp, simp, }, }, }. @@ -252,7 +252,7 @@ def truncate_augment (C : cochain_complex V ℕ) {X : V} (f : X ⟶ C.X 0) (w : @[simp] lemma truncate_augment_inv_f (C : cochain_complex V ℕ) {X : V} (f : X ⟶ C.X 0) (w : f ≫ C.d 0 1 = 0) (i : ℕ) : (truncate_augment C f w).inv.f i = 𝟙 ((truncate.obj (augment C f w)).X i) := -by { cases i; refl, } +rfl @[simp] lemma cochain_complex_d_succ_succ_zero (C : cochain_complex V ℕ) (i : ℕ) : C.d 0 (i+2) = 0 := diff --git a/src/data/int/basic.lean b/src/data/int/basic.lean index 40f7c055d1e5c..c89d3aa9ed0bf 100644 --- a/src/data/int/basic.lean +++ b/src/data/int/basic.lean @@ -430,21 +430,18 @@ match b, eq_succ_of_zero_lt H with ._, ⟨n, rfl⟩ := rfl end -- Will be generalized to Euclidean domains. local attribute [simp] protected theorem zero_div : ∀ (b : ℤ), 0 / b = 0 -| 0 := show of_nat _ = _, by simp -| (n+1:ℕ) := show of_nat _ = _, by simp +| (n:ℕ) := show of_nat _ = _, by simp | -[1+ n] := show -of_nat _ = _, by simp local attribute [simp] -- Will be generalized to Euclidean domains. protected theorem div_zero : ∀ (a : ℤ), a / 0 = 0 -| 0 := show of_nat _ = _, by simp -| (n+1:ℕ) := show of_nat _ = _, by simp +| (n:ℕ) := show of_nat _ = _, by simp | -[1+ n] := rfl @[simp] protected theorem div_neg : ∀ (a b : ℤ), a / -b = -(a / b) | (m : ℕ) 0 := show of_nat (m / 0) = -(m / 0 : ℕ), by rw nat.div_zero; refl | (m : ℕ) (n+1:ℕ) := rfl -| 0 -[1+ n] := by simp -| (m+1:ℕ) -[1+ n] := (neg_neg _).symm +| (m : ℕ) -[1+ n] := (neg_neg _).symm | -[1+ m] 0 := rfl | -[1+ m] (n+1:ℕ) := rfl | -[1+ m] -[1+ n] := rfl @@ -470,8 +467,7 @@ match a, b, eq_neg_succ_of_lt_zero Ha, eq_succ_of_zero_lt Hb with end @[simp] protected theorem div_one : ∀ (a : ℤ), a / 1 = a -| 0 := show of_nat _ = _, by simp -| (n+1:ℕ) := congr_arg of_nat (nat.div_one _) +| (n:ℕ) := congr_arg of_nat (nat.div_one _) | -[1+ n] := congr_arg neg_succ_of_nat (nat.div_one _) theorem div_eq_zero_of_lt {a b : ℤ} (H1 : 0 ≤ a) (H2 : a < b) : a / b = 0 := @@ -612,10 +608,8 @@ begin end theorem mod_add_div : ∀ (a b : ℤ), a % b + b * (a / b) = a -| (m : ℕ) 0 := congr_arg of_nat (nat.mod_add_div _ _) -| (m : ℕ) (n+1:ℕ) := congr_arg of_nat (nat.mod_add_div _ _) -| 0 -[1+ n] := by simp -| (m+1:ℕ) -[1+ n] := show (_ + -(n+1) * -((m + 1) / (n + 1) : ℕ) : ℤ) = _, +| (m : ℕ) (n : ℕ) := congr_arg of_nat (nat.mod_add_div _ _) +| (m : ℕ) -[1+ n] := show (_ + -(n+1) * -((m) / (n + 1) : ℕ) : ℤ) = _, by rw [neg_mul_neg]; exact congr_arg of_nat (nat.mod_add_div _ _) | -[1+ m] 0 := by rw [mod_zero, int.div_zero]; refl | -[1+ m] (n+1:ℕ) := mod_add_div_aux m n.succ diff --git a/src/data/list/rotate.lean b/src/data/list/rotate.lean index e5efd4564916c..b1ba189819b28 100644 --- a/src/data/list/rotate.lean +++ b/src/data/list/rotate.lean @@ -31,7 +31,7 @@ namespace list lemma rotate_mod (l : list α) (n : ℕ) : l.rotate (n % l.length) = l.rotate n := by simp [rotate] -@[simp] lemma rotate_nil (n : ℕ) : ([] : list α).rotate n = [] := by cases n; simp [rotate] +@[simp] lemma rotate_nil (n : ℕ) : ([] : list α).rotate n = [] := by simp [rotate] @[simp] lemma rotate_zero (l : list α) : l.rotate 0 = l := by simp [rotate] diff --git a/src/data/nat/basic.lean b/src/data/nat/basic.lean index 6f0426f07ae03..b722cb1d05dd3 100644 --- a/src/data/nat/basic.lean +++ b/src/data/nat/basic.lean @@ -435,11 +435,9 @@ iff.intro lemma add_eq_one_iff : ∀ {a b : ℕ}, a + b = 1 ↔ (a = 0 ∧ b = 1) ∨ (a = 1 ∧ b = 0) | 0 0 := dec_trivial -| 0 1 := dec_trivial | 1 0 := dec_trivial -| 1 1 := dec_trivial | (a+2) _ := by rw add_right_comm; exact dec_trivial -| _ (b+2) := by rw [← add_assoc]; simp only [nat.succ_inj', nat.succ_ne_zero]; simp +| _ (b+1) := by rw [← add_assoc]; simp only [nat.succ_inj', nat.succ_ne_zero]; simp theorem le_add_one_iff {i j : ℕ} : i ≤ j + 1 ↔ (i ≤ j ∨ i = j + 1) := ⟨λ h, diff --git a/src/data/nat/log.lean b/src/data/nat/log.lean index 27fa58e3d5c90..fa01697bdebb5 100644 --- a/src/data/nat/log.lean +++ b/src/data/nat/log.lean @@ -303,11 +303,10 @@ end lemma clog_le_clog_of_left_ge {b c n : ℕ} (hc : 1 < c) (hb : c ≤ b) : clog b n ≤ clog c n := begin - cases n, { simp }, rw ← le_pow_iff_clog_le (lt_of_lt_of_le hc hb), calc - n.succ ≤ c ^ clog c n.succ : le_pow_clog hc _ - ... ≤ b ^ clog c n.succ : pow_le_pow_of_le_left (le_of_lt $ zero_lt_one.trans hc) hb _ + n ≤ c ^ clog c n : le_pow_clog hc _ + ... ≤ b ^ clog c n : pow_le_pow_of_le_left (le_of_lt $ zero_lt_one.trans hc) hb _ end lemma clog_monotone (b : ℕ) : monotone (clog b) := diff --git a/src/data/polynomial/inductions.lean b/src/data/polynomial/inductions.lean index eebc4c93969a8..22d2f03d1b60c 100644 --- a/src/data/polynomial/inductions.lean +++ b/src/data/polynomial/inductions.lean @@ -41,7 +41,7 @@ lemma div_X_mul_X_add (p : R[X]) : div_X p * X + C (p.coeff 0) = p := ext $ by rintro ⟨_|_⟩; simp [coeff_C, nat.succ_ne_zero, coeff_mul_X] @[simp] lemma div_X_C (a : R) : div_X (C a) = 0 := -ext $ λ n, by cases n; simp [div_X, coeff_C]; simp [coeff] +ext $ λ n, by simp [div_X, coeff_C]; simp [coeff] lemma div_X_eq_zero_iff : div_X p = 0 ↔ p = C (p.coeff 0) := ⟨λ h, by simpa [eq_comm, h] using div_X_mul_X_add p, diff --git a/src/group_theory/specific_groups/dihedral.lean b/src/group_theory/specific_groups/dihedral.lean index 8f396d7436b4c..3ab5aedac3eb7 100644 --- a/src/group_theory/specific_groups/dihedral.lean +++ b/src/group_theory/specific_groups/dihedral.lean @@ -129,11 +129,9 @@ end @[simp] lemma r_one_pow_n : (r (1 : zmod n))^n = 1 := begin - cases n, - { rw pow_zero }, - { rw [r_one_pow, one_def], - congr' 1, - exact zmod.nat_cast_self _, } + rw [r_one_pow, one_def], + congr' 1, + exact zmod.nat_cast_self _, end @[simp] lemma sr_mul_self (i : zmod n) : sr i * sr i = 1 := by rw [sr_mul_sr, sub_self, one_def] diff --git a/src/group_theory/specific_groups/quaternion.lean b/src/group_theory/specific_groups/quaternion.lean index b00fe8563111a..8efd4b9431144 100644 --- a/src/group_theory/specific_groups/quaternion.lean +++ b/src/group_theory/specific_groups/quaternion.lean @@ -183,11 +183,9 @@ end @[simp] lemma a_one_pow_n : (a 1 : quaternion_group n)^(2 * n) = 1 := begin - cases n, - { simp_rw [mul_zero, pow_zero] }, - { rw [a_one_pow, one_def], - congr' 1, - exact zmod.nat_cast_self _ } + rw [a_one_pow, one_def], + congr' 1, + exact zmod.nat_cast_self _ end @[simp] lemma xa_sq (i : zmod (2 * n)) : xa i ^ 2 = a n := diff --git a/src/logic/equiv/fin.lean b/src/logic/equiv/fin.lean index 5a5222974af04..4c3f2ccf2db8d 100644 --- a/src/logic/equiv/fin.lean +++ b/src/logic/equiv/fin.lean @@ -163,7 +163,7 @@ fin_succ_equiv' 0 @[simp] lemma fin_succ_equiv_zero {n : ℕ} : (fin_succ_equiv n) 0 = none := -by cases n; refl +rfl @[simp] lemma fin_succ_equiv_succ {n : ℕ} (m : fin n): (fin_succ_equiv n) m.succ = some m := diff --git a/src/ring_theory/polynomial/pochhammer.lean b/src/ring_theory/polynomial/pochhammer.lean index 8c02bc3fc3a78..81f5de17ff7a7 100644 --- a/src/ring_theory/polynomial/pochhammer.lean +++ b/src/ring_theory/polynomial/pochhammer.lean @@ -104,11 +104,9 @@ begin suffices : (pochhammer ℕ (n + 1)).comp (X + 1) = pochhammer ℕ (n + 1) + (n + 1) * (pochhammer ℕ n).comp (X + 1), { simpa [map_comp] using congr_arg (polynomial.map (nat.cast_ring_hom S)) this }, - cases n, - { simp }, - { nth_rewrite 1 pochhammer_succ_left, - rw [← add_mul, pochhammer_succ_right ℕ (n + 1), mul_comp, mul_comm, add_comp, X_comp, - nat_cast_comp, add_comm ↑(n + 1), ← add_assoc] } + nth_rewrite 1 pochhammer_succ_left, + rw [← add_mul, pochhammer_succ_right ℕ n, mul_comp, mul_comm, add_comp, X_comp, + nat_cast_comp, add_comm ↑n, ← add_assoc] end lemma polynomial.mul_X_add_nat_cast_comp {p q : S[X]} {n : ℕ} : diff --git a/src/set_theory/surreal/dyadic.lean b/src/set_theory/surreal/dyadic.lean index e5e91222366ef..c03bd59a2675f 100644 --- a/src/set_theory/surreal/dyadic.lean +++ b/src/set_theory/surreal/dyadic.lean @@ -41,13 +41,13 @@ def pow_half : ℕ → pgame by cases n; refl @[simp] lemma pow_half_right_moves {n} : (pow_half (n + 1)).right_moves = punit := -by cases n; refl +rfl @[simp] lemma pow_half_move_left {n i} : (pow_half n).move_left i = 0 := by cases n; cases i; refl @[simp] lemma pow_half_move_right {n i} : (pow_half (n + 1)).move_right i = pow_half n := -by cases n; cases i; refl +rfl lemma pow_half_move_left' (n) : (pow_half n).move_left (equiv.cast (pow_half_left_moves.symm) punit.star) = 0 := From c65bebb5a0781bf162bfba9a652e6b122681ebfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20In=C3=A9s=20de=20Frutos-Fern=C3=A1ndez?= Date: Fri, 15 Apr 2022 15:03:05 +0000 Subject: [PATCH 039/373] feat(number_theory/padics/padic_numbers): add padic.add_valuation (#12939) We define the p-adic additive valuation on `Q_[p]`, as an `add_valuation` with values in `with_top Z`. --- src/number_theory/padics/padic_numbers.lean | 80 +++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/number_theory/padics/padic_numbers.lean b/src/number_theory/padics/padic_numbers.lean index b78056a456626..5eac8cfc4797d 100644 --- a/src/number_theory/padics/padic_numbers.lean +++ b/src/number_theory/padics/padic_numbers.lean @@ -18,6 +18,7 @@ and that `ℚ_p` is Cauchy complete. * `padic` : the type of p-adic numbers * `padic_norm_e` : the rational valued p-adic norm on `ℚ_p` +* `padic.add_valuation` : the additive `p`-adic valuation on `ℚ_p`, with values in `with_top ℤ`. ## Notation @@ -1037,6 +1038,85 @@ begin { exact_mod_cast (fact.out p.prime).ne_zero } end +lemma valuation_map_add {x y : ℚ_[p]} (hxy : x + y ≠ 0) : + min (valuation x) (valuation y) ≤ valuation (x + y) := +begin + by_cases hx : x = 0, + { rw [hx, zero_add], + exact min_le_right _ _ }, + { by_cases hy : y = 0, + { rw [hy, add_zero], + exact min_le_left _ _ }, + { have h_norm : ∥x + y∥ ≤ (max ∥x∥ ∥y∥) := padic_norm_e.nonarchimedean x y, + have hp_one : (1 : ℝ) < p, + { rw [← nat.cast_one, nat.cast_lt], + exact nat.prime.one_lt hp_prime.elim, }, + rw [norm_eq_pow_val hx, norm_eq_pow_val hy, norm_eq_pow_val hxy] at h_norm, + exact min_le_of_zpow_le_max hp_one h_norm }} +end + +@[simp] lemma valuation_map_mul {x y : ℚ_[p]} (hx : x ≠ 0) (hy : y ≠ 0) : + valuation (x * y) = valuation x + valuation y := +begin + have h_norm : ∥x * y∥ = ∥x∥ * ∥y∥ := norm_mul x y, + have hp_ne_one : (p : ℝ) ≠ 1, + { rw [← nat.cast_one, ne.def, nat.cast_inj], + exact nat.prime.ne_one hp_prime.elim, }, + have hp_pos : (0 : ℝ) < p, + { rw [← nat.cast_zero, nat.cast_lt], + exact nat.prime.pos hp_prime.elim }, + rw [norm_eq_pow_val hx, norm_eq_pow_val hy, norm_eq_pow_val (mul_ne_zero hx hy), + ← zpow_add₀ (ne_of_gt hp_pos), zpow_inj hp_pos hp_ne_one, ← neg_add, neg_inj] at h_norm, + exact h_norm, +end + +/-- The additive p-adic valuation on `ℚ_p`, with values in `with_top ℤ`. -/ +def add_valuation_def : ℚ_[p] → (with_top ℤ) := +λ x, if x = 0 then ⊤ else x.valuation + +@[simp] lemma add_valuation.map_zero : add_valuation_def (0 : ℚ_[p]) = ⊤ := +by simp only [add_valuation_def, if_pos (eq.refl _)] + +@[simp] lemma add_valuation.map_one : add_valuation_def (1 : ℚ_[p]) = 0 := +by simp only [add_valuation_def, if_neg (one_ne_zero), valuation_one, + with_top.coe_zero] + +lemma add_valuation.map_mul (x y : ℚ_[p]) : + add_valuation_def (x * y) = add_valuation_def x + add_valuation_def y := +begin + simp only [add_valuation_def], + by_cases hx : x = 0, + { rw [hx, if_pos (eq.refl _), zero_mul, if_pos (eq.refl _), with_top.top_add] }, + { by_cases hy : y = 0, + { rw [hy, if_pos (eq.refl _), mul_zero, if_pos (eq.refl _), with_top.add_top] }, + { rw [if_neg hx, if_neg hy, if_neg (mul_ne_zero hx hy), ← with_top.coe_add, + with_top.coe_eq_coe, valuation_map_mul hx hy] }} +end + +lemma add_valuation.map_add (x y : ℚ_[p]) : + min (add_valuation_def x) (add_valuation_def y) ≤ add_valuation_def (x + y) := +begin + simp only [add_valuation_def], + by_cases hxy : x + y = 0, + { rw [hxy, if_pos (eq.refl _)], + exact le_top, }, + { by_cases hx : x = 0, + { simp only [hx, if_pos (eq.refl _), min_eq_right, le_top, zero_add, le_refl] }, + { by_cases hy : y = 0, + { simp only [hy, if_pos (eq.refl _), min_eq_left, le_top, add_zero, le_refl], }, + { rw [if_neg hx, if_neg hy, if_neg hxy, ← with_top.coe_min, with_top.coe_le_coe], + exact valuation_map_add hxy }}} +end + +/-- The additive `p`-adic valuation on `ℚ_p`, as an `add_valuation`. -/ +def add_valuation : add_valuation ℚ_[p] (with_top ℤ) := +add_valuation.of add_valuation_def add_valuation.map_zero add_valuation.map_one + add_valuation.map_add add_valuation.map_mul + +@[simp] lemma add_valuation.apply {x : ℚ_[p]} (hx : x ≠ 0) : + x.add_valuation = x.valuation := +by simp only [add_valuation, add_valuation.of_apply, add_valuation_def, if_neg hx] + section norm_le_iff /-! ### Various characterizations of open unit balls -/ lemma norm_le_pow_iff_norm_lt_pow_add_one (x : ℚ_[p]) (n : ℤ) : From 2194eef23f2aaa72109edc5de4079495485a2328 Mon Sep 17 00:00:00 2001 From: Yuma Mizuno Date: Fri, 15 Apr 2022 15:03:06 +0000 Subject: [PATCH 040/373] chore(ring_theory/ideal/local_ring): generalize to semirings (#13341) --- src/logic/equiv/transfer_instance.lean | 2 +- src/number_theory/padics/padic_integers.lean | 2 +- src/ring_theory/discrete_valuation_ring.lean | 2 +- .../homogeneous_localization.lean | 46 +-- src/ring_theory/ideal/local_ring.lean | 282 ++++++++++-------- src/ring_theory/localization/at_prime.lean | 6 +- src/ring_theory/power_series/basic.lean | 6 +- src/ring_theory/valuation/valuation_ring.lean | 2 +- 8 files changed, 186 insertions(+), 162 deletions(-) diff --git a/src/logic/equiv/transfer_instance.lean b/src/logic/equiv/transfer_instance.lean index 3a7f354101c9f..9063a16cb87bf 100644 --- a/src/logic/equiv/transfer_instance.lean +++ b/src/logic/equiv/transfer_instance.lean @@ -387,7 +387,7 @@ protected lemma local_ring {A B : Type*} [comm_ring A] [local_ring A] [comm_ring local_ring B := begin haveI := e.symm.to_equiv.nontrivial, - refine @local_of_surjective A B _ _ _ _ e e.to_equiv.surjective, + refine @local_ring.of_surjective A B _ _ _ _ e e.to_equiv.surjective, end end ring_equiv diff --git a/src/number_theory/padics/padic_integers.lean b/src/number_theory/padics/padic_integers.lean index 53e79b9f2ef66..c33bd945866fc 100644 --- a/src/number_theory/padics/padic_integers.lean +++ b/src/number_theory/padics/padic_integers.lean @@ -537,7 +537,7 @@ section dvr /-! ### Discrete valuation ring -/ instance : local_ring ℤ_[p] := -local_of_nonunits_ideal zero_ne_one $ by simp only [mem_nonunits]; exact λ x h y, norm_lt_one_add h +local_ring.mk $ by simp only [mem_nonunits]; exact λ x y, norm_lt_one_add lemma p_nonnunit : (p : ℤ_[p]) ∈ nonunits ℤ_[p] := have (p : ℝ)⁻¹ < 1, from inv_lt_one $ by exact_mod_cast hp_prime.1.one_lt, diff --git a/src/ring_theory/discrete_valuation_ring.lean b/src/ring_theory/discrete_valuation_ring.lean index 25e705a425dc0..4e4685eb833e1 100644 --- a/src/ring_theory/discrete_valuation_ring.lean +++ b/src/ring_theory/discrete_valuation_ring.lean @@ -126,7 +126,7 @@ begin rw irreducible_iff_uniformizer at hQ2, exact hQ2.symm } }, { rintro ⟨RPID, Punique⟩, - haveI : local_ring R := local_of_unique_nonzero_prime R Punique, + haveI : local_ring R := local_ring.of_unique_nonzero_prime Punique, refine {not_a_field' := _}, rcases Punique with ⟨P, ⟨hP1, hP2⟩, hP3⟩, have hPM : P ≤ maximal_ideal R := le_maximal_ideal (hP2.1), diff --git a/src/ring_theory/graded_algebra/homogeneous_localization.lean b/src/ring_theory/graded_algebra/homogeneous_localization.lean index d10416d0e37a3..cae0fdc564539 100644 --- a/src/ring_theory/graded_algebra/homogeneous_localization.lean +++ b/src/ring_theory/graded_algebra/homogeneous_localization.lean @@ -470,28 +470,30 @@ end, λ ⟨⟨_, b, eq1, eq2⟩, rfl⟩, begin exact ⟨⟨f.val, b.val, eq1, eq2⟩, rfl⟩ end⟩ +instance : nontrivial (homogeneous_localization 𝒜 x) := +⟨⟨0, 1, λ r, by simpa [ext_iff_val, zero_val, one_val, zero_ne_one] using r⟩⟩ + instance : local_ring (homogeneous_localization 𝒜 x) := -{ exists_pair_ne := ⟨0, 1, λ r, by simpa [ext_iff_val, zero_val, one_val, zero_ne_one] using r⟩, - is_local := λ a, begin - simp only [← is_unit_iff_is_unit_val, sub_val, one_val], - induction a using quotient.induction_on', - simp only [homogeneous_localization.val_mk', ← subtype.val_eq_coe], - by_cases mem1 : a.num.1 ∈ x, - { right, - have : a.denom.1 - a.num.1 ∈ x.prime_compl := λ h, a.denom_not_mem - ((sub_add_cancel a.denom.val a.num.val) ▸ ideal.add_mem _ h mem1 : a.denom.1 ∈ x), - apply is_unit_of_mul_eq_one _ (localization.mk a.denom.1 ⟨a.denom.1 - a.num.1, this⟩), - simp only [sub_mul, localization.mk_mul, one_mul, localization.sub_mk, ← subtype.val_eq_coe, - submonoid.coe_mul], - convert localization.mk_self _, - simp only [← subtype.val_eq_coe, submonoid.coe_mul], - ring, }, - { left, - change _ ∈ x.prime_compl at mem1, - apply is_unit_of_mul_eq_one _ (localization.mk a.denom.1 ⟨a.num.1, mem1⟩), - rw [localization.mk_mul], - convert localization.mk_self _, - simpa only [mul_comm], }, -end } +local_ring.of_is_unit_or_is_unit_one_sub_self $ λ a, begin + simp only [← is_unit_iff_is_unit_val, sub_val, one_val], + induction a using quotient.induction_on', + simp only [homogeneous_localization.val_mk', ← subtype.val_eq_coe], + by_cases mem1 : a.num.1 ∈ x, + { right, + have : a.denom.1 - a.num.1 ∈ x.prime_compl := λ h, a.denom_not_mem + ((sub_add_cancel a.denom.val a.num.val) ▸ ideal.add_mem _ h mem1 : a.denom.1 ∈ x), + apply is_unit_of_mul_eq_one _ (localization.mk a.denom.1 ⟨a.denom.1 - a.num.1, this⟩), + simp only [sub_mul, localization.mk_mul, one_mul, localization.sub_mk, ← subtype.val_eq_coe, + submonoid.coe_mul], + convert localization.mk_self _, + simp only [← subtype.val_eq_coe, submonoid.coe_mul], + ring, }, + { left, + change _ ∈ x.prime_compl at mem1, + apply is_unit_of_mul_eq_one _ (localization.mk a.denom.1 ⟨a.num.1, mem1⟩), + rw [localization.mk_mul], + convert localization.mk_self _, + simpa only [mul_comm], }, +end end homogeneous_localization diff --git a/src/ring_theory/ideal/local_ring.lean b/src/ring_theory/ideal/local_ring.lean index 43ae70d0c96da..468799815127e 100644 --- a/src/ring_theory/ideal/local_ring.lean +++ b/src/ring_theory/ideal/local_ring.lean @@ -16,11 +16,11 @@ Define local rings as commutative rings having a unique maximal ideal. ## Main definitions -* `local_ring`: A predicate on commutative rings, stating that every element `a` is either a unit - or `1 - a` is a unit. This is shown to be equivalent to the condition that there exists a unique +* `local_ring`: A predicate on commutative semirings, stating that the set of nonunits is closed + under the addition. This is shown to be equivalent to the condition that there exists a unique maximal ideal. -* `local_ring.maximal_ideal`: The unique maximal ideal for a local rings. Its carrier set is the set - of non units. +* `local_ring.maximal_ideal`: The unique maximal ideal for a local rings. Its carrier set is the + set of non units. * `is_local_ring_hom`: A predicate on semiring homomorphisms, requiring that it maps nonunits to nonunits. For local rings, this means that the image of the unique maximal ideal is again contained in the unique maximal ideal. @@ -28,48 +28,45 @@ Define local rings as commutative rings having a unique maximal ideal. -/ -universes u v w +universes u v w u' -/-- A commutative ring is local if it has a unique maximal ideal. Note that - `local_ring` is a predicate. -/ -class local_ring (R : Type u) [comm_ring R] extends nontrivial R : Prop := -(is_local : ∀ (a : R), (is_unit a) ∨ (is_unit (1 - a))) +variables {R : Type u} {S : Type v} {T : Type w} {K : Type u'} -namespace local_ring - -variables {R : Type u} [comm_ring R] [local_ring R] +/-- A semiring is local if it is nontrivial and the set of nonunits is closed under the addition. +Note that `local_ring` is a predicate. -/ +class local_ring (R : Type u) [semiring R] extends nontrivial R : Prop := +(nonunits_add : ∀ {a b : R}, a ∈ nonunits R → b ∈ nonunits R → a + b ∈ nonunits R) -lemma is_unit_or_is_unit_one_sub_self (a : R) : - (is_unit a) ∨ (is_unit (1 - a)) := -is_local a - -lemma is_unit_of_mem_nonunits_one_sub_self (a : R) (h : (1 - a) ∈ nonunits R) : - is_unit a := -or_iff_not_imp_right.1 (is_local a) h +section comm_semiring +variables [comm_semiring R] -lemma is_unit_one_sub_self_of_mem_nonunits (a : R) (h : a ∈ nonunits R) : - is_unit (1 - a) := -or_iff_not_imp_left.1 (is_local a) h +namespace local_ring -lemma nonunits_add {x y} (hx : x ∈ nonunits R) (hy : y ∈ nonunits R) : - x + y ∈ nonunits R := -begin - rintros ⟨u, hu⟩, - apply hy, - suffices : is_unit ((↑u⁻¹ : R) * y), - { rcases this with ⟨s, hs⟩, - use u * s, - convert congr_arg (λ z, (u : R) * z) hs, - rw ← mul_assoc, simp }, - rw show (↑u⁻¹ * y) = (1 - ↑u⁻¹ * x), - { rw eq_sub_iff_add_eq, - replace hu := congr_arg (λ z, (↑u⁻¹ : R) * z) hu.symm, - simpa [mul_add, add_comm] using hu }, - apply is_unit_one_sub_self_of_mem_nonunits, - exact mul_mem_nonunits_right hx +/-- A semiring is local if it has a unique maximal ideal. -/ +lemma of_unique_max_ideal (h : ∃! I : ideal R, I.is_maximal) : + local_ring R := +@local_ring.mk _ _ (nontrivial_of_ne (0 : R) 1 $ + let ⟨I, Imax, _⟩ := h in (λ (H : 0 = 1), Imax.1.1 $ I.eq_top_iff_one.2 $ H ▸ I.zero_mem)) $ + λ x y hx hy H, + let ⟨I, Imax, Iuniq⟩ := h in + let ⟨Ix, Ixmax, Hx⟩ := exists_max_ideal_of_mem_nonunits hx in + let ⟨Iy, Iymax, Hy⟩ := exists_max_ideal_of_mem_nonunits hy in + have xmemI : x ∈ I, from ((Iuniq Ix Ixmax) ▸ Hx), + have ymemI : y ∈ I, from ((Iuniq Iy Iymax) ▸ Hy), + Imax.1.1 $ I.eq_top_of_is_unit_mem (I.add_mem xmemI ymemI) H + +lemma of_unique_nonzero_prime (h : ∃! P : ideal R, P ≠ ⊥ ∧ ideal.is_prime P) : + local_ring R := +of_unique_max_ideal begin + rcases h with ⟨P, ⟨hPnonzero, hPnot_top, _⟩, hPunique⟩, + refine ⟨P, ⟨⟨hPnot_top, _⟩⟩, λ M hM, hPunique _ ⟨_, ideal.is_maximal.is_prime hM⟩⟩, + { refine ideal.maximal_of_no_maximal (λ M hPM hM, ne_of_lt hPM _), + exact (hPunique _ ⟨ne_bot_of_gt hPM, ideal.is_maximal.is_prime hM⟩).symm }, + { rintro rfl, + exact hPnot_top (hM.1.2 P (bot_lt_iff_ne_bot.2 hPnonzero)) }, end -variable (R) +variables (R) [local_ring R] /-- The ideal of elements that are not units. -/ def maximal_ideal : ideal R := @@ -89,8 +86,7 @@ begin simpa using I.mul_mem_left ↑u⁻¹ H } end -lemma maximal_ideal_unique : - ∃! I : ideal R, I.is_maximal := +lemma maximal_ideal_unique : ∃! I : ideal R, I.is_maximal := ⟨maximal_ideal R, maximal_ideal.is_maximal R, λ I hI, hI.eq_of_le (maximal_ideal.is_maximal R).1.1 $ λ x hx, hI.1.1 ∘ I.eq_top_of_is_unit_mem hx⟩ @@ -106,99 +102,91 @@ begin rwa ←eq_maximal_ideal hM1 end -@[simp] lemma mem_maximal_ideal (x) : - x ∈ maximal_ideal R ↔ x ∈ nonunits R := iff.rfl +@[simp] lemma mem_maximal_ideal (x) : x ∈ maximal_ideal R ↔ x ∈ nonunits R := iff.rfl end local_ring -variables {R : Type u} {S : Type v} {T : Type w} +end comm_semiring -lemma local_of_nonunits_ideal [comm_ring R] (hnze : (0:R) ≠ 1) - (h : ∀ x y ∈ nonunits R, x + y ∈ nonunits R) : local_ring R := -{ exists_pair_ne := ⟨0, 1, hnze⟩, - is_local := λ x, or_iff_not_imp_left.mpr $ λ hx, - begin - by_contra H, - apply h _ hx _ H, - simp [-sub_eq_add_neg, add_sub_cancel'_right] - end } +section comm_ring +variables [comm_ring R] -lemma local_of_unique_max_ideal [comm_ring R] (h : ∃! I : ideal R, I.is_maximal) : - local_ring R := -local_of_nonunits_ideal -(let ⟨I, Imax, _⟩ := h in (λ (H : 0 = 1), Imax.1.1 $ I.eq_top_iff_one.2 $ H ▸ I.zero_mem)) -$ λ x hx y hy H, -let ⟨I, Imax, Iuniq⟩ := h in -let ⟨Ix, Ixmax, Hx⟩ := exists_max_ideal_of_mem_nonunits hx in -let ⟨Iy, Iymax, Hy⟩ := exists_max_ideal_of_mem_nonunits hy in -have xmemI : x ∈ I, from ((Iuniq Ix Ixmax) ▸ Hx), -have ymemI : y ∈ I, from ((Iuniq Iy Iymax) ▸ Hy), -Imax.1.1 $ I.eq_top_of_is_unit_mem (I.add_mem xmemI ymemI) H - -lemma local_of_unique_nonzero_prime (R : Type u) [comm_ring R] - (h : ∃! P : ideal R, P ≠ ⊥ ∧ ideal.is_prime P) : local_ring R := -local_of_unique_max_ideal begin - rcases h with ⟨P, ⟨hPnonzero, hPnot_top, _⟩, hPunique⟩, - refine ⟨P, ⟨⟨hPnot_top, _⟩⟩, λ M hM, hPunique _ ⟨_, ideal.is_maximal.is_prime hM⟩⟩, - { refine ideal.maximal_of_no_maximal (λ M hPM hM, ne_of_lt hPM _), - exact (hPunique _ ⟨ne_bot_of_gt hPM, ideal.is_maximal.is_prime hM⟩).symm }, - { rintro rfl, - exact hPnot_top (hM.1.2 P (bot_lt_iff_ne_bot.2 hPnonzero)) }, +namespace local_ring + +lemma of_is_unit_or_is_unit_one_sub_self [nontrivial R] + (h : ∀ a : R, is_unit a ∨ is_unit (1 - a)) : local_ring R := +local_ring.mk +begin + intros x y hx hy, + rintros ⟨u, hu⟩, + apply hy, + suffices : is_unit ((↑u⁻¹ : R) * y), + { rcases this with ⟨s, hs⟩, + use u * s, + convert congr_arg (λ z, (u : R) * z) hs, + rw ← mul_assoc, simp }, + rw show (↑u⁻¹ * y) = (1 - ↑u⁻¹ * x), + { rw eq_sub_iff_add_eq, + replace hu := congr_arg (λ z, (↑u⁻¹ : R) * z) hu.symm, + simpa [mul_add, add_comm] using hu }, + apply or_iff_not_imp_left.1 (h _), + exact mul_mem_nonunits_right hx end -lemma local_of_surjective [comm_ring R] [local_ring R] [comm_ring S] [nontrivial S] - (f : R →+* S) (hf : function.surjective f) : +variables [local_ring R] + +lemma is_unit_or_is_unit_one_sub_self (a : R) : is_unit a ∨ is_unit (1 - a) := +or_iff_not_and_not.2 $ λ h, nonunits_add h.1 h.2 $ (add_sub_cancel'_right a 1).symm ▸ is_unit_one + +lemma is_unit_of_mem_nonunits_one_sub_self (a : R) (h : 1 - a ∈ nonunits R) : + is_unit a := +or_iff_not_imp_right.1 (is_unit_or_is_unit_one_sub_self a) h + +lemma is_unit_one_sub_self_of_mem_nonunits (a : R) (h : a ∈ nonunits R) : + is_unit (1 - a) := +or_iff_not_imp_left.1 (is_unit_or_is_unit_one_sub_self a) h + +lemma of_surjective [comm_ring S] [nontrivial S] (f : R →+* S) (hf : function.surjective f) : local_ring S := -{ is_local := - begin - intros b, - obtain ⟨a, rfl⟩ := hf b, - apply (local_ring.is_unit_or_is_unit_one_sub_self a).imp f.is_unit_map _, - rw [← f.map_one, ← f.map_sub], - apply f.is_unit_map, - end, - .. ‹nontrivial S› } - -/-- A local ring homomorphism is a homomorphism between local rings - such that the image of the maximal ideal of the source is contained within - the maximal ideal of the target. -/ +of_is_unit_or_is_unit_one_sub_self +begin + intros b, + obtain ⟨a, rfl⟩ := hf b, + apply (is_unit_or_is_unit_one_sub_self a).imp f.is_unit_map _, + rw [← f.map_one, ← f.map_sub], + apply f.is_unit_map, +end + +end local_ring + +end comm_ring + +/-- A local ring homomorphism is a homomorphism `f` between local rings such that `a` in the domain + is a unit if `f a` is a unit for any `a`. See `local_ring.local_hom_tfae` for other equivalent + definitions. -/ class is_local_ring_hom [semiring R] [semiring S] (f : R →+* S) : Prop := (map_nonunit : ∀ a, is_unit (f a) → is_unit a) +section +variables [semiring R] [semiring S] [semiring T] + instance is_local_ring_hom_id (R : Type*) [semiring R] : is_local_ring_hom (ring_hom.id R) := { map_nonunit := λ a, id } -@[simp] lemma is_unit_map_iff [semiring R] [semiring S] (f : R →+* S) - [is_local_ring_hom f] (a) : +@[simp] lemma is_unit_map_iff (f : R →+* S) [is_local_ring_hom f] (a) : is_unit (f a) ↔ is_unit a := ⟨is_local_ring_hom.map_nonunit a, f.is_unit_map⟩ -instance is_local_ring_hom_comp [semiring R] [semiring S] [semiring T] +@[simp] lemma map_mem_nonunits_iff (f : R →+* S) [is_local_ring_hom f] (a) : + f a ∈ nonunits S ↔ a ∈ nonunits R := +⟨λ h ha, h $ (is_unit_map_iff f a).mpr ha, λ h ha, h $ (is_unit_map_iff f a).mp ha⟩ + +instance is_local_ring_hom_comp (g : S →+* T) (f : R →+* S) [is_local_ring_hom g] [is_local_ring_hom f] : is_local_ring_hom (g.comp f) := { map_nonunit := λ a, is_local_ring_hom.map_nonunit a ∘ is_local_ring_hom.map_nonunit (f a) } -instance _root_.CommRing.is_local_ring_hom_comp {R S T : CommRing} (f : R ⟶ S) (g : S ⟶ T) - [is_local_ring_hom g] [is_local_ring_hom f] : - is_local_ring_hom (f ≫ g) := is_local_ring_hom_comp _ _ - -/-- If `f : R →+* S` is a local ring hom, then `R` is a local ring if `S` is. -/ -lemma _root_.ring_hom.domain_local_ring {R S : Type*} [comm_ring R] [comm_ring S] - [H : _root_.local_ring S] (f : R →+* S) - [is_local_ring_hom f] : _root_.local_ring R := -begin - haveI : nontrivial R := pullback_nonzero f f.map_zero f.map_one, - constructor, - intro x, - rw [← is_unit_map_iff f, ← is_unit_map_iff f, f.map_sub, f.map_one], - exact _root_.local_ring.is_local (f x) -end - -lemma is_local_ring_hom_of_comp {R S T: Type*} [comm_ring R] [comm_ring S] [comm_ring T] - (f : R →+* S) (g : S →+* T) [is_local_ring_hom (g.comp f)] : is_local_ring_hom f := -⟨λ a ha, (is_unit_map_iff (g.comp f) _).mp (g.is_unit_map ha)⟩ - -instance is_local_ring_hom_equiv [semiring R] [semiring S] (f : R ≃+* S) : +instance is_local_ring_hom_equiv (f : R ≃+* S) : is_local_ring_hom f.to_ring_hom := { map_nonunit := λ a ha, begin @@ -206,15 +194,35 @@ instance is_local_ring_hom_equiv [semiring R] [semiring S] (f : R ≃+* S) : rw ring_equiv.symm_to_ring_hom_apply_to_ring_hom_apply, end } -@[simp] lemma is_unit_of_map_unit [semiring R] [semiring S] (f : R →+* S) [is_local_ring_hom f] +@[simp] lemma is_unit_of_map_unit (f : R →+* S) [is_local_ring_hom f] (a) (h : is_unit (f a)) : is_unit a := is_local_ring_hom.map_nonunit a h -theorem of_irreducible_map [semiring R] [semiring S] (f : R →+* S) [h : is_local_ring_hom f] {x : R} +theorem of_irreducible_map (f : R →+* S) [h : is_local_ring_hom f] {x} (hfx : irreducible (f x)) : irreducible x := ⟨λ h, hfx.not_unit $ is_unit.map f h, λ p q hx, let ⟨H⟩ := h in or.imp (H p) (H q) $ hfx.is_unit_or_is_unit $ f.map_mul p q ▸ congr_arg f hx⟩ +lemma is_local_ring_hom_of_comp (f : R →+* S) (g : S →+* T) [is_local_ring_hom (g.comp f)] : + is_local_ring_hom f := +⟨λ a ha, (is_unit_map_iff (g.comp f) _).mp (g.is_unit_map ha)⟩ + +instance _root_.CommRing.is_local_ring_hom_comp {R S T : CommRing} (f : R ⟶ S) (g : S ⟶ T) + [is_local_ring_hom g] [is_local_ring_hom f] : + is_local_ring_hom (f ≫ g) := is_local_ring_hom_comp _ _ + +/-- If `f : R →+* S` is a local ring hom, then `R` is a local ring if `S` is. -/ +lemma _root_.ring_hom.domain_local_ring {R S : Type*} [comm_semiring R] [comm_semiring S] + [H : _root_.local_ring S] (f : R →+* S) + [is_local_ring_hom f] : _root_.local_ring R := +begin + haveI : nontrivial R := pullback_nonzero f f.map_zero f.map_one, + constructor, + intros a b, + simp_rw [←map_mem_nonunits_iff f, f.map_add], + exact local_ring.nonunits_add +end + section open category_theory @@ -232,18 +240,25 @@ is_local_ring_hom_of_iso (as_iso f) end +end + section open local_ring -variables [comm_ring R] [local_ring R] [comm_ring S] [local_ring S] -variables (f : R →+* S) [is_local_ring_hom f] +variables [comm_semiring R] [local_ring R] [comm_semiring S] [local_ring S] -lemma map_nonunit (a : R) (h : a ∈ maximal_ideal R) : f a ∈ maximal_ideal S := +/-- +The image of the maximal ideal of the source is contained within the maximal ideal of the target. +-/ +lemma map_nonunit (f : R →+* S) [is_local_ring_hom f] (a : R) (h : a ∈ maximal_ideal R) : + f a ∈ maximal_ideal S := λ H, h $ is_unit_of_map_unit f a H end namespace local_ring -variables [comm_ring R] [local_ring R] [comm_ring S] [local_ring S] + +section +variables [comm_semiring R] [local_ring R] [comm_semiring S] [local_ring S] /-- A ring homomorphism between local rings is a local ring hom iff it reflects units, @@ -267,7 +282,11 @@ begin tfae_finish, end -variable (R) +end + +section +variables (R) [comm_ring R] [local_ring R] [comm_ring S] [local_ring S] + /-- The residue field of a local ring is the quotient of the ring by its maximal ideal. -/ def residue_field := R ⧸ maximal_ideal R @@ -280,12 +299,13 @@ noncomputable instance : inhabited (residue_field R) := ⟨37⟩ def residue : R →+* (residue_field R) := ideal.quotient.mk _ -noncomputable instance residue_field.algebra : algebra R (residue_field R) := (residue R).to_algebra +noncomputable +instance residue_field.algebra : algebra R (residue_field R) := (residue R).to_algebra -namespace residue_field +variables {R} +namespace residue_field -variables {R S} /-- The map on residue fields induced by a local homomorphism between local rings -/ noncomputable def map (f : R →+* S) [is_local_ring_hom f] : residue_field R →+* residue_field S := @@ -298,24 +318,24 @@ end end residue_field -variables {R} - -lemma ker_eq_maximal_ideal {K : Type*} [field K] - (φ : R →+* K) (hφ : function.surjective φ) : φ.ker = maximal_ideal R := +lemma ker_eq_maximal_ideal [field K] (φ : R →+* K) (hφ : function.surjective φ) : + φ.ker = maximal_ideal R := local_ring.eq_maximal_ideal $ φ.ker_is_maximal_of_surjective hφ +end + end local_ring namespace field -variables [field R] +variables (K) [field K] open_locale classical @[priority 100] -- see Note [lower instance priority] -instance : local_ring R := -{ is_local := λ a, +instance : local_ring K := +local_ring.of_is_unit_or_is_unit_one_sub_self $ λ a, if h : a = 0 then or.inr (by rw [h, sub_zero]; exact is_unit_one) - else or.inl $ is_unit.mk0 a h } + else or.inl $ is_unit.mk0 a h end field diff --git a/src/ring_theory/localization/at_prime.lean b/src/ring_theory/localization/at_prime.lean index 387cb6a9b71fa..6a7b6b328df44 100644 --- a/src/ring_theory/localization/at_prime.lean +++ b/src/ring_theory/localization/at_prime.lean @@ -59,15 +59,15 @@ protected abbreviation localization.at_prime := localization I.prime_compl namespace is_localization theorem at_prime.local_ring [is_localization.at_prime S I] : local_ring S := -local_of_nonunits_ideal +@local_ring.mk _ _ (nontrivial_of_ne (0 : S) 1 (λ hze, begin rw [←(algebra_map R S).map_one, ←(algebra_map R S).map_zero] at hze, obtain ⟨t, ht⟩ := (eq_iff_exists I.prime_compl S).1 hze, exact ((show (t : R) ∉ I, from t.2) (have htz : (t : R) = 0, by simpa using ht.symm, htz.symm ▸ I.zero_mem)) - end) + end)) (begin - intros x hx y hy hu, + intros x y hx hy hu, cases is_unit_iff_exists_inv.1 hu with z hxyz, have : ∀ {r : R} {s : I.prime_compl}, mk' S r s ∈ nonunits S → r ∈ I, from λ (r : R) (s : I.prime_compl), not_imp_comm.1 diff --git a/src/ring_theory/power_series/basic.lean b/src/ring_theory/power_series/basic.lean index fcbfa66234d62..71cdb8daf2b9e 100644 --- a/src/ring_theory/power_series/basic.lean +++ b/src/ring_theory/power_series/basic.lean @@ -649,10 +649,12 @@ variable [comm_ring R] /-- Multivariate formal power series over a local ring form a local ring. -/ instance [local_ring R] : local_ring (mv_power_series σ R) := -{ is_local := by { intro φ, rcases local_ring.is_local (constant_coeff σ R φ) with ⟨u,h⟩|⟨u,h⟩; +local_ring.of_is_unit_or_is_unit_one_sub_self $ by +{ intro φ, + rcases local_ring.is_unit_or_is_unit_one_sub_self (constant_coeff σ R φ) with ⟨u,h⟩|⟨u,h⟩; [left, right]; { refine is_unit_of_mul_eq_one _ _ (mul_inv_of_unit _ u _), - simpa using h.symm } } } + simpa using h.symm } } -- TODO(jmc): once adic topology lands, show that this is complete diff --git a/src/ring_theory/valuation/valuation_ring.lean b/src/ring_theory/valuation/valuation_ring.lean index f1922aa28e83d..bd5ee32a7514b 100644 --- a/src/ring_theory/valuation/valuation_ring.lean +++ b/src/ring_theory/valuation/valuation_ring.lean @@ -237,8 +237,8 @@ variables (A : Type u) [comm_ring A] [is_domain A] [valuation_ring A] @[priority 100] instance : local_ring A := +local_ring.of_is_unit_or_is_unit_one_sub_self begin - constructor, intros a, obtain ⟨c,(h|h)⟩ := valuation_ring.cond a (1-a), { left, From d6c1cf1668dd62584c7f6cbae3d428f80f7122cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Fri, 15 Apr 2022 15:03:07 +0000 Subject: [PATCH 041/373] feat(analysis/normed_space/pointwise): Balls disjointness (#13379) Two balls in a real normed space are disjoint iff the sum of their radii is less than the distance between their centers. --- src/algebra/module/basic.lean | 6 +- src/algebra/order/ring.lean | 6 ++ src/analysis/convex/basic.lean | 3 - src/analysis/normed_space/pointwise.lean | 95 +++++++++++++++++++++++- src/topology/metric_space/basic.lean | 35 +++------ 5 files changed, 115 insertions(+), 30 deletions(-) diff --git a/src/algebra/module/basic.lean b/src/algebra/module/basic.lean index ce79364311c09..549ab9cfcdcfa 100644 --- a/src/algebra/module/basic.lean +++ b/src/algebra/module/basic.lean @@ -72,6 +72,10 @@ instance add_comm_monoid.nat_module : module ℕ M := add_smul := λ r s x, add_nsmul x r s } theorem add_smul : (r + s) • x = r • x + s • x := module.add_smul r s x + +lemma convex.combo_self {a b : R} (h : a + b = 1) (x : M) : a • x + b • x = x := +by rw [←add_smul, h, one_smul] + variables (R) theorem two_smul : (2 : R) • x = x + x := by rw [bit0, add_smul, one_smul] @@ -80,7 +84,7 @@ theorem two_smul' : (2 : R) • x = bit0 x := two_smul R x @[simp] lemma inv_of_two_smul_add_inv_of_two_smul [invertible (2 : R)] (x : M) : (⅟2 : R) • x + (⅟2 : R) • x = x := -by rw [←add_smul, inv_of_two_add_inv_of_two, one_smul] +convex.combo_self inv_of_two_add_inv_of_two _ /-- Pullback a `module` structure along an injective additive monoid homomorphism. See note [reducible non-instances]. -/ diff --git a/src/algebra/order/ring.lean b/src/algebra/order/ring.lean index c708dda9d7e65..29c0e3ca1fe2c 100644 --- a/src/algebra/order/ring.lean +++ b/src/algebra/order/ring.lean @@ -177,6 +177,12 @@ ordered_semiring.mul_lt_mul_of_pos_left a b c h₁ h₂ lemma mul_lt_mul_of_pos_right (h₁ : a < b) (h₂ : 0 < c) : a * c < b * c := ordered_semiring.mul_lt_mul_of_pos_right a b c h₁ h₂ +lemma mul_lt_of_lt_one_left (hb : 0 < b) (ha : a < 1) : a * b < b := +(mul_lt_mul_of_pos_right ha hb).trans_le (one_mul _).le + +lemma mul_lt_of_lt_one_right (ha : 0 < a) (hb : b < 1) : a * b < a := +(mul_lt_mul_of_pos_left hb ha).trans_le (mul_one _).le + -- See Note [decidable namespace] protected lemma decidable.mul_le_mul_of_nonneg_left [@decidable_rel α (≤)] (h₁ : a ≤ b) (h₂ : 0 ≤ c) : c * a ≤ c * b := diff --git a/src/analysis/convex/basic.lean b/src/analysis/convex/basic.lean index 1b1322d682258..9ff7d4cbc233f 100644 --- a/src/analysis/convex/basic.lean +++ b/src/analysis/convex/basic.lean @@ -145,9 +145,6 @@ begin exact h (mem_open_segment_of_ne_left_right 𝕜 hxz hyz hz), end -lemma convex.combo_self {a b : 𝕜} (h : a + b = 1) (x : E) : a • x + b • x = x := -by rw [←add_smul, h, one_smul] - end module end ordered_semiring diff --git a/src/analysis/normed_space/pointwise.lean b/src/analysis/normed_space/pointwise.lean index edbe2da2d30b7..9e31896888c1c 100644 --- a/src/analysis/normed_space/pointwise.lean +++ b/src/analysis/normed_space/pointwise.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2021 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Sébastien Gouëzel +Authors: Sébastien Gouëzel, Yaël Dillies -/ import analysis.normed.group.pointwise import analysis.normed.group.add_torsor @@ -95,13 +95,104 @@ by rw [vadd_ball, vadd_eq_add, add_zero] lemma vadd_closed_ball_zero (x : E) (r : ℝ) : x +ᵥ closed_ball 0 r = closed_ball x r := by rw [vadd_closed_ball, vadd_eq_add, add_zero] -variables [normed_space ℝ E] +variables [normed_space ℝ E] {x y z : E} {δ ε : ℝ} /-- In a real normed space, the image of the unit ball under scalar multiplication by a positive constant `r` is the ball of radius `r`. -/ lemma smul_unit_ball_of_pos {r : ℝ} (hr : 0 < r) : r • ball 0 1 = ball (0 : E) r := by rw [smul_unit_ball hr.ne', real.norm_of_nonneg hr.le] +-- This is also true for `ℚ`-normed spaces +lemma exists_dist_eq (x z : E) {a b : ℝ} (ha : 0 ≤ a) (hb : 0 ≤ b) (hab : a + b = 1) : + ∃ y, dist x y = b * dist x z ∧ dist y z = a * dist x z := +begin + use a • x + b • z, + nth_rewrite 0 [←one_smul ℝ x], + nth_rewrite 3 [←one_smul ℝ z], + simp [dist_eq_norm, ←hab, add_smul, ←smul_sub, norm_smul_of_nonneg, ha, hb], +end + +lemma exists_dist_le_le (hδ : 0 ≤ δ) (hε : 0 ≤ ε) (h : dist x z ≤ ε + δ) : + ∃ y, dist x y ≤ δ ∧ dist y z ≤ ε := +begin + obtain rfl | hε' := hε.eq_or_lt, + { exact ⟨z, by rwa zero_add at h, (dist_self _).le⟩ }, + have hεδ := add_pos_of_pos_of_nonneg hε' hδ, + refine (exists_dist_eq x z (div_nonneg hε $ add_nonneg hε hδ) (div_nonneg hδ $ add_nonneg hε hδ) $ + by rw [←add_div, div_self hεδ.ne']).imp (λ y hy, _), + rw [hy.1, hy.2, div_mul_comm', div_mul_comm' ε], + rw ←div_le_one hεδ at h, + exact ⟨mul_le_of_le_one_left hδ h, mul_le_of_le_one_left hε h⟩, +end + +-- This is also true for `ℚ`-normed spaces +lemma exists_dist_le_lt (hδ : 0 ≤ δ) (hε : 0 < ε) (h : dist x z < ε + δ) : + ∃ y, dist x y ≤ δ ∧ dist y z < ε := +begin + refine (exists_dist_eq x z (div_nonneg hε.le $ add_nonneg hε.le hδ) (div_nonneg hδ $ add_nonneg + hε.le hδ) $ by rw [←add_div, div_self (add_pos_of_pos_of_nonneg hε hδ).ne']).imp (λ y hy, _), + rw [hy.1, hy.2, div_mul_comm', div_mul_comm' ε], + rw ←div_lt_one (add_pos_of_pos_of_nonneg hε hδ) at h, + exact ⟨mul_le_of_le_one_left hδ h.le, mul_lt_of_lt_one_left hε h⟩, +end + +-- This is also true for `ℚ`-normed spaces +lemma exists_dist_lt_le (hδ : 0 < δ) (hε : 0 ≤ ε) (h : dist x z < ε + δ) : + ∃ y, dist x y < δ ∧ dist y z ≤ ε := +begin + obtain ⟨y, yz, xy⟩ := exists_dist_le_lt hε hδ + (show dist z x < δ + ε, by simpa only [dist_comm, add_comm] using h), + exact ⟨y, by simp [dist_comm x y, dist_comm y z, *]⟩, +end + +-- This is also true for `ℚ`-normed spaces +lemma exists_dist_lt_lt (hδ : 0 < δ) (hε : 0 < ε) (h : dist x z < ε + δ) : + ∃ y, dist x y < δ ∧ dist y z < ε := +begin + refine (exists_dist_eq x z (div_nonneg hε.le $ add_nonneg hε.le hδ.le) (div_nonneg hδ.le $ + add_nonneg hε.le hδ.le) $ by rw [←add_div, div_self (add_pos hε hδ).ne']).imp (λ y hy, _), + rw [hy.1, hy.2, div_mul_comm', div_mul_comm' ε], + rw ←div_lt_one (add_pos hε hδ) at h, + exact ⟨mul_lt_of_lt_one_left hδ h, mul_lt_of_lt_one_left hε h⟩, +end + +-- This is also true for `ℚ`-normed spaces +lemma disjoint_ball_ball_iff (hδ : 0 < δ) (hε : 0 < ε) : + disjoint (ball x δ) (ball y ε) ↔ δ + ε ≤ dist x y := +begin + refine ⟨λ h, le_of_not_lt $ λ hxy, _, ball_disjoint_ball⟩, + rw add_comm at hxy, + obtain ⟨z, hxz, hzy⟩ := exists_dist_lt_lt hδ hε hxy, + rw dist_comm at hxz, + exact h ⟨hxz, hzy⟩, +end + +-- This is also true for `ℚ`-normed spaces +lemma disjoint_ball_closed_ball_iff (hδ : 0 < δ) (hε : 0 ≤ ε) : + disjoint (ball x δ) (closed_ball y ε) ↔ δ + ε ≤ dist x y := +begin + refine ⟨λ h, le_of_not_lt $ λ hxy, _, ball_disjoint_closed_ball⟩, + rw add_comm at hxy, + obtain ⟨z, hxz, hzy⟩ := exists_dist_lt_le hδ hε hxy, + rw dist_comm at hxz, + exact h ⟨hxz, hzy⟩, +end + +-- This is also true for `ℚ`-normed spaces +lemma disjoint_closed_ball_ball_iff (hδ : 0 ≤ δ) (hε : 0 < ε) : + disjoint (closed_ball x δ) (ball y ε) ↔ δ + ε ≤ dist x y := +by rw [disjoint.comm, disjoint_ball_closed_ball_iff hε hδ, add_comm, dist_comm]; apply_instance + +lemma disjoint_closed_ball_closed_ball_iff (hδ : 0 ≤ δ) (hε : 0 ≤ ε) : + disjoint (closed_ball x δ) (closed_ball y ε) ↔ δ + ε < dist x y := +begin + refine ⟨λ h, lt_of_not_ge $ λ hxy, _, closed_ball_disjoint_closed_ball⟩, + rw add_comm at hxy, + obtain ⟨z, hxz, hzy⟩ := exists_dist_le_le hδ hε hxy, + rw dist_comm at hxz, + exact h ⟨hxz, hzy⟩, +end + end semi_normed_group section normed_group diff --git a/src/topology/metric_space/basic.lean b/src/topology/metric_space/basic.lean index 28c3367c9dfde..2d0bc2d6c43ba 100644 --- a/src/topology/metric_space/basic.lean +++ b/src/topology/metric_space/basic.lean @@ -389,7 +389,7 @@ by rw [edist_dist, ennreal.to_real_of_real (dist_nonneg)] namespace metric /- instantiate pseudometric space as a topology -/ -variables {x y z : α} {ε ε₁ ε₂ : ℝ} {s : set α} +variables {x y z : α} {δ ε ε₁ ε₂ : ℝ} {s : set α} /-- `ball x ε` is the set of all points `y` with `dist y x < ε` -/ def ball (x : α) (ε : ℝ) : set α := {y | dist y x < ε} @@ -466,31 +466,18 @@ assume y (hy : _ < _), le_of_lt hy theorem sphere_subset_closed_ball : sphere x ε ⊆ closed_ball x ε := λ y, le_of_eq -lemma closed_ball_disjoint_ball (x y : α) (rx ry : ℝ) (h : rx + ry ≤ dist x y) : - disjoint (closed_ball x rx) (ball y ry) := -begin - rw disjoint_left, - intros a ax ay, - apply lt_irrefl (dist x y), - calc dist x y ≤ dist a x + dist a y : dist_triangle_left _ _ _ - ... < rx + ry : add_lt_add_of_le_of_lt (mem_closed_ball.1 ax) (mem_ball.1 ay) - ... ≤ dist x y : h -end +lemma closed_ball_disjoint_ball (h : δ + ε ≤ dist x y) : disjoint (closed_ball x δ) (ball y ε) := +λ a ha, (h.trans $ dist_triangle_left _ _ _).not_lt $ add_lt_add_of_le_of_lt ha.1 ha.2 -lemma ball_disjoint_ball (x y : α) (rx ry : ℝ) (h : rx + ry ≤ dist x y) : - disjoint (ball x rx) (ball y ry) := -(closed_ball_disjoint_ball x y rx ry h).mono_left ball_subset_closed_ball +lemma ball_disjoint_closed_ball (h : δ + ε ≤ dist x y) : disjoint (ball x δ) (closed_ball y ε) := +(closed_ball_disjoint_ball $ by rwa [add_comm, dist_comm]).symm -lemma closed_ball_disjoint_closed_ball {x y : α} {rx ry : ℝ} (h : rx + ry < dist x y) : - disjoint (closed_ball x rx) (closed_ball y ry) := -begin - rw disjoint_left, - intros a ax ay, - apply lt_irrefl (dist x y), - calc dist x y ≤ dist a x + dist a y : dist_triangle_left _ _ _ - ... ≤ rx + ry : add_le_add ax ay - ... < dist x y : h -end +lemma ball_disjoint_ball (h : δ + ε ≤ dist x y) : disjoint (ball x δ) (ball y ε) := +(closed_ball_disjoint_ball h).mono_left ball_subset_closed_ball + +lemma closed_ball_disjoint_closed_ball (h : δ + ε < dist x y) : + disjoint (closed_ball x δ) (closed_ball y ε) := +λ a ha, h.not_le $ (dist_triangle_left _ _ _).trans $ add_le_add ha.1 ha.2 theorem sphere_disjoint_ball : disjoint (sphere x ε) (ball x ε) := λ y ⟨hy₁, hy₂⟩, absurd hy₁ $ ne_of_lt hy₂ From 0c2d68a0610fea63b572b0b5e0aa8d43d5cd5235 Mon Sep 17 00:00:00 2001 From: Kyle Miller Date: Fri, 15 Apr 2022 17:09:01 +0000 Subject: [PATCH 042/373] feat(data/sym/sym2): mem_map/mem_congr/map_id' (#13437) Additional simplification lemmas, one to address non-simp-normal-form. (Also did a few proof simplifications.) --- src/data/sym/sym2.lean | 68 +++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/src/data/sym/sym2.lean b/src/data/sym/sym2.lean index 68392b3acb11a..2e911abd94b8b 100644 --- a/src/data/sym/sym2.lean +++ b/src/data/sym/sym2.lean @@ -145,10 +145,10 @@ def map (f : α → β) : sym2 α → sym2 β := quotient.map (prod.map f f) (by { rintros _ _ h, cases h, { refl }, apply rel.swap }) -@[simp] -lemma map_id : sym2.map (@id α) = id := by tidy +@[simp] lemma map_id : map (@id α) = id := by { ext ⟨⟨x,y⟩⟩, refl } -lemma map_comp {g : β → γ} {f : α → β} : sym2.map (g ∘ f) = sym2.map g ∘ sym2.map f := by tidy +lemma map_comp {g : β → γ} {f : α → β} : sym2.map (g ∘ f) = sym2.map g ∘ sym2.map f := +by { ext ⟨⟨x, y⟩⟩, refl } lemma map_map {g : β → γ} {f : α → β} (x : sym2 α) : map g (map f x) = map (g ∘ f) x := by tidy @@ -214,12 +214,12 @@ by { convert mem_mk_right a h.other, rw other_spec h } lemma mem_and_mem_iff {x y : α} {z : sym2 α} (hne : x ≠ y) : x ∈ z ∧ y ∈ z ↔ z = ⟦(x, y)⟧ := begin - refine ⟨quotient.rec_on_subsingleton z _, _⟩, - { rintro ⟨z₁, z₂⟩ ⟨hx, hy⟩, - rw eq_iff, - cases mem_iff.mp hx with hx hx; cases mem_iff.mp hy with hy hy; subst x; subst y; - try { exact (hne rfl).elim }; - simp only [true_or, eq_self_iff_true, and_self, or_true] }, + split, + { induction z using sym2.ind with x' y', + rw [mem_iff, mem_iff], + rintro ⟨rfl | rfl, rfl | rfl⟩; + try { trivial }; + simp only [sym2.eq_swap] }, { rintro rfl, simp }, end @@ -230,16 +230,12 @@ lemma eq_of_ne_mem {x y : α} {z z' : sym2 α} (h : x ≠ y) @[ext] protected lemma ext (z z' : sym2 α) (h : ∀ x, x ∈ z ↔ x ∈ z') : z = z' := begin - refine quotient.rec_on_subsingleton z (λ w, _) h, - refine quotient.rec_on_subsingleton z' (λ w', _), - intro h, - cases w with x y, cases w' with x' y', - simp only [mem_iff] at h, - apply eq_iff.mpr, + induction z using sym2.ind with x y, + induction z' using sym2.ind with x' y', have hx := h x, have hy := h y, have hx' := h x', have hy' := h y', - simp only [true_iff, true_or, eq_self_iff_true, iff_true, or_true] at hx hy hx' hy', - cases hx; subst x; cases hy; subst y; cases hx'; try { subst x' }; cases hy'; try { subst y' }; - simp only [eq_self_iff_true, and_self, or_self, true_or, or_true], + simp only [mem_iff, eq_self_iff_true, or_true, iff_true, true_or, true_iff] at hx hy hx' hy', + cases hx; cases hy; cases hx'; cases hy'; subst_vars, + simp only [sym2.eq_swap], end instance mem.decidable [decidable_eq α] (x : α) (z : sym2 α) : decidable (x ∈ z) := @@ -247,6 +243,31 @@ quotient.rec_on_subsingleton z (λ ⟨y₁, y₂⟩, decidable_of_iff' _ mem_iff end membership +@[simp] lemma mem_map {f : α → β} {b : β} {z : sym2 α} : + b ∈ sym2.map f z ↔ ∃ a, a ∈ z ∧ f a = b := +begin + induction z using sym2.ind with x y, + simp only [map, quotient.map_mk, prod.map_mk, mem_iff], + split, + { rintro (rfl | rfl), + { exact ⟨x, by simp⟩, }, + { exact ⟨y, by simp⟩, } }, + { rintro ⟨w, rfl | rfl, rfl⟩; simp, }, +end + +@[congr] lemma map_congr {f g : α → β} {s : sym2 α} (h : ∀ x ∈ s, f x = g x) : + map f s = map g s := +begin + ext y, + simp only [mem_map], + split; { rintro ⟨w, hw, rfl⟩, exact ⟨w, hw, by simp [hw, h]⟩ }, +end + +/-- Note: `sym2.map_id` will not simplify `sym2.map id z` due to `sym2.map_congr`. -/ +@[simp] lemma map_id' : map (λ (x : α), x) = id := map_id + +/-! ### Diagonal -/ + /-- A type `α` is naturally included in the diagonal of `α × α`, and this function gives the image of this diagonal in `sym2 α`. @@ -273,10 +294,9 @@ lemma diag_is_diag (a : α) : is_diag (diag a) := eq.refl a lemma is_diag.mem_range_diag {z : sym2 α} : is_diag z → z ∈ set.range (@diag α) := begin - induction z using quotient.induction_on, - cases z, - rintro (rfl : z_fst = z_snd), - exact ⟨z_fst, rfl⟩, + induction z using sym2.ind with x y, + rintro (rfl : x = y), + exact ⟨_, rfl⟩, end lemma is_diag_iff_mem_range_diag (z : sym2 α) : is_diag z ↔ z ∈ set.range (@diag α) := @@ -287,9 +307,9 @@ by { refine λ z, quotient.rec_on_subsingleton z (λ a, _), erw is_diag_iff_proj lemma other_ne {a : α} {z : sym2 α} (hd : ¬is_diag z) (h : a ∈ z) : h.other ≠ a := begin - intro hn, apply hd, + contrapose! hd, have h' := sym2.other_spec h, - rw hn at h', + rw hd at h', rw ←h', simp, end From fbff76b51a6eb293321510f1e4f3ca65accd0796 Mon Sep 17 00:00:00 2001 From: MichaelStollBayreuth Date: Fri, 15 Apr 2022 17:50:16 +0000 Subject: [PATCH 043/373] refactor(number_theory/legendre_symbol/): move Gauss/Eisenstein lemma code to separate file (#13449) In preparation of further changes to number_theory/legendre_symbol/quadratic_reciprocity, this takes most of the code dealing with the lemmas of Gauss and Eisenstein out of quadratic_reciprocity.lean into a new file gauss_eisenstein_lemmas.lean. Since I am not planning to do much (if anything) to this part of the code and it is rather involved and slows down Lean when I'm editing quadratic_reciprocity.lean, it makes sense to separate this code from the remainder of the file. Co-authored-by: Oliver Nash --- .../gauss_eisenstein_lemmas.lean | 282 ++++++++++++++++++ .../quadratic_reciprocity.lean | 259 +--------------- 2 files changed, 287 insertions(+), 254 deletions(-) create mode 100644 src/number_theory/legendre_symbol/gauss_eisenstein_lemmas.lean diff --git a/src/number_theory/legendre_symbol/gauss_eisenstein_lemmas.lean b/src/number_theory/legendre_symbol/gauss_eisenstein_lemmas.lean new file mode 100644 index 0000000000000..be4dcb44bc93b --- /dev/null +++ b/src/number_theory/legendre_symbol/gauss_eisenstein_lemmas.lean @@ -0,0 +1,282 @@ +/- +Copyright (c) 2018 Chris Hughes. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Hughes +-/ +import field_theory.finite.basic +import data.zmod.basic + +/-! +# Lemmas of Gauss and Eisenstein + +This file contains code for the proof of the Lemmas of Gauss and Eisenstein +on the Legendre symbol. The main results are `gauss_lemma_aux` and +`eisenstein_lemma_aux`; they are used in `quadratic_reciprocity.lean` +to prove `gauss_lemma` and `eisenstein_lemma`, respectively. +-/ + +open function finset nat finite_field zmod +open_locale big_operators nat + +namespace zmod + +section wilson + +variables (p : ℕ) [fact p.prime] + +-- One can probably deduce the following from `finite_field.prod_univ_units_id_eq_neg_one` +/-- **Wilson's Lemma**: the product of `1`, ..., `p-1` is `-1` modulo `p`. -/ +@[simp] lemma wilsons_lemma : ((p - 1)! : zmod p) = -1 := +begin + refine + calc ((p - 1)! : zmod p) = (∏ x in Ico 1 (succ (p - 1)), x) : + by rw [← finset.prod_Ico_id_eq_factorial, prod_nat_cast] + ... = (∏ x : (zmod p)ˣ, x) : _ + ... = -1 : by simp_rw [← units.coe_hom_apply, + ← (units.coe_hom (zmod p)).map_prod, prod_univ_units_id_eq_neg_one, units.coe_hom_apply, + units.coe_neg, units.coe_one], + have hp : 0 < p := (fact.out p.prime).pos, + symmetry, + refine prod_bij (λ a _, (a : zmod p).val) _ _ _ _, + { intros a ha, + rw [mem_Ico, ← nat.succ_sub hp, nat.succ_sub_one], + split, + { apply nat.pos_of_ne_zero, rw ← @val_zero p, + assume h, apply units.ne_zero a (val_injective p h) }, + { exact val_lt _ } }, + { intros a ha, simp only [cast_id, nat_cast_val], }, + { intros _ _ _ _ h, rw units.ext_iff, exact val_injective p h }, + { intros b hb, + rw [mem_Ico, nat.succ_le_iff, ← succ_sub hp, succ_sub_one, pos_iff_ne_zero] at hb, + refine ⟨units.mk0 b _, finset.mem_univ _, _⟩, + { assume h, apply hb.1, apply_fun val at h, + simpa only [val_cast_of_lt hb.right, val_zero] using h }, + { simp only [val_cast_of_lt hb.right, units.coe_mk0], } } +end + +@[simp] lemma prod_Ico_one_prime : (∏ x in Ico 1 p, (x : zmod p)) = -1 := +begin + conv in (Ico 1 p) { rw [← succ_sub_one p, succ_sub (fact.out p.prime).pos] }, + rw [← prod_nat_cast, finset.prod_Ico_id_eq_factorial, wilsons_lemma] +end + +end wilson + +end zmod + +section gauss_eisenstein + +namespace legendre_symbol + +/-- The image of the map sending a non zero natural number `x ≤ p / 2` to the absolute value + of the element of interger in the interval `(-p/2, p/2]` congruent to `a * x` mod p is the set + of non zero natural numbers `x` such that `x ≤ p / 2` -/ +lemma Ico_map_val_min_abs_nat_abs_eq_Ico_map_id + (p : ℕ) [hp : fact p.prime] (a : zmod p) (hap : a ≠ 0) : + (Ico 1 (p / 2).succ).1.map (λ x, (a * x).val_min_abs.nat_abs) = + (Ico 1 (p / 2).succ).1.map (λ a, a) := +begin + have he : ∀ {x}, x ∈ Ico 1 (p / 2).succ → x ≠ 0 ∧ x ≤ p / 2, + by simp [nat.lt_succ_iff, nat.succ_le_iff, pos_iff_ne_zero] {contextual := tt}, + have hep : ∀ {x}, x ∈ Ico 1 (p / 2).succ → x < p, + from λ x hx, lt_of_le_of_lt (he hx).2 (nat.div_lt_self hp.1.pos dec_trivial), + have hpe : ∀ {x}, x ∈ Ico 1 (p / 2).succ → ¬ p ∣ x, + from λ x hx hpx, not_lt_of_ge (le_of_dvd (nat.pos_of_ne_zero (he hx).1) hpx) (hep hx), + have hmem : ∀ (x : ℕ) (hx : x ∈ Ico 1 (p / 2).succ), + (a * x : zmod p).val_min_abs.nat_abs ∈ Ico 1 (p / 2).succ, + { assume x hx, + simp [hap, char_p.cast_eq_zero_iff (zmod p) p, hpe hx, lt_succ_iff, succ_le_iff, + pos_iff_ne_zero, nat_abs_val_min_abs_le _], }, + have hsurj : ∀ (b : ℕ) (hb : b ∈ Ico 1 (p / 2).succ), + ∃ x ∈ Ico 1 (p / 2).succ, b = (a * x : zmod p).val_min_abs.nat_abs, + { assume b hb, + refine ⟨(b / a : zmod p).val_min_abs.nat_abs, mem_Ico.mpr ⟨_, _⟩, _⟩, + { apply nat.pos_of_ne_zero, + simp only [div_eq_mul_inv, hap, char_p.cast_eq_zero_iff (zmod p) p, hpe hb, not_false_iff, + val_min_abs_eq_zero, inv_eq_zero, int.nat_abs_eq_zero, ne.def, mul_eq_zero, or_self] }, + { apply lt_succ_of_le, apply nat_abs_val_min_abs_le }, + { rw nat_cast_nat_abs_val_min_abs, + split_ifs, + { erw [mul_div_cancel' _ hap, val_min_abs_def_pos, val_cast_of_lt (hep hb), + if_pos (le_of_lt_succ (mem_Ico.1 hb).2), int.nat_abs_of_nat], }, + { erw [mul_neg, mul_div_cancel' _ hap, nat_abs_val_min_abs_neg, + val_min_abs_def_pos, val_cast_of_lt (hep hb), if_pos (le_of_lt_succ (mem_Ico.1 hb).2), + int.nat_abs_of_nat] } } }, + exact multiset.map_eq_map_of_bij_of_nodup _ _ (finset.nodup _) (finset.nodup _) + (λ x _, (a * x : zmod p).val_min_abs.nat_abs) hmem (λ _ _, rfl) + (inj_on_of_surj_on_of_card_le _ hmem hsurj le_rfl) hsurj +end + +private lemma gauss_lemma_aux₁ (p : ℕ) [fact p.prime] [fact (p % 2 = 1)] + {a : ℤ} (hap : (a : zmod p) ≠ 0) : + (a^(p / 2) * (p / 2)! : zmod p) = + (-1)^((Ico 1 (p / 2).succ).filter + (λ x : ℕ, ¬(a * x : zmod p).val ≤ p / 2)).card * (p / 2)! := +calc (a ^ (p / 2) * (p / 2)! : zmod p) = + (∏ x in Ico 1 (p / 2).succ, a * x) : + by rw [prod_mul_distrib, ← prod_nat_cast, prod_Ico_id_eq_factorial, + prod_const, card_Ico, succ_sub_one]; simp +... = (∏ x in Ico 1 (p / 2).succ, (a * x : zmod p).val) : by simp +... = (∏ x in Ico 1 (p / 2).succ, + (if (a * x : zmod p).val ≤ p / 2 then 1 else -1) * + (a * x : zmod p).val_min_abs.nat_abs) : + prod_congr rfl $ λ _ _, begin + simp only [nat_cast_nat_abs_val_min_abs], + split_ifs; simp + end +... = (-1)^((Ico 1 (p / 2).succ).filter + (λ x : ℕ, ¬(a * x : zmod p).val ≤ p / 2)).card * + (∏ x in Ico 1 (p / 2).succ, (a * x : zmod p).val_min_abs.nat_abs) : + have (∏ x in Ico 1 (p / 2).succ, + if (a * x : zmod p).val ≤ p / 2 then (1 : zmod p) else -1) = + (∏ x in (Ico 1 (p / 2).succ).filter + (λ x : ℕ, ¬(a * x : zmod p).val ≤ p / 2), -1), + from prod_bij_ne_one (λ x _ _, x) + (λ x, by split_ifs; simp * at * {contextual := tt}) + (λ _ _ _ _ _ _, id) + (λ b h _, ⟨b, by simp [-not_le, *] at *⟩) + (by intros; split_ifs at *; simp * at *), + by rw [prod_mul_distrib, this]; simp +... = (-1)^((Ico 1 (p / 2).succ).filter + (λ x : ℕ, ¬(a * x : zmod p).val ≤ p / 2)).card * (p / 2)! : + by rw [← prod_nat_cast, finset.prod_eq_multiset_prod, + Ico_map_val_min_abs_nat_abs_eq_Ico_map_id p a hap, + ← finset.prod_eq_multiset_prod, prod_Ico_id_eq_factorial] + +lemma gauss_lemma_aux (p : ℕ) [hp : fact p.prime] [fact (p % 2 = 1)] + {a : ℤ} (hap : (a : zmod p) ≠ 0) : + (a^(p / 2) : zmod p) = (-1)^((Ico 1 (p / 2).succ).filter + (λ x : ℕ, p / 2 < (a * x : zmod p).val)).card := +(mul_left_inj' + (show ((p / 2)! : zmod p) ≠ 0, + by rw [ne.def, char_p.cast_eq_zero_iff (zmod p) p, hp.1.dvd_factorial, not_le]; + exact nat.div_lt_self hp.1.pos dec_trivial)).1 $ + by simpa using gauss_lemma_aux₁ p hap + +private lemma eisenstein_lemma_aux₁ (p : ℕ) [fact p.prime] [hp2 : fact (p % 2 = 1)] + {a : ℕ} (hap : (a : zmod p) ≠ 0) : + ((∑ x in Ico 1 (p / 2).succ, a * x : ℕ) : zmod 2) = + ((Ico 1 (p / 2).succ).filter + ((λ x : ℕ, p / 2 < (a * x : zmod p).val))).card + + ∑ x in Ico 1 (p / 2).succ, x + + (∑ x in Ico 1 (p / 2).succ, (a * x) / p : ℕ) := +have hp2 : (p : zmod 2) = (1 : ℕ), from (eq_iff_modeq_nat _).2 hp2.1, +calc ((∑ x in Ico 1 (p / 2).succ, a * x : ℕ) : zmod 2) + = ((∑ x in Ico 1 (p / 2).succ, ((a * x) % p + p * ((a * x) / p)) : ℕ) : zmod 2) : + by simp only [mod_add_div] +... = (∑ x in Ico 1 (p / 2).succ, ((a * x : ℕ) : zmod p).val : ℕ) + + (∑ x in Ico 1 (p / 2).succ, (a * x) / p : ℕ) : + by simp only [val_nat_cast]; + simp [sum_add_distrib, mul_sum.symm, nat.cast_add, nat.cast_mul, nat.cast_sum, hp2] +... = _ : congr_arg2 (+) + (calc ((∑ x in Ico 1 (p / 2).succ, ((a * x : ℕ) : zmod p).val : ℕ) : zmod 2) + = ∑ x in Ico 1 (p / 2).succ, + ((((a * x : zmod p).val_min_abs + + (if (a * x : zmod p).val ≤ p / 2 then 0 else p)) : ℤ) : zmod 2) : + by simp only [(val_eq_ite_val_min_abs _).symm]; simp [nat.cast_sum] + ... = ((Ico 1 (p / 2).succ).filter + (λ x : ℕ, p / 2 < (a * x : zmod p).val)).card + + ((∑ x in Ico 1 (p / 2).succ, (a * x : zmod p).val_min_abs.nat_abs) : ℕ) : + by { simp [ite_cast, add_comm, sum_add_distrib, finset.sum_ite, hp2, nat.cast_sum], } + ... = _ : by rw [finset.sum_eq_multiset_sum, + Ico_map_val_min_abs_nat_abs_eq_Ico_map_id p a hap, + ← finset.sum_eq_multiset_sum]; + simp [nat.cast_sum]) rfl + +lemma eisenstein_lemma_aux (p : ℕ) [fact p.prime] [fact (p % 2 = 1)] + {a : ℕ} (ha2 : a % 2 = 1) (hap : (a : zmod p) ≠ 0) : + ((Ico 1 (p / 2).succ).filter + ((λ x : ℕ, p / 2 < (a * x : zmod p).val))).card + ≡ ∑ x in Ico 1 (p / 2).succ, (x * a) / p [MOD 2] := +have ha2 : (a : zmod 2) = (1 : ℕ), from (eq_iff_modeq_nat _).2 ha2, +(eq_iff_modeq_nat 2).1 $ sub_eq_zero.1 $ + by simpa [add_left_comm, sub_eq_add_neg, finset.mul_sum.symm, mul_comm, ha2, nat.cast_sum, + add_neg_eq_iff_eq_add.symm, neg_eq_self_mod_two, add_assoc] + using eq.symm (eisenstein_lemma_aux₁ p hap) + +lemma div_eq_filter_card {a b c : ℕ} (hb0 : 0 < b) (hc : a / b ≤ c) : a / b = + ((Ico 1 c.succ).filter (λ x, x * b ≤ a)).card := +calc a / b = (Ico 1 (a / b).succ).card : by simp +... = ((Ico 1 c.succ).filter (λ x, x * b ≤ a)).card : + congr_arg _ $ finset.ext $ λ x, + have x * b ≤ a → x ≤ c, + from λ h, le_trans (by rwa [le_div_iff_mul_le _ _ hb0]) hc, + by simp [lt_succ_iff, le_div_iff_mul_le _ _ hb0]; tauto + +/-- The given sum is the number of integer points in the triangle formed by the diagonal of the + rectangle `(0, p/2) × (0, q/2)` -/ +private lemma sum_Ico_eq_card_lt {p q : ℕ} : + ∑ a in Ico 1 (p / 2).succ, (a * q) / p = + (((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)).filter + (λ x : ℕ × ℕ, x.2 * p ≤ x.1 * q)).card := +if hp0 : p = 0 then by simp [hp0, finset.ext_iff] +else + calc ∑ a in Ico 1 (p / 2).succ, (a * q) / p = + ∑ a in Ico 1 (p / 2).succ, + ((Ico 1 (q / 2).succ).filter (λ x, x * p ≤ a * q)).card : + finset.sum_congr rfl $ λ x hx, + div_eq_filter_card (nat.pos_of_ne_zero hp0) + (calc x * q / p ≤ (p / 2) * q / p : + nat.div_le_div_right (mul_le_mul_of_nonneg_right + (le_of_lt_succ $ (mem_Ico.mp hx).2) + (nat.zero_le _)) + ... ≤ _ : nat.div_mul_div_le_div _ _ _) + ... = _ : by rw [← card_sigma]; + exact card_congr (λ a _, ⟨a.1, a.2⟩) + (by simp only [mem_filter, mem_sigma, and_self, forall_true_iff, mem_product] + {contextual := tt}) + (λ ⟨_, _⟩ ⟨_, _⟩, by simp only [prod.mk.inj_iff, eq_self_iff_true, and_self, heq_iff_eq, + forall_true_iff] {contextual := tt}) + (λ ⟨b₁, b₂⟩ h, ⟨⟨b₁, b₂⟩, + by revert h; simp only [mem_filter, eq_self_iff_true, exists_prop_of_true, mem_sigma, + and_self, forall_true_iff, mem_product] {contextual := tt}⟩) + +/-- Each of the sums in this lemma is the cardinality of the set integer points in each of the + two triangles formed by the diagonal of the rectangle `(0, p/2) × (0, q/2)`. Adding them + gives the number of points in the rectangle. -/ +lemma sum_mul_div_add_sum_mul_div_eq_mul (p q : ℕ) [hp : fact p.prime] + (hq0 : (q : zmod p) ≠ 0) : + ∑ a in Ico 1 (p / 2).succ, (a * q) / p + + ∑ a in Ico 1 (q / 2).succ, (a * p) / q = + (p / 2) * (q / 2) := +begin + have hswap : (((Ico 1 (q / 2).succ).product (Ico 1 (p / 2).succ)).filter + (λ x : ℕ × ℕ, x.2 * q ≤ x.1 * p)).card = + (((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)).filter + (λ x : ℕ × ℕ, x.1 * q ≤ x.2 * p)).card := + card_congr (λ x _, prod.swap x) + (λ ⟨_, _⟩, by simp only [mem_filter, and_self, prod.swap_prod_mk, forall_true_iff, mem_product] + {contextual := tt}) + (λ ⟨_, _⟩ ⟨_, _⟩, by simp only [prod.mk.inj_iff, eq_self_iff_true, and_self, prod.swap_prod_mk, + forall_true_iff] {contextual := tt}) + (λ ⟨x₁, x₂⟩ h, ⟨⟨x₂, x₁⟩, by revert h; simp only [mem_filter, eq_self_iff_true, and_self, + exists_prop_of_true, prod.swap_prod_mk, forall_true_iff, mem_product] {contextual := tt}⟩), + have hdisj : disjoint + (((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)).filter + (λ x : ℕ × ℕ, x.2 * p ≤ x.1 * q)) + (((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)).filter + (λ x : ℕ × ℕ, x.1 * q ≤ x.2 * p)), + { apply disjoint_filter.2 (λ x hx hpq hqp, _), + have hxp : x.1 < p, from lt_of_le_of_lt + (show x.1 ≤ p / 2, by simp only [*, lt_succ_iff, mem_Ico, mem_product] at *; tauto) + (nat.div_lt_self hp.1.pos dec_trivial), + have : (x.1 : zmod p) = 0, + { simpa [hq0] using congr_arg (coe : ℕ → zmod p) (le_antisymm hpq hqp) }, + apply_fun zmod.val at this, + rw [val_cast_of_lt hxp, val_zero] at this, + simpa only [this, nonpos_iff_eq_zero, mem_Ico, one_ne_zero, false_and, mem_product] using hx }, + have hunion : ((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)).filter + (λ x : ℕ × ℕ, x.2 * p ≤ x.1 * q) ∪ + ((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)).filter + (λ x : ℕ × ℕ, x.1 * q ≤ x.2 * p) = + ((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)), + from finset.ext (λ x, by have := le_total (x.2 * p) (x.1 * q); + simp only [mem_union, mem_filter, mem_Ico, mem_product]; tauto), + rw [sum_Ico_eq_card_lt, sum_Ico_eq_card_lt, hswap, ← card_disjoint_union hdisj, hunion, + card_product], + simp only [card_Ico, tsub_zero, succ_sub_succ_eq_sub] +end + +end legendre_symbol + +end gauss_eisenstein diff --git a/src/number_theory/legendre_symbol/quadratic_reciprocity.lean b/src/number_theory/legendre_symbol/quadratic_reciprocity.lean index 80cd534fb2292..b2efdd48393c9 100644 --- a/src/number_theory/legendre_symbol/quadratic_reciprocity.lean +++ b/src/number_theory/legendre_symbol/quadratic_reciprocity.lean @@ -7,6 +7,7 @@ Authors: Chris Hughes import field_theory.finite.basic import data.zmod.basic import data.nat.parity +import number_theory.legendre_symbol.gauss_eisenstein_lemmas /-! # Quadratic reciprocity. @@ -102,256 +103,6 @@ begin exact pow_card_sub_one_eq_one ha end -/-- **Wilson's Lemma**: the product of `1`, ..., `p-1` is `-1` modulo `p`. -/ -@[simp] lemma wilsons_lemma : ((p - 1)! : zmod p) = -1 := -begin - refine - calc ((p - 1)! : zmod p) = (∏ x in Ico 1 (succ (p - 1)), x) : - by rw [← finset.prod_Ico_id_eq_factorial, prod_nat_cast] - ... = (∏ x : (zmod p)ˣ, x) : _ - ... = -1 : by simp_rw [← units.coe_hom_apply, - ← (units.coe_hom (zmod p)).map_prod, prod_univ_units_id_eq_neg_one, units.coe_hom_apply, - units.coe_neg, units.coe_one], - have hp : 0 < p := (fact.out p.prime).pos, - symmetry, - refine prod_bij (λ a _, (a : zmod p).val) _ _ _ _, - { intros a ha, - rw [mem_Ico, ← nat.succ_sub hp, nat.succ_sub_one], - split, - { apply nat.pos_of_ne_zero, rw ← @val_zero p, - assume h, apply units.ne_zero a (val_injective p h) }, - { exact val_lt _ } }, - { intros a ha, simp only [cast_id, nat_cast_val], }, - { intros _ _ _ _ h, rw units.ext_iff, exact val_injective p h }, - { intros b hb, - rw [mem_Ico, nat.succ_le_iff, ← succ_sub hp, succ_sub_one, pos_iff_ne_zero] at hb, - refine ⟨units.mk0 b _, finset.mem_univ _, _⟩, - { assume h, apply hb.1, apply_fun val at h, - simpa only [val_cast_of_lt hb.right, val_zero] using h }, - { simp only [val_cast_of_lt hb.right, units.coe_mk0], } } -end - -@[simp] lemma prod_Ico_one_prime : (∏ x in Ico 1 p, (x : zmod p)) = -1 := -begin - conv in (Ico 1 p) { rw [← succ_sub_one p, succ_sub (fact.out p.prime).pos] }, - rw [← prod_nat_cast, finset.prod_Ico_id_eq_factorial, wilsons_lemma] -end - -end zmod - -/-- The image of the map sending a non zero natural number `x ≤ p / 2` to the absolute value - of the element of interger in the interval `(-p/2, p/2]` congruent to `a * x` mod p is the set - of non zero natural numbers `x` such that `x ≤ p / 2` -/ -lemma Ico_map_val_min_abs_nat_abs_eq_Ico_map_id - (p : ℕ) [hp : fact p.prime] (a : zmod p) (hap : a ≠ 0) : - (Ico 1 (p / 2).succ).1.map (λ x, (a * x).val_min_abs.nat_abs) = - (Ico 1 (p / 2).succ).1.map (λ a, a) := -begin - have he : ∀ {x}, x ∈ Ico 1 (p / 2).succ → x ≠ 0 ∧ x ≤ p / 2, - by simp [nat.lt_succ_iff, nat.succ_le_iff, pos_iff_ne_zero] {contextual := tt}, - have hep : ∀ {x}, x ∈ Ico 1 (p / 2).succ → x < p, - from λ x hx, lt_of_le_of_lt (he hx).2 (nat.div_lt_self hp.1.pos dec_trivial), - have hpe : ∀ {x}, x ∈ Ico 1 (p / 2).succ → ¬ p ∣ x, - from λ x hx hpx, not_lt_of_ge (le_of_dvd (nat.pos_of_ne_zero (he hx).1) hpx) (hep hx), - have hmem : ∀ (x : ℕ) (hx : x ∈ Ico 1 (p / 2).succ), - (a * x : zmod p).val_min_abs.nat_abs ∈ Ico 1 (p / 2).succ, - { assume x hx, - simp [hap, char_p.cast_eq_zero_iff (zmod p) p, hpe hx, lt_succ_iff, succ_le_iff, - pos_iff_ne_zero, nat_abs_val_min_abs_le _], }, - have hsurj : ∀ (b : ℕ) (hb : b ∈ Ico 1 (p / 2).succ), - ∃ x ∈ Ico 1 (p / 2).succ, b = (a * x : zmod p).val_min_abs.nat_abs, - { assume b hb, - refine ⟨(b / a : zmod p).val_min_abs.nat_abs, mem_Ico.mpr ⟨_, _⟩, _⟩, - { apply nat.pos_of_ne_zero, - simp only [div_eq_mul_inv, hap, char_p.cast_eq_zero_iff (zmod p) p, hpe hb, not_false_iff, - val_min_abs_eq_zero, inv_eq_zero, int.nat_abs_eq_zero, ne.def, mul_eq_zero, or_self] }, - { apply lt_succ_of_le, apply nat_abs_val_min_abs_le }, - { rw nat_cast_nat_abs_val_min_abs, - split_ifs, - { erw [mul_div_cancel' _ hap, val_min_abs_def_pos, val_cast_of_lt (hep hb), - if_pos (le_of_lt_succ (mem_Ico.1 hb).2), int.nat_abs_of_nat], }, - { erw [mul_neg, mul_div_cancel' _ hap, nat_abs_val_min_abs_neg, - val_min_abs_def_pos, val_cast_of_lt (hep hb), if_pos (le_of_lt_succ (mem_Ico.1 hb).2), - int.nat_abs_of_nat] } } }, - exact multiset.map_eq_map_of_bij_of_nodup _ _ (finset.nodup _) (finset.nodup _) - (λ x _, (a * x : zmod p).val_min_abs.nat_abs) hmem (λ _ _, rfl) - (inj_on_of_surj_on_of_card_le _ hmem hsurj le_rfl) hsurj -end - -private lemma gauss_lemma_aux₁ (p : ℕ) [fact p.prime] [fact (p % 2 = 1)] - {a : ℤ} (hap : (a : zmod p) ≠ 0) : - (a^(p / 2) * (p / 2)! : zmod p) = - (-1)^((Ico 1 (p / 2).succ).filter - (λ x : ℕ, ¬(a * x : zmod p).val ≤ p / 2)).card * (p / 2)! := -calc (a ^ (p / 2) * (p / 2)! : zmod p) = - (∏ x in Ico 1 (p / 2).succ, a * x) : - by rw [prod_mul_distrib, ← prod_nat_cast, prod_Ico_id_eq_factorial, - prod_const, card_Ico, succ_sub_one]; simp -... = (∏ x in Ico 1 (p / 2).succ, (a * x : zmod p).val) : by simp -... = (∏ x in Ico 1 (p / 2).succ, - (if (a * x : zmod p).val ≤ p / 2 then 1 else -1) * - (a * x : zmod p).val_min_abs.nat_abs) : - prod_congr rfl $ λ _ _, begin - simp only [nat_cast_nat_abs_val_min_abs], - split_ifs; simp - end -... = (-1)^((Ico 1 (p / 2).succ).filter - (λ x : ℕ, ¬(a * x : zmod p).val ≤ p / 2)).card * - (∏ x in Ico 1 (p / 2).succ, (a * x : zmod p).val_min_abs.nat_abs) : - have (∏ x in Ico 1 (p / 2).succ, - if (a * x : zmod p).val ≤ p / 2 then (1 : zmod p) else -1) = - (∏ x in (Ico 1 (p / 2).succ).filter - (λ x : ℕ, ¬(a * x : zmod p).val ≤ p / 2), -1), - from prod_bij_ne_one (λ x _ _, x) - (λ x, by split_ifs; simp * at * {contextual := tt}) - (λ _ _ _ _ _ _, id) - (λ b h _, ⟨b, by simp [-not_le, *] at *⟩) - (by intros; split_ifs at *; simp * at *), - by rw [prod_mul_distrib, this]; simp -... = (-1)^((Ico 1 (p / 2).succ).filter - (λ x : ℕ, ¬(a * x : zmod p).val ≤ p / 2)).card * (p / 2)! : - by rw [← prod_nat_cast, finset.prod_eq_multiset_prod, - Ico_map_val_min_abs_nat_abs_eq_Ico_map_id p a hap, - ← finset.prod_eq_multiset_prod, prod_Ico_id_eq_factorial] - -private lemma gauss_lemma_aux₂ (p : ℕ) [hp : fact p.prime] [fact (p % 2 = 1)] - {a : ℤ} (hap : (a : zmod p) ≠ 0) : - (a^(p / 2) : zmod p) = (-1)^((Ico 1 (p / 2).succ).filter - (λ x : ℕ, p / 2 < (a * x : zmod p).val)).card := -(mul_left_inj' - (show ((p / 2)! : zmod p) ≠ 0, - by rw [ne.def, char_p.cast_eq_zero_iff (zmod p) p, hp.1.dvd_factorial, not_le]; - exact nat.div_lt_self hp.1.pos dec_trivial)).1 $ - by simpa using gauss_lemma_aux₁ p hap - -private lemma eisenstein_lemma_aux₁ (p : ℕ) [fact p.prime] [hp2 : fact (p % 2 = 1)] - {a : ℕ} (hap : (a : zmod p) ≠ 0) : - ((∑ x in Ico 1 (p / 2).succ, a * x : ℕ) : zmod 2) = - ((Ico 1 (p / 2).succ).filter - ((λ x : ℕ, p / 2 < (a * x : zmod p).val))).card + - ∑ x in Ico 1 (p / 2).succ, x - + (∑ x in Ico 1 (p / 2).succ, (a * x) / p : ℕ) := -have hp2 : (p : zmod 2) = (1 : ℕ), from (eq_iff_modeq_nat _).2 hp2.1, -calc ((∑ x in Ico 1 (p / 2).succ, a * x : ℕ) : zmod 2) - = ((∑ x in Ico 1 (p / 2).succ, ((a * x) % p + p * ((a * x) / p)) : ℕ) : zmod 2) : - by simp only [mod_add_div] -... = (∑ x in Ico 1 (p / 2).succ, ((a * x : ℕ) : zmod p).val : ℕ) + - (∑ x in Ico 1 (p / 2).succ, (a * x) / p : ℕ) : - by simp only [val_nat_cast]; - simp [sum_add_distrib, mul_sum.symm, nat.cast_add, nat.cast_mul, nat.cast_sum, hp2] -... = _ : congr_arg2 (+) - (calc ((∑ x in Ico 1 (p / 2).succ, ((a * x : ℕ) : zmod p).val : ℕ) : zmod 2) - = ∑ x in Ico 1 (p / 2).succ, - ((((a * x : zmod p).val_min_abs + - (if (a * x : zmod p).val ≤ p / 2 then 0 else p)) : ℤ) : zmod 2) : - by simp only [(val_eq_ite_val_min_abs _).symm]; simp [nat.cast_sum] - ... = ((Ico 1 (p / 2).succ).filter - (λ x : ℕ, p / 2 < (a * x : zmod p).val)).card + - ((∑ x in Ico 1 (p / 2).succ, (a * x : zmod p).val_min_abs.nat_abs) : ℕ) : - by { simp [ite_cast, add_comm, sum_add_distrib, finset.sum_ite, hp2, nat.cast_sum], } - ... = _ : by rw [finset.sum_eq_multiset_sum, - Ico_map_val_min_abs_nat_abs_eq_Ico_map_id p a hap, - ← finset.sum_eq_multiset_sum]; - simp [nat.cast_sum]) rfl - -private lemma eisenstein_lemma_aux₂ (p : ℕ) [fact p.prime] [fact (p % 2 = 1)] - {a : ℕ} (ha2 : a % 2 = 1) (hap : (a : zmod p) ≠ 0) : - ((Ico 1 (p / 2).succ).filter - ((λ x : ℕ, p / 2 < (a * x : zmod p).val))).card - ≡ ∑ x in Ico 1 (p / 2).succ, (x * a) / p [MOD 2] := -have ha2 : (a : zmod 2) = (1 : ℕ), from (eq_iff_modeq_nat _).2 ha2, -(eq_iff_modeq_nat 2).1 $ sub_eq_zero.1 $ - by simpa [add_left_comm, sub_eq_add_neg, finset.mul_sum.symm, mul_comm, ha2, nat.cast_sum, - add_neg_eq_iff_eq_add.symm, neg_eq_self_mod_two, add_assoc] - using eq.symm (eisenstein_lemma_aux₁ p hap) - -lemma div_eq_filter_card {a b c : ℕ} (hb0 : 0 < b) (hc : a / b ≤ c) : a / b = - ((Ico 1 c.succ).filter (λ x, x * b ≤ a)).card := -calc a / b = (Ico 1 (a / b).succ).card : by simp -... = ((Ico 1 c.succ).filter (λ x, x * b ≤ a)).card : - congr_arg _ $ finset.ext $ λ x, - have x * b ≤ a → x ≤ c, - from λ h, le_trans (by rwa [le_div_iff_mul_le _ _ hb0]) hc, - by simp [lt_succ_iff, le_div_iff_mul_le _ _ hb0]; tauto - -/-- The given sum is the number of integer points in the triangle formed by the diagonal of the - rectangle `(0, p/2) × (0, q/2)` -/ -private lemma sum_Ico_eq_card_lt {p q : ℕ} : - ∑ a in Ico 1 (p / 2).succ, (a * q) / p = - (((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)).filter - (λ x : ℕ × ℕ, x.2 * p ≤ x.1 * q)).card := -if hp0 : p = 0 then by simp [hp0, finset.ext_iff] -else - calc ∑ a in Ico 1 (p / 2).succ, (a * q) / p = - ∑ a in Ico 1 (p / 2).succ, - ((Ico 1 (q / 2).succ).filter (λ x, x * p ≤ a * q)).card : - finset.sum_congr rfl $ λ x hx, - div_eq_filter_card (nat.pos_of_ne_zero hp0) - (calc x * q / p ≤ (p / 2) * q / p : - nat.div_le_div_right (mul_le_mul_of_nonneg_right - (le_of_lt_succ $ (mem_Ico.mp hx).2) - (nat.zero_le _)) - ... ≤ _ : nat.div_mul_div_le_div _ _ _) - ... = _ : by rw [← card_sigma]; - exact card_congr (λ a _, ⟨a.1, a.2⟩) - (by simp only [mem_filter, mem_sigma, and_self, forall_true_iff, mem_product] - {contextual := tt}) - (λ ⟨_, _⟩ ⟨_, _⟩, by simp only [prod.mk.inj_iff, eq_self_iff_true, and_self, heq_iff_eq, - forall_true_iff] {contextual := tt}) - (λ ⟨b₁, b₂⟩ h, ⟨⟨b₁, b₂⟩, - by revert h; simp only [mem_filter, eq_self_iff_true, exists_prop_of_true, mem_sigma, - and_self, forall_true_iff, mem_product] {contextual := tt}⟩) - -/-- Each of the sums in this lemma is the cardinality of the set integer points in each of the - two triangles formed by the diagonal of the rectangle `(0, p/2) × (0, q/2)`. Adding them - gives the number of points in the rectangle. -/ -private lemma sum_mul_div_add_sum_mul_div_eq_mul (p q : ℕ) [hp : fact p.prime] - (hq0 : (q : zmod p) ≠ 0) : - ∑ a in Ico 1 (p / 2).succ, (a * q) / p + - ∑ a in Ico 1 (q / 2).succ, (a * p) / q = - (p / 2) * (q / 2) := -begin - have hswap : (((Ico 1 (q / 2).succ).product (Ico 1 (p / 2).succ)).filter - (λ x : ℕ × ℕ, x.2 * q ≤ x.1 * p)).card = - (((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)).filter - (λ x : ℕ × ℕ, x.1 * q ≤ x.2 * p)).card := - card_congr (λ x _, prod.swap x) - (λ ⟨_, _⟩, by simp only [mem_filter, and_self, prod.swap_prod_mk, forall_true_iff, mem_product] - {contextual := tt}) - (λ ⟨_, _⟩ ⟨_, _⟩, by simp only [prod.mk.inj_iff, eq_self_iff_true, and_self, prod.swap_prod_mk, - forall_true_iff] {contextual := tt}) - (λ ⟨x₁, x₂⟩ h, ⟨⟨x₂, x₁⟩, by revert h; simp only [mem_filter, eq_self_iff_true, and_self, - exists_prop_of_true, prod.swap_prod_mk, forall_true_iff, mem_product] {contextual := tt}⟩), - have hdisj : disjoint - (((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)).filter - (λ x : ℕ × ℕ, x.2 * p ≤ x.1 * q)) - (((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)).filter - (λ x : ℕ × ℕ, x.1 * q ≤ x.2 * p)), - { apply disjoint_filter.2 (λ x hx hpq hqp, _), - have hxp : x.1 < p, from lt_of_le_of_lt - (show x.1 ≤ p / 2, by simp only [*, lt_succ_iff, mem_Ico, mem_product] at *; tauto) - (nat.div_lt_self hp.1.pos dec_trivial), - have : (x.1 : zmod p) = 0, - { simpa [hq0] using congr_arg (coe : ℕ → zmod p) (le_antisymm hpq hqp) }, - apply_fun zmod.val at this, - rw [val_cast_of_lt hxp, val_zero] at this, - simpa only [this, nonpos_iff_eq_zero, mem_Ico, one_ne_zero, false_and, mem_product] using hx }, - have hunion : ((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)).filter - (λ x : ℕ × ℕ, x.2 * p ≤ x.1 * q) ∪ - ((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)).filter - (λ x : ℕ × ℕ, x.1 * q ≤ x.2 * p) = - ((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)), - from finset.ext (λ x, by have := le_total (x.2 * p) (x.1 * q); - simp only [mem_union, mem_filter, mem_Ico, mem_product]; tauto), - rw [sum_Ico_eq_card_lt, sum_Ico_eq_card_lt, hswap, ← card_disjoint_union hdisj, hunion, - card_product], - simp only [card_Ico, tsub_zero, succ_sub_succ_eq_sub] -end - -variables (p q : ℕ) [fact p.prime] [fact q.prime] - -namespace zmod - /-- The Legendre symbol of `a` and `p`, `legendre_sym p a`, is an integer defined as * `0` if `a` is `0` modulo `p`; @@ -410,7 +161,7 @@ lemma gauss_lemma {a : ℤ} [fact (p % 2 = 1)] (ha0 : (a : zmod p) ≠ 0) : (λ x : ℕ, p / 2 < (a * x : zmod p).val)).card := have (legendre_sym p a : zmod p) = (((-1)^((Ico 1 (p / 2).succ).filter (λ x : ℕ, p / 2 < (a * x : zmod p).val)).card : ℤ) : zmod p), - by rw [legendre_sym_eq_pow, gauss_lemma_aux₂ p ha0]; simp, + by rw [legendre_sym_eq_pow, legendre_symbol.gauss_lemma_aux p ha0]; simp, begin cases legendre_sym_eq_one_or_neg_one p a ha0; cases neg_one_pow_eq_or ℤ ((Ico 1 (p / 2).succ).filter @@ -433,7 +184,7 @@ begin have ha0' : ((a : ℤ) : zmod p) ≠ 0 := by { norm_cast, exact ha0 }, rw [neg_one_pow_eq_pow_mod_two, gauss_lemma p ha0', neg_one_pow_eq_pow_mod_two, (by norm_cast : ((a : ℤ) : zmod p) = (a : zmod p)), - show _ = _, from eisenstein_lemma_aux₂ p ha1 ha0] + show _ = _, from legendre_symbol.eisenstein_lemma_aux p ha1 ha0] end /-- **Quadratic reciprocity theorem** -/ @@ -442,12 +193,12 @@ theorem quadratic_reciprocity [hp1 : fact (p % 2 = 1)] [hq1 : fact (q % 2 = 1)] have hpq0 : (p : zmod q) ≠ 0, from prime_ne_zero q p hpq.symm, have hqp0 : (q : zmod p) ≠ 0, from prime_ne_zero p q hpq, by rw [eisenstein_lemma q hp1.1 hpq0, eisenstein_lemma p hq1.1 hqp0, - ← pow_add, sum_mul_div_add_sum_mul_div_eq_mul q p hpq0, mul_comm] + ← pow_add, legendre_symbol.sum_mul_div_add_sum_mul_div_eq_mul q p hpq0, mul_comm] lemma legendre_sym_two [hp1 : fact (p % 2 = 1)] : legendre_sym p 2 = (-1) ^ (p / 4 + p / 2) := begin have hp2 : p ≠ 2, from mt (congr_arg (% 2)) (by simpa using hp1.1), - have hp22 : p / 2 / 2 = _ := div_eq_filter_card (show 0 < 2, from dec_trivial) + have hp22 : p / 2 / 2 = _ := legendre_symbol.div_eq_filter_card (show 0 < 2, from dec_trivial) (nat.div_le_self (p / 2) 2), have hcard : (Ico 1 (p / 2).succ).card = p / 2, by simp, have hx2 : ∀ x ∈ Ico 1 (p / 2).succ, (2 * x : zmod p).val = 2 * x, From c988c6229455cbab9b4aaf07ab1ab41fa11c2f2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20In=C3=A9s=20de=20Frutos-Fern=C3=A1ndez?= Date: Fri, 15 Apr 2022 17:50:17 +0000 Subject: [PATCH 044/373] chore(number_theory/function_field): fix typo (#13464) --- src/number_theory/function_field.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/number_theory/function_field.lean b/src/number_theory/function_field.lean index eccf8def92a5b..3afd993726b30 100644 --- a/src/number_theory/function_field.lean +++ b/src/number_theory/function_field.lean @@ -277,7 +277,7 @@ instance valued_Fqt_infty : valued (Fqt_infty Fq) (with_zero (multiplicative ℤ lemma valued_Fqt_infty.def {x : Fqt_infty Fq} : valued.v (x) = @valued.extension (ratfunc Fq) _ _ _ (infty_valued_Fqt Fq) x := rfl -instance Fqt_infty.topologal_space : topological_space (Fqt_infty Fq) := +instance Fqt_infty.topological_space : topological_space (Fqt_infty Fq) := valued.topological_space (with_zero (multiplicative ℤ)) instance Fqt_infty.topological_division_ring : topological_division_ring (Fqt_infty Fq) := From 449e06a904fef33505a3e562309cbd9224956be5 Mon Sep 17 00:00:00 2001 From: Mark Lavrentyev Date: Fri, 15 Apr 2022 20:29:48 +0000 Subject: [PATCH 045/373] feat(algebraic_topology/fundamental_groupoid/fundamental_group): add type checker helpers for convertings paths to/from elements of fundamental group (#13182) This pr adds the following helper functions for converting paths to and from elements of the fundamental group: - `to_arrow`: converts element of the fundamental group to an arrow in the fundamental groupoid - `to_path`: converts element of the fundamental group to a (quotient of homotopic) path in the space - `from_arrow`: constructs an element of the fundamental group from a self-arrow in the fundamental groupoid - `from_path`: constructs an element of the fundamental group from a (quotient of homotopic) path in the space These parallel the similarly named functions for the fundamental group [here](https://github.com/leanprover-community/mathlib/blob/743ed5d1dd54fffd65e3a7f3522e4a4e85472964/src/algebraic_topology/fundamental_groupoid/basic.lean#L339-L355). They will prove helpful in doing computations with the fundamental group later e.g. for the disk, circle, etc. --- .../fundamental_groupoid/fundamental_group.lean | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/algebraic_topology/fundamental_groupoid/fundamental_group.lean b/src/algebraic_topology/fundamental_groupoid/fundamental_group.lean index ed49dc6d2e72b..2dfb249fa7de8 100644 --- a/src/algebraic_topology/fundamental_groupoid/fundamental_group.lean +++ b/src/algebraic_topology/fundamental_groupoid/fundamental_group.lean @@ -34,6 +34,7 @@ def fundamental_group (X : Type u) [topological_space X] (x : X) := namespace fundamental_group local attribute [instance] path.homotopic.setoid +local attribute [reducible] fundamental_groupoid /-- Get an isomorphism between the fundamental groups at two points given a path -/ def fundamental_group_mul_equiv_of_path (p : path x₀ x₁) : @@ -46,4 +47,20 @@ def fundamental_group_mul_equiv_of_path_connected [path_connected_space X] : (fundamental_group X x₀) ≃* (fundamental_group X x₁) := fundamental_group_mul_equiv_of_path (path_connected_space.some_path x₀ x₁) +/-- An element of the fundamental group as an arrow in the fundamental groupoid. -/ +abbreviation to_arrow {X : Top} {x : X} (p : fundamental_group X x) : x ⟶ x := +p.hom + +/-- An element of the fundamental group as a quotient of homotopic paths. -/ +abbreviation to_path {X : Top} {x : X} (p : fundamental_group X x) : + path.homotopic.quotient x x := to_arrow p + +/-- An element of the fundamental group, constructed from an arrow in the fundamental groupoid. -/ +abbreviation from_arrow {X : Top} {x : X} (p : x ⟶ x) : fundamental_group X x := +⟨p, category_theory.groupoid.inv p⟩ + +/-- An element of the fundamental gorup, constructed from a quotient of homotopic paths. -/ +abbreviation from_path {X : Top} {x : X} (p : path.homotopic.quotient x x) : + fundamental_group X x := from_arrow p + end fundamental_group From 862a5854eec8391746da856c2c4071a7b4ccbbc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Heikkil=C3=A4?= Date: Sat, 16 Apr 2022 05:39:36 +0000 Subject: [PATCH 046/373] feat(topology/stone_cech): add stone_cech_hom_ext (#13472) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The universal property that characterises the Stone–Čech compactification of a topological space X is that any function from X to a compact Hausdorff space extends uniquely to a continuous function on βX. Existence is already provided by `unique_stone_cech_extend`, but it seems that the uniqueness lemma was intentionally omitted previously. Easy, but probably worth being explicit about. Co-authored-by: Matias Heikkilä --- src/topology/stone_cech.lean | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/topology/stone_cech.lean b/src/topology/stone_cech.lean index 497e64c4b8734..4f93bb4abf2a2 100644 --- a/src/topology/stone_cech.lean +++ b/src/topology/stone_cech.lean @@ -247,6 +247,7 @@ dense_range_pure.quotient section extension variables {γ : Type u} [topological_space γ] [t2_space γ] [compact_space γ] +variables {γ' : Type u} [topological_space γ'] [t2_space γ'] variables {f : α → γ} (hf : continuous f) local attribute [elab_with_expected_type] quotient.lift @@ -262,6 +263,15 @@ ultrafilter_extend_extends f lemma continuous_stone_cech_extend : continuous (stone_cech_extend hf) := continuous_quot_lift _ (continuous_ultrafilter_extend f) +lemma stone_cech_hom_ext {g₁ g₂ : stone_cech α → γ'} + (h₁ : continuous g₁) (h₂ : continuous g₂) + (h : g₁ ∘ stone_cech_unit = g₂ ∘ stone_cech_unit) : g₁ = g₂ := +begin + apply continuous.ext_on dense_range_stone_cech_unit h₁ h₂, + rintros x ⟨x, rfl⟩, + apply (congr_fun h x) +end + end extension lemma convergent_eqv_pure {u : ultrafilter α} {x : α} (ux : ↑u ≤ 𝓝 x) : u ≈ pure x := From f7430cd76fadf42d04669c8d1d2212f4489a53ec Mon Sep 17 00:00:00 2001 From: negiizhao Date: Sat, 16 Apr 2022 12:38:45 +0000 Subject: [PATCH 047/373] feat(data/polynomial/eval): add `protected` on some lemmas about `polynomial.map` (#13478) These clash with global lemmas. --- src/algebra/polynomial/group_ring_action.lean | 6 ++-- src/data/polynomial/derivative.lean | 15 ++++---- src/data/polynomial/div.lean | 6 ++-- src/data/polynomial/eval.lean | 35 +++++++++--------- src/data/polynomial/field_division.lean | 11 +++--- src/data/polynomial/lifts.lean | 7 ++-- src/data/polynomial/ring_division.lean | 12 +++---- src/field_theory/polynomial_galois_group.lean | 2 +- src/field_theory/separable.lean | 5 +-- src/field_theory/splitting_field.lean | 36 ++++++++++--------- src/ring_theory/eisenstein_criterion.lean | 2 +- .../polynomial/cyclotomic/basic.lean | 22 ++++++------ src/ring_theory/polynomial/dickson.lean | 6 ++-- src/ring_theory/polynomial/gauss_lemma.lean | 8 ++--- 14 files changed, 92 insertions(+), 81 deletions(-) diff --git a/src/algebra/polynomial/group_ring_action.lean b/src/algebra/polynomial/group_ring_action.lean index c825b84b7e010..ee9c71ae70bfb 100644 --- a/src/algebra/polynomial/group_ring_action.lean +++ b/src/algebra/polynomial/group_ring_action.lean @@ -40,8 +40,10 @@ variables (M) noncomputable instance [mul_semiring_action M R] : mul_semiring_action M R[X] := { smul := (•), - smul_one := λ m, (smul_eq_map R m).symm ▸ map_one (mul_semiring_action.to_ring_hom M R m), - smul_mul := λ m p q, (smul_eq_map R m).symm ▸ map_mul (mul_semiring_action.to_ring_hom M R m), + smul_one := λ m, + (smul_eq_map R m).symm ▸ polynomial.map_one (mul_semiring_action.to_ring_hom M R m), + smul_mul := λ m p q, + (smul_eq_map R m).symm ▸ polynomial.map_mul (mul_semiring_action.to_ring_hom M R m), ..polynomial.distrib_mul_action } variables {M R} diff --git a/src/data/polynomial/derivative.lean b/src/data/polynomial/derivative.lean index 21431e6bed47a..a975e71d46d65 100644 --- a/src/data/polynomial/derivative.lean +++ b/src/data/polynomial/derivative.lean @@ -261,13 +261,14 @@ end theorem derivative_map [comm_semiring S] (p : R[X]) (f : R →+* S) : (p.map f).derivative = p.derivative.map f := polynomial.induction_on p - (λ r, by rw [map_C, derivative_C, derivative_C, map_zero]) - (λ p q ihp ihq, by rw [map_add, derivative_add, ihp, ihq, derivative_add, map_add]) - (λ n r ih, by rw [map_mul, map_C, polynomial.map_pow, map_X, derivative_mul, derivative_pow_succ, - derivative_C, zero_mul, zero_add, derivative_X, mul_one, derivative_mul, - derivative_pow_succ, derivative_C, zero_mul, zero_add, derivative_X, mul_one, - map_mul, map_C, map_mul, polynomial.map_pow, map_add, - polynomial.map_nat_cast, map_one, map_X]) + (λ r, by rw [map_C, derivative_C, derivative_C, polynomial.map_zero]) + (λ p q ihp ihq, by rw [polynomial.map_add, derivative_add, ihp, ihq, derivative_add, + polynomial.map_add]) + (λ n r ih, by rw [polynomial.map_mul, polynomial.map_C, polynomial.map_pow, polynomial.map_X, + derivative_mul, derivative_pow_succ, derivative_C, zero_mul, zero_add, derivative_X, mul_one, + derivative_mul, derivative_pow_succ, derivative_C, zero_mul, zero_add, derivative_X, mul_one, + polynomial.map_mul, polynomial.map_C, polynomial.map_mul, polynomial.map_pow, + polynomial.map_add, polynomial.map_nat_cast, polynomial.map_one, polynomial.map_X]) @[simp] theorem iterate_derivative_map [comm_semiring S] (p : R[X]) (f : R →+* S) (k : ℕ): diff --git a/src/data/polynomial/div.lean b/src/data/polynomial/div.lean index dbf72602e0694..d00f41b8ff398 100644 --- a/src/data/polynomial/div.lean +++ b/src/data/polynomial/div.lean @@ -301,7 +301,7 @@ begin haveI : nontrivial R := f.domain_nontrivial, have : map f p /ₘ map f q = map f (p /ₘ q) ∧ map f p %ₘ map f q = map f (p %ₘ q), { exact (div_mod_by_monic_unique ((p /ₘ q).map f) _ (hq.map f) - ⟨eq.symm $ by rw [← map_mul, ← map_add, mod_by_monic_add_div _ hq], + ⟨eq.symm $ by rw [← polynomial.map_mul, ← polynomial.map_add, mod_by_monic_add_div _ hq], calc _ ≤ degree (p %ₘ q) : degree_map_le _ _ ... < degree q : degree_mod_by_monic_lt _ hq ... = _ : eq.symm $ degree_map_eq_of_leading_coeff_ne_zero _ @@ -343,8 +343,8 @@ theorem map_dvd_map [comm_ring S] (f : R →+* S) (hf : function.injective f) {x begin rw [← dvd_iff_mod_by_monic_eq_zero hx, ← dvd_iff_mod_by_monic_eq_zero (hx.map f), ← map_mod_by_monic f hx], - exact ⟨λ H, map_injective f hf $ by rw [H, map_zero], - λ H, by rw [H, map_zero]⟩ + exact ⟨λ H, map_injective f hf $ by rw [H, polynomial.map_zero], + λ H, by rw [H, polynomial.map_zero]⟩ end @[simp] lemma mod_by_monic_one (p : R[X]) : p %ₘ 1 = 0 := diff --git a/src/data/polynomial/eval.lean b/src/data/polynomial/eval.lean index a2d31a2ea3e5a..313890d24ba70 100644 --- a/src/data/polynomial/eval.lean +++ b/src/data/polynomial/eval.lean @@ -510,13 +510,13 @@ begin rw [eval₂_monomial, monomial_eq_C_mul_X], refl, end -@[simp] lemma map_zero : (0 : R[X]).map f = 0 := eval₂_zero _ _ +@[simp] protected lemma map_zero : (0 : R[X]).map f = 0 := eval₂_zero _ _ -@[simp] lemma map_add : (p + q).map f = p.map f + q.map f := eval₂_add _ _ +@[simp] protected lemma map_add : (p + q).map f = p.map f + q.map f := eval₂_add _ _ -@[simp] lemma map_one : (1 : R[X]).map f = 1 := eval₂_one _ _ +@[simp] protected lemma map_one : (1 : R[X]).map f = 1 := eval₂_one _ _ -@[simp] lemma map_mul : (p * q).map f = p.map f * q.map f := +@[simp] protected lemma map_mul : (p * q).map f = p.map f * q.map f := by { rw [map, eval₂_mul_noncomm], exact λ k, (commute_X _).symm } @[simp] lemma map_smul (r : R) : (r • p).map f = f r • p.map f := @@ -531,10 +531,10 @@ by rw [map, eval₂_smul, ring_hom.comp_apply, C_mul'] -- lean/blob/487ac5d7e9b34800502e1ddf3c7c806c01cf9d51/src/frontends/lean/elaborator.cpp#L1876-L1913 def map_ring_hom (f : R →+* S) : R[X] →+* S[X] := { to_fun := polynomial.map f, - map_add' := λ _ _, map_add f, - map_zero' := map_zero f, - map_mul' := λ _ _, map_mul f, - map_one' := map_one f } + map_add' := λ _ _, polynomial.map_add f, + map_zero' := polynomial.map_zero f, + map_mul' := λ _ _, polynomial.map_mul f, + map_one' := polynomial.map_one f } @[simp] lemma coe_map_ring_hom (f : R →+* S) : ⇑(map_ring_hom f) = map f := rfl @@ -578,7 +578,8 @@ lemma map_injective (hf : function.injective f) : function.injective (map f) := lemma map_surjective (hf : function.surjective f) : function.surjective (map f) := λ p, polynomial.induction_on' p - (λ p q hp hq, let ⟨p', hp'⟩ := hp, ⟨q', hq'⟩ := hq in ⟨p' + q', by rw [map_add f, hp', hq']⟩) + (λ p q hp hq, let ⟨p', hp'⟩ := hp, ⟨q', hq'⟩ := hq + in ⟨p' + q', by rw [polynomial.map_add f, hp', hq']⟩) (λ n s, let ⟨r, hr⟩ := hf s in ⟨monomial n r, by rw [map_monomial f, hr]⟩) lemma degree_map_le (p : R[X]) : degree (p.map f) ≤ degree p := @@ -648,7 +649,7 @@ begin intros i hi, rcases h i with ⟨c, hc⟩, use [C c * X^i], - rw [coe_map_ring_hom, map_mul, map_C, hc, polynomial.map_pow, map_X] } + rw [coe_map_ring_hom, polynomial.map_mul, map_C, hc, polynomial.map_pow, map_X] } end lemma mem_map_range {R S : Type*} [ring R] [ring S] (f : R →+* S) @@ -669,10 +670,10 @@ protected lemma map_sum {ι : Type*} (g : ι → R[X]) (s : finset ι) : lemma map_comp (p q : R[X]) : map f (p.comp q) = (map f p).comp (map f q) := polynomial.induction_on p (by simp only [map_C, forall_const, C_comp, eq_self_iff_true]) - (by simp only [map_add, add_comp, forall_const, implies_true_iff, eq_self_iff_true] + (by simp only [polynomial.map_add, add_comp, forall_const, implies_true_iff, eq_self_iff_true] {contextual := tt}) (by simp only [pow_succ', ←mul_assoc, comp, forall_const, eval₂_mul_X, implies_true_iff, - eq_self_iff_true, map_X, map_mul] {contextual := tt}) + eq_self_iff_true, map_X, polynomial.map_mul] {contextual := tt}) @[simp] lemma eval_zero_map (f : R →+* S) (p : R[X]) : @@ -684,7 +685,7 @@ lemma eval_one_map (f : R →+* S) (p : R[X]) : (p.map f).eval 1 = f (p.eval 1) := begin apply polynomial.induction_on' p, - { intros p q hp hq, simp only [hp, hq, map_add, ring_hom.map_add, eval_add] }, + { intros p q hp hq, simp only [hp, hq, polynomial.map_add, ring_hom.map_add, eval_add] }, { intros n r, simp only [one_pow, mul_one, eval_monomial, map_monomial] } end @@ -693,7 +694,7 @@ lemma eval_nat_cast_map (f : R →+* S) (p : R[X]) (n : ℕ) : (p.map f).eval n = f (p.eval n) := begin apply polynomial.induction_on' p, - { intros p q hp hq, simp only [hp, hq, map_add, ring_hom.map_add, eval_add] }, + { intros p q hp hq, simp only [hp, hq, polynomial.map_add, ring_hom.map_add, eval_add] }, { intros n r, simp only [map_nat_cast f, eval_monomial, map_monomial, f.map_pow, f.map_mul] } end @@ -703,7 +704,7 @@ lemma eval_int_cast_map {R S : Type*} [ring R] [ring S] (p.map f).eval i = f (p.eval i) := begin apply polynomial.induction_on' p, - { intros p q hp hq, simp only [hp, hq, map_add, ring_hom.map_add, eval_add] }, + { intros p q hp hq, simp only [hp, hq, polynomial.map_add, ring_hom.map_add, eval_add] }, { intros n r, simp only [f.map_int_cast, eval_monomial, map_monomial, f.map_pow, f.map_mul] } end @@ -877,11 +878,11 @@ lemma C_neg : C (-a) = -C a := ring_hom.map_neg C a lemma C_sub : C (a - b) = C a - C b := ring_hom.map_sub C a b -@[simp] lemma map_sub {S} [ring S] (f : R →+* S) : +@[simp] protected lemma map_sub {S} [ring S] (f : R →+* S) : (p - q).map f = p.map f - q.map f := (map_ring_hom f).map_sub p q -@[simp] lemma map_neg {S} [ring S] (f : R →+* S) : +@[simp] protected lemma map_neg {S} [ring S] (f : R →+* S) : (-p).map f = -(p.map f) := (map_ring_hom f).map_neg p diff --git a/src/data/polynomial/field_division.lean b/src/data/polynomial/field_division.lean index d2ad1a0f19ade..b793ce51295c5 100644 --- a/src/data/polynomial/field_division.lean +++ b/src/data/polynomial/field_division.lean @@ -299,20 +299,21 @@ lemma map_div [field k] (f : R →+* k) : (p / q).map f = p.map f / q.map f := if hq0 : q = 0 then by simp [hq0] else -by rw [div_def, div_def, map_mul, map_div_by_monic f (monic_mul_leading_coeff_inv hq0)]; +by rw [div_def, div_def, polynomial.map_mul, map_div_by_monic f (monic_mul_leading_coeff_inv hq0)]; simp [f.map_inv, coeff_map f] lemma map_mod [field k] (f : R →+* k) : (p % q).map f = p.map f % q.map f := if hq0 : q = 0 then by simp [hq0] else by rw [mod_def, mod_def, leading_coeff_map f, ← f.map_inv, ← map_C f, - ← map_mul f, map_mod_by_monic f (monic_mul_leading_coeff_inv hq0)] + ← polynomial.map_mul f, map_mod_by_monic f (monic_mul_leading_coeff_inv hq0)] section open euclidean_domain theorem gcd_map [field k] (f : R →+* k) : gcd (p.map f) (q.map f) = (gcd p q).map f := -gcd.induction p q (λ x, by simp_rw [map_zero, euclidean_domain.gcd_zero_left]) $ λ x y hx ih, +gcd.induction p q (λ x, by simp_rw [polynomial.map_zero, euclidean_domain.gcd_zero_left]) $ + λ x y hx ih, by rw [gcd_val, ← map_mod, ih, ← gcd_val] end @@ -442,11 +443,11 @@ by simp [comm_group_with_zero.coe_norm_unit _ this] lemma normalize_monic (h : monic p) : normalize p = p := by simp [h] theorem map_dvd_map' [field k] (f : R →+* k) {x y : R[X]} : x.map f ∣ y.map f ↔ x ∣ y := -if H : x = 0 then by rw [H, map_zero, zero_dvd_iff, zero_dvd_iff, map_eq_zero] +if H : x = 0 then by rw [H, polynomial.map_zero, zero_dvd_iff, zero_dvd_iff, map_eq_zero] else by rw [← normalize_dvd_iff, ← @normalize_dvd_iff R[X], normalize_apply, normalize_apply, coe_norm_unit_of_ne_zero H, coe_norm_unit_of_ne_zero (mt (map_eq_zero f).1 H), - leading_coeff_map, ← f.map_inv, ← map_C, ← map_mul, + leading_coeff_map, ← f.map_inv, ← map_C, ← polynomial.map_mul, map_dvd_map _ f.injective (monic_mul_leading_coeff_inv H)] lemma degree_normalize : degree (normalize p) = degree p := by simp diff --git a/src/data/polynomial/lifts.lean b/src/data/polynomial/lifts.lean index beae068f583f6..52a3a3b89f079 100644 --- a/src/data/polynomial/lifts.lean +++ b/src/data/polynomial/lifts.lean @@ -125,7 +125,8 @@ lemma monomial_mem_lifts_and_degree_eq {s : S} {n : ℕ} (hl : monomial n s ∈ begin by_cases hzero : s = 0, { use 0, - simp only [hzero, degree_zero, eq_self_iff_true, and_self, monomial_zero_right, map_zero] }, + simp only [hzero, degree_zero, eq_self_iff_true, and_self, monomial_zero_right, + polynomial.map_zero] }, rw lifts_iff_set_range at hl, obtain ⟨q, hq⟩ := hl, replace hq := (ext_iff.1 hq) n, @@ -172,7 +173,7 @@ begin (erase_mem_lifts p.nat_degree hlifts) (refl p.erase_lead.nat_degree), use erase + lead, split, - { simp only [hlead, herase, map_add], + { simp only [hlead, herase, polynomial.map_add], nth_rewrite 0 erase_lead_add_monomial_nat_degree_leading_coeff p }, rw [←hdeg, erase_lead] at deg_erase, replace deg_erase := lt_of_le_of_lt degree_le_nat_degree (with_bot.coe_lt_coe.2 deg_erase), @@ -204,7 +205,7 @@ begin { rw [@degree_X_pow R, hq.2, degree_eq_nat_degree h0, with_bot.coe_lt_coe], exact or.resolve_right (erase_lead_nat_degree_lt_or_erase_lead_eq_zero p) h0, }, refine ⟨q + X ^ p.nat_degree, _, _, (monic_X_pow _).add_of_right hdeg⟩, - { rw [map_add, hq.1, polynomial.map_pow, map_X, H], }, + { rw [polynomial.map_add, hq.1, polynomial.map_pow, map_X, H], }, { rw [degree_add_eq_right_of_degree_lt hdeg, degree_X_pow, degree_eq_nat_degree hp.ne_zero] } end diff --git a/src/data/polynomial/ring_division.lean b/src/data/polynomial/ring_division.lean index d794849bb6dd3..8943000d89706 100644 --- a/src/data/polynomial/ring_division.lean +++ b/src/data/polynomial/ring_division.lean @@ -475,8 +475,8 @@ lemma le_root_multiplicity_map {K L : Type*} [comm_ring K] [comm_ring L] {p : K[X]} {f : K →+* L} (hf : function.injective f) (a : K) : root_multiplicity a p ≤ root_multiplicity (f a) (map f p) := begin - by_cases hp0 : p = 0, { simp only [hp0, root_multiplicity_zero, map_zero], }, - have hmap : map f p ≠ 0, { simpa only [map_zero] using (map_injective f hf).ne hp0, }, + by_cases hp0 : p = 0, { simp only [hp0, root_multiplicity_zero, polynomial.map_zero], }, + have hmap : map f p ≠ 0, { simpa only [polynomial.map_zero] using (map_injective f hf).ne hp0, }, rw [root_multiplicity, root_multiplicity, dif_neg hp0, dif_neg hmap], simp only [not_not, nat.lt_find_iff, nat.le_find_iff], intros m hm, @@ -505,8 +505,8 @@ lemma roots_map_of_injective_card_eq_total_degree {K L : Type*} [comm_ring K] [i (hroots : p.roots.card = p.nat_degree) : multiset.map f p.roots = (map f p).roots := begin - by_cases hp0 : p = 0, { simp only [hp0, roots_zero, multiset.map_zero, map_zero], }, - have hmap : map f p ≠ 0, { simpa only [map_zero] using (map_injective f hf).ne hp0, }, + by_cases hp0 : p = 0, { simp only [hp0, roots_zero, multiset.map_zero, polynomial.map_zero], }, + have hmap : map f p ≠ 0, { simpa only [polynomial.map_zero] using (map_injective f hf).ne hp0, }, apply multiset.eq_of_le_of_card_le, { simpa only [multiset.le_iff_count, count_roots] using count_map_roots hf }, { simpa only [multiset.card_map, hroots] using (card_roots' _).trans (nat_degree_map_le f p) }, @@ -638,7 +638,7 @@ begin rw [mem_root_set_iff', ←eval₂_eq_eval_map], { refl }, intro h, - rw ←map_zero (algebra_map T S) at h, + rw ←polynomial.map_zero (algebra_map T S) at h, exact hp (map_injective _ (no_zero_smul_divisors.algebra_map_injective T S) h) end @@ -773,7 +773,7 @@ begin clear q h_mon, have h' := congr_arg (map φ) h, - simp only [map_mul] at h', + simp only [polynomial.map_mul] at h', cases h_irr.is_unit_or_is_unit h' with w w, { left, exact is_unit_of_is_unit_leading_coeff_of_is_unit_map _ _ au w, }, diff --git a/src/field_theory/polynomial_galois_group.lean b/src/field_theory/polynomial_galois_group.lean index b62ab93563a5f..eeba7342675e5 100644 --- a/src/field_theory/polynomial_galois_group.lean +++ b/src/field_theory/polynomial_galois_group.lean @@ -238,7 +238,7 @@ begin dsimp only [restrict_prod, restrict_dvd] at hfg, simp only [dif_neg hpq, monoid_hom.prod_apply, prod.mk.inj_iff] at hfg, ext x hx, - rw [root_set, map_mul, polynomial.roots_mul] at hx, + rw [root_set, polynomial.map_mul, polynomial.roots_mul] at hx, cases multiset.mem_add.mp (multiset.mem_to_finset.mp hx) with h h, { haveI : fact (p.splits (algebra_map F (p * q).splitting_field)) := ⟨splits_of_splits_of_dvd _ hpq (splitting_field.splits (p * q)) (dvd_mul_right p q)⟩, diff --git a/src/field_theory/separable.lean b/src/field_theory/separable.lean index 99c801391ce2f..b48f18be4aebd 100644 --- a/src/field_theory/separable.lean +++ b/src/field_theory/separable.lean @@ -108,7 +108,8 @@ theorem separable.of_pow {f : R[X]} (hf : ¬is_unit f) {n : ℕ} (hn : n ≠ 0) theorem separable.map {p : R[X]} (h : p.separable) {f : R →+* S} : (p.map f).separable := let ⟨a, b, H⟩ := h in ⟨a.map f, b.map f, -by rw [derivative_map, ← map_mul, ← map_mul, ← map_add, H, map_one]⟩ +by rw [derivative_map, ← polynomial.map_mul, ← polynomial.map_mul, ← polynomial.map_add, H, + polynomial.map_one]⟩ variables (R) (p q : ℕ) @@ -307,7 +308,7 @@ include hp theorem expand_char (f : R[X]) : map (frobenius R p) (expand R p f) = f ^ p := begin refine f.induction_on' (λ a b ha hb, _) (λ n a, _), - { rw [alg_hom.map_add, map_add, ha, hb, add_pow_char], }, + { rw [alg_hom.map_add, polynomial.map_add, ha, hb, add_pow_char], }, { rw [expand_monomial, map_monomial, monomial_eq_C_mul_X, monomial_eq_C_mul_X, mul_pow, ← C.map_pow, frobenius_def], ring_exp } diff --git a/src/field_theory/splitting_field.lean b/src/field_theory/splitting_field.lean index 6557a70c9baf9..5c147f2d00af9 100644 --- a/src/field_theory/splitting_field.lean +++ b/src/field_theory/splitting_field.lean @@ -111,9 +111,9 @@ else or.inr $ λ p hp hpf, ((principal_ideal_ring.irreducible_iff_prime.1 hp).2. lemma splits_of_splits_mul {f g : K[X]} (hfg : f * g ≠ 0) (h : splits i (f * g)) : splits i f ∧ splits i g := ⟨or.inr $ λ g hgi hg, or.resolve_left h hfg hgi - (by rw map_mul; exact hg.trans (dvd_mul_right _ _)), + (by rw polynomial.map_mul; exact hg.trans (dvd_mul_right _ _)), or.inr $ λ g hgi hg, or.resolve_left h hfg hgi - (by rw map_mul; exact hg.trans (dvd_mul_left _ _))⟩ + (by rw polynomial.map_mul; exact hg.trans (dvd_mul_left _ _))⟩ lemma splits_of_splits_of_dvd {f g : K[X]} (hf0 : f ≠ 0) (hf : splits i f) (hgf : g ∣ f) : splits i g := @@ -233,7 +233,7 @@ classical.some_spec $ exists_root_of_splits i hf hfd theorem roots_map {f : K[X]} (hf : f.splits $ ring_hom.id K) : (f.map i).roots = (f.roots).map i := -if hf0 : f = 0 then by rw [hf0, map_zero, roots_zero, roots_zero, multiset.map_zero] else +if hf0 : f = 0 then by rw [hf0, polynomial.map_zero, roots_zero, roots_zero, multiset.map_zero] else have hmf0 : f.map i ≠ 0 := map_ne_zero hf0, let ⟨m, hm⟩ := exists_multiset_of_splits _ hf in have h1 : (0 : K[X]) ∉ m.map (λ r, X - C r), @@ -241,9 +241,10 @@ have h1 : (0 : K[X]) ∉ m.map (λ r, X - C r), have h2 : (0 : L[X]) ∉ m.map (λ r, X - C (i r)), from zero_nmem_multiset_map_X_sub_C _ _, begin - rw map_id at hm, rw hm at hf0 hmf0 ⊢, rw map_mul at hmf0 ⊢, + rw map_id at hm, rw hm at hf0 hmf0 ⊢, rw polynomial.map_mul at hmf0 ⊢, rw [roots_mul hf0, roots_mul hmf0, map_C, roots_C, zero_add, roots_C, zero_add, - polynomial.map_multiset_prod, multiset.map_map], simp_rw [(∘), map_sub, map_X, map_C], + polynomial.map_multiset_prod, multiset.map_map], + simp_rw [(∘), polynomial.map_sub, map_X, map_C], rw [roots_multiset_prod _ h2, multiset.bind_map, roots_multiset_prod _ h1, multiset.bind_map], simp_rw roots_X_sub_C, @@ -255,7 +256,7 @@ lemma eq_prod_roots_of_splits {p : K[X]} {i : K →+* L} p.map i = C (i p.leading_coeff) * ((p.map i).roots.map (λ a, X - C a)).prod := begin by_cases p_eq_zero : p = 0, - { rw [p_eq_zero, map_zero, leading_coeff_zero, i.map_zero, C.map_zero, zero_mul] }, + { rw [p_eq_zero, polynomial.map_zero, leading_coeff_zero, i.map_zero, C.map_zero, zero_mul] }, obtain ⟨s, hs⟩ := exists_multiset_of_splits i hsplit, have map_ne_zero : p.map i ≠ 0 := map_ne_zero (p_eq_zero), @@ -299,7 +300,7 @@ lemma nat_degree_eq_card_roots {p : K[X]} {i : K →+* L} (hsplit : splits i p) : p.nat_degree = (p.map i).roots.card := begin by_cases p_eq_zero : p = 0, - { rw [p_eq_zero, nat_degree_zero, map_zero, roots_zero, multiset.card_zero] }, + { rw [p_eq_zero, nat_degree_zero, polynomial.map_zero, roots_zero, multiset.card_zero] }, have map_ne_zero : p.map i ≠ 0 := map_ne_zero (p_eq_zero), rw eq_prod_roots_of_splits hsplit at map_ne_zero, @@ -408,14 +409,14 @@ lemma prod_multiset_X_sub_C_of_monic_of_roots_card_eq {K : Type*} [comm_ring K] begin apply map_injective _ (is_fraction_ring.injective K (fraction_ring K)), rw polynomial.map_multiset_prod, - simp only [map_C, function.comp_app, map_X, multiset.map_map, map_sub], + simp only [map_C, function.comp_app, map_X, multiset.map_map, polynomial.map_sub], have : p.roots.map (algebra_map K (fraction_ring K)) = (map (algebra_map K (fraction_ring K)) p).roots := roots_map_of_injective_card_eq_total_degree (is_fraction_ring.injective K (fraction_ring K)) hroots, rw ← prod_multiset_X_sub_C_of_monic_of_roots_card_eq_of_field (hmonic.map (algebra_map K (fraction_ring K))), - { simp only [map_C, function.comp_app, map_X, map_sub], + { simp only [map_C, function.comp_app, map_X, polynomial.map_sub], congr' 1, rw ← this, simp, }, @@ -458,8 +459,8 @@ begin have hcoeff : p.leading_coeff ≠ 0, { intro h, exact hzero (leading_coeff_eq_zero.1 h) }, apply map_injective _ (is_fraction_ring.injective K (fraction_ring K)), - rw [map_mul, polynomial.map_multiset_prod], - simp only [map_C, function.comp_app, map_X, multiset.map_map, map_sub], + rw [polynomial.map_mul, polynomial.map_multiset_prod], + simp only [map_C, function.comp_app, map_X, multiset.map_map, polynomial.map_sub], have h : p.roots.map (algebra_map K (fraction_ring K)) = (map (algebra_map K (fraction_ring K)) p).roots := roots_map_of_injective_card_eq_total_degree @@ -469,7 +470,7 @@ begin { rw [nat_degree_map_eq_of_injective (is_fraction_ring.injective K (fraction_ring K)), ← h], simp only [←hroots, multiset.card_map], }, rw [← C_leading_coeff_mul_prod_multiset_X_sub_C_of_field this], - simp only [map_C, function.comp_app, map_X, map_sub], + simp only [map_C, function.comp_app, map_X, polynomial.map_sub], have w : (algebra_map K (fraction_ring K)) p.leading_coeff ≠ 0, { intro hn, apply hcoeff, @@ -770,9 +771,10 @@ nat.rec_on n (λ K _ f hf, by exactI algebra.eq_top_iff.2 (λ x, subalgebra.rang have hndf : f.nat_degree ≠ 0, by { intro h, rw h at hfn, cases hfn }, have hfn0 : f ≠ 0, by { intro h, rw h at hndf, exact hndf rfl }, have hmf0 : map (algebra_map K (splitting_field_aux n.succ f hfn)) f ≠ 0 := map_ne_zero hfn0, -by { rw [algebra_map_succ, ← map_map, ← X_sub_C_mul_remove_factor _ hndf, map_mul] at hmf0 ⊢, -rw [roots_mul hmf0, map_sub, map_X, map_C, roots_X_sub_C, multiset.to_finset_add, finset.coe_union, - multiset.to_finset_singleton, finset.coe_singleton, +by { rw [algebra_map_succ, ← map_map, ← X_sub_C_mul_remove_factor _ hndf, + polynomial.map_mul] at hmf0 ⊢, +rw [roots_mul hmf0, polynomial.map_sub, map_X, map_C, roots_X_sub_C, multiset.to_finset_add, + finset.coe_union, multiset.to_finset_singleton, finset.coe_singleton, algebra.adjoin_union_eq_adjoin_adjoin, ← set.image_singleton, algebra.adjoin_algebra_map K (adjoin_root f.factor) (splitting_field_aux n f.remove_factor (nat_degree_remove_factor' hfn)), @@ -886,7 +888,7 @@ theorem mul (f g : F[X]) (hf : f ≠ 0) (hg : g ≠ 0) [is_splitting_field F K f ⟨(is_scalar_tower.algebra_map_eq F K L).symm ▸ splits_mul _ (splits_comp_of_splits _ _ (splits K f)) ((splits_map_iff _ _).1 (splits L $ g.map $ algebra_map F K)), - by rw [map_mul, roots_mul (mul_ne_zero (map_ne_zero hf : f.map (algebra_map F L) ≠ 0) + by rw [polynomial.map_mul, roots_mul (mul_ne_zero (map_ne_zero hf : f.map (algebra_map F L) ≠ 0) (map_ne_zero hg)), multiset.to_finset_add, finset.coe_union, algebra.adjoin_union_eq_adjoin_adjoin, is_scalar_tower.algebra_map_eq F K L, ← map_map, @@ -915,7 +917,7 @@ theorem finite_dimensional (f : K[X]) [is_splitting_field K L f] : finite_dimens ⟨@algebra.top_to_submodule K L _ _ _ ▸ adjoin_roots L f ▸ fg_adjoin_of_finite (set.finite_mem_finset _) (λ y hy, if hf : f = 0 - then by { rw [hf, map_zero, roots_zero] at hy, cases hy } + then by { rw [hf, polynomial.map_zero, roots_zero] at hy, cases hy } else is_algebraic_iff_is_integral.1 ⟨f, hf, (eval₂_eq_eval_map _).trans $ (mem_roots $ by exact map_ne_zero hf).1 (multiset.mem_to_finset.mp hy)⟩)⟩ diff --git a/src/ring_theory/eisenstein_criterion.lean b/src/ring_theory/eisenstein_criterion.lean index c4455398bdbe7..efd0a39bcc2af 100644 --- a/src/ring_theory/eisenstein_criterion.lean +++ b/src/ring_theory/eisenstein_criterion.lean @@ -84,7 +84,7 @@ have hfd0 : 0 < f.nat_degree, from with_bot.coe_lt_coe.1 ⟨mt degree_eq_zero_of_is_unit (λ h, by simp only [*, lt_irrefl] at *), begin rintros p q rfl, - rw [map_mul] at hf, + rw [polynomial.map_mul] at hf, rcases mul_eq_mul_prime_pow (show prime (X : polynomial (R ⧸ P)), from monic_X.prime_of_degree_eq_one degree_X) hf with ⟨m, n, b, c, hmnd, hbc, hp, hq⟩, diff --git a/src/ring_theory/polynomial/cyclotomic/basic.lean b/src/ring_theory/polynomial/cyclotomic/basic.lean index 4dbfb888773bf..ce299655c8ae9 100644 --- a/src/ring_theory/polynomial/cyclotomic/basic.lean +++ b/src/ring_theory/polynomial/cyclotomic/basic.lean @@ -219,7 +219,7 @@ begin cases nat.eq_zero_or_pos k with hzero hpos, { use 1, simp only [hzero, cyclotomic'_zero, set.mem_univ, subsemiring.coe_top, eq_self_iff_true, - coe_map_ring_hom, map_one, and_self] }, + coe_map_ring_hom, polynomial.map_one, and_self] }, let B : K[X] := ∏ i in nat.proper_divisors k, cyclotomic' i K, have Bmo : B.monic, { apply monic_prod_of_monic, @@ -286,7 +286,7 @@ lemma map_cyclotomic_int (n : ℕ) (R : Type*) [ring R] : map (int.cast_ring_hom R) (cyclotomic n ℤ) = cyclotomic n R := begin by_cases hzero : n = 0, - { simp only [hzero, cyclotomic, dif_pos, map_one] }, + { simp only [hzero, cyclotomic, dif_pos, polynomial.map_one] }, simp only [cyclotomic, int_cyclotomic_rw, hzero, ne.def, dif_neg, not_false_iff] end @@ -295,7 +295,7 @@ lemma int_cyclotomic_spec (n : ℕ) : map (int.cast_ring_hom ℂ) (cyclotomic n begin by_cases hzero : n = 0, { simp only [hzero, cyclotomic, degree_one, monic_one, cyclotomic'_zero, dif_pos, - eq_self_iff_true, map_one, and_self] }, + eq_self_iff_true, polynomial.map_one, and_self] }, rw int_cyclotomic_rw hzero, exact (int_coeff_of_cyclotomic' (complex.is_primitive_root_exp n hzero)).some_spec end @@ -324,20 +324,21 @@ by simp only [cyclotomic, dif_pos] @[simp] lemma cyclotomic_one (R : Type*) [ring R] : cyclotomic 1 R = X - 1 := begin have hspec : map (int.cast_ring_hom ℂ) (X - 1) = cyclotomic' 1 ℂ, - { simp only [cyclotomic'_one, pnat.one_coe, map_X, map_one, map_sub] }, + { simp only [cyclotomic'_one, pnat.one_coe, map_X, polynomial.map_one, polynomial.map_sub] }, symmetry, rw [←map_cyclotomic_int, ←(int_cyclotomic_unique hspec)], - simp only [map_X, map_one, map_sub] + simp only [map_X, polynomial.map_one, polynomial.map_sub] end /-- The second cyclotomic polyomial is `X + 1`. -/ @[simp] lemma cyclotomic_two (R : Type*) [ring R] : cyclotomic 2 R = X + 1 := begin have hspec : map (int.cast_ring_hom ℂ) (X + 1) = cyclotomic' 2 ℂ, - { simp only [cyclotomic'_two ℂ 0 two_ne_zero.symm, map_add, map_X, map_one] }, + { simp only [cyclotomic'_two ℂ 0 two_ne_zero.symm, polynomial.map_add, map_X, + polynomial.map_one], }, symmetry, rw [←map_cyclotomic_int, ←(int_cyclotomic_unique hspec)], - simp only [map_add, map_X, map_one] + simp only [polynomial.map_add, map_X, polynomial.map_one] end /-- `cyclotomic n` is monic. -/ @@ -390,7 +391,8 @@ begin have integer : ∏ i in nat.divisors n, cyclotomic i ℤ = X ^ n - 1, { apply map_injective (int.cast_ring_hom ℂ) int.cast_injective, rw polynomial.map_prod (int.cast_ring_hom ℂ) (λ i, cyclotomic i ℤ), - simp only [int_cyclotomic_spec, polynomial.map_pow, nat.cast_id, map_X, map_one, map_sub], + simp only [int_cyclotomic_spec, polynomial.map_pow, nat.cast_id, map_X, polynomial.map_one, + polynomial.map_sub], exact prod_cyclotomic'_eq_X_pow_sub_one hpos (complex.is_primitive_root_exp n (ne_of_lt hpos).symm) }, have coerc : X ^ n - 1 = map (int.cast_ring_hom R) (X ^ n - 1), @@ -893,13 +895,13 @@ begin { simp }, haveI := ne_zero.of_pos hnpos, suffices : expand ℤ p (cyclotomic n ℤ) = (cyclotomic (n * p) ℤ) * (cyclotomic n ℤ), - { rw [← map_cyclotomic_int, ← map_expand, this, map_mul, map_cyclotomic_int] }, + { rw [← map_cyclotomic_int, ← map_expand, this, polynomial.map_mul, map_cyclotomic_int] }, refine eq_of_monic_of_dvd_of_nat_degree_le ((cyclotomic.monic _ _).mul (cyclotomic.monic _ _)) ((cyclotomic.monic n ℤ).expand hp.pos) _ _, { refine (is_primitive.int.dvd_iff_map_cast_dvd_map_cast _ _ (is_primitive.mul (cyclotomic.is_primitive (n * p) ℤ) (cyclotomic.is_primitive n ℤ)) ((cyclotomic.monic n ℤ).expand hp.pos).is_primitive).2 _, - rw [map_mul, map_cyclotomic_int, map_cyclotomic_int, map_expand, map_cyclotomic_int], + rw [polynomial.map_mul, map_cyclotomic_int, map_cyclotomic_int, map_expand, map_cyclotomic_int], refine is_coprime.mul_dvd (cyclotomic.is_coprime_rat (λ h, _)) _ _, { replace h : n * p = n * 1 := by simp [h], exact nat.prime.ne_one hp (nat.eq_of_mul_eq_mul_left hnpos h) }, diff --git a/src/ring_theory/polynomial/dickson.lean b/src/ring_theory/polynomial/dickson.lean index 8b451ad9c956a..76e01282385bd 100644 --- a/src/ring_theory/polynomial/dickson.lean +++ b/src/ring_theory/polynomial/dickson.lean @@ -80,12 +80,12 @@ variables {R S k a} lemma map_dickson (f : R →+* S) : ∀ (n : ℕ), map f (dickson k a n) = dickson k (f a) n -| 0 := by simp only [dickson_zero, map_sub, polynomial.map_nat_cast, - bit1, bit0, map_add, map_one] +| 0 := by simp only [dickson_zero, polynomial.map_sub, polynomial.map_nat_cast, + bit1, bit0, polynomial.map_add, polynomial.map_one] | 1 := by simp only [dickson_one, map_X] | (n + 2) := begin - simp only [dickson_add_two, map_sub, map_mul, map_X, map_C], + simp only [dickson_add_two, polynomial.map_sub, polynomial.map_mul, map_X, map_C], rw [map_dickson, map_dickson] end diff --git a/src/ring_theory/polynomial/gauss_lemma.lean b/src/ring_theory/polynomial/gauss_lemma.lean index d769a46efd48f..fc1cc3df4bfeb 100644 --- a/src/ring_theory/polynomial/gauss_lemma.lean +++ b/src/ring_theory/polynomial/gauss_lemma.lean @@ -53,7 +53,7 @@ lemma is_primitive.irreducible_of_irreducible_map_of_injective (h_irr : irreduci begin refine ⟨λ h, h_irr.not_unit (is_unit.map (map_ring_hom φ) h), _⟩, intros a b h, - rcases h_irr.is_unit_or_is_unit (by rw [h, map_mul]) with hu | hu, + rcases h_irr.is_unit_or_is_unit (by rw [h, polynomial.map_mul]) with hu | hu, { left, rwa (hf.is_primitive_of_dvd (dvd.intro _ h.symm)).is_unit_iff_is_unit_map_of_injective hinj }, right, @@ -106,7 +106,7 @@ begin rw [ne.def, ← C_eq_zero] at hcd0, have h1 : C c * C d * p = integer_normalization R⁰ a * integer_normalization R⁰ b, { apply map_injective (algebra_map R K) (is_fraction_ring.injective _ _) _, - rw [map_mul, map_mul, map_mul, hc, hd, map_C, map_C, hab], + rw [polynomial.map_mul, polynomial.map_mul, polynomial.map_mul, hc, hd, map_C, map_C, hab], ring }, obtain ⟨u, hu⟩ : associated (c * d) (content (integer_normalization R⁰ a) * content (integer_normalization R⁰ b)), @@ -143,7 +143,7 @@ begin have h : p ∣ q * C s, { use (integer_normalization R⁰ r), apply map_injective (algebra_map R K) (is_fraction_ring.injective _ _), - rw [map_mul, map_mul, hs, hr, mul_assoc, mul_comm r], + rw [polynomial.map_mul, polynomial.map_mul, hs, hr, mul_assoc, mul_comm r], simp }, rw [← hp.dvd_prim_part_iff_dvd, prim_part_mul, hq.prim_part_eq, associated.dvd_iff_dvd_right] at h, @@ -163,7 +163,7 @@ variables (K) lemma is_primitive.dvd_iff_fraction_map_dvd_fraction_map {p q : R[X]} (hp : p.is_primitive) (hq : q.is_primitive) : (p ∣ q) ↔ (p.map (algebra_map R K) ∣ q.map (algebra_map R K)) := -⟨λ ⟨a,b⟩, ⟨a.map (algebra_map R K), b.symm ▸ map_mul (algebra_map R K)⟩, +⟨λ ⟨a,b⟩, ⟨a.map (algebra_map R K), b.symm ▸ polynomial.map_mul (algebra_map R K)⟩, λ h, hp.dvd_of_fraction_map_dvd_fraction_map hq h⟩ end fraction_map From 010f09e786d4a7231da1cde9c97bc0a301650eba Mon Sep 17 00:00:00 2001 From: negiizhao Date: Sat, 16 Apr 2022 14:27:42 +0000 Subject: [PATCH 048/373] feat(data/polynomial/taylor): add `taylor_alg_hom` (#13477) --- src/data/polynomial/taylor.lean | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/data/polynomial/taylor.lean b/src/data/polynomial/taylor.lean index d8e5e471e60d2..1fd7131492a7b 100644 --- a/src/data/polynomial/taylor.lean +++ b/src/data/polynomial/taylor.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin -/ +import data.polynomial.algebra_map import data.polynomial.hasse_deriv /-! @@ -89,6 +90,10 @@ end taylor r (p * q) = taylor r p * taylor r q := by simp only [taylor_apply, mul_comp] +/-- `polynomial.taylor` as a `alg_hom` for commutative semirings -/ +@[simps apply] def taylor_alg_hom {R} [comm_semiring R] (r : R) : R[X] →ₐ[R] R[X] := +alg_hom.of_linear_map (taylor r) (taylor_one r) (taylor_mul r) + lemma taylor_taylor {R} [comm_semiring R] (f : R[X]) (r s : R) : taylor r (taylor s f) = taylor (r + s) f := by simp only [taylor_apply, comp_assoc, map_add, add_comp, X_comp, C_comp, C_add, add_assoc] From 874dde52f661a63e76f88e00d3f1eb59e5be04ed Mon Sep 17 00:00:00 2001 From: negiizhao Date: Sat, 16 Apr 2022 16:18:59 +0000 Subject: [PATCH 049/373] feat(data/polynomial/eval): generalize smul lemmas (#13479) --- src/data/polynomial/eval.lean | 13 +++++++++---- src/topology/continuous_function/polynomial.lean | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/data/polynomial/eval.lean b/src/data/polynomial/eval.lean index 313890d24ba70..7639dbbba6a04 100644 --- a/src/data/polynomial/eval.lean +++ b/src/data/polynomial/eval.lean @@ -306,9 +306,10 @@ eval₂_monomial _ _ @[simp] lemma eval_bit1 : (bit1 p).eval x = bit1 (p.eval x) := eval₂_bit1 _ _ -@[simp] lemma eval_smul (p : R[X]) (x : R) {s : R} : - (s • p).eval x = s * p.eval x := -eval₂_smul (ring_hom.id _) _ _ +@[simp] lemma eval_smul [monoid S] [distrib_mul_action S R] [is_scalar_tower S R R] + (s : S) (p : R[X]) (x : R) : + (s • p).eval x = s • p.eval x := +by rw [← smul_one_smul R s p, eval, eval₂_smul, ring_hom.id_apply, smul_one_mul] @[simp] lemma eval_C_mul : (C a * p).eval x = a * p.eval x := begin @@ -323,7 +324,7 @@ end @[simps] def leval {R : Type*} [semiring R] (r : R) : R[X] →ₗ[R] R := { to_fun := λ f, f.eval r, map_add' := λ f g, eval_add, - map_smul' := λ c f, eval_smul f r } + map_smul' := λ c f, eval_smul c f r } @[simp] lemma eval_nat_cast_mul {n : ℕ} : ((n : R[X]) * p).eval x = n * p.eval x := by rw [←C_eq_nat_cast, eval_C_mul] @@ -469,6 +470,10 @@ by simp only [bit0, add_comp] @[simp] lemma bit1_comp : comp (bit1 p : R[X]) q = bit1 (p.comp q) := by simp only [bit1, add_comp, bit0_comp, one_comp] +@[simp] lemma smul_comp [monoid S] [distrib_mul_action S R] [is_scalar_tower S R R] + (s : S) (p q : R[X]) : (s • p).comp q = s • p.comp q := +by rw [← smul_one_smul R s p, comp, comp, eval₂_smul, ← smul_eq_C_mul, smul_assoc, one_smul] + lemma comp_assoc {R : Type*} [comm_semiring R] (φ ψ χ : R[X]) : (φ.comp ψ).comp χ = φ.comp (ψ.comp χ) := begin diff --git a/src/topology/continuous_function/polynomial.lean b/src/topology/continuous_function/polynomial.lean index 4241ad1260ee2..56cfe2d422548 100644 --- a/src/topology/continuous_function/polynomial.lean +++ b/src/topology/continuous_function/polynomial.lean @@ -153,7 +153,7 @@ begin simp only [neg_mul, ring_hom.map_neg, ring_hom.map_mul, alg_hom.coe_to_ring_hom, polynomial.eval_X, polynomial.eval_neg, polynomial.eval_C, polynomial.eval_smul, - polynomial.eval_mul, polynomial.eval_add, polynomial.coe_aeval_eq_eval, + smul_eq_mul, polynomial.eval_mul, polynomial.eval_add, polynomial.coe_aeval_eq_eval, polynomial.eval_comp, polynomial.to_continuous_map_on_alg_hom_apply, polynomial.to_continuous_map_on_to_fun, polynomial.to_continuous_map_to_fun], convert w ⟨_, _⟩; clear w, From 91a43e71f81a7bcef8eb23acd8d8d720020865f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Sat, 16 Apr 2022 17:33:11 +0000 Subject: [PATCH 050/373] feat(algebra/order/monoid): Co/contravariant classes for `with_bot`/`with_top` (#13369) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the `covariant_class (with_bot α) (with_bot α) (+) (≤)` and `contravariant_class (with_bot α) (with_bot α) (+) (<)` instances, as well as the lemmas that `covariant_class (with_bot α) (with_bot α) (+) (<)` and `contravariant_class (with_bot α) (with_bot α) (+) (≤)` almost hold. On the way, match the APIs for `with_bot`/`with_top` by adding missing lemmas. Co-authored-by: Wrenna Robson --- src/algebra/order/monoid.lean | 688 +++++++++++++++++------------- src/topology/instances/ereal.lean | 4 +- 2 files changed, 400 insertions(+), 292 deletions(-) diff --git a/src/algebra/order/monoid.lean b/src/algebra/order/monoid.lean index d3c1395785e5b..66f35e177ee4b 100644 --- a/src/algebra/order/monoid.lean +++ b/src/algebra/order/monoid.lean @@ -4,11 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Leonardo de Moura, Mario Carneiro, Johannes Hölzl -/ import algebra.group.with_one -import algebra.group.type_tags import algebra.group.prod import algebra.hom.equiv import algebra.order.monoid_lemmas -import order.bounded_order import order.min_max import order.hom.basic @@ -304,222 +302,6 @@ end end with_zero -namespace with_top - -section has_one - -variables [has_one α] - -@[to_additive] instance : has_one (with_top α) := ⟨(1 : α)⟩ - -@[simp, norm_cast, to_additive] lemma coe_one : ((1 : α) : with_top α) = 1 := rfl - -@[simp, norm_cast, to_additive] lemma coe_eq_one {a : α} : (a : with_top α) = 1 ↔ a = 1 := -coe_eq_coe - -@[simp, to_additive] protected lemma map_one {β} (f : α → β) : - (1 : with_top α).map f = (f 1 : with_top β) := rfl - -@[simp, norm_cast, to_additive] theorem one_eq_coe {a : α} : 1 = (a : with_top α) ↔ a = 1 := -trans eq_comm coe_eq_one - -@[simp, to_additive] theorem top_ne_one : ⊤ ≠ (1 : with_top α) . -@[simp, to_additive] theorem one_ne_top : (1 : with_top α) ≠ ⊤ . - -end has_one - -instance [has_add α] : has_add (with_top α) := -⟨λ o₁ o₂, o₁.bind (λ a, o₂.map (λ b, a + b))⟩ - -@[norm_cast] lemma coe_add [has_add α] {a b : α} : ((a + b : α) : with_top α) = a + b := rfl - -@[norm_cast] lemma coe_bit0 [has_add α] {a : α} : ((bit0 a : α) : with_top α) = bit0 a := rfl - -@[norm_cast] -lemma coe_bit1 [has_add α] [has_one α] {a : α} : ((bit1 a : α) : with_top α) = bit1 a := rfl - -@[simp] lemma add_top [has_add α] : ∀{a : with_top α}, a + ⊤ = ⊤ -| none := rfl -| (some a) := rfl - -@[simp] lemma top_add [has_add α] {a : with_top α} : ⊤ + a = ⊤ := rfl - -lemma add_eq_top [has_add α] {a b : with_top α} : a + b = ⊤ ↔ a = ⊤ ∨ b = ⊤ := -by cases a; cases b; simp [none_eq_top, some_eq_coe, ←with_top.coe_add, ←with_zero.coe_add] - -lemma add_lt_top [has_add α] [partial_order α] {a b : with_top α} : a + b < ⊤ ↔ a < ⊤ ∧ b < ⊤ := -by simp [lt_top_iff_ne_top, add_eq_top, not_or_distrib] - -lemma add_eq_coe [has_add α] : ∀ {a b : with_top α} {c : α}, - a + b = c ↔ ∃ (a' b' : α), ↑a' = a ∧ ↑b' = b ∧ a' + b' = c -| none b c := by simp [none_eq_top] -| (some a) none c := by simp [none_eq_top] -| (some a) (some b) c := - by simp only [some_eq_coe, ← coe_add, coe_eq_coe, exists_and_distrib_left, exists_eq_left] - -@[simp] lemma add_coe_eq_top_iff [has_add α] {x : with_top α} {y : α} : x + y = ⊤ ↔ x = ⊤ := -by { induction x using with_top.rec_top_coe; simp [← coe_add, -with_zero.coe_add] } - -@[simp] lemma coe_add_eq_top_iff [has_add α] {x : α} {y : with_top α} : ↑x + y = ⊤ ↔ y = ⊤ := -by { induction y using with_top.rec_top_coe; simp [← coe_add, -with_zero.coe_add] } - -instance [add_semigroup α] : add_semigroup (with_top α) := -{ add_assoc := begin - repeat { refine with_top.rec_top_coe _ _; try { intro }}; - simp [←with_top.coe_add, add_assoc] - end, - ..with_top.has_add } - -instance [add_comm_semigroup α] : add_comm_semigroup (with_top α) := -{ add_comm := - begin - repeat { refine with_top.rec_top_coe _ _; try { intro }}; - simp [←with_top.coe_add, add_comm] - end, - ..with_top.add_semigroup } - -instance [add_zero_class α] : add_zero_class (with_top α) := -{ zero_add := - begin - refine with_top.rec_top_coe _ _, - { simp }, - { intro, - rw [←with_top.coe_zero, ←with_top.coe_add, zero_add] } - end, - add_zero := - begin - refine with_top.rec_top_coe _ _, - { simp }, - { intro, - rw [←with_top.coe_zero, ←with_top.coe_add, add_zero] } - end, - ..with_top.has_zero, - ..with_top.has_add } - -instance [add_monoid α] : add_monoid (with_top α) := -{ ..with_top.add_zero_class, - ..with_top.has_zero, - ..with_top.add_semigroup } - -instance [add_comm_monoid α] : add_comm_monoid (with_top α) := -{ ..with_top.add_monoid, ..with_top.add_comm_semigroup } - -instance [ordered_add_comm_monoid α] : ordered_add_comm_monoid (with_top α) := -{ add_le_add_left := - begin - rintros a b h (_|c), { simp [none_eq_top] }, - rcases b with (_|b), { simp [none_eq_top] }, - rcases le_coe_iff.1 h with ⟨a, rfl, h⟩, - simp only [some_eq_coe, ← coe_add, coe_le_coe] at h ⊢, - exact add_le_add_left h c - end, - ..with_top.partial_order, ..with_top.add_comm_monoid } - -instance [linear_ordered_add_comm_monoid α] : - linear_ordered_add_comm_monoid_with_top (with_top α) := -{ top_add' := λ x, with_top.top_add, - ..with_top.order_top, - ..with_top.linear_order, - ..with_top.ordered_add_comm_monoid, - ..option.nontrivial } - -/-- Coercion from `α` to `with_top α` as an `add_monoid_hom`. -/ -def coe_add_hom [add_monoid α] : α →+ with_top α := -⟨coe, rfl, λ _ _, rfl⟩ - -@[simp] lemma coe_coe_add_hom [add_monoid α] : ⇑(coe_add_hom : α →+ with_top α) = coe := rfl - -@[simp] lemma zero_lt_top [ordered_add_comm_monoid α] : (0 : with_top α) < ⊤ := -coe_lt_top 0 - -@[simp, norm_cast] lemma zero_lt_coe [ordered_add_comm_monoid α] (a : α) : - (0 : with_top α) < a ↔ 0 < a := -coe_lt_coe - -end with_top - -namespace with_bot - -@[to_additive] instance [has_one α] : has_one (with_bot α) := with_top.has_one -instance [has_add α] : has_add (with_bot α) := with_top.has_add -instance [add_semigroup α] : add_semigroup (with_bot α) := with_top.add_semigroup -instance [add_comm_semigroup α] : add_comm_semigroup (with_bot α) := with_top.add_comm_semigroup -instance [add_zero_class α] : add_zero_class (with_bot α) := with_top.add_zero_class -instance [add_monoid α] : add_monoid (with_bot α) := with_top.add_monoid -instance [add_comm_monoid α] : add_comm_monoid (with_bot α) := with_top.add_comm_monoid - -instance [ordered_add_comm_monoid α] : ordered_add_comm_monoid (with_bot α) := -begin - suffices, refine - { add_le_add_left := this, - ..with_bot.partial_order, - ..with_bot.add_comm_monoid, ..}, - { intros a b h c ca h₂, - cases c with c, {cases h₂}, - cases a with a; cases h₂, - cases b with b, {cases le_antisymm h bot_le}, - simp at h, - exact ⟨_, rfl, add_le_add_left h _⟩, } -end - -instance [linear_ordered_add_comm_monoid α] : linear_ordered_add_comm_monoid (with_bot α) := -{ ..with_bot.linear_order, - ..with_bot.ordered_add_comm_monoid } - --- `by norm_cast` proves this lemma, so I did not tag it with `norm_cast` -@[to_additive] -lemma coe_one [has_one α] : ((1 : α) : with_bot α) = 1 := rfl - --- `by norm_cast` proves this lemma, so I did not tag it with `norm_cast` -@[to_additive] -lemma coe_eq_one [has_one α] {a : α} : (a : with_bot α) = 1 ↔ a = 1 := -with_top.coe_eq_one - -@[to_additive] protected lemma map_one {β} [has_one α] (f : α → β) : - (1 : with_bot α).map f = (f 1 : with_bot β) := rfl - --- `by norm_cast` proves this lemma, so I did not tag it with `norm_cast` -lemma coe_add [has_add α] (a b : α) : ((a + b : α) : with_bot α) = a + b := by norm_cast - --- `by norm_cast` proves this lemma, so I did not tag it with `norm_cast` -lemma coe_bit0 [has_add α] {a : α} : ((bit0 a : α) : with_bot α) = bit0 a := -by norm_cast - --- `by norm_cast` proves this lemma, so I did not tag it with `norm_cast` -lemma coe_bit1 [has_add α] [has_one α] {a : α} : ((bit1 a : α) : with_bot α) = bit1 a := -by norm_cast - -@[simp] lemma bot_add [has_add α] (a : with_bot α) : ⊥ + a = ⊥ := rfl - -@[simp] lemma add_bot [has_add α] (a : with_bot α) : a + ⊥ = ⊥ := by cases a; refl - -@[simp] lemma add_eq_bot [has_add α] {m n : with_bot α} : - m + n = ⊥ ↔ m = ⊥ ∨ n = ⊥ := -with_top.add_eq_top - -end with_bot - -namespace with_zero - -local attribute [semireducible] with_zero -variables [has_add α] - -/-- Making an additive monoid multiplicative then adding a zero is the same as adding a bottom -element then making it multiplicative. -/ -def to_mul_bot : with_zero (multiplicative α) ≃* multiplicative (with_bot α) := -by exact mul_equiv.refl _ - -@[simp] lemma to_mul_bot_zero : - to_mul_bot (0 : with_zero (multiplicative α)) = multiplicative.of_add ⊥ := rfl -@[simp] lemma to_mul_bot_coe (x : multiplicative α) : - to_mul_bot ↑x = multiplicative.of_add (x.to_add : with_bot α) := rfl -@[simp] lemma to_mul_bot_symm_bot : - to_mul_bot.symm (multiplicative.of_add (⊥ : with_bot α)) = 0 := rfl -@[simp] lemma to_mul_bot_coe_of_add (x : α) : - to_mul_bot.symm (multiplicative.of_add (x : with_bot α)) = multiplicative.of_add x := rfl - -end with_zero - /-- A canonically ordered additive monoid is an ordered commutative additive monoid in which the ordering coincides with the subtractibility relation, which is to say, `a ≤ b` iff there exists `c` with `b = a + c`. @@ -648,25 +430,6 @@ instance with_zero.canonically_ordered_add_monoid {α : Type u} [canonically_ord .. with_zero.order_bot, .. with_zero.ordered_add_comm_monoid zero_le } -instance with_top.canonically_ordered_add_monoid {α : Type u} [canonically_ordered_add_monoid α] : - canonically_ordered_add_monoid (with_top α) := -{ le_iff_exists_add := assume a b, - match a, b with - | ⊤, ⊤ := by simp - | (a : α), ⊤ := by { simp only [true_iff, le_top], refine ⟨⊤, _⟩, refl } - | (a : α), (b : α) := begin - rw [with_top.coe_le_coe, le_iff_exists_add], - split, - { rintro ⟨c, rfl⟩, - refine ⟨c, _⟩, norm_cast }, - { intro h, - exact match b, h with _, ⟨some c, rfl⟩ := ⟨_, rfl⟩ end } - end - | ⊤, (b : α) := by simp - end, - .. with_top.order_bot, - .. with_top.ordered_add_comm_monoid } - @[priority 100, to_additive] instance canonically_ordered_monoid.has_exists_mul_of_le (α : Type u) [canonically_ordered_monoid α] : has_exists_mul_of_le α := @@ -702,12 +465,6 @@ instance with_zero.canonically_linear_ordered_add_monoid { .. with_zero.canonically_ordered_add_monoid, .. with_zero.linear_order } -instance with_top.canonically_linear_ordered_add_monoid - (α : Type*) [canonically_linear_ordered_add_monoid α] : - canonically_linear_ordered_add_monoid (with_top α) := -{ .. (infer_instance : canonically_ordered_add_monoid (with_top α)), - .. (infer_instance : linear_order (with_top α)) } - @[to_additive] lemma min_mul_distrib (a b c : α) : min a (b * c) = min a (min a b * min a c) := begin @@ -911,6 +668,8 @@ def function.injective.linear_ordered_cancel_comm_monoid {β : Type*} end linear_ordered_cancel_comm_monoid +/-! ### Order dual -/ + namespace order_dual @[to_additive] instance [h : has_mul α] : has_mul (order_dual α) := h @@ -1002,67 +761,403 @@ instance [linear_ordered_comm_monoid α] : end order_dual -section linear_ordered_cancel_add_comm_monoid -variables [linear_ordered_cancel_add_comm_monoid α] +namespace prod + +variables {M N : Type*} -end linear_ordered_cancel_add_comm_monoid +@[to_additive] +instance [ordered_cancel_comm_monoid M] [ordered_cancel_comm_monoid N] : + ordered_cancel_comm_monoid (M × N) := +{ mul_le_mul_left := λ a b h c, ⟨mul_le_mul_left' h.1 _, mul_le_mul_left' h.2 _⟩, + le_of_mul_le_mul_left := λ a b c h, ⟨le_of_mul_le_mul_left' h.1, le_of_mul_le_mul_left' h.2⟩, + .. prod.cancel_comm_monoid, .. prod.partial_order M N } -section ordered_cancel_add_comm_monoid +end prod -variable [ordered_cancel_add_comm_monoid α] +/-! ### `with_bot`/`with_top`-/ namespace with_top -lemma add_lt_add_iff_left {a b c : with_top α} (ha : a ≠ ⊤) : a + b < a + c ↔ b < c := +section has_one + +variables [has_one α] + +@[to_additive] instance : has_one (with_top α) := ⟨(1 : α)⟩ + +@[simp, norm_cast, to_additive] lemma coe_one : ((1 : α) : with_top α) = 1 := rfl + +@[simp, norm_cast, to_additive] lemma coe_eq_one {a : α} : (a : with_top α) = 1 ↔ a = 1 := +coe_eq_coe + +@[simp, to_additive] protected lemma map_one {β} (f : α → β) : + (1 : with_top α).map f = (f 1 : with_top β) := rfl + +@[simp, norm_cast, to_additive] theorem one_eq_coe {a : α} : 1 = (a : with_top α) ↔ a = 1 := +trans eq_comm coe_eq_one + +@[simp, to_additive] theorem top_ne_one : ⊤ ≠ (1 : with_top α) . +@[simp, to_additive] theorem one_ne_top : (1 : with_top α) ≠ ⊤ . + +end has_one + +section has_add +variables [has_add α] {a b c d : with_top α} {x y : α} + +instance : has_add (with_top α) := ⟨λ o₁ o₂, o₁.bind $ λ a, o₂.map $ (+) a⟩ + +@[norm_cast] lemma coe_add : ((x + y : α) : with_top α) = x + y := rfl +@[norm_cast] lemma coe_bit0 : ((bit0 x : α) : with_top α) = bit0 x := rfl +@[norm_cast] lemma coe_bit1 [has_one α] {a : α} : ((bit1 a : α) : with_top α) = bit1 a := rfl + +@[simp] lemma top_add (a : with_top α) : ⊤ + a = ⊤ := rfl +@[simp] lemma add_top (a : with_top α) : a + ⊤ = ⊤ := by cases a; refl + +@[simp] lemma add_eq_top : a + b = ⊤ ↔ a = ⊤ ∨ b = ⊤ := +by cases a; cases b; simp [none_eq_top, some_eq_coe, ←with_top.coe_add, ←with_zero.coe_add] + +lemma add_ne_top : a + b ≠ ⊤ ↔ a ≠ ⊤ ∧ b ≠ ⊤ := add_eq_top.not.trans not_or_distrib + +lemma add_lt_top [partial_order α] {a b : with_top α} : a + b < ⊤ ↔ a < ⊤ ∧ b < ⊤ := +by simp_rw [lt_top_iff_ne_top, add_ne_top] + +lemma add_eq_coe : ∀ {a b : with_top α} {c : α}, + a + b = c ↔ ∃ (a' b' : α), ↑a' = a ∧ ↑b' = b ∧ a' + b' = c +| none b c := by simp [none_eq_top] +| (some a) none c := by simp [none_eq_top] +| (some a) (some b) c := + by simp only [some_eq_coe, ← coe_add, coe_eq_coe, exists_and_distrib_left, exists_eq_left] + +@[simp] lemma add_coe_eq_top_iff {x : with_top α} {y : α} : x + y = ⊤ ↔ x = ⊤ := +by { induction x using with_top.rec_top_coe; simp [← coe_add, -with_zero.coe_add] } + +@[simp] lemma coe_add_eq_top_iff {y : with_top α} : ↑x + y = ⊤ ↔ y = ⊤ := +by { induction y using with_top.rec_top_coe; simp [← coe_add, -with_zero.coe_add] } + +variables [preorder α] + +instance covariant_class_add_le [covariant_class α α (+) (≤)] : + covariant_class (with_top α) (with_top α) (+) (≤) := +⟨λ a b c h, begin + cases a; cases c; try { exact le_top }, + cases b, + { exact (not_top_le_coe _ h).elim }, + { exact some_le_some.2 (add_le_add_left (some_le_some.1 h) _) } +end⟩ + +instance covariant_class_swap_add_le [covariant_class α α (swap (+)) (≤)] : + covariant_class (with_top α) (with_top α) (swap (+)) (≤) := +⟨λ a b c h, begin + cases a; cases c; try { exact le_top }, + cases b, + { exact (not_top_le_coe _ h).elim }, + { exact some_le_some.2 (add_le_add_right (some_le_some.1 h) _) } +end⟩ + +instance contravariant_class_add_lt [contravariant_class α α (+) (<)] : + contravariant_class (with_top α) (with_top α) (+) (<) := +⟨λ a b c h, begin + cases a; cases b; try { exact (not_top_lt h).elim }, + cases c, + { exact coe_lt_top _ }, + { exact some_lt_some.2 (lt_of_add_lt_add_left $ some_lt_some.1 h) } +end⟩ + +instance contravariant_class_swap_add_lt [contravariant_class α α (swap (+)) (<)] : + contravariant_class (with_top α) (with_top α) (swap (+)) (<) := +⟨λ a b c h, begin + cases a; cases b; try { exact (not_top_lt h).elim }, + cases c, + { exact coe_lt_top _ }, + { exact some_lt_some.2 (lt_of_add_lt_add_right $ some_lt_some.1 h) } +end⟩ + +protected lemma le_of_add_le_add_left [contravariant_class α α (+) (≤)] (ha : a ≠ ⊤) + (h : a + b ≤ a + c) : b ≤ c := +begin + lift a to α using ha, + cases c; try {exact le_top}, + cases b, exact (not_top_le_coe _ h).elim, + simp only [some_eq_coe, ← coe_add, coe_le_coe] at h, rw some_le_some, + exact le_of_add_le_add_left h +end + +protected lemma le_of_add_le_add_right [contravariant_class α α (swap (+)) (≤)] (ha : a ≠ ⊤) + (h : b + a ≤ c + a) : b ≤ c := begin lift a to α using ha, - cases b; cases c, - { simp [none_eq_top] }, - { simp [some_eq_coe, none_eq_top, coe_lt_top] }, - { simp [some_eq_coe, none_eq_top, ← coe_add, coe_lt_top] }, - { simp [some_eq_coe, ← coe_add, coe_lt_coe] } + cases c, + { exact le_top }, + cases b, + { exact (not_top_le_coe _ h).elim }, + { exact some_le_some.2 (le_of_add_le_add_right $ some_le_some.1 h) } end -lemma add_lt_add_iff_right {a b c : with_top α} (ha : a ≠ ⊤) : (c + a < b + a ↔ c < b) := -by simp only [← add_comm a, add_lt_add_iff_left ha] +protected lemma add_lt_add_left [covariant_class α α (+) (<)] (ha : a ≠ ⊤) (h : b < c) : + a + b < a + c := +begin + lift a to α using ha, + lift b to α using (h.trans_le le_top).ne, + cases c, + { exact coe_lt_top _ }, + { exact some_lt_some.2 (add_lt_add_left (some_lt_some.1 h) _) } +end -instance contravariant_class_add_lt : contravariant_class (with_top α) (with_top α) (+) (<) := +protected lemma add_lt_add_right [covariant_class α α (swap (+)) (<)] (ha : a ≠ ⊤) (h : b < c) : + b + a < c + a := begin - refine ⟨λ a b c h, _⟩, - cases a, - { rw [none_eq_top, top_add, top_add] at h, exact (lt_irrefl ⊤ h).elim }, - { exact (add_lt_add_iff_left coe_ne_top).1 h } + lift a to α using ha, + lift b to α using (h.trans_le le_top).ne, + cases c, + { exact coe_lt_top _ }, + { exact some_lt_some.2 (add_lt_add_right (some_lt_some.1 h) _) } end +protected lemma add_le_add_iff_left [covariant_class α α (+) (≤)] [contravariant_class α α (+) (≤)] + (ha : a ≠ ⊤) : a + b ≤ a + c ↔ b ≤ c := +⟨with_top.le_of_add_le_add_left ha, λ h, add_le_add_left h a⟩ + +protected lemma add_le_add_iff_right [covariant_class α α (swap (+)) (≤)] + [contravariant_class α α (swap (+)) (≤)] (ha : a ≠ ⊤) : b + a ≤ c + a ↔ b ≤ c := +⟨with_top.le_of_add_le_add_right ha, λ h, add_le_add_right h a⟩ + +protected lemma add_lt_add_iff_left [covariant_class α α (+) (<)] [contravariant_class α α (+) (<)] + (ha : a ≠ ⊤) : a + b < a + c ↔ b < c := +⟨lt_of_add_lt_add_left, with_top.add_lt_add_left ha⟩ + +protected lemma add_lt_add_iff_right [covariant_class α α (swap (+)) (<)] + [contravariant_class α α (swap (+)) (<)] (ha : a ≠ ⊤) : b + a < c + a ↔ b < c := +⟨lt_of_add_lt_add_right, with_top.add_lt_add_right ha⟩ + +protected lemma add_lt_add_of_le_of_lt [covariant_class α α (+) (<)] + [covariant_class α α (swap (+)) (≤)] (ha : a ≠ ⊤) (hab : a ≤ b) (hcd : c < d) : a + c < b + d := +(with_top.add_lt_add_left ha hcd).trans_le $ add_le_add_right hab _ + +protected lemma add_lt_add_of_lt_of_le [covariant_class α α (+) (≤)] + [covariant_class α α (swap (+)) (<)] (hc : c ≠ ⊤) (hab : a < b) (hcd : c ≤ d) : a + c < b + d := +(with_top.add_lt_add_right hc hab).trans_le $ add_le_add_left hcd _ + +end has_add + +instance [add_semigroup α] : add_semigroup (with_top α) := +{ add_assoc := begin + repeat { refine with_top.rec_top_coe _ _; try { intro }}; + simp [←with_top.coe_add, add_assoc] + end, + ..with_top.has_add } + +instance [add_comm_semigroup α] : add_comm_semigroup (with_top α) := +{ add_comm := + begin + repeat { refine with_top.rec_top_coe _ _; try { intro }}; + simp [←with_top.coe_add, add_comm] + end, + ..with_top.add_semigroup } + +instance [add_zero_class α] : add_zero_class (with_top α) := +{ zero_add := + begin + refine with_top.rec_top_coe _ _, + { simp }, + { intro, + rw [←with_top.coe_zero, ←with_top.coe_add, zero_add] } + end, + add_zero := + begin + refine with_top.rec_top_coe _ _, + { simp }, + { intro, + rw [←with_top.coe_zero, ←with_top.coe_add, add_zero] } + end, + ..with_top.has_zero, + ..with_top.has_add } + +instance [add_monoid α] : add_monoid (with_top α) := +{ ..with_top.add_zero_class, + ..with_top.has_zero, + ..with_top.add_semigroup } + +instance [add_comm_monoid α] : add_comm_monoid (with_top α) := +{ ..with_top.add_monoid, ..with_top.add_comm_semigroup } + +instance [ordered_add_comm_monoid α] : ordered_add_comm_monoid (with_top α) := +{ add_le_add_left := + begin + rintros a b h (_|c), { simp [none_eq_top] }, + rcases b with (_|b), { simp [none_eq_top] }, + rcases le_coe_iff.1 h with ⟨a, rfl, h⟩, + simp only [some_eq_coe, ← coe_add, coe_le_coe] at h ⊢, + exact add_le_add_left h c + end, + ..with_top.partial_order, ..with_top.add_comm_monoid } + +instance [linear_ordered_add_comm_monoid α] : + linear_ordered_add_comm_monoid_with_top (with_top α) := +{ top_add' := with_top.top_add, + ..with_top.order_top, + ..with_top.linear_order, + ..with_top.ordered_add_comm_monoid, + ..option.nontrivial } + +instance [canonically_ordered_add_monoid α] : canonically_ordered_add_monoid (with_top α) := +{ le_iff_exists_add := assume a b, + match a, b with + | ⊤, ⊤ := by simp + | (a : α), ⊤ := by { simp only [true_iff, le_top], refine ⟨⊤, _⟩, refl } + | (a : α), (b : α) := begin + rw [with_top.coe_le_coe, le_iff_exists_add], + split, + { rintro ⟨c, rfl⟩, + refine ⟨c, _⟩, norm_cast }, + { intro h, + exact match b, h with _, ⟨some c, rfl⟩ := ⟨_, rfl⟩ end } + end + | ⊤, (b : α) := by simp + end, + .. with_top.order_bot, + .. with_top.ordered_add_comm_monoid } + +instance [canonically_linear_ordered_add_monoid α] : + canonically_linear_ordered_add_monoid (with_top α) := +{ ..with_top.canonically_ordered_add_monoid, ..with_top.linear_order } + +/-- Coercion from `α` to `with_top α` as an `add_monoid_hom`. -/ +def coe_add_hom [add_monoid α] : α →+ with_top α := +⟨coe, rfl, λ _ _, rfl⟩ + +@[simp] lemma coe_coe_add_hom [add_monoid α] : ⇑(coe_add_hom : α →+ with_top α) = coe := rfl + +@[simp] lemma zero_lt_top [ordered_add_comm_monoid α] : (0 : with_top α) < ⊤ := +coe_lt_top 0 + +@[simp, norm_cast] lemma zero_lt_coe [ordered_add_comm_monoid α] (a : α) : + (0 : with_top α) < a ↔ 0 < a := +coe_lt_coe + end with_top namespace with_bot -lemma add_lt_add_iff_left {a b c : with_bot α} (ha : a ≠ ⊥) : a + b < a + c ↔ b < c := -@with_top.add_lt_add_iff_left (order_dual α) _ a c b ha +@[to_additive] instance [has_one α] : has_one (with_bot α) := with_top.has_one +instance [has_add α] : has_add (with_bot α) := with_top.has_add +instance [add_semigroup α] : add_semigroup (with_bot α) := with_top.add_semigroup +instance [add_comm_semigroup α] : add_comm_semigroup (with_bot α) := with_top.add_comm_semigroup +instance [add_zero_class α] : add_zero_class (with_bot α) := with_top.add_zero_class +instance [add_monoid α] : add_monoid (with_bot α) := with_top.add_monoid +instance [add_comm_monoid α] : add_comm_monoid (with_bot α) := with_top.add_comm_monoid + +instance [ordered_add_comm_monoid α] : ordered_add_comm_monoid (with_bot α) := +begin + suffices, refine + { add_le_add_left := this, + ..with_bot.partial_order, + ..with_bot.add_comm_monoid, ..}, + { intros a b h c ca h₂, + cases c with c, {cases h₂}, + cases a with a; cases h₂, + cases b with b, {cases le_antisymm h bot_le}, + simp at h, + exact ⟨_, rfl, add_le_add_left h _⟩, } +end + +instance [linear_ordered_add_comm_monoid α] : linear_ordered_add_comm_monoid (with_bot α) := +{ ..with_bot.linear_order, ..with_bot.ordered_add_comm_monoid } + +-- `by norm_cast` proves this lemma, so I did not tag it with `norm_cast` +@[to_additive] +lemma coe_one [has_one α] : ((1 : α) : with_bot α) = 1 := rfl -lemma add_lt_add_iff_right {a b c : with_bot α} (ha : a ≠ ⊥) : b + a < c + a ↔ b < c := -@with_top.add_lt_add_iff_right (order_dual α) _ _ _ _ ha +-- `by norm_cast` proves this lemma, so I did not tag it with `norm_cast` +@[to_additive] +lemma coe_eq_one [has_one α] {a : α} : (a : with_bot α) = 1 ↔ a = 1 := +with_top.coe_eq_one -instance contravariant_class_add_lt : contravariant_class (with_bot α) (with_bot α) (+) (<) := +@[to_additive] protected lemma map_one {β} [has_one α] (f : α → β) : + (1 : with_bot α).map f = (f 1 : with_bot β) := rfl + +section has_add +variables [has_add α] {a b c d : with_bot α} {x y : α} + +-- `norm_cast` proves those lemmas, because `with_top`/`with_bot` are reducible +lemma coe_add (a b : α) : ((a + b : α) : with_bot α) = a + b := rfl +lemma coe_bit0 : ((bit0 x : α) : with_bot α) = bit0 x := rfl +lemma coe_bit1 [has_one α] {a : α} : ((bit1 a : α) : with_bot α) = bit1 a := rfl + +@[simp] lemma bot_add (a : with_bot α) : ⊥ + a = ⊥ := rfl +@[simp] lemma add_bot (a : with_bot α) : a + ⊥ = ⊥ := by cases a; refl + +@[simp] lemma add_eq_bot : a + b = ⊥ ↔ a = ⊥ ∨ b = ⊥ := with_top.add_eq_top +lemma add_ne_bot : a + b ≠ ⊥ ↔ a ≠ ⊥ ∧ b ≠ ⊥ := with_top.add_ne_top + +lemma bot_lt_add [partial_order α] {a b : with_bot α} : ⊥ < a + b ↔ ⊥ < a ∧ ⊥ < b := +@with_top.add_lt_top (order_dual α) _ _ _ _ + +lemma add_eq_coe : a + b = x ↔ ∃ (a' b' : α), ↑a' = a ∧ ↑b' = b ∧ a' + b' = x := with_top.add_eq_coe + +@[simp] lemma add_coe_eq_bot_iff : a + y = ⊥ ↔ a = ⊥ := with_top.add_coe_eq_top_iff +@[simp] lemma coe_add_eq_bot_iff : ↑x + b = ⊥ ↔ b = ⊥ := with_top.coe_add_eq_top_iff + +variables [preorder α] + +instance covariant_class_add_le [covariant_class α α (+) (≤)] : + covariant_class (with_bot α) (with_bot α) (+) (≤) := +@order_dual.covariant_class_add_le (with_top $ order_dual α) _ _ _ + +instance covariant_class_swap_add_le [covariant_class α α (swap (+)) (≤)] : + covariant_class (with_bot α) (with_bot α) (swap (+)) (≤) := +@order_dual.covariant_class_swap_add_le (with_top $ order_dual α) _ _ _ + +instance contravariant_class_add_lt [contravariant_class α α (+) (<)] : + contravariant_class (with_bot α) (with_bot α) (+) (<) := @order_dual.contravariant_class_add_lt (with_top $ order_dual α) _ _ _ -end with_bot +instance contravariant_class_swap_add_lt [contravariant_class α α (swap (+)) (<)] : + contravariant_class (with_bot α) (with_bot α) (swap (+)) (<) := +@order_dual.contravariant_class_swap_add_lt (with_top $ order_dual α) _ _ _ -end ordered_cancel_add_comm_monoid +protected lemma le_of_add_le_add_left [contravariant_class α α (+) (≤)] (ha : a ≠ ⊥) + (h : a + b ≤ a + c) : b ≤ c := +@with_top.le_of_add_le_add_left (order_dual α) _ _ _ _ _ _ ha h -namespace prod +protected lemma le_of_add_le_add_right [contravariant_class α α (swap (+)) (≤)] (ha : a ≠ ⊥) + (h : b + a ≤ c + a) : b ≤ c := +@with_top.le_of_add_le_add_right (order_dual α) _ _ _ _ _ _ ha h -variables {M N : Type*} +protected lemma add_lt_add_left [covariant_class α α (+) (<)] (ha : a ≠ ⊥) (h : b < c) : + a + b < a + c := +@with_top.add_lt_add_left (order_dual α) _ _ _ _ _ _ ha h -@[to_additive] -instance [ordered_cancel_comm_monoid M] [ordered_cancel_comm_monoid N] : - ordered_cancel_comm_monoid (M × N) := -{ mul_le_mul_left := λ a b h c, ⟨mul_le_mul_left' h.1 _, mul_le_mul_left' h.2 _⟩, - le_of_mul_le_mul_left := λ a b c h, ⟨le_of_mul_le_mul_left' h.1, le_of_mul_le_mul_left' h.2⟩, - .. prod.cancel_comm_monoid, .. prod.partial_order M N } +protected lemma add_lt_add_right [covariant_class α α (swap (+)) (<)] (ha : a ≠ ⊥) (h : b < c) : + b + a < c + a := +@with_top.add_lt_add_right (order_dual α) _ _ _ _ _ _ ha h -end prod +protected lemma add_le_add_iff_left [covariant_class α α (+) (≤)] [contravariant_class α α (+) (≤)] + (ha : a ≠ ⊥) : a + b ≤ a + c ↔ b ≤ c := +⟨with_bot.le_of_add_le_add_left ha, λ h, add_le_add_left h a⟩ + +protected lemma add_le_add_iff_right [covariant_class α α (swap (+)) (≤)] + [contravariant_class α α (swap (+)) (≤)] (ha : a ≠ ⊥) : b + a ≤ c + a ↔ b ≤ c := +⟨with_bot.le_of_add_le_add_right ha, λ h, add_le_add_right h a⟩ + +protected lemma add_lt_add_iff_left [covariant_class α α (+) (<)] [contravariant_class α α (+) (<)] + (ha : a ≠ ⊥) : a + b < a + c ↔ b < c := +⟨lt_of_add_lt_add_left, with_bot.add_lt_add_left ha⟩ + +protected lemma add_lt_add_iff_right [covariant_class α α (swap (+)) (<)] + [contravariant_class α α (swap (+)) (<)] (ha : a ≠ ⊥) : b + a < c + a ↔ b < c := +⟨lt_of_add_lt_add_right, with_bot.add_lt_add_right ha⟩ + +protected lemma add_lt_add_of_le_of_lt [covariant_class α α (+) (<)] + [covariant_class α α (swap (+)) (≤)] (hb : b ≠ ⊥) (hab : a ≤ b) (hcd : c < d) : a + c < b + d := +@with_top.add_lt_add_of_le_of_lt (order_dual α) _ _ _ _ _ _ _ _ hb hab hcd + +protected lemma add_lt_add_of_lt_of_le [covariant_class α α (+) (≤)] + [covariant_class α α (swap (+)) (<)] (hd : d ≠ ⊥) (hab : a < b) (hcd : c ≤ d) : a + c < b + d := +@with_top.add_lt_add_of_lt_of_le (order_dual α) _ _ _ _ _ _ _ _ hd hab hcd + +end has_add +end with_bot + +/-! ### `additive`/`multiplicative` -/ section type_tags @@ -1101,18 +1196,6 @@ instance [linear_ordered_comm_monoid α] : linear_ordered_add_comm_monoid (addit { ..additive.linear_order, ..additive.ordered_add_comm_monoid } -lemma with_zero.to_mul_bot_strict_mono [has_add α] [preorder α] : - strict_mono (@with_zero.to_mul_bot α _) := -λ x y, id - -@[simp] lemma with_zero.to_mul_bot_le [has_add α] [preorder α] - (a b : with_zero (multiplicative α)) : - with_zero.to_mul_bot a ≤ with_zero.to_mul_bot b ↔ a ≤ b := iff.rfl - -@[simp] lemma with_zero.to_mul_bot_lt [has_add α] [preorder α] - (a b : with_zero (multiplicative α)) : - with_zero.to_mul_bot a < with_zero.to_mul_bot b ↔ a < b := iff.rfl - namespace additive variables [preorder α] @@ -1143,6 +1226,33 @@ end multiplicative end type_tags +namespace with_zero + +local attribute [semireducible] with_zero +variables [has_add α] + +/-- Making an additive monoid multiplicative then adding a zero is the same as adding a bottom +element then making it multiplicative. -/ +def to_mul_bot : with_zero (multiplicative α) ≃* multiplicative (with_bot α) := +by exact mul_equiv.refl _ + +@[simp] lemma to_mul_bot_zero : + to_mul_bot (0 : with_zero (multiplicative α)) = multiplicative.of_add ⊥ := rfl +@[simp] lemma to_mul_bot_coe (x : multiplicative α) : + to_mul_bot ↑x = multiplicative.of_add (x.to_add : with_bot α) := rfl +@[simp] lemma to_mul_bot_symm_bot : + to_mul_bot.symm (multiplicative.of_add (⊥ : with_bot α)) = 0 := rfl +@[simp] lemma to_mul_bot_coe_of_add (x : α) : + to_mul_bot.symm (multiplicative.of_add (x : with_bot α)) = multiplicative.of_add x := rfl + +variables [preorder α] (a b : with_zero (multiplicative α)) + +lemma to_mul_bot_strict_mono : strict_mono (@to_mul_bot α _) := λ x y, id +@[simp] lemma to_mul_bot_le : to_mul_bot a ≤ to_mul_bot b ↔ a ≤ b := iff.rfl +@[simp] lemma to_mul_bot_lt : to_mul_bot a < to_mul_bot b ↔ a < b := iff.rfl + +end with_zero + /-- The order embedding sending `b` to `a * b`, for some fixed `a`. See also `order_iso.mul_left` when working in an ordered group. -/ @[to_additive "The order embedding sending `b` to `a + b`, for some fixed `a`. diff --git a/src/topology/instances/ereal.lean b/src/topology/instances/ereal.lean index 04bd2a72748fb..3148a9199d1ab 100644 --- a/src/topology/instances/ereal.lean +++ b/src/topology/instances/ereal.lean @@ -297,10 +297,8 @@ begin refine ⟨λ z, z < ((r - (a + 1): ℝ) : ereal), Iio_mem_nhds (bot_lt_coe _), λ z, z < ((a + 1 : ℝ) : ereal), Iio_mem_nhds (by simp [-coe_add, zero_lt_one]), λ x hx y hy, _⟩, - dsimp, convert add_lt_add hx hy, - dsimp, - ring, + rw sub_add_cancel, end lemma continuous_at_add_coe_bot (a : ℝ) : From 8decd4b1f9a9859123632ee017f419a0d1ae3a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Sat, 16 Apr 2022 17:33:12 +0000 Subject: [PATCH 051/373] chore(logic/encodable/basic): Rename `encodable` instances (#13396) The instances were called `encodable.foo` instead of `foo.encodable` as the naming convention preconizes. --- src/algebra/algebraic_card.lean | 2 +- .../box_integral/partition/measure.lean | 2 +- src/computability/encoding.lean | 2 +- src/data/W/basic.lean | 8 +--- src/data/rat/denumerable.lean | 2 +- src/data/set/countable.lean | 2 +- src/data/tprod.lean | 2 +- src/logic/encodable/basic.lean | 30 +++++++-------- src/logic/equiv/list.lean | 38 +++++++++++-------- .../constructions/borel_space.lean | 2 +- src/measure_theory/constructions/pi.lean | 10 ++--- .../function/strongly_measurable.lean | 4 +- src/measure_theory/measurable_space.lean | 2 +- src/measure_theory/measurable_space_def.lean | 2 +- src/measure_theory/measure/hausdorff.lean | 2 +- src/measure_theory/measure/measure_space.lean | 2 +- src/model_theory/basic.lean | 2 +- src/model_theory/encoding.lean | 4 +- src/set_theory/cardinal_ordinal.lean | 4 +- src/topology/bases.lean | 4 +- src/topology/metric_space/basic.lean | 2 +- 21 files changed, 65 insertions(+), 63 deletions(-) diff --git a/src/algebra/algebraic_card.lean b/src/algebra/algebraic_card.lean index 047fd6a866f88..cf43779263e5d 100644 --- a/src/algebra/algebraic_card.lean +++ b/src/algebra/algebraic_card.lean @@ -42,7 +42,7 @@ begin λ x, ulift.up (classical.some x.1.2), apply cardinal.mk_le_mk_mul_of_mk_preimage_le g (λ f, _), suffices : fintype (g ⁻¹' {f}), - { exact @mk_le_omega _ (@fintype.encodable _ this) }, + { exact @mk_le_omega _ (@fintype.to_encodable _ this) }, by_cases hf : f.1 = 0, { convert set.fintype_empty, apply set.eq_empty_iff_forall_not_mem.2 (λ x hx, _), diff --git a/src/analysis/box_integral/partition/measure.lean b/src/analysis/box_integral/partition/measure.lean index a216a433f8954..c060cee89227d 100644 --- a/src/analysis/box_integral/partition/measure.lean +++ b/src/analysis/box_integral/partition/measure.lean @@ -48,7 +48,7 @@ variables [fintype ι] (I : box ι) lemma measurable_set_coe : measurable_set (I : set (ι → ℝ)) := begin rw [coe_eq_pi], - haveI := fintype.encodable ι, + haveI := fintype.to_encodable ι, exact measurable_set.univ_pi (λ i, measurable_set_Ioc) end diff --git a/src/computability/encoding.lean b/src/computability/encoding.lean index 9fc7bb915e3f1..689fcc9360968 100644 --- a/src/computability/encoding.lean +++ b/src/computability/encoding.lean @@ -207,7 +207,7 @@ end lemma fin_encoding.card_le_omega {α : Type u} (e : fin_encoding α) : (# α) ≤ ω := begin - haveI : encodable e.Γ := fintype.encodable _, + haveI : encodable e.Γ := fintype.to_encodable _, exact e.to_encoding.card_le_omega, end diff --git a/src/data/W/basic.lean b/src/data/W/basic.lean index c40fc1cf3436b..c359b858fd788 100644 --- a/src/data/W/basic.lean +++ b/src/data/W/basic.lean @@ -116,8 +116,6 @@ lemma depth_lt_depth_mk (a : α) (f : β a → W_type β) (i : β a) : depth (f i) < depth ⟨a, f⟩ := nat.lt_succ_of_le (finset.le_sup (finset.mem_univ i)) -end W_type - /- Show that W types are encodable when `α` is an encodable fintype and for every `a : α`, `β a` is encodable. @@ -127,13 +125,11 @@ induction on `n` that these are all encodable. These auxiliary constructions are and of themselves, so we mark them as `private`. -/ -namespace encodable - @[reducible] private def W_type' {α : Type*} (β : α → Type*) [Π a : α, fintype (β a)] [Π a : α, encodable (β a)] (n : ℕ) := { t : W_type β // t.depth ≤ n} -variables {α : Type*} {β : α → Type*} [Π a : α, fintype (β a)] [Π a : α, encodable (β a)] +variables [Π a : α, encodable (β a)] private def encodable_zero : encodable (W_type' β 0) := let f : W_type' β 0 → empty := λ ⟨x, h⟩, false.elim $ not_lt_of_ge h (W_type.depth_pos _), @@ -176,4 +172,4 @@ begin exact encodable.of_left_inverse f finv this end -end encodable +end W_type diff --git a/src/data/rat/denumerable.lean b/src/data/rat/denumerable.lean index 40f68559ecfa2..c0caa16a68cd6 100644 --- a/src/data/rat/denumerable.lean +++ b/src/data/rat/denumerable.lean @@ -28,7 +28,7 @@ instance : denumerable ℚ := begin let T := { x : ℤ × ℕ // 0 < x.2 ∧ x.1.nat_abs.coprime x.2 }, letI : infinite T := infinite.of_injective _ denumerable_aux.injective, - letI : encodable T := encodable.subtype, + letI : encodable T := subtype.encodable, letI : denumerable T := of_encodable_of_infinite T, exact denumerable.of_equiv T denumerable_aux end diff --git a/src/data/set/countable.lean b/src/data/set/countable.lean index 88a77e31ca1a8..593b5da0df82f 100644 --- a/src/data/set/countable.lean +++ b/src/data/set/countable.lean @@ -185,7 +185,7 @@ lemma countable.insert {s : set α} (a : α) (h : countable s) : countable (inse countable_insert.2 h lemma finite.countable {s : set α} : finite s → countable s -| ⟨h⟩ := trunc.nonempty (by exactI trunc_encodable_of_fintype s) +| ⟨h⟩ := trunc.nonempty (by exactI fintype.trunc_encodable s) lemma subsingleton.countable {s : set α} (hs : s.subsingleton) : countable s := hs.finite.countable diff --git a/src/data/tprod.lean b/src/data/tprod.lean index e5aff2b8f0c50..a653cb6bcb69c 100644 --- a/src/data/tprod.lean +++ b/src/data/tprod.lean @@ -23,7 +23,7 @@ construction/theorem that is easier to define/prove on binary products than on f * Then we can use the equivalence `list.tprod.pi_equiv_tprod` below (or enhanced versions of it, like a `measurable_equiv` for product measures) to get the construction on `Π i : ι, α i`, at least when assuming `[fintype ι] [encodable ι]` (using `encodable.sorted_univ`). - Using `local attribute [instance] fintype.encodable` we can get rid of the argument + Using `local attribute [instance] fintype.to_encodable` we can get rid of the argument `[encodable ι]`. ## Main definitions diff --git a/src/logic/encodable/basic.lean b/src/logic/encodable/basic.lean index c39912d3f5b58..993780e8eb558 100644 --- a/src/logic/encodable/basic.lean +++ b/src/logic/encodable/basic.lean @@ -84,16 +84,16 @@ of_left_inverse e e.symm e.left_inv @[simp] theorem decode_of_equiv {α β} [encodable α] (e : β ≃ α) (n : ℕ) : @decode _ (of_equiv _ e) n = (decode α n).map e.symm := rfl -instance nat : encodable ℕ := +instance _root_.nat.encodable : encodable ℕ := ⟨id, some, λ a, rfl⟩ @[simp] theorem encode_nat (n : ℕ) : encode n = n := rfl @[simp] theorem decode_nat (n : ℕ) : decode ℕ n = some n := rfl -@[priority 100] instance is_empty [is_empty α] : encodable α := +@[priority 100] instance _root_.is_empty.to_encodable [is_empty α] : encodable α := ⟨is_empty_elim, λ n, none, is_empty_elim⟩ -instance unit : encodable punit := +instance _root_.punit.encodable : encodable punit := ⟨λ_, 0, λ n, nat.cases_on n (some punit.star) (λ _, none), λ _, by simp⟩ @[simp] theorem encode_star : encode punit.star = 0 := rfl @@ -102,7 +102,7 @@ instance unit : encodable punit := @[simp] theorem decode_unit_succ (n) : decode punit (succ n) = none := rfl /-- If `α` is encodable, then so is `option α`. -/ -instance option {α : Type*} [h : encodable α] : encodable (option α) := +instance _root_.option.encodable {α : Type*} [h : encodable α] : encodable (option α) := ⟨λ o, option.cases_on o nat.zero (λ a, succ (encode a)), λ n, nat.cases_on n (some none) (λ m, (decode α m).map some), λ o, by cases o; dsimp; simp [encodek, nat.succ_ne_zero]⟩ @@ -193,7 +193,7 @@ match bodd_div2 n with end /-- If `α` and `β` are encodable, then so is their sum. -/ -instance sum : encodable (α ⊕ β) := +instance _root_.sum.encodable : encodable (α ⊕ β) := ⟨encode_sum, decode_sum, λ s, by cases s; simp [encode_sum, decode_sum, encodek]; refl⟩ @@ -206,7 +206,7 @@ instance sum : encodable (α ⊕ β) := end sum -instance bool : encodable bool := +instance _root_.bool.encodable : encodable bool := of_equiv (unit ⊕ unit) equiv.bool_equiv_punit_sum_punit @[simp] theorem encode_tt : encode tt = 1 := rfl @@ -226,7 +226,7 @@ begin simp [decode_sum]; cases bodd n; simp [decode_sum]; rw e; refl end -noncomputable instance «Prop» : encodable Prop := +noncomputable instance _root_.Prop.encodable : encodable Prop := of_equiv bool equiv.Prop_equiv_bool section sigma @@ -241,7 +241,7 @@ def decode_sigma (n : ℕ) : option (sigma γ) := let (n₁, n₂) := unpair n in (decode α n₁).bind $ λ a, (decode (γ a) n₂).map $ sigma.mk a -instance sigma : encodable (sigma γ) := +instance _root_.sigma.encodable : encodable (sigma γ) := ⟨encode_sigma, decode_sigma, λ ⟨a, b⟩, by simp [encode_sigma, decode_sigma, unpair_mkpair, encodek]⟩ @@ -258,7 +258,7 @@ section prod variables [encodable α] [encodable β] /-- If `α` and `β` are encodable, then so is their product. -/ -instance prod : encodable (α × β) := +instance _root_.prod.encodable : encodable (α × β) := of_equiv _ (equiv.sigma_equiv_prod α β).symm @[simp] theorem decode_prod_val (n : ℕ) : decode (α × β) n = @@ -289,7 +289,7 @@ def decode_subtype (v : ℕ) : option {a : α // P a} := if h : P a then some ⟨a, h⟩ else none /-- A decidable subtype of an encodable type is encodable. -/ -instance subtype : encodable {a : α // P a} := +instance _root_.subtype.encodable : encodable {a : α // P a} := ⟨encode_subtype, decode_subtype, λ ⟨v, h⟩, by simp [encode_subtype, decode_subtype, encodek, h]⟩ @@ -298,21 +298,21 @@ by cases a; refl end subtype -instance fin (n) : encodable (fin n) := +instance _root_.fin.encodable (n) : encodable (fin n) := of_equiv _ (equiv.fin_equiv_subtype _) -instance int : encodable ℤ := +instance _root_.int.encodable : encodable ℤ := of_equiv _ equiv.int_equiv_nat -instance pnat : encodable ℕ+ := +instance _root_.pnat.encodable : encodable ℕ+ := of_equiv _ equiv.pnat_equiv_nat /-- The lift of an encodable type is encodable. -/ -instance ulift [encodable α] : encodable (ulift α) := +instance _root_.ulift.encodable [encodable α] : encodable (ulift α) := of_equiv _ equiv.ulift /-- The lift of an encodable type is encodable. -/ -instance plift [encodable α] : encodable (plift α) := +instance _root_.plift.encodable [encodable α] : encodable (plift α) := of_equiv _ equiv.plift /-- If `β` is encodable and there is an injection `f : α → β`, then `α` is encodable as well. -/ diff --git a/src/logic/equiv/list.lean b/src/logic/equiv/list.lean index 52d92d334d536..523c5832cb68d 100644 --- a/src/logic/equiv/list.lean +++ b/src/logic/equiv/list.lean @@ -37,7 +37,7 @@ def decode_list : ℕ → option (list α) /-- If `α` is encodable, then so is `list α`. This uses the `mkpair` and `unpair` functions from `data.nat.pairing`. -/ -instance list : encodable (list α) := +instance _root_.list.encodable : encodable (list α) := ⟨encode_list, decode_list, λ l, by induction l with a l IH; simp [encode_list, decode_list, unpair_mkpair, encodek, *]⟩ @@ -84,7 +84,7 @@ def decode_multiset (n : ℕ) : option (multiset α) := coe <$> decode (list α) n /-- If `α` is encodable, then so is `multiset α`. -/ -instance multiset : encodable (multiset α) := +instance _root_.multiset.encodable : encodable (multiset α) := ⟨encode_multiset, decode_multiset, λ s, by simp [encode_multiset, decode_multiset, encodek]⟩ @@ -94,7 +94,9 @@ end finset def encodable_of_list [decidable_eq α] (l : list α) (H : ∀ x, x ∈ l) : encodable α := ⟨λ a, index_of a l, l.nth, λ a, index_of_nth (H _)⟩ -def trunc_encodable_of_fintype (α : Type*) [decidable_eq α] [fintype α] : trunc (encodable α) := +/-- A finite type is encodable. Because the encoding is not unique, we wrap it in `trunc` to +preserve computability. -/ +def _root_.fintype.trunc_encodable (α : Type*) [decidable_eq α] [fintype α] : trunc (encodable α) := @@quot.rec_on_subsingleton _ (λ s : multiset α, (∀ x:α, x ∈ s) → trunc (encodable α)) _ finset.univ.1 @@ -102,14 +104,13 @@ def trunc_encodable_of_fintype (α : Type*) [decidable_eq α] [fintype α] : tru finset.mem_univ /-- A noncomputable way to arbitrarily choose an ordering on a finite type. - It is not made into a global instance, since it involves an arbitrary choice. - This can be locally made into an instance with `local attribute [instance] fintype.encodable`. -/ -noncomputable def _root_.fintype.encodable (α : Type*) [fintype α] : encodable α := -by { classical, exact (encodable.trunc_encodable_of_fintype α).out } +It is not made into a global instance, since it involves an arbitrary choice. +This can be locally made into an instance with `local attribute [instance] fintype.to_encodable`. -/ +noncomputable def _root_.fintype.to_encodable (α : Type*) [fintype α] : encodable α := +by { classical, exact (fintype.trunc_encodable α).out } /-- If `α` is encodable, then so is `vector α n`. -/ -instance vector [encodable α] {n} : encodable (vector α n) := -encodable.subtype +instance _root_.vector.encodable [encodable α] {n} : encodable (vector α n) := subtype.encodable /-- If `α` is encodable, then so is `fin n → α`. -/ instance fin_arrow [encodable α] {n} : encodable (fin n → α) := @@ -119,26 +120,31 @@ instance fin_pi (n) (π : fin n → Type*) [∀ i, encodable (π i)] : encodable of_equiv _ (equiv.pi_equiv_subtype_sigma (fin n) π) /-- If `α` is encodable, then so is `array n α`. -/ -instance array [encodable α] {n} : encodable (array n α) := +instance _root_.array.encodable [encodable α] {n} : encodable (array n α) := of_equiv _ (equiv.array_equiv_fin _ _) /-- If `α` is encodable, then so is `finset α`. -/ -instance finset [encodable α] : encodable (finset α) := +instance _root_.finset.encodable [encodable α] : encodable (finset α) := by haveI := decidable_eq_of_encodable α; exact of_equiv {s : multiset α // s.nodup} ⟨λ ⟨a, b⟩, ⟨a, b⟩, λ ⟨a, b⟩, ⟨a, b⟩, λ ⟨a, b⟩, rfl, λ ⟨a, b⟩, rfl⟩ +-- TODO: Unify with `fintype_pi` and find a better name +/-- When `α` is finite and `β` is encodable, `α → β` is encodable too. Because the encoding is not +unique, we wrap it in `trunc` to preserve computability. -/ def fintype_arrow (α : Type*) (β : Type*) [decidable_eq α] [fintype α] [encodable β] : trunc (encodable (α → β)) := (fintype.trunc_equiv_fin α).map $ λ f, encodable.of_equiv (fin (fintype.card α) → β) $ equiv.arrow_congr f (equiv.refl _) +/-- When `α` is finite and all `π a` are encodable, `Π a, π a` is encodable too. Because the +encoding is not unique, we wrap it in `trunc` to preserve computability. -/ def fintype_pi (α : Type*) (π : α → Type*) [decidable_eq α] [fintype α] [∀ a, encodable (π a)] : trunc (encodable (Π a, π a)) := -(encodable.trunc_encodable_of_fintype α).bind $ λ a, - (@fintype_arrow α (Σa, π a) _ _ (@encodable.sigma _ _ a _)).bind $ λ f, - trunc.mk $ @encodable.of_equiv _ _ (@encodable.subtype _ _ f _) (equiv.pi_equiv_subtype_sigma α π) +(fintype.trunc_encodable α).bind $ λ a, + (@fintype_arrow α (Σa, π a) _ _ (@sigma.encodable _ _ a _)).bind $ λ f, + trunc.mk $ @encodable.of_equiv _ _ (@subtype.encodable _ _ f _) (equiv.pi_equiv_subtype_sigma α π) /-- The elements of a `fintype` as a sorted list. -/ def sorted_univ (α) [fintype α] [encodable α] : list α := @@ -248,7 +254,7 @@ lemma raise_sorted : ∀ l n, list.sorted (≤) (raise l n) | (m :: l) n := (list.chain_iff_pairwise (@le_trans _ _)).1 (raise_chain _ _) /-- If `α` is denumerable, then so is `multiset α`. Warning: this is *not* the same encoding as used -in `encodable.multiset`. -/ +in `multiset.encodable`. -/ instance multiset : denumerable (multiset α) := mk' ⟨ λ s : multiset α, encode $ lower ((s.map encode).sort (≤)) 0, λ n, multiset.map (of_nat α) (raise (of_nat (list ℕ) n) 0), @@ -301,7 +307,7 @@ def raise'_finset (l : list ℕ) (n : ℕ) : finset ℕ := ⟨raise' l n, (raise'_sorted _ _).imp (@ne_of_lt _ _)⟩ /-- If `α` is denumerable, then so is `finset α`. Warning: this is *not* the same encoding as used -in `encodable.finset`. -/ +in `finset.encodable`. -/ instance finset : denumerable (finset α) := mk' ⟨ λ s : finset α, encode $ lower' ((s.map (eqv α).to_embedding).sort (≤)) 0, λ n, finset.map (eqv α).symm.to_embedding (raise'_finset (of_nat (list ℕ) n) 0), diff --git a/src/measure_theory/constructions/borel_space.lean b/src/measure_theory/constructions/borel_space.lean index c26b146289473..406e6b7dc175a 100644 --- a/src/measure_theory/constructions/borel_space.lean +++ b/src/measure_theory/constructions/borel_space.lean @@ -363,7 +363,7 @@ instance pi.opens_measurable_space_fintype {ι : Type*} {π : ι → Type*} [fin [Π i, measurable_space (π i)] [∀ i, second_countable_topology (π i)] [∀ i, opens_measurable_space (π i)] : opens_measurable_space (Π i, π i) := -by { letI := fintype.encodable ι, apply_instance } +by { letI := fintype.to_encodable ι, apply_instance } instance prod.opens_measurable_space [second_countable_topology α] [second_countable_topology β] : opens_measurable_space (α × β) := diff --git a/src/measure_theory/constructions/pi.lean b/src/measure_theory/constructions/pi.lean index b6ee3eba3155a..1187a6f8411a1 100644 --- a/src/measure_theory/constructions/pi.lean +++ b/src/measure_theory/constructions/pi.lean @@ -83,7 +83,7 @@ lemma is_countably_spanning.pi {C : Π i, set (set (α i))} is_countably_spanning (pi univ '' pi univ C) := begin choose s h1s h2s using hC, - haveI := fintype.encodable ι, + haveI := fintype.to_encodable ι, let e : ℕ → (ι → ℕ) := λ n, (decode (ι → ℕ) n).iget, refine ⟨λ n, pi univ (λ i, s i (e n i)), λ n, mem_image_of_mem _ (λ i _, h1s i _), _⟩, simp_rw [(surjective_decode_iget (ι → ℕ)).Union_comp (λ x, pi univ (λ i, s i (x i))), @@ -96,7 +96,7 @@ lemma generate_from_pi_eq {C : Π i, set (set (α i))} (hC : ∀ i, is_countably_spanning (C i)) : @measurable_space.pi _ _ (λ i, generate_from (C i)) = generate_from (pi univ '' pi univ C) := begin - haveI := fintype.encodable ι, + haveI := fintype.to_encodable ι, apply le_antisymm, { refine supr_le _, intro i, rw [comap_generate_from], apply generate_from_le, rintro _ ⟨s, hs, rfl⟩, dsimp, @@ -277,7 +277,7 @@ begin refine le_antisymm _ _, { rw [measure.pi, to_measure_apply _ _ (measurable_set.pi_fintype (λ i _, hs i))], apply outer_measure.pi_pi_le }, - { haveI : encodable ι := fintype.encodable ι, + { haveI : encodable ι := fintype.to_encodable ι, rw [← pi'_pi μ s], simp_rw [← pi'_pi μ s, measure.pi, to_measure_apply _ _ (measurable_set.pi_fintype (λ i _, hs i)), ← to_outer_measure_apply], @@ -298,7 +298,7 @@ def finite_spanning_sets_in.pi {C : Π i, set (set (α i))} (measure.pi μ).finite_spanning_sets_in (pi univ '' pi univ C) := begin haveI := λ i, (hμ i).sigma_finite, - haveI := fintype.encodable ι, + haveI := fintype.to_encodable ι, refine ⟨λ n, pi univ (λ i, (hμ i).set ((decode (ι → ℕ) n).iget i)), λ n, _, λ n, _, _⟩; -- TODO (kmill) If this let comes before the refine, while the noncomputability checker -- correctly sees this definition is computable, the Lean VM fails to see the binding is @@ -357,7 +357,7 @@ eq.symm $ pi_eq $ λ s hs, pi'_pi μ s @[simp] lemma pi_pi (s : Π i, set (α i)) : measure.pi μ (pi univ s) = ∏ i, μ i (s i) := begin - haveI : encodable ι := fintype.encodable ι, + haveI : encodable ι := fintype.to_encodable ι, rw [← pi'_eq_pi, pi'_pi] end diff --git a/src/measure_theory/function/strongly_measurable.lean b/src/measure_theory/function/strongly_measurable.lean index 9e150a1a356df..e3a3b6767d8e1 100644 --- a/src/measure_theory/function/strongly_measurable.lean +++ b/src/measure_theory/function/strongly_measurable.lean @@ -1693,7 +1693,7 @@ begin { rw tendsto_pi_nhds, exact λ p, ht_sf p.fst p.snd, }, refine measurable_of_tendsto_metric (λ n, _) h_tendsto, - haveI : encodable (t_sf n).range, from fintype.encodable ↥(t_sf n).range, + haveI : encodable (t_sf n).range, from fintype.to_encodable ↥(t_sf n).range, have h_meas : measurable (λ (p : (t_sf n).range × α), u ↑p.fst p.snd), { have : (λ (p : ↥((t_sf n).range) × α), u ↑(p.fst) p.snd) = (λ (p : α × ((t_sf n).range)), u ↑(p.snd) p.fst) ∘ prod.swap := rfl, @@ -1725,7 +1725,7 @@ begin { rw tendsto_pi_nhds, exact λ p, ht_sf p.fst p.snd, }, refine strongly_measurable_of_tendsto _ (λ n, _) h_tendsto, - haveI : encodable (t_sf n).range, from fintype.encodable ↥(t_sf n).range, + haveI : encodable (t_sf n).range, from fintype.to_encodable ↥(t_sf n).range, have h_str_meas : strongly_measurable (λ (p : (t_sf n).range × α), u ↑p.fst p.snd), { refine strongly_measurable_iff_measurable_separable.2 ⟨_, _⟩, { have : (λ (p : ↥((t_sf n).range) × α), u ↑(p.fst) p.snd) diff --git a/src/measure_theory/measurable_space.lean b/src/measure_theory/measurable_space.lean index 8e230a3f2a916..db26adea3cbf7 100644 --- a/src/measure_theory/measurable_space.lean +++ b/src/measure_theory/measurable_space.lean @@ -735,7 +735,7 @@ end section fintype -local attribute [instance] fintype.encodable +local attribute [instance] fintype.to_encodable lemma measurable_set.pi_fintype [fintype δ] {s : set δ} {t : Π i, set (π i)} (ht : ∀ i ∈ s, measurable_set (t i)) : measurable_set (pi s t) := diff --git a/src/measure_theory/measurable_space_def.lean b/src/measure_theory/measurable_space_def.lean index a33fac10826da..f554b603bf85f 100644 --- a/src/measure_theory/measurable_space_def.lean +++ b/src/measure_theory/measurable_space_def.lean @@ -140,7 +140,7 @@ by { rw compl_Inter, exact measurable_set.Union (λ b, (h b).compl) } section fintype -local attribute [instance] fintype.encodable +local attribute [instance] fintype.to_encodable lemma measurable_set.Union_fintype [fintype β] {f : β → set α} (h : ∀ b, measurable_set (f b)) : measurable_set (⋃ b, f b) := diff --git a/src/measure_theory/measure/hausdorff.lean b/src/measure_theory/measure/hausdorff.lean index f557606b4dbfe..10076b104abbb 100644 --- a/src/measure_theory/measure/hausdorff.lean +++ b/src/measure_theory/measure/hausdorff.lean @@ -542,7 +542,7 @@ lemma mk_metric_le_liminf_sum {β : Type*} {ι : β → Type*} [hι : ∀ n, fin (m : ℝ≥0∞ → ℝ≥0∞) : mk_metric m s ≤ liminf l (λ n, ∑ i, m (diam (t n i))) := begin - haveI : ∀ n, encodable (ι n), from λ n, fintype.encodable _, + haveI : ∀ n, encodable (ι n), from λ n, fintype.to_encodable _, simpa only [tsum_fintype] using mk_metric_le_liminf_tsum s r hr t ht hst m, end diff --git a/src/measure_theory/measure/measure_space.lean b/src/measure_theory/measure/measure_space.lean index fee1c87ab7ca0..b29391b96c74e 100644 --- a/src/measure_theory/measure/measure_space.lean +++ b/src/measure_theory/measure/measure_space.lean @@ -2606,7 +2606,7 @@ end instance sum.sigma_finite {ι} [fintype ι] (μ : ι → measure α) [∀ i, sigma_finite (μ i)] : sigma_finite (sum μ) := begin - haveI : encodable ι := fintype.encodable ι, + haveI : encodable ι := fintype.to_encodable ι, have : ∀ n, measurable_set (⋂ (i : ι), spanning_sets (μ i) n) := λ n, measurable_set.Inter (λ i, measurable_spanning_sets (μ i) n), refine ⟨⟨⟨λ n, ⋂ i, spanning_sets (μ i) n, λ _, trivial, λ n, _, _⟩⟩⟩, diff --git a/src/model_theory/basic.lean b/src/model_theory/basic.lean index 67a23e5daa485..9486e6f94133f 100644 --- a/src/model_theory/basic.lean +++ b/src/model_theory/basic.lean @@ -173,7 +173,7 @@ instance countable_empty : language.empty.countable := ⟨begin rw [card_eq_card_functions_add_card_relations, add_le_omega, lift_le_omega, lift_le_omega, ← cardinal.encodable_iff, ← cardinal.encodable_iff], - exact ⟨⟨encodable.sigma⟩, ⟨encodable.sigma⟩⟩, + exact ⟨⟨sigma.encodable⟩, ⟨sigma.encodable⟩⟩, end⟩ @[priority 100] instance countable.countable_functions [L.countable] : diff --git a/src/model_theory/encoding.lean b/src/model_theory/encoding.lean index 9a731f1687f25..61d38de7bd39f 100644 --- a/src/model_theory/encoding.lean +++ b/src/model_theory/encoding.lean @@ -109,8 +109,8 @@ begin have h := (mk_le_of_injective list_encode_injective), refine h.trans _, casesI fintype_or_infinite (α ⊕ Σ i, L.functions i) with ft inf, - { haveI := fintype.encodable (α ⊕ Σ i, L.functions i), - exact le_add_left (encodable_iff.1 ⟨encodable.list⟩) }, + { haveI := fintype.to_encodable (α ⊕ Σ i, L.functions i), + exact le_add_left mk_le_omega }, { rw mk_list_eq_mk, exact le_self_add } end diff --git a/src/set_theory/cardinal_ordinal.lean b/src/set_theory/cardinal_ordinal.lean index f308dc381a89d..fa9e2fcbe791c 100644 --- a/src/set_theory/cardinal_ordinal.lean +++ b/src/set_theory/cardinal_ordinal.lean @@ -668,7 +668,7 @@ mk_le_omega.antisymm (omega_le_mk _) theorem mk_list_eq_max_mk_omega (α : Type u) [nonempty α] : #(list α) = max (#α) ω := begin casesI fintype_or_infinite α, - { haveI : encodable α := fintype.encodable α, + { haveI : encodable α := fintype.to_encodable α, rw [mk_list_eq_omega, eq_comm, max_eq_right], exact mk_le_omega }, { rw [mk_list_eq_mk, eq_comm, max_eq_left], @@ -678,7 +678,7 @@ end theorem mk_list_le_max (α : Type u) : #(list α) ≤ max ω (#α) := begin casesI fintype_or_infinite α, - { haveI := fintype.encodable α, + { haveI := fintype.to_encodable α, exact mk_le_omega.trans (le_max_left _ _) }, { rw mk_list_eq_mk, apply le_max_right } diff --git a/src/topology/bases.lean b/src/topology/bases.lean index 03ba9901ad577..7c83edd7206ab 100644 --- a/src/topology/bases.lean +++ b/src/topology/bases.lean @@ -291,7 +291,7 @@ def dense_seq [separable_space α] [nonempty α] : ℕ → α := classical.some variable {α} @[priority 100] -instance encodable.separable_space [encodable α] : separable_space α := +instance encodable.to_separable_space [encodable α] : separable_space α := { exists_countable_dense := ⟨set.univ, set.countable_encodable set.univ, dense_univ⟩ } lemma separable_space_of_dense_range {ι : Type*} [encodable ι] (u : ι → α) (hu : dense_range u) : @@ -648,7 +648,7 @@ end instance second_countable_topology_fintype {ι : Type*} {π : ι → Type*} [fintype ι] [t : ∀a, topological_space (π a)] [∀a, second_countable_topology (π a)] : second_countable_topology (∀a, π a) := -by { letI := fintype.encodable ι, exact topological_space.second_countable_topology_encodable } +by { letI := fintype.to_encodable ι, exact topological_space.second_countable_topology_encodable } @[priority 100] -- see Note [lower instance priority] instance second_countable_topology.to_separable_space diff --git a/src/topology/metric_space/basic.lean b/src/topology/metric_space/basic.lean index 2d0bc2d6c43ba..fd876bd513ba6 100644 --- a/src/topology/metric_space/basic.lean +++ b/src/topology/metric_space/basic.lean @@ -1577,7 +1577,7 @@ lemma _root_.topological_space.is_separable.separable_space {s : set α} (hs : i begin classical, rcases eq_empty_or_nonempty s with rfl|⟨⟨x₀, x₀s⟩⟩, - { haveI : encodable (∅ : set α) := fintype.encodable ↥∅, exact encodable.separable_space }, + { haveI : encodable (∅ : set α) := fintype.to_encodable ↥∅, exact encodable.to_separable_space }, rcases hs with ⟨c, hc, h'c⟩, haveI : encodable c := hc.to_encodable, obtain ⟨u, -, u_pos, u_lim⟩ : ∃ (u : ℕ → ℝ), strict_anti u ∧ (∀ (n : ℕ), 0 < u n) ∧ From 018e9b574a0034058d8f9878934a560d8a61ef7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Sat, 16 Apr 2022 17:33:13 +0000 Subject: [PATCH 052/373] chore(order/bounded_order): Match the `with_bot` and `with_top` API (#13419) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The API for `with_top` and the API for `with_bot` somehow evolved independently from each other, which created frustating disparity in lemmas and argument implicitness. This synchronizes everything (including the layout), generalize a few lemmas from `preorder`/`partial_order` to `has_le`/`has_lt`, and removes the duplicated `is_total (with_bot α) (≤)`/`is_total (with_top α) (≤)` instances. --- src/algebra/cubic_discriminant.lean | 2 +- .../box_integral/partition/basic.lean | 6 +- .../box_integral/partition/split.lean | 2 +- src/linear_algebra/lagrange.lean | 4 +- src/order/bounded_order.lean | 457 +++++++++--------- 5 files changed, 237 insertions(+), 234 deletions(-) diff --git a/src/algebra/cubic_discriminant.lean b/src/algebra/cubic_discriminant.lean index 7db712d6e5c2b..a235d3255df21 100644 --- a/src/algebra/cubic_discriminant.lean +++ b/src/algebra/cubic_discriminant.lean @@ -220,7 +220,7 @@ begin apply (to_finset_card_le P.to_poly.roots).trans, by_cases hP : P.to_poly = 0, { exact (card_roots' P.to_poly).trans (by { rw [hP, nat_degree_zero], exact zero_le 3 }) }, - { simpa only [← @with_bot.coe_le_coe _ _ _ 3] using (card_roots hP).trans degree_cubic_le } + { exact with_bot.coe_le_coe.1 ((card_roots hP).trans degree_cubic_le) } end end extension diff --git a/src/analysis/box_integral/partition/basic.lean b/src/analysis/box_integral/partition/basic.lean index 3dd208d564ad1..8c879527a35d2 100644 --- a/src/analysis/box_integral/partition/basic.lean +++ b/src/analysis/box_integral/partition/basic.lean @@ -344,7 +344,7 @@ lemma of_with_bot_le {boxes : finset (with_bot (box ι))} (H : ∀ J ∈ boxes, J ≠ ⊥ → ∃ J' ∈ π, J ≤ ↑J') : of_with_bot boxes le_of_mem pairwise_disjoint ≤ π := have ∀ (J : box ι), ↑J ∈ boxes → ∃ J' ∈ π, J ≤ J', - from λ J hJ, by simpa only [with_bot.coe_le_coe] using H J hJ (with_bot.coe_ne_bot J), + from λ J hJ, by simpa only [with_bot.coe_le_coe] using H J hJ with_bot.coe_ne_bot, by simpa [of_with_bot, le_def] lemma le_of_with_bot {boxes : finset (with_bot (box ι))} @@ -355,7 +355,7 @@ lemma le_of_with_bot {boxes : finset (with_bot (box ι))} begin intros J hJ, rcases H J hJ with ⟨J', J'mem, hle⟩, - lift J' to box ι using ne_bot_of_le_ne_bot (with_bot.coe_ne_bot _) hle, + lift J' to box ι using ne_bot_of_le_ne_bot with_bot.coe_ne_bot hle, exact ⟨J', mem_of_with_bot.2 J'mem, with_bot.coe_le_coe.1 hle⟩ end @@ -368,7 +368,7 @@ lemma of_with_bot_mono {boxes₁ : finset (with_bot (box ι))} (H : ∀ J ∈ boxes₁, J ≠ ⊥ → ∃ J' ∈ boxes₂, J ≤ J') : of_with_bot boxes₁ le_of_mem₁ pairwise_disjoint₁ ≤ of_with_bot boxes₂ le_of_mem₂ pairwise_disjoint₂ := -le_of_with_bot _ $ λ J hJ, H J (mem_of_with_bot.1 hJ) (with_bot.coe_ne_bot _) +le_of_with_bot _ $ λ J hJ, H J (mem_of_with_bot.1 hJ) with_bot.coe_ne_bot lemma sum_of_with_bot {M : Type*} [add_comm_monoid M] (boxes : finset (with_bot (box ι))) diff --git a/src/analysis/box_integral/partition/split.lean b/src/analysis/box_integral/partition/split.lean index bddac898baa72..4ff176158bffc 100644 --- a/src/analysis/box_integral/partition/split.lean +++ b/src/analysis/box_integral/partition/split.lean @@ -126,7 +126,7 @@ lemma split_lower_ne_split_upper (I : box ι) (i : ι) (x : ℝ) : I.split_lower i x ≠ I.split_upper i x := begin cases le_or_lt x (I.lower i), - { rw [split_upper_eq_self.2 h, split_lower_eq_bot.2 h], exact with_bot.bot_ne_coe _ }, + { rw [split_upper_eq_self.2 h, split_lower_eq_bot.2 h], exact with_bot.bot_ne_coe }, { refine (disjoint_split_lower_split_upper I i x).ne _, rwa [ne.def, split_lower_eq_bot, not_le] } end diff --git a/src/linear_algebra/lagrange.lean b/src/linear_algebra/lagrange.lean index 43062c57dee50..fae4f3c345c35 100644 --- a/src/linear_algebra/lagrange.lean +++ b/src/linear_algebra/lagrange.lean @@ -201,11 +201,11 @@ begin { rw [degree_mul, degree_C (inv_ne_zero (sub_ne_zero.2 hxy.symm)), zero_add], refine lt_of_le_of_lt (degree_add_le _ _) (max_lt _ _), { rw [degree_mul, degree_X_sub_C], - convert (with_bot.add_lt_add_iff_left (with_bot.coe_ne_bot _)).2 + convert (with_bot.add_lt_add_iff_left with_bot.coe_ne_bot).2 (degree_interpolate_erase s f hx), simp [nat.one_add, nat.sub_one, nat.succ_pred_eq_of_pos (finset.card_pos.2 ⟨x, hx⟩)] }, { rw [degree_mul, ←neg_sub, degree_neg, degree_X_sub_C], - convert (with_bot.add_lt_add_iff_left (with_bot.coe_ne_bot _)).2 + convert (with_bot.add_lt_add_iff_left with_bot.coe_ne_bot).2 (degree_interpolate_erase s f hy), simp [nat.one_add, nat.sub_one, nat.succ_pred_eq_of_pos (finset.card_pos.2 ⟨y, hy⟩)] } }, { by_cases hzx : z = x, diff --git a/src/order/bounded_order.lean b/src/order/bounded_order.lean index b0da1d2e30e4a..532485a44af77 100644 --- a/src/order/bounded_order.lean +++ b/src/order/bounded_order.lean @@ -477,27 +477,28 @@ end lift def with_bot (α : Type*) := option α namespace with_bot +variables {a b : α} -meta instance {α} [has_to_format α] : has_to_format (with_bot α) := +meta instance [has_to_format α] : has_to_format (with_bot α) := { to_format := λ x, match x with | none := "⊥" | (some x) := to_fmt x end } -instance {α : Type u} [has_repr α] : has_repr (with_bot α) := +instance [has_repr α] : has_repr (with_bot α) := ⟨λ o, match o with | none := "⊥" | (some a) := "↑" ++ repr a end⟩ instance : has_coe_t α (with_bot α) := ⟨some⟩ -instance has_bot : has_bot (with_bot α) := ⟨none⟩ +instance : has_bot (with_bot α) := ⟨none⟩ instance : inhabited (with_bot α) := ⟨⊥⟩ lemma none_eq_bot : (none : with_bot α) = (⊥ : with_bot α) := rfl lemma some_eq_coe (a : α) : (some a : with_bot α) = (↑a : with_bot α) := rfl -@[simp] theorem bot_ne_coe (a : α) : ⊥ ≠ (a : with_bot α) . -@[simp] theorem coe_ne_bot (a : α) : (a : with_bot α) ≠ ⊥ . +@[simp] lemma bot_ne_coe : ⊥ ≠ (a : with_bot α) . +@[simp] lemma coe_ne_bot : (a : with_bot α) ≠ ⊥ . /-- Recursor for `with_bot` using the preferred forms `⊥` and `↑a`. -/ @[elab_as_eliminator] @@ -505,9 +506,7 @@ def rec_bot_coe {C : with_bot α → Sort*} (h₁ : C ⊥) (h₂ : Π (a : α), Π (n : with_bot α), C n := option.rec h₁ h₂ -@[norm_cast] -theorem coe_eq_coe {a b : α} : (a : with_bot α) = b ↔ a = b := -by rw [← option.some.inj_eq a b]; refl +@[norm_cast] lemma coe_eq_coe : (a : with_bot α) = b ↔ a = b := option.some_inj -- the `by exact` here forces the type of the equality to be `@eq (with_bot α)` @[simp] lemma map_bot (f : α → β) : @@ -515,59 +514,100 @@ by rw [← option.some.inj_eq a b]; refl lemma map_coe (f : α → β) (a : α) : (by exact option.map f (a : with_bot α)) = (f a : with_bot β) := rfl -lemma ne_bot_iff_exists {x : with_bot α} : x ≠ ⊥ ↔ ∃ (a : α), ↑a = x := -option.ne_none_iff_exists +lemma ne_bot_iff_exists {x : with_bot α} : x ≠ ⊥ ↔ ∃ (a : α), ↑a = x := option.ne_none_iff_exists /-- Deconstruct a `x : with_bot α` to the underlying value in `α`, given a proof that `x ≠ ⊥`. -/ def unbot : Π (x : with_bot α), x ≠ ⊥ → α | ⊥ h := absurd rfl h | (some x) h := x -@[simp] lemma coe_unbot {α : Type*} (x : with_bot α) (h : x ≠ ⊥) : - (x.unbot h : with_bot α) = x := +@[simp] lemma coe_unbot (x : with_bot α) (h : x ≠ ⊥) : (x.unbot h : with_bot α) = x := by { cases x, simpa using h, refl, } -@[simp] lemma unbot_coe (x : α) (h : (x : with_bot α) ≠ ⊥ := coe_ne_bot _) : +@[simp] lemma unbot_coe (x : α) (h : (x : with_bot α) ≠ ⊥ := coe_ne_bot) : (x : with_bot α).unbot h = x := rfl +instance : can_lift (with_bot α) α := +{ coe := coe, + cond := λ r, r ≠ ⊥, + prf := λ x h, ⟨x.unbot h, coe_unbot _ _⟩ } + +section has_le +variables [has_le α] + @[priority 10] -instance has_le [has_le α] : has_le (with_bot α) := -{ le := λ o₁ o₂ : option α, ∀ a ∈ o₁, ∃ b ∈ o₂, a ≤ b } +instance : has_le (with_bot α) := ⟨λ o₁ o₂ : option α, ∀ a ∈ o₁, ∃ b ∈ o₂, a ≤ b⟩ + +@[simp] lemma some_le_some : @has_le.le (with_bot α) _ (some a) (some b) ↔ a ≤ b := by simp [(≤)] +@[simp, norm_cast] lemma coe_le_coe : (a : with_bot α) ≤ b ↔ a ≤ b := some_le_some + +@[simp] lemma none_le {a : with_bot α} : @has_le.le (with_bot α) _ none a := +λ b h, option.no_confusion h + +instance : order_bot (with_bot α) := { bot_le := λ a, none_le, ..with_bot.has_bot } + +instance [order_top α] : order_top (with_bot α) := +{ top := some ⊤, + le_top := λ o a ha, by cases ha; exact ⟨_, rfl, le_top⟩ } + +instance [order_top α] : bounded_order (with_bot α) := +{ ..with_bot.order_top, ..with_bot.order_bot } + +lemma not_coe_le_bot (a : α) : ¬ (a : with_bot α) ≤ ⊥ := +λ h, let ⟨b, hb, _⟩ := h _ rfl in option.not_mem_none _ hb + +lemma coe_le : ∀ {o : option α}, b ∈ o → ((a : with_bot α) ≤ o ↔ a ≤ b) | _ rfl := coe_le_coe + +lemma coe_le_iff : ∀ {x : with_bot α}, ↑a ≤ x ↔ ∃ b : α, x = b ∧ a ≤ b +| (some a) := by simp [some_eq_coe, coe_eq_coe] +| none := iff_of_false (not_coe_le_bot _) $ by simp [none_eq_bot] + +lemma le_coe_iff : ∀ {x : with_bot α}, x ≤ b ↔ ∀ a, x = ↑a → a ≤ b +| (some b) := by simp [some_eq_coe, coe_eq_coe] +| none := by simp [none_eq_bot] + +protected lemma _root_.is_max.with_bot (h : is_max a) : is_max (a : with_bot α) +| none _ := bot_le +| (some b) hb := some_le_some.2 $ h $ some_le_some.1 hb + +end has_le + +section has_lt +variables [has_lt α] @[priority 10] -instance has_lt [has_lt α] : has_lt (with_bot α) := -{ lt := λ o₁ o₂ : option α, ∃ b ∈ o₂, ∀ a ∈ o₁, a < b } +instance : has_lt (with_bot α) := ⟨λ o₁ o₂ : option α, ∃ b ∈ o₂, ∀ a ∈ o₁, a < b⟩ -@[simp] theorem some_lt_some [has_lt α] {a b : α} : - @has_lt.lt (with_bot α) _ (some a) (some b) ↔ a < b := -by simp [(<)] +@[simp] lemma some_lt_some : @has_lt.lt (with_bot α) _ (some a) (some b) ↔ a < b := by simp [(<)] +@[simp, norm_cast] lemma coe_lt_coe : (a : with_bot α) < b ↔ a < b := some_lt_some -lemma none_lt_some [has_lt α] (a : α) : - @has_lt.lt (with_bot α) _ none (some a) := +@[simp] lemma none_lt_some (a : α) : @has_lt.lt (with_bot α) _ none (some a) := ⟨a, rfl, λ b hb, (option.not_mem_none _ hb).elim⟩ +lemma bot_lt_coe (a : α) : (⊥ : with_bot α) < a := none_lt_some a -lemma not_lt_none [has_lt α] (a : option α) : ¬ @has_lt.lt (with_bot α) _ a none := +@[simp] lemma not_lt_none (a : with_bot α) : ¬ @has_lt.lt (with_bot α) _ a none := λ ⟨_, h, _⟩, option.not_mem_none _ h -lemma bot_lt_coe [has_lt α] (a : α) : (⊥ : with_bot α) < a := none_lt_some a +lemma lt_iff_exists_coe : ∀ {a b : with_bot α}, a < b ↔ ∃ p : α, b = p ∧ a < p +| a (some b) := by simp [some_eq_coe, coe_eq_coe] +| a none := iff_of_false (not_lt_none _) $ by simp [none_eq_bot] -instance : can_lift (with_bot α) α := -{ coe := coe, - cond := λ r, r ≠ ⊥, - prf := λ x hx, ⟨option.get $ option.ne_none_iff_is_some.1 hx, option.some_get _⟩ } +lemma lt_coe_iff : ∀ {x : with_bot α}, x < b ↔ ∀ a, x = ↑a → a < b +| (some b) := by simp [some_eq_coe, coe_eq_coe, coe_lt_coe] +| none := by simp [none_eq_bot, bot_lt_coe] + +end has_lt instance [preorder α] : preorder (with_bot α) := { le := (≤), lt := (<), - lt_iff_le_not_le := by intros; cases a; cases b; - simp [lt_iff_le_not_le]; simp [(≤), (<)]; - split; refl, + lt_iff_le_not_le := by { intros, cases a; cases b; simp [lt_iff_le_not_le]; simp [(<), (≤)] }, le_refl := λ o a ha, ⟨a, ha, le_rfl⟩, le_trans := λ o₁ o₂ o₃ h₁ h₂ a ha, let ⟨b, hb, ab⟩ := h₁ a ha, ⟨c, hc, bc⟩ := h₂ b hb in ⟨c, hc, le_trans ab bc⟩ } -instance partial_order [partial_order α] : partial_order (with_bot α) := +instance [partial_order α] : partial_order (with_bot α) := { le_antisymm := λ o₁ o₂ h₁ h₂, begin cases o₁ with a, { cases o₂ with b, {refl}, @@ -578,26 +618,6 @@ instance partial_order [partial_order α] : partial_order (with_bot α) := end, .. with_bot.preorder } -instance order_bot [has_le α] : order_bot (with_bot α) := -{ bot_le := λ a a' h, option.no_confusion h, - ..with_bot.has_bot } - -@[simp, norm_cast] theorem coe_le_coe [has_le α] {a b : α} : - (a : with_bot α) ≤ b ↔ a ≤ b := -⟨λ h, by rcases h a rfl with ⟨_, ⟨⟩, h⟩; exact h, - λ h a' e, option.some_inj.1 e ▸ ⟨b, rfl, h⟩⟩ - -@[simp] theorem some_le_some [has_le α] {a b : α} : - @has_le.le (with_bot α) _ (some a) (some b) ↔ a ≤ b := coe_le_coe - -theorem coe_le [has_le α] {a b : α} : - ∀ {o : option α}, b ∈ o → ((a : with_bot α) ≤ o ↔ a ≤ b) -| _ rfl := coe_le_coe - -@[norm_cast] -lemma coe_lt_coe [has_lt α] {a b : α} : (a : with_bot α) < b ↔ a < b := some_lt_some -lemma not_coe_le_bot [preorder α] (a : α) : ¬ (a : with_bot α) ≤ ⊥ := (bot_lt_coe a).not_le - lemma le_coe_get_or_else [preorder α] : ∀ (a : with_bot α) (b : α), a ≤ a.get_or_else b | (some a) b := le_refl a | none b := λ _ h, option.no_confusion h @@ -608,30 +628,7 @@ lemma get_or_else_bot_le_iff [has_le α] [order_bot α] {a : with_bot α} {b : a.get_or_else ⊥ ≤ b ↔ a ≤ b := by cases a; simp [none_eq_bot, some_eq_coe] -instance decidable_le [has_le α] [@decidable_rel α (≤)] : @decidable_rel (with_bot α) (≤) -| none x := is_true $ λ a h, option.no_confusion h -| (some x) (some y) := - if h : x ≤ y - then is_true (some_le_some.2 h) - else is_false $ by simp * -| (some x) none := is_false $ λ h, by rcases h x rfl with ⟨y, ⟨_⟩, _⟩ - -instance decidable_lt [has_lt α] [@decidable_rel α (<)] : @decidable_rel (with_bot α) (<) -| none (some x) := is_true $ by existsi [x,rfl]; rintros _ ⟨⟩ -| (some x) (some y) := - if h : x < y - then is_true $ by simp * - else is_false $ by simp * -| x none := is_false $ by rintro ⟨a,⟨⟨⟩⟩⟩ - -instance [partial_order α] [is_total α (≤)] : is_total (with_bot α) (≤) := -{ total := λ a b, match a, b with - | none , _ := or.inl bot_le - | _ , none := or.inr bot_le - | some x, some y := by simp only [some_le_some, total_of] - end } - -instance semilattice_sup [semilattice_sup α] : semilattice_sup (with_bot α) := +instance [semilattice_sup α] : semilattice_sup (with_bot α) := { sup := option.lift_or_get (⊔), le_sup_left := λ o₁ o₂ a ha, by cases ha; cases o₂; simp [option.lift_or_get], @@ -650,7 +647,7 @@ instance semilattice_sup [semilattice_sup α] : semilattice_sup (with_bot α) := lemma coe_sup [semilattice_sup α] (a b : α) : ((a ⊔ b : α) : with_bot α) = a ⊔ b := rfl -instance semilattice_inf [semilattice_inf α] : semilattice_inf (with_bot α) := +instance [semilattice_inf α] : semilattice_inf (with_bot α) := { inf := λ o₁ o₂, o₁.bind (λ a, o₂.map (λ b, a ⊓ b)), inf_le_left := λ o₁ o₂ a ha, begin simp at ha, rcases ha with ⟨b, rfl, c, rfl, rfl⟩, @@ -671,19 +668,33 @@ instance semilattice_inf [semilattice_inf α] : semilattice_inf (with_bot α) := lemma coe_inf [semilattice_inf α] (a b : α) : ((a ⊓ b : α) : with_bot α) = a ⊓ b := rfl -instance lattice [lattice α] : lattice (with_bot α) := +instance [lattice α] : lattice (with_bot α) := { ..with_bot.semilattice_sup, ..with_bot.semilattice_inf } -instance le_is_total [preorder α] [is_total α (≤)] : is_total (with_bot α) (≤) := -⟨λ o₁ o₂, -begin - cases o₁ with a, {exact or.inl bot_le}, - cases o₂ with b, {exact or.inr bot_le}, - exact (total_of (≤) a b).imp some_le_some.mpr some_le_some.mpr, -end⟩ +instance decidable_le [has_le α] [@decidable_rel α (≤)] : @decidable_rel (with_bot α) (≤) +| none x := is_true $ λ a h, option.no_confusion h +| (some x) (some y) := + if h : x ≤ y + then is_true (some_le_some.2 h) + else is_false $ by simp * +| (some x) none := is_false $ λ h, by rcases h x rfl with ⟨y, ⟨_⟩, _⟩ + +instance decidable_lt [has_lt α] [@decidable_rel α (<)] : @decidable_rel (with_bot α) (<) +| none (some x) := is_true $ by existsi [x,rfl]; rintros _ ⟨⟩ +| (some x) (some y) := + if h : x < y + then is_true $ by simp * + else is_false $ by simp * +| x none := is_false $ by rintro ⟨a,⟨⟨⟩⟩⟩ + +instance is_total_le [has_le α] [is_total α (≤)] : is_total (with_bot α) (≤) := +⟨λ a b, match a, b with + | none , _ := or.inl bot_le + | _ , none := or.inr bot_le + | some x, some y := (total_of (≤) x y).imp some_le_some.2 some_le_some.2 + end⟩ -instance linear_order [linear_order α] : linear_order (with_bot α) := -lattice.to_linear_order _ +instance [linear_order α] : linear_order (with_bot α) := lattice.to_linear_order _ @[norm_cast] -- this is not marked simp because the corresponding with_top lemmas are used lemma coe_min [linear_order α] (x y : α) : ((min x y : α) : with_bot α) = min x y := rfl @@ -691,15 +702,7 @@ lemma coe_min [linear_order α] (x y : α) : ((min x y : α) : with_bot α) = mi @[norm_cast] -- this is not marked simp because the corresponding with_top lemmas are used lemma coe_max [linear_order α] (x y : α) : ((max x y : α) : with_bot α) = max x y := rfl -instance order_top [has_le α] [order_top α] : order_top (with_bot α) := -{ top := some ⊤, - le_top := λ o a ha, by cases ha; exact ⟨_, rfl, le_top⟩ } - -instance bounded_order [has_le α] [order_top α] : bounded_order (with_bot α) := -{ ..with_bot.order_top, ..with_bot.order_bot } - -lemma well_founded_lt [preorder α] (h : well_founded ((<) : α → α → Prop)) : - well_founded ((<) : with_bot α → with_bot α → Prop) := +lemma well_founded_lt [preorder α] (h : @well_founded α (<)) : @well_founded (with_bot α) (<) := have acc_bot : acc ((<) : with_bot α → with_bot α → Prop) ⊥ := acc.intro _ (λ a ha, (not_le_of_gt ha bot_le).elim), ⟨λ a, option.rec_on a acc_bot (λ a, acc.intro _ (λ b, option.rec_on b (λ _, acc_bot) @@ -710,8 +713,7 @@ have acc_bot : acc ((<) : with_bot α → with_bot α → Prop) ⊥ := from λ b ih hba, acc.intro _ (λ c, option.rec_on c (λ _, acc_bot) (λ c hc, ih _ (some_lt_some.1 hc) (lt_trans hc hba)))))))⟩ -instance densely_ordered [has_lt α] [densely_ordered α] [no_min_order α] : - densely_ordered (with_bot α) := +instance [has_lt α] [densely_ordered α] [no_min_order α] : densely_ordered (with_bot α) := ⟨ λ a b, match a, b with | a, none := λ h : a < ⊥, (not_lt_none _ h).elim @@ -720,6 +722,20 @@ instance densely_ordered [has_lt α] [densely_ordered α] [no_min_order α] : ⟨a, coe_lt_coe.2 ha₁, coe_lt_coe.2 ha₂⟩ end⟩ +lemma lt_iff_exists_coe_btwn [preorder α] [densely_ordered α] [no_min_order α] {a b : with_bot α} : + a < b ↔ ∃ x : α, a < ↑x ∧ ↑x < b := +⟨λ h, let ⟨y, hy⟩ := exists_between h, ⟨x, hx⟩ := lt_iff_exists_coe.1 hy.1 in ⟨x, hx.1 ▸ hy⟩, + λ ⟨x, hx⟩, lt_trans hx.1 hx.2⟩ + +instance [has_le α] [no_top_order α] [nonempty α] : no_top_order (with_bot α) := +⟨begin + apply rec_bot_coe, + { exact ‹nonempty α›.elim (λ a, ⟨a, not_coe_le_bot a⟩) }, + { intro a, + obtain ⟨b, h⟩ := exists_not_le a, + exact ⟨b, by rwa coe_le_coe⟩ } +end⟩ + instance [has_lt α] [no_max_order α] [nonempty α] : no_max_order (with_bot α) := ⟨begin apply with_bot.rec_bot_coe, @@ -730,10 +746,6 @@ instance [has_lt α] [no_max_order α] [nonempty α] : no_max_order (with_bot α exact ⟨b, with_bot.coe_lt_coe.mpr ha⟩, } end⟩ -protected lemma _root_.is_max.with_bot [has_le α] {a : α} (h : is_max a) : is_max (a : with_bot α) -| none _ := bot_le -| (some b) hb := some_le_some.2 $ h $ some_le_some.1 hb - end with_bot --TODO(Mario): Construct using order dual on with_bot @@ -741,8 +753,9 @@ end with_bot def with_top (α : Type*) := option α namespace with_top +variables {a b : α} -meta instance {α} [has_to_format α] : has_to_format (with_top α) := +meta instance [has_to_format α] : has_to_format (with_top α) := { to_format := λ x, match x with | none := "⊤" @@ -753,22 +766,23 @@ instance [has_repr α] : has_repr (with_top α) := ⟨λ o, match o with | none := "⊤" | (some a) := "↑" ++ repr a end⟩ instance : has_coe_t α (with_top α) := ⟨some⟩ -instance has_top : has_top (with_top α) := ⟨none⟩ +instance : has_top (with_top α) := ⟨none⟩ instance : inhabited (with_top α) := ⟨⊤⟩ lemma none_eq_top : (none : with_top α) = (⊤ : with_top α) := rfl lemma some_eq_coe (a : α) : (some a : with_top α) = (↑a : with_top α) := rfl +@[simp] lemma top_ne_coe : ⊤ ≠ (a : with_top α) . +@[simp] lemma coe_ne_top : (a : with_top α) ≠ ⊤ . + /-- Recursor for `with_top` using the preferred forms `⊤` and `↑a`. -/ @[elab_as_eliminator] def rec_top_coe {C : with_top α → Sort*} (h₁ : C ⊤) (h₂ : Π (a : α), C a) : Π (n : with_top α), C n := option.rec h₁ h₂ -@[norm_cast] -theorem coe_eq_coe {a b : α} : (a : with_top α) = b ↔ a = b := -by rw [← option.some.inj_eq a b]; refl +@[norm_cast] lemma coe_eq_coe : (a : with_top α) = b ↔ a = b := option.some_inj -- the `by exact` here forces the type of the equality to be `@eq (with_top α)` @[simp] lemma map_top (f : α → β) : @@ -776,66 +790,100 @@ by rw [← option.some.inj_eq a b]; refl lemma map_coe (f : α → β) (a : α) : (by exact option.map f (a : with_top α)) = (f a : with_top β) := rfl -@[simp] theorem top_ne_coe {a : α} : ⊤ ≠ (a : with_top α) . -@[simp] theorem coe_ne_top {a : α} : (a : with_top α) ≠ ⊤ . - -lemma ne_top_iff_exists {x : with_top α} : x ≠ ⊤ ↔ ∃ (a : α), ↑a = x := -option.ne_none_iff_exists +lemma ne_top_iff_exists {x : with_top α} : x ≠ ⊤ ↔ ∃ (a : α), ↑a = x := option.ne_none_iff_exists /-- Deconstruct a `x : with_top α` to the underlying value in `α`, given a proof that `x ≠ ⊤`. -/ def untop : Π (x : with_top α), x ≠ ⊤ → α := with_bot.unbot -@[simp] lemma coe_untop {α : Type*} (x : with_top α) (h : x ≠ ⊤) : - (x.untop h : with_top α) = x := +@[simp] lemma coe_untop (x : with_top α) (h : x ≠ ⊤) : (x.untop h : with_top α) = x := by { cases x, simpa using h, refl, } @[simp] lemma untop_coe (x : α) (h : (x : with_top α) ≠ ⊤ := coe_ne_top) : (x : with_top α).untop h = x := rfl -@[priority 10] -instance has_lt [has_lt α] : has_lt (with_top α) := -{ lt := λ o₁ o₂ : option α, ∃ b ∈ o₁, ∀ a ∈ o₂, b < a } +instance : can_lift (with_top α) α := +{ coe := coe, + cond := λ r, r ≠ ⊤, + prf := λ x h, ⟨x.untop h, coe_untop _ _⟩ } + +section has_le +variables [has_le α] @[priority 10] -instance has_le [has_le α] : has_le (with_top α) := -{ le := λ o₁ o₂ : option α, ∀ a ∈ o₂, ∃ b ∈ o₁, b ≤ a } +instance : has_le (with_top α) := ⟨λ o₁ o₂ : option α, ∀ a ∈ o₂, ∃ b ∈ o₁, b ≤ a⟩ + +@[simp] lemma some_le_some : @has_le.le (with_top α) _ (some a) (some b) ↔ a ≤ b := by simp [(≤)] +@[simp, norm_cast] lemma coe_le_coe : (a : with_top α) ≤ b ↔ a ≤ b := some_le_some + +@[simp] lemma le_none {a : with_top α} : @has_le.le (with_top α) _ a none := +λ b h, option.no_confusion h + +instance : order_top (with_top α) := { le_top := λ a, le_none, .. with_top.has_top } + +instance [order_bot α] : order_bot (with_top α) := +{ bot := some ⊥, + bot_le := λ o a ha, by cases ha; exact ⟨_, rfl, bot_le⟩ } + +instance [order_bot α] : bounded_order (with_top α) := +{ ..with_top.order_top, ..with_top.order_bot } + +lemma not_top_le_coe (a : α) : ¬ (⊤ : with_top α) ≤ ↑a := +λ h, let ⟨b, hb, _⟩ := h _ rfl in option.not_mem_none _ hb + +lemma le_coe : ∀ {o : option α}, a ∈ o → (@has_le.le (with_top α) _ o b ↔ a ≤ b) | _ rfl := +coe_le_coe + +lemma le_coe_iff : ∀ {x : with_top α}, x ≤ b ↔ ∃ a : α, x = a ∧ a ≤ b +| (some a) := by simp [some_eq_coe, coe_eq_coe] +| none := iff_of_false (not_top_le_coe _) $ by simp [none_eq_top] + +lemma coe_le_iff : ∀ {x : with_top α}, ↑a ≤ x ↔ ∀ b, x = ↑b → a ≤ b +| (some b) := by simp [some_eq_coe, coe_eq_coe] +| none := by simp [none_eq_top] + +protected lemma _root_.is_min.with_top (h : is_min a) : is_min (a : with_top α) +| none _ := le_top +| (some b) hb := some_le_some.2 $ h $ some_le_some.1 hb + +end has_le -@[simp] theorem some_lt_some [has_lt α] {a b : α} : - @has_lt.lt (with_top α) _ (some a) (some b) ↔ a < b := -by simp [(<)] +section has_lt +variables [has_lt α] -@[simp] theorem some_le_some [has_le α] {a b : α} : - @has_le.le (with_top α) _ (some a) (some b) ↔ a ≤ b := -by simp [(≤)] +@[priority 10] +instance : has_lt (with_top α) := ⟨λ o₁ o₂ : option α, ∃ b ∈ o₁, ∀ a ∈ o₂, b < a⟩ -@[simp] theorem le_none [has_le α] {a : with_top α} : - @has_le.le (with_top α) _ a none := -by simp [(≤)] +@[simp] lemma some_lt_some : @has_lt.lt (with_top α) _ (some a) (some b) ↔ a < b := by simp [(<)] +@[simp, norm_cast] lemma coe_lt_coe : (a : with_top α) < b ↔ a < b := some_lt_some -@[simp] theorem some_lt_none [has_lt α] (a : α) : - @has_lt.lt (with_top α) _ (some a) none := -by simp [(<)]; existsi a; refl +@[simp] lemma some_lt_none (a : α) : @has_lt.lt (with_top α) _ (some a) none := +⟨a, rfl, λ b hb, (option.not_mem_none _ hb).elim⟩ +lemma coe_lt_top (a : α) : (a : with_top α) < ⊤ := some_lt_none a -@[simp] theorem not_none_lt [has_lt α] (a : option α) : ¬ @has_lt.lt (with_top α) _ none a := +@[simp] lemma not_none_lt (a : with_top α) : ¬ @has_lt.lt (with_top α) _ none a := λ ⟨_, h, _⟩, option.not_mem_none _ h -instance : can_lift (with_top α) α := -{ coe := coe, - cond := λ r, r ≠ ⊤, - prf := λ x hx, ⟨option.get $ option.ne_none_iff_is_some.1 hx, option.some_get _⟩ } +lemma lt_iff_exists_coe : ∀ {a b : with_top α}, a < b ↔ ∃ p : α, a = p ∧ ↑p < b +| (some a) b := by simp [some_eq_coe, coe_eq_coe] +| none b := iff_of_false (not_none_lt _) $ by simp [none_eq_top] + +lemma coe_lt_iff : ∀ {x : with_top α}, ↑a < x ↔ ∀ b, x = ↑b → a < b +| (some b) := by simp [some_eq_coe, coe_eq_coe, coe_lt_coe] +| none := by simp [none_eq_top, coe_lt_top] + +end has_lt instance [preorder α] : preorder (with_top α) := -{ le := λ o₁ o₂ : option α, ∀ a ∈ o₂, ∃ b ∈ o₁, b ≤ a, +{ le := (≤), lt := (<), - lt_iff_le_not_le := by { intros; cases a; cases b; - simp [lt_iff_le_not_le]; simp [(<),(≤)] }, + lt_iff_le_not_le := by { intros, cases a; cases b; simp [lt_iff_le_not_le]; simp [(<), (≤)] }, le_refl := λ o a ha, ⟨a, ha, le_rfl⟩, le_trans := λ o₁ o₂ o₃ h₁ h₂ c hc, let ⟨b, hb, bc⟩ := h₂ c hc, ⟨a, ha, ab⟩ := h₁ b hb in - ⟨a, ha, le_trans ab bc⟩, } + ⟨a, ha, le_trans ab bc⟩ } -instance partial_order [partial_order α] : partial_order (with_top α) := +instance [partial_order α] : partial_order (with_top α) := { le_antisymm := λ o₁ o₂ h₁ h₂, begin cases o₂ with b, { cases o₁ with a, {refl}, @@ -846,57 +894,7 @@ instance partial_order [partial_order α] : partial_order (with_top α) := end, .. with_top.preorder } -instance order_top [has_le α] : order_top (with_top α) := -{ le_top := λ a a' h, option.no_confusion h, - .. with_top.has_top } - -@[simp, norm_cast] theorem coe_le_coe [has_le α] {a b : α} : - (a : with_top α) ≤ b ↔ a ≤ b := -⟨λ h, by rcases h b rfl with ⟨_, ⟨⟩, h⟩; exact h, - λ h a' e, option.some_inj.1 e ▸ ⟨a, rfl, h⟩⟩ - -theorem le_coe [has_le α] {a b : α} : - ∀ {o : option α}, a ∈ o → - (@has_le.le (with_top α) _ o b ↔ a ≤ b) -| _ rfl := coe_le_coe - -theorem le_coe_iff [partial_order α] {b : α} : ∀{x : with_top α}, x ≤ b ↔ (∃a:α, x = a ∧ a ≤ b) -| (some a) := by simp [some_eq_coe, coe_eq_coe] -| none := by simp [none_eq_top] - -theorem coe_le_iff [preorder α] {a : α} : ∀{x : with_top α}, ↑a ≤ x ↔ (∀b:α, x = ↑b → a ≤ b) -| (some b) := by simp [some_eq_coe, coe_eq_coe] -| none := by simp [none_eq_top] - -theorem lt_iff_exists_coe [preorder α] : ∀{a b : with_top α}, a < b ↔ (∃p:α, a = p ∧ ↑p < b) -| (some a) b := by simp [some_eq_coe, coe_eq_coe] -| none b := by simp [none_eq_top] - -@[norm_cast] -lemma coe_lt_coe [has_lt α] {a b : α} : (a : with_top α) < b ↔ a < b := some_lt_some - -lemma coe_lt_top [has_lt α] (a : α) : (a : with_top α) < ⊤ := some_lt_none a - -theorem coe_lt_iff [preorder α] {a : α} : ∀{x : with_top α}, ↑a < x ↔ (∀b:α, x = ↑b → a < b) -| (some b) := by simp [some_eq_coe, coe_eq_coe, coe_lt_coe] -| none := by simp [none_eq_top, coe_lt_top] - -lemma not_top_le_coe [preorder α] (a : α) : ¬ (⊤ : with_top α) ≤ ↑a := (coe_lt_top a).not_le - -instance decidable_le [has_le α] [@decidable_rel α (≤)] : @decidable_rel (with_top α) (≤) := -λ x y, @with_bot.decidable_le (order_dual α) _ _ y x - -instance decidable_lt [has_lt α] [@decidable_rel α (<)] : @decidable_rel (with_top α) (<) := -λ x y, @with_bot.decidable_lt (order_dual α) _ _ y x - -instance [partial_order α] [is_total α (≤)] : is_total (with_top α) (≤) := -{ total := λ a b, match a, b with - | none , _ := or.inr le_top - | _ , none := or.inl le_top - | some x, some y := by simp only [some_le_some, total_of] - end } - -instance semilattice_inf [semilattice_inf α] : semilattice_inf (with_top α) := +instance [semilattice_inf α] : semilattice_inf (with_top α) := { inf := option.lift_or_get (⊓), inf_le_left := λ o₁ o₂ a ha, by cases ha; cases o₂; simp [option.lift_or_get], @@ -914,7 +912,7 @@ instance semilattice_inf [semilattice_inf α] : semilattice_inf (with_top α) := lemma coe_inf [semilattice_inf α] (a b : α) : ((a ⊓ b : α) : with_top α) = a ⊓ b := rfl -instance semilattice_sup [semilattice_sup α] : semilattice_sup (with_top α) := +instance [semilattice_sup α] : semilattice_sup (with_top α) := { sup := λ o₁ o₂, o₁.bind (λ a, o₂.map (λ b, a ⊔ b)), le_sup_left := λ o₁ o₂ a ha, begin simp at ha, rcases ha with ⟨b, rfl, c, rfl, rfl⟩, @@ -934,35 +932,31 @@ instance semilattice_sup [semilattice_sup α] : semilattice_sup (with_top α) := lemma coe_sup [semilattice_sup α] (a b : α) : ((a ⊔ b : α) : with_top α) = a ⊔ b := rfl -instance lattice [lattice α] : lattice (with_top α) := +instance [lattice α] : lattice (with_top α) := { ..with_top.semilattice_sup, ..with_top.semilattice_inf } -instance le_is_total [preorder α] [is_total α (≤)] : is_total (with_top α) (≤) := -⟨λ o₁ o₂, -begin - cases o₁ with a, {exact or.inr le_top}, - cases o₂ with b, {exact or.inl le_top}, - exact (total_of (≤) a b).imp some_le_some.mpr some_le_some.mpr, -end⟩ +instance decidable_le [has_le α] [@decidable_rel α (≤)] : @decidable_rel (with_top α) (≤) := +λ x y, @with_bot.decidable_le (order_dual α) _ _ y x + +instance decidable_lt [has_lt α] [@decidable_rel α (<)] : @decidable_rel (with_top α) (<) := +λ x y, @with_bot.decidable_lt (order_dual α) _ _ y x -instance linear_order [linear_order α] : linear_order (with_top α) := -lattice.to_linear_order _ +instance is_total_le [has_le α] [is_total α (≤)] : is_total (with_top α) (≤) := +⟨λ a b, match a, b with + | _ , none := or.inl le_top + | none , _ := or.inr le_top + | some x, some y := (total_of (≤) x y).imp some_le_some.2 some_le_some.2 + end⟩ -@[simp, norm_cast] -lemma coe_min [linear_order α] (x y : α) : ((min x y : α) : with_top α) = min x y := rfl +instance [linear_order α] : linear_order (with_top α) := lattice.to_linear_order _ @[simp, norm_cast] -lemma coe_max [linear_order α] (x y : α) : ((max x y : α) : with_top α) = max x y := rfl +lemma coe_min [linear_order α] (x y : α) : (↑(min x y) : with_top α) = min x y := rfl -instance order_bot [has_le α] [order_bot α] : order_bot (with_top α) := -{ bot := some ⊥, - bot_le := λ o a ha, by cases ha; exact ⟨_, rfl, bot_le⟩ } - -instance bounded_order [has_le α] [order_bot α] : bounded_order (with_top α) := -{ ..with_top.order_top, ..with_top.order_bot } +@[simp, norm_cast] +lemma coe_max [linear_order α] (x y : α) : (↑(max x y) : with_top α) = max x y := rfl -lemma well_founded_lt {α : Type*} [preorder α] (h : well_founded ((<) : α → α → Prop)) : - well_founded ((<) : with_top α → with_top α → Prop) := +lemma well_founded_lt [preorder α] (h : @well_founded α (<)) : @well_founded (with_top α) (<) := have acc_some : ∀ a : α, acc ((<) : with_top α → with_top α → Prop) (some a) := λ a, acc.intro _ (well_founded.induction h a (show ∀ b, (∀ c, c < b → ∀ d : with_top α, d < some c → acc (<) d) → @@ -972,8 +966,14 @@ have acc_some : ∀ a : α, acc ((<) : with_top α → with_top α → Prop) (so ⟨λ a, option.rec_on a (acc.intro _ (λ y, option.rec_on y (λ h, (lt_irrefl _ h).elim) (λ _ _, acc_some _))) acc_some⟩ -instance densely_ordered [has_lt α] [densely_ordered α] [no_max_order α] : - densely_ordered (with_top α) := +lemma well_founded_gt [preorder α] (h : @well_founded α (>)) : @well_founded (with_top α) (>) := +@with_bot.well_founded_lt (order_dual α) _ h + +lemma _root_.with_bot.well_founded_gt [preorder α] (h : @well_founded α (>)) : + @well_founded (with_bot α) (>) := +@with_top.well_founded_lt (order_dual α) _ h + +instance [has_lt α] [densely_ordered α] [no_max_order α] : densely_ordered (with_top α) := ⟨ λ a b, match a, b with | none, a := λ h : ⊤ < a, (not_none_lt _ h).elim @@ -982,25 +982,28 @@ instance densely_ordered [has_lt α] [densely_ordered α] [no_max_order α] : ⟨a, coe_lt_coe.2 ha₁, coe_lt_coe.2 ha₂⟩ end⟩ -lemma lt_iff_exists_coe_btwn [partial_order α] [densely_ordered α] [no_max_order α] - {a b : with_top α} : - (a < b) ↔ (∃ x : α, a < ↑x ∧ ↑x < b) := +lemma lt_iff_exists_coe_btwn [preorder α] [densely_ordered α] [no_max_order α] {a b : with_top α} : + a < b ↔ ∃ x : α, a < ↑x ∧ ↑x < b := ⟨λ h, let ⟨y, hy⟩ := exists_between h, ⟨x, hx⟩ := lt_iff_exists_coe.1 hy.2 in ⟨x, hx.1 ▸ hy⟩, λ ⟨x, hx⟩, lt_trans hx.1 hx.2⟩ -instance [has_lt α] [no_min_order α] [nonempty α] : no_min_order (with_top α) := +instance [has_le α] [no_bot_order α] [nonempty α] : no_bot_order (with_top α) := ⟨begin apply with_top.rec_top_coe, - { apply ‹nonempty α›.elim, - exact λ a, ⟨a, with_top.coe_lt_top a⟩, }, + { exact ‹nonempty α›.elim (λ a, ⟨a, not_top_le_coe a⟩) }, { intro a, - obtain ⟨b, ha⟩ := exists_lt a, - exact ⟨b, with_top.coe_lt_coe.mpr ha⟩, } + obtain ⟨b, h⟩ := exists_not_ge a, + exact ⟨b, by rwa coe_le_coe⟩ } end⟩ -protected lemma _root_.is_min.with_top [has_le α] {a : α} (h : is_min a) : is_min (a : with_top α) -| none _ := le_top -| (some b) hb := some_le_some.2 $ h $ some_le_some.1 hb +instance [has_lt α] [no_min_order α] [nonempty α] : no_min_order (with_top α) := +⟨begin + apply rec_top_coe, + { exact ‹nonempty α›.elim (λ a, ⟨a, with_top.coe_lt_top a⟩) }, + { intro a, + obtain ⟨b, ha⟩ := exists_lt a, + exact ⟨b, coe_lt_coe.mpr ha⟩ } +end⟩ end with_top From 96667b51f8ce1898f54d9690ca82767f5e1b5e02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Sat, 16 Apr 2022 17:33:14 +0000 Subject: [PATCH 053/373] chore(number_theory/*): Weaken assumptions (#13443) Follow @alexjbest's generalization linter to weaken typeclass assumptions in number theory. --- src/number_theory/arithmetic_function.lean | 16 ++++++++++------ .../class_number/admissible_card_pow_degree.lean | 12 +++++++----- src/number_theory/class_number/finite.lean | 2 +- src/number_theory/liouville/basic.lean | 2 +- src/number_theory/padics/ring_homs.lean | 4 ++-- src/number_theory/zsqrtd/basic.lean | 6 ++++-- 6 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/number_theory/arithmetic_function.lean b/src/number_theory/arithmetic_function.lean index 038f1c597151f..967b2ddb6d76a 100644 --- a/src/number_theory/arithmetic_function.lean +++ b/src/number_theory/arithmetic_function.lean @@ -408,7 +408,8 @@ lemma pmul_comm [comm_monoid_with_zero R] (f g : arithmetic_function R) : f.pmul g = g.pmul f := by { ext, simp [mul_comm] } -variable [semiring R] +section non_assoc_semiring +variable [non_assoc_semiring R] @[simp] lemma pmul_zeta (f : arithmetic_function R) : f.pmul ↑ζ = f := @@ -426,6 +427,10 @@ begin simp [nat.succ_ne_zero], end +end non_assoc_semiring + +variables [semiring R] + /-- This is the pointwise power of `arithmetic_function`s. -/ def ppow (f : arithmetic_function R) (k : ℕ) : arithmetic_function R := @@ -775,7 +780,7 @@ end open unique_factorization_monoid -@[simp] lemma coe_moebius_mul_coe_zeta [comm_ring R] : (μ * ζ : arithmetic_function R) = 1 := +@[simp] lemma coe_moebius_mul_coe_zeta [ring R] : (μ * ζ : arithmetic_function R) = 1 := begin ext x, cases x, @@ -883,15 +888,14 @@ begin rw (if_neg (ne_of_gt (nat.pos_of_mem_divisors (snd_mem_divisors_of_mem_antidiagonal hx)))) }, end -/-- Möbius inversion for functions to a `comm_ring`. -/ -theorem sum_eq_iff_sum_mul_moebius_eq [comm_ring R] {f g : ℕ → R} : +/-- Möbius inversion for functions to a `ring`. -/ +theorem sum_eq_iff_sum_mul_moebius_eq [ring R] {f g : ℕ → R} : (∀ (n : ℕ), 0 < n → ∑ i in (n.divisors), f i = g n) ↔ ∀ (n : ℕ), 0 < n → ∑ (x : ℕ × ℕ) in n.divisors_antidiagonal, (μ x.fst : R) * g x.snd = f n := begin rw sum_eq_iff_sum_smul_moebius_eq, apply forall_congr, - intro a, - apply imp_congr (iff.refl _) (eq.congr_left (sum_congr rfl (λ x hx, _))), + refine λ a, imp_congr_right (λ _, (sum_congr rfl $ λ x hx, _).congr_left), rw [zsmul_eq_mul], end diff --git a/src/number_theory/class_number/admissible_card_pow_degree.lean b/src/number_theory/class_number/admissible_card_pow_degree.lean index 7887b0d7fbe80..528ee0d617d9d 100644 --- a/src/number_theory/class_number/admissible_card_pow_degree.lean +++ b/src/number_theory/class_number/admissible_card_pow_degree.lean @@ -24,11 +24,11 @@ namespace polynomial open_locale polynomial open absolute_value real -variables {Fq : Type*} [field Fq] [fintype Fq] +variables {Fq : Type*} [fintype Fq] -/-- If `A` is a family of enough low-degree polynomials over a finite field, there is a +/-- If `A` is a family of enough low-degree polynomials over a finite semiring, there is a pair of equal elements in `A`. -/ -lemma exists_eq_polynomial {d : ℕ} {m : ℕ} (hm : fintype.card Fq ^ d ≤ m) (b : Fq[X]) +lemma exists_eq_polynomial [semiring Fq] {d : ℕ} {m : ℕ} (hm : fintype.card Fq ^ d ≤ m) (b : Fq[X]) (hb : nat_degree b ≤ d) (A : fin m.succ → Fq[X]) (hA : ∀ i, degree (A i) < degree b) : ∃ i₀ i₁, i₀ ≠ i₁ ∧ A i₁ = A i₀ := begin @@ -53,10 +53,10 @@ begin exact lt_of_lt_of_le (coe_lt_degree.mp hbj) hb end -/-- If `A` is a family of enough low-degree polynomials over a finite field, +/-- If `A` is a family of enough low-degree polynomials over a finite ring, there is a pair of elements in `A` (with different indices but not necessarily distinct), such that their difference has small degree. -/ -lemma exists_approx_polynomial_aux {d : ℕ} {m : ℕ} (hm : fintype.card Fq ^ d ≤ m) +lemma exists_approx_polynomial_aux [ring Fq] {d : ℕ} {m : ℕ} (hm : fintype.card Fq ^ d ≤ m) (b : Fq[X]) (A : fin m.succ → Fq[X]) (hA : ∀ i, degree (A i) < degree b) : ∃ i₀ i₁, i₀ ≠ i₁ ∧ degree (A i₁ - A i₀) < ↑(nat_degree b - d) := begin @@ -94,6 +94,8 @@ begin convert congr_fun i_eq.symm ⟨nat_degree b - j.succ, hj⟩ end +variables [field Fq] + /-- If `A` is a family of enough low-degree polynomials over a finite field, there is a pair of elements in `A` (with different indices but not necessarily distinct), such that the difference of their remainders is close together. -/ diff --git a/src/number_theory/class_number/finite.lean b/src/number_theory/class_number/finite.lean index 7f83caeed5398..b380b9ee4f1ce 100644 --- a/src/number_theory/class_number/finite.lean +++ b/src/number_theory/class_number/finite.lean @@ -90,7 +90,7 @@ end /-- If the `R`-integral element `a : S` has coordinates `< y` with respect to some basis `b`, its norm is strictly less than `norm_bound abv b * y ^ dim S`. -/ -lemma norm_lt {T : Type*} [linear_ordered_comm_ring T] +lemma norm_lt {T : Type*} [linear_ordered_ring T] (a : S) {y : T} (hy : ∀ k, (abv (bS.repr a k) : T) < y) : (abv (algebra.norm R a) : T) < norm_bound abv bS * y ^ fintype.card ι := begin diff --git a/src/number_theory/liouville/basic.lean b/src/number_theory/liouville/basic.lean index e634ee31d3aec..c58cfb8886f4c 100644 --- a/src/number_theory/liouville/basic.lean +++ b/src/number_theory/liouville/basic.lean @@ -87,7 +87,7 @@ It is stated in more general form than needed: in the intended application, `Z = root of `f`, `ε` is small, `M` is a bound on the Lipschitz constant of `f` near `α`, `n` is the degree of the polynomial `f`. -/ -lemma exists_one_le_pow_mul_dist {Z N R : Type*} [metric_space R] +lemma exists_one_le_pow_mul_dist {Z N R : Type*} [pseudo_metric_space R] {d : N → ℝ} {j : Z → N → R} {f : R → R} {α : R} {ε M : ℝ} -- denominators are positive (d0 : ∀ (a : N), 1 ≤ d a) diff --git a/src/number_theory/padics/ring_homs.lean b/src/number_theory/padics/ring_homs.lean index 0aecc1af6e12a..32fd01b7b03b6 100644 --- a/src/number_theory/padics/ring_homs.lean +++ b/src/number_theory/padics/ring_homs.lean @@ -465,7 +465,7 @@ section lift open cau_seq padic_seq -variables {R : Type*} [comm_ring R] (f : Π k : ℕ, R →+* zmod (p^k)) +variables {R : Type*} [non_assoc_semiring R] (f : Π k : ℕ, R →+* zmod (p^k)) (f_compat : ∀ k1 k2 (hk : k1 ≤ k2), (zmod.cast_hom (pow_dvd_pow p hk) _).comp (f k2) = f k1) omit hp_prime @@ -687,7 +687,7 @@ begin { rintro rfl _, refl } end -lemma to_zmod_pow_eq_iff_ext {R : Type*} [comm_ring R] {g g' : R →+* ℤ_[p]} : +lemma to_zmod_pow_eq_iff_ext {R : Type*} [non_assoc_semiring R] {g g' : R →+* ℤ_[p]} : (∀ n, (to_zmod_pow n).comp g = (to_zmod_pow n).comp g') ↔ g = g' := begin split, diff --git a/src/number_theory/zsqrtd/basic.lean b/src/number_theory/zsqrtd/basic.lean index 6c9c148a04b84..d884a97778471 100644 --- a/src/number_theory/zsqrtd/basic.lean +++ b/src/number_theory/zsqrtd/basic.lean @@ -725,14 +725,16 @@ begin exact mul_nonpos_of_nonpos_of_nonneg h.le (mul_self_nonneg _) } end -variables {R : Type} [comm_ring R] +variables {R : Type} -@[ext] lemma hom_ext {d : ℤ} (f g : ℤ√d →+* R) (h : f sqrtd = g sqrtd) : f = g := +@[ext] lemma hom_ext [ring R] {d : ℤ} (f g : ℤ√d →+* R) (h : f sqrtd = g sqrtd) : f = g := begin ext ⟨x_re, x_im⟩, simp [decompose, h], end +variables [comm_ring R] + /-- The unique `ring_hom` from `ℤ√d` to a ring `R`, constructed by replacing `√d` with the provided root. Conversely, this associates to every mapping `ℤ√d →+* R` a value of `√d` in `R`. -/ @[simps] From d4fda045ca8739b8eaa1039c335634c7962b2a7b Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Sat, 16 Apr 2022 19:28:42 +0000 Subject: [PATCH 054/373] feat(data/finsupp/basic): add a few lemmas, mostly about `finsupp.filter` (#13457) --- src/data/finsupp/basic.lean | 44 +++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/src/data/finsupp/basic.lean b/src/data/finsupp/basic.lean index 6b48f4d0c9445..b40c019c8e1bc 100644 --- a/src/data/finsupp/basic.lean +++ b/src/data/finsupp/basic.lean @@ -268,6 +268,9 @@ by rwa [single_eq_same, single_eq_same] at this lemma single_apply_eq_zero {a x : α} {b : M} : single a b x = 0 ↔ (x = a → b = 0) := by simp [single_eq_indicator] +lemma single_apply_ne_zero {a x : α} {b : M} : single a b x ≠ 0 ↔ (x = a ∧ b ≠ 0) := +by simp [single_apply_eq_zero] + lemma mem_support_single (a a' : α) (b : M) : a ∈ (single a' b).support ↔ a = a' ∧ b ≠ 0 := by simp [single_apply_eq_zero, not_or_distrib] @@ -309,11 +312,7 @@ lemma single_left_inj (h : b ≠ 0) : single a b = single a' b ↔ a = a' := lemma support_single_ne_bot (i : α) (h : b ≠ 0) : (single i b).support ≠ ⊥ := -begin - have : i ∈ (single i b).support := by simpa using h, - intro H, - simpa [H] -end +by simpa only [support_single_ne_zero h] using singleton_ne_empty _ lemma support_single_disjoint [decidable_eq α] {b' : M} (hb : b ≠ 0) (hb' : b' ≠ 0) {i j : α} : disjoint (single i b).support (single j b').support ↔ i ≠ j := @@ -1941,6 +1940,14 @@ by rw subsingleton.elim D; refl lemma filter_eq_indicator : ⇑(f.filter p) = set.indicator {x | p x} f := rfl +lemma filter_eq_zero_iff : f.filter p = 0 ↔ ∀ x, p x → f x = 0 := +by simp only [fun_like.ext_iff, filter_eq_indicator, zero_apply, set.indicator_apply_eq_zero, + set.mem_set_of_eq] + +lemma filter_eq_self_iff : f.filter p = f ↔ ∀ x, f x ≠ 0 → p x := +by simp only [fun_like.ext_iff, filter_eq_indicator, set.indicator_apply_eq_self, set.mem_set_of_eq, + not_imp_comm] + @[simp] lemma filter_apply_pos {a : α} (h : p a) : f.filter p a = f a := if_pos h @@ -1953,13 +1960,28 @@ by rw subsingleton.elim D; refl lemma filter_zero : (0 : α →₀ M).filter p = 0 := by rw [← support_eq_empty, support_filter, support_zero, finset.filter_empty] -@[simp] lemma filter_single_of_pos - {a : α} {b : M} (h : p a) : (single a b).filter p = single a b := -coe_fn_injective $ by simp [filter_eq_indicator, set.subset_def, mem_support_single, h] +@[simp] lemma filter_single_of_pos {a : α} {b : M} (h : p a) : + (single a b).filter p = single a b := +(filter_eq_self_iff _ _).2 $ λ x hx, (single_apply_ne_zero.1 hx).1.symm ▸ h + +@[simp] lemma filter_single_of_neg {a : α} {b : M} (h : ¬ p a) : (single a b).filter p = 0 := +(filter_eq_zero_iff _ _).2 $ λ x hpx, single_apply_eq_zero.2 $ λ hxa, absurd hpx (hxa.symm ▸ h) + +@[to_additive] lemma prod_filter_index [comm_monoid N] (g : α → M → N) : + (f.filter p).prod g = ∏ x in (f.filter p).support, g x (f x) := +begin + refine finset.prod_congr rfl (λ x hx, _), + rw [support_filter, finset.mem_filter] at hx, + rw [filter_apply_pos _ _ hx.2] +end + +@[simp, to_additive] lemma prod_filter_mul_prod_filter_not [comm_monoid N] (g : α → M → N) : + (f.filter p).prod g * (f.filter (λ a, ¬ p a)).prod g = f.prod g := +by simp_rw [prod_filter_index, support_filter, prod_filter_mul_prod_filter_not, finsupp.prod] -@[simp] lemma filter_single_of_neg - {a : α} {b : M} (h : ¬ p a) : (single a b).filter p = 0 := -ext $ by simp [filter_eq_indicator, single_apply_eq_zero, @imp.swap (p _), h] +@[simp, to_additive] lemma prod_div_prod_filter [comm_group G] (g : α → M → G) : + f.prod g / (f.filter p).prod g = (f.filter (λ a, ¬p a)).prod g := +div_eq_of_eq_mul' (prod_filter_mul_prod_filter_not _ _ _).symm end has_zero From f4f46cd512c0b3b8aeac5f4fd6269ad231692524 Mon Sep 17 00:00:00 2001 From: leanprover-community-bot Date: Sun, 17 Apr 2022 03:57:45 +0000 Subject: [PATCH 055/373] chore(scripts): update nolints.txt (#13482) I am happy to remove some nolints for you! --- scripts/nolints.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/scripts/nolints.txt b/scripts/nolints.txt index 754a7bbc1e0fb..a8b59ac13d68a 100644 --- a/scripts/nolints.txt +++ b/scripts/nolints.txt @@ -521,11 +521,6 @@ apply_nolint affine_subspace.to_add_torsor fails_quickly apply_nolint function.has_scalar to_additive_doc apply_nolint function.smul_comm_class to_additive_doc --- logic/equiv/list.lean -apply_nolint encodable.fintype_arrow doc_blame -apply_nolint encodable.fintype_pi doc_blame -apply_nolint encodable.trunc_encodable_of_fintype doc_blame - -- logic/relator.lean apply_nolint relator.bi_total doc_blame apply_nolint relator.bi_unique doc_blame From 49e41eb5383e372352490c6236cb0293e4e84d59 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Sun, 17 Apr 2022 10:27:47 +0000 Subject: [PATCH 056/373] feat(topology/algebra/order): extreme value thm for a function continuous on a closed set (#13348) --- src/topology/algebra/order/compact.lean | 38 ++++++++++++++++++------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/topology/algebra/order/compact.lean b/src/topology/algebra/order/compact.lean index 95a4b8238fb59..d6cb0371f26e0 100644 --- a/src/topology/algebra/order/compact.lean +++ b/src/topology/algebra/order/compact.lean @@ -21,7 +21,8 @@ We also prove that the image of a closed interval under a continuous map is a cl compact, extreme value theorem -/ -open classical filter order_dual topological_space function set +open filter order_dual topological_space function set +open_locale filter topological_space /-! ### Compactness of a closed interval @@ -221,19 +222,35 @@ lemma is_compact.exists_forall_ge : ∃x∈s, ∀y∈s, f y ≤ f x := @is_compact.exists_forall_le (order_dual α) _ _ _ _ _ +/-- The **extreme value theorem**: if a function `f` is continuous on a closed set `s` and it is +larger than a value in its image away from compact sets, then it has a minimum on this set. -/ +lemma continuous_on.exists_forall_le' {s : set β} {f : β → α} (hf : continuous_on f s) + (hsc : is_closed s) {x₀ : β} (h₀ : x₀ ∈ s) (hc : ∀ᶠ x in cocompact β ⊓ 𝓟 s, f x₀ ≤ f x) : + ∃ x ∈ s, ∀ y ∈ s, f x ≤ f y := +begin + rcases (has_basis_cocompact.inf_principal _).eventually_iff.1 hc with ⟨K, hK, hKf⟩, + have hsub : insert x₀ (K ∩ s) ⊆ s, from insert_subset.2 ⟨h₀, inter_subset_right _ _⟩, + obtain ⟨x, hx, hxf⟩ : ∃ x ∈ insert x₀ (K ∩ s), ∀ y ∈ insert x₀ (K ∩ s), f x ≤ f y := + ((hK.inter_right hsc).insert x₀).exists_forall_le (nonempty_insert _ _) (hf.mono hsub), + refine ⟨x, hsub hx, λ y hy, _⟩, + by_cases hyK : y ∈ K, + exacts [hxf _ (or.inr ⟨hyK, hy⟩), (hxf _ (or.inl rfl)).trans (hKf ⟨hyK, hy⟩)] +end + +/-- The **extreme value theorem**: if a function `f` is continuous on a closed set `s` and it is +smaller than a value in its image away from compact sets, then it has a maximum on this set. -/ +lemma continuous_on.exists_forall_ge' {s : set β} {f : β → α} (hf : continuous_on f s) + (hsc : is_closed s) {x₀ : β} (h₀ : x₀ ∈ s) (hc : ∀ᶠ x in cocompact β ⊓ 𝓟 s, f x ≤ f x₀) : + ∃ x ∈ s, ∀ y ∈ s, f y ≤ f x := +@continuous_on.exists_forall_le' (order_dual α) _ _ _ _ _ _ _ hf hsc _ h₀ hc + /-- The **extreme value theorem**: if a continuous function `f` is larger than a value in its range away from compact sets, then it has a global minimum. -/ lemma _root_.continuous.exists_forall_le' {f : β → α} (hf : continuous f) (x₀ : β) (h : ∀ᶠ x in cocompact β, f x₀ ≤ f x) : ∃ (x : β), ∀ (y : β), f x ≤ f y := -begin - obtain ⟨K : set β, hK : is_compact K, hKf : ∀ x ∉ K, f x₀ ≤ f x⟩ := - (has_basis_cocompact.eventually_iff).mp h, - obtain ⟨x, -, hx⟩ : ∃ x ∈ insert x₀ K, ∀ y ∈ insert x₀ K, f x ≤ f y := - (hK.insert x₀).exists_forall_le (nonempty_insert _ _) hf.continuous_on, - refine ⟨x, λ y, _⟩, - by_cases hy : y ∈ K, - exacts [hx y (or.inr hy), (hx _ (or.inl rfl)).trans (hKf y hy)] -end +let ⟨x, _, hx⟩ := hf.continuous_on.exists_forall_le' is_closed_univ (mem_univ x₀) + (by rwa [principal_univ, inf_top_eq]) +in ⟨x, λ y, hx y (mem_univ y)⟩ /-- The **extreme value theorem**: if a continuous function `f` is smaller than a value in its range away from compact sets, then it has a global maximum. -/ @@ -248,7 +265,6 @@ lemma _root_.continuous.exists_forall_le [nonempty β] {f : β → α} ∃ x, ∀ y, f x ≤ f y := by { inhabit β, exact hf.exists_forall_le' default (hlim.eventually $ eventually_ge_at_top _) } - /-- The **extreme value theorem**: if a continuous function `f` tends to negative infinity away from compact sets, then it has a global maximum. -/ lemma continuous.exists_forall_ge [nonempty β] {f : β → α} From 7c7f35148e1f22bedb5e86949c01c6f62c32d8da Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Sun, 17 Apr 2022 12:41:22 +0000 Subject: [PATCH 057/373] feat(topology/[separation, homeomorph]): separation properties are topological invariants (#13401) --- src/topology/homeomorph.lean | 23 +++++++++-------- src/topology/separation.lean | 50 +++++++++++++++++++++++++++++------- 2 files changed, 54 insertions(+), 19 deletions(-) diff --git a/src/topology/homeomorph.lean b/src/topology/homeomorph.lean index 1bb8bcc606f36..3529087fd6330 100644 --- a/src/topology/homeomorph.lean +++ b/src/topology/homeomorph.lean @@ -178,17 +178,17 @@ protected lemma compact_space [compact_space α] (h : α ≃ₜ β) : compact_sp { compact_univ := by { rw [← image_univ_of_surjective h.surjective, h.compact_image], apply compact_space.compact_univ } } +protected lemma t0_space [t0_space α] (h : α ≃ₜ β) : t0_space β := +h.symm.embedding.t0_space + +protected lemma t1_space [t1_space α] (h : α ≃ₜ β) : t1_space β := +h.symm.embedding.t1_space + protected lemma t2_space [t2_space α] (h : α ≃ₜ β) : t2_space β := -{ t2 := - begin - intros x y hxy, - obtain ⟨u, v, hu, hv, hxu, hyv, huv⟩ := t2_separation (h.symm.injective.ne hxy), - refine ⟨h.symm ⁻¹' u, h.symm ⁻¹' v, - h.symm.continuous.is_open_preimage _ hu, - h.symm.continuous.is_open_preimage _ hv, - hxu, hyv, _⟩, - rw [← preimage_inter, huv, preimage_empty], - end } +h.symm.embedding.t2_space + +protected lemma regular_space [regular_space α] (h : α ≃ₜ β) : regular_space β := +h.symm.embedding.regular_space protected lemma dense_embedding (h : α ≃ₜ β) : dense_embedding h := { dense := h.surjective.dense_range, @@ -216,6 +216,9 @@ open_embedding_of_embedding_open h.embedding h.is_open_map protected lemma closed_embedding (h : α ≃ₜ β) : closed_embedding h := closed_embedding_of_embedding_closed h.embedding h.is_closed_map +protected lemma normal_space [normal_space α] (h : α ≃ₜ β) : normal_space β := +h.symm.closed_embedding.normal_space + lemma preimage_closure (h : α ≃ₜ β) (s : set β) : h ⁻¹' (closure s) = closure (h ⁻¹' s) := h.is_open_map.preimage_closure_eq_closure_preimage h.continuous _ diff --git a/src/topology/separation.lean b/src/topology/separation.lean index 6ddafb3d0aea2..a39e7e750feb1 100644 --- a/src/topology/separation.lean +++ b/src/topology/separation.lean @@ -447,10 +447,22 @@ begin { exact continuous_within_at_update_same } end +lemma t1_space_of_injective_of_continuous [topological_space β] {f : α → β} + (hf : function.injective f) (hf' : continuous f) [t1_space β] : t1_space α := +{ t1 := + begin + intros x, + rw [← function.injective.preimage_image hf {x}, image_singleton], + exact (t1_space.t1 $ f x).preimage hf' + end } + +protected lemma embedding.t1_space [topological_space β] [t1_space β] {f : α → β} + (hf : embedding f) : t1_space α := +t1_space_of_injective_of_continuous hf.inj hf.continuous + instance subtype.t1_space {α : Type u} [topological_space α] [t1_space α] {p : α → Prop} : t1_space (subtype p) := -⟨λ ⟨x, hx⟩, is_closed_induced_iff.2 $ ⟨{x}, is_closed_singleton, set.ext $ λ y, - by simp [subtype.ext_iff_val]⟩⟩ +embedding_subtype_coe.t1_space @[priority 100] -- see Note [lower instance priority] instance t1_space.t0_space [t1_space α] : t0_space α := @@ -1275,14 +1287,21 @@ lemma topological_space.is_topological_basis.nhds_basis_closure [regular_space ⟨λ s, ⟨λ h, let ⟨t, htB, hat, hts⟩ := hB.exists_closure_subset h in ⟨t, ⟨hat, htB⟩, hts⟩, λ ⟨t, ⟨hat, htB⟩, hts⟩, mem_of_superset (hB.mem_nhds htB hat) (subset_closure.trans hts)⟩⟩ +protected lemma embedding.regular_space [topological_space β] [regular_space β] {f : α → β} + (hf : embedding f) : regular_space α := +{ to_t0_space := hf.t0_space, + regular := + begin + intros s a hs ha, + rcases hf.to_inducing.is_closed_iff.1 hs with ⟨s, hs', rfl⟩, + rcases regular_space.regular hs' ha with ⟨t, ht, hst, hat⟩, + refine ⟨f ⁻¹' t, ht.preimage hf.continuous, preimage_mono hst, _⟩, + rw [nhds_within, hf.to_inducing.nhds_eq_comap, ← comap_principal, ← comap_inf, + ← nhds_within, hat, comap_bot] + end } + instance subtype.regular_space [regular_space α] {p : α → Prop} : regular_space (subtype p) := -⟨begin - intros s a hs ha, - rcases is_closed_induced_iff.1 hs with ⟨s, hs', rfl⟩, - rcases regular_space.regular hs' ha with ⟨t, ht, hst, hat⟩, - refine ⟨coe ⁻¹' t, is_open_induced ht, preimage_mono hst, _⟩, - rw [nhds_within, nhds_induced, ← comap_principal, ← comap_inf, ← nhds_within, hat, comap_bot] - end⟩ +embedding_subtype_coe.regular_space variable (α) @[priority 100] -- see Note [lower instance priority] @@ -1403,6 +1422,19 @@ begin exact compact_compact_separated hs.is_compact ht.is_compact st.eq_bot end +protected lemma closed_embedding.normal_space [topological_space β] [normal_space β] {f : α → β} + (hf : closed_embedding f) : normal_space α := +{ to_t1_space := hf.to_embedding.t1_space, + normal := + begin + intros s t hs ht hst, + rcases normal_space.normal (f '' s) (f '' t) (hf.is_closed_map s hs) (hf.is_closed_map t ht) + (disjoint_image_of_injective hf.inj hst) with ⟨u, v, hu, hv, hsu, htv, huv⟩, + rw image_subset_iff at hsu htv, + exact ⟨f ⁻¹' u, f ⁻¹' v, hu.preimage hf.continuous, hv.preimage hf.continuous, + hsu, htv, huv.preimage f⟩ + end } + variable (α) /-- A regular topological space with second countable topology is a normal space. From 9380977b6bd15d12ed0f02372b6ebb922ea9e580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Sun, 17 Apr 2022 13:47:06 +0000 Subject: [PATCH 058/373] chore(algebra/big_operators/fin): moving lemmas (#13331) This PR moves lemmas about products and sums over `fin n` from `data/fintype/card.lean` to `algebra/big_operators/fin.lean`. Co-authored-by: Oliver Nash --- src/algebra/big_operators/fin.lean | 172 +++++++++++++++++- .../alternating_face_map_complex.lean | 2 +- src/combinatorics/composition.lean | 2 +- src/data/fintype/card.lean | 156 ---------------- src/data/matrix/notation.lean | 1 + 5 files changed, 173 insertions(+), 160 deletions(-) diff --git a/src/algebra/big_operators/fin.lean b/src/algebra/big_operators/fin.lean index 6196b758c417f..fee0c4262cfc8 100644 --- a/src/algebra/big_operators/fin.lean +++ b/src/algebra/big_operators/fin.lean @@ -1,22 +1,108 @@ /- -Copyright (c) 2021 Anne Baanen. All rights reserved. +Copyright (c) 2020 Yury Kudryashov, Anne Baanen. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Anne Baanen +Authors: Yury Kudryashov, Anne Baanen -/ import algebra.big_operators.basic import data.fintype.fin +import data.fintype.card /-! # Big operators and `fin` Some results about products and sums over the type `fin`. + +The most important results are the induction formulas `fin.prod_univ_cast_succ` +and `fin.prod_univ_succ`, and the formula `fin.prod_const` for the product of a +constant function. These results have variants for sums instead of products. + -/ open_locale big_operators open finset +variables {α : Type*} {β : Type*} + +namespace finset + +@[to_additive] +theorem prod_range [comm_monoid β] {n : ℕ} (f : ℕ → β) : + ∏ i in finset.range n, f i = ∏ i : fin n, f i := +begin + fapply @finset.prod_bij' _ _ _ _ _ _, + exact λ k w, ⟨k, (by simpa using w)⟩, + swap 3, + exact λ a m, a, + swap 3, + exact λ a m, by simpa using a.2, + all_goals { tidy, }, +end + +end finset + namespace fin +@[to_additive] +theorem prod_univ_def [comm_monoid β] {n : ℕ} (f : fin n → β) : + ∏ i, f i = ((list.fin_range n).map f).prod := +by simp [univ_def, finset.fin_range] + +@[to_additive] +theorem prod_of_fn [comm_monoid β] {n : ℕ} (f : fin n → β) : + (list.of_fn f).prod = ∏ i, f i := +by rw [list.of_fn_eq_map, prod_univ_def] + +/-- A product of a function `f : fin 0 → β` is `1` because `fin 0` is empty -/ +@[to_additive "A sum of a function `f : fin 0 → β` is `0` because `fin 0` is empty"] +theorem prod_univ_zero [comm_monoid β] (f : fin 0 → β) : ∏ i, f i = 1 := rfl + +/-- A product of a function `f : fin (n + 1) → β` over all `fin (n + 1)` +is the product of `f x`, for some `x : fin (n + 1)` times the remaining product -/ +@[to_additive +/- A sum of a function `f : fin (n + 1) → β` over all `fin (n + 1)` +is the sum of `f x`, for some `x : fin (n + 1)` plus the remaining product -/] +theorem prod_univ_succ_above [comm_monoid β] {n : ℕ} (f : fin (n + 1) → β) + (x : fin (n + 1)) : + ∏ i, f i = f x * ∏ i : fin n, f (x.succ_above i) := +begin + rw [fintype.prod_eq_mul_prod_compl x, ← image_succ_above_univ, prod_image], + exact λ _ _ _ _ h, x.succ_above.injective h +end + +/-- A product of a function `f : fin (n + 1) → β` over all `fin (n + 1)` +is the product of `f 0` plus the remaining product -/ +@[to_additive +/- A sum of a function `f : fin (n + 1) → β` over all `fin (n + 1)` +is the sum of `f 0` plus the remaining product -/] +theorem prod_univ_succ [comm_monoid β] {n : ℕ} (f : fin (n + 1) → β) : + ∏ i, f i = f 0 * ∏ i : fin n, f i.succ := +prod_univ_succ_above f 0 + +/-- A product of a function `f : fin (n + 1) → β` over all `fin (n + 1)` +is the product of `f (fin.last n)` plus the remaining product -/ +@[to_additive +/- A sum of a function `f : fin (n + 1) → β` over all `fin (n + 1)` +is the sum of `f (fin.last n)` plus the remaining sum -/] +theorem prod_univ_cast_succ [comm_monoid β] {n : ℕ} (f : fin (n + 1) → β) : + ∏ i, f i = (∏ i : fin n, f i.cast_succ) * f (last n) := +by simpa [mul_comm] using prod_univ_succ_above f (last n) + +@[to_additive sum_univ_one] theorem prod_univ_one [comm_monoid β] (f : fin 1 → β) : + ∏ i, f i = f 0 := +by simp + +@[to_additive] theorem prod_univ_two [comm_monoid β] (f : fin 2 → β) : + ∏ i, f i = f 0 * f 1 := +by simp [prod_univ_succ] + +lemma sum_pow_mul_eq_add_pow {n : ℕ} {R : Type*} [comm_semiring R] (a b : R) : + ∑ s : finset (fin n), a ^ s.card * b ^ (n - s.card) = (a + b) ^ n := +by simpa using fintype.sum_pow_mul_eq_add_pow (fin n) a b + +lemma prod_const [comm_monoid α] (n : ℕ) (x : α) : ∏ i : fin n, x = x ^ n := by simp + +lemma sum_const [add_comm_monoid α] (n : ℕ) (x : α) : ∑ i : fin n, x = n • x := by simp + @[to_additive] lemma prod_filter_zero_lt {M : Type*} [comm_monoid M] {n : ℕ} {v : fin n.succ → M} : ∏ i in univ.filter (λ (i : fin n.succ), 0 < i), v i = ∏ (j : fin n), v j.succ := @@ -29,3 +115,85 @@ lemma prod_filter_succ_lt {M : Type*} [comm_monoid M] {n : ℕ} (j : fin n) (v : by rw [univ_filter_succ_lt, finset.prod_map, rel_embedding.coe_fn_to_embedding, coe_succ_embedding] end fin + +namespace list + +@[to_additive] +lemma prod_take_of_fn [comm_monoid α] {n : ℕ} (f : fin n → α) (i : ℕ) : + ((of_fn f).take i).prod = ∏ j in finset.univ.filter (λ (j : fin n), j.val < i), f j := +begin + have A : ∀ (j : fin n), ¬ ((j : ℕ) < 0) := λ j, not_lt_bot, + induction i with i IH, { simp [A] }, + by_cases h : i < n, + { have : i < length (of_fn f), by rwa [length_of_fn f], + rw prod_take_succ _ _ this, + have A : ((finset.univ : finset (fin n)).filter (λ j, j.val < i + 1)) + = ((finset.univ : finset (fin n)).filter (λ j, j.val < i)) ∪ {(⟨i, h⟩ : fin n)}, + by { ext j, simp [nat.lt_succ_iff_lt_or_eq, fin.ext_iff, - add_comm] }, + have B : _root_.disjoint (finset.filter (λ (j : fin n), j.val < i) finset.univ) + (singleton (⟨i, h⟩ : fin n)), by simp, + rw [A, finset.prod_union B, IH], + simp }, + { have A : (of_fn f).take i = (of_fn f).take i.succ, + { rw ← length_of_fn f at h, + have : length (of_fn f) ≤ i := not_lt.mp h, + rw [take_all_of_le this, take_all_of_le (le_trans this (nat.le_succ _))] }, + have B : ∀ (j : fin n), ((j : ℕ) < i.succ) = ((j : ℕ) < i), + { assume j, + have : (j : ℕ) < i := lt_of_lt_of_le j.2 (not_lt.mp h), + simp [this, lt_trans this (nat.lt_succ_self _)] }, + simp [← A, B, IH] } +end + +@[to_additive] +lemma prod_of_fn [comm_monoid α] {n : ℕ} {f : fin n → α} : + (of_fn f).prod = ∏ i, f i := +begin + convert prod_take_of_fn f n, + { rw [take_all_of_le (le_of_eq (length_of_fn f))] }, + { have : ∀ (j : fin n), (j : ℕ) < n := λ j, j.is_lt, + simp [this] } +end + +lemma alternating_sum_eq_finset_sum {G : Type*} [add_comm_group G] : + ∀ (L : list G), alternating_sum L = ∑ i : fin L.length, (-1 : ℤ) ^ (i : ℕ) • L.nth_le i i.is_lt +| [] := by { rw [alternating_sum, finset.sum_eq_zero], rintro ⟨i, ⟨⟩⟩ } +| (g :: []) := +begin + show g = ∑ i : fin 1, (-1 : ℤ) ^ (i : ℕ) • [g].nth_le i i.2, + rw [fin.sum_univ_succ], simp, +end +| (g :: h :: L) := +calc g + -h + L.alternating_sum + = g + -h + ∑ i : fin L.length, (-1 : ℤ) ^ (i : ℕ) • L.nth_le i i.2 : + congr_arg _ (alternating_sum_eq_finset_sum _) +... = ∑ i : fin (L.length + 2), (-1 : ℤ) ^ (i : ℕ) • list.nth_le (g :: h :: L) i _ : +begin + rw [fin.sum_univ_succ, fin.sum_univ_succ, add_assoc], + unfold_coes, + simp [nat.succ_eq_add_one, pow_add], + refl, +end + +@[to_additive] +lemma alternating_prod_eq_finset_prod {G : Type*} [comm_group G] : + ∀ (L : list G), alternating_prod L = ∏ i : fin L.length, (L.nth_le i i.2) ^ ((-1 : ℤ) ^ (i : ℕ)) +| [] := by { rw [alternating_prod, finset.prod_eq_one], rintro ⟨i, ⟨⟩⟩ } +| (g :: []) := +begin + show g = ∏ i : fin 1, [g].nth_le i i.2 ^ (-1 : ℤ) ^ (i : ℕ), + rw [fin.prod_univ_succ], simp, +end +| (g :: h :: L) := +calc g * h⁻¹ * L.alternating_prod + = g * h⁻¹ * ∏ i : fin L.length, L.nth_le i i.2 ^ (-1 : ℤ) ^ (i : ℕ) : + congr_arg _ (alternating_prod_eq_finset_prod _) +... = ∏ i : fin (L.length + 2), list.nth_le (g :: h :: L) i _ ^ (-1 : ℤ) ^ (i : ℕ) : +begin + rw [fin.prod_univ_succ, fin.prod_univ_succ, mul_assoc], + unfold_coes, + simp [nat.succ_eq_add_one, pow_add], + refl, +end + +end list diff --git a/src/algebraic_topology/alternating_face_map_complex.lean b/src/algebraic_topology/alternating_face_map_complex.lean index d0eabb2f49d57..2e2c7649b4e6e 100644 --- a/src/algebraic_topology/alternating_face_map_complex.lean +++ b/src/algebraic_topology/alternating_face_map_complex.lean @@ -6,7 +6,7 @@ Authors: Joël Riou, Adam Topaz, Johan Commelin import algebra.homology.additive import algebraic_topology.Moore_complex -import data.fintype.card +import algebra.big_operators.fin /-! diff --git a/src/combinatorics/composition.lean b/src/combinatorics/composition.lean index dea3e3e37fddb..1741afc367f99 100644 --- a/src/combinatorics/composition.lean +++ b/src/combinatorics/composition.lean @@ -3,9 +3,9 @@ Copyright (c) 2020 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ -import data.fintype.card import data.finset.sort import algebra.big_operators.order +import algebra.big_operators.fin /-! # Compositions diff --git a/src/data/fintype/card.lean b/src/data/fintype/card.lean index d95bdd1329bf9..9d5e5a4f1493d 100644 --- a/src/data/fintype/card.lean +++ b/src/data/fintype/card.lean @@ -96,72 +96,6 @@ finset.prod_insert_none f univ end -@[to_additive] -theorem fin.prod_univ_def [comm_monoid β] {n : ℕ} (f : fin n → β) : - ∏ i, f i = ((list.fin_range n).map f).prod := -by simp [fin.univ_def, finset.fin_range] - -@[to_additive] -theorem finset.prod_range [comm_monoid β] {n : ℕ} (f : ℕ → β) : - ∏ i in finset.range n, f i = ∏ i : fin n, f i := -begin - fapply @finset.prod_bij' _ _ _ _ _ _, - exact λ k w, ⟨k, (by simpa using w)⟩, - swap 3, - exact λ a m, a, - swap 3, - exact λ a m, by simpa using a.2, - all_goals { tidy, }, -end - -@[to_additive] -theorem fin.prod_of_fn [comm_monoid β] {n : ℕ} (f : fin n → β) : - (list.of_fn f).prod = ∏ i, f i := -by rw [list.of_fn_eq_map, fin.prod_univ_def] - -/-- A product of a function `f : fin 0 → β` is `1` because `fin 0` is empty -/ -@[to_additive "A sum of a function `f : fin 0 → β` is `0` because `fin 0` is empty"] -theorem fin.prod_univ_zero [comm_monoid β] (f : fin 0 → β) : ∏ i, f i = 1 := rfl - -/-- A product of a function `f : fin (n + 1) → β` over all `fin (n + 1)` -is the product of `f x`, for some `x : fin (n + 1)` times the remaining product -/ -@[to_additive -/- A sum of a function `f : fin (n + 1) → β` over all `fin (n + 1)` -is the sum of `f x`, for some `x : fin (n + 1)` plus the remaining product -/] -theorem fin.prod_univ_succ_above [comm_monoid β] {n : ℕ} (f : fin (n + 1) → β) - (x : fin (n + 1)) : - ∏ i, f i = f x * ∏ i : fin n, f (x.succ_above i) := -begin - rw [fintype.prod_eq_mul_prod_compl x, ← fin.image_succ_above_univ, prod_image], - exact λ _ _ _ _ h, x.succ_above.injective h -end - -/-- A product of a function `f : fin (n + 1) → β` over all `fin (n + 1)` -is the product of `f 0` plus the remaining product -/ -@[to_additive -/- A sum of a function `f : fin (n + 1) → β` over all `fin (n + 1)` -is the sum of `f 0` plus the remaining product -/] -theorem fin.prod_univ_succ [comm_monoid β] {n : ℕ} (f : fin (n + 1) → β) : - ∏ i, f i = f 0 * ∏ i : fin n, f i.succ := -fin.prod_univ_succ_above f 0 - -/-- A product of a function `f : fin (n + 1) → β` over all `fin (n + 1)` -is the product of `f (fin.last n)` plus the remaining product -/ -@[to_additive -/- A sum of a function `f : fin (n + 1) → β` over all `fin (n + 1)` -is the sum of `f (fin.last n)` plus the remaining sum -/] -theorem fin.prod_univ_cast_succ [comm_monoid β] {n : ℕ} (f : fin (n + 1) → β) : - ∏ i, f i = (∏ i : fin n, f i.cast_succ) * f (fin.last n) := -by simpa [mul_comm] using fin.prod_univ_succ_above f (fin.last n) - -@[to_additive sum_univ_one] theorem fin.prod_univ_one [comm_monoid β] (f : fin 1 → β) : - ∏ i, f i = f 0 := -by simp - -@[to_additive] theorem fin.prod_univ_two [comm_monoid β] (f : fin 2 → β) : - ∏ i, f i = f 0 * f 1 := -by simp [fin.prod_univ_succ] - open finset @[simp] theorem fintype.card_sigma {α : Type*} (β : α → Type*) @@ -234,14 +168,6 @@ lemma fintype.sum_pow_mul_eq_add_pow (a + b) ^ (fintype.card α) := finset.sum_pow_mul_eq_add_pow _ _ _ -lemma fin.sum_pow_mul_eq_add_pow {n : ℕ} {R : Type*} [comm_semiring R] (a b : R) : - ∑ s : finset (fin n), a ^ s.card * b ^ (n - s.card) = (a + b) ^ n := -by simpa using fintype.sum_pow_mul_eq_add_pow (fin n) a b - -lemma fin.prod_const [comm_monoid α] (n : ℕ) (x : α) : ∏ i : fin n, x = x ^ n := by simp - -lemma fin.sum_const [add_comm_monoid α] (n : ℕ) (x : α) : ∑ i : fin n, x = n • x := by simp - @[to_additive] lemma function.bijective.prod_comp [fintype α] [fintype β] [comm_monoid γ] {f : α → β} (hf : function.bijective f) (g : β → γ) : @@ -319,85 +245,3 @@ lemma fintype.prod_sum_type (f : α₁ ⊕ α₂ → M) : by simp only [← fintype.prod_sum_elim, sum.elim_comp_inl_inr] end - -namespace list - -@[to_additive] -lemma prod_take_of_fn [comm_monoid α] {n : ℕ} (f : fin n → α) (i : ℕ) : - ((of_fn f).take i).prod = ∏ j in finset.univ.filter (λ (j : fin n), j.val < i), f j := -begin - have A : ∀ (j : fin n), ¬ ((j : ℕ) < 0) := λ j, not_lt_bot, - induction i with i IH, { simp [A] }, - by_cases h : i < n, - { have : i < length (of_fn f), by rwa [length_of_fn f], - rw prod_take_succ _ _ this, - have A : ((finset.univ : finset (fin n)).filter (λ j, j.val < i + 1)) - = ((finset.univ : finset (fin n)).filter (λ j, j.val < i)) ∪ {(⟨i, h⟩ : fin n)}, - by { ext j, simp [nat.lt_succ_iff_lt_or_eq, fin.ext_iff, - add_comm] }, - have B : _root_.disjoint (finset.filter (λ (j : fin n), j.val < i) finset.univ) - (singleton (⟨i, h⟩ : fin n)), by simp, - rw [A, finset.prod_union B, IH], - simp }, - { have A : (of_fn f).take i = (of_fn f).take i.succ, - { rw ← length_of_fn f at h, - have : length (of_fn f) ≤ i := not_lt.mp h, - rw [take_all_of_le this, take_all_of_le (le_trans this (nat.le_succ _))] }, - have B : ∀ (j : fin n), ((j : ℕ) < i.succ) = ((j : ℕ) < i), - { assume j, - have : (j : ℕ) < i := lt_of_lt_of_le j.2 (not_lt.mp h), - simp [this, lt_trans this (nat.lt_succ_self _)] }, - simp [← A, B, IH] } -end - -@[to_additive] -lemma prod_of_fn [comm_monoid α] {n : ℕ} {f : fin n → α} : - (of_fn f).prod = ∏ i, f i := -begin - convert prod_take_of_fn f n, - { rw [take_all_of_le (le_of_eq (length_of_fn f))] }, - { have : ∀ (j : fin n), (j : ℕ) < n := λ j, j.is_lt, - simp [this] } -end - -lemma alternating_sum_eq_finset_sum {G : Type*} [add_comm_group G] : - ∀ (L : list G), alternating_sum L = ∑ i : fin L.length, (-1 : ℤ) ^ (i : ℕ) • L.nth_le i i.is_lt -| [] := by { rw [alternating_sum, finset.sum_eq_zero], rintro ⟨i, ⟨⟩⟩ } -| (g :: []) := -begin - show g = ∑ i : fin 1, (-1 : ℤ) ^ (i : ℕ) • [g].nth_le i i.2, - rw [fin.sum_univ_succ], simp, -end -| (g :: h :: L) := -calc g + -h + L.alternating_sum - = g + -h + ∑ i : fin L.length, (-1 : ℤ) ^ (i : ℕ) • L.nth_le i i.2 : - congr_arg _ (alternating_sum_eq_finset_sum _) -... = ∑ i : fin (L.length + 2), (-1 : ℤ) ^ (i : ℕ) • list.nth_le (g :: h :: L) i _ : -begin - rw [fin.sum_univ_succ, fin.sum_univ_succ, add_assoc], - unfold_coes, - simp [nat.succ_eq_add_one, pow_add], - refl, -end - -@[to_additive] -lemma alternating_prod_eq_finset_prod {G : Type*} [comm_group G] : - ∀ (L : list G), alternating_prod L = ∏ i : fin L.length, (L.nth_le i i.2) ^ ((-1 : ℤ) ^ (i : ℕ)) -| [] := by { rw [alternating_prod, finset.prod_eq_one], rintro ⟨i, ⟨⟩⟩ } -| (g :: []) := -begin - show g = ∏ i : fin 1, [g].nth_le i i.2 ^ (-1 : ℤ) ^ (i : ℕ), - rw [fin.prod_univ_succ], simp, -end -| (g :: h :: L) := -calc g * h⁻¹ * L.alternating_prod - = g * h⁻¹ * ∏ i : fin L.length, L.nth_le i i.2 ^ (-1 : ℤ) ^ (i : ℕ) : - congr_arg _ (alternating_prod_eq_finset_prod _) -... = ∏ i : fin (L.length + 2), list.nth_le (g :: h :: L) i _ ^ (-1 : ℤ) ^ (i : ℕ) : -begin - rw [fin.prod_univ_succ, fin.prod_univ_succ, mul_assoc], - unfold_coes, - simp [nat.succ_eq_add_one, pow_add], - refl, -end - -end list diff --git a/src/data/matrix/notation.lean b/src/data/matrix/notation.lean index ef32278f963a3..d6d5bf6659a7d 100644 --- a/src/data/matrix/notation.lean +++ b/src/data/matrix/notation.lean @@ -6,6 +6,7 @@ Authors: Anne Baanen import data.matrix.basic import data.fin.vec_notation import tactic.fin_cases +import algebra.big_operators.fin /-! # Matrix and vector notation From b90e770fd3929c858be4cb2f7f0ebdfc525999ed Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sun, 17 Apr 2022 15:18:44 +0000 Subject: [PATCH 059/373] feat(data/fin/tuple/nat_antidiagonal): add `list.nat.antidiagonal_tuple_pairwise_pi_lex` (#13339) This proof feels a little clumsy, but maybe that's unavoidable. --- src/data/fin/tuple/nat_antidiagonal.lean | 40 +++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/data/fin/tuple/nat_antidiagonal.lean b/src/data/fin/tuple/nat_antidiagonal.lean index 2f0ac3e1d3af4..6f76b6696dd2a 100644 --- a/src/data/fin/tuple/nat_antidiagonal.lean +++ b/src/data/fin/tuple/nat_antidiagonal.lean @@ -50,7 +50,8 @@ namespace list.nat /-- `list.antidiagonal_tuple k n` is a list of all `k`-tuples which sum to `n`. -This list contains no duplicates, and is sorted lexicographically, starting with `![0, ..., n]` +This list contains no duplicates (`list.nat.nodup_antidiagonal_tuple`), and is sorted +lexicographically (`list.nat.antidiagonal_tuple_pairwise_pi_lex`), starting with `![0, ..., n]` and ending with `![n, ..., 0]`. ``` @@ -113,6 +114,14 @@ begin exact h (list.mem_map_of_mem _ hx₁) (list.mem_map_of_mem _ hx₂) }, }, end +lemma antidiagonal_tuple_zero_right : ∀ k, antidiagonal_tuple k 0 = [0] +| 0 := congr_arg (λ x, [x]) $ subsingleton.elim _ _ +| (k + 1) := begin + rw [antidiagonal_tuple, antidiagonal_zero, list.bind_singleton, antidiagonal_tuple_zero_right k, + list.map_singleton], + exact congr_arg (λ x, [x]) matrix.cons_zero_zero +end + @[simp] lemma antidiagonal_tuple_one (n : ℕ) : antidiagonal_tuple 1 n = [![n]] := begin simp_rw [antidiagonal_tuple, antidiagonal, list.range_succ, list.map_append, list.map_singleton, @@ -135,6 +144,29 @@ begin refl, end +lemma antidiagonal_tuple_pairwise_pi_lex : ∀ k n, + (antidiagonal_tuple k n).pairwise (pi.lex (<) (λ _, (<))) +| 0 0 := list.pairwise_singleton _ _ +| 0 (n + 1) := list.pairwise.nil +| (k + 1) n := begin + simp_rw [antidiagonal_tuple, list.pairwise_bind, list.pairwise_map, list.mem_map, + forall_exists_index, and_imp, forall_apply_eq_imp_iff₂], + simp only [mem_antidiagonal, prod.forall, and_imp, forall_apply_eq_imp_iff₂], + simp only [fin.pi_lex_lt_cons_cons, eq_self_iff_true, true_and, lt_self_iff_false, false_or], + refine ⟨λ _ _ _, antidiagonal_tuple_pairwise_pi_lex k _, _⟩, + induction n, + { rw [antidiagonal_zero], + exact list.pairwise_singleton _ _ }, + { rw [antidiagonal_succ, list.pairwise_cons, list.pairwise_map], + refine ⟨λ p hp x hx y hy, _, _⟩, + { rw [list.mem_map, prod.exists] at hp, + obtain ⟨a, b, hab, (rfl : (nat.succ a, b) = p)⟩ := hp, + exact or.inl (nat.zero_lt_succ _), }, + dsimp, + simp_rw [nat.succ_inj', nat.succ_lt_succ_iff], + exact n_ih }, +end + end list.nat /-! ### Multisets -/ @@ -154,6 +186,9 @@ list.nat.mem_antidiagonal_tuple lemma nodup_antidiagonal_tuple (k n : ℕ) : (antidiagonal_tuple k n).nodup := list.nat.nodup_antidiagonal_tuple _ _ +lemma antidiagonal_tuple_zero_right (k : ℕ) : antidiagonal_tuple k 0 = {0} := +congr_arg _ (list.nat.antidiagonal_tuple_zero_right k) + @[simp] lemma antidiagonal_tuple_one (n : ℕ) : antidiagonal_tuple 1 n = { ![n]} := congr_arg _ (list.nat.antidiagonal_tuple_one n) @@ -177,6 +212,9 @@ lemma mem_antidiagonal_tuple {n : ℕ} {k : ℕ} {x : fin k → ℕ} : x ∈ antidiagonal_tuple k n ↔ ∑ i, x i = n := list.nat.mem_antidiagonal_tuple +lemma antidiagonal_tuple_zero_right (k : ℕ) : antidiagonal_tuple k 0 = {0} := +finset.eq_of_veq (multiset.nat.antidiagonal_tuple_zero_right k) + @[simp] lemma antidiagonal_tuple_one (n : ℕ) : antidiagonal_tuple 1 n = { ![n]} := finset.eq_of_veq (multiset.nat.antidiagonal_tuple_one n) From e6322c6acc2a71447ce123bed4fae533f0ced711 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Sun, 17 Apr 2022 15:18:45 +0000 Subject: [PATCH 060/373] feat(analysis/convex): golf some proofs (#13451) --- src/algebra/order/smul.lean | 11 ++- src/analysis/convex/extrema.lean | 84 ++++++++----------- src/analysis/convex/topology.lean | 31 +++---- src/data/real/cardinality.lean | 2 +- src/data/set/intervals/image_preimage.lean | 10 ++- .../affine_space/affine_map.lean | 6 +- 6 files changed, 60 insertions(+), 84 deletions(-) diff --git a/src/algebra/order/smul.lean b/src/algebra/order/smul.lean index f80243dff13ee..85bc3a0a26666 100644 --- a/src/algebra/order/smul.lean +++ b/src/algebra/order/smul.lean @@ -97,12 +97,11 @@ lemma smul_lt_smul_of_pos : a < b → 0 < c → c • a < c • b := ordered_smu lemma smul_le_smul_of_nonneg (h₁ : a ≤ b) (h₂ : 0 ≤ c) : c • a ≤ c • b := begin - by_cases H₁ : c = 0, - { simp [H₁, zero_smul] }, - { by_cases H₂ : a = b, - { rw H₂ }, - { exact le_of_lt - (smul_lt_smul_of_pos (lt_of_le_of_ne h₁ H₂) (lt_of_le_of_ne h₂ (ne.symm H₁))), } } + rcases h₁.eq_or_lt with rfl|hab, + { refl }, + { rcases h₂.eq_or_lt with rfl|hc, + { rw [zero_smul, zero_smul] }, + { exact (smul_lt_smul_of_pos hab hc).le } } end lemma smul_nonneg (hc : 0 ≤ c) (ha : 0 ≤ a) : 0 ≤ c • a := diff --git a/src/analysis/convex/extrema.lean b/src/analysis/convex/extrema.lean index d78c76cab518e..5bc221d88a1c9 100644 --- a/src/analysis/convex/extrema.lean +++ b/src/analysis/convex/extrema.lean @@ -17,43 +17,33 @@ a global minimum, and likewise for concave functions. variables {E β : Type*} [add_comm_group E] [topological_space E] [module ℝ E] [topological_add_group E] [has_continuous_smul ℝ E] - [linear_ordered_add_comm_group β] [module ℝ β] [ordered_smul ℝ β] + [ordered_add_comm_group β] [module ℝ β] [ordered_smul ℝ β] {s : set E} -open set filter -open_locale classical +open set filter function +open_locale classical topological_space /-- Helper lemma for the more general case: `is_min_on.of_is_local_min_on_of_convex_on`. -/ lemma is_min_on.of_is_local_min_on_of_convex_on_Icc {f : ℝ → β} {a b : ℝ} (a_lt_b : a < b) (h_local_min : is_local_min_on f (Icc a b) a) (h_conv : convex_on ℝ (Icc a b) f) : - ∀ x ∈ Icc a b, f a ≤ f x := + is_min_on f (Icc a b) a := begin - by_contra' H_cont, - rcases H_cont with ⟨x, ⟨h_ax, h_xb⟩, fx_lt_fa⟩, - obtain ⟨z, hz, ge_on_nhd⟩ : ∃ z > a, ∀ y ∈ (Icc a z), f y ≥ f a, - { rcases eventually_iff_exists_mem.mp h_local_min with ⟨U, U_in_nhds_within, fy_ge_fa⟩, - rw [nhds_within_Icc_eq_nhds_within_Ici a_lt_b, mem_nhds_within_Ici_iff_exists_Icc_subset] - at U_in_nhds_within, - rcases U_in_nhds_within with ⟨ε, ε_in_Ioi, Ioc_in_U⟩, - exact ⟨ε, mem_Ioi.mp ε_in_Ioi, λ y y_in_Ioc, fy_ge_fa y $ Ioc_in_U y_in_Ioc⟩ }, - have a_lt_x : a < x := lt_of_le_of_ne h_ax (λ H, by subst H; exact lt_irrefl (f a) fx_lt_fa), - have lt_on_nhd : ∀ y ∈ Ioc a x, f y < f a, - { intros y y_in_Ioc, - rcases (convex.mem_Ioc a_lt_x).mp y_in_Ioc with ⟨ya, yx, ya_pos, yx_pos, yax, y_combo⟩, - calc - f y = f (ya * a + yx * x) : by rw [y_combo] - ... ≤ ya • f a + yx • f x - : h_conv.2 (left_mem_Icc.mpr (le_of_lt a_lt_b)) ⟨h_ax, h_xb⟩ (ya_pos) - (le_of_lt yx_pos) yax - ... < ya • f a + yx • f a : add_lt_add_left (smul_lt_smul_of_pos fx_lt_fa yx_pos) _ - ... = f a : by rw [←add_smul, yax, one_smul] }, - by_cases h_xz : x ≤ z, - { exact not_lt_of_ge (ge_on_nhd x (show x ∈ Icc a z, by exact ⟨h_ax, h_xz⟩)) fx_lt_fa, }, - { have h₁ : z ∈ Ioc a x := ⟨hz, le_of_not_ge h_xz⟩, - have h₂ : z ∈ Icc a z := ⟨le_of_lt hz, le_refl z⟩, - exact not_lt_of_ge (ge_on_nhd z h₂) (lt_on_nhd z h₁) } + rintro c hc, dsimp only [mem_set_of_eq], + rw [is_local_min_on, nhds_within_Icc_eq_nhds_within_Ici a_lt_b] at h_local_min, + rcases hc.1.eq_or_lt with rfl|a_lt_c, { exact le_rfl }, + have H₁ : ∀ᶠ y in 𝓝[>] a, f a ≤ f y, + from h_local_min.filter_mono (nhds_within_mono _ Ioi_subset_Ici_self), + have H₂ : ∀ᶠ y in 𝓝[>] a, y ∈ Ioc a c, + from Ioc_mem_nhds_within_Ioi (left_mem_Ico.2 a_lt_c), + rcases (H₁.and H₂).exists with ⟨y, hfy, hy_ac⟩, + rcases (convex.mem_Ioc a_lt_c).mp hy_ac with ⟨ya, yc, ya₀, yc₀, yac, rfl⟩, + suffices : ya • f a + yc • f a ≤ ya • f a + yc • f c, + from (smul_le_smul_iff_of_pos yc₀).1 (le_of_add_le_add_left this), + calc ya • f a + yc • f a = f a : by rw [← add_smul, yac, one_smul] + ... ≤ f (ya * a + yc * c) : hfy + ... ≤ ya • f a + yc • f c : h_conv.2 (left_mem_Icc.2 a_lt_b.le) hc ya₀ yc₀.le yac end /-- @@ -61,37 +51,29 @@ A local minimum of a convex function is a global minimum, restricted to a set `s -/ lemma is_min_on.of_is_local_min_on_of_convex_on {f : E → β} {a : E} (a_in_s : a ∈ s) (h_localmin : is_local_min_on f s a) (h_conv : convex_on ℝ s f) : - ∀ x ∈ s, f a ≤ f x := + is_min_on f s a := begin - by_contra' H_cont, - rcases H_cont with ⟨x, ⟨x_in_s, fx_lt_fa⟩⟩, + intros x x_in_s, let g : ℝ →ᵃ[ℝ] E := affine_map.line_map a x, have hg0 : g 0 = a := affine_map.line_map_apply_zero a x, have hg1 : g 1 = x := affine_map.line_map_apply_one a x, - have fg_local_min_on : is_local_min_on (f ∘ g) (g ⁻¹' s) 0, - { rw ←hg0 at h_localmin, - refine is_local_min_on.comp_continuous_on h_localmin subset.rfl - (continuous.continuous_on (affine_map.line_map_continuous)) _, - simp [mem_preimage, hg0, a_in_s] }, - have fg_min_on : ∀ x ∈ (Icc 0 1 : set ℝ), (f ∘ g) 0 ≤ (f ∘ g) x, - { have Icc_in_s' : Icc 0 1 ⊆ (g ⁻¹' s), - { have h0 : (0 : ℝ) ∈ (g ⁻¹' s) := by simp [mem_preimage, a_in_s], - have h1 : (1 : ℝ) ∈ (g ⁻¹' s) := by simp [mem_preimage, hg1, x_in_s], - rw ←segment_eq_Icc (show (0 : ℝ) ≤ 1, by linarith), - exact (convex.affine_preimage g h_conv.1).segment_subset - (by simp [mem_preimage, hg0, a_in_s]) (by simp [mem_preimage, hg1, x_in_s]) }, - have fg_local_min_on' : is_local_min_on (f ∘ g) (Icc 0 1) 0 := - is_local_min_on.on_subset fg_local_min_on Icc_in_s', - refine is_min_on.of_is_local_min_on_of_convex_on_Icc (by linarith) fg_local_min_on' _, - exact (convex_on.comp_affine_map g h_conv).subset Icc_in_s' (convex_Icc 0 1) }, - have gx_lt_ga : (f ∘ g) 1 < (f ∘ g) 0 := by simp [hg1, fx_lt_fa, hg0], - exact not_lt_of_ge (fg_min_on 1 (mem_Icc.mpr ⟨zero_le_one, le_refl 1⟩)) gx_lt_ga, + have hgc : continuous g, from affine_map.line_map_continuous, + have h_maps : maps_to g (Icc 0 1) s, + { simpa only [maps_to', ← segment_eq_image_line_map] + using h_conv.1.segment_subset a_in_s x_in_s }, + have fg_local_min_on : is_local_min_on (f ∘ g) (Icc 0 1) 0, + { rw ← hg0 at h_localmin, + exact h_localmin.comp_continuous_on h_maps hgc.continuous_on (left_mem_Icc.2 zero_le_one) }, + have fg_min_on : is_min_on (f ∘ g) (Icc 0 1 : set ℝ) 0, + { refine is_min_on.of_is_local_min_on_of_convex_on_Icc one_pos fg_local_min_on _, + exact (h_conv.comp_affine_map g).subset h_maps (convex_Icc 0 1) }, + simpa only [hg0, hg1, comp_app, mem_set_of_eq] using fg_min_on (right_mem_Icc.2 zero_le_one) end /-- A local maximum of a concave function is a global maximum, restricted to a set `s`. -/ lemma is_max_on.of_is_local_max_on_of_concave_on {f : E → β} {a : E} (a_in_s : a ∈ s) (h_localmax: is_local_max_on f s a) (h_conc : concave_on ℝ s f) : - ∀ x ∈ s, f x ≤ f a := + is_max_on f s a := @is_min_on.of_is_local_min_on_of_convex_on _ (order_dual β) _ _ _ _ _ _ _ _ s f a a_in_s h_localmax h_conc @@ -99,7 +81,7 @@ lemma is_max_on.of_is_local_max_on_of_concave_on {f : E → β} {a : E} lemma is_min_on.of_is_local_min_of_convex_univ {f : E → β} {a : E} (h_local_min : is_local_min f a) (h_conv : convex_on ℝ univ f) : ∀ x, f a ≤ f x := λ x, (is_min_on.of_is_local_min_on_of_convex_on (mem_univ a) - (is_local_min.on h_local_min univ) h_conv) x (mem_univ x) + (h_local_min.on univ) h_conv) (mem_univ x) /-- A local maximum of a concave function is a global maximum. -/ lemma is_max_on.of_is_local_max_of_convex_univ {f : E → β} {a : E} diff --git a/src/analysis/convex/topology.lean b/src/analysis/convex/topology.lean index a9e66d2a8b9e3..6fd114592ff55 100644 --- a/src/analysis/convex/topology.lean +++ b/src/analysis/convex/topology.lean @@ -234,27 +234,16 @@ lemma convex.closure_subset_interior_image_homothety_of_one_lt {s : set E} (hs : closure s ⊆ interior (homothety x t '' s) := begin intros y hy, - let I := { z | ∃ (u : ℝ), u ∈ Ioc (0 : ℝ) 1 ∧ z = y + u • (x - y) }, - have hI : I ⊆ interior s, - { rintros z ⟨u, hu, rfl⟩, exact hs.add_smul_sub_mem_interior' hy hx hu, }, - let z := homothety x t⁻¹ y, - have hz₁ : z ∈ interior s, - { suffices : z ∈ I, { exact hI this, }, - use 1 - t⁻¹, - split, - { simp only [mem_Ioc, sub_le_self_iff, inv_nonneg, sub_pos, inv_lt_one ht, true_and], - linarith, }, - { simp only [z, homothety_apply, sub_smul, smul_sub, vsub_eq_sub, vadd_eq_add, one_smul], - abel, }, }, - have ht' : t ≠ 0, { linarith, }, - have hz₂ : y = homothety x t z, { simp [z, ht', homothety_apply, smul_smul], }, - rw hz₂, - rw mem_interior at hz₁ ⊢, - obtain ⟨U, hU₁, hU₂, hU₃⟩ := hz₁, - exact ⟨homothety x t '' U, - image_subset ⇑(homothety x t) hU₁, - homothety_is_open_map x t ht' U hU₂, - mem_image_of_mem ⇑(homothety x t) hU₃⟩, + have ht' : 0 < t, from one_pos.trans ht, + obtain ⟨z, rfl⟩ : ∃ z, homothety x t z = y, + from (affine_equiv.homothety_units_mul_hom x (units.mk0 t ht'.ne')).surjective y, + suffices : z ∈ interior s, + from (homothety_is_open_map x t ht'.ne').image_interior_subset _ (mem_image_of_mem _ this), + refine hs.open_segment_interior_closure_subset_interior hx hy _, + rw [open_segment_eq_image_line_map, ← inv_one, ← inv_Ioi (@one_pos ℝ _ _), ← image_inv, + image_image], + use [t, ht], + simp [← homothety_eq_line_map, ← homothety_mul_apply, ht'.ne'] end /-- If we dilate a convex set about a point in its interior by a scale `t > 1`, the interior of diff --git a/src/data/real/cardinality.lean b/src/data/real/cardinality.lean index 5c4631f95f314..98d299ce5232b 100644 --- a/src/data/real/cardinality.lean +++ b/src/data/real/cardinality.lean @@ -213,7 +213,7 @@ begin replace h := sub_pos_of_lt h, have h2 : #(has_inv.inv '' Ioo 0 (b - a)) ≤ #(Ioo 0 (b - a)) := mk_image_le, refine le_trans _ h2, - rw [image_inv_Ioo_0_left h, mk_Ioi_real] + rw [image_inv, inv_Ioo_0_left h, mk_Ioi_real] end /-- The cardinality of the interval [a, b). -/ diff --git a/src/data/set/intervals/image_preimage.lean b/src/data/set/intervals/image_preimage.lean index 8b0632446ae98..414413825f40a 100644 --- a/src/data/set/intervals/image_preimage.lean +++ b/src/data/set/intervals/image_preimage.lean @@ -520,14 +520,16 @@ lemma image_mul_left_Ioo {a : k} (h : 0 < a) (b c : k) : ((*) a) '' Ioo b c = Ioo (a * b) (a * c) := by { convert image_mul_right_Ioo b c h using 1; simp only [mul_comm _ a] } -/-- The image under `inv` of `Ioo 0 a` is `Ioi a⁻¹`. -/ -lemma image_inv_Ioo_0_left {a : k} (ha : 0 < a) : has_inv.inv '' Ioo 0 a = Ioi a⁻¹ := +/-- The (pre)image under `inv` of `Ioo 0 a` is `Ioi a⁻¹`. -/ +lemma inv_Ioo_0_left {a : k} (ha : 0 < a) : (Ioo 0 a)⁻¹ = Ioi a⁻¹ := begin ext x, - exact ⟨λ ⟨y, ⟨hy0, hya⟩, hyx⟩, hyx ▸ (inv_lt_inv ha hy0).2 hya, λ h, ⟨x⁻¹, ⟨inv_pos.2 (lt_trans - (inv_pos.2 ha) h), (inv_lt ha (lt_trans (inv_pos.2 ha) h)).1 h⟩, inv_inv x⟩⟩, + exact ⟨λ h, inv_inv x ▸ (inv_lt_inv ha h.1).2 h.2, λ h, ⟨inv_pos.2 $ (inv_pos.2 ha).trans h, + inv_inv a ▸ (inv_lt_inv ((inv_pos.2 ha).trans h) (inv_pos.2 ha)).2 h⟩⟩, end +lemma inv_Ioi {a : k} (ha : 0 < a) : (Ioi a)⁻¹ = Ioo 0 a⁻¹ := +by rw [inv_eq_iff_inv_eq, inv_Ioo_0_left (inv_pos.2 ha), inv_inv] /-! ### Images under `x ↦ a * x + b` diff --git a/src/linear_algebra/affine_space/affine_map.lean b/src/linear_algebra/affine_space/affine_map.lean index d6832293c8233..7190f5c99b37f 100644 --- a/src/linear_algebra/affine_space/affine_map.lean +++ b/src/linear_algebra/affine_space/affine_map.lean @@ -589,9 +589,13 @@ by { ext p, simp [homothety_apply] } @[simp] lemma homothety_apply_same (c : P1) (r : k) : homothety c r c = c := line_map_same_apply c r +lemma homothety_mul_apply (c : P1) (r₁ r₂ : k) (p : P1) : + homothety c (r₁ * r₂) p = homothety c r₁ (homothety c r₂ p) := +by simp [homothety_apply, mul_smul] + lemma homothety_mul (c : P1) (r₁ r₂ : k) : homothety c (r₁ * r₂) = (homothety c r₁).comp (homothety c r₂) := -by { ext p, simp [homothety_apply, mul_smul] } +ext $ homothety_mul_apply c r₁ r₂ @[simp] lemma homothety_zero (c : P1) : homothety c (0:k) = const k P1 c := by { ext p, simp [homothety_apply] } From 279b7f34a1615f73b601c44fd789ba4c9949850e Mon Sep 17 00:00:00 2001 From: leanprover-community-bot Date: Mon, 18 Apr 2022 03:41:36 +0000 Subject: [PATCH 061/373] chore(scripts): update nolints.txt (#13493) I am happy to remove some nolints for you! --- scripts/nolints.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/nolints.txt b/scripts/nolints.txt index a8b59ac13d68a..005c60d46d055 100644 --- a/scripts/nolints.txt +++ b/scripts/nolints.txt @@ -1,6 +1,11 @@ import .all run_cmd tactic.skip +-- algebra/big_operators/fin.lean +apply_nolint fin.prod_univ_cast_succ to_additive_doc +apply_nolint fin.prod_univ_succ to_additive_doc +apply_nolint fin.prod_univ_succ_above to_additive_doc + -- algebra/category/Group/limits.lean apply_nolint CommGroup.category_theory.forget₂.category_theory.creates_limit to_additive_doc apply_nolint CommGroup.forget_preserves_limits to_additive_doc @@ -213,10 +218,7 @@ apply_nolint locally_finite.realizer doc_blame has_inhabited_instance apply_nolint finset.noncomm_prod_union_of_disjoint to_additive_doc -- data/fintype/card.lean -apply_nolint fin.prod_univ_cast_succ to_additive_doc apply_nolint fin.prod_univ_eq_prod_range to_additive_doc -apply_nolint fin.prod_univ_succ to_additive_doc -apply_nolint fin.prod_univ_succ_above to_additive_doc -- data/fp/basic.lean apply_nolint fp.div_nat_lt_two_pow doc_blame unused_arguments From 82348a6001b51b8622adafb1c68094038a686352 Mon Sep 17 00:00:00 2001 From: Bolton Bailey Date: Mon, 18 Apr 2022 05:37:15 +0000 Subject: [PATCH 062/373] feat(computability/partrec_code): add eval prec helpers (#11945) A few helpers to clarify the definition of `eval`. --- src/computability/partrec_code.lean | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/computability/partrec_code.lean b/src/computability/partrec_code.lean index 77313ddd5bf75..71d8e9d285f3a 100644 --- a/src/computability/partrec_code.lean +++ b/src/computability/partrec_code.lean @@ -555,6 +555,19 @@ def eval : code → ℕ →. ℕ (nat.rfind (λ n, (λ m, m = 0) <$> eval cf (mkpair a (n + m)))).map (+ m)) +/-- Helper lemma for the evaluation of `prec` in the base case. -/ +@[simp] lemma eval_prec_zero (cf cg : code) (a : ℕ) : eval (prec cf cg) (mkpair a 0) = eval cf a := +by rw [eval, nat.unpaired, nat.unpair_mkpair, nat.elim_zero] + +/-- Helper lemma for the evaluation of `prec` in the recursive case. -/ +lemma eval_prec_succ (cf cg : code) (a k : ℕ) : + eval (prec cf cg) (mkpair a (nat.succ k)) = + do ih <- eval (prec cf cg) (mkpair a k), eval cg (mkpair a (mkpair k ih)) := +begin + rw [eval, nat.unpaired, part.bind_eq_bind, nat.unpair_mkpair, nat.elim_succ], + simp, +end + instance : has_mem (ℕ →. ℕ) code := ⟨λ f c, eval c = f⟩ @[simp] theorem eval_const : ∀ n m, eval (code.const n) m = part.some n From e18ea79e7ceca20d686217d6b28cfdda6c56363b Mon Sep 17 00:00:00 2001 From: MichaelStollBayreuth Date: Mon, 18 Apr 2022 10:31:05 +0000 Subject: [PATCH 063/373] =?UTF-8?q?feat(number=5Ftheory/legendre=5Fsymbol/?= =?UTF-8?q?quadratic=5Freciprocity):=20replace=20`[fact=20(p=20%=202=20=3D?= =?UTF-8?q?=201)]`=20arguments=20by=20`(p=20=E2=89=A0=202)`=20(#13474)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes implicit arguments of the form `[fact (p % 2 = 1)]` and replaces them by explicit arguments `(hp : p ≠ 2)`. (See the short discussion on April 9 in [this topic](https://leanprover.zulipchat.com/#narrow/stream/116395-maths/topic/Quadratic.20Hilbert.20symbol.20over.20.E2.84.9A).) --- src/data/nat/prime.lean | 8 +++ .../quadratic_reciprocity.lean | 49 ++++++++++--------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/data/nat/prime.lean b/src/data/nat/prime.lean index c927accbf2353..6800c71ac9186 100644 --- a/src/data/nat/prime.lean +++ b/src/data/nat/prime.lean @@ -429,6 +429,14 @@ p.mod_two_eq_zero_or_one.imp_left lemma prime.eq_two_or_odd' {p : ℕ} (hp : prime p) : p = 2 ∨ odd p := or.imp_right (λ h, ⟨p / 2, (div_add_mod p 2).symm.trans (congr_arg _ h)⟩) hp.eq_two_or_odd +/-- A prime `p` satisfies `p % 2 = 1` if and only if `p ≠ 2`. -/ +lemma prime.mod_two_eq_one_iff_ne_two {p : ℕ} [fact p.prime] : p % 2 = 1 ↔ p ≠ 2 := +begin + refine ⟨λ h hf, _, (nat.prime.eq_two_or_odd $ fact.out p.prime).resolve_left⟩, + rw hf at h, + simpa using h, +end + theorem coprime_of_dvd {m n : ℕ} (H : ∀ k, prime k → k ∣ m → ¬ k ∣ n) : coprime m n := begin rw [coprime_iff_gcd_eq_one], diff --git a/src/number_theory/legendre_symbol/quadratic_reciprocity.lean b/src/number_theory/legendre_symbol/quadratic_reciprocity.lean index b2efdd48393c9..6466075dc6dba 100644 --- a/src/number_theory/legendre_symbol/quadratic_reciprocity.lean +++ b/src/number_theory/legendre_symbol/quadratic_reciprocity.lean @@ -156,13 +156,14 @@ end /-- Gauss' lemma. The legendre symbol can be computed by considering the number of naturals less than `p/2` such that `(a * x) % p > p / 2` -/ -lemma gauss_lemma {a : ℤ} [fact (p % 2 = 1)] (ha0 : (a : zmod p) ≠ 0) : +lemma gauss_lemma {a : ℤ} (hp : p ≠ 2) (ha0 : (a : zmod p) ≠ 0) : legendre_sym p a = (-1) ^ ((Ico 1 (p / 2).succ).filter (λ x : ℕ, p / 2 < (a * x : zmod p).val)).card := -have (legendre_sym p a : zmod p) = (((-1)^((Ico 1 (p / 2).succ).filter - (λ x : ℕ, p / 2 < (a * x : zmod p).val)).card : ℤ) : zmod p), - by rw [legendre_sym_eq_pow, legendre_symbol.gauss_lemma_aux p ha0]; simp, begin + haveI hp' : fact (p % 2 = 1) := ⟨nat.prime.mod_two_eq_one_iff_ne_two.mpr hp⟩, + have : (legendre_sym p a : zmod p) = (((-1)^((Ico 1 (p / 2).succ).filter + (λ x : ℕ, p / 2 < (a * x : zmod p).val)).card : ℤ) : zmod p) := + by { rw [legendre_sym_eq_pow, legendre_symbol.gauss_lemma_aux p ha0]; simp }, cases legendre_sym_eq_one_or_neg_one p a ha0; cases neg_one_pow_eq_or ℤ ((Ico 1 (p / 2).succ).filter (λ x : ℕ, p / 2 < (a * x : zmod p).val)).card; @@ -178,26 +179,28 @@ begin { simp only [h, iff_false], tauto } end -lemma eisenstein_lemma [fact (p % 2 = 1)] {a : ℕ} (ha1 : a % 2 = 1) (ha0 : (a : zmod p) ≠ 0) : +lemma eisenstein_lemma (hp : p ≠ 2) {a : ℕ} (ha1 : a % 2 = 1) (ha0 : (a : zmod p) ≠ 0) : legendre_sym p a = (-1)^∑ x in Ico 1 (p / 2).succ, (x * a) / p := begin + haveI hp' : fact (p % 2 = 1) := ⟨nat.prime.mod_two_eq_one_iff_ne_two.mpr hp⟩, have ha0' : ((a : ℤ) : zmod p) ≠ 0 := by { norm_cast, exact ha0 }, - rw [neg_one_pow_eq_pow_mod_two, gauss_lemma p ha0', neg_one_pow_eq_pow_mod_two, + rw [neg_one_pow_eq_pow_mod_two, gauss_lemma p hp ha0', neg_one_pow_eq_pow_mod_two, (by norm_cast : ((a : ℤ) : zmod p) = (a : zmod p)), show _ = _, from legendre_symbol.eisenstein_lemma_aux p ha1 ha0] end /-- **Quadratic reciprocity theorem** -/ -theorem quadratic_reciprocity [hp1 : fact (p % 2 = 1)] [hq1 : fact (q % 2 = 1)] (hpq : p ≠ q) : +theorem quadratic_reciprocity (hp1 : p ≠ 2) (hq1 : q ≠ 2) (hpq : p ≠ q) : legendre_sym q p * legendre_sym p q = (-1) ^ ((p / 2) * (q / 2)) := have hpq0 : (p : zmod q) ≠ 0, from prime_ne_zero q p hpq.symm, have hqp0 : (q : zmod p) ≠ 0, from prime_ne_zero p q hpq, -by rw [eisenstein_lemma q hp1.1 hpq0, eisenstein_lemma p hq1.1 hqp0, +by rw [eisenstein_lemma q hq1 (nat.prime.mod_two_eq_one_iff_ne_two.mpr hp1) hpq0, + eisenstein_lemma p hp1 (nat.prime.mod_two_eq_one_iff_ne_two.mpr hq1) hqp0, ← pow_add, legendre_symbol.sum_mul_div_add_sum_mul_div_eq_mul q p hpq0, mul_comm] -lemma legendre_sym_two [hp1 : fact (p % 2 = 1)] : legendre_sym p 2 = (-1) ^ (p / 4 + p / 2) := +lemma legendre_sym_two (hp2 : p ≠ 2) : legendre_sym p 2 = (-1) ^ (p / 4 + p / 2) := begin - have hp2 : p ≠ 2, from mt (congr_arg (% 2)) (by simpa using hp1.1), + have hp1 := nat.prime.mod_two_eq_one_iff_ne_two.mpr hp2, have hp22 : p / 2 / 2 = _ := legendre_symbol.div_eq_filter_card (show 0 < 2, from dec_trivial) (nat.div_le_self (p / 2) 2), have hcard : (Ico 1 (p / 2).succ).card = p / 2, by simp, @@ -205,7 +208,7 @@ begin from λ x hx, have h2xp : 2 * x < p, from calc 2 * x ≤ 2 * (p / 2) : mul_le_mul_of_nonneg_left (le_of_lt_succ $ (mem_Ico.mp hx).2) dec_trivial - ... < _ : by conv_rhs {rw [← div_add_mod p 2, hp1.1]}; exact lt_succ_self _, + ... < _ : by conv_rhs {rw [← div_add_mod p 2, hp1]}; exact lt_succ_self _, by rw [← nat.cast_two, ← nat.cast_mul, val_cast_of_lt h2xp], have hdisj : disjoint ((Ico 1 (p / 2).succ).filter (λ x, p / 2 < ((2 : ℕ) * x : zmod p).val)) @@ -222,7 +225,7 @@ begin end, have hp2' := prime_ne_zero p 2 hp2, rw (by norm_cast : ((2 : ℕ) : zmod p) = (2 : ℤ)) at *, - erw [gauss_lemma p hp2', + erw [gauss_lemma p hp2 hp2', neg_one_pow_eq_pow_mod_two, @neg_one_pow_eq_pow_mod_two _ _ (p / 4 + p / 2)], refine congr_arg2 _ rfl ((eq_iff_modeq_nat 2).1 _), rw [show 4 = 2 * 2, from rfl, ← nat.div_div_eq_div_mul, hp22, nat.cast_add, @@ -230,25 +233,25 @@ begin ← nat.cast_add, ← card_disjoint_union hdisj, hunion, hcard] end -lemma exists_sq_eq_two_iff [hp1 : fact (p % 2 = 1)] : +lemma exists_sq_eq_two_iff (hp1 : p ≠ 2) : (∃ a : zmod p, a ^ 2 = 2) ↔ p % 8 = 1 ∨ p % 8 = 7 := have hp2 : ((2 : ℤ) : zmod p) ≠ 0, - from prime_ne_zero p 2 (λ h, by simpa [h] using hp1.1), + from prime_ne_zero p 2 (λ h, by simpa [h] using hp1), have hpm4 : p % 4 = p % 8 % 4, from (nat.mod_mul_left_mod p 2 4).symm, have hpm2 : p % 2 = p % 8 % 2, from (nat.mod_mul_left_mod p 4 2).symm, begin rw [show (2 : zmod p) = (2 : ℤ), by simp, ← legendre_sym_eq_one_iff p hp2], - erw [legendre_sym_two p, neg_one_pow_eq_one_iff_even (show (-1 : ℤ) ≠ 1, from dec_trivial), + erw [legendre_sym_two p hp1, neg_one_pow_eq_one_iff_even (show (-1 : ℤ) ≠ 1, from dec_trivial), even_add, even_div, even_div], have := nat.mod_lt p (show 0 < 8, from dec_trivial), - resetI, rw fact_iff at hp1, - revert this hp1, + have hp := nat.prime.mod_two_eq_one_iff_ne_two.mpr hp1, + revert this hp, erw [hpm4, hpm2], generalize hm : p % 8 = m, unfreezingI {clear_dependent p}, dec_trivial!, end -lemma exists_sq_eq_prime_iff_of_mod_four_eq_one (hp1 : p % 4 = 1) [hq1 : fact (q % 2 = 1)] : +lemma exists_sq_eq_prime_iff_of_mod_four_eq_one (hp1 : p % 4 = 1) (hq1 : q ≠ 2) : (∃ a : zmod p, a ^ 2 = q) ↔ ∃ b : zmod q, b ^ 2 = p := if hpq : p = q then by substI hpq else have h1 : ((p / 2) * (q / 2)) % 2 = 0, @@ -256,10 +259,10 @@ have h1 : ((p / 2) * (q / 2)) % 2 = 0, (dvd_mul_of_dvd_left ((dvd_iff_mod_eq_zero _ _).2 $ by rw [← mod_mul_right_div_self, show 2 * 2 = 4, from rfl, hp1]; refl) _), begin - haveI hp_odd : fact (p % 2 = 1) := ⟨odd_of_mod_four_eq_one hp1⟩, + have hp_odd : p ≠ 2 := by { by_contra, simp [h] at hp1, norm_num at hp1, }, have hpq0 : (p : zmod q) ≠ 0 := prime_ne_zero q p (ne.symm hpq), have hqp0 : (q : zmod p) ≠ 0 := prime_ne_zero p q hpq, - have := quadratic_reciprocity p q hpq, + have := quadratic_reciprocity p q hp_odd hq1 hpq, rw [neg_one_pow_eq_pow_mod_two, h1, legendre_sym, legendre_sym, int.cast_coe_nat, int.cast_coe_nat, if_neg hqp0, if_neg hpq0] at this, rw [euler_criterion q hpq0, euler_criterion p hqp0], @@ -273,11 +276,11 @@ have h1 : ((p / 2) * (q / 2)) % 2 = 1, (by rw [← mod_mul_right_div_self, show 2 * 2 = 4, from rfl, hp3]; refl) (by rw [← mod_mul_right_div_self, show 2 * 2 = 4, from rfl, hq3]; refl), begin - haveI hp_odd : fact (p % 2 = 1) := ⟨odd_of_mod_four_eq_three hp3⟩, - haveI hq_odd : fact (q % 2 = 1) := ⟨odd_of_mod_four_eq_three hq3⟩, + have hp_odd : p ≠ 2 := by { by_contra, simp [h] at hp3, norm_num at hp3, }, + have hq_odd : q ≠ 2 := by { by_contra, simp [h] at hq3, norm_num at hq3, }, have hpq0 : (p : zmod q) ≠ 0 := prime_ne_zero q p (ne.symm hpq), have hqp0 : (q : zmod p) ≠ 0 := prime_ne_zero p q hpq, - have := quadratic_reciprocity p q hpq, + have := quadratic_reciprocity p q hp_odd hq_odd hpq, rw [neg_one_pow_eq_pow_mod_two, h1, legendre_sym, legendre_sym, int.cast_coe_nat, int.cast_coe_nat, if_neg hpq0, if_neg hqp0] at this, rw [euler_criterion q hpq0, euler_criterion p hqp0], From d790b4b8b957f782577f86d9f2bc7ae10cbb8d47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Mon, 18 Apr 2022 15:45:35 +0000 Subject: [PATCH 064/373] feat(set_theory/cardinal): `lt_omega_of_fintype` (#13365) --- archive/100-theorems-list/82_cubing_a_cube.lean | 2 +- src/data/W/cardinal.lean | 2 +- src/data/mv_polynomial/cardinal.lean | 7 ++----- src/data/polynomial/cardinal.lean | 5 +---- src/field_theory/is_alg_closed/classification.lean | 4 ++-- src/linear_algebra/finsupp_vector_space.lean | 2 +- src/set_theory/cardinal.lean | 3 +++ 7 files changed, 11 insertions(+), 14 deletions(-) diff --git a/archive/100-theorems-list/82_cubing_a_cube.lean b/archive/100-theorems-list/82_cubing_a_cube.lean index 997285fe2bc91..f2a69654f255c 100644 --- a/archive/100-theorems-list/82_cubing_a_cube.lean +++ b/archive/100-theorems-list/82_cubing_a_cube.lean @@ -509,7 +509,7 @@ omit h /-- The infinite sequence of cubes contradicts the finiteness of the family. -/ theorem not_correct : ¬correct cs := begin - intro h, apply not_le_of_lt (lt_omega_iff_fintype.mpr ⟨_inst_1⟩), + intro h, apply (lt_omega_of_fintype ι).not_le, rw [omega, lift_id], fapply mk_le_of_injective, exact λ n, (sequence_of_cubes h n).1, intros n m hnm, apply strict_mono.injective (strict_mono_sequence_of_cubes h), dsimp only [decreasing_sequence], rw hnm diff --git a/src/data/W/cardinal.lean b/src/data/W/cardinal.lean index aa19146d8d594..27a122490cf91 100644 --- a/src/data/W/cardinal.lean +++ b/src/data/W/cardinal.lean @@ -69,7 +69,7 @@ calc cardinal.sum (λ a : α, m ^ #(β a)) mul_le_mul' (le_max_left _ _) le_rfl ... = m : mul_eq_left.{u} (le_max_right _ _) (cardinal.sup_le (λ i, begin - cases lt_omega.1 (lt_omega_iff_fintype.2 ⟨show fintype (β i), by apply_instance⟩) with n hn, + cases lt_omega.1 (lt_omega_of_fintype (β i)) with n hn, rw [hn], exact power_nat_le (le_max_right _ _) end)) diff --git a/src/data/mv_polynomial/cardinal.lean b/src/data/mv_polynomial/cardinal.lean index 3407ce37f2a64..d923f8ba7c137 100644 --- a/src/data/mv_polynomial/cardinal.lean +++ b/src/data/mv_polynomial/cardinal.lean @@ -84,11 +84,8 @@ calc #(mv_polynomial_fun σ R) = #R + #σ + #(ulift bool) : ... ≤ max (max (#R + #σ) (#(ulift bool))) ω : add_le_max _ _ ... ≤ max (max (max (max (#R) (#σ)) ω) (#(ulift bool))) ω : max_le_max (max_le_max (add_le_max _ _) le_rfl) le_rfl -... ≤ _ : begin - have : #(ulift.{u} bool) ≤ ω, - from le_of_lt (lt_omega_iff_fintype.2 ⟨infer_instance⟩), - simp only [max_comm omega.{u}, max_assoc, max_left_comm omega.{u}, max_self, max_eq_left this], -end +... ≤ _ : by simp only [max_comm omega.{u}, max_assoc, max_left_comm omega.{u}, max_self, + max_eq_left (lt_omega_of_fintype (ulift.{u} bool)).le] namespace mv_polynomial diff --git a/src/data/polynomial/cardinal.lean b/src/data/polynomial/cardinal.lean index 97aa71399a4c9..25880dfa7c6ed 100644 --- a/src/data/polynomial/cardinal.lean +++ b/src/data/polynomial/cardinal.lean @@ -22,9 +22,6 @@ lemma cardinal_mk_le_max {R : Type u} [comm_semiring R] : #R[X] ≤ max (#R) ω calc #R[X] = #(mv_polynomial punit.{u + 1} R) : cardinal.eq.2 ⟨(mv_polynomial.punit_alg_equiv.{u u} R).to_equiv.symm⟩ ... ≤ _ : mv_polynomial.cardinal_mk_le_max -... ≤ _ : begin - have : #(punit.{u + 1}) ≤ ω, from le_of_lt (lt_omega_iff_fintype.2 ⟨infer_instance⟩), - rw [max_assoc, max_eq_right this] -end +... ≤ _ : by rw [max_assoc, max_eq_right (lt_omega_of_fintype punit).le] end polynomial diff --git a/src/field_theory/is_alg_closed/classification.lean b/src/field_theory/is_alg_closed/classification.lean index 591ce21e18420..0480bdd8de3b3 100644 --- a/src/field_theory/is_alg_closed/classification.lean +++ b/src/field_theory/is_alg_closed/classification.lean @@ -192,9 +192,9 @@ begin from ring_hom.injective _) with t ht, have : #s = #t, { rw [← cardinal_eq_cardinal_transcendence_basis_of_omega_lt _ hs - (le_of_lt $ lt_omega_iff_fintype.2 ⟨infer_instance⟩) hK, + (lt_omega_of_fintype (zmod p)).le hK, ← cardinal_eq_cardinal_transcendence_basis_of_omega_lt _ ht - (le_of_lt $ lt_omega_iff_fintype.2 ⟨infer_instance⟩), hKL], + (lt_omega_of_fintype (zmod p)).le, hKL], rwa ← hKL }, cases cardinal.eq.1 this with e, exact ⟨equiv_of_transcendence_basis _ _ e hs ht⟩ diff --git a/src/linear_algebra/finsupp_vector_space.lean b/src/linear_algebra/finsupp_vector_space.lean index aa3d5c6dbf60e..4e820134ef5ea 100644 --- a/src/linear_algebra/finsupp_vector_space.lean +++ b/src/linear_algebra/finsupp_vector_space.lean @@ -199,7 +199,7 @@ lemma cardinal_lt_omega_of_finite_dimensional [fintype K] [finite_dimensional K begin letI : is_noetherian K V := is_noetherian.iff_fg.2 infer_instance, rw cardinal_mk_eq_cardinal_mk_field_pow_dim K V, - exact cardinal.power_lt_omega (cardinal.lt_omega_iff_fintype.2 ⟨infer_instance⟩) + exact cardinal.power_lt_omega (cardinal.lt_omega_of_fintype K) (is_noetherian.dim_lt_omega K V), end diff --git a/src/set_theory/cardinal.lean b/src/set_theory/cardinal.lean index 5f2d0a132f3de..45baab238be8d 100644 --- a/src/set_theory/cardinal.lean +++ b/src/set_theory/cardinal.lean @@ -918,6 +918,9 @@ lt_omega.trans ⟨λ ⟨n, e⟩, begin exact ⟨fintype.of_equiv _ f.symm⟩ end, λ ⟨_⟩, by exactI ⟨_, mk_fintype _⟩⟩ +theorem lt_omega_of_fintype (α : Type u) [fintype α] : #α < ω := +lt_omega_iff_fintype.2 ⟨infer_instance⟩ + theorem lt_omega_iff_finite {α} {S : set α} : #S < ω ↔ finite S := lt_omega_iff_fintype.trans finite_def.symm From 546618eb1b4409f73d4d5149400bd51149e4bfae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Mon, 18 Apr 2022 17:14:05 +0000 Subject: [PATCH 065/373] feat(order/upper_lower): Principal upper/lower sets (#13069) Define `upper_set.Ici` and `lower_set.Iic`. Also add membership lemmas for the lattice operations. --- src/data/set/lattice.lean | 19 +++++ src/order/upper_lower.lean | 167 ++++++++++++++++++++++++++++++++++++- 2 files changed, 182 insertions(+), 4 deletions(-) diff --git a/src/data/set/lattice.lean b/src/data/set/lattice.lean index 8808f5ce0beab..a97b5621ddd5a 100644 --- a/src/data/set/lattice.lean +++ b/src/data/set/lattice.lean @@ -1588,6 +1588,25 @@ end set end disjoint +/-! ### Intervals -/ + +namespace set +variables [complete_lattice α] + +lemma Ici_supr (f : ι → α) : Ici (⨆ i, f i) = ⋂ i, Ici (f i) := +ext $ λ _, by simp only [mem_Ici, supr_le_iff, mem_Inter] + +lemma Iic_infi (f : ι → α) : Iic (⨅ i, f i) = ⋂ i, Iic (f i) := +ext $ λ _, by simp only [mem_Iic, le_infi_iff, mem_Inter] + +lemma Ici_supr₂ (f : Π i, κ i → α) : Ici (⨆ i j, f i j) = ⋂ i j, Ici (f i j) := by simp_rw Ici_supr +lemma Iic_infi₂ (f : Π i, κ i → α) : Iic (⨅ i j, f i j) = ⋂ i j, Iic (f i j) := by simp_rw Iic_infi + +lemma Ici_Sup (s : set α) : Ici (Sup s) = ⋂ a ∈ s, Ici a := by rw [Sup_eq_supr, Ici_supr₂] +lemma Iic_Inf (s : set α) : Iic (Inf s) = ⋂ a ∈ s, Iic a := by rw [Inf_eq_infi, Iic_infi₂] + +end set + namespace set variables (t : α → set β) diff --git a/src/order/upper_lower.lean b/src/order/upper_lower.lean index 216e35dcb0e2c..18ca128ad0824 100644 --- a/src/order/upper_lower.lean +++ b/src/order/upper_lower.lean @@ -3,8 +3,8 @@ Copyright (c) 2022 Yaël Dillies, Sara Rousta. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies, Sara Rousta -/ -import data.set.lattice import data.set_like.basic +import order.hom.complete_lattice /-! # Up-sets and down-sets @@ -19,6 +19,10 @@ This file defines upper and lower sets in an order. of the set is in the set itself. * `upper_set`: The type of upper sets. * `lower_set`: The type of lower sets. +* `upper_set.Ici`: Principal upper set. `set.Ici` as an upper set. +* `upper_set.Ioi`: Strict principal upper set. `set.Ioi` as an upper set. +* `lower_set.Iic`: Principal lower set. `set.Iic` as an lower set. +* `lower_set.Iio`: Strict principal lower set. `set.Iio` as an lower set. ## TODO @@ -27,11 +31,11 @@ Lattice structure on antichains. Order equivalence between upper/lower sets and open order_dual set -variables {ι : Sort*} {κ : ι → Sort*} {α : Type*} +variables {α : Type*} {ι : Sort*} {κ : ι → Sort*} /-! ### Unbundled upper/lower sets -/ -section unbundled +section has_le variables [has_le α] {s t : set α} /-- An upper set in an order `α` is a set such that any element greater than one of its members is @@ -115,7 +119,17 @@ alias is_upper_set_preimage_of_dual_iff ↔ _ is_lower_set.of_dual alias is_lower_set_preimage_to_dual_iff ↔ _ is_upper_set.to_dual alias is_upper_set_preimage_to_dual_iff ↔ _ is_lower_set.to_dual -end unbundled +end has_le + +section preorder +variables [preorder α] (a : α) + +lemma is_upper_set_Ici : is_upper_set (Ici a) := λ _ _, ge_trans +lemma is_lower_set_Iic : is_lower_set (Iic a) := λ _ _, le_trans +lemma is_upper_set_Ioi : is_upper_set (Ioi a) := λ _ _, flip lt_of_lt_of_le +lemma is_lower_set_Iio : is_lower_set (Iio a) := λ _ _, lt_of_le_of_lt + +end preorder /-! ### Bundled upper/lower sets -/ @@ -193,6 +207,21 @@ by simp_rw coe_supr @[simp] lemma coe_infi₂ (f : Π i, κ i → upper_set α) : (↑(⨅ i j, f i j) : set α) = ⋂ i j, f i j := by simp_rw coe_infi +@[simp] lemma mem_top : a ∈ (⊤ : upper_set α) := trivial +@[simp] lemma not_mem_bot : a ∉ (⊥ : upper_set α) := id +@[simp] lemma mem_sup_iff : a ∈ s ⊔ t ↔ a ∈ s ∨ a ∈ t := iff.rfl +@[simp] lemma mem_inf_iff : a ∈ s ⊓ t ↔ a ∈ s ∧ a ∈ t := iff.rfl +@[simp] lemma mem_Sup_iff : a ∈ Sup S ↔ ∃ s ∈ S, a ∈ s := mem_Union₂ +@[simp] lemma mem_Inf_iff : a ∈ Inf S ↔ ∀ s ∈ S, a ∈ s := mem_Inter₂ +@[simp] lemma mem_supr_iff {f : ι → upper_set α} : a ∈ (⨆ i, f i) ↔ ∃ i, a ∈ f i := +by { rw [←set_like.mem_coe, coe_supr], exact mem_Union } +@[simp] lemma mem_infi_iff {f : ι → upper_set α} : a ∈ (⨅ i, f i) ↔ ∀ i, a ∈ f i := +by { rw [←set_like.mem_coe, coe_infi], exact mem_Inter } +@[simp] lemma mem_supr₂_iff {f : Π i, κ i → upper_set α} : a ∈ (⨆ i j, f i j) ↔ ∃ i j, a ∈ f i j := +by simp_rw mem_supr_iff +@[simp] lemma mem_infi₂_iff {f : Π i, κ i → upper_set α} : a ∈ (⨅ i j, f i j) ↔ ∀ i j, a ∈ f i j := +by simp_rw mem_infi_iff + end upper_set namespace lower_set @@ -226,6 +255,21 @@ by simp_rw coe_supr @[simp] lemma coe_infi₂ (f : Π i, κ i → lower_set α) : (↑(⨅ i j, f i j) : set α) = ⋂ i j, f i j := by simp_rw coe_infi +@[simp] lemma mem_top : a ∈ (⊤ : lower_set α) := trivial +@[simp] lemma not_mem_bot : a ∉ (⊥ : lower_set α) := id +@[simp] lemma mem_sup_iff : a ∈ s ⊔ t ↔ a ∈ s ∨ a ∈ t := iff.rfl +@[simp] lemma mem_inf_iff : a ∈ s ⊓ t ↔ a ∈ s ∧ a ∈ t := iff.rfl +@[simp] lemma mem_Sup_iff : a ∈ Sup S ↔ ∃ s ∈ S, a ∈ s := mem_Union₂ +@[simp] lemma mem_Inf_iff : a ∈ Inf S ↔ ∀ s ∈ S, a ∈ s := mem_Inter₂ +@[simp] lemma mem_supr_iff {f : ι → lower_set α} : a ∈ (⨆ i, f i) ↔ ∃ i, a ∈ f i := +by { rw [←set_like.mem_coe, coe_supr], exact mem_Union } +@[simp] lemma mem_infi_iff {f : ι → lower_set α} : a ∈ (⨅ i, f i) ↔ ∀ i, a ∈ f i := +by { rw [←set_like.mem_coe, coe_infi], exact mem_Inter } +@[simp] lemma mem_supr₂_iff {f : Π i, κ i → lower_set α} : a ∈ (⨆ i j, f i j) ↔ ∃ i j, a ∈ f i j := +by simp_rw mem_supr_iff +@[simp] lemma mem_infi₂_iff {f : Π i, κ i → lower_set α} : a ∈ (⨅ i j, f i j) ↔ ∀ i j, a ∈ f i j := +by simp_rw mem_infi_iff + end lower_set /-! #### Complement -/ @@ -308,3 +352,118 @@ by simp_rw lower_set.compl_infi end lower_set end has_le + +/-! #### Principal sets -/ + +namespace upper_set +section preorder +variables [preorder α] {a b : α} + +/-- The smallest upper set containing a given element. -/ +def Ici (a : α) : upper_set α := ⟨Ici a, is_upper_set_Ici a⟩ + +/-- The smallest upper set containing a given element. -/ +def Ioi (a : α) : upper_set α := ⟨Ioi a, is_upper_set_Ioi a⟩ + +@[simp] lemma coe_Ici (a : α) : ↑(Ici a) = set.Ici a := rfl +@[simp] lemma coe_Ioi (a : α) : ↑(Ioi a) = set.Ioi a := rfl +@[simp] lemma mem_Ici_iff : b ∈ Ici a ↔ a ≤ b := iff.rfl +@[simp] lemma mem_Ioi_iff : b ∈ Ioi a ↔ a < b := iff.rfl + +lemma Ioi_le_Ici (a : α) : Ioi a ≤ Ici a := Ioi_subset_Ici_self + +@[simp] lemma Ici_top [order_bot α] : Ici (⊥ : α) = ⊤ := set_like.coe_injective Ici_bot +@[simp] lemma Ioi_bot [order_top α] : Ioi (⊤ : α) = ⊥ := set_like.coe_injective Ioi_top + +end preorder + +section semilattice_sup +variables [semilattice_sup α] + +@[simp] lemma Ici_sup (a b : α) : Ici (a ⊔ b) = Ici a ⊓ Ici b := ext Ici_inter_Ici.symm + +/-- `upper_set.Ici` as a `sup_hom`. -/ +def Ici_sup_hom : sup_hom α (order_dual $ upper_set α) := ⟨Ici, Ici_sup⟩ + +@[simp] lemma Ici_sup_hom_apply (a : α) : Ici_sup_hom a = to_dual (Ici a) := rfl + +end semilattice_sup + +section complete_lattice +variables [complete_lattice α] + +@[simp] lemma Ici_Sup (S : set α) : Ici (Sup S) = ⨅ a ∈ S, Ici a := +set_like.ext $ λ c, by simp only [mem_Ici_iff, mem_infi_iff, Sup_le_iff] + +@[simp] lemma Ici_supr (f : ι → α) : Ici (⨆ i, f i) = ⨅ i, Ici (f i) := +set_like.ext $ λ c, by simp only [mem_Ici_iff, mem_infi_iff, supr_le_iff] + +@[simp] lemma Ici_supr₂ (f : Π i, κ i → α) : Ici (⨆ i j, f i j) = ⨅ i j, Ici (f i j) := +by simp_rw Ici_supr + +/-- `upper_set.Ici` as a `Sup_hom`. -/ +def Ici_Sup_hom : Sup_hom α (order_dual $ upper_set α) := +⟨Ici, λ s, (Ici_Sup s).trans Inf_image.symm⟩ + +@[simp] lemma Ici_Sup_hom_apply (a : α) : Ici_Sup_hom a = to_dual (Ici a) := rfl + +end complete_lattice +end upper_set + +namespace lower_set +section preorder +variables [preorder α] {a b : α} + +/-- Principal lower set. `set.Iic` as a lower set. The smallest lower set containing a given +element. -/ +def Iic (a : α) : lower_set α := ⟨Iic a, is_lower_set_Iic a⟩ + +/-- Strict principal lower set. `set.Iio` as a lower set. -/ +def Iio (a : α) : lower_set α := ⟨Iio a, is_lower_set_Iio a⟩ + +@[simp] lemma coe_Iic (a : α) : ↑(Iic a) = set.Iic a := rfl +@[simp] lemma coe_Iio (a : α) : ↑(Iio a) = set.Iio a := rfl +@[simp] lemma mem_Iic_iff : b ∈ Iic a ↔ b ≤ a := iff.rfl +@[simp] lemma mem_Iio_iff : b ∈ Iio a ↔ b < a := iff.rfl + +lemma Ioi_le_Ici (a : α) : Ioi a ≤ Ici a := Ioi_subset_Ici_self + +@[simp] lemma Iic_top [order_top α] : Iic (⊤ : α) = ⊤ := set_like.coe_injective Iic_top +@[simp] lemma Iio_bot [order_bot α] : Iio (⊥ : α) = ⊥ := set_like.coe_injective Iio_bot + +end preorder + +section semilattice_inf +variables [semilattice_inf α] + +@[simp] lemma Iic_inf (a b : α) : Iic (a ⊓ b) = Iic a ⊓ Iic b := +set_like.coe_injective Iic_inter_Iic.symm + +/-- `lower_set.Iic` as an `inf_hom`. -/ +def Iic_inf_hom : inf_hom α (lower_set α) := ⟨Iic, Iic_inf⟩ + +@[simp] lemma coe_Iic_inf_hom : (Iic_inf_hom : α → lower_set α) = Iic := rfl +@[simp] lemma Iic_inf_hom_apply (a : α) : Iic_inf_hom a = Iic a := rfl + +end semilattice_inf + +section complete_lattice +variables [complete_lattice α] + +@[simp] lemma Iic_Inf (S : set α) : Iic (Inf S) = ⨅ a ∈ S, Iic a := +set_like.ext $ λ c, by simp only [mem_Iic_iff, mem_infi₂_iff, le_Inf_iff] + +@[simp] lemma Iic_infi (f : ι → α) : Iic (⨅ i, f i) = ⨅ i, Iic (f i) := +set_like.ext $ λ c, by simp only [mem_Iic_iff, mem_infi_iff, le_infi_iff] + +@[simp] lemma Iic_infi₂ (f : Π i, κ i → α) : Iic (⨅ i j, f i j) = ⨅ i j, Iic (f i j) := +by simp_rw Iic_infi + +/-- `lower_set.Iic` as an `Inf_hom`. -/ +def Iic_Inf_hom : Inf_hom α (lower_set α) := ⟨Iic, λ s, (Iic_Inf s).trans Inf_image.symm⟩ + +@[simp] lemma coe_Iic_Inf_hom : (Iic_Inf_hom : α → lower_set α) = Iic := rfl +@[simp] lemma Iic_Inf_hom_apply (a : α) : Iic_Inf_hom a = Iic a := rfl + +end complete_lattice +end lower_set From 5c75390e9cf88f5f2220c375e39f5726724ccd88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Mon, 18 Apr 2022 17:14:06 +0000 Subject: [PATCH 066/373] feat(data/real/ennreal): Order properties of addition (#13371) Inherit algebraic order lemmas from `with_top`. Also protect `ennreal.add_lt_add_iff_left` and `ennreal.add_lt_add_iff_right`, as they should have been. --- src/data/real/ennreal.lean | 56 ++++++++++------------- src/measure_theory/integral/lebesgue.lean | 2 +- src/order/filter/ennreal.lean | 2 +- 3 files changed, 26 insertions(+), 34 deletions(-) diff --git a/src/data/real/ennreal.lean b/src/data/real/ennreal.lean index f74779c73d408..f8e728045d543 100644 --- a/src/data/real/ennreal.lean +++ b/src/data/real/ennreal.lean @@ -84,16 +84,16 @@ def ennreal := with_top ℝ≥0 localized "notation `ℝ≥0∞` := ennreal" in ennreal localized "notation `∞` := (⊤ : ennreal)" in ennreal +namespace ennreal +variables {a b c d : ℝ≥0∞} {r p q : ℝ≥0} + -- TODO: why are the two covariant instances necessary? why aren't they inferred? -instance covariant_class_mul : covariant_class ℝ≥0∞ ℝ≥0∞ (*) (≤) := +instance covariant_class_mul_le : covariant_class ℝ≥0∞ ℝ≥0∞ (*) (≤) := canonically_ordered_comm_semiring.to_covariant_mul_le -instance covariant_class_add : covariant_class ℝ≥0∞ ℝ≥0∞ (+) (≤) := +instance covariant_class_add_le : covariant_class ℝ≥0∞ ℝ≥0∞ (+) (≤) := ordered_add_comm_monoid.to_covariant_class_left ℝ≥0∞ -namespace ennreal -variables {a b c d : ℝ≥0∞} {r p q : ℝ≥0} - instance : inhabited ℝ≥0∞ := ⟨0⟩ instance : has_coe ℝ≥0 ℝ≥0∞ := ⟨ option.some ⟩ @@ -484,23 +484,30 @@ by simpa only [pos_iff_ne_zero] using ennreal.pow_pos @[simp] lemma not_lt_zero : ¬ a < 0 := by simp -lemma add_lt_add_iff_left (ha : a ≠ ∞) : a + c < a + b ↔ c < b := -with_top.add_lt_add_iff_left ha - -lemma add_lt_add_left (ha : a ≠ ∞) (h : b < c) : a + b < a + c := -(add_lt_add_iff_left ha).2 h - -lemma add_lt_add_iff_right (ha : a ≠ ∞) : c + a < b + a ↔ c < b := -with_top.add_lt_add_iff_right ha - -lemma add_lt_add_right (ha : a ≠ ∞) (h : b < c) : b + a < c + a := -(add_lt_add_iff_right ha).2 h +protected lemma le_of_add_le_add_left : a ≠ ∞ → a + b ≤ a + c → b ≤ c := +with_top.le_of_add_le_add_left +protected lemma le_of_add_le_add_right : a ≠ ∞ → b + a ≤ c + a → b ≤ c := +with_top.le_of_add_le_add_right +protected lemma add_lt_add_left : a ≠ ∞ → b < c → a + b < a + c := with_top.add_lt_add_left +protected lemma add_lt_add_right : a ≠ ∞ → b < c → b + a < c + a := with_top.add_lt_add_right +protected lemma add_le_add_iff_left : a ≠ ∞ → (a + b ≤ a + c ↔ b ≤ c) := +with_top.add_le_add_iff_left +protected lemma add_le_add_iff_right : a ≠ ∞ → (b + a ≤ c + a ↔ b ≤ c) := +with_top.add_le_add_iff_right +protected lemma add_lt_add_iff_left : a ≠ ∞ → (a + b < a + c ↔ b < c) := +with_top.add_lt_add_iff_left +protected lemma add_lt_add_iff_right : a ≠ ∞ → (b + a < c + a ↔ b < c) := +with_top.add_lt_add_iff_right +protected lemma add_lt_add_of_le_of_lt : a ≠ ∞ → a ≤ b → c < d → a + c < b + d := +with_top.add_lt_add_of_le_of_lt +protected lemma add_lt_add_of_lt_of_le : c ≠ ∞ → a < b → c ≤ d → a + c < b + d := +with_top.add_lt_add_of_lt_of_le instance contravariant_class_add_lt : contravariant_class ℝ≥0∞ ℝ≥0∞ (+) (<) := with_top.contravariant_class_add_lt lemma lt_add_right (ha : a ≠ ∞) (hb : b ≠ 0) : a < a + b := -by rwa [← pos_iff_ne_zero, ← add_lt_add_iff_left ha, add_zero] at hb +by rwa [← pos_iff_ne_zero, ←ennreal.add_lt_add_iff_left ha, add_zero] at hb lemma le_of_forall_pos_le_add : ∀{a b : ℝ≥0∞}, (∀ε : ℝ≥0, 0 < ε → b < ∞ → a ≤ b + ε) → a ≤ b | a none h := le_top @@ -614,21 +621,6 @@ by simp [upper_bounds, ball_image_iff, -mem_image, *] {contextual := tt} end complete_lattice -/-- `le_of_add_le_add_left` is normally applicable to `ordered_cancel_add_comm_monoid`, -but it holds in `ℝ≥0∞` with the additional assumption that `a ≠ ∞`. -/ -lemma le_of_add_le_add_left {a b c : ℝ≥0∞} (ha : a ≠ ∞) : - a + b ≤ a + c → b ≤ c := -begin - lift a to ℝ≥0 using ha, - cases b; cases c; simp [← ennreal.coe_add, ennreal.coe_le_coe] -end - -/-- `le_of_add_le_add_right` is normally applicable to `ordered_cancel_add_comm_monoid`, -but it holds in `ℝ≥0∞` with the additional assumption that `a ≠ ∞`. -/ -lemma le_of_add_le_add_right {a b c : ℝ≥0∞} : a ≠ ∞ → - b + a ≤ c + a → b ≤ c := -by simpa only [add_comm _ a] using le_of_add_le_add_left - section mul @[mono] lemma mul_le_mul : a ≤ b → c ≤ d → a * c ≤ b * d := diff --git a/src/measure_theory/integral/lebesgue.lean b/src/measure_theory/integral/lebesgue.lean index f818d6d16df11..b190341a4868e 100644 --- a/src/measure_theory/integral/lebesgue.lean +++ b/src/measure_theory/integral/lebesgue.lean @@ -1116,7 +1116,7 @@ begin rcases this with ⟨φ, hle : ∀ x, ↑(φ x) ≤ f x, b, hbφ, hb⟩, refine ⟨φ, hle, λ ψ hψ, _⟩, have : (map coe φ).lintegral μ ≠ ∞, from ne_top_of_le_ne_top h (le_supr₂ φ hle), - rw [← add_lt_add_iff_left this, ← add_lintegral, ← map_add @ennreal.coe_add], + rw [← ennreal.add_lt_add_iff_left this, ← add_lintegral, ← map_add @ennreal.coe_add], refine (hb _ (λ x, le_trans _ (max_le (hle x) (hψ x)))).trans_lt hbφ, norm_cast, simp only [add_apply, sub_apply, add_tsub_eq_max] diff --git a/src/order/filter/ennreal.lean b/src/order/filter/ennreal.lean index 95339f390d6d2..2673f8643da8e 100644 --- a/src/order/filter/ennreal.lean +++ b/src/order/filter/ennreal.lean @@ -30,7 +30,7 @@ begin { rw eventually_countable_forall, refine λ n, eventually_lt_of_limsup_lt _, nth_rewrite 0 ←add_zero (f.limsup u), - exact (add_lt_add_iff_left hx_top).mpr (by simp), }, + exact (ennreal.add_lt_add_iff_left hx_top).mpr (by simp), }, refine h_forall_le.mono (λ y hy, le_of_forall_pos_le_add (λ r hr_pos hx_top, _)), have hr_ne_zero : (r : ℝ≥0∞) ≠ 0, { rw [ne.def, coe_eq_zero], From d89160b5874c1c6c96d6cc1d6a0ae07405b5ee46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Mon, 18 Apr 2022 17:14:07 +0000 Subject: [PATCH 067/373] feat(order/bounded_order): Strictly monotone functions preserve maximality (#13434) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prove `f a = f ⊤ ↔ a = ⊤` and `f a = f ⊥ ↔ a = ⊥` for strictly monotone/antitone functions. Also fix `is_max.eq_top` and friends and delete `eq_top_of_maximal` (which accidentally survived the last refactor). --- src/logic/basic.lean | 6 ++++-- src/order/bounded_order.lean | 23 +++++++++++++++++------ src/order/monotone.lean | 16 ++++++++++++++-- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/logic/basic.lean b/src/logic/basic.lean index 078f07cbb712d..7ba854bd9a54b 100644 --- a/src/logic/basic.lean +++ b/src/logic/basic.lean @@ -294,8 +294,6 @@ def not.elim {α : Sort*} (H1 : ¬a) (H2 : a) : α := absurd H2 H1 @[reducible] theorem not.imp {a b : Prop} (H2 : ¬b) (H1 : a → b) : ¬a := mt H1 H2 -lemma iff.not (h : a ↔ b) : ¬ a ↔ ¬ b := not_congr h - theorem not_not_of_not_imp : ¬(a → b) → ¬¬a := mt not.elim @@ -399,6 +397,10 @@ theorem imp.swap : (a → b → c) ↔ (b → a → c) := theorem imp_not_comm : (a → ¬b) ↔ (b → ¬a) := imp.swap +lemma iff.not (h : a ↔ b) : ¬ a ↔ ¬ b := not_congr h +lemma iff.not_left (h : a ↔ ¬ b) : ¬ a ↔ b := h.not.trans not_not +lemma iff.not_right (h : ¬ a ↔ b) : a ↔ ¬ b := not_not.symm.trans h.not + /-! ### Declarations about `xor` -/ @[simp] theorem xor_true : xor true = not := funext $ λ a, by simp [xor] diff --git a/src/order/bounded_order.lean b/src/order/bounded_order.lean index 532485a44af77..ddd7f7dac49d2 100644 --- a/src/order/bounded_order.lean +++ b/src/order/bounded_order.lean @@ -88,7 +88,7 @@ alias ne_top_of_lt ← has_lt.lt.ne_top end preorder -variables [partial_order α] [order_top α] {a b : α} +variables [partial_order α] [order_top α] [preorder β] {f : α → β} {a b : α} @[simp] lemma is_max_iff_eq_top : is_max a ↔ a = ⊤ := ⟨λ h, h.eq_of_le le_top, λ h b _, h.symm ▸ le_top⟩ @@ -99,21 +99,25 @@ variables [partial_order α] [order_top α] {a b : α} lemma not_is_max_iff_ne_top : ¬ is_max a ↔ a ≠ ⊤ := is_max_iff_eq_top.not lemma not_is_top_iff_ne_top : ¬ is_top a ↔ a ≠ ⊤ := is_top_iff_eq_top.not -alias is_max_iff_eq_top ↔ _ is_max.eq_top -alias is_top_iff_eq_top ↔ _ is_top.eq_top +alias is_max_iff_eq_top ↔ is_max.eq_top _ +alias is_top_iff_eq_top ↔ is_top.eq_top _ @[simp] lemma top_le_iff : ⊤ ≤ a ↔ a = ⊤ := le_top.le_iff_eq.trans eq_comm lemma top_unique (h : ⊤ ≤ a) : a = ⊤ := le_top.antisymm h lemma eq_top_iff : a = ⊤ ↔ ⊤ ≤ a := top_le_iff.symm lemma eq_top_mono (h : a ≤ b) (h₂ : a = ⊤) : b = ⊤ := top_unique $ h₂ ▸ h lemma lt_top_iff_ne_top : a < ⊤ ↔ a ≠ ⊤ := le_top.lt_iff_ne +@[simp] lemma not_lt_top_iff : ¬ a < ⊤ ↔ a = ⊤ := lt_top_iff_ne_top.not_left lemma eq_top_or_lt_top (a : α) : a = ⊤ ∨ a < ⊤ := le_top.eq_or_lt lemma ne.lt_top (h : a ≠ ⊤) : a < ⊤ := lt_top_iff_ne_top.mpr h lemma ne.lt_top' (h : ⊤ ≠ a) : a < ⊤ := h.symm.lt_top lemma ne_top_of_le_ne_top (hb : b ≠ ⊤) (hab : a ≤ b) : a ≠ ⊤ := (hab.trans_lt hb.lt_top).ne -lemma eq_top_of_maximal (h : ∀ b, ¬ a < b) : a = ⊤ := -or.elim (lt_or_eq_of_le le_top) (λ hlt, absurd hlt (h ⊤)) (λ he, he) +lemma strict_mono.apply_eq_top_iff (hf : strict_mono f) : f a = f ⊤ ↔ a = ⊤ := +⟨λ h, not_lt_top_iff.1 $ λ ha, (hf ha).ne h, congr_arg _⟩ + +lemma strict_anti.apply_eq_top_iff (hf : strict_anti f) : f a = f ⊤ ↔ a = ⊤ := +⟨λ h, not_lt_top_iff.1 $ λ ha, (hf ha).ne' h, congr_arg _⟩ variables [nontrivial α] @@ -168,7 +172,7 @@ alias ne_bot_of_gt ← has_lt.lt.ne_bot end preorder -variables [partial_order α] [order_bot α] {a b : α} +variables [partial_order α] [order_bot α] [preorder β] {f : α → β} {a b : α} @[simp] lemma is_min_iff_eq_bot : is_min a ↔ a = ⊥ := ⟨λ h, h.eq_of_ge bot_le, λ h b _, h.symm ▸ bot_le⟩ @@ -187,12 +191,19 @@ lemma bot_unique (h : a ≤ ⊥) : a = ⊥ := h.antisymm bot_le lemma eq_bot_iff : a = ⊥ ↔ a ≤ ⊥ := le_bot_iff.symm lemma eq_bot_mono (h : a ≤ b) (h₂ : b = ⊥) : a = ⊥ := bot_unique $ h₂ ▸ h lemma bot_lt_iff_ne_bot : ⊥ < a ↔ a ≠ ⊥ := bot_le.lt_iff_ne.trans ne_comm +@[simp] lemma not_bot_lt_iff : ¬ ⊥ < a ↔ a = ⊥ := bot_lt_iff_ne_bot.not_left lemma eq_bot_or_bot_lt (a : α) : a = ⊥ ∨ ⊥ < a := bot_le.eq_or_gt lemma eq_bot_of_minimal (h : ∀ b, ¬ b < a) : a = ⊥ := (eq_bot_or_bot_lt a).resolve_right (h ⊥) lemma ne.bot_lt (h : a ≠ ⊥) : ⊥ < a := bot_lt_iff_ne_bot.mpr h lemma ne.bot_lt' (h : ⊥ ≠ a) : ⊥ < a := h.symm.bot_lt lemma ne_bot_of_le_ne_bot (hb : b ≠ ⊥) (hab : b ≤ a) : a ≠ ⊥ := (hb.bot_lt.trans_le hab).ne' +lemma strict_mono.apply_eq_bot_iff (hf : strict_mono f) : f a = f ⊥ ↔ a = ⊥ := +⟨λ h, not_bot_lt_iff.1 $ λ ha, (hf ha).ne' h, congr_arg _⟩ + +lemma strict_anti.apply_eq_bot_iff (hf : strict_anti f) : f a = f ⊥ ↔ a = ⊥ := +⟨λ h, not_bot_lt_iff.1 $ λ ha, (hf ha).ne h, congr_arg _⟩ + variables [nontrivial α] lemma not_is_max_bot : ¬ is_max (⊥ : α) := diff --git a/src/order/monotone.lean b/src/order/monotone.lean index 2ac09cb3a2620..8df550fd1916a 100644 --- a/src/order/monotone.lean +++ b/src/order/monotone.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Mario Carneiro, Yaël Dillies -/ import order.compare -import order.order_dual +import order.max import order.rel_classes /-! @@ -339,7 +339,19 @@ lemma injective_of_le_imp_le [partial_order α] [preorder β] (f : α → β) λ x y hxy, (h hxy.le).antisymm (h hxy.ge) section preorder -variables [preorder α] [preorder β] {f g : α → β} +variables [preorder α] [preorder β] {f g : α → β} {a : α} + +lemma strict_mono.is_max_of_apply (hf : strict_mono f) (ha : is_max (f a)) : is_max a := +of_not_not $ λ h, let ⟨b, hb⟩ := not_is_max_iff.1 h in (hf hb).not_is_max ha + +lemma strict_mono.is_min_of_apply (hf : strict_mono f) (ha : is_min (f a)) : is_min a := +of_not_not $ λ h, let ⟨b, hb⟩ := not_is_min_iff.1 h in (hf hb).not_is_min ha + +lemma strict_anti.is_max_of_apply (hf : strict_anti f) (ha : is_min (f a)) : is_max a := +of_not_not $ λ h, let ⟨b, hb⟩ := not_is_max_iff.1 h in (hf hb).not_is_min ha + +lemma strict_anti.is_min_of_apply (hf : strict_anti f) (ha : is_max (f a)) : is_min a := +of_not_not $ λ h, let ⟨b, hb⟩ := not_is_min_iff.1 h in (hf hb).not_is_max ha protected lemma strict_mono.ite' (hf : strict_mono f) (hg : strict_mono g) {p : α → Prop} [decidable_pred p] (hp : ∀ ⦃x y⦄, x < y → p y → p x) From fd08afe3eea9c106e9e06a9768329b5925fc56e9 Mon Sep 17 00:00:00 2001 From: Stuart Presnell Date: Mon, 18 Apr 2022 19:11:37 +0000 Subject: [PATCH 068/373] chore(data/nat/factorization): golf `dvd_iff_prime_pow_dvd_dvd` (#13473) Golfing the edge-case proof added in https://github.com/leanprover-community/mathlib/pull/13316 --- src/data/nat/factorization.lean | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/data/nat/factorization.lean b/src/data/nat/factorization.lean index 13e166671c4fa..ea92303cd189c 100644 --- a/src/data/nat/factorization.lean +++ b/src/data/nat/factorization.lean @@ -293,17 +293,11 @@ end lemma dvd_iff_prime_pow_dvd_dvd (n d : ℕ) : d ∣ n ↔ ∀ p k : ℕ, prime p → p ^ k ∣ d → p ^ k ∣ n := begin - by_cases hn : n = 0, - { simp [hn], }, - by_cases hd : d = 0, - { simp only [hd, hn, zero_dvd_iff, dvd_zero, forall_true_left, false_iff, - not_forall, exists_prop, exists_and_distrib_left], - refine ⟨2, prime_two, n, λ h, _⟩, - have := le_of_dvd (nat.pos_of_ne_zero hn) h, - revert this, - change ¬ _, - rw [not_le], - exact lt_two_pow n, }, + rcases eq_or_ne n 0 with rfl | hn, { simp }, + rcases eq_or_ne d 0 with rfl | hd, + { simp only [zero_dvd_iff, hn, false_iff, not_forall], + refine ⟨2, n, prime_two, ⟨dvd_zero _, _⟩⟩, + apply mt (le_of_dvd hn.bot_lt) (not_le.mpr (lt_two_pow n)) }, refine ⟨λ h p k _ hpkd, dvd_trans hpkd h, _⟩, rw [←factorization_le_iff_dvd hd hn, finsupp.le_def], intros h p, From b54591f7b62ebb86a38c91d7875f36b8ea08ae5a Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 18 Apr 2022 19:11:38 +0000 Subject: [PATCH 069/373] chore(analysis/normed_space/finite_dimension): golf a proof (#13491) These `letI`s just made this proof convoluted, the instances were not needed. Without them, we don't even need the import. Similarly, the `classical` was the cause of the need for the `congr`. --- src/analysis/normed_space/finite_dimension.lean | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/analysis/normed_space/finite_dimension.lean b/src/analysis/normed_space/finite_dimension.lean index 4a3014994f5e7..129d90e397e82 100644 --- a/src/analysis/normed_space/finite_dimension.lean +++ b/src/analysis/normed_space/finite_dimension.lean @@ -7,7 +7,6 @@ import analysis.asymptotics.asymptotic_equivalent import analysis.normed_space.affine_isometry import analysis.normed_space.operator_norm import analysis.normed_space.riesz_lemma -import analysis.matrix import linear_algebra.matrix.to_lin import topology.algebra.matrix @@ -273,20 +272,13 @@ lemma continuous_linear_map.continuous_det : continuous (λ (f : E →L[𝕜] E), f.det) := begin change continuous (λ (f : E →L[𝕜] E), (f : E →ₗ[𝕜] E).det), - classical, by_cases h : ∃ (s : finset E), nonempty (basis ↥s 𝕜 E), { rcases h with ⟨s, ⟨b⟩⟩, haveI : finite_dimensional 𝕜 E := finite_dimensional.of_finset_basis b, - letI : semi_normed_group (matrix s s 𝕜) := matrix.semi_normed_group, - letI : normed_space 𝕜 (matrix s s 𝕜) := matrix.normed_space, simp_rw linear_map.det_eq_det_to_matrix_of_finset b, - have A : continuous (λ (f : E →L[𝕜] E), linear_map.to_matrix b b f), - { change continuous ((linear_map.to_matrix b b).to_linear_map.comp - (continuous_linear_map.coe_lm 𝕜)), - exact linear_map.continuous_of_finite_dimensional _ }, - convert A.matrix_det, - ext f, - congr }, + refine continuous.matrix_det _, + exact ((linear_map.to_matrix b b).to_linear_map.comp + (continuous_linear_map.coe_lm 𝕜)).continuous_of_finite_dimensional }, { unfold linear_map.det, simpa only [h, monoid_hom.one_apply, dif_neg, not_false_iff] using continuous_const } end From 3c20253bb3738f0e5ea90b8617a291d1ad8dd23a Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Mon, 18 Apr 2022 19:11:39 +0000 Subject: [PATCH 070/373] chore(algebra/ring/{pi, prod}): fix errors in `ring_hom` for `pi` and `prod`. (#13501) Looks like some things were incorrectly changed when copied from the corresponding `monoid_hom` files. --- src/algebra/ring/pi.lean | 2 +- src/algebra/ring/prod.lean | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/algebra/ring/pi.lean b/src/algebra/ring/pi.lean index d0f835cba6045..33af3ec66d4b0 100644 --- a/src/algebra/ring/pi.lean +++ b/src/algebra/ring/pi.lean @@ -100,7 +100,7 @@ section ring_hom universes u v variable {I : Type u} -/-- Evaluation of functions into an indexed collection of monoids at a point is a monoid +/-- Evaluation of functions into an indexed collection of rings at a point is a ring homomorphism. This is `function.eval` as a `ring_hom`. -/ @[simps] def pi.eval_ring_hom (f : I → Type v) [Π i, non_assoc_semiring (f i)] (i : I) : diff --git a/src/algebra/ring/prod.lean b/src/algebra/ring/prod.lean index bbdd95d84d682..472ecee75591b 100644 --- a/src/algebra/ring/prod.lean +++ b/src/algebra/ring/prod.lean @@ -120,14 +120,14 @@ variables [non_assoc_semiring R'] [non_assoc_semiring S'] [non_assoc_semiring T] variables (f : R →+* R') (g : S →+* S') /-- `prod.map` as a `ring_hom`. -/ -def prod_map : R × S →* R' × S' := (f.comp (fst R S)).prod (g.comp (snd R S)) +def prod_map : R × S →+* R' × S' := (f.comp (fst R S)).prod (g.comp (snd R S)) lemma prod_map_def : prod_map f g = (f.comp (fst R S)).prod (g.comp (snd R S)) := rfl @[simp] lemma coe_prod_map : ⇑(prod_map f g) = prod.map f g := rfl -lemma prod_comp_prod_map (f : T →* R) (g : T →* S) (f' : R →* R') (g' : S →* S') : +lemma prod_comp_prod_map (f : T →+* R) (g : T →+* S) (f' : R →+* R') (g' : S →+* S') : (f'.prod_map g').comp (f.prod g) = (f'.comp f).prod (g'.comp g) := rfl From 37d02d3da4e6d8437d522174bf85276fcd882b54 Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Mon, 18 Apr 2022 20:47:04 +0000 Subject: [PATCH 071/373] chore(ring_theory/hahn_series, topology/locally_constant/algebra): add missing `non_unital_non_assoc_ring` instances (#13504) --- src/ring_theory/hahn_series.lean | 12 ++++++++++++ src/topology/locally_constant/algebra.lean | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/ring_theory/hahn_series.lean b/src/ring_theory/hahn_series.lean index 3c66dc89d2beb..74db2ffa13ecc 100644 --- a/src/ring_theory/hahn_series.lean +++ b/src/ring_theory/hahn_series.lean @@ -753,6 +753,18 @@ instance [comm_semiring R] : comm_semiring (hahn_series Γ R) := end, .. hahn_series.semiring } +instance [non_unital_non_assoc_ring R] : non_unital_non_assoc_ring (hahn_series Γ R) := +{ .. hahn_series.non_unital_non_assoc_semiring, + .. hahn_series.add_group } + +instance [non_unital_ring R] : non_unital_ring (hahn_series Γ R) := +{ .. hahn_series.non_unital_non_assoc_ring, + .. hahn_series.non_unital_semiring } + +instance [non_assoc_ring R] : non_assoc_ring (hahn_series Γ R) := +{ .. hahn_series.non_unital_non_assoc_ring, + .. hahn_series.non_assoc_semiring } + instance [ring R] : ring (hahn_series Γ R) := { .. hahn_series.semiring, .. hahn_series.add_comm_group } diff --git a/src/topology/locally_constant/algebra.lean b/src/topology/locally_constant/algebra.lean index 36d369c02ffcf..577481f4ec6cf 100644 --- a/src/topology/locally_constant/algebra.lean +++ b/src/topology/locally_constant/algebra.lean @@ -136,6 +136,16 @@ instance [semiring Y] : semiring (locally_constant X Y) := instance [comm_semiring Y] : comm_semiring (locally_constant X Y) := { .. locally_constant.semiring, .. locally_constant.comm_monoid } +instance [non_unital_non_assoc_ring Y] : non_unital_non_assoc_ring (locally_constant X Y) := +{ .. locally_constant.add_comm_group, .. locally_constant.has_mul, + .. locally_constant.distrib, .. locally_constant.mul_zero_class } + +instance [non_unital_ring Y] : non_unital_ring (locally_constant X Y) := +{ .. locally_constant.semigroup, .. locally_constant.non_unital_non_assoc_ring } + +instance [non_assoc_ring Y] : non_assoc_ring (locally_constant X Y) := +{ .. locally_constant.mul_one_class, .. locally_constant.non_unital_non_assoc_ring } + instance [ring Y] : ring (locally_constant X Y) := { .. locally_constant.semiring, .. locally_constant.add_comm_group } From eb22ba4f6e62243777c23844be5103d3c002666c Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Tue, 19 Apr 2022 01:03:57 +0000 Subject: [PATCH 072/373] chore(algebra/monoid_algebra/basic): use the homomorphism typeclasses (#13389) This replaces `mul_hom` with `mul_hom_class` and `add_hom` with `add_hom_class`. Also adds two trivial lemmas, `monoid_algebra.map_domain_one` and `add_monoid_algebra.map_domain_one`. --- src/algebra/monoid_algebra/basic.lean | 28 +++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/algebra/monoid_algebra/basic.lean b/src/algebra/monoid_algebra/basic.lean index 2658f2810d33d..c0c95778c61fe 100644 --- a/src/algebra/monoid_algebra/basic.lean +++ b/src/algebra/monoid_algebra/basic.lean @@ -336,13 +336,19 @@ subset.trans support_sum $ bUnion_mono $ assume a₁ _, section +/-- Like `finsupp.map_domain_zero`, but for the `1` we define in this file -/ +@[simp] lemma map_domain_one {α : Type*} {β : Type*} {α₂ : Type*} + [semiring β] [has_one α] [has_one α₂] {F : Type*} [one_hom_class F α α₂] (f : F) : + (map_domain f (1 : monoid_algebra β α) : monoid_algebra β α₂) = (1 : monoid_algebra β α₂) := +by simp_rw [one_def, map_domain_single, map_one] + /-- Like `finsupp.map_domain_add`, but for the convolutive multiplication we define in this file -/ lemma map_domain_mul {α : Type*} {β : Type*} {α₂ : Type*} [semiring β] [has_mul α] [has_mul α₂] - {x y : monoid_algebra β α} (f : mul_hom α α₂) : + {F : Type*} [mul_hom_class F α α₂] (f : F) (x y : monoid_algebra β α) : (map_domain f (x * y : monoid_algebra β α) : monoid_algebra β α₂) = (map_domain f x * map_domain f y : monoid_algebra β α₂) := begin - simp_rw [mul_def, map_domain_sum, map_domain_single, f.map_mul], + simp_rw [mul_def, map_domain_sum, map_domain_single, map_mul], rw finsupp.sum_map_domain_index, { congr, ext a b, @@ -1098,14 +1104,20 @@ lemma single_pow [add_monoid G] {a : G} {b : k} : | (n+1) := by rw [pow_succ, pow_succ, single_pow n, single_mul_single, add_comm, add_nsmul, one_nsmul] +/-- Like `finsupp.map_domain_zero`, but for the `1` we define in this file -/ +@[simp] lemma map_domain_one {α : Type*} {β : Type*} {α₂ : Type*} + [semiring β] [has_zero α] [has_zero α₂] {F : Type*} [zero_hom_class F α α₂] (f : F) : + (map_domain f (1 : add_monoid_algebra β α) : add_monoid_algebra β α₂) = + (1 : add_monoid_algebra β α₂) := +by simp_rw [one_def, map_domain_single, map_zero] + /-- Like `finsupp.map_domain_add`, but for the convolutive multiplication we define in this file -/ -lemma map_domain_mul {α : Type*} {β : Type*} {α₂ : Type*} - [semiring β] [has_add α] [has_add α₂] - {x y : add_monoid_algebra β α} (f : add_hom α α₂) : +lemma map_domain_mul {α : Type*} {β : Type*} {α₂ : Type*} [semiring β] [has_add α] [has_add α₂] + {F : Type*} [add_hom_class F α α₂] (f : F) (x y : add_monoid_algebra β α) : (map_domain f (x * y : add_monoid_algebra β α) : add_monoid_algebra β α₂) = (map_domain f x * map_domain f y : add_monoid_algebra β α₂) := begin - simp_rw [mul_def, map_domain_sum, map_domain_single, f.map_add], + simp_rw [mul_def, map_domain_sum, map_domain_single, map_add], rw finsupp.sum_map_domain_index, { congr, ext a b, @@ -1250,7 +1262,7 @@ protected def add_monoid_algebra.to_multiplicative [semiring k] [has_add G] : map_mul' := λ x y, begin repeat {rw equiv_map_domain_eq_map_domain}, dsimp [multiplicative.of_add], - convert monoid_algebra.map_domain_mul (mul_hom.id (multiplicative G)), + convert monoid_algebra.map_domain_mul (mul_hom.id (multiplicative G)) _ _, end, ..finsupp.dom_congr multiplicative.of_add } @@ -1261,7 +1273,7 @@ protected def monoid_algebra.to_additive [semiring k] [has_mul G] : map_mul' := λ x y, begin repeat {rw equiv_map_domain_eq_map_domain}, dsimp [additive.of_mul], - convert monoid_algebra.map_domain_mul (mul_hom.id G), + convert monoid_algebra.map_domain_mul (mul_hom.id G) _ _, end, ..finsupp.dom_congr additive.of_mul } From fb44330ec70e555fee4fc3afb97d6b323a3ba9ae Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Tue, 19 Apr 2022 03:39:47 +0000 Subject: [PATCH 073/373] feat(data/matrix/block): `matrix.block_diagonal` is a ring homomorphism (#13489) This is one of the steps on the path to showing that the matrix exponential of a block diagonal matrix is a block diagonal matrix of the exponents of the blocks. As well as adding the new bundled homomorphisms, this generalizes the typeclasses in this file and tidies up the order of arguments. Finally, this protects some `map_*` lemmas to prevent clashes with the global lemmas of the same name. --- src/data/matrix/basic.lean | 8 +- src/data/matrix/block.lean | 154 +++++++++++++++++++++++-------------- 2 files changed, 102 insertions(+), 60 deletions(-) diff --git a/src/data/matrix/basic.lean b/src/data/matrix/basic.lean index 7f985e3872116..1a4550e16e158 100644 --- a/src/data/matrix/basic.lean +++ b/src/data/matrix/basic.lean @@ -135,15 +135,17 @@ instance [monoid R] [add_monoid α] [distrib_mul_action R α] : instance [semiring R] [add_comm_monoid α] [module R α] : module R (matrix m n α) := pi.module _ _ _ -@[simp] lemma map_zero [has_zero α] [has_zero β] (f : α → β) (h : f 0 = 0) : +@[simp] protected lemma map_zero [has_zero α] [has_zero β] (f : α → β) (h : f 0 = 0) : (0 : matrix m n α).map f = 0 := by { ext, simp [h], } -lemma map_add [has_add α] [has_add β] (f : α → β) (hf : ∀ a₁ a₂, f (a₁ + a₂) = f a₁ + f a₂) +protected lemma map_add [has_add α] [has_add β] (f : α → β) + (hf : ∀ a₁ a₂, f (a₁ + a₂) = f a₁ + f a₂) (M N : matrix m n α) : (M + N).map f = M.map f + N.map f := ext $ λ _ _, hf _ _ -lemma map_sub [has_sub α] [has_sub β] (f : α → β) (hf : ∀ a₁ a₂, f (a₁ - a₂) = f a₁ - f a₂) +protected lemma map_sub [has_sub α] [has_sub β] (f : α → β) + (hf : ∀ a₁ a₂, f (a₁ - a₂) = f a₁ - f a₂) (M N : matrix m n α) : (M - N).map f = M.map f - N.map f := ext $ λ _ _, hf _ _ diff --git a/src/data/matrix/block.lean b/src/data/matrix/block.lean index 433ae0260aeed..f88cae4d27cab 100644 --- a/src/data/matrix/block.lean +++ b/src/data/matrix/block.lean @@ -13,11 +13,13 @@ import data.matrix.basic * `matrix.from_blocks`: build a block matrix out of 4 blocks * `matrix.to_blocks₁₁`, `matrix.to_blocks₁₂`, `matrix.to_blocks₂₁`, `matrix.to_blocks₂₂`: extract each of the four blocks from `matrix.from_blocks`. -* `matrix.block_diagonal`: block diagonal of equally sized blocks -* `matrix.block_diagonal'`: block diagonal of unequally sized blocks +* `matrix.block_diagonal`: block diagonal of equally sized blocks. On square blocks, this is a + ring homomorphisms, `matrix.block_diagonal_ring_hom`. +* `matrix.block_diagonal'`: block diagonal of unequally sized blocks. On square blocks, this is a + ring homomorphisms, `matrix.block_diagonal'_ring_hom`. -/ -variables {l m n o : Type*} {m' : o → Type*} {n' : o → Type*} +variables {l m n o p q : Type*} {m' n' p' : o → Type*} variables {R : Type*} {S : Type*} {α : Type*} {β : Type*} open_locale matrix @@ -157,16 +159,14 @@ def to_square_block_prop (M : matrix m m α) (p : m → Prop) : @[simp] lemma to_square_block_prop_def (M : matrix m m α) (p : m → Prop) : to_square_block_prop M p = λ i j, M ↑i ↑j := rfl -variables [semiring α] - -lemma from_blocks_smul - (x : α) (A : matrix n l α) (B : matrix n m α) (C : matrix o l α) (D : matrix o m α) : +lemma from_blocks_smul [has_scalar R α] + (x : R) (A : matrix n l α) (B : matrix n m α) (C : matrix o l α) (D : matrix o m α) : x • (from_blocks A B C D) = from_blocks (x • A) (x • B) (x • C) (x • D) := begin ext i j, rcases i; rcases j; simp [from_blocks], end -lemma from_blocks_add +lemma from_blocks_add [has_add α] (A : matrix n l α) (B : matrix n m α) (C : matrix o l α) (D : matrix o m α) (A' : matrix n l α) (B' : matrix n m α) (C' : matrix o l α) (D' : matrix o m α) : (from_blocks A B C D) + (from_blocks A' B' C' D') = @@ -176,7 +176,7 @@ begin ext i j, rcases i; rcases j; refl, end -lemma from_blocks_multiply {p q : Type*} [fintype l] [fintype m] +lemma from_blocks_multiply [fintype l] [fintype m] [non_unital_non_assoc_semiring α] (A : matrix n l α) (B : matrix n m α) (C : matrix o l α) (D : matrix o m α) (A' : matrix l p α) (B' : matrix l q α) (C' : matrix m p α) (D' : matrix m q α) : (from_blocks A B C D) ⬝ (from_blocks A' B' C' D') = @@ -190,23 +190,22 @@ end variables [decidable_eq l] [decidable_eq m] -@[simp] lemma from_blocks_diagonal (d₁ : l → α) (d₂ : m → α) : +@[simp] lemma from_blocks_diagonal [has_zero α] (d₁ : l → α) (d₂ : m → α) : from_blocks (diagonal d₁) 0 0 (diagonal d₂) = diagonal (sum.elim d₁ d₂) := begin ext i j, rcases i; rcases j; simp [diagonal], end -@[simp] lemma from_blocks_one : from_blocks (1 : matrix l l α) 0 0 (1 : matrix m m α) = 1 := +@[simp] lemma from_blocks_one [has_zero α] [has_one α] : + from_blocks (1 : matrix l l α) 0 0 (1 : matrix m m α) = 1 := by { ext i j, rcases i; rcases j; simp [one_apply] } end block_matrices section block_diagonal - -variables (M N : o → matrix m n α) [decidable_eq o] +variables [decidable_eq o] section has_zero - variables [has_zero α] [has_zero β] /-- `matrix.block_diagonal M` turns a homogenously-indexed collection of matrices @@ -215,23 +214,23 @@ the diagonal and zero elsewhere. See also `matrix.block_diagonal'` if the matrices may not have the same size everywhere. -/ -def block_diagonal : matrix (m × o) (n × o) α +def block_diagonal (M : o → matrix m n α) : matrix (m × o) (n × o) α | ⟨i, k⟩ ⟨j, k'⟩ := if k = k' then M k i j else 0 -lemma block_diagonal_apply (ik jk) : +lemma block_diagonal_apply (M : o → matrix m n α) (ik jk) : block_diagonal M ik jk = if ik.2 = jk.2 then M ik.2 ik.1 jk.1 else 0 := by { cases ik, cases jk, refl } @[simp] -lemma block_diagonal_apply_eq (i j k) : +lemma block_diagonal_apply_eq (M : o → matrix m n α) (i j k) : block_diagonal M (i, k) (j, k) = M k i j := if_pos rfl -lemma block_diagonal_apply_ne (i j) {k k'} (h : k ≠ k') : +lemma block_diagonal_apply_ne (M : o → matrix m n α) (i j) {k k'} (h : k ≠ k') : block_diagonal M (i, k) (j, k') = 0 := if_neg h -lemma block_diagonal_map (f : α → β) (hf : f 0 = 0) : +lemma block_diagonal_map (M : o → matrix m n α) (f : α → β) (hf : f 0 = 0) : (block_diagonal M).map f = block_diagonal (λ k, (M k).map f) := begin ext, @@ -239,7 +238,7 @@ begin rw [apply_ite f, hf], end -@[simp] lemma block_diagonal_transpose : +@[simp] lemma block_diagonal_transpose (M : o → matrix m n α) : (block_diagonal M)ᵀ = block_diagonal (λ k, (M k)ᵀ) := begin ext, @@ -250,7 +249,7 @@ begin end @[simp] lemma block_diagonal_conj_transpose - {α : Type*} [semiring α] [star_ring α] (M : o → matrix m n α) : + {α : Type*} [add_monoid α] [star_add_monoid α] (M : o → matrix m n α) : (block_diagonal M)ᴴ = block_diagonal (λ k, (M k)ᴴ) := begin simp only [conj_transpose, block_diagonal_transpose], @@ -277,7 +276,7 @@ by rw [block_diagonal_diagonal] end has_zero -@[simp] lemma block_diagonal_add [add_monoid α] : +@[simp] lemma block_diagonal_add [add_zero_class α] (M N : o → matrix m n α) : block_diagonal (M + N) = block_diagonal M + block_diagonal N := begin ext, @@ -285,20 +284,26 @@ begin split_ifs; simp end -@[simp] lemma block_diagonal_neg [add_group α] : - block_diagonal (-M) = - block_diagonal M := -begin - ext, - simp only [block_diagonal_apply, pi.neg_apply], - split_ifs; simp +section +variables (o m n α) +/-- `matrix.block_diagonal` as an `add_monoid_hom`. -/ +@[simps] def block_diagonal_add_monoid_hom [add_zero_class α] : + (o → matrix m n α) →+ matrix (m × o) (n × o) α := +{ to_fun := block_diagonal, + map_zero' := block_diagonal_zero, + map_add' := block_diagonal_add } end -@[simp] lemma block_diagonal_sub [add_group α] : +@[simp] lemma block_diagonal_neg [add_group α] (M : o → matrix m n α) : + block_diagonal (-M) = - block_diagonal M := +map_neg (block_diagonal_add_monoid_hom m n o α) M + +@[simp] lemma block_diagonal_sub [add_group α] (M N : o → matrix m n α) : block_diagonal (M - N) = block_diagonal M - block_diagonal N := -by simp [sub_eq_add_neg] +map_sub (block_diagonal_add_monoid_hom m n o α) M N -@[simp] lemma block_diagonal_mul {p : Type*} [fintype n] [fintype o] [semiring α] - (N : o → matrix n p α) : +@[simp] lemma block_diagonal_mul [fintype n] [fintype o] [non_unital_non_assoc_semiring α] + (M : o → matrix m n α) (N : o → matrix n p α) : block_diagonal (λ k, M k ⬝ N k) = block_diagonal M ⬝ block_diagonal N := begin ext ⟨i, k⟩ ⟨j, k'⟩, @@ -306,15 +311,27 @@ begin split_ifs with h; simp [h] end -@[simp] lemma block_diagonal_smul {R : Type*} [semiring R] [add_comm_monoid α] [module R α] - (x : R) : block_diagonal (x • M) = x • block_diagonal M := +section +variables (α m o) +/-- `matrix.block_diagonal` as a `ring_hom`. -/ +@[simps] +def block_diagonal_ring_hom [decidable_eq m] [fintype o] [fintype m] [non_assoc_semiring α] : + (o → matrix m m α) →+* matrix (m × o) (m × o) α := +{ to_fun := block_diagonal, + map_one' := block_diagonal_one, + map_mul' := block_diagonal_mul, + ..block_diagonal_add_monoid_hom m m o α } +end + +@[simp] lemma block_diagonal_smul {R : Type*} [monoid R] [add_monoid α] [distrib_mul_action R α] + (x : R) (M : o → matrix m n α) : block_diagonal (x • M) = x • block_diagonal M := by { ext, simp only [block_diagonal_apply, pi.smul_apply], split_ifs; simp } end block_diagonal section block_diagonal' -variables (M N : Π i, matrix (m' i) (n' i) α) [decidable_eq o] +variables [decidable_eq o] section has_zero @@ -325,7 +342,7 @@ variables [has_zero α] [has_zero β] and zero elsewhere. This is the dependently-typed version of `matrix.block_diagonal`. -/ -def block_diagonal' : matrix (Σ i, m' i) (Σ i, n' i) α +def block_diagonal' (M : Π i, matrix (m' i) (n' i) α) : matrix (Σ i, m' i) (Σ i, n' i) α | ⟨k, i⟩ ⟨k', j⟩ := if h : k = k' then M k i (cast (congr_arg n' h.symm) j) else 0 lemma block_diagonal'_eq_block_diagonal (M : o → matrix m n α) {k k'} (i j) : @@ -337,21 +354,21 @@ lemma block_diagonal'_minor_eq_block_diagonal (M : o → matrix m n α) : block_diagonal M := matrix.ext $ λ ⟨k, i⟩ ⟨k', j⟩, rfl -lemma block_diagonal'_apply (ik jk) : +lemma block_diagonal'_apply (M : Π i, matrix (m' i) (n' i) α) (ik jk) : block_diagonal' M ik jk = if h : ik.1 = jk.1 then M ik.1 ik.2 (cast (congr_arg n' h.symm) jk.2) else 0 := by { cases ik, cases jk, refl } @[simp] -lemma block_diagonal'_apply_eq (k i j) : +lemma block_diagonal'_apply_eq (M : Π i, matrix (m' i) (n' i) α) (k i j) : block_diagonal' M ⟨k, i⟩ ⟨k, j⟩ = M k i j := dif_pos rfl -lemma block_diagonal'_apply_ne {k k'} (i j) (h : k ≠ k') : +lemma block_diagonal'_apply_ne (M : Π i, matrix (m' i) (n' i) α) {k k'} (i j) (h : k ≠ k') : block_diagonal' M ⟨k, i⟩ ⟨k', j⟩ = 0 := dif_neg h -lemma block_diagonal'_map (f : α → β) (hf : f 0 = 0) : +lemma block_diagonal'_map (M : Π i, matrix (m' i) (n' i) α) (f : α → β) (hf : f 0 = 0) : (block_diagonal' M).map f = block_diagonal' (λ k, (M k).map f) := begin ext, @@ -359,7 +376,7 @@ begin rw [apply_dite f, hf], end -@[simp] lemma block_diagonal'_transpose : +@[simp] lemma block_diagonal'_transpose (M : Π i, matrix (m' i) (n' i) α) : (block_diagonal' M)ᵀ = block_diagonal' (λ k, (M k)ᵀ) := begin ext ⟨ii, ix⟩ ⟨ji, jx⟩, @@ -367,7 +384,7 @@ begin split_ifs; cc end -@[simp] lemma block_diagonal'_conj_transpose {α} [semiring α] [star_ring α] +@[simp] lemma block_diagonal'_conj_transpose {α} [add_monoid α] [star_add_monoid α] (M : Π i, matrix (m' i) (n' i) α) : (block_diagonal' M)ᴴ = block_diagonal' (λ k, (M k)ᴴ) := begin @@ -379,12 +396,14 @@ end block_diagonal' (0 : Π i, matrix (m' i) (n' i) α) = 0 := by { ext, simp [block_diagonal'_apply] } -@[simp] lemma block_diagonal'_diagonal [∀ i, decidable_eq (m' i)] (d : Π i, m' i → α) : +@[simp] lemma block_diagonal'_diagonal [Π i, decidable_eq (m' i)] (d : Π i, m' i → α) : block_diagonal' (λ k, diagonal (d k)) = diagonal (λ ik, d ik.1 ik.2) := begin ext ⟨i, k⟩ ⟨j, k'⟩, simp only [block_diagonal'_apply, diagonal], - split_ifs; cc + obtain rfl | hij := decidable.eq_or_ne i j, + { simp, }, + { simp [hij] }, end @[simp] lemma block_diagonal'_one [∀ i, decidable_eq (m' i)] [has_one α] : @@ -394,7 +413,7 @@ by rw [block_diagonal'_diagonal] end has_zero -@[simp] lemma block_diagonal'_add [add_monoid α] : +@[simp] lemma block_diagonal'_add [add_zero_class α] (M N : Π i, matrix (m' i) (n' i) α) : block_diagonal' (M + N) = block_diagonal' M + block_diagonal' N := begin ext, @@ -402,21 +421,29 @@ begin split_ifs; simp end -@[simp] lemma block_diagonal'_neg [add_group α] : - block_diagonal' (-M) = - block_diagonal' M := -begin - ext, - simp only [block_diagonal'_apply, pi.neg_apply], - split_ifs; simp + +section +variables (m' n' α) +/-- `matrix.block_diagonal'` as an `add_monoid_hom`. -/ +@[simps] def block_diagonal'_add_monoid_hom [add_zero_class α] : + (Π i, matrix (m' i) (n' i) α) →+ matrix (Σ i, m' i) (Σ i, n' i) α := +{ to_fun := block_diagonal', + map_zero' := block_diagonal'_zero, + map_add' := block_diagonal'_add } end -@[simp] lemma block_diagonal'_sub [add_group α] : +@[simp] lemma block_diagonal'_neg [add_group α] (M : Π i, matrix (m' i) (n' i) α) : + block_diagonal' (-M) = - block_diagonal' M := +map_neg (block_diagonal'_add_monoid_hom m' n' α) M + +@[simp] lemma block_diagonal'_sub [add_group α] (M N : Π i, matrix (m' i) (n' i) α) : block_diagonal' (M - N) = block_diagonal' M - block_diagonal' N := -by simp [sub_eq_add_neg] +map_sub (block_diagonal'_add_monoid_hom m' n' α) M N -@[simp] lemma block_diagonal'_mul {p : o → Type*} [semiring α] [Π i, fintype (n' i)] [fintype o] - (N : Π i, matrix (n' i) (p i) α) : - block_diagonal' (λ k, M k ⬝ N k) = block_diagonal' M ⬝ block_diagonal' N := +@[simp] lemma block_diagonal'_mul [non_unital_non_assoc_semiring α] + [Π i, fintype (n' i)] [fintype o] + (M : Π i, matrix (m' i) (n' i) α) (N : Π i, matrix (n' i) (p' i) α) : + block_diagonal' (λ k, M k ⬝ N k) = block_diagonal' M ⬝ block_diagonal' N := begin ext ⟨k, i⟩ ⟨k', j⟩, simp only [block_diagonal'_apply, mul_apply, ← finset.univ_sigma_univ, finset.sum_sigma], @@ -425,8 +452,21 @@ begin { intros j' hj', exact finset.sum_eq_zero (λ _ _, by rw [dif_neg hj'.symm, zero_mul]) }, end +section +variables (α m') +/-- `matrix.block_diagonal'` as a `ring_hom`. -/ +@[simps] +def block_diagonal'_ring_hom [Π i, decidable_eq (m' i)] [fintype o] [Π i, fintype (m' i)] + [non_assoc_semiring α] : + (Π i, matrix (m' i) (m' i) α) →+* matrix (Σ i, m' i) (Σ i, m' i) α := +{ to_fun := block_diagonal', + map_one' := block_diagonal'_one, + map_mul' := block_diagonal'_mul, + ..block_diagonal'_add_monoid_hom m' m' α } +end + @[simp] lemma block_diagonal'_smul {R : Type*} [semiring R] [add_comm_monoid α] [module R α] - (x : R) : block_diagonal' (x • M) = x • block_diagonal' M := + (x : R) (M : Π i, matrix (m' i) (n' i) α) : block_diagonal' (x • M) = x • block_diagonal' M := by { ext, simp only [block_diagonal'_apply, pi.smul_apply], split_ifs; simp } end block_diagonal' From 828ef48c26d54d92709b93b8487d791945b1ed97 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Tue, 19 Apr 2022 05:04:57 +0000 Subject: [PATCH 074/373] fix(category_theory/monoidal): increase class search depth in coherence tactic (#13413) There were two places, not just one, where the class search depth needs to be increased. Co-authored-by: Scott Morrison --- src/category_theory/monoidal/braided.lean | 2 -- src/category_theory/monoidal/coherence.lean | 8 +++++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/category_theory/monoidal/braided.lean b/src/category_theory/monoidal/braided.lean index 2cf768de59670..fa2a6de44e94d 100644 --- a/src/category_theory/monoidal/braided.lean +++ b/src/category_theory/monoidal/braided.lean @@ -412,8 +412,6 @@ begin tensor_comp, tensor_comp] }, end -set_option class.instance_max_depth 64 - lemma tensor_associativity (X₁ X₂ Y₁ Y₂ Z₁ Z₂ : C) : (tensor_μ C (X₁, X₂) (Y₁, Y₂) ⊗ 𝟙 (Z₁ ⊗ Z₂)) ≫ tensor_μ C (X₁ ⊗ Y₁, X₂ ⊗ Y₂) (Z₁, Z₂) ≫ diff --git a/src/category_theory/monoidal/coherence.lean b/src/category_theory/monoidal/coherence.lean index b671cc90aa3f3..56a222dd23af6 100644 --- a/src/category_theory/monoidal/coherence.lean +++ b/src/category_theory/monoidal/coherence.lean @@ -241,9 +241,11 @@ where `f₀` and `g₀` are maximal prefixes of `f` and `g` (possibly after reas which are "liftable" (i.e. expressible as compositions of unitors and associators). -/ meta def liftable_prefixes : tactic unit := -try `[simp only [monoidal_comp, category_theory.category.assoc]] >> - `[apply (cancel_epi (𝟙 _)).1; try { apply_instance }] >> - try `[simp only [tactic.coherence.assoc_lift_hom]] +do + o ← get_options, set_options $ o.set_nat `class.instance_max_depth 128, + try `[simp only [monoidal_comp, category_theory.category.assoc]] >> + `[apply (cancel_epi (𝟙 _)).1; try { apply_instance }] >> + try `[simp only [tactic.coherence.assoc_lift_hom]] example {W X Y Z : C} (f : Y ⟶ Z) (g) (w : false) : (λ_ _).hom ≫ f = g := begin From d19e8cb7f24b33c79600bed337033ce9d993de9d Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Tue, 19 Apr 2022 06:50:55 +0000 Subject: [PATCH 075/373] chore(docs): don't use deprecated is_subring (#13505) Co-authored-by: Scott Morrison --- docs/overview.yaml | 2 +- docs/undergrad.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/overview.yaml b/docs/overview.yaml index 32a91cba3a168..0e0148deb8825 100644 --- a/docs/overview.yaml +++ b/docs/overview.yaml @@ -51,7 +51,7 @@ General algebra: ring: 'ring' ring morphism: 'ring_hom' the category of rings: 'Ring' - subring: 'is_subring' + subring: 'subring' localization: 'localization' local ring: 'local_ring' noetherian ring: 'is_noetherian_ring' diff --git a/docs/undergrad.yaml b/docs/undergrad.yaml index e5e7aef2c4559..1432c5fd43159 100644 --- a/docs/undergrad.yaml +++ b/docs/undergrad.yaml @@ -124,7 +124,7 @@ Group Theory: Ring Theory: Fundamentals: ring: 'ring' - subrings: 'is_subring' + subrings: 'subring' ring morphisms: 'ring_hom' ring structure $\Z$: 'int.comm_ring' product of rings: 'pi.ring' From 9202b6d1d471f6020dd6b9c6b99fcf821e385406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 19 Apr 2022 08:07:49 +0000 Subject: [PATCH 076/373] feat(order/succ_pred/basic): Intervals and `succ`/`pred` (#13486) Relate `order.succ`, `order.pred` and `set.Ixx`. --- src/analysis/calculus/cont_diff.lean | 2 +- src/data/set/basic.lean | 25 +++-- src/data/set/intervals/basic.lean | 21 ++++ src/data/set/intervals/ord_connected.lean | 5 +- src/logic/basic.lean | 12 +++ src/order/succ_pred/basic.lean | 120 +++++++++++++++++++--- 6 files changed, 158 insertions(+), 27 deletions(-) diff --git a/src/analysis/calculus/cont_diff.lean b/src/analysis/calculus/cont_diff.lean index ef702fa4444f4..af3830268d99f 100644 --- a/src/analysis/calculus/cont_diff.lean +++ b/src/analysis/calculus/cont_diff.lean @@ -2803,7 +2803,7 @@ begin rcases metric.mem_nhds_within_iff.mp hst with ⟨ε, ε0, hε⟩, replace hp : has_ftaylor_series_up_to_on 1 f p (metric.ball x ε ∩ insert x s) := hp.mono hε, clear hst hε t, - rw [← insert_eq_of_mem (metric.mem_ball_self ε0), ← insert_inter] at hp, + rw [← insert_eq_of_mem (metric.mem_ball_self ε0), ← insert_inter_distrib] at hp, rcases hp.exists_lipschitz_on_with ((convex_ball _ _).inter hs) with ⟨K, t, hst, hft⟩, rw [inter_comm, ← nhds_within_restrict' _ (metric.ball_mem_nhds _ ε0)] at hst, exact ⟨K, t, hst, hft⟩ diff --git a/src/data/set/basic.lean b/src/data/set/basic.lean index 15eacf6aba492..4cad16996589f 100644 --- a/src/data/set/basic.lean +++ b/src/data/set/basic.lean @@ -691,9 +691,12 @@ theorem insert_nonempty (a : α) (s : set α) : (insert a s).nonempty := ⟨a, m instance (a : α) (s : set α) : nonempty (insert a s : set α) := (insert_nonempty a s).to_subtype -lemma insert_inter (x : α) (s t : set α) : insert x (s ∩ t) = insert x s ∩ insert x t := +lemma insert_inter_distrib (a : α) (s t : set α) : insert a (s ∩ t) = insert a s ∩ insert a t := ext $ λ y, or_and_distrib_left +lemma insert_union_distrib (a : α) (s t : set α) : insert a (s ∪ t) = insert a s ∪ insert a t := +ext $ λ _, or_or_distrib_left _ _ _ + lemma insert_inj (ha : a ∉ s) : insert a s = insert b s ↔ a = b := ⟨λ h, eq_of_not_mem_of_mem_insert (h.subst $ mem_insert a s) ha, congr_arg _⟩ @@ -1074,17 +1077,17 @@ begin exact h, end -lemma insert_inter_of_mem {s₁ s₂ : set α} {a : α} (h : a ∈ s₂) : - insert a s₁ ∩ s₂ = insert a (s₁ ∩ s₂) := -by simp [set.insert_inter, h] +lemma inter_insert_of_mem (h : a ∈ s) : s ∩ insert a t = insert a (s ∩ t) := +by rw [insert_inter_distrib, insert_eq_of_mem h] -lemma insert_inter_of_not_mem {s₁ s₂ : set α} {a : α} (h : a ∉ s₂) : - insert a s₁ ∩ s₂ = s₁ ∩ s₂ := -begin - ext x, - simp only [mem_inter_iff, mem_insert_iff, mem_inter_eq, and.congr_left_iff, or_iff_right_iff_imp], - cc, -end +lemma insert_inter_of_mem (h : a ∈ t) : insert a s ∩ t = insert a (s ∩ t) := +by rw [insert_inter_distrib, insert_eq_of_mem h] + +lemma inter_insert_of_not_mem (h : a ∉ s) : s ∩ insert a t = s ∩ t := +ext $ λ x, and_congr_right $ λ hx, or_iff_right $ ne_of_mem_of_not_mem hx h + +lemma insert_inter_of_not_mem (h : a ∉ t) : insert a s ∩ t = s ∩ t := +ext $ λ x, and_congr_left $ λ hx, or_iff_right $ ne_of_mem_of_not_mem hx h @[simp] theorem union_diff_self {s t : set α} : s ∪ (t \ s) = s ∪ t := sup_sdiff_self_right diff --git a/src/data/set/intervals/basic.lean b/src/data/set/intervals/basic.lean index 555ee29523fdb..ce8edd65c4dd7 100644 --- a/src/data/set/intervals/basic.lean +++ b/src/data/set/intervals/basic.lean @@ -349,6 +349,10 @@ lemma Ici_inter_Iic : Ici a ∩ Iic b = Icc a b := rfl lemma Ici_inter_Iio : Ici a ∩ Iio b = Ico a b := rfl lemma Ioi_inter_Iic : Ioi a ∩ Iic b = Ioc a b := rfl lemma Ioi_inter_Iio : Ioi a ∩ Iio b = Ioo a b := rfl +lemma Iic_inter_Ici : Iic a ∩ Ici b = Icc b a := inter_comm _ _ +lemma Iio_inter_Ici : Iio a ∩ Ici b = Ico b a := inter_comm _ _ +lemma Iic_inter_Ioi : Iic a ∩ Ioi b = Ioc b a := inter_comm _ _ +lemma Iio_inter_Ioi : Iio a ∩ Ioi b = Ioo b a := inter_comm _ _ lemma mem_Icc_of_Ioo (h : x ∈ Ioo a b) : x ∈ Icc a b := Ioo_subset_Icc_self h lemma mem_Ico_of_Ioo (h : x ∈ Ioo a b) : x ∈ Ico a b := Ioo_subset_Ico_self h @@ -456,6 +460,23 @@ by rw [← Icc_diff_left, diff_union_self, lemma Ico_union_right (hab : a ≤ b) : Ico a b ∪ {b} = Icc a b := by simpa only [dual_Ioc, dual_Icc] using Ioc_union_left hab.dual +@[simp] lemma Ico_insert_right (h : a ≤ b) : insert b (Ico a b) = Icc a b := +by rw [insert_eq, union_comm, Ico_union_right h] + +@[simp] lemma Ioc_insert_left (h : a ≤ b) : insert a (Ioc a b) = Icc a b := +by rw [insert_eq, union_comm, Ioc_union_left h] + +@[simp] lemma Ioo_insert_left (h : a < b) : insert a (Ioo a b) = Ico a b := +by rw [insert_eq, union_comm, Ioo_union_left h] + +@[simp] lemma Ioo_insert_right (h : a < b) : insert b (Ioo a b) = Ioc a b := +by rw [insert_eq, union_comm, Ioo_union_right h] + +@[simp] lemma Iio_insert : insert a (Iio a) = Iic a := ext $ λ _, le_iff_eq_or_lt.symm + +@[simp] lemma Ioi_insert : insert a (Ioi a) = Ici a := +ext $ λ _, (or_congr_left' eq_comm).trans le_iff_eq_or_lt.symm + lemma mem_Ici_Ioi_of_subset_of_subset {s : set α} (ho : Ioi a ⊆ s) (hc : s ⊆ Ici a) : s ∈ ({Ici a, Ioi a} : set (set α)) := classical.by_cases diff --git a/src/data/set/intervals/ord_connected.lean b/src/data/set/intervals/ord_connected.lean index ea5ec9eaed14f..a5c6c574d857c 100644 --- a/src/data/set/intervals/ord_connected.lean +++ b/src/data/set/intervals/ord_connected.lean @@ -49,9 +49,8 @@ begin rw ord_connected_iff, intros x hx y hy hxy, rcases eq_or_lt_of_le hxy with rfl|hxy', { simpa }, - have := hs x hx y hy hxy', - rw [← union_diff_cancel Ioo_subset_Icc_self], - simp [*, insert_subset] + rw [←Ioc_insert_left hxy, ←Ioo_insert_right hxy'], + exact insert_subset.2 ⟨hx, insert_subset.2 ⟨hy, hs x hx y hy hxy'⟩⟩, end protected lemma Icc_subset (s : set α) [hs : ord_connected s] {x y} (hx : x ∈ s) (hy : y ∈ s) : diff --git a/src/logic/basic.lean b/src/logic/basic.lean index 7ba854bd9a54b..571a140f04b96 100644 --- a/src/logic/basic.lean +++ b/src/logic/basic.lean @@ -442,6 +442,12 @@ by simp only [and.left_comm, and.comm] lemma and_and_and_comm (a b c d : Prop) : (a ∧ b) ∧ c ∧ d ↔ (a ∧ c) ∧ b ∧ d := by rw [←and_assoc, @and.right_comm a, and_assoc] +lemma and_and_distrib_left (a b c : Prop) : a ∧ (b ∧ c) ↔ (a ∧ b) ∧ (a ∧ c) := +by rw [and_and_and_comm, and_self] + +lemma and_and_distrib_right (a b c : Prop) : (a ∧ b) ∧ c ↔ (a ∧ c) ∧ (b ∧ c) := +by rw [and_and_and_comm, and_self] + lemma and_rotate : a ∧ b ∧ c ↔ b ∧ c ∧ a := by simp only [and.left_comm, and.comm] lemma and.rotate : a ∧ b ∧ c → b ∧ c ∧ a := and_rotate.1 @@ -493,6 +499,12 @@ theorem or.right_comm : (a ∨ b) ∨ c ↔ (a ∨ c) ∨ b := by rw [or_assoc, lemma or_or_or_comm (a b c d : Prop) : (a ∨ b) ∨ c ∨ d ↔ (a ∨ c) ∨ b ∨ d := by rw [←or_assoc, @or.right_comm a, or_assoc] +lemma or_or_distrib_left (a b c : Prop) : a ∨ (b ∨ c) ↔ (a ∨ b) ∨ (a ∨ c) := +by rw [or_or_or_comm, or_self] + +lemma or_or_distrib_right (a b c : Prop) : (a ∨ b) ∨ c ↔ (a ∨ c) ∨ (b ∨ c) := +by rw [or_or_or_comm, or_self] + lemma or_rotate : a ∨ b ∨ c ↔ b ∨ c ∨ a := by simp only [or.left_comm, or.comm] lemma or.rotate : a ∨ b ∨ c → b ∨ c ∨ a := or_rotate.1 diff --git a/src/order/succ_pred/basic.lean b/src/order/succ_pred/basic.lean index 2689e59fdaafc..a4839b7a2de11 100644 --- a/src/order/succ_pred/basic.lean +++ b/src/order/succ_pred/basic.lean @@ -182,6 +182,18 @@ set.ext $ λ x, lt_succ_iff_of_not_is_max ha lemma Ici_succ_of_not_is_max (ha : ¬ is_max a) : Ici (succ a) = Ioi a := set.ext $ λ x, succ_le_iff_of_not_is_max ha +lemma Ico_succ_right_of_not_is_max (hb : ¬ is_max b) : Ico a (succ b) = Icc a b := +by rw [←Ici_inter_Iio, Iio_succ_of_not_is_max hb, Ici_inter_Iic] + +lemma Ioo_succ_right_of_not_is_max (hb : ¬ is_max b) : Ioo a (succ b) = Ioc a b := +by rw [←Ioi_inter_Iio, Iio_succ_of_not_is_max hb, Ioi_inter_Iic] + +lemma Icc_succ_left_of_not_is_max (ha : ¬ is_max a) : Icc (succ a) b = Ioc a b := +by rw [←Ici_inter_Iic, Ici_succ_of_not_is_max ha, Ioi_inter_Iic] + +lemma Ico_succ_left_of_not_is_max (ha : ¬ is_max a) : Ico (succ a) b = Ioo a b := +by rw [←Ici_inter_Iio, Ici_succ_of_not_is_max ha, Ioi_inter_Iio] + section no_max_order variables [no_max_order α] @@ -202,8 +214,20 @@ lemma succ_strict_mono : strict_mono (succ : α → α) := λ a b, succ_lt_succ lemma covby_succ (a : α) : a ⋖ succ a := covby_succ_of_not_is_max $ not_is_max a -lemma Iio_succ (a : α) : Iio (succ a) = Iic a := Iio_succ_of_not_is_max $ not_is_max a -lemma Ici_succ (a : α) : Ici (succ a) = Ioi a := Ici_succ_of_not_is_max $ not_is_max a +@[simp] lemma Iio_succ (a : α) : Iio (succ a) = Iic a := Iio_succ_of_not_is_max $ not_is_max _ +@[simp] lemma Ici_succ (a : α) : Ici (succ a) = Ioi a := Ici_succ_of_not_is_max $ not_is_max _ + +lemma Ico_succ_right (a b : α) : Ico a (succ b) = Icc a b := +Ico_succ_right_of_not_is_max $ not_is_max _ + +lemma Ioo_succ_right (a b : α) : Ioo a (succ b) = Ioc a b := +Ioo_succ_right_of_not_is_max $ not_is_max _ + +lemma Icc_succ_left (a b : α) : Icc (succ a) b = Ioc a b := +Icc_succ_left_of_not_is_max $ not_is_max _ + +lemma Ico_succ_left (a b : α) : Ico (succ a) b = Ioo a b := +Ico_succ_left_of_not_is_max $ not_is_max _ end no_max_order end preorder @@ -228,6 +252,24 @@ end lemma _root_.covby.succ_eq (h : a ⋖ b) : succ a = b := (succ_le_of_lt h.lt).eq_of_not_lt $ λ h', h.2 (lt_succ_of_not_is_max h.lt.not_is_max) h' +lemma le_succ_iff_eq_or_le : a ≤ succ b ↔ a = succ b ∨ a ≤ b := +begin + by_cases hb : is_max b, + { rw [hb.succ_eq, or_iff_right_of_imp le_of_eq] }, + { rw [←lt_succ_iff_of_not_is_max hb, le_iff_eq_or_lt] } +end + +lemma lt_succ_iff_eq_or_lt_of_not_is_max (hb : ¬ is_max b) : a < succ b ↔ a = b ∨ a < b := +(lt_succ_iff_of_not_is_max hb).trans le_iff_eq_or_lt + +lemma Iic_succ (a : α) : Iic (succ a) = insert (succ a) (Iic a) := ext $ λ _, le_succ_iff_eq_or_le + +lemma Icc_succ_right (h : a ≤ succ b) : Icc a (succ b) = insert (succ b) (Icc a b) := +by simp_rw [←Ici_inter_Iic, Iic_succ, inter_insert_of_mem (mem_Ici.2 h)] + +lemma Ioc_succ_right (h : a < succ b) : Ioc a (succ b) = insert (succ b) (Ioc a b) := +by simp_rw [←Ioi_inter_Iic, Iic_succ, inter_insert_of_mem (mem_Ioi.2 h)] + section no_max_order variables [no_max_order α] @@ -239,14 +281,20 @@ lemma succ_ne_succ_iff : succ a ≠ succ b ↔ a ≠ b := succ_injective.ne_iff alias succ_ne_succ_iff ↔ _ order.succ_ne_succ -lemma lt_succ_iff_lt_or_eq : a < succ b ↔ a < b ∨ a = b := lt_succ_iff.trans le_iff_lt_or_eq - -lemma le_succ_iff_lt_or_eq : a ≤ succ b ↔ a ≤ b ∨ a = succ b := -by rw [←lt_succ_iff, ←lt_succ_iff, lt_succ_iff_lt_or_eq] +lemma lt_succ_iff_eq_or_lt : a < succ b ↔ a = b ∨ a < b := lt_succ_iff.trans le_iff_eq_or_lt lemma succ_eq_iff_covby : succ a = b ↔ a ⋖ b := ⟨by { rintro rfl, exact covby_succ _ }, covby.succ_eq⟩ +lemma Iio_succ_eq_insert (a : α) : Iio (succ a) = insert a (Iio a) := +ext $ λ _, lt_succ_iff_eq_or_lt + +lemma Ico_succ_right_eq_insert (h : a ≤ b) : Ico a (succ b) = insert b (Ico a b) := +by simp_rw [←Iio_inter_Ici, Iio_succ_eq_insert, insert_inter_of_mem (mem_Ici.2 h)] + +lemma Ioo_succ_right_eq_insert (h : a < b) : Ioo a (succ b) = insert b (Ioo a b) := +by simp_rw [←Iio_inter_Ioi, Iio_succ_eq_insert, insert_inter_of_mem (mem_Ioi.2 h)] + end no_max_order section order_top @@ -335,6 +383,18 @@ set.ext $ λ x, pred_lt_iff_of_not_is_min ha lemma Iic_pred_of_not_is_min (ha : ¬ is_min a) : Iic (pred a) = Iio a := set.ext $ λ x, le_pred_iff_of_not_is_min ha +lemma Ioc_pred_left_of_not_is_min (ha : ¬ is_min a) : Ioc (pred a) b = Icc a b := +by rw [←Ioi_inter_Iic, Ioi_pred_of_not_is_min ha, Ici_inter_Iic] + +lemma Ioo_pred_left_of_not_is_min (ha : ¬ is_min a) : Ioo (pred a) b = Ico a b := +by rw [←Ioi_inter_Iio, Ioi_pred_of_not_is_min ha, Ici_inter_Iio] + +lemma Icc_pred_right_of_not_is_min (ha : ¬ is_min b) : Icc a (pred b) = Ico a b := +by rw [←Ici_inter_Iic, Iic_pred_of_not_is_min ha, Ici_inter_Iio] + +lemma Ioc_pred_right_of_not_is_min (ha : ¬ is_min b) : Ioc a (pred b) = Ioo a b := +by rw [←Ioi_inter_Iic, Iic_pred_of_not_is_min ha, Ioi_inter_Iio] + section no_min_order variables [no_min_order α] @@ -355,8 +415,20 @@ lemma pred_strict_mono : strict_mono (pred : α → α) := λ a b, pred_lt_pred lemma pred_covby (a : α) : pred a ⋖ a := pred_covby_of_not_is_min $ not_is_min a -lemma Ioi_pred (a : α) : Ioi (pred a) = Ici a := Ioi_pred_of_not_is_min $ not_is_min a -lemma Iic_pred (a : α) : Iic (pred a) = Iio a := Iic_pred_of_not_is_min $ not_is_min a +@[simp] lemma Ioi_pred (a : α) : Ioi (pred a) = Ici a := Ioi_pred_of_not_is_min $ not_is_min a +@[simp] lemma Iic_pred (a : α) : Iic (pred a) = Iio a := Iic_pred_of_not_is_min $ not_is_min a + +lemma Ioc_pred_left (a b : α) : Ioc (pred a) b = Icc a b := +Ioc_pred_left_of_not_is_min $ not_is_min _ + +lemma Ioo_pred_left (a b : α) : Ioo (pred a) b = Ico a b := +Ioo_pred_left_of_not_is_min $ not_is_min _ + +lemma Icc_pred_right (a b : α) : Icc a (pred b) = Ico a b := +Icc_pred_right_of_not_is_min $ not_is_min _ + +lemma Ioc_pred_right (a b : α) : Ioc a (pred b) = Ioo a b := +Ioc_pred_right_of_not_is_min $ not_is_min _ end no_min_order end preorder @@ -381,6 +453,24 @@ end lemma _root_.covby.pred_eq {a b : α} (h : a ⋖ b) : pred b = a := (le_pred_of_lt h.lt).eq_of_not_gt $ λ h', h.2 h' $ pred_lt_of_not_is_min h.lt.not_is_min +lemma pred_le_iff_eq_or_le : pred a ≤ b ↔ b = pred a ∨ a ≤ b := +begin + by_cases ha : is_min a, + { rw [ha.pred_eq, or_iff_right_of_imp ge_of_eq] }, + { rw [←pred_lt_iff_of_not_is_min ha, le_iff_eq_or_lt, eq_comm] } +end + +lemma pred_lt_iff_eq_or_lt_of_not_is_min (ha : ¬ is_min a) : pred a < b ↔ a = b ∨ a < b := +(pred_lt_iff_of_not_is_min ha).trans le_iff_eq_or_lt + +lemma Ici_pred (a : α) : Ici (pred a) = insert (pred a) (Ici a) := ext $ λ _, pred_le_iff_eq_or_le + +lemma Icc_pred_left (h : pred a ≤ b) : Icc (pred a) b = insert (pred a) (Icc a b) := +by simp_rw [←Ici_inter_Iic, Ici_pred, insert_inter_of_mem (mem_Iic.2 h)] + +lemma Ico_pred_left (h : pred a < b) : Ico (pred a) b = insert (pred a) (Ico a b) := +by simp_rw [←Ici_inter_Iio, Ici_pred, insert_inter_of_mem (mem_Iio.2 h)] + section no_min_order variables [no_min_order α] @@ -392,14 +482,20 @@ lemma pred_ne_pred_iff : pred a ≠ pred b ↔ a ≠ b := pred_injective.ne_iff alias pred_ne_pred_iff ↔ _ order.pred_ne_pred -lemma pred_lt_iff_lt_or_eq : pred a < b ↔ a < b ∨ a = b := pred_lt_iff.trans le_iff_lt_or_eq - -lemma le_pred_iff_lt_or_eq : pred a ≤ b ↔ a ≤ b ∨ pred a = b := -by rw [←pred_lt_iff, ←pred_lt_iff, pred_lt_iff_lt_or_eq] +lemma pred_lt_iff_eq_or_lt : pred a < b ↔ a = b ∨ a < b := pred_lt_iff.trans le_iff_eq_or_lt lemma pred_eq_iff_covby : pred b = a ↔ a ⋖ b := ⟨by { rintro rfl, exact pred_covby _ }, covby.pred_eq⟩ +lemma Ioi_pred_eq_insert (a : α) : Ioi (pred a) = insert a (Ioi a) := +ext $ λ _, pred_lt_iff_eq_or_lt.trans $ or_congr_left' eq_comm + +lemma Ico_pred_right_eq_insert (h : a ≤ b) : Ioc (pred a) b = insert a (Ioc a b) := +by simp_rw [←Ioi_inter_Iic, Ioi_pred_eq_insert, insert_inter_of_mem (mem_Iic.2 h)] + +lemma Ioo_pred_right_eq_insert (h : a < b) : Ioo (pred a) b = insert a (Ioo a b) := +by simp_rw [←Ioi_inter_Iio, Ioi_pred_eq_insert, insert_inter_of_mem (mem_Iio.2 h)] + end no_min_order section order_bot From 5a4bae1158b5503def0d5b417c82578bc1b7b009 Mon Sep 17 00:00:00 2001 From: Eric Rodriguez Date: Tue, 19 Apr 2022 10:05:03 +0000 Subject: [PATCH 077/373] feat(algebra/*/basic): add trivial lemmas (#13416) These save you from having to fiddle with `mul_one` when you want to rewrite them the other way, or allow easier commutativity rewrites. Co-authored-by: Eric Rodriguez <37984851+ericrbg@users.noreply.github.com> --- src/algebra/group/basic.lean | 8 ++++++++ src/algebra/ring/basic.lean | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/algebra/group/basic.lean b/src/algebra/group/basic.lean index f284d8504570b..a204850bec373 100644 --- a/src/algebra/group/basic.lean +++ b/src/algebra/group/basic.lean @@ -104,6 +104,14 @@ right_comm has_mul.mul mul_comm mul_assoc theorem mul_mul_mul_comm (a b c d : G) : (a * b) * (c * d) = (a * c) * (b * d) := by simp only [mul_left_comm, mul_assoc] +@[to_additive] +lemma mul_rotate (a b c : G) : a * b * c = b * c * a := +by simp only [mul_left_comm, mul_comm] + +@[to_additive] +lemma mul_rotate' (a b c : G) : a * (b * c) = b * (c * a) := +by simp only [mul_left_comm, mul_comm] + end comm_semigroup local attribute [simp] mul_assoc sub_eq_add_neg diff --git a/src/algebra/ring/basic.lean b/src/algebra/ring/basic.lean index c6dd76f349319..57bcef0fa13e1 100644 --- a/src/algebra/ring/basic.lean +++ b/src/algebra/ring/basic.lean @@ -231,6 +231,15 @@ end non_unital_semiring section non_assoc_semiring variables [non_assoc_semiring α] +lemma add_one_mul (a b : α) : (a + 1) * b = a * b + b := +by rw [add_mul, one_mul] +lemma mul_add_one (a b : α) : a * (b + 1) = a * b + a := +by rw [mul_add, mul_one] +lemma one_add_mul (a b : α) : (1 + a) * b = b + a * b := +by rw [add_mul, one_mul] +lemma mul_one_add (a b : α) : a * (1 + b) = a + a * b := +by rw [mul_add, mul_one] + theorem two_mul (n : α) : 2 * n = n + n := eq.trans (right_distrib 1 1 n) (by simp) @@ -855,6 +864,15 @@ protected def function.surjective.non_assoc_ring { .. hf.add_comm_group f zero add neg sub nsmul gsmul, .. hf.mul_zero_class f zero mul, .. hf.distrib f add mul, .. hf.mul_one_class f one mul } +lemma sub_one_mul (a b : α) : (a - 1) * b = a * b - b := +by rw [sub_mul, one_mul] +lemma mul_sub_one (a b : α) : a * (b - 1) = a * b - a := +by rw [mul_sub, mul_one] +lemma one_sub_mul (a b : α) : (1 - a) * b = b - a * b := +by rw [sub_mul, one_mul] +lemma mul_one_sub (a b : α) : a * (1 - b) = a - a * b := +by rw [mul_sub, mul_one] + end non_assoc_ring /-- A ring is a type with the following structures: additive commutative group (`add_comm_group`), From 3e78c23763f821fb355c2b37f2cc0d43a5c1c854 Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Tue, 19 Apr 2022 12:11:00 +0000 Subject: [PATCH 078/373] fix(algebra/hom/units): better defeq in `is_unit.lift_right` (#13508) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … and fix a timeout introduced by this change and remove some extraneous parentheses there. --- src/algebra/hom/units.lean | 6 +++--- src/algebraic_geometry/structure_sheaf.lean | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/algebra/hom/units.lean b/src/algebra/hom/units.lean index 842c807b47e1d..81ed23832af68 100644 --- a/src/algebra/hom/units.lean +++ b/src/algebra/hom/units.lean @@ -109,7 +109,7 @@ to `f : M →* Nˣ`. See also `units.lift_right` for a computable version. -/ lifted to `f : M →+ add_units N`. See also `add_units.lift_right` for a computable version."] noncomputable def is_unit.lift_right [monoid M] [monoid N] (f : M →* N) (hf : ∀ x, is_unit (f x)) : M →* Nˣ := -units.lift_right f (λ x, classical.some (hf x)) $ λ x, classical.some_spec (hf x) +units.lift_right f (λ x, (hf x).unit) $ λ x, rfl @[to_additive] lemma is_unit.coe_lift_right [monoid M] [monoid N] (f : M →* N) (hf : ∀ x, is_unit (f x)) (x) : @@ -118,10 +118,10 @@ units.coe_lift_right _ x @[simp, to_additive] lemma is_unit.mul_lift_right_inv [monoid M] [monoid N] (f : M →* N) (h : ∀ x, is_unit (f x)) (x) : f x * ↑(is_unit.lift_right f h x)⁻¹ = 1 := -units.mul_lift_right_inv (λ y, classical.some_spec $ h y) x +units.mul_lift_right_inv (λ y, rfl) x @[simp, to_additive] lemma is_unit.lift_right_inv_mul [monoid M] [monoid N] (f : M →* N) (h : ∀ x, is_unit (f x)) (x) : ↑(is_unit.lift_right f h x)⁻¹ * f x = 1 := -units.lift_right_inv_mul (λ y, classical.some_spec $ h y) x +units.lift_right_inv_mul (λ y, rfl) x end is_unit diff --git a/src/algebraic_geometry/structure_sheaf.lean b/src/algebraic_geometry/structure_sheaf.lean index d406b63a9519c..f80c5316ccc7a 100644 --- a/src/algebraic_geometry/structure_sheaf.lean +++ b/src/algebraic_geometry/structure_sheaf.lean @@ -857,9 +857,10 @@ instance to_basic_open_epi (r : R) : epi (to_open R (basic_open r)) := swap 5, exact is_localization.to_basic_open R r, exact h }⟩ @[elementwise] lemma to_global_factors : to_open R ⊤ = - (CommRing.of_hom (algebra_map R (localization.away (1 : R)))) ≫ (to_basic_open R (1 : R)) ≫ + CommRing.of_hom (algebra_map R (localization.away (1 : R))) ≫ to_basic_open R (1 : R) ≫ (structure_sheaf R).1.map (eq_to_hom (basic_open_one.symm)).op := begin + rw ← category.assoc, change to_open R ⊤ = (to_basic_open R 1).comp _ ≫ _, unfold CommRing.of_hom, rw [localization_to_basic_open R, to_open_res], From 8f7e10b888790ecc06c938ad55b4dcadabda7fdf Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Tue, 19 Apr 2022 14:04:44 +0000 Subject: [PATCH 079/373] refactor(group_theory/group_action/big_operators): extract to a new file (#13340) `basic` is a misleading name, as `group_action.basic` imports a lot of things. For now I'm not renaming it, but I've adding a skeletal docstring. Splitting out the big operator lemmas allows access to big operators before modules and quotients. This also performs a drive-by generalization of the typeclasses on `smul_cancel_of_non_zero_divisor`. Authorship is from #1910 --- src/algebra/hom/group_action.lean | 10 +-- src/algebra/module/basic.lean | 1 + src/data/dfinsupp/interval.lean | 1 + src/data/finset/finsupp.lean | 1 + src/group_theory/group_action/basic.lean | 67 ++++++------------- .../group_action/big_operators.lean | 63 +++++++++++++++++ 6 files changed, 89 insertions(+), 54 deletions(-) create mode 100644 src/group_theory/group_action/big_operators.lean diff --git a/src/algebra/hom/group_action.lean b/src/algebra/hom/group_action.lean index c3cfce8f23c85..55bc58e280721 100644 --- a/src/algebra/hom/group_action.lean +++ b/src/algebra/hom/group_action.lean @@ -3,8 +3,8 @@ Copyright (c) 2020 Kenny Lau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau -/ -import group_theory.group_action.basic import algebra.group_ring_action +import group_theory.group_action.defs /-! # Equivariant homomorphisms @@ -106,14 +106,6 @@ variables {A B} ... = g (f (m • (g x))) : by rw f.map_smul ... = m • g x : by rw h₁, } -variables {G} (H) - -/-- The canonical map to the left cosets. -/ -def to_quotient : G →[G] G ⧸ H := -⟨coe, λ g x, rfl⟩ - -@[simp] lemma to_quotient_apply (g : G) : to_quotient H g = g := rfl - end mul_action_hom /-- Equivariant additive monoid homomorphisms. -/ diff --git a/src/algebra/module/basic.lean b/src/algebra/module/basic.lean index 549ab9cfcdcfa..cbcc6cbd42a6e 100644 --- a/src/algebra/module/basic.lean +++ b/src/algebra/module/basic.lean @@ -5,6 +5,7 @@ Authors: Nathaniel Thomas, Jeremy Avigad, Johannes Hölzl, Mario Carneiro -/ import algebra.big_operators.basic import algebra.smul_with_zero +import group_theory.group_action.big_operators import group_theory.group_action.group import tactic.norm_num diff --git a/src/data/dfinsupp/interval.lean b/src/data/dfinsupp/interval.lean index 584fce78425e4..f589ac9929f4a 100644 --- a/src/data/dfinsupp/interval.lean +++ b/src/data/dfinsupp/interval.lean @@ -5,6 +5,7 @@ Authors: Yaël Dillies -/ import data.finset.locally_finite import data.finset.pointwise +import data.fintype.card import data.dfinsupp.order /-! diff --git a/src/data/finset/finsupp.lean b/src/data/finset/finsupp.lean index 758a99f8d62b7..bdff527eeafe4 100644 --- a/src/data/finset/finsupp.lean +++ b/src/data/finset/finsupp.lean @@ -5,6 +5,7 @@ Authors: Yaël Dillies -/ import data.finset.pointwise import data.finsupp.indicator +import data.fintype.card /-! # Finitely supported product of finsets diff --git a/src/group_theory/group_action/basic.lean b/src/group_theory/group_action/basic.lean index 56f3c5c7f5305..4c125527b417b 100644 --- a/src/group_theory/group_action/basic.lean +++ b/src/group_theory/group_action/basic.lean @@ -3,6 +3,7 @@ Copyright (c) 2018 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ +import algebra.hom.group_action import group_theory.group_action.defs import group_theory.group_action.group import group_theory.quotient_group @@ -11,6 +12,18 @@ import data.fintype.card /-! # Basic properties of group actions + +This file primarily concerns itself with orbits, stabilizers, and other objects defined in terms of +actions. Despite this file being called `basic`, low-level helper lemmas for algebraic manipulation +of `•` belong elsewhere. + +## Main definitions + +* `mul_action.orbit` +* `mul_action.fixed_points` +* `mul_action.fixed_by` +* `mul_action.stabilizer` + -/ universes u v w @@ -335,6 +348,13 @@ end quotient_action open quotient_group +/-- The canonical map to the left cosets. -/ +def _root_.mul_action_hom.to_quotient (H : subgroup α) : α →[α] α ⧸ H := +⟨coe, quotient.smul_coe H⟩ + +@[simp] lemma _root_.mul_action_hom.to_quotient_apply (H : subgroup α) (g : α) : + mul_action_hom.to_quotient H g = g := rfl + @[to_additive] instance mul_left_cosets_comp_subtype_val (H I : subgroup α) : mul_action I (α ⧸ H) := mul_action.comp_hom (α ⧸ H) (subgroup.subtype I) @@ -505,17 +525,11 @@ by rw [← fintype.card_prod, ← fintype.card_sigma, end mul_action -section -variables [monoid α] [add_monoid β] [distrib_mul_action α β] - -lemma list.smul_sum {r : α} {l : list β} : - r • l.sum = (l.map ((•) r)).sum := -(distrib_mul_action.to_add_monoid_hom β r).map_list_sum l - /-- `smul` by a `k : M` over a ring is injective, if `k` is not a zero divisor. The general theory of such `k` is elaborated by `is_smul_regular`. The typeclass that restricts all terms of `M` to have this property is `no_zero_smul_divisors`. -/ -lemma smul_cancel_of_non_zero_divisor {M R : Type*} [monoid M] [ring R] [distrib_mul_action M R] +lemma smul_cancel_of_non_zero_divisor {M R : Type*} + [monoid M] [non_unital_non_assoc_ring R] [distrib_mul_action M R] (k : M) (h : ∀ (x : R), k • x = 0 → x = 0) {a b : R} (h' : k • a = k • b) : a = b := begin @@ -524,43 +538,6 @@ begin rw [smul_sub, h', sub_self] end -end - -section -variables [monoid α] [monoid β] [mul_distrib_mul_action α β] - -lemma list.smul_prod {r : α} {l : list β} : - r • l.prod = (l.map ((•) r)).prod := -(mul_distrib_mul_action.to_monoid_hom β r).map_list_prod l - -end - -section -variables [monoid α] [add_comm_monoid β] [distrib_mul_action α β] - -lemma multiset.smul_sum {r : α} {s : multiset β} : - r • s.sum = (s.map ((•) r)).sum := -(distrib_mul_action.to_add_monoid_hom β r).map_multiset_sum s - -lemma finset.smul_sum {r : α} {f : γ → β} {s : finset γ} : - r • ∑ x in s, f x = ∑ x in s, r • f x := -(distrib_mul_action.to_add_monoid_hom β r).map_sum f s - -end - -section -variables [monoid α] [comm_monoid β] [mul_distrib_mul_action α β] - -lemma multiset.smul_prod {r : α} {s : multiset β} : - r • s.prod = (s.map ((•) r)).prod := -(mul_distrib_mul_action.to_monoid_hom β r).map_multiset_prod s - -lemma finset.smul_prod {r : α} {f : γ → β} {s : finset γ} : - r • ∏ x in s, f x = ∏ x in s, r • f x := -(mul_distrib_mul_action.to_monoid_hom β r).map_prod f s - -end - namespace subgroup variables {G : Type*} [group G] (H : subgroup G) diff --git a/src/group_theory/group_action/big_operators.lean b/src/group_theory/group_action/big_operators.lean new file mode 100644 index 0000000000000..f1a2ec0b17ea8 --- /dev/null +++ b/src/group_theory/group_action/big_operators.lean @@ -0,0 +1,63 @@ +/- +Copyright (c) 2020 Yury Kudryashov. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yury Kudryashov +-/ +import algebra.big_operators.basic +import data.finset.basic +import data.multiset.basic +import group_theory.group_action.defs + +/-! +# Lemmas about group actions on big operators + +Note that analogous lemmas for `module`s like `finset.sum_smul` appear in other files. +-/ + +variables {α β γ : Type*} + +open_locale big_operators + +section +variables [monoid α] [add_monoid β] [distrib_mul_action α β] + +lemma list.smul_sum {r : α} {l : list β} : + r • l.sum = (l.map ((•) r)).sum := +(distrib_mul_action.to_add_monoid_hom β r).map_list_sum l + +end + +section +variables [monoid α] [monoid β] [mul_distrib_mul_action α β] + +lemma list.smul_prod {r : α} {l : list β} : + r • l.prod = (l.map ((•) r)).prod := +(mul_distrib_mul_action.to_monoid_hom β r).map_list_prod l + +end + +section +variables [monoid α] [add_comm_monoid β] [distrib_mul_action α β] + +lemma multiset.smul_sum {r : α} {s : multiset β} : + r • s.sum = (s.map ((•) r)).sum := +(distrib_mul_action.to_add_monoid_hom β r).map_multiset_sum s + +lemma finset.smul_sum {r : α} {f : γ → β} {s : finset γ} : + r • ∑ x in s, f x = ∑ x in s, r • f x := +(distrib_mul_action.to_add_monoid_hom β r).map_sum f s + +end + +section +variables [monoid α] [comm_monoid β] [mul_distrib_mul_action α β] + +lemma multiset.smul_prod {r : α} {s : multiset β} : + r • s.prod = (s.map ((•) r)).prod := +(mul_distrib_mul_action.to_monoid_hom β r).map_multiset_prod s + +lemma finset.smul_prod {r : α} {f : γ → β} {s : finset γ} : + r • ∏ x in s, f x = ∏ x in s, r • f x := +(mul_distrib_mul_action.to_monoid_hom β r).map_prod f s + +end From ba6a9858108df1a82921bdc9be6e2b2232e90227 Mon Sep 17 00:00:00 2001 From: Floris van Doorn Date: Tue, 19 Apr 2022 14:04:45 +0000 Subject: [PATCH 080/373] feat(order/cover): define `wcovby` (#13424) * This defines the reflexive closure of `covby`, which I call `wcovby` ("weakly covered by") * This is useful, since some results about `covby` still hold for `wcovby`. * Use `wcovby` in the proofs of the properties for `covby`. * Also define `wcovby_insert` (the motivating example, since I really want `(wcovby_insert _ _).eq_or_eq`) --- src/data/set/intervals/ord_connected.lean | 15 +- src/order/cover.lean | 196 ++++++++++++++++++---- src/order/succ_pred/basic.lean | 10 +- 3 files changed, 183 insertions(+), 38 deletions(-) diff --git a/src/data/set/intervals/ord_connected.lean b/src/data/set/intervals/ord_connected.lean index a5c6c574d857c..a18dcbd8d37ea 100644 --- a/src/data/set/intervals/ord_connected.lean +++ b/src/data/set/intervals/ord_connected.lean @@ -20,7 +20,7 @@ that all standard intervals are `ord_connected`. namespace set section preorder -variables {α : Type*} [preorder α] {s t : set α} +variables {α β : Type*} [preorder α] [preorder β] {s t : set α} /-- We say that a set `s : set α` is `ord_connected` if for all `x y ∈ s` it includes the @@ -134,6 +134,19 @@ instance [densely_ordered α] {s : set α} [hs : ord_connected s] : ⟨λ a b (h : (a : α) < b), let ⟨x, H⟩ := exists_between h in ⟨⟨x, (hs.out a.2 b.2) (Ioo_subset_Icc_self H)⟩, H⟩ ⟩ +@[instance] lemma ord_connected_image {E : Type*} [order_iso_class E α β] (e : E) {s : set α} + [hs : ord_connected s] : ord_connected (e '' s) := +begin + constructor, + rintro _ ⟨x, hx, rfl⟩ _ ⟨y, hy, rfl⟩ z ⟨hxz, hzy⟩, + exact ⟨equiv_like.inv e z, hs.out hx hy ⟨(le_map_inv_iff e).mpr hxz, (map_inv_le_iff e).mpr hzy⟩, + equiv_like.right_inv e z⟩ +end + +@[instance] lemma ord_connected_range {E : Type*} [order_iso_class E α β] (e : E) : + ord_connected (range e) := +by simp_rw [← image_univ, ord_connected_image e] + end preorder section linear_order diff --git a/src/order/cover.lean b/src/order/cover.lean index f70655ca0ecd9..68f1e034d37a4 100644 --- a/src/order/cover.lean +++ b/src/order/cover.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2021 Yaël Dillies. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Yaël Dillies, Violeta Hernández Palacios, Grayson Burton +Authors: Yaël Dillies, Violeta Hernández Palacios, Grayson Burton, Floris van Doorn -/ import data.set.intervals.ord_connected @@ -9,17 +9,118 @@ import data.set.intervals.ord_connected # The covering relation This file defines the covering relation in an order. `b` is said to cover `a` if `a < b` and there -is no element in between. ∃ b, a < b +is no element in between. We say that `b` weakly covers `a` if `a ≤ b` and there is no element +between `a` and `b`. In a partial order this is equivalent to `a ⋖ b ∨ a = b`, in a preorder this +is equivalent to `a ⋖ b ∨ (a ≤ b ∧ b ≤ a)` ## Notation -`a ⋖ b` means that `b` covers `a`. +* `a ⋖ b` means that `b` covers `a`. +* `a ⩿ b` means that `b` weakly covers `a`. -/ -open set +open set order_dual variables {α β : Type*} +section weakly_covers + +section preorder +variables [preorder α] [preorder β] {a b c: α} + +/-- `wcovby a b` means that `a = b` or `b` covers `a`. +This means that `a ≤ b` and there is no element in between. +-/ +def wcovby (a b : α) : Prop := a ≤ b ∧ ∀ ⦃c⦄, a < c → ¬ c < b + +infix ` ⩿ `:50 := wcovby + +lemma wcovby.le (h : a ⩿ b) : a ≤ b := h.1 + +lemma wcovby.refl (a : α) : a ⩿ a := ⟨le_rfl, λ c hc, hc.not_lt⟩ +lemma wcovby.rfl : a ⩿ a := wcovby.refl a + +protected lemma eq.wcovby (h : a = b) : a ⩿ b := h ▸ wcovby.rfl + +lemma wcovby_of_le_of_le (h1 : a ≤ b) (h2 : b ≤ a) : a ⩿ b := +⟨h1, λ c hac hcb, (hac.trans hcb).not_le h2⟩ + +alias wcovby_of_le_of_le ← has_le.le.wcovby_of_le + +lemma wcovby.wcovby_iff_le (hab : a ⩿ b) : b ⩿ a ↔ b ≤ a := +⟨λ h, h.le, λ h, h.wcovby_of_le hab.le⟩ + +lemma wcovby_of_eq_or_eq (hab : a ≤ b) (h : ∀ c, a ≤ c → c ≤ b → c = a ∨ c = b) : a ⩿ b := +⟨hab, λ c ha hb, (h c ha.le hb.le).elim ha.ne' hb.ne⟩ + +/-- If `a ≤ b`, then `b` does not cover `a` iff there's an element in between. -/ +lemma not_wcovby_iff (h : a ≤ b) : ¬ a ⩿ b ↔ ∃ c, a < c ∧ c < b := +by simp_rw [wcovby, h, true_and, not_forall, exists_prop, not_not] + +instance wcovby.is_refl : is_refl α (⩿) := ⟨wcovby.refl⟩ + +lemma wcovby.Ioo_eq (h : a ⩿ b) : Ioo a b = ∅ := +eq_empty_iff_forall_not_mem.2 $ λ x hx, h.2 hx.1 hx.2 + +lemma wcovby.of_image (f : α ↪o β) (h : f a ⩿ f b) : a ⩿ b := +⟨f.le_iff_le.mp h.le, λ c hac hcb, h.2 (f.lt_iff_lt.mpr hac) (f.lt_iff_lt.mpr hcb)⟩ + +lemma wcovby.image (f : α ↪o β) (hab : a ⩿ b) (h : (range f).ord_connected) : f a ⩿ f b := +begin + refine ⟨f.monotone hab.le, λ c ha hb, _⟩, + obtain ⟨c, rfl⟩ := h.out (mem_range_self _) (mem_range_self _) ⟨ha.le, hb.le⟩, + rw f.lt_iff_lt at ha hb, + exact hab.2 ha hb, +end + +lemma set.ord_connected.apply_wcovby_apply_iff (f : α ↪o β) (h : (range f).ord_connected) : + f a ⩿ f b ↔ a ⩿ b := +⟨λ h2, h2.of_image f, λ hab, hab.image f h⟩ + +@[simp] lemma apply_wcovby_apply_iff {E : Type*} [order_iso_class E α β] (e : E) : + e a ⩿ e b ↔ a ⩿ b := +(ord_connected_range (e : α ≃o β)).apply_wcovby_apply_iff ((e : α ≃o β) : α ↪o β) + +@[simp] lemma to_dual_wcovby_to_dual_iff : to_dual b ⩿ to_dual a ↔ a ⩿ b := +and_congr_right' $ forall_congr $ λ c, forall_swap + +@[simp] lemma of_dual_wcovby_of_dual_iff {a b : order_dual α} : + of_dual a ⩿ of_dual b ↔ b ⩿ a := +and_congr_right' $ forall_congr $ λ c, forall_swap + +alias to_dual_wcovby_to_dual_iff ↔ _ wcovby.to_dual +alias of_dual_wcovby_of_dual_iff ↔ _ wcovby.of_dual + +end preorder + +section partial_order +variables [partial_order α] {a b c : α} + +lemma wcovby.eq_or_eq (h : a ⩿ b) (h2 : a ≤ c) (h3 : c ≤ b) : c = a ∨ c = b := +begin + rcases h2.eq_or_lt with h2|h2, { exact or.inl h2.symm }, + rcases h3.eq_or_lt with h3|h3, { exact or.inr h3 }, + exact (h.2 h2 h3).elim +end + +lemma wcovby.le_and_le_iff (h : a ⩿ b) : a ≤ c ∧ c ≤ b ↔ c = a ∨ c = b := +begin + refine ⟨λ h2, h.eq_or_eq h2.1 h2.2, _⟩, rintro (rfl|rfl), exacts [⟨le_rfl, h.le⟩, ⟨h.le, le_rfl⟩] +end + +lemma wcovby.Icc_eq (h : a ⩿ b) : Icc a b = {a, b} := +by { ext c, exact h.le_and_le_iff } + +lemma wcovby.Ico_subset (h : a ⩿ b) : Ico a b ⊆ {a} := +by rw [← Icc_diff_right, h.Icc_eq, diff_singleton_subset_iff, pair_comm] + +lemma wcovby.Ioc_subset (h : a ⩿ b) : Ioc a b ⊆ {b} := +by rw [← Icc_diff_left, h.Icc_eq, diff_singleton_subset_iff] + +end partial_order + +end weakly_covers + section has_lt variables [has_lt α] {a b : α} @@ -32,7 +133,7 @@ lemma covby.lt (h : a ⋖ b) : a < b := h.1 /-- If `a < b`, then `b` does not cover `a` iff there's an element in between. -/ lemma not_covby_iff (h : a < b) : ¬a ⋖ b ↔ ∃ c, a < c ∧ c < b := -by { simp_rw [covby, not_and, not_forall, exists_prop, not_not], exact imp_iff_right h } +by simp_rw [covby, h, true_and, not_forall, exists_prop, not_not] alias not_covby_iff ↔ exists_lt_lt_of_not_covby _ alias exists_lt_lt_of_not_covby ← has_lt.lt.exists_lt_lt @@ -44,8 +145,6 @@ lemma not_covby [densely_ordered α] : ¬ a ⋖ b := lemma densely_ordered_iff_forall_not_covby : densely_ordered α ↔ ∀ a b : α, ¬ a ⋖ b := ⟨λ h a b, @not_covby _ _ _ _ h, λ h, ⟨λ a b hab, exists_lt_lt_of_not_covby hab $ h _ _⟩⟩ -open order_dual - @[simp] lemma to_dual_covby_to_dual_iff : to_dual b ⋖ to_dual a ↔ a ⋖ b := and_congr_right' $ forall_congr $ λ c, forall_swap @@ -59,57 +158,84 @@ alias of_dual_covby_of_dual_iff ↔ _ covby.of_dual end has_lt section preorder -variables [preorder α] [preorder β] {a b : α} {f : α ↪o β} {e : α ≃o β} +variables [preorder α] [preorder β] {a b : α} lemma covby.le (h : a ⋖ b) : a ≤ b := h.1.le protected lemma covby.ne (h : a ⋖ b) : a ≠ b := h.lt.ne lemma covby.ne' (h : a ⋖ b) : b ≠ a := h.lt.ne' +protected lemma covby.wcovby (h : a ⋖ b) : a ⩿ b := ⟨h.le, h.2⟩ +lemma wcovby.covby_of_not_le (h : a ⩿ b) (h2 : ¬ b ≤ a) : a ⋖ b := ⟨h.le.lt_of_not_le h2, h.2⟩ +lemma wcovby.covby_of_lt (h : a ⩿ b) (h2 : a < b) : a ⋖ b := ⟨h2, h.2⟩ + +lemma covby_iff_wcovby_and_lt : a ⋖ b ↔ a ⩿ b ∧ a < b := +⟨λ h, ⟨h.wcovby, h.lt⟩, λ h, h.1.covby_of_lt h.2⟩ + +lemma covby_iff_wcovby_and_not_le : a ⋖ b ↔ a ⩿ b ∧ ¬ b ≤ a := +⟨λ h, ⟨h.wcovby, h.lt.not_le⟩, λ h, h.1.covby_of_not_le h.2⟩ + +lemma wcovby_iff_covby_or_le_and_le : a ⩿ b ↔ a ⋖ b ∨ (a ≤ b ∧ b ≤ a) := +⟨λ h, or_iff_not_imp_right.mpr $ λ h', h.covby_of_not_le $ λ hba, h' ⟨h.le, hba⟩, + λ h', h'.elim (λ h, h.wcovby) (λ h, h.1.wcovby_of_le h.2)⟩ + +instance : is_nonstrict_strict_order α (⩿) (⋖) := +⟨λ a b, covby_iff_wcovby_and_not_le.trans $ and_congr_right $ λ h, h.wcovby_iff_le.not.symm⟩ + instance covby.is_irrefl : is_irrefl α (⋖) := ⟨λ a ha, ha.ne rfl⟩ lemma covby.Ioo_eq (h : a ⋖ b) : Ioo a b = ∅ := -eq_empty_iff_forall_not_mem.2 $ λ x hx, h.2 hx.1 hx.2 +h.wcovby.Ioo_eq -lemma covby.of_image (h : f a ⋖ f b) : a ⋖ b := -begin - refine ⟨_, λ c hac hcb, _⟩, - { rw ←order_embedding.lt_iff_lt f, - exact h.1 }, - rw ←order_embedding.lt_iff_lt f at hac hcb, - exact h.2 hac hcb, -end +lemma covby.of_image (f : α ↪o β) (h : f a ⋖ f b) : a ⋖ b := +⟨f.lt_iff_lt.mp h.lt, λ c hac hcb, h.2 (f.lt_iff_lt.mpr hac) (f.lt_iff_lt.mpr hcb)⟩ -lemma covby.image (hab : a ⋖ b) (h : (set.range f).ord_connected) : f a ⋖ f b := -begin - refine ⟨f.strict_mono hab.1, λ c ha hb, _⟩, - obtain ⟨c, rfl⟩ := h.out (mem_range_self _) (mem_range_self _) ⟨ha.le, hb.le⟩, - rw f.lt_iff_lt at ha hb, - exact hab.2 ha hb, -end +lemma covby.image (f : α ↪o β) (hab : a ⋖ b) (h : (range f).ord_connected) : f a ⋖ f b := +(hab.wcovby.image f h).covby_of_lt $ f.strict_mono hab.lt -protected lemma set.ord_connected.image_covby_image_iff (h : (set.range f).ord_connected) : +lemma set.ord_connected.apply_covby_apply_iff (f : α ↪o β) (h : (range f).ord_connected) : f a ⋖ f b ↔ a ⋖ b := -⟨covby.of_image, λ hab, hab.image h⟩ +⟨covby.of_image f, λ hab, hab.image f h⟩ -@[simp] lemma apply_covby_apply_iff : e a ⋖ e b ↔ a ⋖ b := -⟨covby.of_image, λ hab, begin - refine ⟨e.strict_mono hab.1, λ c ha hb, _⟩, - rw [←e.symm.lt_iff_lt, order_iso.symm_apply_apply] at ha hb, - exact hab.2 ha hb, -end⟩ +@[simp] lemma apply_covby_apply_iff {E : Type*} [order_iso_class E α β] (e : E) : + e a ⋖ e b ↔ a ⋖ b := +(ord_connected_range (e : α ≃o β)).apply_covby_apply_iff ((e : α ≃o β) : α ↪o β) end preorder section partial_order variables [partial_order α] {a b : α} +lemma wcovby.covby_of_ne (h : a ⩿ b) (h2 : a ≠ b) : a ⋖ b := ⟨h.le.lt_of_ne h2, h.2⟩ + +lemma covby_iff_wcovby_and_ne : a ⋖ b ↔ a ⩿ b ∧ a ≠ b := +⟨λ h, ⟨h.wcovby, h.ne⟩, λ h, h.1.covby_of_ne h.2⟩ + +lemma wcovby_iff_covby_or_eq : a ⩿ b ↔ a ⋖ b ∨ a = b := +by rw [le_antisymm_iff, wcovby_iff_covby_or_le_and_le] + lemma covby.Ico_eq (h : a ⋖ b) : Ico a b = {a} := -by rw [←set.Ioo_union_left h.lt, h.Ioo_eq, empty_union] +by rw [←Ioo_union_left h.lt, h.Ioo_eq, empty_union] lemma covby.Ioc_eq (h : a ⋖ b) : Ioc a b = {b} := -by rw [←set.Ioo_union_right h.lt, h.Ioo_eq, empty_union] +by rw [←Ioo_union_right h.lt, h.Ioo_eq, empty_union] lemma covby.Icc_eq (h : a ⋖ b) : Icc a b = {a, b} := -by { rw [←set.Ico_union_right h.le, h.Ico_eq], refl } +h.wcovby.Icc_eq end partial_order + +namespace set + +lemma wcovby_insert (x : α) (s : set α) : s ⩿ insert x s := +begin + refine wcovby_of_eq_or_eq (subset_insert x s) (λ t hst h2t, _), + by_cases h : x ∈ t, + { exact or.inr (subset_antisymm h2t $ insert_subset.mpr ⟨h, hst⟩) }, + { refine or.inl (subset_antisymm _ hst), + rwa [← diff_singleton_eq_self h, diff_singleton_subset_iff] } +end + +lemma covby_insert {x : α} {s : set α} (hx : x ∉ s) : s ⋖ insert x s := +(wcovby_insert x s).covby_of_lt $ ssubset_insert hx + +end set diff --git a/src/order/succ_pred/basic.lean b/src/order/succ_pred/basic.lean index a4839b7a2de11..4b6e6416bd93a 100644 --- a/src/order/succ_pred/basic.lean +++ b/src/order/succ_pred/basic.lean @@ -156,8 +156,11 @@ lemma le_of_lt_succ {a b : α} : a < succ b → a ≤ b := succ_order.le_of_lt_s alias lt_succ_iff_not_is_max ↔ _ order.lt_succ_of_not_is_max +lemma wcovby_succ (a : α) : a ⩿ succ a := +⟨le_succ a, λ b hb, (succ_le_of_lt hb).not_lt⟩ + lemma covby_succ_of_not_is_max (h : ¬ is_max a) : a ⋖ succ a := -⟨lt_succ_of_not_is_max h, λ b hb, (succ_le_of_lt hb).not_lt⟩ +(wcovby_succ a).covby_of_lt $ lt_succ_of_not_is_max h lemma lt_succ_iff_of_not_is_max (ha : ¬ is_max a) : b < succ a ↔ b ≤ a := ⟨le_of_lt_succ, λ h, h.trans_lt $ lt_succ_of_not_is_max ha⟩ @@ -364,8 +367,11 @@ lemma le_of_pred_lt {a b : α} : pred a < b → a ≤ b := pred_order.le_of_pred alias pred_lt_iff_not_is_min ↔ _ order.pred_lt_of_not_is_min +lemma pred_wcovby (a : α) : pred a ⩿ a := +⟨pred_le a, λ b hb, (le_of_pred_lt hb).not_lt⟩ + lemma pred_covby_of_not_is_min (h : ¬ is_min a) : pred a ⋖ a := -⟨pred_lt_of_not_is_min h, λ b hb, (le_of_pred_lt hb).not_lt⟩ +(pred_wcovby a).covby_of_lt $ pred_lt_of_not_is_min h lemma pred_lt_iff_of_not_is_min (ha : ¬ is_min a) : pred a < b ↔ a ≤ b := ⟨le_of_pred_lt, (pred_lt_of_not_is_min ha).trans_le⟩ From 8fa3263c0c0cfc61fe0828f91be635fc983d166d Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Tue, 19 Apr 2022 14:04:46 +0000 Subject: [PATCH 081/373] fix(analysis/locally_convex/balanced_hull_core): minimize import (#13450) I'm doing this because I need to have `balanced_hull_core` before `normed_space.finite_dimensional` and this little change seems to be enough for that, but I think at some point we'll need to move lemmas so that normed_spaces come as late as possible --- src/analysis/locally_convex/balanced_core_hull.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analysis/locally_convex/balanced_core_hull.lean b/src/analysis/locally_convex/balanced_core_hull.lean index 5b29e73629ba6..6b962ff17cc7a 100644 --- a/src/analysis/locally_convex/balanced_core_hull.lean +++ b/src/analysis/locally_convex/balanced_core_hull.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 -/ -import analysis.seminorm +import analysis.locally_convex.basic import order.closure /-! From 5dc8c1cf64737787dff8a3f27f75e9107661a7f0 Mon Sep 17 00:00:00 2001 From: berndlosert Date: Tue, 19 Apr 2022 14:04:47 +0000 Subject: [PATCH 082/373] =?UTF-8?q?feat(order/filter/n=5Fary):=20Add=20lem?= =?UTF-8?q?ma=20equating=20map=E2=82=82=20to=20map=20on=20the=20product=20?= =?UTF-8?q?(#13490)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Proof that map₂ is the image of the corresponding function `α × β → γ`. Discussion: https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/filter.20map.E2.82.82.20as.20map --- src/order/filter/n_ary.lean | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/order/filter/n_ary.lean b/src/order/filter/n_ary.lean index 589470fd757cc..70906967e9f1c 100644 --- a/src/order/filter/n_ary.lean +++ b/src/order/filter/n_ary.lean @@ -22,6 +22,7 @@ This file is very similar to the n-ary section of `data.set.basic`. Please keep -/ open function set +open_locale filter namespace filter variables {α α' β β' γ γ' δ δ' ε ε' : Type*} {m : α → β → γ} {f f₁ f₂ : filter α} @@ -49,6 +50,31 @@ def map₂ (m : α → β → γ) (f : filter α) (g : filter β) : filter γ := lemma image2_mem_map₂ (hs : s ∈ f) (ht : t ∈ g) : image2 m s t ∈ map₂ m f g := ⟨_, _, hs, ht, subset.rfl⟩ +lemma map_prod_eq_map₂ (m : α → β → γ) (f : filter α) (g : filter β) : + filter.map (λ p : α × β, m p.1 p.2) (f ×ᶠ g) = map₂ m f g := +begin + ext s, + split, + { intro hmem, + rw filter.mem_map_iff_exists_image at hmem, + obtain ⟨s', hs', hsub⟩ := hmem, + rw filter.mem_prod_iff at hs', + obtain ⟨t, ht, t', ht', hsub'⟩ := hs', + refine ⟨t, t', ht, ht', _⟩, + rw ← set.image_prod, + exact subset_trans (set.image_subset (λ (p : α × β), m p.fst p.snd) hsub') hsub }, + { intro hmem, + rw mem_map₂_iff at hmem, + obtain ⟨t, t', ht, ht', hsub⟩ := hmem, + rw ← set.image_prod at hsub, + rw filter.mem_map_iff_exists_image, + exact ⟨t ×ˢ t', filter.prod_mem_prod ht ht', hsub⟩ }, +end + +lemma map_prod_eq_map₂' (m : α × β → γ) (f : filter α) (g : filter β) : + filter.map m (f ×ᶠ g) = map₂ (λ a b, m (a, b)) f g := +by { refine eq.trans _ (map_prod_eq_map₂ (curry m) f g), ext, simp } + -- lemma image2_mem_map₂_iff (hm : injective2 m) : image2 m s t ∈ map₂ m f g ↔ s ∈ f ∧ t ∈ g := -- ⟨by { rintro ⟨u, v, hu, hv, h⟩, rw image2_subset_image2_iff hm at h, -- exact ⟨mem_of_superset hu h.1, mem_of_superset hv h.2⟩ }, λ h, image2_mem_map₂ h.1 h.2⟩ From 634eab1080e5313afd206b1cc6e00aa28135fc15 Mon Sep 17 00:00:00 2001 From: Johan Commelin Date: Tue, 19 Apr 2022 15:52:31 +0000 Subject: [PATCH 083/373] feat(category_theory/limits): add characteristic predicate for zero objects (#13511) --- src/algebra/category/Group/zero.lean | 2 +- .../normed/group/SemiNormedGroup.lean | 2 +- src/category_theory/closed/zero.lean | 2 +- .../limits/preserves/shapes/zero.lean | 2 +- .../limits/shapes/default.lean | 2 +- .../shapes/{zero.lean => zero_morphisms.lean} | 90 ++------ .../limits/shapes/zero_objects.lean | 205 ++++++++++++++++++ src/category_theory/simple.lean | 2 +- 8 files changed, 225 insertions(+), 82 deletions(-) rename src/category_theory/limits/shapes/{zero.lean => zero_morphisms.lean} (85%) create mode 100644 src/category_theory/limits/shapes/zero_objects.lean diff --git a/src/algebra/category/Group/zero.lean b/src/algebra/category/Group/zero.lean index ff16c712bbe24..47e5e3ec3d166 100644 --- a/src/algebra/category/Group/zero.lean +++ b/src/algebra/category/Group/zero.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Scott Morrison -/ import algebra.category.Group.basic -import category_theory.limits.shapes.zero +import category_theory.limits.shapes.zero_morphisms /-! # The category of (commutative) (additive) groups has a zero object. diff --git a/src/analysis/normed/group/SemiNormedGroup.lean b/src/analysis/normed/group/SemiNormedGroup.lean index 3681388833d59..46a5a9d9646c5 100644 --- a/src/analysis/normed/group/SemiNormedGroup.lean +++ b/src/analysis/normed/group/SemiNormedGroup.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin, Riccardo Brasca -/ import analysis.normed.group.hom -import category_theory.limits.shapes.zero +import category_theory.limits.shapes.zero_morphisms import category_theory.concrete_category.bundled_hom /-! diff --git a/src/category_theory/closed/zero.lean b/src/category_theory/closed/zero.lean index 04f35974b8dc3..751ad5e9daf12 100644 --- a/src/category_theory/closed/zero.lean +++ b/src/category_theory/closed/zero.lean @@ -5,7 +5,7 @@ Authors: Bhavik Mehta -/ import category_theory.closed.cartesian -import category_theory.limits.shapes.zero +import category_theory.limits.shapes.zero_morphisms import category_theory.punit import category_theory.conj diff --git a/src/category_theory/limits/preserves/shapes/zero.lean b/src/category_theory/limits/preserves/shapes/zero.lean index fe9098d1e9987..407b1444f4f9f 100644 --- a/src/category_theory/limits/preserves/shapes/zero.lean +++ b/src/category_theory/limits/preserves/shapes/zero.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Markus Himmel -/ import category_theory.limits.preserves.shapes.terminal -import category_theory.limits.shapes.zero +import category_theory.limits.shapes.zero_morphisms /-! # Preservation of zero objects and zero morphisms diff --git a/src/category_theory/limits/shapes/default.lean b/src/category_theory/limits/shapes/default.lean index 157e139ed7f73..ce39844b6f1e1 100644 --- a/src/category_theory/limits/shapes/default.lean +++ b/src/category_theory/limits/shapes/default.lean @@ -5,7 +5,7 @@ import category_theory.limits.shapes.finite_products import category_theory.limits.shapes.finite_limits import category_theory.limits.shapes.biproducts import category_theory.limits.shapes.images -import category_theory.limits.shapes.zero +import category_theory.limits.shapes.zero_morphisms import category_theory.limits.shapes.kernels import category_theory.limits.shapes.equalizers import category_theory.limits.shapes.wide_pullbacks diff --git a/src/category_theory/limits/shapes/zero.lean b/src/category_theory/limits/shapes/zero_morphisms.lean similarity index 85% rename from src/category_theory/limits/shapes/zero.lean rename to src/category_theory/limits/shapes/zero_morphisms.lean index 14beac6f2db01..d2c95656aef36 100644 --- a/src/category_theory/limits/shapes/zero.lean +++ b/src/category_theory/limits/shapes/zero_morphisms.lean @@ -6,6 +6,7 @@ Authors: Scott Morrison import category_theory.limits.shapes.products import category_theory.limits.shapes.images import category_theory.isomorphism_classes +import category_theory.limits.shapes.zero_objects /-! # Zero morphisms and zero objects @@ -131,51 +132,24 @@ instance : has_zero_morphisms (C ⥤ D) := end -variables (C) - -/-- A category "has a zero object" if it has an object which is both initial and terminal. -/ -class has_zero_object := -(zero : C) -(unique_to : Π X : C, unique (zero ⟶ X)) -(unique_from : Π X : C, unique (X ⟶ zero)) - -instance has_zero_object_punit : has_zero_object (discrete punit) := -{ zero := punit.star, - unique_to := by tidy, - unique_from := by tidy, } +/-- A category with a zero object has zero morphisms. -variables {C} + It is rarely a good idea to use this. Many categories that have a zero object have zero + morphisms for some other reason, for example from additivity. Library code that uses + `zero_morphisms_of_zero_object` will then be incompatible with these categories because + the `has_zero_morphisms` instances will not be definitionally equal. For this reason library + code should generally ask for an instance of `has_zero_morphisms` separately, even if it already + asks for an instance of `has_zero_objects`. -/ +def is_zero.has_zero_morphisms {O : C} (hO : is_zero O) : has_zero_morphisms C := +{ has_zero := λ X Y, + { zero := hO.from X ≫ hO.to Y }, + zero_comp' := λ X Y Z f, by { rw category.assoc, congr, apply hO.eq_of_src, }, + comp_zero' := λ X Y Z f, by { rw ←category.assoc, congr, apply hO.eq_of_tgt, }} namespace has_zero_object variables [has_zero_object C] - -/-- -Construct a `has_zero C` for a category with a zero object. -This can not be a global instance as it will trigger for every `has_zero C` typeclass search. --/ -protected def has_zero : has_zero C := -{ zero := has_zero_object.zero } - -localized "attribute [instance] category_theory.limits.has_zero_object.has_zero" in zero_object -localized "attribute [instance] category_theory.limits.has_zero_object.unique_to" in zero_object -localized "attribute [instance] category_theory.limits.has_zero_object.unique_from" in zero_object - -@[ext] -lemma to_zero_ext {X : C} (f g : X ⟶ 0) : f = g := -by rw [(has_zero_object.unique_from X).uniq f, (has_zero_object.unique_from X).uniq g] - -@[ext] -lemma from_zero_ext {X : C} (f g : 0 ⟶ X) : f = g := -by rw [(has_zero_object.unique_to X).uniq f, (has_zero_object.unique_to X).uniq g] - -instance (X : C) : subsingleton (X ≅ 0) := by tidy - -instance {X : C} (f : 0 ⟶ X) : mono f := -{ right_cancellation := λ Z g h w, by ext, } - -instance {X : C} (f : X ⟶ 0) : epi f := -{ left_cancellation := λ Z g h w, by ext, } +open_locale zero_object /-- A category with a zero object has zero morphisms. @@ -191,38 +165,6 @@ def zero_morphisms_of_zero_object : has_zero_morphisms C := zero_comp' := λ X Y Z f, by { dunfold has_zero.zero, rw category.assoc, congr, }, comp_zero' := λ X Y Z f, by { dunfold has_zero.zero, rw ←category.assoc, congr, }} -/-- A zero object is in particular initial. -/ -def zero_is_initial : is_initial (0 : C) := -is_initial.of_unique 0 -/-- A zero object is in particular terminal. -/ -def zero_is_terminal : is_terminal (0 : C) := -is_terminal.of_unique 0 - -/-- A zero object is in particular initial. -/ -@[priority 10] -instance has_initial : has_initial C := -has_initial_of_unique 0 -/-- A zero object is in particular terminal. -/ -@[priority 10] -instance has_terminal : has_terminal C := -has_terminal_of_unique 0 - -/-- The (unique) isomorphism between any initial object and the zero object. -/ -def zero_iso_is_initial {X : C} (t : is_initial X) : 0 ≅ X := -zero_is_initial.unique_up_to_iso t - -/-- The (unique) isomorphism between any terminal object and the zero object. -/ -def zero_iso_is_terminal {X : C} (t : is_terminal X) : 0 ≅ X := -zero_is_terminal.unique_up_to_iso t - -/-- The (unique) isomorphism between the chosen initial object and the chosen zero object. -/ -def zero_iso_initial [has_initial C] : 0 ≅ ⊥_ C := -zero_is_initial.unique_up_to_iso initial_is_initial - -/-- The (unique) isomorphism between the chosen terminal object and the chosen zero object. -/ -def zero_iso_terminal [has_terminal C] : 0 ≅ ⊤_ C := -zero_is_terminal.unique_up_to_iso terminal_is_terminal - section has_zero_morphisms variables [has_zero_morphisms C] @@ -256,10 +198,6 @@ by ext end has_zero_morphisms -@[priority 100] -instance has_strict_initial : initial_mono_class C := -initial_mono_class.of_is_initial zero_is_initial (λ X, category_theory.mono _) - open_locale zero_object instance {B : Type*} [category B] [has_zero_morphisms C] : has_zero_object (B ⥤ C) := diff --git a/src/category_theory/limits/shapes/zero_objects.lean b/src/category_theory/limits/shapes/zero_objects.lean new file mode 100644 index 0000000000000..0e6096842ebc9 --- /dev/null +++ b/src/category_theory/limits/shapes/zero_objects.lean @@ -0,0 +1,205 @@ +/- +Copyright (c) 2019 Scott Morrison. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Scott Morrison, Johan Commelin +-/ +import category_theory.limits.shapes.products +import category_theory.limits.shapes.images +import category_theory.isomorphism_classes + +/-! +# Zero objects + +A category "has a zero object" if it has an object which is both initial and terminal. Having a +zero object provides zero morphisms, as the unique morphisms factoring through the zero object; +see `category_theory.limits.shapes.zero_morphisms`. + +## References + +* [F. Borceux, *Handbook of Categorical Algebra 2*][borceux-vol2] +-/ + +noncomputable theory + +universes v u v' u' + +open category_theory +open category_theory.category + +namespace category_theory.limits + +variables {C : Type u} [category.{v} C] +variables {D : Type u'} [category.{v'} D] + +/-- An object `X` in a category is a *zero object* if for every object `Y` +there is a unique morphism `to : X → Y` and a unique morphism `from : Y → X`. + +This is a characteristic predicate for `has_zero_object`. -/ +structure is_zero (X : C) : Prop := +(unique_to : ∀ Y, nonempty (unique (X ⟶ Y))) +(unique_from : ∀ Y, nonempty (unique (Y ⟶ X))) + +namespace is_zero + +variables {X Y : C} + +/-- If `h : is_zero X`, then `h.to Y` is a choice of unique morphism `X → Y`. -/ +protected def «to» (h : is_zero X) (Y : C) : X ⟶ Y := +@default (X ⟶ Y) $ @unique.inhabited _ $ (h.unique_to Y).some + +lemma eq_to (h : is_zero X) (f : X ⟶ Y) : f = h.to Y := +@unique.eq_default _ (id _) _ + +lemma to_eq (h : is_zero X) (f : X ⟶ Y) : h.to Y = f := +(h.eq_to f).symm + +/-- If `h : is_zero X`, then `h.from Y` is a choice of unique morphism `Y → X`. -/ +protected def «from» (h : is_zero X) (Y : C) : Y ⟶ X := +@default (Y ⟶ X) $ @unique.inhabited _ $ (h.unique_from Y).some + +lemma eq_from (h : is_zero X) (f : Y ⟶ X) : f = h.from Y := +@unique.eq_default _ (id _) _ + +lemma from_eq (h : is_zero X) (f : Y ⟶ X) : h.from Y = f := +(h.eq_from f).symm + +lemma eq_of_src (hX : is_zero X) (f g : X ⟶ Y) : f = g := +(hX.eq_to f).trans (hX.eq_to g).symm + +lemma eq_of_tgt (hX : is_zero X) (f g : Y ⟶ X) : f = g := +(hX.eq_from f).trans (hX.eq_from g).symm + +/-- Any two zero objects are isomorphic. -/ +def iso (hX : is_zero X) (hY : is_zero Y) : X ≅ Y := +{ hom := hX.to Y, + inv := hX.from Y, + hom_inv_id' := hX.eq_of_src _ _, + inv_hom_id' := hY.eq_of_src _ _, } + +/-- A zero object is in particular initial. -/ +protected def is_initial (hX : is_zero X) : is_initial X := +@is_initial.of_unique _ _ X $ λ Y, (hX.unique_to Y).some + +/-- A zero object is in particular terminal. -/ +protected def is_terminal (hX : is_zero X) : is_terminal X := +@is_terminal.of_unique _ _ X $ λ Y, (hX.unique_from Y).some + +/-- The (unique) isomorphism between any initial object and the zero object. -/ +def iso_is_initial (hX : is_zero X) (hY : is_initial Y) : X ≅ Y := +hX.is_initial.unique_up_to_iso hY + +/-- The (unique) isomorphism between any terminal object and the zero object. -/ +def iso_is_terminal (hX : is_zero X) (hY : is_terminal Y) : X ≅ Y := +hX.is_terminal.unique_up_to_iso hY + +lemma of_iso (hY : is_zero Y) (e : X ≅ Y) : is_zero X := +begin + refine ⟨λ Z, ⟨⟨⟨e.hom ≫ hY.to Z⟩, λ f, _⟩⟩, λ Z, ⟨⟨⟨hY.from Z ≫ e.inv⟩, λ f, _⟩⟩⟩, + { rw ← cancel_epi e.inv, apply hY.eq_of_src, }, + { rw ← cancel_mono e.hom, apply hY.eq_of_tgt, }, +end + +end is_zero + +lemma iso.is_zero_iff {X Y : C} (e : X ≅ Y) : + is_zero X ↔ is_zero Y := +⟨λ h, h.of_iso e.symm, λ h, h.of_iso e⟩ + +variables (C) + +/-- A category "has a zero object" if it has an object which is both initial and terminal. -/ +class has_zero_object := +(zero : C) +(unique_to : Π X : C, unique (zero ⟶ X)) +(unique_from : Π X : C, unique (X ⟶ zero)) + +instance has_zero_object_punit : has_zero_object (discrete punit) := +{ zero := punit.star, + unique_to := by tidy, + unique_from := by tidy, } + + +namespace has_zero_object + +variables [has_zero_object C] + +/-- +Construct a `has_zero C` for a category with a zero object. +This can not be a global instance as it will trigger for every `has_zero C` typeclass search. +-/ +protected def has_zero : has_zero C := +{ zero := has_zero_object.zero } + +localized "attribute [instance] category_theory.limits.has_zero_object.has_zero" in zero_object +localized "attribute [instance] category_theory.limits.has_zero_object.unique_to" in zero_object +localized "attribute [instance] category_theory.limits.has_zero_object.unique_from" in zero_object + +lemma is_zero_zero : is_zero (0 : C) := +{ unique_to := λ Y, ⟨has_zero_object.unique_to Y⟩, + unique_from := λ Y, ⟨has_zero_object.unique_from Y⟩ } + +/-- Every zero object is isomorphic to *the* zero object. -/ +def is_zero.iso_zero {X : C} (hX : is_zero X) : X ≅ 0 := +hX.iso (is_zero_zero C) + +variables {C} + +@[ext] +lemma to_zero_ext {X : C} (f g : X ⟶ 0) : f = g := +(is_zero_zero C).eq_of_tgt _ _ + +@[ext] +lemma from_zero_ext {X : C} (f g : 0 ⟶ X) : f = g := +(is_zero_zero C).eq_of_src _ _ + +instance (X : C) : subsingleton (X ≅ 0) := by tidy + +instance {X : C} (f : 0 ⟶ X) : mono f := +{ right_cancellation := λ Z g h w, by ext, } + +instance {X : C} (f : X ⟶ 0) : epi f := +{ left_cancellation := λ Z g h w, by ext, } + +/-- A zero object is in particular initial. -/ +def zero_is_initial : is_initial (0 : C) := +is_initial.of_unique 0 + +/-- A zero object is in particular terminal. -/ +def zero_is_terminal : is_terminal (0 : C) := +is_terminal.of_unique 0 + +/-- A zero object is in particular initial. -/ +@[priority 10] +instance has_initial : has_initial C := +has_initial_of_unique 0 + +/-- A zero object is in particular terminal. -/ +@[priority 10] +instance has_terminal : has_terminal C := +has_terminal_of_unique 0 + +/-- The (unique) isomorphism between any initial object and the zero object. -/ +def zero_iso_is_initial {X : C} (t : is_initial X) : 0 ≅ X := +zero_is_initial.unique_up_to_iso t + +/-- The (unique) isomorphism between any terminal object and the zero object. -/ +def zero_iso_is_terminal {X : C} (t : is_terminal X) : 0 ≅ X := +zero_is_terminal.unique_up_to_iso t + +/-- The (unique) isomorphism between the chosen initial object and the chosen zero object. -/ +def zero_iso_initial [has_initial C] : 0 ≅ ⊥_ C := +zero_is_initial.unique_up_to_iso initial_is_initial + +/-- The (unique) isomorphism between the chosen terminal object and the chosen zero object. -/ +def zero_iso_terminal [has_terminal C] : 0 ≅ ⊤_ C := +zero_is_terminal.unique_up_to_iso terminal_is_terminal + +@[priority 100] +instance has_strict_initial : initial_mono_class C := +initial_mono_class.of_is_initial zero_is_initial (λ X, category_theory.mono _) + +open_locale zero_object + +end has_zero_object + +end category_theory.limits diff --git a/src/category_theory/simple.lean b/src/category_theory/simple.lean index a3370b017afda..3f5a8fe86a69d 100644 --- a/src/category_theory/simple.lean +++ b/src/category_theory/simple.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Scott Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Markus Himmel, Scott Morrison -/ -import category_theory.limits.shapes.zero +import category_theory.limits.shapes.zero_morphisms import category_theory.limits.shapes.kernels import category_theory.abelian.basic From f06dca76a989f23ba6e310e135c7ce1037bfba9d Mon Sep 17 00:00:00 2001 From: Oliver Nash Date: Tue, 19 Apr 2022 15:52:32 +0000 Subject: [PATCH 084/373] feat(data/int/basic): add lemma `int.abs_le_one_iff` (#13513) Also renaming `int.eq_zero_iff_abs_lt_one`. The proof is due to @Ruben-VandeVelde Discussed on Zulip [here](https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/Integers.20of.20norm.20at.20most.20one) Co-authored-by: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> --- src/data/int/basic.lean | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/data/int/basic.lean b/src/data/int/basic.lean index c89d3aa9ed0bf..a3aea134be6eb 100644 --- a/src/data/int/basic.lean +++ b/src/data/int/basic.lean @@ -214,10 +214,13 @@ sub_lt_iff_lt_add.trans lt_add_one_iff theorem le_sub_one_iff {a b : ℤ} : a ≤ b - 1 ↔ a < b := le_sub_iff_add_le -@[simp] lemma eq_zero_iff_abs_lt_one {a : ℤ} : |a| < 1 ↔ a = 0 := +@[simp] lemma abs_lt_one_iff {a : ℤ} : |a| < 1 ↔ a = 0 := ⟨λ a0, let ⟨hn, hp⟩ := abs_lt.mp a0 in (le_of_lt_add_one (by exact hp)).antisymm hn, λ a0, (abs_eq_zero.mpr a0).le.trans_lt zero_lt_one⟩ +lemma abs_le_one_iff {a : ℤ} : |a| ≤ 1 ↔ a = 0 ∨ a = 1 ∨ a = -1 := +by rw [le_iff_lt_or_eq, abs_lt_one_iff, abs_eq (@zero_le_one ℤ _)] + @[elab_as_eliminator] protected lemma induction_on {p : ℤ → Prop} (i : ℤ) (hz : p 0) (hp : ∀ i : ℕ, p i → p (i + 1)) (hn : ∀ i : ℕ, p (-i) → p (-i - 1)) : p i := begin @@ -1546,7 +1549,7 @@ begin by_cases hm : m = 0, { subst m, exact zero_dvd_iff.mp h1, }, rcases h1 with ⟨d, rfl⟩, apply mul_eq_zero_of_right, - rw [←eq_zero_iff_abs_lt_one, ←mul_lt_iff_lt_one_right (abs_pos.mpr hm), ←abs_mul], + rw [←abs_lt_one_iff, ←mul_lt_iff_lt_one_right (abs_pos.mpr hm), ←abs_mul], exact lt_of_lt_of_le h2 (le_abs_self m), end From 70759ef9177b4dfdb1cb4df4b77bffa1d13c81eb Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Tue, 19 Apr 2022 17:41:07 +0000 Subject: [PATCH 085/373] feat(analysis): lemmas about nnnorm and nndist (#13498) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most of these lemmas follow trivially from the `norm` versions. This is far from exhaustive. Additionally: * `nnreal.coe_supr` and `nnreal.coe_infi` are added * The old `is_primitive_root.nnnorm_eq_one` is renamed to `is_primitive_root.norm'_eq_one` as it was not about `nnnorm` at all. The unprimed name is already taken in reference to `algebra.norm`. * `parallelogram_law_with_norm_real` is removed since it's syntactically identical to `parallelogram_law_with_norm ℝ` and also not used anywhere. --- src/analysis/complex/basic.lean | 14 ++++++ src/analysis/complex/roots_of_unity.lean | 7 ++- src/analysis/inner_product_space/basic.lean | 14 +++--- .../inner_product_space/projection.lean | 2 +- src/analysis/matrix.lean | 15 ++++++- src/analysis/normed/group/basic.lean | 24 ++++++++++ src/analysis/normed/normed_field.lean | 19 ++++++++ src/analysis/normed_space/operator_norm.lean | 13 +++++- src/analysis/normed_space/pi_Lp.lean | 5 +++ src/analysis/normed_space/star/basic.lean | 2 + src/analysis/quaternion.lean | 3 ++ src/data/real/nnreal.lean | 14 +++++- src/topology/continuous_function/bounded.lean | 45 ++++++++++++++----- src/topology/metric_space/isometry.lean | 9 ++++ 14 files changed, 164 insertions(+), 22 deletions(-) diff --git a/src/analysis/complex/basic.lean b/src/analysis/complex/basic.lean index b61a305f63264..98e96f07a2f78 100644 --- a/src/analysis/complex/basic.lean +++ b/src/analysis/complex/basic.lean @@ -137,6 +137,8 @@ le_antisymm (linear_map.mk_continuous_norm_le _ zero_le_one _) $ calc 1 = ∥re_clm 1∥ : by simp ... ≤ ∥re_clm∥ : unit_le_op_norm _ _ (by simp) +@[simp] lemma re_clm_nnnorm : ∥re_clm∥₊ = 1 := subtype.ext re_clm_norm + /-- Continuous linear map version of the real part function, from `ℂ` to `ℝ`. -/ def im_clm : ℂ →L[ℝ] ℝ := im_lm.mk_continuous 1 (λ x, by simp [real.norm_eq_abs, abs_im_le_abs]) @@ -151,6 +153,8 @@ le_antisymm (linear_map.mk_continuous_norm_le _ zero_le_one _) $ calc 1 = ∥im_clm I∥ : by simp ... ≤ ∥im_clm∥ : unit_le_op_norm _ _ (by simp) +@[simp] lemma im_clm_nnnorm : ∥im_clm∥₊ = 1 := subtype.ext im_clm_norm + lemma restrict_scalars_one_smul_right' {E : Type*} [normed_group E] [normed_space ℂ E] (x : E) : continuous_linear_map.restrict_scalars ℝ ((1 : ℂ →L[ℂ] ℂ).smul_right x : ℂ →L[ℂ] E) = re_clm.smul_right x + I • im_clm.smul_right x := @@ -172,9 +176,15 @@ lemma isometry_conj : isometry (conj : ℂ → ℂ) := conj_lie.isometry @[simp] lemma dist_conj_conj (z w : ℂ) : dist (conj z) (conj w) = dist z w := isometry_conj.dist_eq z w +@[simp] lemma nndist_conj_conj (z w : ℂ) : nndist (conj z) (conj w) = nndist z w := +isometry_conj.nndist_eq z w + lemma dist_conj_comm (z w : ℂ) : dist (conj z) w = dist z (conj w) := by rw [← dist_conj_conj, conj_conj] +lemma nndist_conj_comm (z w : ℂ) : nndist (conj z) w = nndist z (conj w) := +subtype.ext $ dist_conj_comm _ _ + /-- The determinant of `conj_lie`, as a linear map. -/ @[simp] lemma det_conj_lie : (conj_lie.to_linear_equiv : ℂ →ₗ[ℝ] ℂ).det = -1 := det_conj_ae @@ -195,6 +205,8 @@ def conj_cle : ℂ ≃L[ℝ] ℂ := conj_lie @[simp] lemma conj_cle_norm : ∥(conj_cle : ℂ →L[ℝ] ℂ)∥ = 1 := conj_lie.to_linear_isometry.norm_to_continuous_linear_map +@[simp] lemma conj_cle_nnorm : ∥(conj_cle : ℂ →L[ℝ] ℂ)∥₊ = 1 := subtype.ext conj_cle_norm + /-- Linear isometry version of the canonical embedding of `ℝ` in `ℂ`. -/ def of_real_li : ℝ →ₗᵢ[ℝ] ℂ := ⟨of_real_am.to_linear_map, norm_real⟩ @@ -211,6 +223,8 @@ def of_real_clm : ℝ →L[ℝ] ℂ := of_real_li.to_continuous_linear_map @[simp] lemma of_real_clm_norm : ∥of_real_clm∥ = 1 := of_real_li.norm_to_continuous_linear_map +@[simp] lemma of_real_clm_nnnorm : ∥of_real_clm∥₊ = 1 := subtype.ext $ of_real_clm_norm + noncomputable instance : is_R_or_C ℂ := { re := ⟨complex.re, complex.zero_re, complex.add_re⟩, im := ⟨complex.im, complex.zero_im, complex.add_im⟩, diff --git a/src/analysis/complex/roots_of_unity.lean b/src/analysis/complex/roots_of_unity.lean index 281acf808f4ab..12a43533616f4 100644 --- a/src/analysis/complex/roots_of_unity.lean +++ b/src/analysis/complex/roots_of_unity.lean @@ -95,12 +95,15 @@ end end complex -lemma is_primitive_root.nnnorm_eq_one {ζ : ℂ} {n : ℕ} (h : is_primitive_root ζ n) (hn : n ≠ 0) : +lemma is_primitive_root.norm'_eq_one {ζ : ℂ} {n : ℕ} (h : is_primitive_root ζ n) (hn : n ≠ 0) : ∥ζ∥ = 1 := complex.norm_eq_one_of_pow_eq_one h.pow_eq_one hn +lemma is_primitive_root.nnnorm_eq_one {ζ : ℂ} {n : ℕ} (h : is_primitive_root ζ n) (hn : n ≠ 0) : + ∥ζ∥₊ = 1 := subtype.ext $ h.norm'_eq_one hn + lemma is_primitive_root.arg_ext {n m : ℕ} {ζ μ : ℂ} (hζ : is_primitive_root ζ n) (hμ : is_primitive_root μ m) (hn : n ≠ 0) (hm : m ≠ 0) (h : ζ.arg = μ.arg) : ζ = μ := -complex.ext_abs_arg ((hζ.nnnorm_eq_one hn).trans (hμ.nnnorm_eq_one hm).symm) h +complex.ext_abs_arg ((hζ.norm'_eq_one hn).trans (hμ.norm'_eq_one hm).symm) h lemma is_primitive_root.arg_eq_zero_iff {n : ℕ} {ζ : ℂ} (hζ : is_primitive_root ζ n) (hn : n ≠ 0) : ζ.arg = 0 ↔ ζ = 1 := diff --git a/src/analysis/inner_product_space/basic.lean b/src/analysis/inner_product_space/basic.lean index 1404d13bad03f..3f3ef98cff338 100644 --- a/src/analysis/inner_product_space/basic.lean +++ b/src/analysis/inner_product_space/basic.lean @@ -1012,6 +1012,9 @@ end lemma norm_inner_le_norm (x y : E) : ∥⟪x, y⟫∥ ≤ ∥x∥ * ∥y∥ := (is_R_or_C.norm_eq_abs _).le.trans (abs_inner_le_norm x y) +lemma nnnorm_inner_le_nnnorm (x y : E) : ∥⟪x, y⟫∥₊ ≤ ∥x∥₊ * ∥y∥₊ := +norm_inner_le_norm x y + lemma re_inner_le_norm (x y : E) : re ⟪x, y⟫ ≤ ∥x∥ * ∥y∥ := le_trans (re_le_abs (inner x y)) (abs_inner_le_norm x y) @@ -1024,18 +1027,19 @@ lemma real_inner_le_norm (x y : F) : ⟪x, y⟫_ℝ ≤ ∥x∥ * ∥y∥ := le_trans (le_abs_self _) (abs_real_inner_le_norm _ _) include 𝕜 -lemma parallelogram_law_with_norm {x y : E} : +lemma parallelogram_law_with_norm (x y : E) : ∥x + y∥ * ∥x + y∥ + ∥x - y∥ * ∥x - y∥ = 2 * (∥x∥ * ∥x∥ + ∥y∥ * ∥y∥) := begin simp only [← inner_self_eq_norm_mul_norm], rw [← re.map_add, parallelogram_law, two_mul, two_mul], simp only [re.map_add], end -omit 𝕜 -lemma parallelogram_law_with_norm_real {x y : F} : - ∥x + y∥ * ∥x + y∥ + ∥x - y∥ * ∥x - y∥ = 2 * (∥x∥ * ∥x∥ + ∥y∥ * ∥y∥) := -by { have h := @parallelogram_law_with_norm ℝ F _ _ x y, simpa using h } +lemma parallelogram_law_with_nnnorm (x y : E) : + ∥x + y∥₊ * ∥x + y∥₊ + ∥x - y∥₊ * ∥x - y∥₊ = 2 * (∥x∥₊ * ∥x∥₊ + ∥y∥₊ * ∥y∥₊) := +subtype.ext $ parallelogram_law_with_norm x y + +omit 𝕜 /-- Polarization identity: The real part of the inner product, in terms of the norm. -/ lemma re_inner_eq_norm_add_mul_self_sub_norm_mul_self_sub_norm_mul_self_div_two (x y : E) : diff --git a/src/analysis/inner_product_space/projection.lean b/src/analysis/inner_product_space/projection.lean index 8d99aa5711458..79a4cd03405e2 100644 --- a/src/analysis/inner_product_space/projection.lean +++ b/src/analysis/inner_product_space/projection.lean @@ -123,7 +123,7 @@ begin have eq₂ : u + u - (wq + wp) = a + b, show u + u - (wq + wp) = (u - wq) + (u - wp), abel, rw [eq₁, eq₂], end - ... = 2 * (∥a∥ * ∥a∥ + ∥b∥ * ∥b∥) : parallelogram_law_with_norm, + ... = 2 * (∥a∥ * ∥a∥ + ∥b∥ * ∥b∥) : parallelogram_law_with_norm _ _, have eq : δ ≤ ∥u - half • (wq + wp)∥, { rw smul_add, apply δ_le', apply h₂, diff --git a/src/analysis/matrix.lean b/src/analysis/matrix.lean index 69df08e69be54..4c6116b54f8c8 100644 --- a/src/analysis/matrix.lean +++ b/src/analysis/matrix.lean @@ -20,6 +20,8 @@ of a matrix. noncomputable theory +open_locale nnreal + namespace matrix variables {R n m α : Type*} [fintype n] [fintype m] @@ -39,14 +41,26 @@ lemma norm_le_iff {r : ℝ} (hr : 0 ≤ r) {A : matrix n m α} : ∥A∥ ≤ r ↔ ∀ i j, ∥A i j∥ ≤ r := by simp [pi_norm_le_iff hr] +lemma nnnorm_le_iff {r : ℝ≥0} {A : matrix n m α} : + ∥A∥₊ ≤ r ↔ ∀ i j, ∥A i j∥₊ ≤ r := +by simp [pi_nnnorm_le_iff] + lemma norm_lt_iff {r : ℝ} (hr : 0 < r) {A : matrix n m α} : ∥A∥ < r ↔ ∀ i j, ∥A i j∥ < r := by simp [pi_norm_lt_iff hr] +lemma nnnorm_lt_iff {r : ℝ≥0} (hr : 0 < r) {A : matrix n m α} : + ∥A∥₊ < r ↔ ∀ i j, ∥A i j∥₊ < r := +by simp [pi_nnnorm_lt_iff hr] + lemma norm_entry_le_entrywise_sup_norm (A : matrix n m α) {i : n} {j : m} : ∥A i j∥ ≤ ∥A∥ := (norm_le_pi_norm (A i) j).trans (norm_le_pi_norm A i) +lemma nnnorm_entry_le_entrywise_sup_nnorm (A : matrix n m α) {i : n} {j : m} : + ∥A i j∥₊ ≤ ∥A∥₊ := +(nnnorm_le_pi_nnnorm (A i) j).trans (nnnorm_le_pi_nnnorm A i) + end semi_normed_group /-- Normed group instance (using sup norm of sup norm) for matrices over a normed ring. Not @@ -55,7 +69,6 @@ matrix. -/ protected def normed_group [normed_group α] : normed_group (matrix n m α) := pi.normed_group - section normed_space local attribute [instance] matrix.semi_normed_group diff --git a/src/analysis/normed/group/basic.lean b/src/analysis/normed/group/basic.lean index e8b3d1a39e6f2..e25e5cbdf344a 100644 --- a/src/analysis/normed/group/basic.lean +++ b/src/analysis/normed/group/basic.lean @@ -550,6 +550,8 @@ instance semi_normed_group.to_has_nnnorm : has_nnnorm E := ⟨λ a, ⟨norm a, n @[simp, norm_cast] lemma coe_nnnorm (a : E) : (∥a∥₊ : ℝ) = norm a := rfl +@[simp] lemma coe_comp_nnnorm : (coe : ℝ≥0 → ℝ) ∘ (nnnorm : E → ℝ≥0) = norm := rfl + lemma norm_to_nnreal {a : E} : ∥a∥.to_nnreal = ∥a∥₊ := @real.to_nnreal_coe ∥a∥₊ @@ -570,6 +572,13 @@ nnreal.eq $ norm_neg g lemma nndist_nnnorm_nnnorm_le (g h : E) : nndist ∥g∥₊ ∥h∥₊ ≤ ∥g - h∥₊ := nnreal.coe_le_coe.1 $ dist_norm_norm_le g h +/-- The direct path from `0` to `v` is shorter than the path with `u` inserted in between. -/ +lemma nnnorm_le_insert (u v : E) : ∥v∥₊ ≤ ∥u∥₊ + ∥u - v∥₊ := norm_le_insert u v + +lemma nnnorm_le_insert' (u v : E) : ∥u∥₊ ≤ ∥v∥₊ + ∥u - v∥₊ := norm_le_insert' u v + +lemma nnnorm_le_add_nnnorm_add (u v : E) : ∥u∥₊ ≤ ∥u + v∥₊ + ∥v∥₊ := norm_le_add_norm_add u v + lemma of_real_norm_eq_coe_nnnorm (x : E) : ennreal.of_real ∥x∥ = (∥x∥₊ : ℝ≥0∞) := ennreal.of_real_eq_coe_nnreal _ @@ -762,16 +771,28 @@ lemma pi_norm_le_iff {π : ι → Type*} [fintype ι] [∀i, semi_normed_group ( (hr : 0 ≤ r) {x : Πi, π i} : ∥x∥ ≤ r ↔ ∀i, ∥x i∥ ≤ r := by simp only [← dist_zero_right, dist_pi_le_iff hr, pi.zero_apply] +lemma pi_nnnorm_le_iff {π : ι → Type*} [fintype ι] [∀i, semi_normed_group (π i)] {r : ℝ≥0} + {x : Πi, π i} : ∥x∥₊ ≤ r ↔ ∀i, ∥x i∥₊ ≤ r := +pi_norm_le_iff r.coe_nonneg + /-- The seminorm of an element in a product space is `< r` if and only if the norm of each component is. -/ lemma pi_norm_lt_iff {π : ι → Type*} [fintype ι] [∀i, semi_normed_group (π i)] {r : ℝ} (hr : 0 < r) {x : Πi, π i} : ∥x∥ < r ↔ ∀i, ∥x i∥ < r := by simp only [← dist_zero_right, dist_pi_lt_iff hr, pi.zero_apply] +lemma pi_nnnorm_lt_iff {π : ι → Type*} [fintype ι] [∀i, semi_normed_group (π i)] {r : ℝ≥0} + (hr : 0 < r) {x : Πi, π i} : ∥x∥₊ < r ↔ ∀i, ∥x i∥₊ < r := +pi_norm_lt_iff hr + lemma norm_le_pi_norm {π : ι → Type*} [fintype ι] [∀i, semi_normed_group (π i)] (x : Πi, π i) (i : ι) : ∥x i∥ ≤ ∥x∥ := (pi_norm_le_iff (norm_nonneg x)).1 le_rfl i +lemma nnnorm_le_pi_nnnorm {π : ι → Type*} [fintype ι] [∀i, semi_normed_group (π i)] (x : Πi, π i) + (i : ι) : ∥x i∥₊ ≤ ∥x∥₊ := +norm_le_pi_norm x i + @[simp] lemma pi_norm_const [nonempty ι] [fintype ι] (a : E) : ∥(λ i : ι, a)∥ = ∥a∥ := by simpa only [← dist_zero_right] using dist_pi_const a 0 @@ -825,6 +846,9 @@ continuous_subtype_mk _ continuous_norm lemma lipschitz_with_one_norm : lipschitz_with 1 (norm : E → ℝ) := by simpa only [dist_zero_left] using lipschitz_with.dist_right (0 : E) +lemma lipschitz_with_one_nnnorm : lipschitz_with 1 (has_nnnorm.nnnorm : E → ℝ≥0) := +lipschitz_with_one_norm + lemma uniform_continuous_norm : uniform_continuous (norm : E → ℝ) := lipschitz_with_one_norm.uniform_continuous diff --git a/src/analysis/normed/normed_field.lean b/src/analysis/normed/normed_field.lean index b22dcdf9bb793..7ca752c84cac2 100644 --- a/src/analysis/normed/normed_field.lean +++ b/src/analysis/normed/normed_field.lean @@ -218,10 +218,16 @@ lemma list.norm_prod_le' : ∀ {l : list α}, l ≠ [] → ∥l.prod∥ ≤ (l.m exact list.norm_prod_le' (list.cons_ne_nil b l) end +lemma list.nnnorm_prod_le' {l : list α} (hl : l ≠ []) : ∥l.prod∥₊ ≤ (l.map nnnorm).prod := +(list.norm_prod_le' hl).trans_eq $ by simp [nnreal.coe_list_prod, list.map_map] + lemma list.norm_prod_le [norm_one_class α] : ∀ l : list α, ∥l.prod∥ ≤ (l.map norm).prod | [] := by simp | (a::l) := list.norm_prod_le' (list.cons_ne_nil a l) +lemma list.nnnorm_prod_le [norm_one_class α] (l : list α) : ∥l.prod∥₊ ≤ (l.map nnnorm).prod := +l.norm_prod_le.trans_eq $ by simp [nnreal.coe_list_prod, list.map_map] + lemma finset.norm_prod_le' {α : Type*} [normed_comm_ring α] (s : finset ι) (hs : s.nonempty) (f : ι → α) : ∥∏ i in s, f i∥ ≤ ∏ i in s, ∥f i∥ := @@ -231,6 +237,11 @@ begin simpa using list.norm_prod_le' this end +lemma finset.nnnorm_prod_le' {α : Type*} [normed_comm_ring α] (s : finset ι) (hs : s.nonempty) + (f : ι → α) : + ∥∏ i in s, f i∥₊ ≤ ∏ i in s, ∥f i∥₊ := +(s.norm_prod_le' hs f).trans_eq $ by simp [nnreal.coe_prod] + lemma finset.norm_prod_le {α : Type*} [normed_comm_ring α] [norm_one_class α] (s : finset ι) (f : ι → α) : ∥∏ i in s, f i∥ ≤ ∏ i in s, ∥f i∥ := @@ -239,6 +250,11 @@ begin simpa using (l.map f).norm_prod_le end +lemma finset.nnnorm_prod_le {α : Type*} [normed_comm_ring α] [norm_one_class α] (s : finset ι) + (f : ι → α) : + ∥∏ i in s, f i∥₊ ≤ ∏ i in s, ∥f i∥₊ := +(s.norm_prod_le f).trans_eq $ by simp [nnreal.coe_prod] + /-- If `α` is a seminormed ring, then `∥a ^ n∥₊ ≤ ∥a∥₊ ^ n` for `n > 0`. See also `nnnorm_pow_le`. -/ lemma nnnorm_pow_le' (a : α) : ∀ {n : ℕ}, 0 < n → ∥a ^ n∥₊ ≤ ∥a∥₊ ^ n @@ -303,6 +319,9 @@ variables [normed_ring α] lemma units.norm_pos [nontrivial α] (x : αˣ) : 0 < ∥(x:α)∥ := norm_pos_iff.mpr (units.ne_zero x) +lemma units.nnorm_pos [nontrivial α] (x : αˣ) : 0 < ∥(x:α)∥₊ := +x.norm_pos + /-- Normed ring structure on the product of two normed rings, using the sup norm. -/ instance prod.normed_ring [normed_ring β] : normed_ring (α × β) := { norm_mul := norm_mul_le, diff --git a/src/analysis/normed_space/operator_norm.lean b/src/analysis/normed_space/operator_norm.lean index f6046400df573..dfa6a1ca83df8 100644 --- a/src/analysis/normed_space/operator_norm.lean +++ b/src/analysis/normed_space/operator_norm.lean @@ -365,7 +365,7 @@ theorem op_norm_add_le : ∥f + g∥ ≤ ∥f∥ + ∥g∥ := /-- The norm of the `0` operator is `0`. -/ theorem op_norm_zero : ∥(0 : E →SL[σ₁₂] F)∥ = 0 := le_antisymm (cInf_le bounds_bdd_below - ⟨ge_of_eq rfl, λ _, le_of_eq (by { rw [zero_mul], exact norm_zero })⟩) + ⟨le_rfl, λ _, le_of_eq (by { rw [zero_mul], exact norm_zero })⟩) (op_norm_nonneg _) /-- The norm of the identity is at most `1`. It is in fact `1`, except when the space is trivial @@ -394,6 +394,14 @@ lemma op_norm_smul_le {𝕜' : Type*} [normed_field 𝕜'] [normed_space 𝕜' F instance to_semi_normed_group : semi_normed_group (E →SL[σ₁₂] F) := semi_normed_group.of_core _ ⟨op_norm_zero, λ x y, op_norm_add_le x y, op_norm_neg⟩ +lemma nnnorm_def (f : E →SL[σ₁₂] F) : ∥f∥₊ = Inf {c | ∀ x, ∥f x∥₊ ≤ c * ∥x∥₊} := +begin + ext, + rw [nnreal.coe_Inf, coe_nnnorm, norm_def, nnreal.coe_image], + simp_rw [← nnreal.coe_le_coe, nnreal.coe_mul, coe_nnnorm, mem_set_of_eq, subtype.coe_mk, + exists_prop], +end + instance to_normed_space {𝕜' : Type*} [normed_field 𝕜'] [normed_space 𝕜' F] [smul_comm_class 𝕜₂ 𝕜' F] : normed_space 𝕜' (E →SL[σ₁₂] F) := ⟨op_norm_smul_le⟩ @@ -404,6 +412,9 @@ lemma op_norm_comp_le (f : E →SL[σ₁₂] F) : ∥h.comp f∥ ≤ ∥h∥ * (cInf_le bounds_bdd_below ⟨mul_nonneg (op_norm_nonneg _) (op_norm_nonneg _), λ x, by { rw mul_assoc, exact h.le_op_norm_of_le (f.le_op_norm x) } ⟩) + +lemma op_nnnorm_comp_le [ring_hom_isometric σ₁₃] (f : E →SL[σ₁₂] F) : ∥h.comp f∥₊ ≤ ∥h∥₊ * ∥f∥₊ := +op_norm_comp_le h f omit σ₁₃ /-- Continuous linear maps form a seminormed ring with respect to the operator norm. -/ diff --git a/src/analysis/normed_space/pi_Lp.lean b/src/analysis/normed_space/pi_Lp.lean index f0bf4fd1c32b2..e6a0b78cc11e6 100644 --- a/src/analysis/normed_space/pi_Lp.lean +++ b/src/analysis/normed_space/pi_Lp.lean @@ -285,6 +285,11 @@ lemma norm_eq {p : ℝ} [fact (1 ≤ p)] {β : ι → Type*} [∀i, semi_normed_group (β i)] (f : pi_Lp p β) : ∥f∥ = (∑ (i : ι), ∥f i∥ ^ p) ^ (1/p) := rfl +lemma nnnorm_eq {p : ℝ} [fact (1 ≤ p)] {β : ι → Type*} + [∀i, semi_normed_group (β i)] (f : pi_Lp p β) : + ∥f∥₊ = (∑ (i : ι), ∥f i∥₊ ^ p) ^ (1/p) := +by { ext, simp [nnreal.coe_sum, norm_eq] } + lemma norm_eq_of_nat {p : ℝ} [fact (1 ≤ p)] {β : ι → Type*} [∀i, semi_normed_group (β i)] (n : ℕ) (h : p = n) (f : pi_Lp p β) : ∥f∥ = (∑ (i : ι), ∥f i∥ ^ n) ^ (1/(n : ℝ)) := diff --git a/src/analysis/normed_space/star/basic.lean b/src/analysis/normed_space/star/basic.lean index 44415cc4db6aa..fcff072e8b481 100644 --- a/src/analysis/normed_space/star/basic.lean +++ b/src/analysis/normed_space/star/basic.lean @@ -46,6 +46,8 @@ variables {𝕜 E α : Type*} section normed_star_group variables [semi_normed_group E] [star_add_monoid E] [normed_star_group E] +@[simp] lemma nnnorm_star (x : E) : ∥star x∥₊ = ∥x∥₊ := subtype.ext norm_star + /-- The `star` map in a normed star group is a normed group homomorphism. -/ def star_normed_group_hom : normed_group_hom E E := { bound' := ⟨1, λ v, le_trans (norm_star.le) (one_mul _).symm.le⟩, diff --git a/src/analysis/quaternion.lean b/src/analysis/quaternion.lean index 9d9fb10d71a95..c5fdbf03e0ca9 100644 --- a/src/analysis/quaternion.lean +++ b/src/analysis/quaternion.lean @@ -57,6 +57,9 @@ instance : norm_one_class ℍ := @[simp, norm_cast] lemma norm_coe (a : ℝ) : ∥(a : ℍ)∥ = ∥a∥ := by rw [norm_eq_sqrt_real_inner, inner_self, norm_sq_coe, real.sqrt_sq_eq_abs, real.norm_eq_abs] +@[simp, norm_cast] lemma nnorm_coe (a : ℝ) : ∥(a : ℍ)∥₊ = ∥a∥₊ := +subtype.ext $ norm_coe a + noncomputable instance : normed_division_ring ℍ := { dist_eq := λ _ _, rfl, norm_mul' := λ a b, by { simp only [norm_eq_sqrt_real_inner, inner_self, norm_sq.map_mul], diff --git a/src/data/real/nnreal.lean b/src/data/real/nnreal.lean index 4a93b6a1520a6..7a104f186e3f5 100644 --- a/src/data/real/nnreal.lean +++ b/src/data/real/nnreal.lean @@ -283,6 +283,10 @@ example : canonically_ordered_comm_semiring ℝ≥0 := by apply_instance example : densely_ordered ℝ≥0 := by apply_instance example : no_max_order ℝ≥0 := by apply_instance +-- note we need the `@` to make the `has_mem.mem` have a sensible type +lemma coe_image {s : set ℝ≥0} : coe '' s = {x : ℝ | ∃ h : 0 ≤ x, @has_mem.mem (ℝ≥0) _ _ ⟨x, h⟩ s} := +subtype.coe_image + lemma bdd_above_coe {s : set ℝ≥0} : bdd_above ((coe : ℝ≥0 → ℝ) '' s) ↔ bdd_above s := iff.intro (assume ⟨b, hb⟩, ⟨real.to_nnreal b, assume ⟨y, hy⟩ hys, show y ≤ max b 0, from @@ -295,14 +299,20 @@ lemma bdd_below_coe (s : set ℝ≥0) : bdd_below ((coe : ℝ≥0 → ℝ) '' s) noncomputable instance : conditionally_complete_linear_order_bot ℝ≥0 := nonneg.conditionally_complete_linear_order_bot real.Sup_empty.le -lemma coe_Sup (s : set ℝ≥0) : (↑(Sup s) : ℝ) = Sup ((coe : ℝ≥0 → ℝ) '' s) := +@[norm_cast] lemma coe_Sup (s : set ℝ≥0) : (↑(Sup s) : ℝ) = Sup ((coe : ℝ≥0 → ℝ) '' s) := eq.symm $ @subset_Sup_of_within ℝ (set.Ici 0) _ ⟨(0 : ℝ≥0)⟩ s $ real.Sup_nonneg _ $ λ y ⟨x, _, hy⟩, hy ▸ x.2 -lemma coe_Inf (s : set ℝ≥0) : (↑(Inf s) : ℝ) = Inf ((coe : ℝ≥0 → ℝ) '' s) := +@[norm_cast] lemma coe_supr {ι : Sort*} (s : ι → ℝ≥0) : (↑(⨆ i, s i) : ℝ) = ⨆ i, (s i) := +by rw [supr, supr, coe_Sup, set.range_comp] + +@[norm_cast] lemma coe_Inf (s : set ℝ≥0) : (↑(Inf s) : ℝ) = Inf ((coe : ℝ≥0 → ℝ) '' s) := eq.symm $ @subset_Inf_of_within ℝ (set.Ici 0) _ ⟨(0 : ℝ≥0)⟩ s $ real.Inf_nonneg _ $ λ y ⟨x, _, hy⟩, hy ▸ x.2 +@[norm_cast] lemma coe_infi {ι : Sort*} (s : ι → ℝ≥0) : (↑(⨅ i, s i) : ℝ) = ⨅ i, (s i) := +by rw [infi, infi, coe_Inf, set.range_comp] + example : archimedean ℝ≥0 := by apply_instance -- TODO: why are these three instances necessary? why aren't they inferred? diff --git a/src/topology/continuous_function/bounded.lean b/src/topology/continuous_function/bounded.lean index 0a4bd7cb01c0c..f83d3f09fb856 100644 --- a/src/topology/continuous_function/bounded.lean +++ b/src/topology/continuous_function/bounded.lean @@ -180,6 +180,18 @@ instance : metric_space (α →ᵇ β) := (dist_le (add_nonneg dist_nonneg' dist_nonneg')).2 $ λ x, le_trans (dist_triangle _ _ _) (add_le_add (dist_coe_le_dist _) (dist_coe_le_dist _)) } +lemma nndist_eq : nndist f g = Inf {C | ∀ x : α, nndist (f x) (g x) ≤ C} := +subtype.ext $ dist_eq.trans $ begin + rw [nnreal.coe_Inf, nnreal.coe_image], + simp_rw [mem_set_of_eq, ←nnreal.coe_le_coe, subtype.coe_mk, exists_prop, coe_nndist], +end + +lemma nndist_set_exists : ∃ C, ∀ x : α, nndist (f x) (g x) ≤ C := +subtype.exists.mpr $ dist_set_exists.imp $ λ a ⟨ha, h⟩, ⟨ha, h⟩ + +lemma nndist_coe_le_nndist (x : α) : nndist (f x) (g x) ≤ nndist f g := +dist_coe_le_dist x + /-- On an empty space, bounded continuous functions are at distance 0 -/ lemma dist_zero_of_empty [is_empty α] : dist f g = 0 := dist_eq_zero.2 (eq_of_empty f g) @@ -191,6 +203,9 @@ begin exact dist_set_exists.imp (λ C hC, forall_range_iff.2 hC.2) end +lemma nndist_eq_supr : nndist f g = ⨆ x : α, nndist (f x) (g x) := +subtype.ext $ dist_eq_supr.trans $ by simp_rw [nnreal.coe_supr, coe_nndist] + lemma tendsto_iff_tendsto_uniformly {ι : Type*} {F : ι → (α →ᵇ β)} {f : α →ᵇ β} {l : filter ι} : tendsto F l (𝓝 f) ↔ tendsto_uniformly (λ i, F i) f l := iff.intro @@ -777,16 +792,7 @@ lemma bdd_above_range_norm_comp : bdd_above $ set.range $ norm ∘ f := (real.bounded_iff_bdd_below_bdd_above.mp $ @bounded_range _ _ _ _ f.norm_comp).2 lemma norm_eq_supr_norm : ∥f∥ = ⨆ x : α, ∥f x∥ := -begin - casesI is_empty_or_nonempty α with hα _, - { suffices : range (norm ∘ f) = ∅, { rw [f.norm_eq_zero_of_empty, supr, this, real.Sup_empty], }, - simp only [hα, range_eq_empty, not_nonempty_iff], }, - { rw [norm_eq_of_nonempty, supr, - ← cInf_upper_bounds_eq_cSup f.bdd_above_range_norm_comp (range_nonempty _)], - congr, - ext, - simp only [forall_apply_eq_imp_iff', mem_range, exists_imp_distrib], }, -end +by simp_rw [norm_def, dist_eq_supr, coe_zero, pi.zero_apply, dist_zero_right] /-- The pointwise opposite of a bounded continuous function is again bounded continuous. -/ instance : has_neg (α →ᵇ β) := @@ -831,6 +837,25 @@ fun_like.coe_injective.add_comm_group _ coe_zero coe_add coe_neg coe_sub (λ _ _ instance : normed_group (α →ᵇ β) := { dist_eq := λ f g, by simp only [norm_eq, dist_eq, dist_eq_norm, sub_apply] } +lemma nnnorm_def : ∥f∥₊ = nndist f 0 := rfl + +lemma nnnorm_coe_le_nnnorm (x : α) : ∥f x∥₊ ≤ ∥f∥₊ := norm_coe_le_norm _ _ + +lemma nndist_le_two_nnnorm (x y : α) : nndist (f x) (f y) ≤ 2 * ∥f∥₊ := dist_le_two_norm _ _ _ + +/-- The nnnorm of a function is controlled by the supremum of the pointwise nnnorms -/ +lemma nnnorm_le (C : ℝ≥0) : ∥f∥₊ ≤ C ↔ ∀x:α, ∥f x∥₊ ≤ C := +norm_le C.prop + +lemma nnnorm_const_le (b : β) : ∥const α b∥₊ ≤ ∥b∥₊ := +norm_const_le _ + +@[simp] lemma nnnorm_const_eq [h : nonempty α] (b : β) : ∥const α b∥₊ = ∥b∥₊ := +subtype.ext $ norm_const_eq _ + +lemma nnnorm_eq_supr_nnnorm : ∥f∥₊ = ⨆ x : α, ∥f x∥₊ := +subtype.ext $ (norm_eq_supr_norm f).trans $ by simp_rw [nnreal.coe_supr, coe_nnnorm] + lemma abs_diff_coe_le_dist : ∥f x - g x∥ ≤ dist f g := by { rw dist_eq_norm, exact (f - g).norm_coe_le_norm x } diff --git a/src/topology/metric_space/isometry.lean b/src/topology/metric_space/isometry.lean index 16032a61bb9da..c7dd5d2fb9c5d 100644 --- a/src/topology/metric_space/isometry.lean +++ b/src/topology/metric_space/isometry.lean @@ -46,6 +46,11 @@ theorem isometry.dist_eq [pseudo_metric_space α] [pseudo_metric_space β] {f : (hf : isometry f) (x y : α) : dist (f x) (f y) = dist x y := by rw [dist_edist, dist_edist, hf] +/-- An isometry preserves non-negative distances. -/ +theorem isometry.nndist_eq [pseudo_metric_space α] [pseudo_metric_space β] {f : α → β} + (hf : isometry f) (x y : α) : nndist (f x) (f y) = nndist x y := +subtype.ext $ hf.dist_eq x y + section pseudo_emetric_isometry variables [pseudo_emetric_space α] [pseudo_emetric_space β] [pseudo_emetric_space γ] @@ -233,6 +238,10 @@ protected lemma dist_eq {α β : Type*} [pseudo_metric_space α] [pseudo_metric_ (x y : α) : dist (h x) (h y) = dist x y := h.isometry.dist_eq x y +protected lemma nndist_eq {α β : Type*} [pseudo_metric_space α] [pseudo_metric_space β] (h : α ≃ᵢ β) + (x y : α) : nndist (h x) (h y) = nndist x y := +h.isometry.nndist_eq x y + protected lemma continuous (h : α ≃ᵢ β) : continuous h := h.isometry.continuous @[simp] lemma ediam_image (h : α ≃ᵢ β) (s : set α) : emetric.diam (h '' s) = emetric.diam s := From 3ac979a211c8ecaecb01ca020b191bb1a5b8a4d1 Mon Sep 17 00:00:00 2001 From: Floris van Doorn Date: Tue, 19 Apr 2022 19:41:21 +0000 Subject: [PATCH 086/373] feat(analysis/calculus/specific_functions): trivial extra lemmas (#13516) --- src/analysis/calculus/specific_functions.lean | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/analysis/calculus/specific_functions.lean b/src/analysis/calculus/specific_functions.lean index 7a60b5ea6d9bd..19527e8b03d77 100644 --- a/src/analysis/calculus/specific_functions.lean +++ b/src/analysis/calculus/specific_functions.lean @@ -230,6 +230,12 @@ lemma one_of_one_le (h : 1 ≤ x) : smooth_transition x = 1 := lemma zero_of_nonpos (h : x ≤ 0) : smooth_transition x = 0 := by rw [smooth_transition, zero_of_nonpos h, zero_div] +@[simp] protected lemma zero : smooth_transition 0 = 0 := +zero_of_nonpos le_rfl + +@[simp] protected lemma one : smooth_transition 1 = 1 := +one_of_one_le le_rfl + lemma le_one (x : ℝ) : smooth_transition x ≤ 1 := (div_le_one (pos_denom x)).2 $ le_add_of_nonneg_right (nonneg _) @@ -251,6 +257,9 @@ exp_neg_inv_glue.cont_diff.div protected lemma cont_diff_at {x n} : cont_diff_at ℝ n smooth_transition x := smooth_transition.cont_diff.cont_diff_at +protected lemma continuous : continuous smooth_transition := +(@smooth_transition.cont_diff 0).continuous + end smooth_transition end real From 094b1f51f1da3fe34a87bc6f1294c0129039062d Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Tue, 19 Apr 2022 20:26:47 +0000 Subject: [PATCH 087/373] chore(*/matrix): order `m` and `n` alphabetically (#13510) In a few places this also reorders `(n) [fintype n] (m) [fintype m]` to `(m n) [fintype m] [fintype n]` which seems to be where we prefer to put typeclasses. --- src/analysis/matrix.lean | 20 ++++---- src/data/matrix/basic.lean | 50 +++++++++---------- src/data/matrix/basis.lean | 6 +-- src/linear_algebra/free_module/basic.lean | 5 +- .../free_module/finite/rank.lean | 8 +-- src/linear_algebra/free_module/rank.lean | 22 ++++---- src/linear_algebra/matrix/to_lin.lean | 4 +- src/linear_algebra/std_basis.lean | 8 +-- src/topology/algebra/matrix.lean | 6 +-- 9 files changed, 64 insertions(+), 65 deletions(-) diff --git a/src/analysis/matrix.lean b/src/analysis/matrix.lean index 4c6116b54f8c8..8996b3a54ae20 100644 --- a/src/analysis/matrix.lean +++ b/src/analysis/matrix.lean @@ -24,7 +24,7 @@ open_locale nnreal namespace matrix -variables {R n m α : Type*} [fintype n] [fintype m] +variables {R m n α : Type*} [fintype m] [fintype n] section semi_normed_group variables [semi_normed_group α] @@ -32,32 +32,32 @@ variables [semi_normed_group α] /-- Seminormed group instance (using sup norm of sup norm) for matrices over a seminormed ring. Not declared as an instance because there are several natural choices for defining the norm of a matrix. -/ -protected def semi_normed_group : semi_normed_group (matrix n m α) := +protected def semi_normed_group : semi_normed_group (matrix m n α) := pi.semi_normed_group local attribute [instance] matrix.semi_normed_group -lemma norm_le_iff {r : ℝ} (hr : 0 ≤ r) {A : matrix n m α} : +lemma norm_le_iff {r : ℝ} (hr : 0 ≤ r) {A : matrix m n α} : ∥A∥ ≤ r ↔ ∀ i j, ∥A i j∥ ≤ r := by simp [pi_norm_le_iff hr] -lemma nnnorm_le_iff {r : ℝ≥0} {A : matrix n m α} : +lemma nnnorm_le_iff {r : ℝ≥0} {A : matrix m n α} : ∥A∥₊ ≤ r ↔ ∀ i j, ∥A i j∥₊ ≤ r := by simp [pi_nnnorm_le_iff] -lemma norm_lt_iff {r : ℝ} (hr : 0 < r) {A : matrix n m α} : +lemma norm_lt_iff {r : ℝ} (hr : 0 < r) {A : matrix m n α} : ∥A∥ < r ↔ ∀ i j, ∥A i j∥ < r := by simp [pi_norm_lt_iff hr] -lemma nnnorm_lt_iff {r : ℝ≥0} (hr : 0 < r) {A : matrix n m α} : +lemma nnnorm_lt_iff {r : ℝ≥0} (hr : 0 < r) {A : matrix m n α} : ∥A∥₊ < r ↔ ∀ i j, ∥A i j∥₊ < r := by simp [pi_nnnorm_lt_iff hr] -lemma norm_entry_le_entrywise_sup_norm (A : matrix n m α) {i : n} {j : m} : +lemma norm_entry_le_entrywise_sup_norm (A : matrix m n α) {i : m} {j : n} : ∥A i j∥ ≤ ∥A∥ := (norm_le_pi_norm (A i) j).trans (norm_le_pi_norm A i) -lemma nnnorm_entry_le_entrywise_sup_nnorm (A : matrix n m α) {i : n} {j : m} : +lemma nnnorm_entry_le_entrywise_sup_nnorm (A : matrix m n α) {i : m} {j : n} : ∥A i j∥₊ ≤ ∥A∥₊ := (nnnorm_le_pi_nnnorm (A i) j).trans (nnnorm_le_pi_nnnorm A i) @@ -66,7 +66,7 @@ end semi_normed_group /-- Normed group instance (using sup norm of sup norm) for matrices over a normed ring. Not declared as an instance because there are several natural choices for defining the norm of a matrix. -/ -protected def normed_group [normed_group α] : normed_group (matrix n m α) := +protected def normed_group [normed_group α] : normed_group (matrix m n α) := pi.normed_group section normed_space @@ -77,7 +77,7 @@ variables [normed_field R] [semi_normed_group α] [normed_space R α] /-- Normed space instance (using sup norm of sup norm) for matrices over a normed field. Not declared as an instance because there are several natural choices for defining the norm of a matrix. -/ -protected def normed_space : normed_space R (matrix n m α) := +protected def normed_space : normed_space R (matrix m n α) := pi.normed_space end normed_space diff --git a/src/data/matrix/basic.lean b/src/data/matrix/basic.lean index 1a4550e16e158..c272c62249e75 100644 --- a/src/data/matrix/basic.lean +++ b/src/data/matrix/basic.lean @@ -1052,8 +1052,8 @@ lemma add_vec_mul [fintype m] (A : matrix m n α) (x y : m → α) : vec_mul (x + y) A = vec_mul x A + vec_mul y A := by { ext, apply add_dot_product } -lemma vec_mul_smul [fintype n] [comm_semiring R] [semiring S] [algebra R S] - (M : matrix n m S) (b : R) (v : n → S) : +lemma vec_mul_smul [fintype m] [comm_semiring R] [semiring S] [algebra R S] + (M : matrix m n S) (b : R) (v : m → S) : M.vec_mul (b • v) = b • M.vec_mul v := by { ext i, simp only [vec_mul, dot_product, finset.smul_sum, pi.smul_apply, smul_mul_assoc] } @@ -1485,8 +1485,8 @@ lemma conj_transpose_reindex [has_star α] (eₘ : m ≃ l) (eₙ : n ≃ o) (M rfl @[simp] -lemma minor_mul_transpose_minor [fintype n] [fintype m] [semiring α] - (e : n ≃ m) (M : matrix n m α) : +lemma minor_mul_transpose_minor [fintype m] [fintype n] [semiring α] + (e : m ≃ n) (M : matrix m n α) : (M.minor id e) ⬝ (Mᵀ).minor e id = M ⬝ Mᵀ := by rw [minor_mul_equiv, minor_id_id] @@ -1581,28 +1581,28 @@ end row_col section update /-- Update, i.e. replace the `i`th row of matrix `A` with the values in `b`. -/ -def update_row [decidable_eq n] (M : matrix n m α) (i : n) (b : m → α) : matrix n m α := +def update_row [decidable_eq m] (M : matrix m n α) (i : m) (b : n → α) : matrix m n α := function.update M i b /-- Update, i.e. replace the `j`th column of matrix `A` with the values in `b`. -/ -def update_column [decidable_eq m] (M : matrix n m α) (j : m) (b : n → α) : matrix n m α := +def update_column [decidable_eq n] (M : matrix m n α) (j : n) (b : m → α) : matrix m n α := λ i, function.update (M i) j (b i) -variables {M : matrix n m α} {i : n} {j : m} {b : m → α} {c : n → α} +variables {M : matrix m n α} {i : m} {j : n} {b : n → α} {c : m → α} -@[simp] lemma update_row_self [decidable_eq n] : update_row M i b i = b := +@[simp] lemma update_row_self [decidable_eq m] : update_row M i b i = b := function.update_same i b M -@[simp] lemma update_column_self [decidable_eq m] : update_column M j c i j = c i := +@[simp] lemma update_column_self [decidable_eq n] : update_column M j c i j = c i := function.update_same j (c i) (M i) -@[simp] lemma update_row_ne [decidable_eq n] {i' : n} (i_ne : i' ≠ i) : +@[simp] lemma update_row_ne [decidable_eq m] {i' : m} (i_ne : i' ≠ i) : update_row M i b i' = M i' := function.update_noteq i_ne b M -@[simp] lemma update_column_ne [decidable_eq m] {j' : m} (j_ne : j' ≠ j) : +@[simp] lemma update_column_ne [decidable_eq n] {j' : n} (j_ne : j' ≠ j) : update_column M j c i j' = M i j' := function.update_noteq j_ne (c i) (M i) -lemma update_row_apply [decidable_eq n] {i' : n} : +lemma update_row_apply [decidable_eq m] {i' : m} : update_row M i b i' j = if i' = i then b j else M i' j := begin by_cases i' = i, @@ -1610,7 +1610,7 @@ begin { rwa [update_row_ne h, if_neg h] } end -lemma update_column_apply [decidable_eq m] {j' : m} : +lemma update_column_apply [decidable_eq n] {j' : n} : update_column M j c i j' = if j' = j then c i else M i j' := begin by_cases j' = j, @@ -1618,23 +1618,23 @@ begin { rwa [update_column_ne h, if_neg h] } end -@[simp] lemma update_column_subsingleton [subsingleton m] (A : matrix n m R) - (i : m) (b : n → R) : - A.update_column i b = (col b).minor id (function.const m ()) := +@[simp] lemma update_column_subsingleton [subsingleton n] (A : matrix m n R) + (i : n) (b : m → R) : + A.update_column i b = (col b).minor id (function.const n ()) := begin ext x y, simp [update_column_apply, subsingleton.elim i y] end -@[simp] lemma update_row_subsingleton [subsingleton n] (A : matrix n m R) - (i : n) (b : m → R) : - A.update_row i b = (row b).minor (function.const n ()) id := +@[simp] lemma update_row_subsingleton [subsingleton m] (A : matrix m n R) + (i : m) (b : n → R) : + A.update_row i b = (row b).minor (function.const m ()) id := begin ext x y, simp [update_column_apply, subsingleton.elim i x] end -lemma map_update_row [decidable_eq n] (f : α → β) : +lemma map_update_row [decidable_eq m] (f : α → β) : map (update_row M i b) f = update_row (M.map f) i (f ∘ b) := begin ext i' j', @@ -1642,7 +1642,7 @@ begin exact apply_ite f _ _ _, end -lemma map_update_column [decidable_eq m] (f : α → β) : +lemma map_update_column [decidable_eq n] (f : α → β) : map (update_column M j c) f = update_column (M.map f) j (f ∘ c) := begin ext i' j', @@ -1650,21 +1650,21 @@ begin exact apply_ite f _ _ _, end -lemma update_row_transpose [decidable_eq m] : update_row Mᵀ j c = (update_column M j c)ᵀ := +lemma update_row_transpose [decidable_eq n] : update_row Mᵀ j c = (update_column M j c)ᵀ := begin ext i' j, rw [transpose_apply, update_row_apply, update_column_apply], refl end -lemma update_column_transpose [decidable_eq n] : update_column Mᵀ i b = (update_row M i b)ᵀ := +lemma update_column_transpose [decidable_eq m] : update_column Mᵀ i b = (update_row M i b)ᵀ := begin ext i' j, rw [transpose_apply, update_row_apply, update_column_apply], refl end -lemma update_row_conj_transpose [decidable_eq m] [has_star α] : +lemma update_row_conj_transpose [decidable_eq n] [has_star α] : update_row Mᴴ j (star c) = (update_column M j c)ᴴ := begin rw [conj_transpose, conj_transpose, transpose_map, transpose_map, update_row_transpose, @@ -1672,7 +1672,7 @@ begin refl, end -lemma update_column_conj_transpose [decidable_eq n] [has_star α] : +lemma update_column_conj_transpose [decidable_eq m] [has_star α] : update_column Mᴴ i (star b) = (update_row M i b)ᴴ := begin rw [conj_transpose, conj_transpose, transpose_map, transpose_map, update_column_transpose, diff --git a/src/data/matrix/basis.lean b/src/data/matrix/basis.lean index d3b4dfdf17b33..7a022894374df 100644 --- a/src/data/matrix/basis.lean +++ b/src/data/matrix/basis.lean @@ -46,8 +46,8 @@ begin split_ifs with h; simp [h], end -lemma matrix_eq_sum_std_basis (x : matrix n m α) [fintype n] [fintype m] : - x = ∑ (i : n) (j : m), std_basis_matrix i j (x i j) := +lemma matrix_eq_sum_std_basis [fintype m] [fintype n] (x : matrix m n α) : + x = ∑ (i : m) (j : n), std_basis_matrix i j (x i j) := begin ext, symmetry, iterate 2 { rw finset.sum_apply }, @@ -62,7 +62,7 @@ end -- TODO: add `std_basis_vec` lemma std_basis_eq_basis_mul_basis (i : m) (j : n) : -std_basis_matrix i j 1 = vec_mul_vec (λ i', ite (i = i') 1 0) (λ j', ite (j = j') 1 0) := + std_basis_matrix i j 1 = vec_mul_vec (λ i', ite (i = i') 1 0) (λ j', ite (j = j') 1 0) := begin ext, norm_num [std_basis_matrix, vec_mul_vec], diff --git a/src/linear_algebra/free_module/basic.lean b/src/linear_algebra/free_module/basic.lean index 705aebe407061..243ccdabbde6a 100644 --- a/src/linear_algebra/free_module/basic.lean +++ b/src/linear_algebra/free_module/basic.lean @@ -97,9 +97,8 @@ instance pi {ι : Type*} [fintype ι] {M : ι → Type*} [Π (i : ι), add_comm_ of_basis $ pi.basis $ λ i, choose_basis R (M i) /-- The module of finite matrices is free. -/ -instance matrix {n : Type*} [fintype n] {m : Type*} [fintype m] : - module.free R (matrix n m R) := -of_basis $ matrix.std_basis R n m +instance matrix {m n : Type*} [fintype m] [fintype n] : module.free R (matrix m n R) := +of_basis $ matrix.std_basis R m n variables {R M N} diff --git a/src/linear_algebra/free_module/finite/rank.lean b/src/linear_algebra/free_module/finite/rank.lean index 7b5ee1edee0b6..e82c8e6b8d928 100644 --- a/src/linear_algebra/free_module/finite/rank.lean +++ b/src/linear_algebra/free_module/finite/rank.lean @@ -87,10 +87,10 @@ begin ← mk_sigma, mk_to_nat_eq_card, card_sigma], end -/-- If `n` and `m` are `fintype`, the finrank of `n × m` matrices is - `(fintype.card n) * (fintype.card m)`. -/ -lemma finrank_matrix (n : Type v) [fintype n] (m : Type w) [fintype m] : - finrank R (matrix n m R) = (card n) * (card m) := +/-- If `m` and `n` are `fintype`, the finrank of `m × n` matrices is + `(fintype.card m) * (fintype.card n)`. -/ +lemma finrank_matrix (m n : Type v) [fintype m] [fintype n] : + finrank R (matrix m n R) = (card m) * (card n) := by { simp [finrank] } end ring diff --git a/src/linear_algebra/free_module/rank.lean b/src/linear_algebra/free_module/rank.lean index d363b6bfd33bb..f4457a08efbbe 100644 --- a/src/linear_algebra/free_module/rank.lean +++ b/src/linear_algebra/free_module/rank.lean @@ -70,25 +70,25 @@ end module.rank R (Π i, M i) = cardinal.sum (λ i, module.rank R (M i)) := by { rw [← (direct_sum.linear_equiv_fun_on_fintype _ _ M).dim_eq, rank_direct_sum] } -/-- If `n` and `m` are `fintype`, the rank of `n × m` matrices is `(# n).lift * (# m).lift`. -/ -@[simp] lemma rank_matrix (n : Type v) [fintype n] (m : Type w) [fintype m] : - module.rank R (matrix n m R) = (lift.{(max v w u) v} (# n)) * (lift.{(max v w u) w} (# m)) := +/-- If `m` and `n` are `fintype`, the rank of `m × n` matrices is `(# m).lift * (# n).lift`. -/ +@[simp] lemma rank_matrix (m : Type v) (n : Type w) [fintype m] [fintype n] : + module.rank R (matrix m n R) = (lift.{(max v w u) v} (# m)) * (lift.{(max v w u) w} (# n)) := begin - have h := (matrix.std_basis R n m).mk_eq_dim, + have h := (matrix.std_basis R m n).mk_eq_dim, rw [← lift_lift.{(max v w u) (max v w)}, lift_inj] at h, simpa using h.symm, end -/-- If `n` and `m` are `fintype` that lie in the same universe, the rank of `n × m` matrices is +/-- If `m` and `n` are `fintype` that lie in the same universe, the rank of `m × n` matrices is `(# n * # m).lift`. -/ -@[simp] lemma rank_matrix' (n : Type v) [fintype n] (m : Type v) [fintype m] : - module.rank R (matrix n m R) = (# n * # m).lift := +@[simp] lemma rank_matrix' (m n : Type v) [fintype m] [fintype n] : + module.rank R (matrix m n R) = (# m * # n).lift := by rw [rank_matrix, lift_mul, lift_umax] -/-- If `n` and `m` are `fintype` that lie in the same universe as `R`, the rank of `n × m` matrices - is `# n * # m`. -/ -@[simp] lemma rank_matrix'' (n : Type u) [fintype n] (m : Type u) [fintype m] : - module.rank R (matrix n m R) = # n * # m := by simp +/-- If `m` and `n` are `fintype` that lie in the same universe as `R`, the rank of `m × n` matrices + is `# m * # n`. -/ +@[simp] lemma rank_matrix'' (m n : Type u) [fintype m] [fintype n] : + module.rank R (matrix m n R) = # m * # n := by simp end ring diff --git a/src/linear_algebra/matrix/to_lin.lean b/src/linear_algebra/matrix/to_lin.lean index 72c3054c71bf5..7b2dfbfbc4e32 100644 --- a/src/linear_algebra/matrix/to_lin.lean +++ b/src/linear_algebra/matrix/to_lin.lean @@ -26,8 +26,8 @@ types used for indexing. * `linear_map.to_matrix`: given bases `v₁ : ι → M₁` and `v₂ : κ → M₂`, the `R`-linear equivalence from `M₁ →ₗ[R] M₂` to `matrix κ ι R` * `matrix.to_lin`: the inverse of `linear_map.to_matrix` - * `linear_map.to_matrix'`: the `R`-linear equivalence from `(n → R) →ₗ[R] (m → R)` - to `matrix n m R` (with the standard basis on `n → R` and `m → R`) + * `linear_map.to_matrix'`: the `R`-linear equivalence from `(m → R) →ₗ[R] (n → R)` + to `matrix m n R` (with the standard basis on `m → R` and `n → R`) * `matrix.to_lin'`: the inverse of `linear_map.to_matrix'` * `alg_equiv_matrix`: given a basis indexed by `n`, the `R`-algebra equivalence between `R`-endomorphisms of `M` and `matrix n n R` diff --git a/src/linear_algebra/std_basis.lean b/src/linear_algebra/std_basis.lean index 1092e00ed8a6e..152612e47dd6d 100644 --- a/src/linear_algebra/std_basis.lean +++ b/src/linear_algebra/std_basis.lean @@ -262,11 +262,11 @@ end pi namespace matrix -variables (R : Type*) (n : Type*) (m : Type*) [fintype m] [fintype n] [semiring R] +variables (R : Type*) (m n : Type*) [fintype m] [fintype n] [semiring R] -/-- The standard basis of `matrix n m R`. -/ -noncomputable def std_basis : basis (n × m) R (matrix n m R) := -basis.reindex (pi.basis (λ (i : n), pi.basis_fun R m)) (equiv.sigma_equiv_prod _ _) +/-- The standard basis of `matrix m n R`. -/ +noncomputable def std_basis : basis (m × n) R (matrix m n R) := +basis.reindex (pi.basis (λ (i : m), pi.basis_fun R n)) (equiv.sigma_equiv_prod _ _) variables {n m} diff --git a/src/topology/algebra/matrix.lean b/src/topology/algebra/matrix.lean index 18ead64501125..f099572743c6d 100644 --- a/src/topology/algebra/matrix.lean +++ b/src/topology/algebra/matrix.lean @@ -45,19 +45,19 @@ lemma continuous.matrix_elem {A : X → matrix m n R} (hA : continuous A) (i : m (continuous_apply_apply i j).comp hA @[continuity] -lemma continuous.matrix_map [topological_space S] {A : X → matrix n m S} {f : S → R} +lemma continuous.matrix_map [topological_space S] {A : X → matrix m n S} {f : S → R} (hA : continuous A) (hf : continuous f) : continuous (λ x, (A x).map f) := continuous_matrix $ λ i j, hf.comp $ hA.matrix_elem _ _ @[continuity] -lemma continuous.matrix_transpose {A : X → matrix n m R} (hA : continuous A) : +lemma continuous.matrix_transpose {A : X → matrix m n R} (hA : continuous A) : continuous (λ x, (A x)ᵀ) := continuous_matrix $ λ i j, hA.matrix_elem j i /-! TODO: add a `has_continuous_star` typeclass so we can write ``` -lemma continuous.matrix.conj_transpose [has_star R] {A : X → matrix n m R} (hA : continuous A) : +lemma continuous.matrix.conj_transpose [has_star R] {A : X → matrix m n R} (hA : continuous A) : continuous (λ x, (A x)ᴴ) := hA.matrix_transpose.matrix_map continuous_star ``` From cf5aea0a7abaffff75a1dfa0f1f42a059562fcc1 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Tue, 19 Apr 2022 20:26:48 +0000 Subject: [PATCH 088/373] chore(data/real/nnreal): add commuted version of `nnreal.mul_finset_sup` (#13512) Also make the argument explicit --- src/data/real/nnreal.lean | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/data/real/nnreal.lean b/src/data/real/nnreal.lean index 7a104f186e3f5..b9e8f7b77ceaa 100644 --- a/src/data/real/nnreal.lean +++ b/src/data/real/nnreal.lean @@ -352,19 +352,18 @@ iff.intro lemma bot_eq_zero : (⊥ : ℝ≥0) = 0 := rfl lemma mul_sup (a b c : ℝ≥0) : a * (b ⊔ c) = (a * b) ⊔ (a * c) := -begin - cases le_total b c with h h, - { simp [sup_eq_max, max_eq_right h, max_eq_right (mul_le_mul_of_nonneg_left h (zero_le a))] }, - { simp [sup_eq_max, max_eq_left h, max_eq_left (mul_le_mul_of_nonneg_left h (zero_le a))] }, -end +mul_max_of_nonneg _ _ $ zero_le a -lemma mul_finset_sup {α} {f : α → ℝ≥0} {s : finset α} (r : ℝ≥0) : - r * s.sup f = s.sup (λa, r * f a) := -begin - refine s.induction_on _ _, - { simp [bot_eq_zero] }, - { assume a s has ih, simp [has, ih, mul_sup], } -end +lemma sup_mul (a b c : ℝ≥0) : (a ⊔ b) * c = (a * c) ⊔ (b * c) := +max_mul_of_nonneg _ _ $ zero_le c + +lemma mul_finset_sup {α} (r : ℝ≥0) (s : finset α) (f : α → ℝ≥0) : + r * s.sup f = s.sup (λ a, r * f a) := +(finset.comp_sup_eq_sup_comp _ (nnreal.mul_sup r) (mul_zero r)) + +lemma finset_sup_mul {α} (s : finset α) (f : α → ℝ≥0) (r : ℝ≥0) : + s.sup f * r = s.sup (λ a, f a * r) := +(finset.comp_sup_eq_sup_comp (* r) (λ x y, nnreal.sup_mul x y r) (zero_mul r)) lemma finset_sup_div {α} {f : α → ℝ≥0} {s : finset α} (r : ℝ≥0) : s.sup f / r = s.sup (λ a, f a / r) := From 5038a4a978d539d933fb62c8c05a74d591d2d654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 19 Apr 2022 20:26:49 +0000 Subject: [PATCH 089/373] feat(*): `op_op_op_comm` lemmas (#13528) A handful of lemmas of the form `op (op a b) (op c d) = op (op a c) (op b d)`. --- src/algebra/group/basic.lean | 3 +++ src/algebra/group_with_zero/basic.lean | 3 +++ src/group_theory/group_action/defs.lean | 7 ++++++- src/order/symm_diff.lean | 10 +++++++++- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/algebra/group/basic.lean b/src/algebra/group/basic.lean index a204850bec373..a3ddf47309785 100644 --- a/src/algebra/group/basic.lean +++ b/src/algebra/group/basic.lean @@ -507,6 +507,9 @@ by simp_rw [div_eq_mul_inv, mul_left_comm] lemma div_mul_div_comm (a b c d : G) : a / b * (c / d) = a * c / (b * d) := by simp +@[to_additive] +lemma div_div_div_comm (a b c d : G) : (a / b) / (c / d) = (a / c) / (b / d) := by simp + @[to_additive] lemma div_mul_eq_div_div (a b c : G) : a / (b * c) = a / b / c := by simp diff --git a/src/algebra/group_with_zero/basic.lean b/src/algebra/group_with_zero/basic.lean index e081f72d9e325..f6215fade5726 100644 --- a/src/algebra/group_with_zero/basic.lean +++ b/src/algebra/group_with_zero/basic.lean @@ -990,6 +990,9 @@ lemma div_mul_div_comm₀ (a b c d : G₀) : (a / b) * (c / d) = (a * c) / (b * d) := by simp [div_eq_mul_inv, mul_inv₀] +lemma div_div_div_comm₀ (a b c d : G₀) : (a / b) / (c / d) = (a / c) / (b / d) := +by simp_rw [div_eq_mul_inv, mul_inv₀, inv_inv, mul_mul_mul_comm] + lemma mul_div_mul_left (a b : G₀) {c : G₀} (hc : c ≠ 0) : (c * a) / (c * b) = a / b := by rw [mul_comm c, mul_comm c, mul_div_mul_right _ _ hc] diff --git a/src/group_theory/group_action/defs.lean b/src/group_theory/group_action/defs.lean index c16c905eb93d9..e3845ecac017e 100644 --- a/src/group_theory/group_action/defs.lean +++ b/src/group_theory/group_action/defs.lean @@ -44,7 +44,7 @@ More sophisticated lemmas belong in `group_theory.group_action`. group action -/ -variables {M N G A B α β γ : Type*} +variables {M N G A B α β γ δ : Type*} open function (injective surjective) @@ -290,6 +290,11 @@ lemma smul_mul_assoc [has_mul β] [has_scalar α β] [is_scalar_tower α β β] (r • x) * y = r • (x * y) := smul_assoc r x y +lemma smul_smul_smul_comm [has_scalar α β] [has_scalar α γ] [has_scalar β δ] [has_scalar α δ] + [has_scalar γ δ] [is_scalar_tower α β δ] [is_scalar_tower α γ δ] [smul_comm_class β γ δ] + (a : α) (b : β) (c : γ) (d : δ) : (a • b) • (c • d) = (a • c) • b • d := +by { rw [smul_assoc, smul_assoc, smul_comm b], apply_instance } + variables [has_scalar M α] lemma commute.smul_right [has_mul α] [smul_comm_class M α α] [is_scalar_tower M α α] diff --git a/src/order/symm_diff.lean b/src/order/symm_diff.lean index b989b0592764c..8ff6d2324906e 100644 --- a/src/order/symm_diff.lean +++ b/src/order/symm_diff.lean @@ -56,7 +56,7 @@ rfl lemma symm_diff_eq_xor (p q : Prop) : p ∆ q = xor p q := rfl section generalized_boolean_algebra -variables {α : Type*} [generalized_boolean_algebra α] (a b c : α) +variables {α : Type*} [generalized_boolean_algebra α] (a b c d : α) lemma symm_diff_comm : a ∆ b = b ∆ a := by simp only [(∆), sup_comm] @@ -154,6 +154,14 @@ by rw [symm_diff_symm_diff_left, symm_diff_symm_diff_right] instance symm_diff_is_assoc : is_associative α (∆) := ⟨symm_diff_assoc⟩ +lemma symm_diff_left_comm : a ∆ (b ∆ c) = b ∆ (a ∆ c) := +by simp_rw [←symm_diff_assoc, symm_diff_comm] + +lemma symm_diff_right_comm : a ∆ b ∆ c = a ∆ c ∆ b := by simp_rw [symm_diff_assoc, symm_diff_comm] + +lemma symm_diff_symm_diff_symm_diff_comm : (a ∆ b) ∆ (c ∆ d) = (a ∆ c) ∆ (b ∆ d) := +by simp_rw [symm_diff_assoc, symm_diff_left_comm] + @[simp] lemma symm_diff_symm_diff_self : a ∆ (a ∆ b) = b := by simp [←symm_diff_assoc] @[simp] lemma symm_diff_symm_diff_self' : a ∆ b ∆ a = b := From 71b470f9a6af307a4f9885dfd73440cde081ac42 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Tue, 19 Apr 2022 23:26:34 +0000 Subject: [PATCH 090/373] chore(analysis/normed_space/star): make an argument explicit (#13523) --- src/analysis/normed_space/star/basic.lean | 14 +++++++------- src/analysis/normed_space/star/matrix.lean | 2 +- src/topology/continuous_function/bounded.lean | 3 +-- .../continuous_function/zero_at_infty.lean | 2 +- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/analysis/normed_space/star/basic.lean b/src/analysis/normed_space/star/basic.lean index fcff072e8b481..84eaf1fd7220c 100644 --- a/src/analysis/normed_space/star/basic.lean +++ b/src/analysis/normed_space/star/basic.lean @@ -36,7 +36,7 @@ local postfix `⋆`:std.prec.max_plus := star /-- A normed star group is a normed group with a compatible `star` which is isometric. -/ class normed_star_group (E : Type*) [semi_normed_group E] [star_add_monoid E] : Prop := -(norm_star : ∀ {x : E}, ∥x⋆∥ = ∥x∥) +(norm_star : ∀ x : E, ∥x⋆∥ = ∥x∥) export normed_star_group (norm_star) attribute [simp] norm_star @@ -46,16 +46,16 @@ variables {𝕜 E α : Type*} section normed_star_group variables [semi_normed_group E] [star_add_monoid E] [normed_star_group E] -@[simp] lemma nnnorm_star (x : E) : ∥star x∥₊ = ∥x∥₊ := subtype.ext norm_star +@[simp] lemma nnnorm_star (x : E) : ∥star x∥₊ = ∥x∥₊ := subtype.ext $ norm_star _ /-- The `star` map in a normed star group is a normed group homomorphism. -/ def star_normed_group_hom : normed_group_hom E E := -{ bound' := ⟨1, λ v, le_trans (norm_star.le) (one_mul _).symm.le⟩, +{ bound' := ⟨1, λ v, le_trans (norm_star _).le (one_mul _).symm.le⟩, .. star_add_equiv } /-- The `star` map in a normed star group is an isometry -/ lemma star_isometry : isometry (star : E → E) := -star_add_equiv.to_add_monoid_hom.isometry_of_norm (λ _, norm_star) +star_add_equiv.to_add_monoid_hom.isometry_of_norm norm_star lemma continuous_star : continuous (star : E → E) := star_isometry.continuous @@ -92,7 +92,7 @@ end normed_star_group instance ring_hom_isometric.star_ring_end [normed_comm_ring E] [star_ring E] [normed_star_group E] : ring_hom_isometric (star_ring_end E) := -⟨λ _, norm_star⟩ +⟨norm_star⟩ /-- A C*-ring is a normed star ring that satifies the stronger condition `∥x⋆ * x∥ = ∥x∥^2` for every `x`. -/ @@ -179,7 +179,7 @@ norm_coe_unitary_mul ⟨U, hU⟩ A calc _ = ∥((U : E)⋆ * A⋆)⋆∥ : by simp only [star_star, star_mul] ... = ∥(U : E)⋆ * A⋆∥ : by rw [norm_star] ... = ∥A⋆∥ : norm_mem_unitary_mul (star A) (unitary.star_mem U.prop) - ... = ∥A∥ : norm_star + ... = ∥A∥ : norm_star _ lemma norm_mul_mem_unitary (A : E) {U : E} (hU : U ∈ unitary E) : ∥A * U∥ = ∥A∥ := norm_mul_coe_unitary A ⟨U, hU⟩ @@ -210,7 +210,7 @@ variables (𝕜) /-- `star` bundled as a linear isometric equivalence -/ def starₗᵢ : E ≃ₗᵢ⋆[𝕜] E := { map_smul' := star_smul, - norm_map' := λ x, norm_star, + norm_map' := norm_star, .. star_add_equiv } variables {𝕜} diff --git a/src/analysis/normed_space/star/matrix.lean b/src/analysis/normed_space/star/matrix.lean index f045ac73ff595..5044a55c132d0 100644 --- a/src/analysis/normed_space/star/matrix.lean +++ b/src/analysis/normed_space/star/matrix.lean @@ -28,7 +28,7 @@ begin refine le_antisymm (by simp [matrix.norm_le_iff, M.norm_entry_le_entrywise_sup_norm]) _, refine ((matrix.norm_le_iff (norm_nonneg _)).mpr (λ i j, _)).trans (congr_arg _ M.star_eq_conj_transpose).ge, - exact (normed_star_group.norm_star).symm.le.trans Mᴴ.norm_entry_le_entrywise_sup_norm + exact (norm_star _).ge.trans Mᴴ.norm_entry_le_entrywise_sup_norm end @[priority 100] -- see Note [lower instance priority] diff --git a/src/topology/continuous_function/bounded.lean b/src/topology/continuous_function/bounded.lean index f83d3f09fb856..13c2843ff26b2 100644 --- a/src/topology/continuous_function/bounded.lean +++ b/src/topology/continuous_function/bounded.lean @@ -1202,8 +1202,7 @@ instance `pi.has_star`. Upon inspecting the goal, one sees `⊢ ⇑(star f) = st @[simp] lemma star_apply (f : α →ᵇ β) (x : α) : star f x = star (f x) := rfl instance : normed_star_group (α →ᵇ β) := -{ norm_star := λ f, by - { simp only [norm_eq], congr, ext, conv_lhs { find (∥_∥) { erw (@norm_star β _ _ _ (f x)) } } } } +{ norm_star := λ f, by simp only [norm_eq, star_apply, norm_star] } instance : star_module 𝕜 (α →ᵇ β) := { star_smul := λ k f, ext $ λ x, star_smul k (f x) } diff --git a/src/topology/continuous_function/zero_at_infty.lean b/src/topology/continuous_function/zero_at_infty.lean index 24a7064d6e6dd..f747021fa0f6d 100644 --- a/src/topology/continuous_function/zero_at_infty.lean +++ b/src/topology/continuous_function/zero_at_infty.lean @@ -438,7 +438,7 @@ instance : star_add_monoid C₀(α, β) := star_add := λ f g, ext $ λ x, star_add (f x) (g x) } instance : normed_star_group C₀(α, β) := -{ norm_star := λ f, @norm_star _ _ _ _ f.to_bcf } +{ norm_star := λ f, (norm_star f.to_bcf : _) } end star From 92f6eb6bf6e16e1e10912ffea637993b99a6f031 Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Wed, 20 Apr 2022 08:56:47 +0000 Subject: [PATCH 091/373] chore(algebra/big_operators/fin): golf finset.prod_range (#13535) --- src/algebra/big_operators/fin.lean | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/algebra/big_operators/fin.lean b/src/algebra/big_operators/fin.lean index fee0c4262cfc8..3b62524fa8d0b 100644 --- a/src/algebra/big_operators/fin.lean +++ b/src/algebra/big_operators/fin.lean @@ -28,15 +28,14 @@ namespace finset @[to_additive] theorem prod_range [comm_monoid β] {n : ℕ} (f : ℕ → β) : ∏ i in finset.range n, f i = ∏ i : fin n, f i := -begin - fapply @finset.prod_bij' _ _ _ _ _ _, - exact λ k w, ⟨k, (by simpa using w)⟩, - swap 3, - exact λ a m, a, - swap 3, - exact λ a m, by simpa using a.2, - all_goals { tidy, }, -end +prod_bij' + (λ k w, ⟨k, mem_range.mp w⟩) + (λ a ha, mem_univ _) + (λ a ha, congr_arg _ (fin.coe_mk _).symm) + (λ a m, a) + (λ a m, mem_range.mpr a.prop) + (λ a ha, fin.coe_mk _) + (λ a ha, fin.eta _ _) end finset From 8d351dc38a22b83ffbd451fc237150e8f8764aec Mon Sep 17 00:00:00 2001 From: BillyMiao Date: Wed, 20 Apr 2022 10:04:20 +0000 Subject: [PATCH 092/373] feat(analysis/inner_product_space/gram_schmidt_ortho): Gram-Schmidt Orthogonalization and Orthonormalization (#12857) Formalize Gram-Schmidt Orthogonalization and Orthonormalization --- docs/undergrad.yaml | 2 +- .../gram_schmidt_ortho.lean | 205 ++++++++++++++++++ 2 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 src/analysis/inner_product_space/gram_schmidt_ortho.lean diff --git a/docs/undergrad.yaml b/docs/undergrad.yaml index 1432c5fd43159..4f27043f36f9e 100644 --- a/docs/undergrad.yaml +++ b/docs/undergrad.yaml @@ -209,7 +209,7 @@ Bilinear and Quadratic Forms Over a Vector Space: 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: '' - Gram-Schmidt orthogonalisation: 'https://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process' + Gram-Schmidt orthogonalisation: 'gram_schmidt_orthogonal' Euclidean and Hermitian spaces: Euclidean vector spaces: 'inner_product_space' Hermitian vector spaces: 'inner_product_space' diff --git a/src/analysis/inner_product_space/gram_schmidt_ortho.lean b/src/analysis/inner_product_space/gram_schmidt_ortho.lean new file mode 100644 index 0000000000000..1ec388b30788e --- /dev/null +++ b/src/analysis/inner_product_space/gram_schmidt_ortho.lean @@ -0,0 +1,205 @@ +/- +Copyright (c) 2022 Jiale Miao. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jiale Miao, Kevin Buzzard +-/ + +import analysis.inner_product_space.projection + +/-! +# Gram-Schmidt Orthogonalization and Orthonormalization + +In this file we introduce Gram-Schmidt Orthogonalization and Orthonormalization. + +The Gram-Schmidt process takes a set of vectors as input +and outputs a set of orthogonal vectors which have the same span. + +## Main results + +- `gram_schmidt` : the Gram-Schmidt process +- `gram_schmidt_orthogonal` : + `gram_schmidt` produces an orthogonal system of vectors. +- `span_gram_schmidt` : + `gram_schmidt` preserves span of vectors. +- `gram_schmidt_ne_zero` : + If the input of the first `n + 1` vectors of `gram_schmidt` are linearly independent, + then the output of the first `n + 1` vectors are non-zero. +- `gram_schmidt_normed` : + the normalized `gram_schmidt` (i.e each vector in `gram_schmidt_normed` has unit length.) +- `gram_schmidt_orthornormal` : + `gram_schmidt_normed` produces an orthornormal system of vectors. + +## TODO + Construct a version with an orthonormal basis from Gram-Schmidt process. +-/ + +open_locale big_operators + +variables (𝕜 : Type*) {E : Type*} [is_R_or_C 𝕜] [inner_product_space 𝕜 E] + +local notation `⟪`x`, `y`⟫` := @inner 𝕜 _ _ x y + +/-- The Gram-Schmidt process takes a set of vectors as input +and outputs a set of orthogonal vectors which have the same span. -/ +noncomputable def gram_schmidt (f : ℕ → E) : ℕ → E +| n := f n - ∑ i : fin n, orthogonal_projection (𝕜 ∙ gram_schmidt i) (f n) +using_well_founded {dec_tac := `[exact i.prop]} + +/-- `gram_schmidt_def` turns the sum over `fin n` into a sum over `ℕ`. -/ +lemma gram_schmidt_def (f : ℕ → E) (n : ℕ) : + gram_schmidt 𝕜 f n = f n - ∑ i in finset.range n, + orthogonal_projection (𝕜 ∙ gram_schmidt 𝕜 f i) (f n) := +begin + rw gram_schmidt, + congr' 1, + exact fin.sum_univ_eq_sum_range (λ i, + (orthogonal_projection (𝕜 ∙ gram_schmidt 𝕜 f i) (f n) : E)) n, +end + +lemma gram_schmidt_def' (f : ℕ → E) (n : ℕ): + f n = gram_schmidt 𝕜 f n + ∑ i in finset.range n, + orthogonal_projection (𝕜 ∙ gram_schmidt 𝕜 f i) (f n) := +by simp only [gram_schmidt_def, sub_add_cancel] + +@[simp] lemma gram_schmidt_zero (f : ℕ → E) : + gram_schmidt 𝕜 f 0 = f 0 := +by simp only [gram_schmidt, fintype.univ_of_is_empty, finset.sum_empty, sub_zero] + +/-- **Gram-Schmidt Orthogonalisation**: +`gram_schmidt` produces an orthogonal system of vectors. -/ +theorem gram_schmidt_orthogonal (f : ℕ → E) {a b : ℕ} (h₀ : a ≠ b) : + ⟪gram_schmidt 𝕜 f a, gram_schmidt 𝕜 f b⟫ = 0 := +begin + suffices : ∀ a b : ℕ, a < b → ⟪gram_schmidt 𝕜 f a, gram_schmidt 𝕜 f b⟫ = 0, + { cases h₀.lt_or_lt with ha hb, + { exact this _ _ ha, }, + { rw inner_eq_zero_sym, + exact this _ _ hb, }, }, + clear h₀ a b, + intros a b h₀, + induction b using nat.strong_induction_on with b ih generalizing a, + simp only [gram_schmidt_def 𝕜 f b, inner_sub_right, inner_sum, + orthogonal_projection_singleton, inner_smul_right], + rw finset.sum_eq_single_of_mem a (finset.mem_range.mpr h₀), + { by_cases h : gram_schmidt 𝕜 f a = 0, + { simp only [h, inner_zero_left, zero_div, zero_mul, sub_zero], }, + { rw [← inner_self_eq_norm_sq_to_K, div_mul_cancel, sub_self], + rwa [ne.def, inner_self_eq_zero], }, }, + simp_intros i hi hia only [finset.mem_range], + simp only [mul_eq_zero, div_eq_zero_iff, inner_self_eq_zero], + right, + cases hia.lt_or_lt with hia₁ hia₂, + { rw inner_eq_zero_sym, + exact ih a h₀ i hia₁, }, + { exact ih i hi a hia₂, }, +end + +/-- This is another version of `gram_schmidt_orthogonal` using `pairwise` instead. -/ +theorem gram_schmidt_pairwise_orthogonal (f : ℕ → E) : + pairwise (λ a b, ⟪gram_schmidt 𝕜 f a, gram_schmidt 𝕜 f b⟫ = 0) := +@gram_schmidt_orthogonal 𝕜 _ _ _ f + +open submodule set order + +/-- `gram_schmidt` preserves span of vectors. -/ +lemma span_gram_schmidt (f : ℕ → E) (c : ℕ) : + span 𝕜 (gram_schmidt 𝕜 f '' Iic c) = span 𝕜 (f '' Iic c) := +begin + induction c with c hc, + { simp only [Iic, gram_schmidt_zero, le_zero_iff, set_of_eq_eq_singleton, image_singleton], }, + have h₀ : ∀ b, b ∈ finset.range c.succ → gram_schmidt 𝕜 f b ∈ span 𝕜 (f '' Iic c), + { simp_intros b hb only [finset.mem_range, nat.succ_eq_add_one], + rw ← hc, + refine subset_span _, + simp only [mem_image, mem_Iic], + refine ⟨b, by linarith, by refl⟩, }, + rw [← nat.succ_eq_succ, Iic_succ], + simp only [span_insert, image_insert_eq, hc], + apply le_antisymm, + { simp only [nat.succ_eq_succ,gram_schmidt_def 𝕜 f c.succ, orthogonal_projection_singleton, + sup_le_iff, span_singleton_le_iff_mem, le_sup_right, and_true], + apply submodule.sub_mem _ _ _, + { exact mem_sup_left (mem_span_singleton_self (f c.succ)), }, + { exact submodule.sum_mem _ (λ b hb, mem_sup_right (smul_mem _ _ (h₀ b hb))), }, }, + { rw [nat.succ_eq_succ, gram_schmidt_def' 𝕜 f c.succ], + simp only [orthogonal_projection_singleton, + sup_le_iff, span_singleton_le_iff_mem, le_sup_right, and_true], + apply submodule.add_mem _ _ _, + { exact mem_sup_left (mem_span_singleton_self (gram_schmidt 𝕜 f c.succ)), }, + { exact submodule.sum_mem _ (λ b hb, mem_sup_right (smul_mem _ _ (h₀ b hb))), }, }, +end + +/-- If the input of the first `n + 1` vectors of `gram_schmidt` are linearly independent, +then the output of the first `n + 1` vectors are non-zero. -/ +lemma gram_schmidt_ne_zero (f : ℕ → E) (n : ℕ) + (h₀ : linear_independent 𝕜 (f ∘ (coe : fin n.succ → ℕ))) : + gram_schmidt 𝕜 f n ≠ 0 := +begin + induction n with n hn, + { intro h, + simp only [gram_schmidt_zero, ne.def] at h, + exact linear_independent.ne_zero 0 h₀ (by simp only [function.comp_app, fin.coe_zero, h]), }, + { by_contra h₁, + rw nat.succ_eq_add_one at hn h₀ h₁, + have h₂ := gram_schmidt_def' 𝕜 f n.succ, + simp only [nat.succ_eq_add_one, h₁, orthogonal_projection_singleton, zero_add] at h₂, + have h₃ : f (n + 1) ∈ span 𝕜 (f '' Iic n), + { rw [h₂, ← span_gram_schmidt 𝕜 f n], + apply submodule.sum_mem _ _, + simp_intros a ha only [finset.mem_range], + apply submodule.smul_mem _ _ _, + refine subset_span _, + simp only [mem_image, mem_Iic], + exact ⟨a, by linarith, by refl⟩, }, + change linear_independent 𝕜 (f ∘ (coe : fin (n + 2) → ℕ)) at h₀, + have h₄ : ((n + 1) : fin (n + 2)) ∉ (coe : fin (n + 2) → ℕ) ⁻¹' (Iic n), + { simp only [mem_preimage, mem_Iic, not_le], + norm_cast, + rw fin.coe_coe_of_lt; + linarith, }, + apply linear_independent.not_mem_span_image h₀ h₄, + rw [image_comp, image_preimage_eq_inter_range], + simp only [function.comp_app, subtype.range_coe_subtype], + convert h₃, + { norm_cast, + refine fin.coe_coe_of_lt (by linarith), }, + { simp only [inter_eq_left_iff_subset, Iic, set_of_subset_set_of], + exact (λ a ha, by linarith), }, }, +end + +/-- If the input of `gram_schmidt` is linearly independent, then the output is non-zero. -/ +lemma gram_schmidt_ne_zero' (f : ℕ → E) (h₀ : linear_independent 𝕜 f) (n : ℕ) : + gram_schmidt 𝕜 f n ≠ 0 := +gram_schmidt_ne_zero 𝕜 f n (linear_independent.comp h₀ _ (fin.coe_injective)) + +/-- the normalized `gram_schmidt` +(i.e each vector in `gram_schmidt_normed` has unit length.) -/ +noncomputable def gram_schmidt_normed (f : ℕ → E) (n : ℕ) : E := +(∥gram_schmidt 𝕜 f n∥ : 𝕜)⁻¹ • (gram_schmidt 𝕜 f n) + +lemma gram_schmidt_normed_unit_length (f : ℕ → E) (n : ℕ) + (h₀ : linear_independent 𝕜 (f ∘ (coe : fin n.succ → ℕ))) : + ∥gram_schmidt_normed 𝕜 f n∥ = 1 := +by simp only [gram_schmidt_ne_zero 𝕜 f n h₀, + gram_schmidt_normed, norm_smul_inv_norm, ne.def, not_false_iff] + +lemma gram_schmidt_normed_unit_length' (f : ℕ → E) (n : ℕ) + (h₀ : linear_independent 𝕜 f) : + ∥gram_schmidt_normed 𝕜 f n∥ = 1 := +by simp only [gram_schmidt_ne_zero' 𝕜 f h₀, + gram_schmidt_normed, norm_smul_inv_norm, ne.def, not_false_iff] + +/-- **Gram-Schmidt Orthonormalization**: +`gram_schmidt_normed` produces an orthornormal system of vectors. -/ +theorem gram_schmidt_orthonormal (f : ℕ → E) (h₀ : linear_independent 𝕜 f) : + orthonormal 𝕜 (gram_schmidt_normed 𝕜 f) := +begin + unfold orthonormal, + split, + { simp only [gram_schmidt_normed_unit_length', h₀, forall_const], }, + { intros i j hij, + simp only [gram_schmidt_normed, inner_smul_left, inner_smul_right, is_R_or_C.conj_inv, + is_R_or_C.conj_of_real, mul_eq_zero, inv_eq_zero, is_R_or_C.of_real_eq_zero, norm_eq_zero], + repeat { right }, + exact gram_schmidt_orthogonal 𝕜 f hij, }, +end From d9a8d6e504253b7f9b9b254029cdb572cf962a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Wed, 20 Apr 2022 10:38:25 +0000 Subject: [PATCH 093/373] feat(topology/separation): Finite sets in T2 spaces (#12845) We prove the following theorem: given a finite set in a T2 space, one can choose an open set around each point so that these are pairwise disjoint. --- src/topology/separation.lean | 38 ++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/topology/separation.lean b/src/topology/separation.lean index a39e7e750feb1..a92dfb113c69c 100644 --- a/src/topology/separation.lean +++ b/src/topology/separation.lean @@ -713,12 +713,46 @@ end `x ≠ y` there exists disjoint open sets around `x` and `y`. This is the most widely used of the separation axioms. -/ @[mk_iff] class t2_space (α : Type u) [topological_space α] : Prop := -(t2 : ∀x y, x ≠ y → ∃u v : set α, is_open u ∧ is_open v ∧ x ∈ u ∧ y ∈ v ∧ u ∩ v = ∅) +(t2 : ∀ x y, x ≠ y → ∃ u v : set α, is_open u ∧ is_open v ∧ x ∈ u ∧ y ∈ v ∧ u ∩ v = ∅) +/-- Two different points can be separated by open sets. -/ lemma t2_separation [t2_space α] {x y : α} (h : x ≠ y) : - ∃u v : set α, is_open u ∧ is_open v ∧ x ∈ u ∧ y ∈ v ∧ u ∩ v = ∅ := + ∃ u v : set α, is_open u ∧ is_open v ∧ x ∈ u ∧ y ∈ v ∧ u ∩ v = ∅ := t2_space.t2 x y h +/-- A finite set can be separated by open sets. -/ +lemma t2_separation_finset [t2_space α] (s : finset α) : + ∃ f : α → set α, set.pairwise_disjoint ↑s f ∧ ∀ x ∈ s, x ∈ f x ∧ is_open (f x) := +finset.induction_on s (by simp) begin + rintros t s ht ⟨f, hf, hf'⟩, + have hty : ∀ y : s, t ≠ y := by { rintros y rfl, exact ht y.2 }, + choose u v hu hv htu hxv huv using λ {x} (h : t ≠ x), t2_separation h, + refine ⟨λ x, if ht : t = x then ⋂ y : s, u (hty y) else f x ∩ v ht, _, _⟩, + { rintros x hx₁ y hy₁ hxy a ⟨hx, hy⟩, + rw [finset.mem_coe, finset.mem_insert, eq_comm] at hx₁ hy₁, + rcases eq_or_ne t x with rfl | hx₂; + rcases eq_or_ne t y with rfl | hy₂, + { exact hxy rfl }, + { simp_rw [dif_pos rfl, mem_Inter] at hx, + simp_rw [dif_neg hy₂] at hy, + rw [bot_eq_empty, ←huv hy₂], + exact ⟨hx ⟨y, hy₁.resolve_left hy₂⟩, hy.2⟩ }, + { simp_rw [dif_neg hx₂] at hx, + simp_rw [dif_pos rfl, mem_Inter] at hy, + rw [bot_eq_empty, ←huv hx₂], + exact ⟨hy ⟨x, hx₁.resolve_left hx₂⟩, hx.2⟩ }, + { simp_rw [dif_neg hx₂] at hx, + simp_rw [dif_neg hy₂] at hy, + exact hf (hx₁.resolve_left hx₂) (hy₁.resolve_left hy₂) hxy ⟨hx.1, hy.1⟩ } }, + { intros x hx, + split_ifs with ht, + { refine ⟨mem_Inter.2 (λ y, _), is_open_Inter (λ y, hu (hty y))⟩, + rw ←ht, + exact htu (hty y) }, + { have hx := hf' x ((finset.mem_insert.1 hx).resolve_left (ne.symm ht)), + exact ⟨⟨hx.1, hxv ht⟩, is_open.inter hx.2 (hv ht)⟩ } } +end + @[priority 100] -- see Note [lower instance priority] instance t2_space.t1_space [t2_space α] : t1_space α := ⟨λ x, is_open_compl_iff.1 $ is_open_iff_forall_mem_open.2 $ λ y hxy, From a3a166bcf61429dd14fb0867b75c2e844a665543 Mon Sep 17 00:00:00 2001 From: Aaron Anderson Date: Wed, 20 Apr 2022 10:38:26 +0000 Subject: [PATCH 094/373] chore(model_theory/encoding): Improve the encoding of terms (#13532) Makes it so that the encoding of terms no longer requires the assumption `inhabited (L.term A)`. Adjusts following lemmas to use the `encoding` API more directly. --- src/model_theory/encoding.lean | 90 ++++++++++++++--------------- src/model_theory/substructures.lean | 2 +- 2 files changed, 44 insertions(+), 48 deletions(-) diff --git a/src/model_theory/encoding.lean b/src/model_theory/encoding.lean index 61d38de7bd39f..b8a7faa2c04ba 100644 --- a/src/model_theory/encoding.lean +++ b/src/model_theory/encoding.lean @@ -20,8 +20,8 @@ import computability.encoding ## TODO * An encoding for formulas -* `fin_encoding`s for terms and formulas, based on the `encoding`s -* Computability facts about these `fin_encoding`s, to set up a computability approach to +* `primcodable` instances for terms and formulas, based on the `encoding`s +* Computability facts about term and formula operations, to set up a computability approach to incompleteness -/ @@ -46,86 +46,82 @@ def list_encode : L.term α → list (α ⊕ Σ i, L.functions i) ((list.fin_range _).bind (λ i, (ts i).list_encode))) /-- Decodes a list of variables and function symbols as a list of terms. -/ -def list_decode [inhabited (L.term α)] : - list (α ⊕ Σ i, L.functions i) → list (L.term α) +def list_decode : + list (α ⊕ Σ i, L.functions i) → list (option (L.term α)) | [] := [] -| ((sum.inl a) :: l) := var a :: list_decode l -| ((sum.inr ⟨n, f⟩) :: l) := func f (λ i, ((list_decode l).nth i).iget) :: ((list_decode l).drop n) - -@[simp] theorem list_decode_encode_list [inhabited (L.term α)] (l : list (L.term α)) : - list_decode (l.bind list_encode) = l := +| ((sum.inl a) :: l) := some (var a) :: list_decode l +| ((sum.inr ⟨n, f⟩) :: l) := + if h : ∀ (i : fin n), ((list_decode l).nth i).join.is_some + then func f (λ i, option.get (h i)) :: ((list_decode l).drop n) + else [none] + +theorem list_decode_encode_list (l : list (L.term α)) : + list_decode (l.bind list_encode) = l.map option.some := begin suffices h : ∀ (t : L.term α) (l : list (α ⊕ Σ i, L.functions i)), - list_decode (t.list_encode ++ l) = t :: list_decode l, + list_decode (t.list_encode ++ l) = some t :: list_decode l, { induction l with t l lih, { refl }, - { rw [cons_bind, h t (l.bind list_encode), lih] } }, + { rw [cons_bind, h t (l.bind list_encode), lih, list.map] } }, { intro t, induction t with a n f ts ih; intro l, { rw [list_encode, singleton_append, list_decode] }, { rw [list_encode, cons_append, list_decode], have h : list_decode ((fin_range n).bind (λ (i : fin n), (ts i).list_encode) ++ l) = - (fin_range n).map ts ++ list_decode l, + (fin_range n).map (option.some ∘ ts) ++ list_decode l, { induction (fin_range n) with i l' l'ih, { refl }, { rw [cons_bind, append_assoc, ih, map_cons, l'ih, cons_append] } }, - have h' : n ≤ (list_decode ((fin_range n).bind (λ (i : fin n), - (ts i).list_encode) ++ l)).length, - { rw [h, length_append, length_map, length_fin_range], - exact le_self_add, }, - refine congr (congr rfl (congr rfl (funext (λ i, _)))) _, - { rw [nth_le_nth (lt_of_lt_of_le i.is_lt h'), option.iget_some, nth_le_of_eq h, nth_le_append, - nth_le_map, nth_le_fin_range, fin.eta], - { rw [length_fin_range], - exact i.is_lt }, - { rw [length_map, length_fin_range], - exact i.is_lt } }, + have h' : ∀ i, (list_decode ((fin_range n).bind (λ (i : fin n), (ts i).list_encode) ++ l)).nth + ↑i = some (some (ts i)), + { intro i, + rw [h, nth_append, nth_map], + { simp only [option.map_eq_some', function.comp_app, nth_eq_some], + refine ⟨i, ⟨lt_of_lt_of_le i.2 (ge_of_eq (length_fin_range _)), _⟩, rfl⟩, + rw [nth_le_fin_range, fin.eta] }, + { refine lt_of_lt_of_le i.2 _, + simp } }, + refine (dif_pos (λ i, option.is_some_iff_exists.2 ⟨ts i, _⟩)).trans _, + { rw [option.join_eq_some, h'] }, + refine congr (congr rfl (congr rfl (congr rfl (funext (λ i, option.get_of_mem _ _))))) _, + { simp [h'] }, { rw [h, drop_left'], rw [length_map, length_fin_range] } } } end /-- An encoding of terms as lists. -/ -@[simps] protected def encoding [inhabited (L.term α)] : encoding (L.term α) := +@[simps] protected def encoding : encoding (L.term α) := { Γ := α ⊕ Σ i, L.functions i, encode := list_encode, - decode := λ l, (list_decode l).head', + decode := λ l, (list_decode l).head'.join, decode_encode := λ t, begin have h := list_decode_encode_list [t], rw [bind_singleton] at h, - rw [h, head'], + simp only [h, option.join, head', list.map, option.some_bind, id.def], end } lemma list_encode_injective : function.injective (list_encode : L.term α → list (α ⊕ Σ i, L.functions i)) := -begin - casesI is_empty_or_nonempty (L.term α) with he hne, - { exact he.elim }, - { inhabit (L.term α), - exact term.encoding.encode_injective } -end +term.encoding.encode_injective -theorem card_le : # (L.term α) ≤ # (α ⊕ Σ i, L.functions i) + ω := -begin - have h := (mk_le_of_injective list_encode_injective), - refine h.trans _, - casesI fintype_or_infinite (α ⊕ Σ i, L.functions i) with ft inf, - { haveI := fintype.to_encodable (α ⊕ Σ i, L.functions i), - exact le_add_left mk_le_omega }, - { rw mk_list_eq_mk, - exact le_self_add } -end +theorem card_le : # (L.term α) ≤ max ω (# (α ⊕ Σ i, L.functions i)) := +lift_le.1 (trans term.encoding.card_le_card_list (lift_le.2 (mk_list_le_max _))) -instance [encodable α] [encodable ((Σ i, L.functions i))] [inhabited (L.term α)] : +instance [encodable α] [encodable ((Σ i, L.functions i))] : encodable (L.term α) := -encodable.of_left_injection list_encode (λ l, (list_decode l).head') - (λ t, by rw [← bind_singleton list_encode, list_decode_encode_list, head']) +encodable.of_left_injection list_encode (λ l, (list_decode l).head'.join) + (λ t, begin + rw [← bind_singleton list_encode, list_decode_encode_list], + simp only [option.join, head', list.map, option.some_bind, id.def], + end) lemma card_le_omega [h1 : nonempty (encodable α)] [h2 : L.countable_functions] : # (L.term α) ≤ ω := begin refine (card_le.trans _), - rw [add_le_omega, mk_sum, add_le_omega, lift_le_omega, lift_le_omega, ← encodable_iff], - exact ⟨⟨h1, L.card_functions_le_omega⟩, refl _⟩, + rw [max_le_iff], + simp only [le_refl, mk_sum, add_le_omega, lift_le_omega, true_and], + exact ⟨encodable_iff.1 h1, L.card_functions_le_omega⟩, end instance small [small.{u} α] : diff --git a/src/model_theory/substructures.lean b/src/model_theory/substructures.lean index f0e12304266a1..b69df45bb4db5 100644 --- a/src/model_theory/substructures.lean +++ b/src/model_theory/substructures.lean @@ -263,7 +263,7 @@ begin end theorem lift_card_closure_le : cardinal.lift.{(max u w) w} (# (closure L s)) ≤ - cardinal.lift.{(max u w) w} (#s) + cardinal.lift.{(max u w) u} (#(Σ i, L.functions i)) + ω := + max ω (cardinal.lift.{(max u w) w} (#s) + cardinal.lift.{(max u w) u} (#(Σ i, L.functions i))) := begin refine lift_card_closure_le_card_term.trans (term.card_le.trans _), rw [mk_sum, lift_umax', lift_umax], From 8ba7df83a8eaa9adde3e93920c28fef5c31bb191 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Wed, 20 Apr 2022 12:56:15 +0000 Subject: [PATCH 095/373] =?UTF-8?q?feat(topology/algebra/algebra):=20?= =?UTF-8?q?=E2=84=9A-scalar=20multiplication=20is=20continuous=20(#13458)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/topology/algebra/algebra.lean | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/topology/algebra/algebra.lean b/src/topology/algebra/algebra.lean index 008e197516345..297f91aef929c 100644 --- a/src/topology/algebra/algebra.lean +++ b/src/topology/algebra/algebra.lean @@ -5,6 +5,7 @@ Authors: Scott Morrison -/ import algebra.algebra.subalgebra.basic import topology.algebra.module.basic +import topology.algebra.field /-! # Topological (sub)algebras @@ -149,3 +150,13 @@ begin end end ring + +section division_ring + +/-- The action induced by `algebra_rat` is continuous. -/ +instance division_ring.has_continuous_const_smul_rat + {A} [division_ring A] [topological_space A] [has_continuous_mul A] [char_zero A] : + has_continuous_const_smul ℚ A := +⟨λ r, continuous_const.mul continuous_id⟩ + +end division_ring From d79f6f3ce00dec9425d90247855bd54c6c716382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Wed, 20 Apr 2022 14:05:05 +0000 Subject: [PATCH 096/373] feat(data/finset/basic): simp `to_finset_eq_empty` (#13531) --- src/data/finset/basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/finset/basic.lean b/src/data/finset/basic.lean index b812cfc4e3874..6d97192ef9ea4 100644 --- a/src/data/finset/basic.lean +++ b/src/data/finset/basic.lean @@ -1738,7 +1738,7 @@ finset.ext $ by simp @[simp] lemma to_finset_union (s t : multiset α) : (s ∪ t).to_finset = s.to_finset ∪ t.to_finset := by ext; simp -theorem to_finset_eq_empty {m : multiset α} : m.to_finset = ∅ ↔ m = 0 := +@[simp] theorem to_finset_eq_empty {m : multiset α} : m.to_finset = ∅ ↔ m = 0 := finset.val_inj.symm.trans multiset.dedup_eq_zero @[simp] lemma to_finset_subset (s t : multiset α) : s.to_finset ⊆ t.to_finset ↔ s ⊆ t := From 311ca722e066614d8c869905ebe00bf9bd684146 Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Wed, 20 Apr 2022 16:01:13 +0000 Subject: [PATCH 097/373] feat(order/filter/basic): allow functions between different types in lemmas about [co]map by a constant function (#13542) --- src/order/filter/basic.lean | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/order/filter/basic.lean b/src/order/filter/basic.lean index 6cbfe706dcb61..9dfbbe9432f8c 100644 --- a/src/order/filter/basic.lean +++ b/src/order/filter/basic.lean @@ -1622,19 +1622,19 @@ theorem preimage_mem_comap (ht : t ∈ g) : m ⁻¹' t ∈ comap m g := lemma comap_id : comap id f = f := le_antisymm (λ s, preimage_mem_comap) (λ s ⟨t, ht, hst⟩, mem_of_superset ht hst) -lemma comap_const_of_not_mem {x : α} {f : filter α} {V : set α} (hV : V ∈ f) (hx : x ∉ V) : - comap (λ y : α, x) f = ⊥ := +lemma comap_const_of_not_mem {x : β} (ht : t ∈ g) (hx : x ∉ t) : + comap (λ y : α, x) g = ⊥ := begin ext W, - suffices : ∃ t ∈ f, (λ (y : α), x) ⁻¹' t ⊆ W, by simpa, - use [V, hV], + suffices : ∃ t ∈ g, (λ (y : α), x) ⁻¹' t ⊆ W, by simpa, + use [t, ht], simp [preimage_const_of_not_mem hx], end -lemma comap_const_of_mem {x : α} {f : filter α} (h : ∀ V ∈ f, x ∈ V) : comap (λ y : α, x) f = ⊤ := +lemma comap_const_of_mem {x : β} (h : ∀ t ∈ g, x ∈ t) : comap (λ y : α, x) g = ⊤ := begin ext W, - suffices : (∃ (t : set α), t ∈ f ∧ (λ (y : α), x) ⁻¹' t ⊆ W) ↔ W = univ, + suffices : (∃ (t : set β), t ∈ g ∧ (λ (y : α), x) ⁻¹' t ⊆ W) ↔ W = univ, by simpa, split, { rintro ⟨V, V_in, hW⟩, @@ -1644,7 +1644,7 @@ begin simp [univ_mem] }, end -lemma map_const [ne_bot f] {c : α} : f.map (λ x, c) = pure c := +lemma map_const [ne_bot f] {c : β} : f.map (λ x, c) = pure c := by { ext s, by_cases h : c ∈ s; simp [h] } lemma comap_comap {m : γ → β} {n : β → α} : comap m (comap n f) = comap (n ∘ m) f := From b0805a5eaa66fcf13d0e0589659da2a1ba55d8ba Mon Sep 17 00:00:00 2001 From: antoinelab01 Date: Wed, 20 Apr 2022 17:09:56 +0000 Subject: [PATCH 098/373] feat(linear_algebra/trace): dual_tensor_hom is an equivalence + basis-free characterization of the trace (#10372) Co-authored-by: antoinelab01 <66086247+antoinelab01@users.noreply.github.com> Co-authored-by: Oliver Nash --- src/data/finsupp/basic.lean | 17 +++++ src/data/matrix/basis.lean | 3 + src/linear_algebra/contraction.lean | 72 ++++++++++++++++++-- src/linear_algebra/dual.lean | 15 ++++ src/linear_algebra/tensor_product_basis.lean | 9 +++ src/linear_algebra/trace.lean | 62 ++++++++++++++--- src/representation_theory/basic.lean | 3 +- 7 files changed, 162 insertions(+), 19 deletions(-) diff --git a/src/data/finsupp/basic.lean b/src/data/finsupp/basic.lean index b40c019c8e1bc..7ced9f872c9ba 100644 --- a/src/data/finsupp/basic.lean +++ b/src/data/finsupp/basic.lean @@ -1297,6 +1297,14 @@ lift_add_hom.to_equiv.apply_eq_iff_eq_symm_apply.2 rfl f.sum single = f := add_monoid_hom.congr_fun lift_add_hom_single_add_hom f +@[simp] lemma sum_univ_single [add_comm_monoid M] [fintype α] (i : α) (m : M) : + ∑ (j : α), (single i m) j = m := +by simp [single] + +@[simp] lemma sum_univ_single' [add_comm_monoid M] [fintype α] (i : α) (m : M) : + ∑ (j : α), (single j m) i = m := +by simp [single] + @[simp] lemma lift_add_hom_apply_single [add_comm_monoid M] [add_comm_monoid N] (f : α → M →+ N) (a : α) (b : M) : lift_add_hom f (single a b) = f a b := @@ -2325,6 +2333,15 @@ rfl end sum +section +variables [has_zero M] [monoid_with_zero R] [mul_action_with_zero R M] + +@[simp] lemma single_smul (a b : α) (f : α → M) (r : R) : + (single a r b) • (f a) = single a (r • f b) b := +by by_cases a = b; simp [h] + +end + section variables [monoid G] [mul_action G α] [add_comm_monoid M] diff --git a/src/data/matrix/basis.lean b/src/data/matrix/basis.lean index 7a022894374df..b3a7610d779e9 100644 --- a/src/data/matrix/basis.lean +++ b/src/data/matrix/basis.lean @@ -124,6 +124,9 @@ variables (i j : n) (c : α) (i' j' : n) @[simp] lemma diag_zero (h : j ≠ i) : diag n α α (std_basis_matrix i j c) = 0 := funext $ λ k, if_neg $ λ ⟨e₁, e₂⟩, h (e₂.trans e₁.symm) +@[simp] lemma diag_same : diag n α α (std_basis_matrix i i c) = pi.single i c := +by { ext j, by_cases hij : i = j; try {rw hij}; simp [hij] } + variable [fintype n] lemma trace_zero (h : j ≠ i) : trace n α α (std_basis_matrix i j c) = 0 := by simp [h] diff --git a/src/linear_algebra/contraction.lean b/src/linear_algebra/contraction.lean index ff9320cc0c9b4..bb9ded19d814f 100644 --- a/src/linear_algebra/contraction.lean +++ b/src/linear_algebra/contraction.lean @@ -1,9 +1,12 @@ /- Copyright (c) 2020 Oliver Nash. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Oliver Nash +Authors: Oliver Nash, Antoine Labelle -/ import linear_algebra.dual +import linear_algebra.matrix.to_lin +import linear_algebra.tensor_product_basis +import linear_algebra.free_module.finite.rank /-! # Contractions @@ -17,15 +20,17 @@ some basic properties of these maps. contraction, dual module, tensor product -/ -universes u v +section contraction +open tensor_product linear_map matrix +open_locale tensor_product big_operators -section contraction -open tensor_product -open_locale tensor_product +variables (R M N : Type*) [add_comm_group M] [add_comm_group N] -variables (R : Type u) (M N : Type v) -variables [comm_ring R] [add_comm_group M] [add_comm_group N] [module R M] [module R N] +section comm_ring + +variables [comm_ring R] [module R M] [module R N] +variables {ι : Type*} [decidable_eq ι] [fintype ι] (b : basis ι R M) /-- The natural left-handed pairing between a module and its dual. -/ def contract_left : (module.dual R M) ⊗ M →ₗ[R] R := (uncurry _ _ _ _).to_fun linear_map.id @@ -51,4 +56,57 @@ variables {R M N} dual_tensor_hom R M N (f ⊗ₜ n) m = (f m) • n := by { dunfold dual_tensor_hom, rw uncurry_apply, refl, } +/-- As a matrix, `dual_tensor_hom` evaluated on a basis element of `M* ⊗ N` is a matrix with a +single one and zeros elsewhere -/ +theorem to_matrix_dual_tensor_hom + {m : Type*} {n : Type*} [fintype m] [fintype n] [decidable_eq m] [decidable_eq n] + (bM : basis m R M) (bN : basis n R N) (j : m) (i : n) : + to_matrix bM bN (dual_tensor_hom R M N (bM.coord j ⊗ₜ bN i)) = std_basis_matrix i j 1 := +begin + ext i' j', + by_cases hij : (i = i' ∧ j = j'); + simp [linear_map.to_matrix_apply, finsupp.single_eq_pi_single, hij], + rw [and_iff_not_or_not, not_not] at hij, cases hij; simp [hij], +end + +local attribute [ext] tensor_product.ext + +/-- If `M` is free, the natural linear map $M^* ⊗ N → Hom(M, N)$ is an equivalence. This function +provides this equivalence in return for a basis of `M`. -/ +@[simps] +noncomputable def dual_tensor_hom_equiv_of_basis + {ι : Type*} [decidable_eq ι] [fintype ι] (b : basis ι R M) : + (module.dual R M) ⊗[R] N ≃ₗ[R] M →ₗ[R] N := +linear_equiv.of_linear + (dual_tensor_hom R M N) + (∑ i, (tensor_product.mk R _ N (b.dual_basis i)) ∘ₗ linear_map.applyₗ (b i)) + (begin + ext f m, + simp only [applyₗ_apply_apply, coe_fn_sum, dual_tensor_hom_apply, mk_apply, id_coe, id.def, + fintype.sum_apply, function.comp_app, basis.coe_dual_basis, coe_comp, + basis.coord_apply, ← f.map_smul, (dual_tensor_hom R M N).map_sum, ← f.map_sum, b.sum_repr], + end) + (begin + ext f m, + simp only [applyₗ_apply_apply, coe_fn_sum, dual_tensor_hom_apply, mk_apply, id_coe, id.def, + fintype.sum_apply, function.comp_app, basis.coe_dual_basis, coe_comp, + compr₂_apply, tmul_smul, smul_tmul', ← sum_tmul, basis.sum_dual_apply_smul_coord], +end) + +@[simp] lemma dual_tensor_hom_equiv_of_basis_to_linear_map : + (dual_tensor_hom_equiv_of_basis b : (module.dual R M) ⊗[R] N ≃ₗ[R] M →ₗ[R] N).to_linear_map = + dual_tensor_hom R M N := +rfl + +variables [module.free R M] [module.finite R M] [nontrivial R] + +open_locale classical + +/-- If `M` is finite free, the natural map $M^* ⊗ N → Hom(M, N)$ is an +equivalence. -/ +@[simp] noncomputable def dual_tensor_hom_equiv : (module.dual R M) ⊗[R] N ≃ₗ[R] M →ₗ[R] N := +dual_tensor_hom_equiv_of_basis (module.free.choose_basis R M) + +end comm_ring + end contraction diff --git a/src/linear_algebra/dual.lean b/src/linear_algebra/dual.lean index 67b33607f4dd1..0fd6a4c68cc4c 100644 --- a/src/linear_algebra/dual.lean +++ b/src/linear_algebra/dual.lean @@ -98,6 +98,7 @@ namespace basis universes u v w open module module.dual submodule linear_map cardinal function +open_locale big_operators variables {R M K V ι : Type*} @@ -185,6 +186,20 @@ end end comm_semiring +section + +variables [comm_semiring R] [add_comm_monoid M] [module R M] [fintype ι] +variables (b : basis ι R M) + +@[simp] lemma sum_dual_apply_smul_coord (f : module.dual R M) : ∑ x, f (b x) • b.coord x = f := +begin + ext m, + simp_rw [linear_map.sum_apply, linear_map.smul_apply, smul_eq_mul, mul_comm (f _), ←smul_eq_mul, + ←f.map_smul, ←f.map_sum, basis.coord_apply, basis.sum_repr], +end + +end + section comm_ring variables [comm_ring R] [add_comm_group M] [module R M] [decidable_eq ι] diff --git a/src/linear_algebra/tensor_product_basis.lean b/src/linear_algebra/tensor_product_basis.lean index 6bad82cf91512..673d640c01dff 100644 --- a/src/linear_algebra/tensor_product_basis.lean +++ b/src/linear_algebra/tensor_product_basis.lean @@ -28,6 +28,15 @@ finsupp.basis_single_one.map (finsupp_tensor_finsupp R _ _ _ _).trans $ finsupp.lcongr (equiv.refl _) (tensor_product.lid R R)).symm +@[simp] +lemma basis.tensor_product_apply (b : basis ι R M) (c : basis κ R N) (i : ι) (j : κ) : + basis.tensor_product b c (i, j) = b i ⊗ₜ c j := +by simp [basis.tensor_product] + +lemma basis.tensor_product_apply' (b : basis ι R M) (c : basis κ R N) (i : ι × κ) : + basis.tensor_product b c i = b i.1 ⊗ₜ c i.2 := +by simp [basis.tensor_product] + end comm_ring section field diff --git a/src/linear_algebra/trace.lean b/src/linear_algebra/trace.lean index 150eb34e9dbd1..afbb55aa628bb 100644 --- a/src/linear_algebra/trace.lean +++ b/src/linear_algebra/trace.lean @@ -1,11 +1,13 @@ /- Copyright (c) 2019 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Johannes Hölzl, Patrick Massot, Casper Putz, Anne Baanen +Authors: Johannes Hölzl, Patrick Massot, Casper Putz, Anne Baanen, Antoine Labelle -/ import linear_algebra.matrix.to_lin import linear_algebra.matrix.trace - +import linear_algebra.contraction +import linear_algebra.tensor_product_basis +import linear_algebra.free_module.strong_rank_condition /-! # Trace of a linear map @@ -110,18 +112,56 @@ by { rw trace_mul_comm, simp } end section -variables (R : Type u) [field R] {M : Type v} [add_comm_group M] [module R M] -/-- The trace of the identity endomorphism is the dimension of the vector space -/ -@[simp] theorem trace_one : trace R M 1 = (finrank R M : R) := +variables (R : Type u) [comm_ring R] {M : Type v} [add_comm_group M] [module R M] +variables {ι : Type w} [fintype ι] + +/-- The trace of a linear map correspond to the contraction pairing under the isomorphism + `End(M) ≃ M* ⊗ M`-/ +lemma trace_eq_contract_of_basis (b : basis ι R M) : + (linear_map.trace R M) ∘ₗ (dual_tensor_hom R M M) = contract_left R M := begin classical, - by_cases H : ∃ (s : finset M), nonempty (basis s R M), - { obtain ⟨s, ⟨b⟩⟩ := H, - rw [trace_eq_matrix_trace R b, to_matrix_one, finrank_eq_card_finset_basis b], - simp, }, - { suffices : (finrank R M : R) = 0, { simp [this, trace, H], }, - simp [finrank_eq_zero_of_not_exists_basis H], }, + apply basis.ext (basis.tensor_product (basis.dual_basis b) b), + rintros ⟨i, j⟩, + simp only [function.comp_app, basis.tensor_product_apply, basis.coe_dual_basis, coe_comp], + rw [trace_eq_matrix_trace R b, to_matrix_dual_tensor_hom], + by_cases hij : i = j, + { rw [hij], simp}, + rw matrix.std_basis_matrix.trace_zero j i (1:R) hij, + simp [finsupp.single_eq_pi_single, hij], +end + +/-- The trace of a linear map correspond to the contraction pairing under the isomorphism + `End(M) ≃ M* ⊗ M`-/ +lemma trace_eq_contract_of_basis' [decidable_eq ι] (b : basis ι R M) : + (linear_map.trace R M) = + (contract_left R M) ∘ₗ (dual_tensor_hom_equiv_of_basis b).symm.to_linear_map := +by simp [linear_equiv.eq_comp_to_linear_map_symm, trace_eq_contract_of_basis R b] + +variables [module.free R M] [module.finite R M] [nontrivial R] + +/-- When `M` is finite free, the trace of a linear map correspond to the contraction pairing under +the isomorphism `End(M) ≃ M* ⊗ M`-/ +@[simp] theorem trace_eq_contract : + (linear_map.trace R M) ∘ₗ (dual_tensor_hom R M M) = contract_left R M := +trace_eq_contract_of_basis R (module.free.choose_basis R M) + +open_locale classical + +/-- When `M` is finite free, the trace of a linear map correspond to the contraction pairing under +the isomorphism `End(M) ≃ M* ⊗ M`-/ +theorem trace_eq_contract' : + (linear_map.trace R M) = + (contract_left R M) ∘ₗ (dual_tensor_hom_equiv).symm.to_linear_map := +trace_eq_contract_of_basis' R (module.free.choose_basis R M) + +/-- The trace of the identity endomorphism is the dimension of the free module -/ +@[simp] theorem trace_one : trace R M 1 = (finrank R M : R) := +begin + have b := module.free.choose_basis R M, + rw [trace_eq_matrix_trace R b, to_matrix_one, module.free.finrank_eq_card_choose_basis_index], + simp, end end diff --git a/src/representation_theory/basic.lean b/src/representation_theory/basic.lean index c2c1e0039e8cf..40b5c4b1af4dd 100644 --- a/src/representation_theory/basic.lean +++ b/src/representation_theory/basic.lean @@ -100,7 +100,8 @@ noncomputable def character (g : G) : k := linear_map.trace k V (as_group_hom k G V g) /-- The evaluation of the character at the identity is the dimension of the representation. -/ -theorem char_one : character k G V 1 = finite_dimensional.finrank k V := by simp +theorem char_one [finite_dimensional k V] : character k G V 1 = finite_dimensional.finrank k V := +by simp /-- The character of a representation is constant on conjugacy classes. -/ theorem char_conj (g : G) (h : G) : (character k G V) (h * g * h⁻¹) = (character k G V) g := by simp From 7bfaa5c8f6954138d39b9f9e2a1b45d84cdf3153 Mon Sep 17 00:00:00 2001 From: tb65536 Date: Wed, 20 Apr 2022 17:09:57 +0000 Subject: [PATCH 099/373] feat(group_theory/schreier): Schreier's lemma in terms of `group.fg` and `group.rank` (#13361) This PR adds statements of Schreier's lemma in terms of `group.fg` and `group.rank`. --- src/group_theory/schreier.lean | 47 ++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/group_theory/schreier.lean b/src/group_theory/schreier.lean index 4f4effba32ab9..4381c2e8449d0 100644 --- a/src/group_theory/schreier.lean +++ b/src/group_theory/schreier.lean @@ -6,6 +6,8 @@ Authors: Thomas Browning import data.finset.pointwise import group_theory.complement +import group_theory.finiteness +import group_theory.index import tactic.group /-! @@ -18,6 +20,8 @@ In this file we prove Schreier's lemma. - `closure_mul_image_eq` : **Schreier's Lemma**: If `R : set G` is a right_transversal of `H : subgroup G` with `1 ∈ R`, and if `G` is generated by `S : set G`, then `H` is generated by the `set` `(R * S).image (λ g, g * (to_fun hR g)⁻¹)`. +- `fg_of_index_ne_zero` : **Schreier's Lemma**: A finite index subgroup of a finitely generated + group is finitely generated. -/ open_locale pointwise @@ -99,4 +103,47 @@ begin exact closure_mul_image_eq_top hR hR1 hS, end +lemma exists_finset_card_le_mul (hH : H.index ≠ 0) {S : finset G} (hS : closure (S : set G) = ⊤) : + ∃ T : finset H, T.card ≤ H.index * S.card ∧ closure (T : set H) = ⊤ := +begin + haveI : decidable_eq G := classical.dec_eq G, + obtain ⟨R₀, hR : R₀ ∈ right_transversals (H : set G), hR1⟩ := exists_right_transversal (1 : G), + haveI : fintype (G ⧸ H) := fintype_of_index_ne_zero hH, + haveI : fintype R₀ := fintype.of_equiv _ (mem_right_transversals.to_equiv hR), + let R : finset G := set.to_finset R₀, + replace hR : (R : set G) ∈ right_transversals (H : set G) := by rwa set.coe_to_finset, + replace hR1 : (1 : G) ∈ R := by rwa set.mem_to_finset, + refine ⟨_, _, closure_mul_image_eq_top' hR hR1 hS⟩, + calc _ ≤ (R * S).card : finset.card_image_le + ... ≤ (R.product S).card : finset.card_image_le + ... = R.card * S.card : R.card_product S + ... = H.index * S.card : congr_arg (* S.card) _, + calc R.card = fintype.card R : (fintype.card_coe R).symm + ... = _ : (fintype.card_congr (mem_right_transversals.to_equiv hR)).symm + ... = fintype.card (G ⧸ H) : quotient_group.card_quotient_right_rel H + ... = H.index : H.index_eq_card.symm, +end + +/-- **Schreier's Lemma**: A finite index subgroup of a finitely generated + group is finitely generated. -/ +lemma fg_of_index_ne_zero [hG : group.fg G] (hH : H.index ≠ 0) : group.fg H := +begin + obtain ⟨S, hS⟩ := hG.1, + obtain ⟨T, -, hT⟩ := exists_finset_card_le_mul hH hS, + exact ⟨⟨T, hT⟩⟩, +end + +lemma rank_le_index_mul_rank [hG : group.fg G] {H : subgroup G} (hH : H.index ≠ 0) + [decidable_pred (λ n, ∃ (S : finset G), S.card = n ∧ subgroup.closure (S : set G) = ⊤)] + [decidable_pred (λ n, ∃ (S : finset H), S.card = n ∧ subgroup.closure (S : set H) = ⊤)] : + @group.rank H _ (fg_of_index_ne_zero hH) _ ≤ H.index * group.rank G := +begin + haveI := fg_of_index_ne_zero hH, + obtain ⟨S, hS₀, hS⟩ := group.rank_spec G, + obtain ⟨T, hT₀, hT⟩ := exists_finset_card_le_mul hH hS, + calc group.rank H ≤ T.card : group.rank_le H hT + ... ≤ H.index * S.card : hT₀ + ... = H.index * group.rank G : congr_arg ((*) H.index) hS₀, +end + end subgroup From 242d687581e1bac72e7a4ec272c5869fe9e5b238 Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Wed, 20 Apr 2022 18:42:09 +0000 Subject: [PATCH 100/373] =?UTF-8?q?feat(algebra/hom/group=20and=20*):=20in?= =?UTF-8?q?troduce=20`mul=5Fhom=20M=20N`=20notation=20`M=20=E2=86=92?= =?UTF-8?q?=E2=82=99*=20N`=20(#13526)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The discussion and poll related to this new notation can be found in this [Zulip thread](https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/ring_hom.20notation.20and.20friends/near/279313301) --- src/algebra/category/Semigroup/basic.lean | 8 +- src/algebra/divisibility.lean | 2 +- src/algebra/free.lean | 4 +- src/algebra/group/pi.lean | 4 +- src/algebra/group/prod.lean | 36 ++++----- src/algebra/group/with_one.lean | 14 ++-- src/algebra/hom/equiv.lean | 8 +- src/algebra/hom/group.lean | 73 ++++++++++--------- src/algebra/hom/non_unital_alg.lean | 14 ++-- src/algebra/monoid_algebra/basic.lean | 10 +-- src/algebra/order/absolute_value.lean | 2 +- src/data/fintype/basic.lean | 2 +- src/data/set/pointwise.lean | 2 +- src/group_theory/group_action/prod.lean | 2 +- src/group_theory/subsemigroup/basic.lean | 10 +-- src/tactic/simps.lean | 2 +- src/topology/algebra/group.lean | 2 +- .../continuous_function/zero_at_infty.lean | 2 +- 18 files changed, 101 insertions(+), 96 deletions(-) diff --git a/src/algebra/category/Semigroup/basic.lean b/src/algebra/category/Semigroup/basic.lean index 1ea13d5584a59..b1437c0212461 100644 --- a/src/algebra/category/Semigroup/basic.lean +++ b/src/algebra/category/Semigroup/basic.lean @@ -56,13 +56,13 @@ def of (M : Type u) [has_mul M] : Magma := bundled.of M add_decl_doc AddMagma.of /-- Typecheck a `mul_hom` as a morphism in `Magma`. -/ -@[to_additive] def of_hom {X Y : Type u} [has_mul X] [has_mul Y] (f : mul_hom X Y) : +@[to_additive] def of_hom {X Y : Type u} [has_mul X] [has_mul Y] (f : X →ₙ* Y) : of X ⟶ of Y := f /-- Typecheck a `add_hom` as a morphism in `AddMagma`. -/ add_decl_doc AddMagma.of_hom -@[simp, to_additive] lemma of_hom_apply {X Y : Type u} [has_mul X] [has_mul Y] (f : mul_hom X Y) +@[simp, to_additive] lemma of_hom_apply {X Y : Type u} [has_mul X] [has_mul Y] (f : X →ₙ* Y) (x : X) : of_hom f x = f x := rfl @[to_additive] @@ -100,13 +100,13 @@ def of (M : Type u) [semigroup M] : Semigroup := bundled.of M add_decl_doc AddSemigroup.of /-- Typecheck a `mul_hom` as a morphism in `Semigroup`. -/ -@[to_additive] def of_hom {X Y : Type u} [semigroup X] [semigroup Y] (f : mul_hom X Y) : +@[to_additive] def of_hom {X Y : Type u} [semigroup X] [semigroup Y] (f : X →ₙ* Y) : of X ⟶ of Y := f /-- Typecheck a `add_hom` as a morphism in `AddSemigroup`. -/ add_decl_doc AddSemigroup.of_hom -@[simp, to_additive] lemma of_hom_apply {X Y : Type u} [semigroup X] [semigroup Y] (f : mul_hom X Y) +@[simp, to_additive] lemma of_hom_apply {X Y : Type u} [semigroup X] [semigroup Y] (f : X →ₙ* Y) (x : X) : of_hom f x = f x := rfl @[to_additive] diff --git a/src/algebra/divisibility.lean b/src/algebra/divisibility.lean index 427b2c234eb0c..10f0d165ec8c6 100644 --- a/src/algebra/divisibility.lean +++ b/src/algebra/divisibility.lean @@ -77,7 +77,7 @@ variables {M N : Type*} [monoid M] [monoid N] lemma map_dvd {F : Type*} [mul_hom_class F M N] (f : F) {a b} : a ∣ b → f a ∣ f b | ⟨c, h⟩ := ⟨f c, h.symm ▸ map_mul f a c⟩ -lemma mul_hom.map_dvd (f : mul_hom M N) {a b} : a ∣ b → f a ∣ f b := map_dvd f +lemma mul_hom.map_dvd (f : M →ₙ* N) {a b} : a ∣ b → f a ∣ f b := map_dvd f lemma monoid_hom.map_dvd (f : M →* N) {a b} : a ∣ b → f a ∣ f b := map_dvd f diff --git a/src/algebra/free.lean b/src/algebra/free.lean index 61118d3dfc1c4..e62e005b0c2c9 100644 --- a/src/algebra/free.lean +++ b/src/algebra/free.lean @@ -82,13 +82,13 @@ namespace free_magma variables {α : Type u} {β : Type v} [has_mul β] (f : α → β) @[to_additive] -theorem lift_aux_unique (F : mul_hom (free_magma α) β) : ⇑F = lift_aux (F ∘ of) := +theorem lift_aux_unique (F : free_magma α →ₙ* β) : ⇑F = lift_aux (F ∘ of) := funext $ λ x, free_magma.rec_on x (λ x, rfl) $ λ x y ih1 ih2, (F.map_mul x y).trans $ congr (congr_arg _ ih1) ih2 /-- The universal property of the free magma expressing its adjointness. -/ @[to_additive "The universal property of the free additive magma expressing its adjointness."] -def lift : (α → β) ≃ mul_hom (free_magma α) β := +def lift : (α → β) ≃ (free_magma α →ₙ* β) := { to_fun := λ f, { to_fun := lift_aux f, map_mul' := λ x y, rfl, }, diff --git a/src/algebra/group/pi.lean b/src/algebra/group/pi.lean index 22a5dc142d9fc..b6fe4274ae7e5 100644 --- a/src/algebra/group/pi.lean +++ b/src/algebra/group/pi.lean @@ -126,7 +126,7 @@ end pi namespace mul_hom @[to_additive] lemma coe_mul {M N} {mM : has_mul M} {mN : comm_semigroup N} - (f g : mul_hom M N) : + (f g : M →ₙ* N) : (f * g : M → N) = λ x, f x * g x := rfl end mul_hom @@ -219,7 +219,7 @@ lemma monoid_hom.single_apply [Π i, mul_one_class $ f i] (i : I) (x : f i) : into a dependent family of `mul_zero_class`es, as functions supported at a point. This is the `mul_hom` version of `pi.single`. -/ -@[simps] def mul_hom.single [Π i, mul_zero_class $ f i] (i : I) : mul_hom (f i) (Π i, f i) := +@[simps] def mul_hom.single [Π i, mul_zero_class $ f i] (i : I) : (f i) →ₙ* (Π i, f i) := { to_fun := single i, map_mul' := pi.single_op₂ (λ _, (*)) (λ _, zero_mul _) _, } diff --git a/src/algebra/group/prod.lean b/src/algebra/group/prod.lean index bd56b518ac0c2..02ccdc3969a29 100644 --- a/src/algebra/group/prod.lean +++ b/src/algebra/group/prod.lean @@ -194,42 +194,42 @@ variables (M N) [has_mul M] [has_mul N] [has_mul P] /-- Given magmas `M`, `N`, the natural projection homomorphism from `M × N` to `M`.-/ @[to_additive "Given additive magmas `A`, `B`, the natural projection homomorphism from `A × B` to `A`"] -def fst : mul_hom (M × N) M := ⟨prod.fst, λ _ _, rfl⟩ +def fst : (M × N) →ₙ* M := ⟨prod.fst, λ _ _, rfl⟩ /-- Given magmas `M`, `N`, the natural projection homomorphism from `M × N` to `N`.-/ @[to_additive "Given additive magmas `A`, `B`, the natural projection homomorphism from `A × B` to `B`"] -def snd : mul_hom (M × N) N := ⟨prod.snd, λ _ _, rfl⟩ +def snd : (M × N) →ₙ* N := ⟨prod.snd, λ _ _, rfl⟩ variables {M N} @[simp, to_additive] lemma coe_fst : ⇑(fst M N) = prod.fst := rfl @[simp, to_additive] lemma coe_snd : ⇑(snd M N) = prod.snd := rfl -/-- Combine two `monoid_hom`s `f : mul_hom M N`, `g : mul_hom M P` into -`f.prod g : mul_hom M (N × P)` given by `(f.prod g) x = (f x, g x)`. -/ +/-- Combine two `monoid_hom`s `f : M →ₙ* N`, `g : M →ₙ* P` into +`f.prod g : M →ₙ* (N × P)` given by `(f.prod g) x = (f x, g x)`. -/ @[to_additive prod "Combine two `add_monoid_hom`s `f : add_hom M N`, `g : add_hom M P` into `f.prod g : add_hom M (N × P)` given by `(f.prod g) x = (f x, g x)`"] -protected def prod (f : mul_hom M N) (g : mul_hom M P) : mul_hom M (N × P) := +protected def prod (f : M →ₙ* N) (g : M →ₙ* P) : M →ₙ* (N × P) := { to_fun := pi.prod f g, map_mul' := λ x y, prod.ext (f.map_mul x y) (g.map_mul x y) } @[to_additive coe_prod] -lemma coe_prod (f : mul_hom M N) (g : mul_hom M P) : ⇑(f.prod g) = pi.prod f g := rfl +lemma coe_prod (f : M →ₙ* N) (g : M →ₙ* P) : ⇑(f.prod g) = pi.prod f g := rfl @[simp, to_additive prod_apply] -lemma prod_apply (f : mul_hom M N) (g : mul_hom M P) (x) : f.prod g x = (f x, g x) := rfl +lemma prod_apply (f : M →ₙ* N) (g : M →ₙ* P) (x) : f.prod g x = (f x, g x) := rfl @[simp, to_additive fst_comp_prod] -lemma fst_comp_prod (f : mul_hom M N) (g : mul_hom M P) : (fst N P).comp (f.prod g) = f := +lemma fst_comp_prod (f : M →ₙ* N) (g : M →ₙ* P) : (fst N P).comp (f.prod g) = f := ext $ λ x, rfl @[simp, to_additive snd_comp_prod] -lemma snd_comp_prod (f : mul_hom M N) (g : mul_hom M P) : (snd N P).comp (f.prod g) = g := +lemma snd_comp_prod (f : M →ₙ* N) (g : M →ₙ* P) : (snd N P).comp (f.prod g) = g := ext $ λ x, rfl @[simp, to_additive prod_unique] -lemma prod_unique (f : mul_hom M (N × P)) : +lemma prod_unique (f : M →ₙ* (N × P)) : ((fst N P).comp f).prod ((snd N P).comp f) = f := ext $ λ x, by simp only [prod_apply, coe_fst, coe_snd, comp_apply, prod.mk.eta] @@ -238,11 +238,11 @@ end prod section prod_map variables {M' : Type*} {N' : Type*} [has_mul M] [has_mul N] [has_mul M'] [has_mul N'] [has_mul P] - (f : mul_hom M M') (g : mul_hom N N') + (f : M →ₙ* M') (g : N →ₙ* N') /-- `prod.map` as a `monoid_hom`. -/ @[to_additive prod_map "`prod.map` as an `add_monoid_hom`"] -def prod_map : mul_hom (M × N) (M' × N') := (f.comp (fst M N)).prod (g.comp (snd M N)) +def prod_map : (M × N) →ₙ* (M' × N') := (f.comp (fst M N)).prod (g.comp (snd M N)) @[to_additive prod_map_def] lemma prod_map_def : prod_map f g = (f.comp (fst M N)).prod (g.comp (snd M N)) := rfl @@ -251,8 +251,8 @@ lemma prod_map_def : prod_map f g = (f.comp (fst M N)).prod (g.comp (snd M N)) : lemma coe_prod_map : ⇑(prod_map f g) = prod.map f g := rfl @[to_additive prod_comp_prod_map] -lemma prod_comp_prod_map (f : mul_hom P M) (g : mul_hom P N) - (f' : mul_hom M M') (g' : mul_hom N N') : +lemma prod_comp_prod_map (f : P →ₙ* M) (g : P →ₙ* N) + (f' : M →ₙ* M') (g' : N →ₙ* N') : (f'.prod_map g').comp (f.prod g) = (f'.comp f).prod (g'.comp g) := rfl @@ -260,20 +260,20 @@ end prod_map section coprod -variables [has_mul M] [has_mul N] [comm_semigroup P] (f : mul_hom M P) (g : mul_hom N P) +variables [has_mul M] [has_mul N] [comm_semigroup P] (f : M →ₙ* P) (g : N →ₙ* P) /-- Coproduct of two `mul_hom`s with the same codomain: `f.coprod g (p : M × N) = f p.1 * g p.2`. -/ @[to_additive "Coproduct of two `add_hom`s with the same codomain: `f.coprod g (p : M × N) = f p.1 + g p.2`."] -def coprod : mul_hom (M × N) P := f.comp (fst M N) * g.comp (snd M N) +def coprod : (M × N) →ₙ* P := f.comp (fst M N) * g.comp (snd M N) @[simp, to_additive] lemma coprod_apply (p : M × N) : f.coprod g p = f p.1 * g p.2 := rfl @[to_additive] lemma comp_coprod {Q : Type*} [comm_semigroup Q] - (h : mul_hom P Q) (f : mul_hom M P) (g : mul_hom N P) : + (h : P →ₙ* Q) (f : M →ₙ* P) (g : N →ₙ* P) : h.comp (f.coprod g) = (h.comp f).coprod (h.comp g) := ext $ λ x, by simp @@ -475,7 +475,7 @@ variables {α : Type*} /-- Multiplication as a multiplicative homomorphism. -/ @[to_additive "Addition as an additive homomorphism.", simps] -def mul_mul_hom [comm_semigroup α] : mul_hom (α × α) α := +def mul_mul_hom [comm_semigroup α] : (α × α) →ₙ* α := { to_fun := λ a, a.1 * a.2, map_mul' := λ a b, mul_mul_mul_comm _ _ _ _ } diff --git a/src/algebra/group/with_one.lean b/src/algebra/group/with_one.lean index 98dc5e973f493..947969d1a122b 100644 --- a/src/algebra/group/with_one.lean +++ b/src/algebra/group/with_one.lean @@ -116,7 +116,7 @@ section local attribute [irreducible] with_one with_zero /-- `coe` as a bundled morphism -/ @[to_additive "`coe` as a bundled morphism", simps apply] -def coe_mul_hom [has_mul α] : mul_hom α (with_one α) := +def coe_mul_hom [has_mul α] : α →ₙ* (with_one α) := { to_fun := coe, map_mul' := λ x y, rfl } end @@ -127,7 +127,7 @@ variables [has_mul α] [mul_one_class β] /-- Lift a semigroup homomorphism `f` to a bundled monoid homorphism. -/ @[to_additive "Lift an add_semigroup homomorphism `f` to a bundled add_monoid homorphism."] -def lift : mul_hom α β ≃ (with_one α →* β) := +def lift : (α →ₙ* β) ≃ (with_one α →* β) := { to_fun := λ f, { to_fun := λ x, option.cases_on x 1 f, map_one' := rfl, @@ -139,7 +139,7 @@ def lift : mul_hom α β ≃ (with_one α →* β) := left_inv := λ f, mul_hom.ext $ λ x, rfl, right_inv := λ F, monoid_hom.ext $ λ x, with_one.cases_on x F.map_one.symm $ λ x, rfl } -variables (f : mul_hom α β) +variables (f : α →ₙ* β) @[simp, to_additive] lemma lift_coe (x : α) : lift f x = f x := rfl @@ -163,10 +163,10 @@ variables [has_mul α] [has_mul β] [has_mul γ] from `with_one α` to `with_one β` -/ @[to_additive "Given an additive map from `α → β` returns an add_monoid homomorphism from `with_zero α` to `with_zero β`"] -def map (f : mul_hom α β) : with_one α →* with_one β := +def map (f : α →ₙ* β) : with_one α →* with_one β := lift (coe_mul_hom.comp f) -@[simp, to_additive] lemma map_coe (f : mul_hom α β) (a : α) : map f (a : with_one α) = f a := +@[simp, to_additive] lemma map_coe (f : α →ₙ* β) (a : α) : map f (a : with_one α) = f a := lift_coe _ _ @[simp, to_additive] @@ -174,12 +174,12 @@ lemma map_id : map (mul_hom.id α) = monoid_hom.id (with_one α) := by { ext, induction x using with_one.cases_on; refl } @[to_additive] -lemma map_map (f : mul_hom α β) (g : mul_hom β γ) (x) : +lemma map_map (f : α →ₙ* β) (g : β →ₙ* γ) (x) : map g (map f x) = map (g.comp f) x := by { induction x using with_one.cases_on; refl } @[simp, to_additive] -lemma map_comp (f : mul_hom α β) (g : mul_hom β γ) : +lemma map_comp (f : α →ₙ* β) (g : β →ₙ* γ) : map (g.comp f) = (map g).comp (map f) := monoid_hom.ext $ λ x, (map_map f g x).symm diff --git a/src/algebra/hom/equiv.lean b/src/algebra/hom/equiv.lean index 678cd94d184ca..5f4e3db648b1a 100644 --- a/src/algebra/hom/equiv.lean +++ b/src/algebra/hom/equiv.lean @@ -35,8 +35,8 @@ variables {F α β A B M N P Q G H : Type*} /-- Makes a multiplicative inverse from a bijection which preserves multiplication. -/ @[to_additive "Makes an additive inverse from a bijection which preserves addition."] -def mul_hom.inverse [has_mul M] [has_mul N] (f : mul_hom M N) (g : N → M) - (h₁ : function.left_inverse g f) (h₂ : function.right_inverse g f) : mul_hom N M := +def mul_hom.inverse [has_mul M] [has_mul N] (f : M →ₙ* N) (g : N → M) + (h₁ : function.left_inverse g f) (h₂ : function.right_inverse g f) : N →ₙ* M := { to_fun := g, map_mul' := λ x y, calc g (x * y) = g (f (g x) * f (g y)) : by rw [h₂ x, h₂ y] @@ -50,7 +50,7 @@ def monoid_hom.inverse {A B : Type*} [monoid A] [monoid B] (f : A →* B) (g : B B →* A := { to_fun := g, map_one' := by rw [← f.map_one, h₁], - .. (f : mul_hom A B).inverse g h₁ h₂, } + .. (f : A →ₙ* B).inverse g h₁ h₂, } set_option old_structure_cmd true @@ -71,7 +71,7 @@ add_decl_doc add_equiv.to_add_hom /-- `mul_equiv α β` is the type of an equiv `α ≃ β` which preserves multiplication. -/ @[ancestor equiv mul_hom, to_additive] -structure mul_equiv (M N : Type*) [has_mul M] [has_mul N] extends M ≃ N, mul_hom M N +structure mul_equiv (M N : Type*) [has_mul M] [has_mul N] extends M ≃ N, M →ₙ* N /-- The `equiv` underlying a `mul_equiv`. -/ add_decl_doc mul_equiv.to_equiv diff --git a/src/algebra/hom/group.lean b/src/algebra/hom/group.lean index 14668e21817c0..73334b7ab39f9 100644 --- a/src/algebra/hom/group.lean +++ b/src/algebra/hom/group.lean @@ -32,6 +32,7 @@ building blocks for other homomorphisms: * `→+`: Bundled `add_monoid` homs. Also use for `add_group` homs. * `→*`: Bundled `monoid` homs. Also use for `group` homs. * `→*₀`: Bundled `monoid_with_zero` homs. Also use for `group_with_zero` homs. +* `→ₙ*`: Bundled `semigroup` homs. ## Implementation notes @@ -207,9 +208,11 @@ section mul variables [has_mul M] [has_mul N] -/-- `mul_hom M N` is the type of functions `M → N` that preserve multiplication. +/-- `M →ₙ* N` is the type of functions `M → N` that preserve multiplication. The `ₙ` in the notation +stands for "non-unital" because it is intended to match the notation for `non_unital_alg_hom` and +`non_unital_ring_hom`, so a `mul_hom` is a non-unital monoid hom. -When possible, instead of parametrizing results over `(f : mul_hom M N)`, +When possible, instead of parametrizing results over `(f : M →ₙ* N)`, you should parametrize over `(F : Type*) [mul_hom_class F M N] (f : F)`. When you extend this structure, make sure to extend `mul_hom_class`. -/ @@ -218,6 +221,8 @@ structure mul_hom (M : Type*) (N : Type*) [has_mul M] [has_mul N] := (to_fun : M → N) (map_mul' : ∀ x y, to_fun (x * y) = to_fun x * to_fun y) +infixr ` →ₙ* `:25 := mul_hom + /-- `mul_hom_class F M N` states that `F` is a type of multiplication-preserving homomorphisms. You should declare an instance of this typeclass when you extend `mul_hom`. @@ -228,7 +233,7 @@ class mul_hom_class (F : Type*) (M N : out_param $ Type*) (map_mul : ∀ (f : F) (x y : M), f (x * y) = f x * f y) @[to_additive] -instance mul_hom.mul_hom_class : mul_hom_class (mul_hom M N) M N := +instance mul_hom.mul_hom_class : mul_hom_class (M →ₙ* N) M N := { coe := mul_hom.to_fun, coe_injective' := λ f g h, by cases f; cases g; congr', map_mul := mul_hom.map_mul' } @@ -238,7 +243,7 @@ instance mul_hom.mul_hom_class : mul_hom_class (mul_hom M N) M N := mul_hom_class.map_mul f x y @[to_additive] -instance [mul_hom_class F M N] : has_coe_t F (mul_hom M N) := +instance [mul_hom_class F M N] : has_coe_t F (M →ₙ* N) := ⟨λ f, { to_fun := f, map_mul' := map_mul f }⟩ end mul @@ -257,7 +262,7 @@ When you extend this structure, make sure to extend `monoid_hom_class`. -/ @[ancestor one_hom mul_hom, to_additive] structure monoid_hom (M : Type*) (N : Type*) [mul_one_class M] [mul_one_class N] - extends one_hom M N, mul_hom M N + extends one_hom M N, M →ₙ* N attribute [nolint doc_blame] monoid_hom.to_mul_hom attribute [nolint doc_blame] monoid_hom.to_one_hom @@ -399,7 +404,7 @@ instance monoid_hom.has_coe_to_one_hom {mM : mul_one_class M} {mN : mul_one_clas has_coe (M →* N) (one_hom M N) := ⟨monoid_hom.to_one_hom⟩ @[to_additive] instance monoid_hom.has_coe_to_mul_hom {mM : mul_one_class M} {mN : mul_one_class N} : - has_coe (M →* N) (mul_hom M N) := ⟨monoid_hom.to_mul_hom⟩ + has_coe (M →* N) (M →ₙ* N) := ⟨monoid_hom.to_mul_hom⟩ instance monoid_with_zero_hom.has_coe_to_monoid_hom {mM : mul_zero_one_class M} {mN : mul_zero_one_class N} : has_coe (M →*₀ N) (M →* N) := ⟨monoid_with_zero_hom.to_monoid_hom⟩ @@ -415,7 +420,7 @@ lemma monoid_hom.coe_eq_to_one_hom {mM : mul_one_class M} {mN : mul_one_class N} (f : one_hom M N) = f.to_one_hom := rfl @[simp, to_additive] lemma monoid_hom.coe_eq_to_mul_hom {mM : mul_one_class M} {mN : mul_one_class N} (f : M →* N) : - (f : mul_hom M N) = f.to_mul_hom := rfl + (f : M →ₙ* N) = f.to_mul_hom := rfl @[simp] lemma monoid_with_zero_hom.coe_eq_to_monoid_hom {mM : mul_zero_one_class M} {mN : mul_zero_one_class N} (f : M →*₀ N) : @@ -430,7 +435,7 @@ lemma monoid_with_zero_hom.coe_eq_to_zero_hom instance {mM : has_one M} {mN : has_one N} : has_coe_to_fun (one_hom M N) (λ _, M → N) := ⟨one_hom.to_fun⟩ @[to_additive] -instance {mM : has_mul M} {mN : has_mul N} : has_coe_to_fun (mul_hom M N) (λ _, M → N) := +instance {mM : has_mul M} {mN : has_mul N} : has_coe_to_fun (M →ₙ* N) (λ _, M → N) := ⟨mul_hom.to_fun⟩ @[to_additive] instance {mM : mul_one_class M} {mN : mul_one_class N} : has_coe_to_fun (M →* N) (λ _, M → N) := @@ -452,7 +457,7 @@ initialize_simps_projections monoid_with_zero_hom (to_fun → apply) @[simp, to_additive] lemma one_hom.to_fun_eq_coe [has_one M] [has_one N] (f : one_hom M N) : f.to_fun = f := rfl @[simp, to_additive] -lemma mul_hom.to_fun_eq_coe [has_mul M] [has_mul N] (f : mul_hom M N) : f.to_fun = f := rfl +lemma mul_hom.to_fun_eq_coe [has_mul M] [has_mul N] (f : M →ₙ* N) : f.to_fun = f := rfl @[simp, to_additive] lemma monoid_hom.to_fun_eq_coe [mul_one_class M] [mul_one_class N] (f : M →* N) : f.to_fun = f := rfl @@ -492,7 +497,7 @@ lemma monoid_with_zero_hom.to_monoid_hom_coe [mul_zero_one_class M] [mul_zero_on lemma one_hom.ext [has_one M] [has_one N] ⦃f g : one_hom M N⦄ (h : ∀ x, f x = g x) : f = g := fun_like.ext _ _ h @[ext, to_additive] -lemma mul_hom.ext [has_mul M] [has_mul N] ⦃f g : mul_hom M N⦄ (h : ∀ x, f x = g x) : f = g := +lemma mul_hom.ext [has_mul M] [has_mul N] ⦃f g : M →ₙ* N⦄ (h : ∀ x, f x = g x) : f = g := fun_like.ext _ _ h @[ext, to_additive] lemma monoid_hom.ext [mul_one_class M] [mul_one_class N] @@ -513,7 +518,7 @@ fun_like.congr_fun h x /-- Deprecated: use `fun_like.congr_fun` instead. -/ @[to_additive "Deprecated: use `fun_like.congr_fun` instead."] theorem mul_hom.congr_fun [has_mul M] [has_mul N] - {f g : mul_hom M N} (h : f = g) (x : M) : f x = g x := + {f g : M →ₙ* N} (h : f = g) (x : M) : f x = g x := fun_like.congr_fun h x /-- Deprecated: use `fun_like.congr_fun` instead. -/ @[to_additive "Deprecated: use `fun_like.congr_fun` instead."] @@ -533,7 +538,7 @@ fun_like.congr_arg f h /-- Deprecated: use `fun_like.congr_arg` instead. -/ @[to_additive "Deprecated: use `fun_like.congr_arg` instead."] theorem mul_hom.congr_arg [has_mul M] [has_mul N] - (f : mul_hom M N) {x y : M} (h : x = y) : f x = f y := + (f : M →ₙ* N) {x y : M} (h : x = y) : f x = f y := fun_like.congr_arg f h /-- Deprecated: use `fun_like.congr_arg` instead. -/ @[to_additive "Deprecated: use `fun_like.congr_arg` instead."] @@ -551,7 +556,7 @@ lemma one_hom.coe_inj [has_one M] [has_one N] ⦃f g : one_hom M N⦄ (h : (f : fun_like.coe_injective h /-- Deprecated: use `fun_like.coe_injective` instead. -/ @[to_additive "Deprecated: use `fun_like.coe_injective` instead."] -lemma mul_hom.coe_inj [has_mul M] [has_mul N] ⦃f g : mul_hom M N⦄ (h : (f : M → N) = g) : f = g := +lemma mul_hom.coe_inj [has_mul M] [has_mul N] ⦃f g : M →ₙ* N⦄ (h : (f : M → N) = g) : f = g := fun_like.coe_injective h /-- Deprecated: use `fun_like.coe_injective` instead. -/ @[to_additive "Deprecated: use `fun_like.coe_injective` instead."] @@ -569,7 +574,7 @@ lemma one_hom.ext_iff [has_one M] [has_one N] {f g : one_hom M N} : f = g ↔ fun_like.ext_iff /-- Deprecated: use `fun_like.ext_iff` instead. -/ @[to_additive] -lemma mul_hom.ext_iff [has_mul M] [has_mul N] {f g : mul_hom M N} : f = g ↔ ∀ x, f x = g x := +lemma mul_hom.ext_iff [has_mul M] [has_mul N] {f g : M →ₙ* N} : f = g ↔ ∀ x, f x = g x := fun_like.ext_iff /-- Deprecated: use `fun_like.ext_iff` instead. -/ @[to_additive] @@ -588,7 +593,7 @@ lemma one_hom.mk_coe [has_one M] [has_one N] one_hom.ext $ λ _, rfl @[simp, to_additive] lemma mul_hom.mk_coe [has_mul M] [has_mul N] - (f : mul_hom M N) (hmul) : mul_hom.mk f hmul = f := + (f : M →ₙ* N) (hmul) : mul_hom.mk f hmul = f := mul_hom.ext $ λ _, rfl @[simp, to_additive] lemma monoid_hom.mk_coe [mul_one_class M] [mul_one_class N] @@ -614,8 +619,8 @@ protected def one_hom.copy {hM : has_one M} {hN : has_one N} (f : one_hom M N) ( equalities. -/ @[to_additive "Copy of an `add_hom` with a new `to_fun` equal to the old one. Useful to fix definitional equalities."] -protected def mul_hom.copy {hM : has_mul M} {hN : has_mul N} (f : mul_hom M N) (f' : M → N) - (h : f' = f) : mul_hom M N := +protected def mul_hom.copy {hM : has_mul M} {hN : has_mul N} (f : M →ₙ* N) (f' : M → N) + (h : f' = f) : M →ₙ* N := { to_fun := f', map_mul' := h.symm ▸ f.map_mul' } @@ -649,7 +654,7 @@ protected lemma monoid_with_zero_hom.map_zero [mul_zero_one_class M] [mul_zero_o @[to_additive] protected lemma mul_hom.map_mul [has_mul M] [has_mul N] - (f : mul_hom M N) (a b : M) : f (a * b) = f a * f b := f.map_mul' a b + (f : M →ₙ* N) (a b : M) : f (a * b) = f a * f b := f.map_mul' a b /-- If `f` is a monoid homomorphism then `f (a * b) = f a * f b`. -/ @[to_additive] protected lemma monoid_hom.map_mul [mul_one_class M] [mul_one_class N] @@ -703,7 +708,7 @@ def one_hom.id (M : Type*) [has_one M] : one_hom M M := { to_fun := λ x, x, map_one' := rfl, } /-- The identity map from a type with multiplication to itself. -/ @[to_additive, simps] -def mul_hom.id (M : Type*) [has_mul M] : mul_hom M M := +def mul_hom.id (M : Type*) [has_mul M] : M →ₙ* M := { to_fun := λ x, x, map_mul' := λ _ _, rfl, } /-- The identity map from a monoid to itself. -/ @[to_additive, simps] @@ -729,7 +734,7 @@ def one_hom.comp [has_one M] [has_one N] [has_one P] /-- Composition of `mul_hom`s as a `mul_hom`. -/ @[to_additive] def mul_hom.comp [has_mul M] [has_mul N] [has_mul P] - (hnp : mul_hom N P) (hmn : mul_hom M N) : mul_hom M P := + (hnp : N →ₙ* P) (hmn : M →ₙ* N) : M →ₙ* P := { to_fun := hnp ∘ hmn, map_mul' := by simp, } /-- Composition of monoid morphisms as a monoid morphism. -/ @@ -754,7 +759,7 @@ add_decl_doc add_monoid_hom.comp (g : one_hom N P) (f : one_hom M N) : ⇑(g.comp f) = g ∘ f := rfl @[simp, to_additive] lemma mul_hom.coe_comp [has_mul M] [has_mul N] [has_mul P] - (g : mul_hom N P) (f : mul_hom M N) : + (g : N →ₙ* P) (f : M →ₙ* N) : ⇑(g.comp f) = g ∘ f := rfl @[simp, to_additive] lemma monoid_hom.coe_comp [mul_one_class M] [mul_one_class N] [mul_one_class P] (g : N →* P) (f : M →* N) : @@ -767,7 +772,7 @@ add_decl_doc add_monoid_hom.comp (g : one_hom N P) (f : one_hom M N) (x : M) : g.comp f x = g (f x) := rfl @[to_additive] lemma mul_hom.comp_apply [has_mul M] [has_mul N] [has_mul P] - (g : mul_hom N P) (f : mul_hom M N) (x : M) : + (g : N →ₙ* P) (f : M →ₙ* N) (x : M) : g.comp f x = g (f x) := rfl @[to_additive] lemma monoid_hom.comp_apply [mul_one_class M] [mul_one_class N] [mul_one_class P] (g : N →* P) (f : M →* N) (x : M) : @@ -781,7 +786,7 @@ lemma monoid_with_zero_hom.comp_apply [mul_zero_one_class M] [mul_zero_one_class (f : one_hom M N) (g : one_hom N P) (h : one_hom P Q) : (h.comp g).comp f = h.comp (g.comp f) := rfl @[to_additive] lemma mul_hom.comp_assoc {Q : Type*} [has_mul M] [has_mul N] [has_mul P] [has_mul Q] - (f : mul_hom M N) (g : mul_hom N P) (h : mul_hom P Q) : + (f : M →ₙ* N) (g : N →ₙ* P) (h : P →ₙ* Q) : (h.comp g).comp f = h.comp (g.comp f) := rfl @[to_additive] lemma monoid_hom.comp_assoc {Q : Type*} [mul_one_class M] [mul_one_class N] [mul_one_class P] [mul_one_class Q] @@ -799,7 +804,7 @@ lemma one_hom.cancel_right [has_one M] [has_one N] [has_one P] ⟨λ h, one_hom.ext $ hf.forall.2 (one_hom.ext_iff.1 h), λ h, h ▸ rfl⟩ @[to_additive] lemma mul_hom.cancel_right [has_mul M] [has_mul N] [has_mul P] - {g₁ g₂ : mul_hom N P} {f : mul_hom M N} (hf : function.surjective f) : + {g₁ g₂ : N →ₙ* P} {f : M →ₙ* N} (hf : function.surjective f) : g₁.comp f = g₂.comp f ↔ g₁ = g₂ := ⟨λ h, mul_hom.ext $ hf.forall.2 (mul_hom.ext_iff.1 h), λ h, h ▸ rfl⟩ @[to_additive] @@ -822,7 +827,7 @@ lemma one_hom.cancel_left [has_one M] [has_one N] [has_one P] λ h, h ▸ rfl⟩ @[to_additive] lemma mul_hom.cancel_left [has_mul M] [has_mul N] [has_mul P] - {g : mul_hom N P} {f₁ f₂ : mul_hom M N} (hg : function.injective g) : + {g : N →ₙ* P} {f₁ f₂ : M →ₙ* N} (hg : function.injective g) : g.comp f₁ = g.comp f₂ ↔ f₁ = f₂ := ⟨λ h, mul_hom.ext $ λ x, hg $ by rw [← mul_hom.comp_apply, h, mul_hom.comp_apply], λ h, h ▸ rfl⟩ @@ -845,7 +850,7 @@ lemma monoid_hom.to_one_hom_injective [mul_one_class M] [mul_one_class N] : λ f g h, monoid_hom.ext $ one_hom.ext_iff.mp h @[to_additive] lemma monoid_hom.to_mul_hom_injective [mul_one_class M] [mul_one_class N] : - function.injective (monoid_hom.to_mul_hom : (M →* N) → mul_hom M N) := + function.injective (monoid_hom.to_mul_hom : (M →* N) → M →ₙ* N) := λ f g h, monoid_hom.ext $ mul_hom.ext_iff.mp h lemma monoid_with_zero_hom.to_monoid_hom_injective [mul_zero_one_class M] [mul_zero_one_class N] : function.injective (monoid_with_zero_hom.to_monoid_hom : (M →*₀ N) → M →* N) := @@ -857,7 +862,7 @@ lemma monoid_with_zero_hom.to_zero_hom_injective [mul_zero_one_class M] [mul_zer @[simp, to_additive] lemma one_hom.comp_id [has_one M] [has_one N] (f : one_hom M N) : f.comp (one_hom.id M) = f := one_hom.ext $ λ x, rfl @[simp, to_additive] lemma mul_hom.comp_id [has_mul M] [has_mul N] - (f : mul_hom M N) : f.comp (mul_hom.id M) = f := mul_hom.ext $ λ x, rfl + (f : M →ₙ* N) : f.comp (mul_hom.id M) = f := mul_hom.ext $ λ x, rfl @[simp, to_additive] lemma monoid_hom.comp_id [mul_one_class M] [mul_one_class N] (f : M →* N) : f.comp (monoid_hom.id M) = f := monoid_hom.ext $ λ x, rfl @[simp] lemma monoid_with_zero_hom.comp_id [mul_zero_one_class M] [mul_zero_one_class N] @@ -867,7 +872,7 @@ monoid_with_zero_hom.ext $ λ x, rfl @[simp, to_additive] lemma one_hom.id_comp [has_one M] [has_one N] (f : one_hom M N) : (one_hom.id N).comp f = f := one_hom.ext $ λ x, rfl @[simp, to_additive] lemma mul_hom.id_comp [has_mul M] [has_mul N] - (f : mul_hom M N) : (mul_hom.id N).comp f = f := mul_hom.ext $ λ x, rfl + (f : M →ₙ* N) : (mul_hom.id N).comp f = f := mul_hom.ext $ λ x, rfl @[simp, to_additive] lemma monoid_hom.id_comp [mul_one_class M] [mul_one_class N] (f : M →* N) : (monoid_hom.id N).comp f = f := monoid_hom.ext $ λ x, rfl @[simp] lemma monoid_with_zero_hom.id_comp [mul_zero_one_class M] [mul_zero_one_class N] @@ -953,7 +958,7 @@ end End instance [has_one M] [has_one N] : has_one (one_hom M N) := ⟨⟨λ _, 1, rfl⟩⟩ /-- `1` is the multiplicative homomorphism sending all elements to `1`. -/ @[to_additive] -instance [has_mul M] [mul_one_class N] : has_one (mul_hom M N) := +instance [has_mul M] [mul_one_class N] : has_one (M →ₙ* N) := ⟨⟨λ _, 1, λ _ _, (one_mul 1).symm⟩⟩ /-- `1` is the monoid homomorphism sending all elements to `1`. -/ @[to_additive] @@ -981,7 +986,7 @@ by { ext, simp only [one_hom.map_one, one_hom.coe_comp, function.comp_app, one_h @[to_additive] instance [has_one M] [has_one N] : inhabited (one_hom M N) := ⟨1⟩ @[to_additive] -instance [has_mul M] [mul_one_class N] : inhabited (mul_hom M N) := ⟨1⟩ +instance [has_mul M] [mul_one_class N] : inhabited (M →ₙ* N) := ⟨1⟩ @[to_additive] instance [mul_one_class M] [mul_one_class N] : inhabited (M →* N) := ⟨1⟩ -- unlike the other homs, `monoid_with_zero_hom` does not have a `1` or `0` @@ -992,7 +997,7 @@ namespace mul_hom /-- Given two mul morphisms `f`, `g` to a commutative semigroup, `f * g` is the mul morphism sending `x` to `f x * g x`. -/ @[to_additive] -instance [has_mul M] [comm_semigroup N] : has_mul (mul_hom M N) := +instance [has_mul M] [comm_semigroup N] : has_mul (M →ₙ* N) := ⟨λ f g, { to_fun := λ m, f m * g m, map_mul' := begin intros, show f (x * y) * g (x * y) = f x * g x * (f y * g y), @@ -1003,14 +1008,14 @@ additive morphism sending `x` to `f x + g x`. -/ add_decl_doc add_hom.has_add @[simp, to_additive] lemma mul_apply {M N} {mM : has_mul M} {mN : comm_semigroup N} - (f g : mul_hom M N) (x : M) : + (f g : M →ₙ* N) (x : M) : (f * g) x = f x * g x := rfl @[to_additive] lemma mul_comp [has_mul M] [has_mul N] [comm_semigroup P] - (g₁ g₂ : mul_hom N P) (f : mul_hom M N) : + (g₁ g₂ : N →ₙ* P) (f : M →ₙ* N) : (g₁ * g₂).comp f = g₁.comp f * g₂.comp f := rfl @[to_additive] lemma comp_mul [has_mul M] [comm_semigroup N] [comm_semigroup P] - (g : mul_hom N P) (f₁ f₂ : mul_hom M N) : + (g : N →ₙ* P) (f₁ f₂ : M →ₙ* N) : g.comp (f₁ * f₂) = g.comp f₁ * g.comp f₂ := by { ext, simp only [mul_apply, function.comp_app, map_mul, coe_comp] } diff --git a/src/algebra/hom/non_unital_alg.lean b/src/algebra/hom/non_unital_alg.lean index 5f9b63c1c3e26..a32b7ae3c1bd4 100644 --- a/src/algebra/hom/non_unital_alg.lean +++ b/src/algebra/hom/non_unital_alg.lean @@ -52,7 +52,7 @@ algebra structures, this is the same as a not-necessarily-unital morphism of alg structure non_unital_alg_hom [monoid R] [non_unital_non_assoc_semiring A] [distrib_mul_action R A] [non_unital_non_assoc_semiring B] [distrib_mul_action R B] - extends A →+[R] B, mul_hom A B + extends A →+[R] B, A →ₙ* B attribute [nolint doc_blame] non_unital_alg_hom.to_distrib_mul_action_hom attribute [nolint doc_blame] non_unital_alg_hom.to_mul_hom @@ -94,7 +94,7 @@ by { ext, refl, } instance : has_coe (non_unital_alg_hom R A B) (A →+[R] B) := ⟨to_distrib_mul_action_hom⟩ -instance : has_coe (non_unital_alg_hom R A B) (mul_hom A B) := ⟨to_mul_hom⟩ +instance : has_coe (non_unital_alg_hom R A B) (A →ₙ* B) := ⟨to_mul_hom⟩ @[simp] lemma to_distrib_mul_action_hom_eq_coe (f : non_unital_alg_hom R A B) : f.to_distrib_mul_action_hom = ↑f := @@ -108,7 +108,7 @@ rfl rfl @[simp, norm_cast] lemma coe_to_mul_hom (f : non_unital_alg_hom R A B) : - ((f : mul_hom A B) : A → B) = f := + ((f : A →ₙ* B) : A → B) = f := rfl lemma to_distrib_mul_action_hom_injective {f g : non_unital_alg_hom R A B} @@ -116,7 +116,7 @@ lemma to_distrib_mul_action_hom_injective {f g : non_unital_alg_hom R A B} by { ext a, exact distrib_mul_action_hom.congr_fun h a, } lemma to_mul_hom_injective {f g : non_unital_alg_hom R A B} - (h : (f : mul_hom A B) = (g : mul_hom A B)) : f = g := + (h : (f : A →ₙ* B) = (g : A →ₙ* B)) : f = g := by { ext a, exact mul_hom.congr_fun h a, } @[norm_cast] lemma coe_distrib_mul_action_hom_mk (f : non_unital_alg_hom R A B) (h₁ h₂ h₃ h₄) : @@ -125,7 +125,7 @@ by { ext a, exact mul_hom.congr_fun h a, } by { ext, refl, } @[norm_cast] lemma coe_mul_hom_mk (f : non_unital_alg_hom R A B) (h₁ h₂ h₃ h₄) : - ((⟨f, h₁, h₂, h₃, h₄⟩ : non_unital_alg_hom R A B) : mul_hom A B) = ⟨f, h₄⟩ := + ((⟨f, h₁, h₂, h₃, h₄⟩ : non_unital_alg_hom R A B) : A →ₙ* B) = ⟨f, h₄⟩ := by { ext, refl, } @[simp] lemma map_smul (f : non_unital_alg_hom R A B) (c : R) (x : A) : @@ -163,7 +163,7 @@ instance : inhabited (non_unital_alg_hom R A B) := ⟨0⟩ /-- The composition of morphisms is a morphism. -/ def comp (f : non_unital_alg_hom R B C) (g : non_unital_alg_hom R A B) : non_unital_alg_hom R A C := -{ .. (f : mul_hom B C).comp (g : mul_hom A B), +{ .. (f : B →ₙ* C).comp (g : A →ₙ* B), .. (f : B →+[R] C).comp (g : A →+[R] B) } @[simp, norm_cast] lemma coe_comp (f : non_unital_alg_hom R B C) (g : non_unital_alg_hom R A B) : @@ -178,7 +178,7 @@ rfl def inverse (f : non_unital_alg_hom R A B) (g : B → A) (h₁ : function.left_inverse g f) (h₂ : function.right_inverse g f) : non_unital_alg_hom R B A := -{ .. (f : mul_hom A B).inverse g h₁ h₂, +{ .. (f : A →ₙ* B).inverse g h₁ h₂, .. (f : A →+[R] B).inverse g h₁ h₂ } @[simp] lemma coe_inverse (f : non_unital_alg_hom R A B) (g : B → A) diff --git a/src/algebra/monoid_algebra/basic.lean b/src/algebra/monoid_algebra/basic.lean index c0c95778c61fe..9b3b2d2f2dace 100644 --- a/src/algebra/monoid_algebra/basic.lean +++ b/src/algebra/monoid_algebra/basic.lean @@ -362,7 +362,7 @@ end variables (k G) /-- The embedding of a magma into its magma algebra. -/ -@[simps] def of_magma [has_mul G] : mul_hom G (monoid_algebra k G) := +@[simps] def of_magma [has_mul G] : G →ₙ* (monoid_algebra k G) := { to_fun := λ a, single a 1, map_mul' := λ a b, by simp only [mul_def, mul_one, sum_single_index, single_eq_zero, mul_zero], } @@ -510,7 +510,7 @@ non_unital_alg_hom_ext k $ mul_hom.congr_fun h /-- The functor `G ↦ monoid_algebra k G`, from the category of magmas to the category of non-unital, non-associative algebras over `k` is adjoint to the forgetful functor in the other direction. -/ @[simps] def lift_magma [module k A] [is_scalar_tower k A A] [smul_comm_class k A A] : - mul_hom G A ≃ non_unital_alg_hom k (monoid_algebra k G) A := + (G →ₙ* A) ≃ non_unital_alg_hom k (monoid_algebra k G) A := { to_fun := λ f, { to_fun := λ a, a.sum (λ m t, t • f m), map_smul' := λ t' a, @@ -1133,7 +1133,7 @@ section variables (k G) /-- The embedding of an additive magma into its additive magma algebra. -/ -@[simps] def of_magma [has_add G] : mul_hom (multiplicative G) (add_monoid_algebra k G) := +@[simps] def of_magma [has_add G] : multiplicative G →ₙ* add_monoid_algebra k G := { to_fun := λ a, single a 1, map_mul' := λ a b, by simpa only [mul_def, mul_one, sum_single_index, single_eq_zero, mul_zero], } @@ -1321,11 +1321,11 @@ lemma non_unital_alg_hom_ext [distrib_mul_action k A] non-unital, non-associative algebras over `k` is adjoint to the forgetful functor in the other direction. -/ @[simps] def lift_magma [module k A] [is_scalar_tower k A A] [smul_comm_class k A A] : - mul_hom (multiplicative G) A ≃ non_unital_alg_hom k (add_monoid_algebra k G) A := + (multiplicative G →ₙ* A) ≃ non_unital_alg_hom k (add_monoid_algebra k G) A := { to_fun := λ f, { to_fun := λ a, sum a (λ m t, t • f (multiplicative.of_add m)), .. (monoid_algebra.lift_magma k f : _)}, inv_fun := λ F, F.to_mul_hom.comp (of_magma k G), - .. (monoid_algebra.lift_magma k : mul_hom (multiplicative G) A ≃ non_unital_alg_hom k _ A) } + .. (monoid_algebra.lift_magma k : (multiplicative G →ₙ* A) ≃ non_unital_alg_hom k _ A) } end non_unital_non_assoc_algebra diff --git a/src/algebra/order/absolute_value.lean b/src/algebra/order/absolute_value.lean index e35a9ba25f8b6..e17a13b6e4dd6 100644 --- a/src/algebra/order/absolute_value.lean +++ b/src/algebra/order/absolute_value.lean @@ -22,7 +22,7 @@ This file defines a bundled type of absolute values `absolute_value R S`. /-- `absolute_value R S` is the type of absolute values on `R` mapping to `S`: the maps that preserve `*`, are nonnegative, positive definite and satisfy the triangle equality. -/ structure absolute_value (R S : Type*) [semiring R] [ordered_semiring S] - extends mul_hom R S := + extends R →ₙ* S := (nonneg' : ∀ x, 0 ≤ to_fun x) (eq_zero' : ∀ x, to_fun x = 0 ↔ x = 0) (add_le' : ∀ x y, to_fun (x + y) ≤ to_fun x + to_fun y) diff --git a/src/data/fintype/basic.lean b/src/data/fintype/basic.lean index b039c38686ef1..e464fe054d09e 100644 --- a/src/data/fintype/basic.lean +++ b/src/data/fintype/basic.lean @@ -269,7 +269,7 @@ instance decidable_eq_one_hom_fintype [decidable_eq β] [fintype α] [has_one α @[to_additive] instance decidable_eq_mul_hom_fintype [decidable_eq β] [fintype α] [has_mul α] [has_mul β]: - decidable_eq (mul_hom α β) := + decidable_eq (α →ₙ* β) := λ a b, decidable_of_iff ((a : α → β) = b) (injective.eq_iff mul_hom.coe_inj) @[to_additive] diff --git a/src/data/set/pointwise.lean b/src/data/set/pointwise.lean index 8e363e561fdf8..bdee911b76418 100644 --- a/src/data/set/pointwise.lean +++ b/src/data/set/pointwise.lean @@ -192,7 +192,7 @@ image2_Inter₂_subset_right _ _ _ which preserves multiplication. -/ @[to_additive "Under `[has_add A]`, the `singleton` map from `A` to `set A` as an `add_hom`, that is, a map which preserves addition.", simps] -def singleton_mul_hom : mul_hom α (set α) := +def singleton_mul_hom : α →ₙ* (set α) := { to_fun := singleton, map_mul' := λ a b, singleton_mul_singleton.symm } diff --git a/src/group_theory/group_action/prod.lean b/src/group_theory/group_action/prod.lean index 4dc42ddcda1e1..dc845b81552d2 100644 --- a/src/group_theory/group_action/prod.lean +++ b/src/group_theory/group_action/prod.lean @@ -93,7 +93,7 @@ section bundled_smul @[simps] def smul_mul_hom [monoid α] [has_mul β] [mul_action α β] [is_scalar_tower α β β] [smul_comm_class α β β] : - mul_hom (α × β) β := + (α × β) →ₙ* β := { to_fun := λ a, a.1 • a.2, map_mul' := λ a b, (smul_mul_smul _ _ _ _).symm } diff --git a/src/group_theory/subsemigroup/basic.lean b/src/group_theory/subsemigroup/basic.lean index e192e38d4e28c..445eaa37c0fc1 100644 --- a/src/group_theory/subsemigroup/basic.lean +++ b/src/group_theory/subsemigroup/basic.lean @@ -336,24 +336,24 @@ open subsemigroup /-- The subsemigroup of elements `x : M` such that `f x = g x` -/ @[to_additive "The additive subsemigroup of elements `x : M` such that `f x = g x`"] -def eq_mlocus (f g : mul_hom M N) : subsemigroup M := +def eq_mlocus (f g : M →ₙ* N) : subsemigroup M := { carrier := {x | f x = g x}, mul_mem' := λ x y (hx : _ = _) (hy : _ = _), by simp [*] } /-- If two mul homomorphisms are equal on a set, then they are equal on its subsemigroup closure. -/ @[to_additive "If two add homomorphisms are equal on a set, then they are equal on its additive subsemigroup closure."] -lemma eq_on_mclosure {f g : mul_hom M N} {s : set M} (h : set.eq_on f g s) : +lemma eq_on_mclosure {f g : M →ₙ* N} {s : set M} (h : set.eq_on f g s) : set.eq_on f g (closure s) := show closure s ≤ f.eq_mlocus g, from closure_le.2 h @[to_additive] -lemma eq_of_eq_on_mtop {f g : mul_hom M N} (h : set.eq_on f g (⊤ : subsemigroup M)) : +lemma eq_of_eq_on_mtop {f g : M →ₙ* N} (h : set.eq_on f g (⊤ : subsemigroup M)) : f = g := ext $ λ x, h trivial @[to_additive] -lemma eq_of_eq_on_mdense {s : set M} (hs : closure s = ⊤) {f g : mul_hom M N} (h : s.eq_on f g) : +lemma eq_of_eq_on_mdense {s : set M} (hs : closure s = ⊤) {f g : M →ₙ* N} (h : s.eq_on f g) : f = g := eq_of_eq_on_mtop $ hs ▸ eq_on_mclosure h @@ -374,7 +374,7 @@ of `f (x * y) = f x * f y` only for `y ∈ s`. -/ @[to_additive] def of_mdense {M N} [semigroup M] [semigroup N] {s : set M} (f : M → N) (hs : closure s = ⊤) (hmul : ∀ x (y ∈ s), f (x * y) = f x * f y) : - mul_hom M N := + M →ₙ* N := { to_fun := f, map_mul' := λ x y, dense_induction y hs (λ y hy x, hmul x y hy) (λ y₁ y₂ h₁ h₂ x, by simp only [← mul_assoc, h₁, h₂]) x } diff --git a/src/tactic/simps.lean b/src/tactic/simps.lean index 20593f5b09225..167adf136e985 100644 --- a/src/tactic/simps.lean +++ b/src/tactic/simps.lean @@ -416,7 +416,7 @@ Some common uses: * If you define a new homomorphism-like structure (like `mul_hom`) you can just run `initialize_simps_projections` after defining the `has_coe_to_fun` instance ``` - instance {mM : has_mul M} {mN : has_mul N} : has_coe_to_fun (mul_hom M N) := ... + instance {mM : has_mul M} {mN : has_mul N} : has_coe_to_fun (M →ₙ* N) := ... initialize_simps_projections mul_hom (to_fun → apply) ``` This will generate `foo_apply` lemmas for each declaration `foo`. diff --git a/src/topology/algebra/group.lean b/src/topology/algebra/group.lean index 5a22353d613ba..792e4dffa821f 100644 --- a/src/topology/algebra/group.lean +++ b/src/topology/algebra/group.lean @@ -1069,7 +1069,7 @@ end /-- On a topological group, `𝓝 : G → filter G` can be promoted to a `mul_hom`. -/ @[to_additive "On an additive topological group, `𝓝 : G → filter G` can be promoted to an `add_hom`.", simps] -def nhds_mul_hom : mul_hom G (filter G) := +def nhds_mul_hom : G →ₙ* (filter G) := { to_fun := 𝓝, map_mul' := λ_ _, nhds_mul _ _ } diff --git a/src/topology/continuous_function/zero_at_infty.lean b/src/topology/continuous_function/zero_at_infty.lean index f747021fa0f6d..a318af726a967 100644 --- a/src/topology/continuous_function/zero_at_infty.lean +++ b/src/topology/continuous_function/zero_at_infty.lean @@ -506,7 +506,7 @@ def comp_add_monoid_hom [add_monoid δ] [has_continuous_add δ] (g : β →co γ /-- Composition as a semigroup homomorphism. -/ def comp_mul_hom [mul_zero_class δ] [has_continuous_mul δ] - (g : β →co γ) : mul_hom C₀(γ, δ) C₀(β, δ) := + (g : β →co γ) : C₀(γ, δ) →ₙ* C₀(β, δ) := { to_fun := λ f, f.comp g, map_mul' := λ f₁ f₂, rfl } From 27a8328b3bfff5f8cf51466c3032f89718201573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Wed, 20 Apr 2022 18:42:10 +0000 Subject: [PATCH 101/373] =?UTF-8?q?feat(data/real/sqrt):=20`sqrt=20x=20 0`, consider using `le_sqrt'` -/ theorem le_sqrt (hx : 0 ≤ x) (hy : 0 ≤ y) : x ≤ sqrt y ↔ x ^ 2 ≤ y := -by rw [mul_self_le_mul_self_iff hx (sqrt_nonneg _), sq, mul_self_sqrt hy] +le_iff_le_iff_lt_iff_lt.2 $ sqrt_lt hy hx -theorem le_sqrt' (hx : 0 < x) : x ≤ sqrt y ↔ x ^ 2 ≤ y := -by { rw [sqrt, ← nnreal.coe_mk x hx.le, nnreal.coe_le_coe, nnreal.le_sqrt_iff, - real.le_to_nnreal_iff_coe_le', sq, nnreal.coe_mul], exact mul_pos hx hx } +lemma le_sqrt' (hx : 0 < x) : x ≤ sqrt y ↔ x ^ 2 ≤ y := le_iff_le_iff_lt_iff_lt.2 $ sqrt_lt' hx theorem abs_le_sqrt (h : x^2 ≤ y) : |x| ≤ sqrt y := by rw ← sqrt_sq_eq_abs; exact sqrt_le_sqrt h @@ -293,16 +297,10 @@ by rw [←div_sqrt, one_div_div, div_sqrt] theorem sqrt_div_self : sqrt x / x = (sqrt x)⁻¹ := by rw [sqrt_div_self', one_div] -theorem lt_sqrt (hx : 0 ≤ x) (hy : 0 ≤ y) : x < sqrt y ↔ x ^ 2 < y := -by rw [mul_self_lt_mul_self_iff hx (sqrt_nonneg y), sq, mul_self_sqrt hy] +lemma lt_sqrt (hx : 0 ≤ x) : x < sqrt y ↔ x ^ 2 < y := +by rw [←sqrt_lt_sqrt_iff (sq_nonneg _), sqrt_sq hx] -theorem sq_lt : x^2 < y ↔ -sqrt y < x ∧ x < sqrt y := -begin - split, - { simpa only [← sqrt_lt_sqrt_iff (sq_nonneg x), sqrt_sq_eq_abs] using abs_lt.mp }, - { rw [← abs_lt, ← sq_abs], - exact λ h, (lt_sqrt (abs_nonneg x) (sqrt_pos.mp (lt_of_le_of_lt (abs_nonneg x) h)).le).mp h }, -end +lemma sq_lt : x^2 < y ↔ -sqrt y < x ∧ x < sqrt y := by rw [←abs_lt, ←sq_abs, lt_sqrt (abs_nonneg _)] theorem neg_sqrt_lt_of_sq_lt (h : x^2 < y) : -sqrt y < x := (sq_lt.mp h).1 From 9d6d8c26784b7eb301de840071c21046d1e4d9dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Wed, 20 Apr 2022 18:42:11 +0000 Subject: [PATCH 102/373] feat(group_theory/perm/basic): Iterating a permutation is the same as taking a power (#13554) --- src/group_theory/perm/basic.lean | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/group_theory/perm/basic.lean b/src/group_theory/perm/basic.lean index ad2cf23c063a2..fc96c9c447c1f 100644 --- a/src/group_theory/perm/basic.lean +++ b/src/group_theory/perm/basic.lean @@ -5,6 +5,7 @@ Authors: Leonardo de Moura, Mario Carneiro -/ import algebra.group.pi import algebra.group_power.lemmas +import logic.function.iterate /-! # The group of permutations (self-equivalences) of a type `α` @@ -51,10 +52,14 @@ lemma eq_inv_iff_eq {f : perm α} {x y : α} : x = f⁻¹ y ↔ f x = y := f.eq_ lemma inv_eq_iff_eq {f : perm α} {x y : α} : f⁻¹ x = y ↔ x = f y := f.symm_apply_eq -lemma zpow_apply_comm {α : Type*} (σ : equiv.perm α) (m n : ℤ) {x : α} : +lemma zpow_apply_comm {α : Type*} (σ : perm α) (m n : ℤ) {x : α} : (σ ^ m) ((σ ^ n) x) = (σ ^ n) ((σ ^ m) x) := by rw [←equiv.perm.mul_apply, ←equiv.perm.mul_apply, zpow_mul_comm] +@[simp] lemma iterate_eq_pow (f : perm α) : ∀ n, f^[n] = ⇑(f ^ n) +| 0 := rfl +| (n + 1) := by { rw [function.iterate_succ, pow_add, iterate_eq_pow], refl } + /-! Lemmas about mixing `perm` with `equiv`. Because we have multiple ways to express `equiv.refl`, `equiv.symm`, and `equiv.trans`, we want simp lemmas for every combination. The assumption made here is that if you're using the group structure, you want to preserve it after From 741d28519981f307f6f2621b44cb2156792c184a Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Wed, 20 Apr 2022 20:40:18 +0000 Subject: [PATCH 103/373] chore(number_theory/zsqrtd/basic): simplify le_total proof (#13555) --- src/number_theory/zsqrtd/basic.lean | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/number_theory/zsqrtd/basic.lean b/src/number_theory/zsqrtd/basic.lean index d884a97778471..f4f972c69b422 100644 --- a/src/number_theory/zsqrtd/basic.lean +++ b/src/number_theory/zsqrtd/basic.lean @@ -516,7 +516,10 @@ protected theorem nonneg_total : Π (a : ℤ√d), nonneg a ∨ nonneg (-a) | ⟨-[1+ x], (y+1:ℕ)⟩ := nat.le_total protected theorem le_total (a b : ℤ√d) : a ≤ b ∨ b ≤ a := -let t := nonneg_total (b - a) in by rw [show -(b-a) = a-b, from neg_sub b a] at t; exact t +begin + have t := (b - a).nonneg_total, + rwa neg_sub at t, +end instance : preorder ℤ√d := { le := (≤), From b86b927259e35348ddf4dddecb09b918c3664f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Wed, 20 Apr 2022 21:15:06 +0000 Subject: [PATCH 104/373] move(set_theory/*): Organize in folders (#13530) Create folders `cardinal`, `ordinal` and `game`. Most files under `set_theory` belong to a least one of them. --- archive/100-theorems-list/82_cubing_a_cube.lean | 3 ++- src/algebra/quaternion.lean | 2 +- src/category_theory/limits/small_complete.lean | 2 +- src/combinatorics/configuration.lean | 2 +- src/computability/encoding.lean | 2 +- src/data/W/cardinal.lean | 3 ++- src/data/nat/count.lean | 2 +- src/data/rat/denumerable.lean | 2 +- src/data/real/cardinality.lean | 2 +- src/field_theory/cardinality.lean | 2 +- src/group_theory/free_product.lean | 3 +-- src/group_theory/index.lean | 2 +- src/group_theory/solvable.lean | 2 +- src/linear_algebra/dimension.lean | 6 +++--- src/linear_algebra/linear_independent.lean | 2 +- src/measure_theory/card_measurable_space.lean | 4 ++-- src/measure_theory/covering/besicovitch.lean | 2 +- src/model_theory/basic.lean | 6 +++--- src/model_theory/encoding.lean | 4 ++-- src/ring_theory/localization/cardinality.lean | 4 ++-- src/set_theory/{cardinal.lean => cardinal/basic.lean} | 0 src/set_theory/{ => cardinal}/cofinality.lean | 5 +++-- src/set_theory/{ => cardinal}/continuum.lean | 2 +- .../divisibility.lean} | 2 +- src/set_theory/{fincard.lean => cardinal/finite.lean} | 2 +- .../{cardinal_ordinal.lean => cardinal/ordinal.lean} | 2 +- src/set_theory/{game.lean => game/basic.lean} | 2 +- src/set_theory/game/nim.lean | 2 +- src/set_theory/{ => game}/pgame.lean | 0 src/set_theory/game/short.lean | 2 +- src/set_theory/game/winner.lean | 2 +- .../{ordinal_arithmetic.lean => ordinal/arithmetic.lean} | 2 +- src/set_theory/{ordinal.lean => ordinal/basic.lean} | 2 +- .../{fixed_points.lean => ordinal/fixed_point.lean} | 2 +- .../{ordinal_notation.lean => ordinal/notation.lean} | 2 +- src/set_theory/{ => ordinal}/principal.lean | 2 +- .../{ordinal_topology.lean => ordinal/topology.lean} | 2 +- src/set_theory/surreal/basic.lean | 2 +- src/topology/metric_space/emetric_paracompact.lean | 2 +- src/topology/metric_space/gromov_hausdorff.lean | 4 ++-- src/topology/partition_of_unity.lean | 6 +++--- 41 files changed, 53 insertions(+), 51 deletions(-) rename src/set_theory/{cardinal.lean => cardinal/basic.lean} (100%) rename src/set_theory/{ => cardinal}/cofinality.lean (99%) rename src/set_theory/{ => cardinal}/continuum.lean (98%) rename src/set_theory/{cardinal_divisibility.lean => cardinal/divisibility.lean} (99%) rename src/set_theory/{fincard.lean => cardinal/finite.lean} (97%) rename src/set_theory/{cardinal_ordinal.lean => cardinal/ordinal.lean} (99%) rename src/set_theory/{game.lean => game/basic.lean} (99%) rename src/set_theory/{ => game}/pgame.lean (100%) rename src/set_theory/{ordinal_arithmetic.lean => ordinal/arithmetic.lean} (99%) rename src/set_theory/{ordinal.lean => ordinal/basic.lean} (99%) rename src/set_theory/{fixed_points.lean => ordinal/fixed_point.lean} (99%) rename src/set_theory/{ordinal_notation.lean => ordinal/notation.lean} (99%) rename src/set_theory/{ => ordinal}/principal.lean (99%) rename src/set_theory/{ordinal_topology.lean => ordinal/topology.lean} (99%) diff --git a/archive/100-theorems-list/82_cubing_a_cube.lean b/archive/100-theorems-list/82_cubing_a_cube.lean index f2a69654f255c..a96eeefa80ea1 100644 --- a/archive/100-theorems-list/82_cubing_a_cube.lean +++ b/archive/100-theorems-list/82_cubing_a_cube.lean @@ -7,7 +7,8 @@ import data.fin.tuple import data.real.basic import data.set.intervals import data.set.pairwise -import set_theory.cardinal +import set_theory.cardinal.basic + /-! 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) diff --git a/src/algebra/quaternion.lean b/src/algebra/quaternion.lean index 03ac18dd2eb9b..7d645994e9ea0 100644 --- a/src/algebra/quaternion.lean +++ b/src/algebra/quaternion.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import algebra.algebra.basic -import set_theory.cardinal_ordinal +import set_theory.cardinal.ordinal import tactic.ring_exp /-! diff --git a/src/category_theory/limits/small_complete.lean b/src/category_theory/limits/small_complete.lean index fcbc5238d5f5f..e416c868d1212 100644 --- a/src/category_theory/limits/small_complete.lean +++ b/src/category_theory/limits/small_complete.lean @@ -5,7 +5,7 @@ Authors: Bhavik Mehta -/ import category_theory.limits.shapes.products -import set_theory.cardinal +import set_theory.cardinal.basic /-! # Any small complete category is a preorder diff --git a/src/combinatorics/configuration.lean b/src/combinatorics/configuration.lean index 99be7ceca1dd8..c767e7bd0718e 100644 --- a/src/combinatorics/configuration.lean +++ b/src/combinatorics/configuration.lean @@ -6,7 +6,7 @@ Authors: Thomas Browning import algebra.big_operators.order import combinatorics.hall.basic import data.fintype.card -import set_theory.fincard +import set_theory.cardinal.finite /-! # Configurations of Points and lines diff --git a/src/computability/encoding.lean b/src/computability/encoding.lean index 689fcc9360968..d52384f7a2d0a 100644 --- a/src/computability/encoding.lean +++ b/src/computability/encoding.lean @@ -6,8 +6,8 @@ Authors: Pim Spelier, Daan van Gent import data.fintype.basic import data.num.lemmas +import set_theory.cardinal.ordinal import tactic.derive_fintype -import set_theory.cardinal_ordinal /-! # Encodings diff --git a/src/data/W/cardinal.lean b/src/data/W/cardinal.lean index 27a122490cf91..d5dd68d7b2759 100644 --- a/src/data/W/cardinal.lean +++ b/src/data/W/cardinal.lean @@ -3,8 +3,9 @@ Copyright (c) 2021 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ -import set_theory.cardinal_ordinal import data.W.basic +import set_theory.cardinal.ordinal + /-! # Cardinality of W-types diff --git a/src/data/nat/count.lean b/src/data/nat/count.lean index 86e5626ad2acc..d7649b4a53427 100644 --- a/src/data/nat/count.lean +++ b/src/data/nat/count.lean @@ -5,7 +5,7 @@ Authors: Yaël Dillies, Vladimir Goryachev, Kyle Miller, Scott Morrison, Eric Ro -/ import data.list.basic import data.nat.prime -import set_theory.fincard +import set_theory.cardinal.finite /-! # Counting on ℕ diff --git a/src/data/rat/denumerable.lean b/src/data/rat/denumerable.lean index c0caa16a68cd6..b5fa8b12c17b8 100644 --- a/src/data/rat/denumerable.lean +++ b/src/data/rat/denumerable.lean @@ -3,7 +3,7 @@ Copyright (c) 2019 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ -import set_theory.cardinal +import set_theory.cardinal.basic /-! # Denumerability of ℚ diff --git a/src/data/real/cardinality.lean b/src/data/real/cardinality.lean index 98d299ce5232b..d301d012069d2 100644 --- a/src/data/real/cardinality.lean +++ b/src/data/real/cardinality.lean @@ -3,10 +3,10 @@ Copyright (c) 2019 Floris van Doorn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn -/ -import set_theory.continuum import analysis.specific_limits.basic import data.rat.denumerable import data.set.intervals.image_preimage +import set_theory.cardinal.continuum /-! # The cardinality of the reals diff --git a/src/field_theory/cardinality.lean b/src/field_theory/cardinality.lean index b4c166a6da781..2d48f1aa45b25 100644 --- a/src/field_theory/cardinality.lean +++ b/src/field_theory/cardinality.lean @@ -9,7 +9,7 @@ import data.rat.denumerable import field_theory.finite.galois_field import logic.equiv.transfer_instance import ring_theory.localization.cardinality -import set_theory.cardinal_divisibility +import set_theory.cardinal.divisibility /-! # Cardinality of Fields diff --git a/src/group_theory/free_product.lean b/src/group_theory/free_product.lean index 6fe7caded260a..f26c786d203bf 100644 --- a/src/group_theory/free_product.lean +++ b/src/group_theory/free_product.lean @@ -8,8 +8,7 @@ import group_theory.congruence import group_theory.is_free_group import group_theory.subgroup.pointwise import data.list.chain -import set_theory.cardinal -import set_theory.cardinal_ordinal +import set_theory.cardinal.ordinal /-! # The free product of groups or monoids diff --git a/src/group_theory/index.lean b/src/group_theory/index.lean index 1a6d9fd33217d..79b83b7e5edc4 100644 --- a/src/group_theory/index.lean +++ b/src/group_theory/index.lean @@ -5,7 +5,7 @@ Authors: Thomas Browning -/ import group_theory.quotient_group -import set_theory.fincard +import set_theory.cardinal.finite /-! # Index of a Subgroup diff --git a/src/group_theory/solvable.lean b/src/group_theory/solvable.lean index d48745d0a1186..32a39b4b8e698 100644 --- a/src/group_theory/solvable.lean +++ b/src/group_theory/solvable.lean @@ -6,7 +6,7 @@ Authors: Jordan Brown, Thomas Browning, Patrick Lutz import data.fin.vec_notation import group_theory.abelianization -import set_theory.cardinal +import set_theory.cardinal.basic /-! # Solvable Groups diff --git a/src/linear_algebra/dimension.lean b/src/linear_algebra/dimension.lean index 5e64f309ca74a..d058093538b46 100644 --- a/src/linear_algebra/dimension.lean +++ b/src/linear_algebra/dimension.lean @@ -4,10 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Johannes Hölzl, Sander Dahmen, Scott Morrison -/ import linear_algebra.dfinsupp -import linear_algebra.std_basis -import linear_algebra.isomorphisms -import set_theory.cofinality import linear_algebra.invariant_basis_number +import linear_algebra.isomorphisms +import linear_algebra.std_basis +import set_theory.cardinal.cofinality /-! # Dimension of modules and vector spaces diff --git a/src/linear_algebra/linear_independent.lean b/src/linear_algebra/linear_independent.lean index 19fac22920bc8..7b6cd8b6ce506 100644 --- a/src/linear_algebra/linear_independent.lean +++ b/src/linear_algebra/linear_independent.lean @@ -6,7 +6,7 @@ Authors: Johannes Hölzl, Mario Carneiro, Alexander Bentkamp, Anne Baanen import linear_algebra.finsupp import linear_algebra.prod import logic.equiv.fin -import set_theory.cardinal +import set_theory.cardinal.basic /-! diff --git a/src/measure_theory/card_measurable_space.lean b/src/measure_theory/card_measurable_space.lean index 2cd06e1192312..2c83c4b6d4f3d 100644 --- a/src/measure_theory/card_measurable_space.lean +++ b/src/measure_theory/card_measurable_space.lean @@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel, Violeta Hernández Palacios -/ import measure_theory.measurable_space_def -import set_theory.continuum -import set_theory.cofinality +import set_theory.cardinal.cofinality +import set_theory.cardinal.continuum /-! # Cardinal of sigma-algebras diff --git a/src/measure_theory/covering/besicovitch.lean b/src/measure_theory/covering/besicovitch.lean index e9026f3d12290..a88727f55140d 100644 --- a/src/measure_theory/covering/besicovitch.lean +++ b/src/measure_theory/covering/besicovitch.lean @@ -7,7 +7,7 @@ import measure_theory.covering.differentiation import measure_theory.covering.vitali_family import measure_theory.integral.lebesgue import measure_theory.measure.regular -import set_theory.ordinal_arithmetic +import set_theory.ordinal.arithmetic import topology.metric_space.basic /-! diff --git a/src/model_theory/basic.lean b/src/model_theory/basic.lean index 9486e6f94133f..bc389f9a09b6b 100644 --- a/src/model_theory/basic.lean +++ b/src/model_theory/basic.lean @@ -3,12 +3,12 @@ Copyright (c) 2021 Aaron Anderson, Jesse Michael Han, Floris van Doorn. All righ Released under Apache 2.0 license as described in the file LICENSE. Authors: Aaron Anderson, Jesse Michael Han, Floris van Doorn -/ -import data.fin.vec_notation +import category_theory.concrete_category.bundled import data.fin.tuple.basic +import data.fin.vec_notation import logic.encodable.basic import logic.small -import set_theory.cardinal -import category_theory.concrete_category.bundled +import set_theory.cardinal.basic /-! diff --git a/src/model_theory/encoding.lean b/src/model_theory/encoding.lean index b8a7faa2c04ba..c04120c934e55 100644 --- a/src/model_theory/encoding.lean +++ b/src/model_theory/encoding.lean @@ -4,9 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Aaron Anderson -/ -import model_theory.syntax -import set_theory.cardinal_ordinal import computability.encoding +import model_theory.syntax +import set_theory.cardinal.ordinal /-! # Encodings and Cardinality of First-Order Syntax diff --git a/src/ring_theory/localization/cardinality.lean b/src/ring_theory/localization/cardinality.lean index af8cc15be6df2..5bc32507eea44 100644 --- a/src/ring_theory/localization/cardinality.lean +++ b/src/ring_theory/localization/cardinality.lean @@ -3,9 +3,9 @@ Copyright (c) 2022 Eric Rodriguez. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Rodriguez -/ -import ring_theory.localization.basic -import set_theory.cardinal_ordinal import ring_theory.integral_domain +import ring_theory.localization.basic +import set_theory.cardinal.ordinal /-! # Cardinality of localizations diff --git a/src/set_theory/cardinal.lean b/src/set_theory/cardinal/basic.lean similarity index 100% rename from src/set_theory/cardinal.lean rename to src/set_theory/cardinal/basic.lean diff --git a/src/set_theory/cofinality.lean b/src/set_theory/cardinal/cofinality.lean similarity index 99% rename from src/set_theory/cofinality.lean rename to src/set_theory/cardinal/cofinality.lean index 6a6e96414aecd..1495460b762b7 100644 --- a/src/set_theory/cofinality.lean +++ b/src/set_theory/cardinal/cofinality.lean @@ -3,11 +3,12 @@ Copyright (c) 2017 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Floris van Doorn -/ -import set_theory.cardinal_ordinal +import set_theory.cardinal.ordinal + /-! # Cofinality -This file contains the definition of cofinality of a ordinal number and regular cardinals +This file contains the definition of cofinality of an ordinal number and regular cardinals ## Main Definitions diff --git a/src/set_theory/continuum.lean b/src/set_theory/cardinal/continuum.lean similarity index 98% rename from src/set_theory/continuum.lean rename to src/set_theory/cardinal/continuum.lean index c64b6ae95c468..929e6a6369691 100644 --- a/src/set_theory/continuum.lean +++ b/src/set_theory/cardinal/continuum.lean @@ -3,7 +3,7 @@ Copyright (c) 2021 Yury Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ -import set_theory.cardinal_ordinal +import set_theory.cardinal.ordinal /-! # Cardinality of continuum diff --git a/src/set_theory/cardinal_divisibility.lean b/src/set_theory/cardinal/divisibility.lean similarity index 99% rename from src/set_theory/cardinal_divisibility.lean rename to src/set_theory/cardinal/divisibility.lean index a7cfd2d2f2f18..0abd61ae6e5ba 100644 --- a/src/set_theory/cardinal_divisibility.lean +++ b/src/set_theory/cardinal/divisibility.lean @@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Rodriguez -/ -import set_theory.cardinal_ordinal import algebra.is_prime_pow +import set_theory.cardinal.ordinal /-! # Cardinal Divisibility diff --git a/src/set_theory/fincard.lean b/src/set_theory/cardinal/finite.lean similarity index 97% rename from src/set_theory/fincard.lean rename to src/set_theory/cardinal/finite.lean index 0af54dd8ea871..31afa0177383e 100644 --- a/src/set_theory/fincard.lean +++ b/src/set_theory/cardinal/finite.lean @@ -3,7 +3,7 @@ Copyright (c) 2021 Aaron Anderson. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Aaron Anderson -/ -import set_theory.cardinal +import set_theory.cardinal.basic /-! # Finite Cardinality Functions diff --git a/src/set_theory/cardinal_ordinal.lean b/src/set_theory/cardinal/ordinal.lean similarity index 99% rename from src/set_theory/cardinal_ordinal.lean rename to src/set_theory/cardinal/ordinal.lean index fa9e2fcbe791c..01e94fa0c6b25 100644 --- a/src/set_theory/cardinal_ordinal.lean +++ b/src/set_theory/cardinal/ordinal.lean @@ -5,7 +5,7 @@ Authors: Johannes Hölzl, Mario Carneiro, Floris van Doorn -/ import order.bounded -import set_theory.principal +import set_theory.ordinal.principal import tactic.linarith /-! diff --git a/src/set_theory/game.lean b/src/set_theory/game/basic.lean similarity index 99% rename from src/set_theory/game.lean rename to src/set_theory/game/basic.lean index c74fe0b93e954..f58729e041508 100644 --- a/src/set_theory/game.lean +++ b/src/set_theory/game/basic.lean @@ -3,7 +3,7 @@ Copyright (c) 2019 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Reid Barton, Mario Carneiro, Isabel Longbottom, Scott Morrison, Apurva Nakade -/ -import set_theory.pgame +import set_theory.game.pgame import tactic.abel /-! diff --git a/src/set_theory/game/nim.lean b/src/set_theory/game/nim.lean index 167a34eab9a58..8ceabff8e17af 100644 --- a/src/set_theory/game/nim.lean +++ b/src/set_theory/game/nim.lean @@ -5,7 +5,7 @@ Authors: Fox Thomson, Markus Himmel -/ import data.nat.bitwise import set_theory.game.impartial -import set_theory.ordinal_arithmetic +import set_theory.ordinal.arithmetic /-! # Nim and the Sprague-Grundy theorem diff --git a/src/set_theory/pgame.lean b/src/set_theory/game/pgame.lean similarity index 100% rename from src/set_theory/pgame.lean rename to src/set_theory/game/pgame.lean diff --git a/src/set_theory/game/short.lean b/src/set_theory/game/short.lean index 314d2c934e62a..92b9c76a0c801 100644 --- a/src/set_theory/game/short.lean +++ b/src/set_theory/game/short.lean @@ -3,8 +3,8 @@ Copyright (c) 2019 Scott Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Scott Morrison -/ -import set_theory.game import data.fintype.basic +import set_theory.game.basic /-! # Short games diff --git a/src/set_theory/game/winner.lean b/src/set_theory/game/winner.lean index e87f868626f76..af0e6b24337f4 100644 --- a/src/set_theory/game/winner.lean +++ b/src/set_theory/game/winner.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Fox Thomson. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Fox Thomson -/ -import set_theory.pgame +import set_theory.game.pgame /-! # Basic definitions about who has a winning stratergy diff --git a/src/set_theory/ordinal_arithmetic.lean b/src/set_theory/ordinal/arithmetic.lean similarity index 99% rename from src/set_theory/ordinal_arithmetic.lean rename to src/set_theory/ordinal/arithmetic.lean index 0a70211d32a06..cb182df7f9126 100644 --- a/src/set_theory/ordinal_arithmetic.lean +++ b/src/set_theory/ordinal/arithmetic.lean @@ -3,7 +3,7 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Floris van Doorn, Violeta Hernández Palacios -/ -import set_theory.ordinal +import set_theory.ordinal.basic import tactic.by_contra /-! diff --git a/src/set_theory/ordinal.lean b/src/set_theory/ordinal/basic.lean similarity index 99% rename from src/set_theory/ordinal.lean rename to src/set_theory/ordinal/basic.lean index 57be22898e326..6db5f5f00a79a 100644 --- a/src/set_theory/ordinal.lean +++ b/src/set_theory/ordinal/basic.lean @@ -6,7 +6,7 @@ Authors: Mario Carneiro, Floris van Doorn import data.sum.order import logic.small import order.succ_pred.basic -import set_theory.cardinal +import set_theory.cardinal.basic /-! # Ordinals diff --git a/src/set_theory/fixed_points.lean b/src/set_theory/ordinal/fixed_point.lean similarity index 99% rename from src/set_theory/fixed_points.lean rename to src/set_theory/ordinal/fixed_point.lean index 99662024d405d..13359187aec24 100644 --- a/src/set_theory/fixed_points.lean +++ b/src/set_theory/ordinal/fixed_point.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Violeta Hernández Palacios -/ -import set_theory.ordinal_arithmetic +import set_theory.ordinal.arithmetic /-! # Fixed points of normal functions diff --git a/src/set_theory/ordinal_notation.lean b/src/set_theory/ordinal/notation.lean similarity index 99% rename from src/set_theory/ordinal_notation.lean rename to src/set_theory/ordinal/notation.lean index fb384ee2591e6..c1bd6c3c109dd 100644 --- a/src/set_theory/ordinal_notation.lean +++ b/src/set_theory/ordinal/notation.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ -import set_theory.principal +import set_theory.ordinal.principal /-! # Ordinal notation diff --git a/src/set_theory/principal.lean b/src/set_theory/ordinal/principal.lean similarity index 99% rename from src/set_theory/principal.lean rename to src/set_theory/ordinal/principal.lean index be4a61cfecd71..578c9eec1786d 100644 --- a/src/set_theory/principal.lean +++ b/src/set_theory/ordinal/principal.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Violeta Hernández Palacios -/ -import set_theory.ordinal_arithmetic +import set_theory.ordinal.arithmetic /-! ### Principal ordinals diff --git a/src/set_theory/ordinal_topology.lean b/src/set_theory/ordinal/topology.lean similarity index 99% rename from src/set_theory/ordinal_topology.lean rename to src/set_theory/ordinal/topology.lean index 030c5cbb7ebc6..e3d157dfc5444 100644 --- a/src/set_theory/ordinal_topology.lean +++ b/src/set_theory/ordinal/topology.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Violeta Hernández Palacios. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Violeta Hernández Palacios -/ -import set_theory.ordinal_arithmetic +import set_theory.ordinal.arithmetic import topology.algebra.order.basic /-! diff --git a/src/set_theory/surreal/basic.lean b/src/set_theory/surreal/basic.lean index eb65789c550f9..7545656a8a66c 100644 --- a/src/set_theory/surreal/basic.lean +++ b/src/set_theory/surreal/basic.lean @@ -3,7 +3,7 @@ Copyright (c) 2019 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Scott Morrison -/ -import set_theory.pgame +import set_theory.game.pgame /-! # Surreal numbers diff --git a/src/topology/metric_space/emetric_paracompact.lean b/src/topology/metric_space/emetric_paracompact.lean index 39cd889359e50..801c60c72932c 100644 --- a/src/topology/metric_space/emetric_paracompact.lean +++ b/src/topology/metric_space/emetric_paracompact.lean @@ -3,9 +3,9 @@ Copyright (c) 202 Yury G. Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury G. Kudryashov -/ +import set_theory.ordinal.basic import topology.metric_space.emetric_space import topology.paracompact -import set_theory.ordinal /-! # (Extended) metric spaces are paracompact diff --git a/src/topology/metric_space/gromov_hausdorff.lean b/src/topology/metric_space/gromov_hausdorff.lean index 228bfc6991085..b55d1b10a459f 100644 --- a/src/topology/metric_space/gromov_hausdorff.lean +++ b/src/topology/metric_space/gromov_hausdorff.lean @@ -3,10 +3,10 @@ Copyright (c) 2019 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ +import set_theory.cardinal.basic import topology.metric_space.closeds -import set_theory.cardinal -import topology.metric_space.gromov_hausdorff_realized import topology.metric_space.completion +import topology.metric_space.gromov_hausdorff_realized import topology.metric_space.kuratowski /-! diff --git a/src/topology/partition_of_unity.lean b/src/topology/partition_of_unity.lean index f3cfd509c4d4c..e84f667a35365 100644 --- a/src/topology/partition_of_unity.lean +++ b/src/topology/partition_of_unity.lean @@ -4,11 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import algebra.big_operators.finprod -import topology.urysohns_lemma +import set_theory.ordinal.basic +import topology.continuous_function.algebra import topology.paracompact import topology.shrinking_lemma -import topology.continuous_function.algebra -import set_theory.ordinal +import topology.urysohns_lemma /-! # Continuous partition of unity From 81c8f310c6bffbf40f97140e3bbaecb455a1d03c Mon Sep 17 00:00:00 2001 From: Floris van Doorn Date: Wed, 20 Apr 2022 22:44:20 +0000 Subject: [PATCH 105/373] refactor(analysis/calculus/cont_diff): reorder the file (#13468) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * There are no functional changes in this PR (except the order of implicit arguments in some lemmas) * This PR tries to move `cont_diff.comp` above some other lemmas. In a follow-up PR I will use this to add lemmas like `cont_diff.fst` which requires `cont_diff.comp`, but after this PR we can add it near `cont_diff_fst`. * We also add `{m n : with_top ℕ}` as variables, so that we don't have to repeat this in every lemma --- src/analysis/calculus/cont_diff.lean | 649 +++++++++++++-------------- 1 file changed, 305 insertions(+), 344 deletions(-) diff --git a/src/analysis/calculus/cont_diff.lean b/src/analysis/calculus/cont_diff.lean index af3830268d99f..f0e55623f35f6 100644 --- a/src/analysis/calculus/cont_diff.lean +++ b/src/analysis/calculus/cont_diff.lean @@ -174,7 +174,7 @@ variables {𝕜 : Type*} [nondiscrete_normed_field 𝕜] {F : Type*} [normed_group F] [normed_space 𝕜 F] {G : Type*} [normed_group G] [normed_space 𝕜 G] {s s₁ t u : set E} {f f₁ : E → F} {g : F → G} {x : E} {c : F} -{b : E × F → G} +{b : E × F → G} {m n : with_top ℕ} /-! ### Functions with a Taylor series on a domain -/ @@ -190,14 +190,14 @@ structure has_ftaylor_series_up_to_on (n : with_top ℕ) has_fderiv_within_at (λ y, p y m) (p x m.succ).curry_left s x) (cont : ∀ (m : ℕ) (hm : (m : with_top ℕ) ≤ n), continuous_on (λ x, p x m) s) -lemma has_ftaylor_series_up_to_on.zero_eq' {n : with_top ℕ} +lemma has_ftaylor_series_up_to_on.zero_eq' (h : has_ftaylor_series_up_to_on n f p s) {x : E} (hx : x ∈ s) : p x 0 = (continuous_multilinear_curry_fin0 𝕜 E F).symm (f x) := by { rw ← h.zero_eq x hx, symmetry, exact continuous_multilinear_map.uncurry0_curry0 _ } /-- If two functions coincide on a set `s`, then a Taylor series for the first one is as well a Taylor series for the second one. -/ -lemma has_ftaylor_series_up_to_on.congr {n : with_top ℕ} +lemma has_ftaylor_series_up_to_on.congr (h : has_ftaylor_series_up_to_on n f p s) (h₁ : ∀ x ∈ s, f₁ x = f x) : has_ftaylor_series_up_to_on n f₁ p s := begin @@ -206,21 +206,21 @@ begin exact h.zero_eq x hx end -lemma has_ftaylor_series_up_to_on.mono {n : with_top ℕ} +lemma has_ftaylor_series_up_to_on.mono (h : has_ftaylor_series_up_to_on n f p s) {t : set E} (hst : t ⊆ s) : has_ftaylor_series_up_to_on n f p t := ⟨λ x hx, h.zero_eq x (hst hx), λ m hm x hx, (h.fderiv_within m hm x (hst hx)).mono hst, λ m hm, (h.cont m hm).mono hst⟩ -lemma has_ftaylor_series_up_to_on.of_le {m n : with_top ℕ} +lemma has_ftaylor_series_up_to_on.of_le (h : has_ftaylor_series_up_to_on n f p s) (hmn : m ≤ n) : has_ftaylor_series_up_to_on m f p s := ⟨h.zero_eq, λ k hk x hx, h.fderiv_within k (lt_of_lt_of_le hk hmn) x hx, λ k hk, h.cont k (le_trans hk hmn)⟩ -lemma has_ftaylor_series_up_to_on.continuous_on {n : with_top ℕ} +lemma has_ftaylor_series_up_to_on.continuous_on (h : has_ftaylor_series_up_to_on n f p s) : continuous_on f s := begin have := (h.cont 0 bot_le).congr (λ x hx, (h.zero_eq' hx).symm), @@ -256,7 +256,7 @@ end /-- If a function has a Taylor series at order at least `1`, then the term of order `1` of this series is a derivative of `f`. -/ -lemma has_ftaylor_series_up_to_on.has_fderiv_within_at {n : with_top ℕ} +lemma has_ftaylor_series_up_to_on.has_fderiv_within_at (h : has_ftaylor_series_up_to_on n f p s) (hn : 1 ≤ n) (hx : x ∈ s) : has_fderiv_within_at f (continuous_multilinear_curry_fin1 𝕜 E F (p x 1)) s x := begin @@ -278,27 +278,27 @@ begin refl end -lemma has_ftaylor_series_up_to_on.differentiable_on {n : with_top ℕ} +lemma has_ftaylor_series_up_to_on.differentiable_on (h : has_ftaylor_series_up_to_on n f p s) (hn : 1 ≤ n) : differentiable_on 𝕜 f s := λ x hx, (h.has_fderiv_within_at hn hx).differentiable_within_at /-- If a function has a Taylor series at order at least `1` on a neighborhood of `x`, then the term of order `1` of this series is a derivative of `f` at `x`. -/ -lemma has_ftaylor_series_up_to_on.has_fderiv_at {n : with_top ℕ} +lemma has_ftaylor_series_up_to_on.has_fderiv_at (h : has_ftaylor_series_up_to_on n f p s) (hn : 1 ≤ n) (hx : s ∈ 𝓝 x) : has_fderiv_at f (continuous_multilinear_curry_fin1 𝕜 E F (p x 1)) x := (h.has_fderiv_within_at hn (mem_of_mem_nhds hx)).has_fderiv_at hx /-- If a function has a Taylor series at order at least `1` on a neighborhood of `x`, then in a neighborhood of `x`, the term of order `1` of this series is a derivative of `f`. -/ -lemma has_ftaylor_series_up_to_on.eventually_has_fderiv_at {n : with_top ℕ} +lemma has_ftaylor_series_up_to_on.eventually_has_fderiv_at (h : has_ftaylor_series_up_to_on n f p s) (hn : 1 ≤ n) (hx : s ∈ 𝓝 x) : ∀ᶠ y in 𝓝 x, has_fderiv_at f (continuous_multilinear_curry_fin1 𝕜 E F (p y 1)) y := (eventually_eventually_nhds.2 hx).mono $ λ y hy, h.has_fderiv_at hn hy /-- If a function has a Taylor series at order at least `1` on a neighborhood of `x`, then it is differentiable at `x`. -/ -lemma has_ftaylor_series_up_to_on.differentiable_at {n : with_top ℕ} +lemma has_ftaylor_series_up_to_on.differentiable_at (h : has_ftaylor_series_up_to_on n f p s) (hn : 1 ≤ n) (hx : s ∈ 𝓝 x) : differentiable_at 𝕜 f x := (h.has_fderiv_at hn hx).differentiable_at @@ -422,12 +422,12 @@ lemma cont_diff_within_at_nat {n : ℕ} : has_ftaylor_series_up_to_on n f p u := ⟨λ H, H n le_rfl, λ ⟨u, hu, p, hp⟩ m hm, ⟨u, hu, p, hp.of_le hm⟩⟩ -lemma cont_diff_within_at.of_le {m n : with_top ℕ} +lemma cont_diff_within_at.of_le (h : cont_diff_within_at 𝕜 n f s x) (hmn : m ≤ n) : cont_diff_within_at 𝕜 m f s x := λ k hk, h k (le_trans hk hmn) -lemma cont_diff_within_at_iff_forall_nat_le {n : with_top ℕ} : +lemma cont_diff_within_at_iff_forall_nat_le : cont_diff_within_at 𝕜 n f s x ↔ ∀ m : ℕ, ↑m ≤ n → cont_diff_within_at 𝕜 m f s x := ⟨λ H m hm, H.of_le hm, λ H m hm, H m hm _ le_rfl⟩ @@ -435,7 +435,7 @@ lemma cont_diff_within_at_top : cont_diff_within_at 𝕜 ∞ f s x ↔ ∀ (n : ℕ), cont_diff_within_at 𝕜 n f s x := cont_diff_within_at_iff_forall_nat_le.trans $ by simp only [forall_prop_of_true, le_top] -lemma cont_diff_within_at.continuous_within_at {n : with_top ℕ} +lemma cont_diff_within_at.continuous_within_at (h : cont_diff_within_at 𝕜 n f s x) : continuous_within_at f s x := begin rcases h 0 bot_le with ⟨u, hu, p, H⟩, @@ -443,35 +443,35 @@ begin exact (H.continuous_on.continuous_within_at hu.1).mono_of_mem hu.2 end -lemma cont_diff_within_at.congr_of_eventually_eq {n : with_top ℕ} +lemma cont_diff_within_at.congr_of_eventually_eq (h : cont_diff_within_at 𝕜 n f s x) (h₁ : f₁ =ᶠ[𝓝[s] x] f) (hx : f₁ x = f x) : cont_diff_within_at 𝕜 n f₁ s x := λ m hm, let ⟨u, hu, p, H⟩ := h m hm in ⟨{x ∈ u | f₁ x = f x}, filter.inter_mem hu (mem_nhds_within_insert.2 ⟨hx, h₁⟩), p, (H.mono (sep_subset _ _)).congr (λ _, and.right)⟩ -lemma cont_diff_within_at.congr_of_eventually_eq' {n : with_top ℕ} +lemma cont_diff_within_at.congr_of_eventually_eq' (h : cont_diff_within_at 𝕜 n f s x) (h₁ : f₁ =ᶠ[𝓝[s] x] f) (hx : x ∈ s) : cont_diff_within_at 𝕜 n f₁ s x := h.congr_of_eventually_eq h₁ $ h₁.self_of_nhds_within hx -lemma filter.eventually_eq.cont_diff_within_at_iff {n : with_top ℕ} +lemma filter.eventually_eq.cont_diff_within_at_iff (h₁ : f₁ =ᶠ[𝓝[s] x] f) (hx : f₁ x = f x) : cont_diff_within_at 𝕜 n f₁ s x ↔ cont_diff_within_at 𝕜 n f s x := ⟨λ H, cont_diff_within_at.congr_of_eventually_eq H h₁.symm hx.symm, λ H, H.congr_of_eventually_eq h₁ hx⟩ -lemma cont_diff_within_at.congr {n : with_top ℕ} +lemma cont_diff_within_at.congr (h : cont_diff_within_at 𝕜 n f s x) (h₁ : ∀ y ∈ s, f₁ y = f y) (hx : f₁ x = f x) : cont_diff_within_at 𝕜 n f₁ s x := h.congr_of_eventually_eq (filter.eventually_eq_of_mem self_mem_nhds_within h₁) hx -lemma cont_diff_within_at.congr' {n : with_top ℕ} +lemma cont_diff_within_at.congr' (h : cont_diff_within_at 𝕜 n f s x) (h₁ : ∀ y ∈ s, f₁ y = f y) (hx : x ∈ s) : cont_diff_within_at 𝕜 n f₁ s x := h.congr h₁ (h₁ _ hx) -lemma cont_diff_within_at.mono_of_mem {n : with_top ℕ} +lemma cont_diff_within_at.mono_of_mem (h : cont_diff_within_at 𝕜 n f s x) {t : set E} (hst : s ∈ 𝓝[t] x) : cont_diff_within_at 𝕜 n f t x := begin @@ -480,31 +480,31 @@ begin exact ⟨u, nhds_within_le_of_mem (insert_mem_nhds_within_insert hst) hu, p, H⟩ end -lemma cont_diff_within_at.mono {n : with_top ℕ} +lemma cont_diff_within_at.mono (h : cont_diff_within_at 𝕜 n f s x) {t : set E} (hst : t ⊆ s) : cont_diff_within_at 𝕜 n f t x := h.mono_of_mem $ filter.mem_of_superset self_mem_nhds_within hst -lemma cont_diff_within_at.congr_nhds {n : with_top ℕ} +lemma cont_diff_within_at.congr_nhds (h : cont_diff_within_at 𝕜 n f s x) {t : set E} (hst : 𝓝[s] x = 𝓝[t] x) : cont_diff_within_at 𝕜 n f t x := h.mono_of_mem $ hst ▸ self_mem_nhds_within -lemma cont_diff_within_at_congr_nhds {n : with_top ℕ} {t : set E} (hst : 𝓝[s] x = 𝓝[t] x) : +lemma cont_diff_within_at_congr_nhds {t : set E} (hst : 𝓝[s] x = 𝓝[t] x) : cont_diff_within_at 𝕜 n f s x ↔ cont_diff_within_at 𝕜 n f t x := ⟨λ h, h.congr_nhds hst, λ h, h.congr_nhds hst.symm⟩ -lemma cont_diff_within_at_inter' {n : with_top ℕ} (h : t ∈ 𝓝[s] x) : +lemma cont_diff_within_at_inter' (h : t ∈ 𝓝[s] x) : cont_diff_within_at 𝕜 n f (s ∩ t) x ↔ cont_diff_within_at 𝕜 n f s x := cont_diff_within_at_congr_nhds $ eq.symm $ nhds_within_restrict'' _ h -lemma cont_diff_within_at_inter {n : with_top ℕ} (h : t ∈ 𝓝 x) : +lemma cont_diff_within_at_inter (h : t ∈ 𝓝 x) : cont_diff_within_at 𝕜 n f (s ∩ t) x ↔ cont_diff_within_at 𝕜 n f s x := cont_diff_within_at_inter' (mem_nhds_within_of_mem_nhds h) /-- If a function is `C^n` within a set at a point, with `n ≥ 1`, then it is differentiable within this set at this point. -/ -lemma cont_diff_within_at.differentiable_within_at' {n : with_top ℕ} +lemma cont_diff_within_at.differentiable_within_at' (h : cont_diff_within_at 𝕜 n f s x) (hn : 1 ≤ n) : differentiable_within_at 𝕜 f (insert x s) x := begin @@ -515,7 +515,7 @@ begin exact (differentiable_within_at_inter (is_open.mem_nhds t_open xt)).1 this, end -lemma cont_diff_within_at.differentiable_within_at {n : with_top ℕ} +lemma cont_diff_within_at.differentiable_within_at (h : cont_diff_within_at 𝕜 n f s x) (hn : 1 ≤ n) : differentiable_within_at 𝕜 f s x := (h.differentiable_within_at' hn).mono (subset_insert x s) @@ -582,12 +582,11 @@ definition cont_diff_on (n : with_top ℕ) (f : E → F) (s : set E) := variable {𝕜} -lemma cont_diff_on.cont_diff_within_at {n : with_top ℕ} - (h : cont_diff_on 𝕜 n f s) (hx : x ∈ s) : +lemma cont_diff_on.cont_diff_within_at (h : cont_diff_on 𝕜 n f s) (hx : x ∈ s) : cont_diff_within_at 𝕜 n f s x := h x hx -lemma cont_diff_within_at.cont_diff_on {n : with_top ℕ} {m : ℕ} +lemma cont_diff_within_at.cont_diff_on {m : ℕ} (hm : (m : with_top ℕ) ≤ n) (h : cont_diff_within_at 𝕜 n f s x) : ∃ u ∈ 𝓝[insert x s] x, u ⊆ insert x s ∧ cont_diff_on 𝕜 m f u := begin @@ -611,12 +610,11 @@ begin exact nhds_within_mono y (subset_insert _ _) hy.1 end -lemma cont_diff_on.of_le {m n : with_top ℕ} - (h : cont_diff_on 𝕜 n f s) (hmn : m ≤ n) : +lemma cont_diff_on.of_le (h : cont_diff_on 𝕜 n f s) (hmn : m ≤ n) : cont_diff_on 𝕜 m f s := λ x hx, (h x hx).of_le hmn -lemma cont_diff_on_iff_forall_nat_le {n : with_top ℕ} : +lemma cont_diff_on_iff_forall_nat_le : cont_diff_on 𝕜 n f s ↔ ∀ m : ℕ, ↑m ≤ n → cont_diff_on 𝕜 m f s := ⟨λ H m hm, H.of_le hm, λ H x hx m hm, H m hm x hx m le_rfl⟩ @@ -632,36 +630,36 @@ begin exacts [cont_diff_on_top.2 H, H n] end -lemma cont_diff_on.continuous_on {n : with_top ℕ} +lemma cont_diff_on.continuous_on (h : cont_diff_on 𝕜 n f s) : continuous_on f s := λ x hx, (h x hx).continuous_within_at -lemma cont_diff_on.congr {n : with_top ℕ} +lemma cont_diff_on.congr (h : cont_diff_on 𝕜 n f s) (h₁ : ∀ x ∈ s, f₁ x = f x) : cont_diff_on 𝕜 n f₁ s := λ x hx, (h x hx).congr h₁ (h₁ x hx) -lemma cont_diff_on_congr {n : with_top ℕ} (h₁ : ∀ x ∈ s, f₁ x = f x) : +lemma cont_diff_on_congr (h₁ : ∀ x ∈ s, f₁ x = f x) : cont_diff_on 𝕜 n f₁ s ↔ cont_diff_on 𝕜 n f s := ⟨λ H, H.congr (λ x hx, (h₁ x hx).symm), λ H, H.congr h₁⟩ -lemma cont_diff_on.mono {n : with_top ℕ} +lemma cont_diff_on.mono (h : cont_diff_on 𝕜 n f s) {t : set E} (hst : t ⊆ s) : cont_diff_on 𝕜 n f t := λ x hx, (h x (hst hx)).mono hst -lemma cont_diff_on.congr_mono {n : with_top ℕ} +lemma cont_diff_on.congr_mono (hf : cont_diff_on 𝕜 n f s) (h₁ : ∀ x ∈ s₁, f₁ x = f x) (hs : s₁ ⊆ s) : cont_diff_on 𝕜 n f₁ s₁ := (hf.mono hs).congr h₁ /-- If a function is `C^n` on a set with `n ≥ 1`, then it is differentiable there. -/ -lemma cont_diff_on.differentiable_on {n : with_top ℕ} +lemma cont_diff_on.differentiable_on (h : cont_diff_on 𝕜 n f s) (hn : 1 ≤ n) : differentiable_on 𝕜 f s := λ x hx, (h x hx).differentiable_within_at hn /-- If a function is `C^n` around each point in a set, then it is `C^n` on the set. -/ -lemma cont_diff_on_of_locally_cont_diff_on {n : with_top ℕ} +lemma cont_diff_on_of_locally_cont_diff_on (h : ∀ x ∈ s, ∃u, is_open u ∧ x ∈ u ∧ cont_diff_on 𝕜 n f (s ∩ u)) : cont_diff_on 𝕜 n f s := begin @@ -869,7 +867,7 @@ end /-- On a set with unique differentiability, any choice of iterated differential has to coincide with the one we have chosen in `iterated_fderiv_within 𝕜 m f s`. -/ -theorem has_ftaylor_series_up_to_on.eq_ftaylor_series_of_unique_diff_on {n : with_top ℕ} +theorem has_ftaylor_series_up_to_on.eq_ftaylor_series_of_unique_diff_on (h : has_ftaylor_series_up_to_on n f p s) {m : ℕ} (hmn : (m : with_top ℕ) ≤ n) (hs : unique_diff_on 𝕜 s) (hx : x ∈ s) : p x m = iterated_fderiv_within 𝕜 m f s x := @@ -887,7 +885,7 @@ end /-- When a function is `C^n` in a set `s` of unique differentiability, it admits `ftaylor_series_within 𝕜 f s` as a Taylor series up to order `n` in `s`. -/ -theorem cont_diff_on.ftaylor_series_within {n : with_top ℕ} +theorem cont_diff_on.ftaylor_series_within (h : cont_diff_on 𝕜 n f s) (hs : unique_diff_on 𝕜 s) : has_ftaylor_series_up_to_on n f (ftaylor_series_within 𝕜 f s) s := begin @@ -931,7 +929,7 @@ begin exact ((Hp.mono ho).cont m le_rfl).congr (λ y hy, (A y hy).symm) } end -lemma cont_diff_on_of_continuous_on_differentiable_on {n : with_top ℕ} +lemma cont_diff_on_of_continuous_on_differentiable_on (Hcont : ∀ (m : ℕ), (m : with_top ℕ) ≤ n → continuous_on (λ x, iterated_fderiv_within 𝕜 m f s x) s) (Hdiff : ∀ (m : ℕ), (m : with_top ℕ) < n → @@ -954,23 +952,23 @@ begin exact Hcont k (le_trans hk hm) } end -lemma cont_diff_on_of_differentiable_on {n : with_top ℕ} +lemma cont_diff_on_of_differentiable_on (h : ∀(m : ℕ), (m : with_top ℕ) ≤ n → differentiable_on 𝕜 (iterated_fderiv_within 𝕜 m f s) s) : cont_diff_on 𝕜 n f s := cont_diff_on_of_continuous_on_differentiable_on (λ m hm, (h m hm).continuous_on) (λ m hm, (h m (le_of_lt hm))) -lemma cont_diff_on.continuous_on_iterated_fderiv_within {n : with_top ℕ} {m : ℕ} +lemma cont_diff_on.continuous_on_iterated_fderiv_within {m : ℕ} (h : cont_diff_on 𝕜 n f s) (hmn : (m : with_top ℕ) ≤ n) (hs : unique_diff_on 𝕜 s) : continuous_on (iterated_fderiv_within 𝕜 m f s) s := (h.ftaylor_series_within hs).cont m hmn -lemma cont_diff_on.differentiable_on_iterated_fderiv_within {n : with_top ℕ} {m : ℕ} +lemma cont_diff_on.differentiable_on_iterated_fderiv_within {m : ℕ} (h : cont_diff_on 𝕜 n f s) (hmn : (m : with_top ℕ) < n) (hs : unique_diff_on 𝕜 s) : differentiable_on 𝕜 (iterated_fderiv_within 𝕜 m f s) s := λ x hx, ((h.ftaylor_series_within hs).fderiv_within m hmn x hx).differentiable_within_at -lemma cont_diff_on_iff_continuous_on_differentiable_on {n : with_top ℕ} +lemma cont_diff_on_iff_continuous_on_differentiable_on (hs : unique_diff_on 𝕜 s) : cont_diff_on 𝕜 n f s ↔ (∀ (m : ℕ), (m : with_top ℕ) ≤ n → @@ -1062,7 +1060,7 @@ begin exact fderiv_within_of_open hs hx end -lemma cont_diff_on.fderiv_within {m n : with_top ℕ} +lemma cont_diff_on.fderiv_within (hf : cont_diff_on 𝕜 n f s) (hs : unique_diff_on 𝕜 s) (hmn : m + 1 ≤ n) : cont_diff_on 𝕜 m (λ y, fderiv_within 𝕜 f s y) s := begin @@ -1075,17 +1073,17 @@ begin exact ((cont_diff_on_succ_iff_fderiv_within hs).1 (hf.of_le hmn)).2 } end -lemma cont_diff_on.fderiv_of_open {m n : with_top ℕ} +lemma cont_diff_on.fderiv_of_open (hf : cont_diff_on 𝕜 n f s) (hs : is_open s) (hmn : m + 1 ≤ n) : cont_diff_on 𝕜 m (λ y, fderiv 𝕜 f y) s := (hf.fderiv_within hs.unique_diff_on hmn).congr (λ x hx, (fderiv_within_of_open hs hx).symm) -lemma cont_diff_on.continuous_on_fderiv_within {n : with_top ℕ} +lemma cont_diff_on.continuous_on_fderiv_within (h : cont_diff_on 𝕜 n f s) (hs : unique_diff_on 𝕜 s) (hn : 1 ≤ n) : continuous_on (λ x, fderiv_within 𝕜 f s x) s := ((cont_diff_on_succ_iff_fderiv_within hs).1 (h.of_le hn)).2.continuous_on -lemma cont_diff_on.continuous_on_fderiv_of_open {n : with_top ℕ} +lemma cont_diff_on.continuous_on_fderiv_of_open (h : cont_diff_on 𝕜 n f s) (hs : is_open s) (hn : 1 ≤ n) : continuous_on (λ x, fderiv 𝕜 f x) s := ((cont_diff_on_succ_iff_fderiv_of_open hs).1 (h.of_le hn)).2.continuous_on @@ -1093,7 +1091,7 @@ lemma cont_diff_on.continuous_on_fderiv_of_open {n : with_top ℕ} /-- If a function is at least `C^1`, its bundled derivative (mapping `(x, v)` to `Df(x) v`) is continuous. -/ lemma cont_diff_on.continuous_on_fderiv_within_apply - {n : with_top ℕ} (h : cont_diff_on 𝕜 n f s) (hs : unique_diff_on 𝕜 s) (hn : 1 ≤ n) : + (h : cont_diff_on 𝕜 n f s) (hs : unique_diff_on 𝕜 s) (hn : 1 ≤ n) : continuous_on (λp : E × E, (fderiv_within 𝕜 f s p.1 : E → F) p.2) (s ×ˢ (univ : set E)) := begin have A : continuous (λq : (E →L[𝕜] F) × E, q.1 q.2) := is_bounded_bilinear_map_apply.continuous, @@ -1116,12 +1114,12 @@ structure has_ftaylor_series_up_to (n : with_top ℕ) has_fderiv_at (λ y, p y m) (p x m.succ).curry_left x) (cont : ∀ (m : ℕ) (hm : (m : with_top ℕ) ≤ n), continuous (λ x, p x m)) -lemma has_ftaylor_series_up_to.zero_eq' {n : with_top ℕ} +lemma has_ftaylor_series_up_to.zero_eq' (h : has_ftaylor_series_up_to n f p) (x : E) : p x 0 = (continuous_multilinear_curry_fin0 𝕜 E F).symm (f x) := by { rw ← h.zero_eq x, symmetry, exact continuous_multilinear_map.uncurry0_curry0 _ } -lemma has_ftaylor_series_up_to_on_univ_iff {n : with_top ℕ} : +lemma has_ftaylor_series_up_to_on_univ_iff : has_ftaylor_series_up_to_on n f p univ ↔ has_ftaylor_series_up_to n f p := begin split, @@ -1145,17 +1143,17 @@ begin exact H.cont m hm } } end -lemma has_ftaylor_series_up_to.has_ftaylor_series_up_to_on {n : with_top ℕ} +lemma has_ftaylor_series_up_to.has_ftaylor_series_up_to_on (h : has_ftaylor_series_up_to n f p) (s : set E) : has_ftaylor_series_up_to_on n f p s := (has_ftaylor_series_up_to_on_univ_iff.2 h).mono (subset_univ _) -lemma has_ftaylor_series_up_to.of_le {m n : with_top ℕ} +lemma has_ftaylor_series_up_to.of_le (h : has_ftaylor_series_up_to n f p) (hmn : m ≤ n) : has_ftaylor_series_up_to m f p := by { rw ← has_ftaylor_series_up_to_on_univ_iff at h ⊢, exact h.of_le hmn } -lemma has_ftaylor_series_up_to.continuous {n : with_top ℕ} +lemma has_ftaylor_series_up_to.continuous (h : has_ftaylor_series_up_to n f p) : continuous f := begin rw ← has_ftaylor_series_up_to_on_univ_iff at h, @@ -1170,7 +1168,7 @@ by simp [has_ftaylor_series_up_to_on_univ_iff.symm, continuous_iff_continuous_on /-- If a function has a Taylor series at order at least `1`, then the term of order `1` of this series is a derivative of `f`. -/ -lemma has_ftaylor_series_up_to.has_fderiv_at {n : with_top ℕ} +lemma has_ftaylor_series_up_to.has_fderiv_at (h : has_ftaylor_series_up_to n f p) (hn : 1 ≤ n) (x : E) : has_fderiv_at f (continuous_multilinear_curry_fin1 𝕜 E F (p x 1)) x := begin @@ -1178,7 +1176,7 @@ begin exact (has_ftaylor_series_up_to_on_univ_iff.2 h).has_fderiv_within_at hn (mem_univ _) end -lemma has_ftaylor_series_up_to.differentiable {n : with_top ℕ} +lemma has_ftaylor_series_up_to.differentiable (h : has_ftaylor_series_up_to n f p) (hn : 1 ≤ n) : differentiable 𝕜 f := λ x, (h.has_fderiv_at hn x).differentiable_at @@ -1205,7 +1203,7 @@ cont_diff_within_at 𝕜 n f univ x variable {𝕜} -theorem cont_diff_within_at_univ {n : with_top ℕ} : +theorem cont_diff_within_at_univ : cont_diff_within_at 𝕜 n f univ x ↔ cont_diff_at 𝕜 n f x := iff.rfl @@ -1213,31 +1211,31 @@ lemma cont_diff_at_top : cont_diff_at 𝕜 ∞ f x ↔ ∀ (n : ℕ), cont_diff_at 𝕜 n f x := by simp [← cont_diff_within_at_univ, cont_diff_within_at_top] -lemma cont_diff_at.cont_diff_within_at {n : with_top ℕ} +lemma cont_diff_at.cont_diff_within_at (h : cont_diff_at 𝕜 n f x) : cont_diff_within_at 𝕜 n f s x := h.mono (subset_univ _) -lemma cont_diff_within_at.cont_diff_at {n : with_top ℕ} +lemma cont_diff_within_at.cont_diff_at (h : cont_diff_within_at 𝕜 n f s x) (hx : s ∈ 𝓝 x) : cont_diff_at 𝕜 n f x := by rwa [cont_diff_at, ← cont_diff_within_at_inter hx, univ_inter] -lemma cont_diff_at.congr_of_eventually_eq {n : with_top ℕ} +lemma cont_diff_at.congr_of_eventually_eq (h : cont_diff_at 𝕜 n f x) (hg : f₁ =ᶠ[𝓝 x] f) : cont_diff_at 𝕜 n f₁ x := h.congr_of_eventually_eq' (by rwa nhds_within_univ) (mem_univ x) -lemma cont_diff_at.of_le {m n : with_top ℕ} +lemma cont_diff_at.of_le (h : cont_diff_at 𝕜 n f x) (hmn : m ≤ n) : cont_diff_at 𝕜 m f x := h.of_le hmn -lemma cont_diff_at.continuous_at {n : with_top ℕ} +lemma cont_diff_at.continuous_at (h : cont_diff_at 𝕜 n f x) : continuous_at f x := by simpa [continuous_within_at_univ] using h.continuous_within_at /-- If a function is `C^n` with `n ≥ 1` at a point, then it is differentiable there. -/ -lemma cont_diff_at.differentiable_at {n : with_top ℕ} +lemma cont_diff_at.differentiable_at (h : cont_diff_at 𝕜 n f x) (hn : 1 ≤ n) : differentiable_at 𝕜 f x := by simpa [hn, differentiable_within_at_univ] using h.differentiable_within_at @@ -1280,7 +1278,7 @@ definition cont_diff (n : with_top ℕ) (f : E → F) := variable {𝕜} -theorem cont_diff_on_univ {n : with_top ℕ} : +theorem cont_diff_on_univ : cont_diff_on 𝕜 n f univ ↔ cont_diff 𝕜 n f := begin split, @@ -1292,15 +1290,15 @@ begin exact ⟨univ, filter.univ_sets _, p, (hp.has_ftaylor_series_up_to_on univ).of_le hm⟩ } end -lemma cont_diff_iff_cont_diff_at {n : with_top ℕ} : +lemma cont_diff_iff_cont_diff_at : cont_diff 𝕜 n f ↔ ∀ x, cont_diff_at 𝕜 n f x := by simp [← cont_diff_on_univ, cont_diff_on, cont_diff_at] -lemma cont_diff.cont_diff_at {n : with_top ℕ} (h : cont_diff 𝕜 n f) : +lemma cont_diff.cont_diff_at (h : cont_diff 𝕜 n f) : cont_diff_at 𝕜 n f x := cont_diff_iff_cont_diff_at.1 h x -lemma cont_diff.cont_diff_within_at {n : with_top ℕ} (h : cont_diff 𝕜 n f) : +lemma cont_diff.cont_diff_within_at (h : cont_diff 𝕜 n f) : cont_diff_within_at 𝕜 n f s x := h.cont_diff_at.cont_diff_within_at @@ -1312,7 +1310,7 @@ lemma cont_diff_all_iff_nat : (∀ n, cont_diff 𝕜 n f) ↔ (∀ n : ℕ, cont_diff 𝕜 n f) := by simp only [← cont_diff_on_univ, cont_diff_on_all_iff_nat] -lemma cont_diff.cont_diff_on {n : with_top ℕ} +lemma cont_diff.cont_diff_on (h : cont_diff 𝕜 n f) : cont_diff_on 𝕜 n f s := (cont_diff_on_univ.2 h).mono (subset_univ _) @@ -1333,17 +1331,17 @@ by simp_rw [show (1 : with_top ℕ) = (0 + 1 : ℕ), from (zero_add 1).symm, cont_diff_at_succ_iff_has_fderiv_at, show ((0 : ℕ) : with_top ℕ) = 0, from rfl, cont_diff_at_zero, exists_mem_and_iff antitone_bforall antitone_continuous_on, and_comm] -lemma cont_diff.of_le {m n : with_top ℕ} +lemma cont_diff.of_le (h : cont_diff 𝕜 n f) (hmn : m ≤ n) : cont_diff 𝕜 m f := cont_diff_on_univ.1 $ (cont_diff_on_univ.2 h).of_le hmn -lemma cont_diff.continuous {n : with_top ℕ} +lemma cont_diff.continuous (h : cont_diff 𝕜 n f) : continuous f := cont_diff_zero.1 (h.of_le bot_le) /-- If a function is `C^n` with `n ≥ 1`, then it is differentiable. -/ -lemma cont_diff.differentiable {n : with_top ℕ} +lemma cont_diff.differentiable (h : cont_diff 𝕜 n f) (hn : 1 ≤ n) : differentiable 𝕜 f := differentiable_on_univ.1 $ (cont_diff_on_univ.2 h).differentiable_on hn @@ -1442,7 +1440,7 @@ by { rw [iterated_fderiv_succ_apply_right, iterated_fderiv_zero_apply], refl } /-- When a function is `C^n` in a set `s` of unique differentiability, it admits `ftaylor_series_within 𝕜 f s` as a Taylor series up to order `n` in `s`. -/ -theorem cont_diff_on_iff_ftaylor_series {n : with_top ℕ} : +theorem cont_diff_on_iff_ftaylor_series : cont_diff 𝕜 n f ↔ has_ftaylor_series_up_to n f (ftaylor_series 𝕜 f) := begin split, @@ -1452,7 +1450,7 @@ begin { assume h, exact ⟨ftaylor_series 𝕜 f, h⟩ } end -lemma cont_diff_iff_continuous_differentiable {n : with_top ℕ} : +lemma cont_diff_iff_continuous_differentiable : cont_diff 𝕜 n f ↔ (∀ (m : ℕ), (m : with_top ℕ) ≤ n → continuous (λ x, iterated_fderiv 𝕜 m f x)) ∧ (∀ (m : ℕ), (m : with_top ℕ) < n → differentiable 𝕜 (λ x, iterated_fderiv 𝕜 m f x)) := @@ -1460,7 +1458,7 @@ by simp [cont_diff_on_univ.symm, continuous_iff_continuous_on_univ, differentiable_on_univ.symm, iterated_fderiv_within_univ, cont_diff_on_iff_continuous_on_differentiable_on unique_diff_on_univ] -lemma cont_diff_of_differentiable_iterated_fderiv {n : with_top ℕ} +lemma cont_diff_of_differentiable_iterated_fderiv (h : ∀(m : ℕ), (m : with_top ℕ) ≤ n → differentiable 𝕜 (iterated_fderiv 𝕜 m f)) : cont_diff 𝕜 n f := cont_diff_iff_continuous_differentiable.2 @@ -1490,14 +1488,14 @@ begin rw cont_diff_on_top_iff_fderiv_within unique_diff_on_univ, end -lemma cont_diff.continuous_fderiv {n : with_top ℕ} +lemma cont_diff.continuous_fderiv (h : cont_diff 𝕜 n f) (hn : 1 ≤ n) : continuous (λ x, fderiv 𝕜 f x) := ((cont_diff_succ_iff_fderiv).1 (h.of_le hn)).2.continuous /-- If a function is at least `C^1`, its bundled derivative (mapping `(x, v)` to `Df(x) v`) is continuous. -/ -lemma cont_diff.continuous_fderiv_apply {n : with_top ℕ} +lemma cont_diff.continuous_fderiv_apply (h : cont_diff 𝕜 n f) (hn : 1 ≤ n) : continuous (λp : E × E, (fderiv 𝕜 f p.1 : E → F) p.2) := begin @@ -1522,7 +1520,7 @@ begin refl } end -lemma cont_diff_zero_fun {n : with_top ℕ} : +lemma cont_diff_zero_fun : cont_diff 𝕜 n (λ x : E, (0 : F)) := begin apply cont_diff_of_differentiable_iterated_fderiv (λm hm, _), @@ -1533,7 +1531,7 @@ end /-- Constants are `C^∞`. -/ -lemma cont_diff_const {n : with_top ℕ} {c : F} : cont_diff 𝕜 n (λx : E, c) := +lemma cont_diff_const {c : F} : cont_diff 𝕜 n (λx : E, c) := begin suffices h : cont_diff 𝕜 ∞ (λx : E, c), by exact h.of_le le_top, rw cont_diff_top_iff_fderiv, @@ -1542,40 +1540,40 @@ begin exact cont_diff_zero_fun end -lemma cont_diff_on_const {n : with_top ℕ} {c : F} {s : set E} : +lemma cont_diff_on_const {c : F} {s : set E} : cont_diff_on 𝕜 n (λx : E, c) s := cont_diff_const.cont_diff_on -lemma cont_diff_at_const {n : with_top ℕ} {c : F} : +lemma cont_diff_at_const {c : F} : cont_diff_at 𝕜 n (λx : E, c) x := cont_diff_const.cont_diff_at -lemma cont_diff_within_at_const {n : with_top ℕ} {c : F} : +lemma cont_diff_within_at_const {c : F} : cont_diff_within_at 𝕜 n (λx : E, c) s x := cont_diff_at_const.cont_diff_within_at -@[nontriviality] lemma cont_diff_of_subsingleton [subsingleton F] {n : with_top ℕ} : +@[nontriviality] lemma cont_diff_of_subsingleton [subsingleton F] : cont_diff 𝕜 n f := by { rw [subsingleton.elim f (λ _, 0)], exact cont_diff_const } -@[nontriviality] lemma cont_diff_at_of_subsingleton [subsingleton F] {n : with_top ℕ} : +@[nontriviality] lemma cont_diff_at_of_subsingleton [subsingleton F] : cont_diff_at 𝕜 n f x := by { rw [subsingleton.elim f (λ _, 0)], exact cont_diff_at_const } -@[nontriviality] lemma cont_diff_within_at_of_subsingleton [subsingleton F] {n : with_top ℕ} : +@[nontriviality] lemma cont_diff_within_at_of_subsingleton [subsingleton F] : cont_diff_within_at 𝕜 n f s x := by { rw [subsingleton.elim f (λ _, 0)], exact cont_diff_within_at_const } -@[nontriviality] lemma cont_diff_on_of_subsingleton [subsingleton F] {n : with_top ℕ} : +@[nontriviality] lemma cont_diff_on_of_subsingleton [subsingleton F] : cont_diff_on 𝕜 n f s := by { rw [subsingleton.elim f (λ _, 0)], exact cont_diff_on_const } -/-! ### Linear functions -/ +/-! ### Smoothness of linear functions -/ /-- Unbundled bounded linear functions are `C^∞`. -/ -lemma is_bounded_linear_map.cont_diff {n : with_top ℕ} (hf : is_bounded_linear_map 𝕜 f) : +lemma is_bounded_linear_map.cont_diff (hf : is_bounded_linear_map 𝕜 f) : cont_diff 𝕜 n f := begin suffices h : cont_diff 𝕜 ∞ f, by exact h.of_le le_top, @@ -1585,116 +1583,37 @@ begin exact cont_diff_const end -lemma continuous_linear_map.cont_diff {n : with_top ℕ} (f : E →L[𝕜] F) : - cont_diff 𝕜 n f := +lemma continuous_linear_map.cont_diff (f : E →L[𝕜] F) : cont_diff 𝕜 n f := f.is_bounded_linear_map.cont_diff -lemma continuous_linear_equiv.cont_diff {n : with_top ℕ} (f : E ≃L[𝕜] F) : - cont_diff 𝕜 n f := +lemma continuous_linear_equiv.cont_diff (f : E ≃L[𝕜] F) : cont_diff 𝕜 n f := (f : E →L[𝕜] F).cont_diff -lemma linear_isometry.cont_diff {n : with_top ℕ} (f : E →ₗᵢ[𝕜] F) : - cont_diff 𝕜 n f := +lemma linear_isometry.cont_diff (f : E →ₗᵢ[𝕜] F) : cont_diff 𝕜 n f := f.to_continuous_linear_map.cont_diff -lemma linear_isometry_equiv.cont_diff {n : with_top ℕ} (f : E ≃ₗᵢ[𝕜] F) : - cont_diff 𝕜 n f := +lemma linear_isometry_equiv.cont_diff (f : E ≃ₗᵢ[𝕜] F) : cont_diff 𝕜 n f := (f : E →L[𝕜] F).cont_diff -/-- -The first projection in a product is `C^∞`. --/ -lemma cont_diff_fst {n : with_top ℕ} : cont_diff 𝕜 n (prod.fst : E × F → E) := -is_bounded_linear_map.cont_diff is_bounded_linear_map.fst - -/-- -The first projection on a domain in a product is `C^∞`. --/ -lemma cont_diff_on_fst {s : set (E×F)} {n : with_top ℕ} : - cont_diff_on 𝕜 n (prod.fst : E × F → E) s := -cont_diff.cont_diff_on cont_diff_fst - -/-- -The first projection at a point in a product is `C^∞`. --/ -lemma cont_diff_at_fst {p : E × F} {n : with_top ℕ} : - cont_diff_at 𝕜 n (prod.fst : E × F → E) p := -cont_diff_fst.cont_diff_at - -/-- -The first projection within a domain at a point in a product is `C^∞`. --/ -lemma cont_diff_within_at_fst {s : set (E × F)} {p : E × F} {n : with_top ℕ} : - cont_diff_within_at 𝕜 n (prod.fst : E × F → E) s p := -cont_diff_fst.cont_diff_within_at - -/-- -The second projection in a product is `C^∞`. --/ -lemma cont_diff_snd {n : with_top ℕ} : cont_diff 𝕜 n (prod.snd : E × F → F) := -is_bounded_linear_map.cont_diff is_bounded_linear_map.snd - -/-- -The second projection on a domain in a product is `C^∞`. --/ -lemma cont_diff_on_snd {s : set (E×F)} {n : with_top ℕ} : - cont_diff_on 𝕜 n (prod.snd : E × F → F) s := -cont_diff.cont_diff_on cont_diff_snd - -/-- -The second projection at a point in a product is `C^∞`. --/ -lemma cont_diff_at_snd {p : E × F} {n : with_top ℕ} : - cont_diff_at 𝕜 n (prod.snd : E × F → F) p := -cont_diff_snd.cont_diff_at - -/-- -The second projection within a domain at a point in a product is `C^∞`. --/ -lemma cont_diff_within_at_snd {s : set (E × F)} {p : E × F} {n : with_top ℕ} : - cont_diff_within_at 𝕜 n (prod.snd : E × F → F) s p := -cont_diff_snd.cont_diff_within_at - -/-- -The natural equivalence `(E × F) × G ≃ E × (F × G)` is smooth. - -Warning: if you think you need this lemma, it is likely that you can simplify your proof by -reformulating the lemma that you're applying next using the tips in -Note [continuity lemma statement] --/ -lemma cont_diff_prod_assoc : cont_diff 𝕜 ⊤ $ equiv.prod_assoc E F G := -(linear_isometry_equiv.prod_assoc 𝕜 E F G).cont_diff - -/-- -The natural equivalence `E × (F × G) ≃ (E × F) × G` is smooth. - -Warning: see remarks attached to `cont_diff_prod_assoc` --/ -lemma cont_diff_prod_assoc_symm : cont_diff 𝕜 ⊤ $ (equiv.prod_assoc E F G).symm := -(linear_isometry_equiv.prod_assoc 𝕜 E F G).symm.cont_diff - /-- The identity is `C^∞`. -/ -lemma cont_diff_id {n : with_top ℕ} : cont_diff 𝕜 n (id : E → E) := +lemma cont_diff_id : cont_diff 𝕜 n (id : E → E) := is_bounded_linear_map.id.cont_diff -lemma cont_diff_within_at_id {n : with_top ℕ} {s x} : - cont_diff_within_at 𝕜 n (id : E → E) s x := +lemma cont_diff_within_at_id {s x} : cont_diff_within_at 𝕜 n (id : E → E) s x := cont_diff_id.cont_diff_within_at -lemma cont_diff_at_id {n : with_top ℕ} {x} : - cont_diff_at 𝕜 n (id : E → E) x := +lemma cont_diff_at_id {x} : cont_diff_at 𝕜 n (id : E → E) x := cont_diff_id.cont_diff_at -lemma cont_diff_on_id {n : with_top ℕ} {s} : - cont_diff_on 𝕜 n (id : E → E) s := +lemma cont_diff_on_id {s} : cont_diff_on 𝕜 n (id : E → E) s := cont_diff_id.cont_diff_on /-- Bilinear functions are `C^∞`. -/ -lemma is_bounded_bilinear_map.cont_diff {n : with_top ℕ} (hb : is_bounded_bilinear_map 𝕜 b) : +lemma is_bounded_bilinear_map.cont_diff (hb : is_bounded_bilinear_map 𝕜 b) : cont_diff 𝕜 n b := begin suffices h : cont_diff 𝕜 ∞ b, by exact h.of_le le_top, @@ -1706,7 +1625,7 @@ end /-- If `f` admits a Taylor series `p` in a set `s`, and `g` is linear, then `g ∘ f` admits a Taylor series whose `k`-th term is given by `g ∘ (p k)`. -/ -lemma has_ftaylor_series_up_to_on.continuous_linear_map_comp {n : with_top ℕ} (g : F →L[𝕜] G) +lemma has_ftaylor_series_up_to_on.continuous_linear_map_comp (g : F →L[𝕜] G) (hf : has_ftaylor_series_up_to_on n f p s) : has_ftaylor_series_up_to_on n (g ∘ f) (λ x k, g.comp_continuous_multilinear_map (p x k)) s := begin @@ -1722,7 +1641,7 @@ end /-- Composition by continuous linear maps on the left preserves `C^n` functions in a domain at a point. -/ -lemma cont_diff_within_at.continuous_linear_map_comp {n : with_top ℕ} (g : F →L[𝕜] G) +lemma cont_diff_within_at.continuous_linear_map_comp (g : F →L[𝕜] G) (hf : cont_diff_within_at 𝕜 n f s x) : cont_diff_within_at 𝕜 n (g ∘ f) s x := begin @@ -1733,19 +1652,19 @@ end /-- Composition by continuous linear maps on the left preserves `C^n` functions in a domain at a point. -/ -lemma cont_diff_at.continuous_linear_map_comp {n : with_top ℕ} (g : F →L[𝕜] G) +lemma cont_diff_at.continuous_linear_map_comp (g : F →L[𝕜] G) (hf : cont_diff_at 𝕜 n f x) : cont_diff_at 𝕜 n (g ∘ f) x := cont_diff_within_at.continuous_linear_map_comp g hf /-- Composition by continuous linear maps on the left preserves `C^n` functions on domains. -/ -lemma cont_diff_on.continuous_linear_map_comp {n : with_top ℕ} (g : F →L[𝕜] G) +lemma cont_diff_on.continuous_linear_map_comp (g : F →L[𝕜] G) (hf : cont_diff_on 𝕜 n f s) : cont_diff_on 𝕜 n (g ∘ f) s := λ x hx, (hf x hx).continuous_linear_map_comp g /-- Composition by continuous linear maps on the left preserves `C^n` functions. -/ -lemma cont_diff.continuous_linear_map_comp {n : with_top ℕ} {f : E → F} (g : F →L[𝕜] G) +lemma cont_diff.continuous_linear_map_comp {f : E → F} (g : F →L[𝕜] G) (hf : cont_diff 𝕜 n f) : cont_diff 𝕜 n (λx, g (f x)) := cont_diff_on_univ.1 $ cont_diff_on.continuous_linear_map_comp _ (cont_diff_on_univ.2 hf) @@ -1753,7 +1672,7 @@ cont_diff_on_univ.1 $ cont_diff_on.continuous_linear_map_comp /-- Composition by continuous linear equivs on the left respects higher differentiability on domains. -/ lemma continuous_linear_equiv.comp_cont_diff_within_at_iff - {n : with_top ℕ} (e : F ≃L[𝕜] G) : + (e : F ≃L[𝕜] G) : cont_diff_within_at 𝕜 n (e ∘ f) s x ↔ cont_diff_within_at 𝕜 n f s x := ⟨λ H, by simpa only [(∘), e.symm.coe_coe, e.symm_apply_apply] using H.continuous_linear_map_comp (e.symm : G →L[𝕜] F), @@ -1762,13 +1681,13 @@ lemma continuous_linear_equiv.comp_cont_diff_within_at_iff /-- Composition by continuous linear equivs on the left respects higher differentiability on domains. -/ lemma continuous_linear_equiv.comp_cont_diff_on_iff - {n : with_top ℕ} (e : F ≃L[𝕜] G) : + (e : F ≃L[𝕜] G) : cont_diff_on 𝕜 n (e ∘ f) s ↔ cont_diff_on 𝕜 n f s := by simp [cont_diff_on, e.comp_cont_diff_within_at_iff] /-- If `f` admits a Taylor series `p` in a set `s`, and `g` is linear, then `f ∘ g` admits a Taylor series in `g ⁻¹' s`, whose `k`-th term is given by `p k (g v₁, ..., g vₖ)` . -/ -lemma has_ftaylor_series_up_to_on.comp_continuous_linear_map {n : with_top ℕ} +lemma has_ftaylor_series_up_to_on.comp_continuous_linear_map (hf : has_ftaylor_series_up_to_on n f p s) (g : G →L[𝕜] E) : has_ftaylor_series_up_to_on n (f ∘ g) (λ x k, (p (g x) k).comp_continuous_linear_map (λ _, g)) (g ⁻¹' s) := @@ -1796,7 +1715,7 @@ end /-- Composition by continuous linear maps on the right preserves `C^n` functions at a point on a domain. -/ -lemma cont_diff_within_at.comp_continuous_linear_map {n : with_top ℕ} {x : G} +lemma cont_diff_within_at.comp_continuous_linear_map {x : G} (g : G →L[𝕜] E) (hf : cont_diff_within_at 𝕜 n f s (g x)) : cont_diff_within_at 𝕜 n (f ∘ g) (g ⁻¹' s) x := begin @@ -1811,20 +1730,20 @@ begin end /-- Composition by continuous linear maps on the right preserves `C^n` functions on domains. -/ -lemma cont_diff_on.comp_continuous_linear_map {n : with_top ℕ} +lemma cont_diff_on.comp_continuous_linear_map (hf : cont_diff_on 𝕜 n f s) (g : G →L[𝕜] E) : cont_diff_on 𝕜 n (f ∘ g) (g ⁻¹' s) := λ x hx, (hf (g x) hx).comp_continuous_linear_map g /-- Composition by continuous linear maps on the right preserves `C^n` functions. -/ -lemma cont_diff.comp_continuous_linear_map {n : with_top ℕ} {f : E → F} {g : G →L[𝕜] E} +lemma cont_diff.comp_continuous_linear_map {f : E → F} {g : G →L[𝕜] E} (hf : cont_diff 𝕜 n f) : cont_diff 𝕜 n (f ∘ g) := cont_diff_on_univ.1 $ cont_diff_on.comp_continuous_linear_map (cont_diff_on_univ.2 hf) _ /-- Composition by continuous linear equivs on the right respects higher differentiability at a point in a domain. -/ -lemma continuous_linear_equiv.cont_diff_within_at_comp_iff {n : with_top ℕ} (e : G ≃L[𝕜] E) : +lemma continuous_linear_equiv.cont_diff_within_at_comp_iff (e : G ≃L[𝕜] E) : cont_diff_within_at 𝕜 n (f ∘ e) (e ⁻¹' s) (e.symm x) ↔ cont_diff_within_at 𝕜 n f s x := begin @@ -1838,7 +1757,7 @@ end /-- Composition by continuous linear equivs on the right respects higher differentiability on domains. -/ -lemma continuous_linear_equiv.cont_diff_on_comp_iff {n : with_top ℕ} (e : G ≃L[𝕜] E) : +lemma continuous_linear_equiv.cont_diff_on_comp_iff (e : G ≃L[𝕜] E) : cont_diff_on 𝕜 n (f ∘ e) (e ⁻¹' s) ↔ cont_diff_on 𝕜 n f s := begin refine ⟨λ H, _, λ H, H.comp_continuous_linear_map (e : G →L[𝕜] E)⟩, @@ -1852,7 +1771,7 @@ end /-- If two functions `f` and `g` admit Taylor series `p` and `q` in a set `s`, then the cartesian product of `f` and `g` admits the cartesian product of `p` and `q` as a Taylor series. -/ -lemma has_ftaylor_series_up_to_on.prod {n : with_top ℕ} (hf : has_ftaylor_series_up_to_on n f p s) +lemma has_ftaylor_series_up_to_on.prod (hf : has_ftaylor_series_up_to_on n f p s) {g : E → G} {q : E → formal_multilinear_series 𝕜 E G} (hg : has_ftaylor_series_up_to_on n g q s) : has_ftaylor_series_up_to_on n (λ y, (f y, g y)) (λ y k, (p y k).prod (q y k)) s := begin @@ -1867,7 +1786,7 @@ begin end /-- The cartesian product of `C^n` functions at a point in a domain is `C^n`. -/ -lemma cont_diff_within_at.prod {n : with_top ℕ} {s : set E} {f : E → F} {g : E → G} +lemma cont_diff_within_at.prod {s : set E} {f : E → F} {g : E → G} (hf : cont_diff_within_at 𝕜 n f s x) (hg : cont_diff_within_at 𝕜 n g s x) : cont_diff_within_at 𝕜 n (λx:E, (f x, g x)) s x := begin @@ -1879,95 +1798,25 @@ begin end /-- The cartesian product of `C^n` functions on domains is `C^n`. -/ -lemma cont_diff_on.prod {n : with_top ℕ} {s : set E} {f : E → F} {g : E → G} +lemma cont_diff_on.prod {s : set E} {f : E → F} {g : E → G} (hf : cont_diff_on 𝕜 n f s) (hg : cont_diff_on 𝕜 n g s) : - cont_diff_on 𝕜 n (λx:E, (f x, g x)) s := + cont_diff_on 𝕜 n (λ x : E, (f x, g x)) s := λ x hx, (hf x hx).prod (hg x hx) /-- The cartesian product of `C^n` functions at a point is `C^n`. -/ -lemma cont_diff_at.prod {n : with_top ℕ} {f : E → F} {g : E → G} +lemma cont_diff_at.prod {f : E → F} {g : E → G} (hf : cont_diff_at 𝕜 n f x) (hg : cont_diff_at 𝕜 n g x) : - cont_diff_at 𝕜 n (λx:E, (f x, g x)) x := + cont_diff_at 𝕜 n (λ x : E, (f x, g x)) x := cont_diff_within_at_univ.1 $ cont_diff_within_at.prod (cont_diff_within_at_univ.2 hf) (cont_diff_within_at_univ.2 hg) -/-- -The cartesian product of `C^n` functions is `C^n`. --/ -lemma cont_diff.prod {n : with_top ℕ} {f : E → F} {g : E → G} - (hf : cont_diff 𝕜 n f) (hg : cont_diff 𝕜 n g) : - cont_diff 𝕜 n (λx:E, (f x, g x)) := +/-- The cartesian product of `C^n` functions is `C^n`.-/ +lemma cont_diff.prod {f : E → F} {g : E → G} (hf : cont_diff 𝕜 n f) (hg : cont_diff 𝕜 n g) : + cont_diff 𝕜 n (λ x : E, (f x, g x)) := cont_diff_on_univ.1 $ cont_diff_on.prod (cont_diff_on_univ.2 hf) (cont_diff_on_univ.2 hg) -/-! -### Smoothness of functions `f : E → Π i, F' i` --/ - -section pi - -variables {ι : Type*} [fintype ι] {F' : ι → Type*} [Π i, normed_group (F' i)] - [Π i, normed_space 𝕜 (F' i)] {φ : Π i, E → F' i} - {p' : Π i, E → formal_multilinear_series 𝕜 E (F' i)} - {Φ : E → Π i, F' i} {P' : E → formal_multilinear_series 𝕜 E (Π i, F' i)} - {n : with_top ℕ} - -lemma has_ftaylor_series_up_to_on_pi : - has_ftaylor_series_up_to_on n (λ x i, φ i x) - (λ x m, continuous_multilinear_map.pi (λ i, p' i x m)) s ↔ - ∀ i, has_ftaylor_series_up_to_on n (φ i) (p' i) s := -begin - set pr := @continuous_linear_map.proj 𝕜 _ ι F' _ _ _, - letI : Π (m : ℕ) (i : ι), normed_space 𝕜 (E [×m]→L[𝕜] (F' i)) := λ m i, infer_instance, - set L : Π m : ℕ, (Π i, E [×m]→L[𝕜] (F' i)) ≃ₗᵢ[𝕜] (E [×m]→L[𝕜] (Π i, F' i)) := - λ m, continuous_multilinear_map.piₗᵢ _ _, - refine ⟨λ h i, _, λ h, ⟨λ x hx, _, _, _⟩⟩, - { convert h.continuous_linear_map_comp (pr i), - ext, refl }, - { ext1 i, - exact (h i).zero_eq x hx }, - { intros m hm x hx, - have := has_fderiv_within_at_pi.2 (λ i, (h i).fderiv_within m hm x hx), - convert (L m).has_fderiv_at.comp_has_fderiv_within_at x this }, - { intros m hm, - have := continuous_on_pi.2 (λ i, (h i).cont m hm), - convert (L m).continuous.comp_continuous_on this } -end - -@[simp] lemma has_ftaylor_series_up_to_on_pi' : - has_ftaylor_series_up_to_on n Φ P' s ↔ - ∀ i, has_ftaylor_series_up_to_on n (λ x, Φ x i) - (λ x m, (@continuous_linear_map.proj 𝕜 _ ι F' _ _ _ i).comp_continuous_multilinear_map - (P' x m)) s := -by { convert has_ftaylor_series_up_to_on_pi, ext, refl } - -lemma cont_diff_within_at_pi : - cont_diff_within_at 𝕜 n Φ s x ↔ - ∀ i, cont_diff_within_at 𝕜 n (λ x, Φ x i) s x := -begin - set pr := @continuous_linear_map.proj 𝕜 _ ι F' _ _ _, - refine ⟨λ h i, h.continuous_linear_map_comp (pr i), λ h m hm, _⟩, - choose u hux p hp using λ i, h i m hm, - exact ⟨⋂ i, u i, filter.Inter_mem.2 hux, _, - has_ftaylor_series_up_to_on_pi.2 (λ i, (hp i).mono $ Inter_subset _ _)⟩, -end - -lemma cont_diff_on_pi : - cont_diff_on 𝕜 n Φ s ↔ ∀ i, cont_diff_on 𝕜 n (λ x, Φ x i) s := -⟨λ h i x hx, cont_diff_within_at_pi.1 (h x hx) _, - λ h x hx, cont_diff_within_at_pi.2 (λ i, h i x hx)⟩ - -lemma cont_diff_at_pi : - cont_diff_at 𝕜 n Φ x ↔ ∀ i, cont_diff_at 𝕜 n (λ x, Φ x i) x := -cont_diff_within_at_pi - -lemma cont_diff_pi : - cont_diff 𝕜 n Φ ↔ ∀ i, cont_diff 𝕜 n (λ x, Φ x i) := -by simp only [← cont_diff_on_univ, cont_diff_on_pi] - -end pi - /-! ### Composition of `C^n` functions @@ -2003,7 +1852,7 @@ private lemma cont_diff_on.comp_same_univ {Eu : Type u} [normed_group Eu] [normed_space 𝕜 Eu] {Fu : Type u} [normed_group Fu] [normed_space 𝕜 Fu] {Gu : Type u} [normed_group Gu] [normed_space 𝕜 Gu] - {n : with_top ℕ} {s : set Eu} {t : set Fu} {g : Fu → Gu} {f : Eu → Fu} + {s : set Eu} {t : set Fu} {g : Fu → Gu} {f : Eu → Fu} (hg : cont_diff_on 𝕜 n g t) (hf : cont_diff_on 𝕜 n f s) (st : s ⊆ f ⁻¹' t) : cont_diff_on 𝕜 n (g ∘ f) s := begin @@ -2051,7 +1900,7 @@ end /-- The composition of `C^n` functions on domains is `C^n`. -/ lemma cont_diff_on.comp - {n : with_top ℕ} {s : set E} {t : set F} {g : F → G} {f : E → F} + {s : set E} {t : set F} {g : F → G} {f : E → F} (hg : cont_diff_on 𝕜 n g t) (hf : cont_diff_on 𝕜 n f s) (st : s ⊆ f ⁻¹' t) : cont_diff_on 𝕜 n (g ∘ f) s := begin @@ -2094,19 +1943,19 @@ end /-- The composition of `C^n` functions on domains is `C^n`. -/ lemma cont_diff_on.comp' - {n : with_top ℕ} {s : set E} {t : set F} {g : F → G} {f : E → F} + {s : set E} {t : set F} {g : F → G} {f : E → F} (hg : cont_diff_on 𝕜 n g t) (hf : cont_diff_on 𝕜 n f s) : cont_diff_on 𝕜 n (g ∘ f) (s ∩ f⁻¹' t) := hg.comp (hf.mono (inter_subset_left _ _)) (inter_subset_right _ _) /-- The composition of a `C^n` function on a domain with a `C^n` function is `C^n`. -/ -lemma cont_diff.comp_cont_diff_on {n : with_top ℕ} {s : set E} {g : F → G} {f : E → F} +lemma cont_diff.comp_cont_diff_on {s : set E} {g : F → G} {f : E → F} (hg : cont_diff 𝕜 n g) (hf : cont_diff_on 𝕜 n f s) : cont_diff_on 𝕜 n (g ∘ f) s := (cont_diff_on_univ.2 hg).comp hf subset_preimage_univ /-- The composition of `C^n` functions is `C^n`. -/ -lemma cont_diff.comp {n : with_top ℕ} {g : F → G} {f : E → F} +lemma cont_diff.comp {g : F → G} {f : E → F} (hg : cont_diff 𝕜 n g) (hf : cont_diff 𝕜 n f) : cont_diff 𝕜 n (g ∘ f) := cont_diff_on_univ.1 $ cont_diff_on.comp (cont_diff_on_univ.2 hg) @@ -2114,7 +1963,7 @@ cont_diff_on_univ.1 $ cont_diff_on.comp (cont_diff_on_univ.2 hg) /-- The composition of `C^n` functions at points in domains is `C^n`. -/ lemma cont_diff_within_at.comp - {n : with_top ℕ} {s : set E} {t : set F} {g : F → G} {f : E → F} (x : E) + {s : set E} {t : set F} {g : F → G} {f : E → F} (x : E) (hg : cont_diff_within_at 𝕜 n g t (f x)) (hf : cont_diff_within_at 𝕜 n f s x) (st : s ⊆ f ⁻¹' t) : cont_diff_within_at 𝕜 n (g ∘ f) s x := @@ -2143,7 +1992,7 @@ begin end /-- The composition of `C^n` functions at points in domains is `C^n`. -/ -lemma cont_diff_within_at.comp' {n : with_top ℕ} {s : set E} {t : set F} {g : F → G} +lemma cont_diff_within_at.comp' {s : set E} {t : set F} {g : F → G} {f : E → F} (x : E) (hg : cont_diff_within_at 𝕜 n g t (f x)) (hf : cont_diff_within_at 𝕜 n f s x) : cont_diff_within_at 𝕜 n (g ∘ f) (s ∩ f⁻¹' t) x := @@ -2155,14 +2004,14 @@ lemma cont_diff_at.comp_cont_diff_within_at {n} (x : E) hg.comp x hf (maps_to_univ _ _) /-- The composition of `C^n` functions at points is `C^n`. -/ -lemma cont_diff_at.comp {n : with_top ℕ} (x : E) +lemma cont_diff_at.comp (x : E) (hg : cont_diff_at 𝕜 n g (f x)) (hf : cont_diff_at 𝕜 n f x) : cont_diff_at 𝕜 n (g ∘ f) x := hg.comp x hf subset_preimage_univ lemma cont_diff.comp_cont_diff_within_at - {n : with_top ℕ} {g : F → G} {f : E → F} (h : cont_diff 𝕜 n g) + {g : F → G} {f : E → F} (h : cont_diff 𝕜 n g) (hf : cont_diff_within_at 𝕜 n f t x) : cont_diff_within_at 𝕜 n (g ∘ f) t x := begin @@ -2172,12 +2021,68 @@ begin end lemma cont_diff.comp_cont_diff_at - {n : with_top ℕ} {g : F → G} {f : E → F} (x : E) + {g : F → G} {f : E → F} (x : E) (hg : cont_diff 𝕜 n g) (hf : cont_diff_at 𝕜 n f x) : cont_diff_at 𝕜 n (g ∘ f) x := hg.comp_cont_diff_within_at hf +/-- The first projection in a product is `C^∞`. -/ +lemma cont_diff_fst : cont_diff 𝕜 n (prod.fst : E × F → E) := +is_bounded_linear_map.cont_diff is_bounded_linear_map.fst + +/-- The first projection on a domain in a product is `C^∞`. -/ +lemma cont_diff_on_fst {s : set (E×F)} : + cont_diff_on 𝕜 n (prod.fst : E × F → E) s := +cont_diff.cont_diff_on cont_diff_fst + +/-- The first projection at a point in a product is `C^∞`. -/ +lemma cont_diff_at_fst {p : E × F} : + cont_diff_at 𝕜 n (prod.fst : E × F → E) p := +cont_diff_fst.cont_diff_at + +/-- The first projection within a domain at a point in a product is `C^∞`. -/ +lemma cont_diff_within_at_fst {s : set (E × F)} {p : E × F} : + cont_diff_within_at 𝕜 n (prod.fst : E × F → E) s p := +cont_diff_fst.cont_diff_within_at + +/-- The second projection in a product is `C^∞`. -/ +lemma cont_diff_snd : cont_diff 𝕜 n (prod.snd : E × F → F) := +is_bounded_linear_map.cont_diff is_bounded_linear_map.snd + +/-- The second projection on a domain in a product is `C^∞`. -/ +lemma cont_diff_on_snd {s : set (E×F)} : + cont_diff_on 𝕜 n (prod.snd : E × F → F) s := +cont_diff.cont_diff_on cont_diff_snd + +/-- The second projection at a point in a product is `C^∞`. -/ +lemma cont_diff_at_snd {p : E × F} : + cont_diff_at 𝕜 n (prod.snd : E × F → F) p := +cont_diff_snd.cont_diff_at + +/-- The second projection within a domain at a point in a product is `C^∞`. -/ +lemma cont_diff_within_at_snd {s : set (E × F)} {p : E × F} : + cont_diff_within_at 𝕜 n (prod.snd : E × F → F) s p := +cont_diff_snd.cont_diff_within_at + +/-- +The natural equivalence `(E × F) × G ≃ E × (F × G)` is smooth. + +Warning: if you think you need this lemma, it is likely that you can simplify your proof by +reformulating the lemma that you're applying next using the tips in +Note [continuity lemma statement] +-/ +lemma cont_diff_prod_assoc : cont_diff 𝕜 ⊤ $ equiv.prod_assoc E F G := +(linear_isometry_equiv.prod_assoc 𝕜 E F G).cont_diff + +/-- +The natural equivalence `E × (F × G) ≃ (E × F) × G` is smooth. + +Warning: see remarks attached to `cont_diff_prod_assoc` +-/ +lemma cont_diff_prod_assoc_symm : cont_diff 𝕜 ⊤ $ (equiv.prod_assoc E F G).symm := +(linear_isometry_equiv.prod_assoc 𝕜 E F G).symm.cont_diff + /-- The bundled derivative of a `C^{n+1}` function is `C^n`. -/ lemma cont_diff_on_fderiv_within_apply {m n : with_top ℕ} {s : set E} {f : E → F} (hf : cont_diff_on 𝕜 n f s) (hs : unique_diff_on 𝕜 s) (hmn : m + 1 ≤ n) : @@ -2201,7 +2106,7 @@ begin end /-- The bundled derivative of a `C^{n+1}` function is `C^n`. -/ -lemma cont_diff.cont_diff_fderiv_apply {n m : with_top ℕ} {f : E → F} +lemma cont_diff.cont_diff_fderiv_apply {f : E → F} (hf : cont_diff 𝕜 n f) (hmn : m + 1 ≤ n) : cont_diff 𝕜 m (λp : E × E, (fderiv 𝕜 f p.1 : E →L[𝕜] F) p.2) := begin @@ -2210,34 +2115,97 @@ begin exact cont_diff_on_fderiv_within_apply hf unique_diff_on_univ hmn end +/-! +### Smoothness of functions `f : E → Π i, F' i` +-/ + +section pi + +variables {ι : Type*} [fintype ι] {F' : ι → Type*} [Π i, normed_group (F' i)] + [Π i, normed_space 𝕜 (F' i)] {φ : Π i, E → F' i} + {p' : Π i, E → formal_multilinear_series 𝕜 E (F' i)} + {Φ : E → Π i, F' i} {P' : E → formal_multilinear_series 𝕜 E (Π i, F' i)} + +lemma has_ftaylor_series_up_to_on_pi : + has_ftaylor_series_up_to_on n (λ x i, φ i x) + (λ x m, continuous_multilinear_map.pi (λ i, p' i x m)) s ↔ + ∀ i, has_ftaylor_series_up_to_on n (φ i) (p' i) s := +begin + set pr := @continuous_linear_map.proj 𝕜 _ ι F' _ _ _, + letI : Π (m : ℕ) (i : ι), normed_space 𝕜 (E [×m]→L[𝕜] (F' i)) := λ m i, infer_instance, + set L : Π m : ℕ, (Π i, E [×m]→L[𝕜] (F' i)) ≃ₗᵢ[𝕜] (E [×m]→L[𝕜] (Π i, F' i)) := + λ m, continuous_multilinear_map.piₗᵢ _ _, + refine ⟨λ h i, _, λ h, ⟨λ x hx, _, _, _⟩⟩, + { convert h.continuous_linear_map_comp (pr i), + ext, refl }, + { ext1 i, + exact (h i).zero_eq x hx }, + { intros m hm x hx, + have := has_fderiv_within_at_pi.2 (λ i, (h i).fderiv_within m hm x hx), + convert (L m).has_fderiv_at.comp_has_fderiv_within_at x this }, + { intros m hm, + have := continuous_on_pi.2 (λ i, (h i).cont m hm), + convert (L m).continuous.comp_continuous_on this } +end + +@[simp] lemma has_ftaylor_series_up_to_on_pi' : + has_ftaylor_series_up_to_on n Φ P' s ↔ + ∀ i, has_ftaylor_series_up_to_on n (λ x, Φ x i) + (λ x m, (@continuous_linear_map.proj 𝕜 _ ι F' _ _ _ i).comp_continuous_multilinear_map + (P' x m)) s := +by { convert has_ftaylor_series_up_to_on_pi, ext, refl } + +lemma cont_diff_within_at_pi : + cont_diff_within_at 𝕜 n Φ s x ↔ + ∀ i, cont_diff_within_at 𝕜 n (λ x, Φ x i) s x := +begin + set pr := @continuous_linear_map.proj 𝕜 _ ι F' _ _ _, + refine ⟨λ h i, h.continuous_linear_map_comp (pr i), λ h m hm, _⟩, + choose u hux p hp using λ i, h i m hm, + exact ⟨⋂ i, u i, filter.Inter_mem.2 hux, _, + has_ftaylor_series_up_to_on_pi.2 (λ i, (hp i).mono $ Inter_subset _ _)⟩, +end + +lemma cont_diff_on_pi : + cont_diff_on 𝕜 n Φ s ↔ ∀ i, cont_diff_on 𝕜 n (λ x, Φ x i) s := +⟨λ h i x hx, cont_diff_within_at_pi.1 (h x hx) _, + λ h x hx, cont_diff_within_at_pi.2 (λ i, h i x hx)⟩ + +lemma cont_diff_at_pi : + cont_diff_at 𝕜 n Φ x ↔ ∀ i, cont_diff_at 𝕜 n (λ x, Φ x i) x := +cont_diff_within_at_pi + +lemma cont_diff_pi : + cont_diff 𝕜 n Φ ↔ ∀ i, cont_diff 𝕜 n (λ x, Φ x i) := +by simp only [← cont_diff_on_univ, cont_diff_on_pi] + +end pi + /-! ### Sum of two functions -/ /- The sum is smooth. -/ -lemma cont_diff_add {n : with_top ℕ} : - cont_diff 𝕜 n (λp : F × F, p.1 + p.2) := +lemma cont_diff_add : cont_diff 𝕜 n (λp : F × F, p.1 + p.2) := (is_bounded_linear_map.fst.add is_bounded_linear_map.snd).cont_diff /-- The sum of two `C^n` functions within a set at a point is `C^n` within this set at this point. -/ -lemma cont_diff_within_at.add {n : with_top ℕ} {s : set E} {f g : E → F} +lemma cont_diff_within_at.add {s : set E} {f g : E → F} (hf : cont_diff_within_at 𝕜 n f s x) (hg : cont_diff_within_at 𝕜 n g s x) : cont_diff_within_at 𝕜 n (λx, f x + g x) s x := cont_diff_add.cont_diff_within_at.comp x (hf.prod hg) subset_preimage_univ /-- The sum of two `C^n` functions at a point is `C^n` at this point. -/ -lemma cont_diff_at.add {n : with_top ℕ} {f g : E → F} - (hf : cont_diff_at 𝕜 n f x) (hg : cont_diff_at 𝕜 n g x) : +lemma cont_diff_at.add {f g : E → F} (hf : cont_diff_at 𝕜 n f x) (hg : cont_diff_at 𝕜 n g x) : cont_diff_at 𝕜 n (λx, f x + g x) x := by rw [← cont_diff_within_at_univ] at *; exact hf.add hg /-- The sum of two `C^n`functions is `C^n`. -/ -lemma cont_diff.add {n : with_top ℕ} {f g : E → F} - (hf : cont_diff 𝕜 n f) (hg : cont_diff 𝕜 n g) : +lemma cont_diff.add {f g : E → F} (hf : cont_diff 𝕜 n f) (hg : cont_diff 𝕜 n g) : cont_diff 𝕜 n (λx, f x + g x) := cont_diff_add.comp (hf.prod hg) /-- The sum of two `C^n` functions on a domain is `C^n`. -/ -lemma cont_diff_on.add {n : with_top ℕ} {s : set E} {f g : E → F} +lemma cont_diff_on.add {s : set E} {f g : E → F} (hf : cont_diff_on 𝕜 n f s) (hg : cont_diff_on 𝕜 n g s) : cont_diff_on 𝕜 n (λx, f x + g x) s := λ x hx, (hf x hx).add (hg x hx) @@ -2245,28 +2213,26 @@ lemma cont_diff_on.add {n : with_top ℕ} {s : set E} {f g : E → F} /-! ### Negative -/ /- The negative is smooth. -/ -lemma cont_diff_neg {n : with_top ℕ} : - cont_diff 𝕜 n (λp : F, -p) := +lemma cont_diff_neg : cont_diff 𝕜 n (λp : F, -p) := is_bounded_linear_map.id.neg.cont_diff /-- The negative of a `C^n` function within a domain at a point is `C^n` within this domain at this point. -/ -lemma cont_diff_within_at.neg {n : with_top ℕ} {s : set E} {f : E → F} +lemma cont_diff_within_at.neg {s : set E} {f : E → F} (hf : cont_diff_within_at 𝕜 n f s x) : cont_diff_within_at 𝕜 n (λx, -f x) s x := cont_diff_neg.cont_diff_within_at.comp x hf subset_preimage_univ /-- The negative of a `C^n` function at a point is `C^n` at this point. -/ -lemma cont_diff_at.neg {n : with_top ℕ} {f : E → F} +lemma cont_diff_at.neg {f : E → F} (hf : cont_diff_at 𝕜 n f x) : cont_diff_at 𝕜 n (λx, -f x) x := by rw ← cont_diff_within_at_univ at *; exact hf.neg /-- The negative of a `C^n`function is `C^n`. -/ -lemma cont_diff.neg {n : with_top ℕ} {f : E → F} (hf : cont_diff 𝕜 n f) : - cont_diff 𝕜 n (λx, -f x) := +lemma cont_diff.neg {f : E → F} (hf : cont_diff 𝕜 n f) : cont_diff 𝕜 n (λx, -f x) := cont_diff_neg.comp hf /-- The negative of a `C^n` function on a domain is `C^n`. -/ -lemma cont_diff_on.neg {n : with_top ℕ} {s : set E} {f : E → F} +lemma cont_diff_on.neg {s : set E} {f : E → F} (hf : cont_diff_on 𝕜 n f s) : cont_diff_on 𝕜 n (λx, -f x) s := λ x hx, (hf x hx).neg @@ -2274,32 +2240,32 @@ lemma cont_diff_on.neg {n : with_top ℕ} {s : set E} {f : E → F} /-- The difference of two `C^n` functions within a set at a point is `C^n` within this set at this point. -/ -lemma cont_diff_within_at.sub {n : with_top ℕ} {s : set E} {f g : E → F} +lemma cont_diff_within_at.sub {s : set E} {f g : E → F} (hf : cont_diff_within_at 𝕜 n f s x) (hg : cont_diff_within_at 𝕜 n g s x) : cont_diff_within_at 𝕜 n (λx, f x - g x) s x := by simpa only [sub_eq_add_neg] using hf.add hg.neg /-- The difference of two `C^n` functions at a point is `C^n` at this point. -/ -lemma cont_diff_at.sub {n : with_top ℕ} {f g : E → F} +lemma cont_diff_at.sub {f g : E → F} (hf : cont_diff_at 𝕜 n f x) (hg : cont_diff_at 𝕜 n g x) : cont_diff_at 𝕜 n (λx, f x - g x) x := by simpa only [sub_eq_add_neg] using hf.add hg.neg /-- The difference of two `C^n` functions on a domain is `C^n`. -/ -lemma cont_diff_on.sub {n : with_top ℕ} {s : set E} {f g : E → F} +lemma cont_diff_on.sub {s : set E} {f g : E → F} (hf : cont_diff_on 𝕜 n f s) (hg : cont_diff_on 𝕜 n g s) : cont_diff_on 𝕜 n (λx, f x - g x) s := by simpa only [sub_eq_add_neg] using hf.add hg.neg /-- The difference of two `C^n` functions is `C^n`. -/ -lemma cont_diff.sub {n : with_top ℕ} {f g : E → F} +lemma cont_diff.sub {f g : E → F} (hf : cont_diff 𝕜 n f) (hg : cont_diff 𝕜 n g) : cont_diff 𝕜 n (λx, f x - g x) := by simpa only [sub_eq_add_neg] using hf.add hg.neg /-! ### Sum of finitely many functions -/ lemma cont_diff_within_at.sum - {ι : Type*} {f : ι → E → F} {s : finset ι} {n : with_top ℕ} {t : set E} {x : E} + {ι : Type*} {f : ι → E → F} {s : finset ι} {t : set E} {x : E} (h : ∀ i ∈ s, cont_diff_within_at 𝕜 n (λ x, f i x) t x) : cont_diff_within_at 𝕜 n (λ x, (∑ i in s, f i x)) t x := begin @@ -2311,19 +2277,19 @@ begin end lemma cont_diff_at.sum - {ι : Type*} {f : ι → E → F} {s : finset ι} {n : with_top ℕ} {x : E} + {ι : Type*} {f : ι → E → F} {s : finset ι} {x : E} (h : ∀ i ∈ s, cont_diff_at 𝕜 n (λ x, f i x) x) : cont_diff_at 𝕜 n (λ x, (∑ i in s, f i x)) x := by rw [← cont_diff_within_at_univ] at *; exact cont_diff_within_at.sum h lemma cont_diff_on.sum - {ι : Type*} {f : ι → E → F} {s : finset ι} {n : with_top ℕ} {t : set E} + {ι : Type*} {f : ι → E → F} {s : finset ι} {t : set E} (h : ∀ i ∈ s, cont_diff_on 𝕜 n (λ x, f i x) t) : cont_diff_on 𝕜 n (λ x, (∑ i in s, f i x)) t := λ x hx, cont_diff_within_at.sum (λ i hi, h i hi x hx) lemma cont_diff.sum - {ι : Type*} {f : ι → E → F} {s : finset ι} {n : with_top ℕ} + {ι : Type*} {f : ι → E → F} {s : finset ι} (h : ∀ i ∈ s, cont_diff 𝕜 n (λ x, f i x)) : cont_diff 𝕜 n (λ x, (∑ i in s, f i x)) := by simp [← cont_diff_on_univ] at *; exact cont_diff_on.sum h @@ -2331,32 +2297,30 @@ by simp [← cont_diff_on_univ] at *; exact cont_diff_on.sum h /-! ### Product of two functions -/ /- The product is smooth. -/ -lemma cont_diff_mul {n : with_top ℕ} : - cont_diff 𝕜 n (λ p : 𝕜 × 𝕜, p.1 * p.2) := +lemma cont_diff_mul : cont_diff 𝕜 n (λ p : 𝕜 × 𝕜, p.1 * p.2) := is_bounded_bilinear_map_mul.cont_diff /-- The product of two `C^n` functions within a set at a point is `C^n` within this set at this point. -/ -lemma cont_diff_within_at.mul {n : with_top ℕ} {s : set E} {f g : E → 𝕜} +lemma cont_diff_within_at.mul {s : set E} {f g : E → 𝕜} (hf : cont_diff_within_at 𝕜 n f s x) (hg : cont_diff_within_at 𝕜 n g s x) : cont_diff_within_at 𝕜 n (λ x, f x * g x) s x := cont_diff_mul.cont_diff_within_at.comp x (hf.prod hg) subset_preimage_univ /-- The product of two `C^n` functions at a point is `C^n` at this point. -/ -lemma cont_diff_at.mul {n : with_top ℕ} {f g : E → 𝕜} +lemma cont_diff_at.mul {f g : E → 𝕜} (hf : cont_diff_at 𝕜 n f x) (hg : cont_diff_at 𝕜 n g x) : cont_diff_at 𝕜 n (λ x, f x * g x) x := by rw [← cont_diff_within_at_univ] at *; exact hf.mul hg /-- The product of two `C^n` functions on a domain is `C^n`. -/ -lemma cont_diff_on.mul {n : with_top ℕ} {s : set E} {f g : E → 𝕜} +lemma cont_diff_on.mul {s : set E} {f g : E → 𝕜} (hf : cont_diff_on 𝕜 n f s) (hg : cont_diff_on 𝕜 n g s) : cont_diff_on 𝕜 n (λ x, f x * g x) s := λ x hx, (hf x hx).mul (hg x hx) /-- The product of two `C^n`functions is `C^n`. -/ -lemma cont_diff.mul {n : with_top ℕ} {f g : E → 𝕜} - (hf : cont_diff 𝕜 n f) (hg : cont_diff 𝕜 n g) : +lemma cont_diff.mul {f g : E → 𝕜} (hf : cont_diff 𝕜 n f) (hg : cont_diff 𝕜 n g) : cont_diff 𝕜 n (λ x, f x * g x) := cont_diff_mul.comp (hf.prod hg) @@ -2377,22 +2341,22 @@ lemma cont_diff.div_const {f : E → 𝕜} {n} {c : 𝕜} (hf : cont_diff 𝕜 n cont_diff 𝕜 n (λ x, f x / c) := by simpa only [div_eq_mul_inv] using hf.mul cont_diff_const -lemma cont_diff.pow {n : with_top ℕ} {f : E → 𝕜} +lemma cont_diff.pow {f : E → 𝕜} (hf : cont_diff 𝕜 n f) : ∀ m : ℕ, cont_diff 𝕜 n (λ x, (f x) ^ m) | 0 := by simpa using cont_diff_const | (m + 1) := by simpa [pow_succ] using hf.mul (cont_diff.pow m) -lemma cont_diff_at.pow {n : with_top ℕ} {f : E → 𝕜} (hf : cont_diff_at 𝕜 n f x) +lemma cont_diff_at.pow {f : E → 𝕜} (hf : cont_diff_at 𝕜 n f x) (m : ℕ) : cont_diff_at 𝕜 n (λ y, f y ^ m) x := (cont_diff_id.pow m).cont_diff_at.comp x hf -lemma cont_diff_within_at.pow {n : with_top ℕ} {f : E → 𝕜} +lemma cont_diff_within_at.pow {f : E → 𝕜} (hf : cont_diff_within_at 𝕜 n f s x) (m : ℕ) : cont_diff_within_at 𝕜 n (λ y, f y ^ m) s x := (cont_diff_id.pow m).cont_diff_at.comp_cont_diff_within_at x hf -lemma cont_diff_on.pow {n : with_top ℕ} {f : E → 𝕜} +lemma cont_diff_on.pow {f : E → 𝕜} (hf : cont_diff_on 𝕜 n f s) (m : ℕ) : cont_diff_on 𝕜 n (λ y, f y ^ m) s := λ y hy, (hf y hy).pow m @@ -2400,31 +2364,29 @@ lemma cont_diff_on.pow {n : with_top ℕ} {f : E → 𝕜} /-! ### Scalar multiplication -/ /- The scalar multiplication is smooth. -/ -lemma cont_diff_smul {n : with_top ℕ} : - cont_diff 𝕜 n (λ p : 𝕜 × F, p.1 • p.2) := +lemma cont_diff_smul : cont_diff 𝕜 n (λ p : 𝕜 × F, p.1 • p.2) := is_bounded_bilinear_map_smul.cont_diff /-- The scalar multiplication of two `C^n` functions within a set at a point is `C^n` within this set at this point. -/ -lemma cont_diff_within_at.smul {n : with_top ℕ} {s : set E} {f : E → 𝕜} {g : E → F} +lemma cont_diff_within_at.smul {s : set E} {f : E → 𝕜} {g : E → F} (hf : cont_diff_within_at 𝕜 n f s x) (hg : cont_diff_within_at 𝕜 n g s x) : cont_diff_within_at 𝕜 n (λ x, f x • g x) s x := cont_diff_smul.cont_diff_within_at.comp x (hf.prod hg) subset_preimage_univ /-- The scalar multiplication of two `C^n` functions at a point is `C^n` at this point. -/ -lemma cont_diff_at.smul {n : with_top ℕ} {f : E → 𝕜} {g : E → F} +lemma cont_diff_at.smul {f : E → 𝕜} {g : E → F} (hf : cont_diff_at 𝕜 n f x) (hg : cont_diff_at 𝕜 n g x) : cont_diff_at 𝕜 n (λ x, f x • g x) x := by rw [← cont_diff_within_at_univ] at *; exact hf.smul hg /-- The scalar multiplication of two `C^n` functions is `C^n`. -/ -lemma cont_diff.smul {n : with_top ℕ} {f : E → 𝕜} {g : E → F} - (hf : cont_diff 𝕜 n f) (hg : cont_diff 𝕜 n g) : +lemma cont_diff.smul {f : E → 𝕜} {g : E → F} (hf : cont_diff 𝕜 n f) (hg : cont_diff 𝕜 n g) : cont_diff 𝕜 n (λ x, f x • g x) := cont_diff_smul.comp (hf.prod hg) /-- The scalar multiplication of two `C^n` functions on a domain is `C^n`. -/ -lemma cont_diff_on.smul {n : with_top ℕ} {s : set E} {f : E → 𝕜} {g : E → F} +lemma cont_diff_on.smul {s : set E} {f : E → 𝕜} {g : E → F} (hf : cont_diff_on 𝕜 n f s) (hg : cont_diff_on 𝕜 n g s) : cont_diff_on 𝕜 n (λ x, f x • g x) s := λ x hx, (hf x hx).smul (hg x hx) @@ -2433,8 +2395,8 @@ lemma cont_diff_on.smul {n : with_top ℕ} {s : set E} {f : E → 𝕜} {g : E section prod_map variables {E' : Type*} [normed_group E'] [normed_space 𝕜 E'] -{F' : Type*} [normed_group F'] [normed_space 𝕜 F'] -{n : with_top ℕ} +variables {F' : Type*} [normed_group F'] [normed_space 𝕜 F'] + /-- The product map of two `C^n` functions within a set at a point is `C^n` within the product set at the product point. -/ @@ -2454,7 +2416,7 @@ cont_diff_within_at.prod_map' hf hg /-- The product map of two `C^n` functions on a set is `C^n` on the product set. -/ lemma cont_diff_on.prod_map {E' : Type*} [normed_group E'] [normed_space 𝕜 E'] {F' : Type*} [normed_group F'] [normed_space 𝕜 F'] - {s : set E} {t : set E'} {n : with_top ℕ} {f : E → F} {g : E' → F'} + {s : set E} {t : set E'} {f : E → F} {g : E' → F'} (hf : cont_diff_on 𝕜 n f s) (hg : cont_diff_on 𝕜 n g t) : cont_diff_on 𝕜 n (prod.map f g) (s ×ˢ t) := (hf.comp cont_diff_on_fst (prod_subset_preimage_fst _ _)).prod @@ -2482,8 +2444,7 @@ begin end /-- The product map of two `C^n` functions is `C^n`. -/ -lemma cont_diff.prod_map - {f : E → F} {g : E' → F'} +lemma cont_diff.prod_map {f : E → F} {g : E' → F'} (hf : cont_diff 𝕜 n f) (hg : cont_diff 𝕜 n g) : cont_diff 𝕜 n (prod.map f g) := begin @@ -2502,7 +2463,7 @@ open normed_ring continuous_linear_map ring /-- In a complete normed algebra, the operation of inversion is `C^n`, for all `n`, at each invertible element. The proof is by induction, bootstrapping using an identity expressing the derivative of inversion as a bilinear map of inversion itself. -/ -lemma cont_diff_at_ring_inverse [complete_space R] {n : with_top ℕ} (x : Rˣ) : +lemma cont_diff_at_ring_inverse [complete_space R] (x : Rˣ) : cont_diff_at 𝕜 n ring.inverse (x : R) := begin induction n using with_top.nat_induction with n IH Itop, @@ -2596,7 +2557,7 @@ open continuous_linear_map /-- At a continuous linear equivalence `e : E ≃L[𝕜] F` between Banach spaces, the operation of inversion is `C^n`, for all `n`. -/ -lemma cont_diff_at_map_inverse [complete_space E] {n : with_top ℕ} (e : E ≃L[𝕜] F) : +lemma cont_diff_at_map_inverse [complete_space E] (e : E ≃L[𝕜] F) : cont_diff_at 𝕜 n inverse (e : E →L[𝕜] F) := begin nontriviality E, @@ -2632,7 +2593,7 @@ then `f.symm` is `n` times continuously differentiable at the point `a`. This is one of the easy parts of the inverse function theorem: it assumes that we already have an inverse function. -/ -theorem local_homeomorph.cont_diff_at_symm [complete_space E] {n : with_top ℕ} +theorem local_homeomorph.cont_diff_at_symm [complete_space E] (f : local_homeomorph E F) {f₀' : E ≃L[𝕜] F} {a : F} (ha : a ∈ f.target) (hf₀' : has_fderiv_at f (f₀' : E →L[𝕜] F) (f.symm a)) (hf : cont_diff_at 𝕜 n f (f.symm a)) : cont_diff_at 𝕜 n f.symm a := @@ -2687,7 +2648,7 @@ target. if `f` is `n` times continuously differentiable at `f.symm a`, and if th This is one of the easy parts of the inverse function theorem: it assumes that we already have an inverse function. -/ -theorem local_homeomorph.cont_diff_at_symm_deriv [complete_space 𝕜] {n : with_top ℕ} +theorem local_homeomorph.cont_diff_at_symm_deriv [complete_space 𝕜] (f : local_homeomorph 𝕜 𝕜) {f₀' a : 𝕜} (h₀ : f₀' ≠ 0) (ha : a ∈ f.target) (hf₀' : has_deriv_at f f₀' (f.symm a)) (hf : cont_diff_at 𝕜 n f (f.symm a)) : cont_diff_at 𝕜 n f.symm a := @@ -2710,7 +2671,7 @@ variables /-- If a function has a Taylor series at order at least 1, then at points in the interior of the domain of definition, the term of order 1 of this series is a strict derivative of `f`. -/ lemma has_ftaylor_series_up_to_on.has_strict_fderiv_at - {s : set E'} {f : E' → F'} {x : E'} {p : E' → formal_multilinear_series 𝕂 E' F'} {n : with_top ℕ} + {s : set E'} {f : E' → F'} {x : E'} {p : E' → formal_multilinear_series 𝕂 E' F'} (hf : has_ftaylor_series_up_to_on n f p s) (hn : 1 ≤ n) (hs : s ∈ 𝓝 x) : has_strict_fderiv_at f ((continuous_multilinear_curry_fin1 𝕂 E' F') (p x 1)) x := has_strict_fderiv_at_of_has_fderiv_at_of_continuous_at (hf.eventually_has_fderiv_at hn hs) $ @@ -2721,7 +2682,7 @@ has_strict_fderiv_at_of_has_fderiv_at_of_continuous_at (hf.eventually_has_fderiv us as `f'`, then `f'` is also a strict derivative. -/ lemma cont_diff_at.has_strict_fderiv_at' {f : E' → F'} {f' : E' →L[𝕂] F'} {x : E'} - {n : with_top ℕ} (hf : cont_diff_at 𝕂 n f x) (hf' : has_fderiv_at f f' x) (hn : 1 ≤ n) : + (hf : cont_diff_at 𝕂 n f x) (hf' : has_fderiv_at f f' x) (hn : 1 ≤ n) : has_strict_fderiv_at f f' x := begin rcases hf 1 hn with ⟨u, H, p, hp⟩, @@ -2733,33 +2694,33 @@ end /-- If a function is `C^n` with `1 ≤ n` around a point, and its derivative at that point is given to us as `f'`, then `f'` is also a strict derivative. -/ lemma cont_diff_at.has_strict_deriv_at' {f : 𝕂 → F'} {f' : F'} {x : 𝕂} - {n : with_top ℕ} (hf : cont_diff_at 𝕂 n f x) (hf' : has_deriv_at f f' x) (hn : 1 ≤ n) : + (hf : cont_diff_at 𝕂 n f x) (hf' : has_deriv_at f f' x) (hn : 1 ≤ n) : has_strict_deriv_at f f' x := hf.has_strict_fderiv_at' hf' hn /-- If a function is `C^n` with `1 ≤ n` around a point, then the derivative of `f` at this point is also a strict derivative. -/ -lemma cont_diff_at.has_strict_fderiv_at {f : E' → F'} {x : E'} {n : with_top ℕ} +lemma cont_diff_at.has_strict_fderiv_at {f : E' → F'} {x : E'} (hf : cont_diff_at 𝕂 n f x) (hn : 1 ≤ n) : has_strict_fderiv_at f (fderiv 𝕂 f x) x := hf.has_strict_fderiv_at' (hf.differentiable_at hn).has_fderiv_at hn /-- If a function is `C^n` with `1 ≤ n` around a point, then the derivative of `f` at this point is also a strict derivative. -/ -lemma cont_diff_at.has_strict_deriv_at {f : 𝕂 → F'} {x : 𝕂} {n : with_top ℕ} +lemma cont_diff_at.has_strict_deriv_at {f : 𝕂 → F'} {x : 𝕂} (hf : cont_diff_at 𝕂 n f x) (hn : 1 ≤ n) : has_strict_deriv_at f (deriv f x) x := (hf.has_strict_fderiv_at hn).has_strict_deriv_at /-- If a function is `C^n` with `1 ≤ n`, then the derivative of `f` is also a strict derivative. -/ lemma cont_diff.has_strict_fderiv_at - {f : E' → F'} {x : E'} {n : with_top ℕ} (hf : cont_diff 𝕂 n f) (hn : 1 ≤ n) : + {f : E' → F'} {x : E'} (hf : cont_diff 𝕂 n f) (hn : 1 ≤ n) : has_strict_fderiv_at f (fderiv 𝕂 f x) x := hf.cont_diff_at.has_strict_fderiv_at hn /-- If a function is `C^n` with `1 ≤ n`, then the derivative of `f` is also a strict derivative. -/ lemma cont_diff.has_strict_deriv_at - {f : 𝕂 → F'} {x : 𝕂} {n : with_top ℕ} (hf : cont_diff 𝕂 n f) (hn : 1 ≤ n) : + {f : 𝕂 → F'} {x : 𝕂} (hf : cont_diff 𝕂 n f) (hn : 1 ≤ n) : has_strict_deriv_at f (deriv f x) x := hf.cont_diff_at.has_strict_deriv_at hn @@ -2907,7 +2868,7 @@ begin exact deriv_within_of_open hs hx end -lemma cont_diff_on.deriv_within {m n : with_top ℕ} +lemma cont_diff_on.deriv_within (hf : cont_diff_on 𝕜 n f₂ s₂) (hs : unique_diff_on 𝕜 s₂) (hmn : m + 1 ≤ n) : cont_diff_on 𝕜 m (deriv_within f₂ s₂) s₂ := begin @@ -2920,17 +2881,17 @@ begin exact ((cont_diff_on_succ_iff_deriv_within hs).1 (hf.of_le hmn)).2 } end -lemma cont_diff_on.deriv_of_open {m n : with_top ℕ} +lemma cont_diff_on.deriv_of_open (hf : cont_diff_on 𝕜 n f₂ s₂) (hs : is_open s₂) (hmn : m + 1 ≤ n) : cont_diff_on 𝕜 m (deriv f₂) s₂ := (hf.deriv_within hs.unique_diff_on hmn).congr (λ x hx, (deriv_within_of_open hs hx).symm) -lemma cont_diff_on.continuous_on_deriv_within {n : with_top ℕ} +lemma cont_diff_on.continuous_on_deriv_within (h : cont_diff_on 𝕜 n f₂ s₂) (hs : unique_diff_on 𝕜 s₂) (hn : 1 ≤ n) : continuous_on (deriv_within f₂ s₂) s₂ := ((cont_diff_on_succ_iff_deriv_within hs).1 (h.of_le hn)).2.continuous_on -lemma cont_diff_on.continuous_on_deriv_of_open {n : with_top ℕ} +lemma cont_diff_on.continuous_on_deriv_of_open (h : cont_diff_on 𝕜 n f₂ s₂) (hs : is_open s₂) (hn : 1 ≤ n) : continuous_on (deriv f₂) s₂ := ((cont_diff_on_succ_iff_deriv_of_open hs).1 (h.of_le hn)).2.continuous_on @@ -2958,7 +2919,7 @@ begin rw cont_diff_on_top_iff_deriv_within unique_diff_on_univ, end -lemma cont_diff.continuous_deriv {n : with_top ℕ} (h : cont_diff 𝕜 n f₂) (hn : 1 ≤ n) : +lemma cont_diff.continuous_deriv (h : cont_diff 𝕜 n f₂) (hn : 1 ≤ n) : continuous (deriv f₂) := (cont_diff_succ_iff_deriv.mp (h.of_le hn)).2.continuous @@ -2977,7 +2938,7 @@ over `𝕜`. variables (𝕜) {𝕜' : Type*} [nondiscrete_normed_field 𝕜'] [normed_algebra 𝕜 𝕜'] variables [normed_space 𝕜' E] [is_scalar_tower 𝕜 𝕜' E] variables [normed_space 𝕜' F] [is_scalar_tower 𝕜 𝕜' F] -variables {p' : E → formal_multilinear_series 𝕜' E F} {n : with_top ℕ} +variables {p' : E → formal_multilinear_series 𝕜' E F} lemma has_ftaylor_series_up_to_on.restrict_scalars (h : has_ftaylor_series_up_to_on n f p' s) : From b2518beef5f00e5d8515419f5522df13165d4592 Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Wed, 20 Apr 2022 22:44:21 +0000 Subject: [PATCH 106/373] feat(analysis/normed/normed_field): add `one_le_(nn)norm_one` for nontrivial normed rings (#13556) Co-authored-by: Eric Wieser --- src/analysis/normed/normed_field.lean | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/analysis/normed/normed_field.lean b/src/analysis/normed/normed_field.lean index 7ca752c84cac2..9edf04a48fd24 100644 --- a/src/analysis/normed/normed_field.lean +++ b/src/analysis/normed/normed_field.lean @@ -137,6 +137,13 @@ lemma nnnorm_mul_le (a b : α) : ∥a * b∥₊ ≤ ∥a∥₊ * ∥b∥₊ := by simpa only [←norm_to_nnreal, ←real.to_nnreal_mul (norm_nonneg _)] using real.to_nnreal_mono (norm_mul_le _ _) +lemma one_le_norm_one (β) [normed_ring β] [nontrivial β] : 1 ≤ ∥(1 : β)∥ := +(le_mul_iff_one_le_left $ norm_pos_iff.mpr (one_ne_zero : (1 : β) ≠ 0)).mp + (by simpa only [mul_one] using norm_mul_le (1 : β) 1) + +lemma one_le_nnnorm_one (β) [normed_ring β] [nontrivial β] : 1 ≤ ∥(1 : β)∥₊ := +one_le_norm_one β + lemma filter.tendsto.zero_mul_is_bounded_under_le {f g : ι → α} {l : filter ι} (hf : tendsto f l (𝓝 0)) (hg : is_bounded_under (≤) l (norm ∘ g)) : tendsto (λ x, f x * g x) l (𝓝 0) := From c93b99fab5343cd511b62751ad3d8aff8ab8a2e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Thu, 21 Apr 2022 01:41:41 +0000 Subject: [PATCH 107/373] chore(algebra/group/defs): Declare `field_simps` attribute earlier (#13543) Declaring `field_simps` earlier make the relevant lemmas taggable as they are declared. --- src/algebra/field/basic.lean | 2 -- src/algebra/group/basic.lean | 4 ++-- src/algebra/group/defs.lean | 4 ++++ src/algebra/group_with_zero/basic.lean | 6 ------ 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/algebra/field/basic.lean b/src/algebra/field/basic.lean index 595d53b38f176..0a9164f5a400a 100644 --- a/src/algebra/field/basic.lean +++ b/src/algebra/field/basic.lean @@ -64,8 +64,6 @@ instance division_ring.to_group_with_zero : { .. ‹division_ring K›, .. (infer_instance : semiring K) } -attribute [field_simps] inv_eq_one_div - local attribute [simp] division_def mul_comm mul_assoc mul_left_comm mul_inv_cancel inv_mul_cancel diff --git a/src/algebra/group/basic.lean b/src/algebra/group/basic.lean index a3ddf47309785..fb96cf015dd77 100644 --- a/src/algebra/group/basic.lean +++ b/src/algebra/group/basic.lean @@ -193,7 +193,7 @@ section div_inv_monoid variables {G : Type u} [div_inv_monoid G] -@[to_additive] +@[to_additive, field_simps] -- The attributes are out of order on purpose lemma inv_eq_one_div (x : G) : x⁻¹ = 1 / x := by rw [div_eq_mul_inv, one_mul] @@ -207,7 +207,7 @@ by rw [div_eq_mul_inv, one_mul, div_eq_mul_inv] lemma mul_div_assoc (a b c : G) : a * b / c = a * (b / c) := by rw [div_eq_mul_inv, div_eq_mul_inv, mul_assoc _ _ _] -@[to_additive] +@[to_additive, field_simps] -- The attributes are out of order on purpose lemma mul_div_assoc' (a b c : G) : a * (b / c) = (a * b) / c := (mul_div_assoc _ _ _).symm diff --git a/src/algebra/group/defs.lean b/src/algebra/group/defs.lean index 8432406eb710e..caeb898d875e6 100644 --- a/src/algebra/group/defs.lean +++ b/src/algebra/group/defs.lean @@ -80,6 +80,10 @@ universe u to the additive one. -/ +mk_simp_attribute field_simps "The simpset `field_simps` is used by the tactic `field_simp` to +reduce an expression in a field to an expression of the form `n / d` where `n` and `d` are +division-free." + section has_mul variables {G : Type u} [has_mul G] diff --git a/src/algebra/group_with_zero/basic.lean b/src/algebra/group_with_zero/basic.lean index f6215fade5726..c838911267331 100644 --- a/src/algebra/group_with_zero/basic.lean +++ b/src/algebra/group_with_zero/basic.lean @@ -40,12 +40,6 @@ open function variables {M₀ G₀ M₀' G₀' : Type*} -mk_simp_attribute field_simps "The simpset `field_simps` is used by the tactic `field_simp` to -reduce an expression in a field to an expression of the form `n / d` where `n` and `d` are -division-free." - -attribute [field_simps] mul_div_assoc' - section section mul_zero_class From 2f1a4aff21c9aadf7cfb96911734754d6c228029 Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Thu, 21 Apr 2022 03:36:36 +0000 Subject: [PATCH 108/373] feat(algebra/hom/non_unital_alg): introduce notation for non-unital algebra homomorphisms (#13470) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This introduces the notation `A →ₙₐ[R] B` for `non_unital_alg_hom R A B` to mirror that of `non_unital_ring_hom R S` as `R →ₙ+* S` from #13430. Here, the `ₙ` stands for "non-unital". --- src/algebra/algebra/unitization.lean | 4 +- .../free_non_unital_non_assoc_algebra.lean | 10 +-- src/algebra/hom/non_unital_alg.lean | 85 ++++++++++--------- src/algebra/lie/free.lean | 2 +- .../lie/non_unital_non_assoc_algebra.lean | 4 +- src/algebra/monoid_algebra/basic.lean | 14 +-- .../algebra/module/character_space.lean | 2 +- .../continuous_function/zero_at_infty.lean | 2 +- 8 files changed, 63 insertions(+), 60 deletions(-) diff --git a/src/algebra/algebra/unitization.lean b/src/algebra/algebra/unitization.lean index b18aabb988a30..b21beee7f5a81 100644 --- a/src/algebra/algebra/unitization.lean +++ b/src/algebra/algebra/unitization.lean @@ -467,7 +467,7 @@ section coe realized as a non-unital algebra homomorphism. -/ @[simps] def coe_non_unital_alg_hom (R A : Type*) [comm_semiring R] [non_unital_semiring A] [module R A] : - non_unital_alg_hom R A (unitization R A) := + A →ₙₐ[R] unitization R A := { to_fun := coe, map_smul' := coe_smul R, map_zero' := coe_zero R, @@ -505,7 +505,7 @@ alg_hom_ext (non_unital_alg_hom.congr_fun h) (by simp [alg_hom.commutes]) /-- Non-unital algebra homomorphisms from `A` into a unital `R`-algebra `C` lift uniquely to `unitization R A →ₐ[R] C`. This is the universal property of the unitization. -/ @[simps apply_apply] -def lift : non_unital_alg_hom R A C ≃ (unitization R A →ₐ[R] C) := +def lift : (A →ₙₐ[R] C) ≃ (unitization R A →ₐ[R] C) := { to_fun := λ φ, { to_fun := λ x, algebra_map R C x.fst + φ x.snd, map_one' := by simp only [fst_one, map_one, snd_one, φ.map_zero, add_zero], diff --git a/src/algebra/free_non_unital_non_assoc_algebra.lean b/src/algebra/free_non_unital_non_assoc_algebra.lean index 5a16c88ec76a3..3b1a15738d151 100644 --- a/src/algebra/free_non_unital_non_assoc_algebra.lean +++ b/src/algebra/free_non_unital_non_assoc_algebra.lean @@ -58,10 +58,10 @@ variables [module R A] [is_scalar_tower R A A] [smul_comm_class R A A] /-- The functor `X ↦ free_non_unital_non_assoc_algebra R X` from the category of types to the category of non-unital, non-associative algebras over `R` is adjoint to the forgetful functor in the other direction. -/ -def lift : (X → A) ≃ non_unital_alg_hom R (free_non_unital_non_assoc_algebra R X) A := +def lift : (X → A) ≃ (free_non_unital_non_assoc_algebra R X →ₙₐ[R] A) := free_magma.lift.trans (monoid_algebra.lift_magma R) -@[simp] lemma lift_symm_apply (F : non_unital_alg_hom R (free_non_unital_non_assoc_algebra R X) A) : +@[simp] lemma lift_symm_apply (F : free_non_unital_non_assoc_algebra R X →ₙₐ[R] A) : (lift R).symm F = F ∘ (of R) := rfl @@ -69,18 +69,18 @@ rfl (lift R).left_inv f @[simp] lemma lift_unique - (f : X → A) (F : non_unital_alg_hom R (free_non_unital_non_assoc_algebra R X) A) : + (f : X → A) (F : free_non_unital_non_assoc_algebra R X →ₙₐ[R] A) : F ∘ (of R) = f ↔ F = lift R f := (lift R).symm_apply_eq @[simp] lemma lift_of_apply (f : X → A) (x) : lift R f (of R x) = f x := congr_fun (of_comp_lift _ f) x -@[simp] lemma lift_comp_of (F : non_unital_alg_hom R (free_non_unital_non_assoc_algebra R X) A) : +@[simp] lemma lift_comp_of (F : free_non_unital_non_assoc_algebra R X →ₙₐ[R] A) : lift R (F ∘ (of R)) = F := (lift R).apply_symm_apply F -@[ext] lemma hom_ext {F₁ F₂ : non_unital_alg_hom R (free_non_unital_non_assoc_algebra R X) A} +@[ext] lemma hom_ext {F₁ F₂ : free_non_unital_non_assoc_algebra R X →ₙₐ[R] A} (h : ∀ x, F₁ (of R x) = F₂ (of R x)) : F₁ = F₂ := (lift R).symm.injective $ funext h diff --git a/src/algebra/hom/non_unital_alg.lean b/src/algebra/hom/non_unital_alg.lean index a32b7ae3c1bd4..f31095bbddca4 100644 --- a/src/algebra/hom/non_unital_alg.lean +++ b/src/algebra/hom/non_unital_alg.lean @@ -54,6 +54,9 @@ structure non_unital_alg_hom [monoid R] [non_unital_non_assoc_semiring B] [distrib_mul_action R B] extends A →+[R] B, A →ₙ* B +infixr ` →ₙₐ `:25 := non_unital_alg_hom _ +notation A ` →ₙₐ[`:25 R `] ` B := non_unital_alg_hom R A B + attribute [nolint doc_blame] non_unital_alg_hom.to_distrib_mul_action_hom attribute [nolint doc_blame] non_unital_alg_hom.to_mul_hom @@ -65,123 +68,123 @@ variables [non_unital_non_assoc_semiring B] [distrib_mul_action R B] variables [non_unital_non_assoc_semiring C] [distrib_mul_action R C] /-- see Note [function coercion] -/ -instance : has_coe_to_fun (non_unital_alg_hom R A B) (λ _, A → B) := ⟨to_fun⟩ +instance : has_coe_to_fun (A →ₙₐ[R] B) (λ _, A → B) := ⟨to_fun⟩ -@[simp] lemma to_fun_eq_coe (f : non_unital_alg_hom R A B) : f.to_fun = ⇑f := rfl +@[simp] lemma to_fun_eq_coe (f : A →ₙₐ[R] B) : f.to_fun = ⇑f := rfl initialize_simps_projections non_unital_alg_hom (to_fun → apply) lemma coe_injective : - @function.injective (non_unital_alg_hom R A B) (A → B) coe_fn := + @function.injective (A →ₙₐ[R] B) (A → B) coe_fn := by rintro ⟨f, _⟩ ⟨g, _⟩ ⟨h⟩; congr -@[ext] lemma ext {f g : non_unital_alg_hom R A B} (h : ∀ x, f x = g x) : f = g := +@[ext] lemma ext {f g : A →ₙₐ[R] B} (h : ∀ x, f x = g x) : f = g := coe_injective $ funext h -lemma ext_iff {f g : non_unital_alg_hom R A B} : f = g ↔ ∀ x, f x = g x := +lemma ext_iff {f g : A →ₙₐ[R] B} : f = g ↔ ∀ x, f x = g x := ⟨by { rintro rfl x, refl }, ext⟩ -lemma congr_fun {f g : non_unital_alg_hom R A B} (h : f = g) (x : A) : f x = g x := h ▸ rfl +lemma congr_fun {f g : A →ₙₐ[R] B} (h : f = g) (x : A) : f x = g x := h ▸ rfl @[simp] lemma coe_mk (f : A → B) (h₁ h₂ h₃ h₄) : - ((⟨f, h₁, h₂, h₃, h₄⟩ : non_unital_alg_hom R A B) : A → B) = f := + ((⟨f, h₁, h₂, h₃, h₄⟩ : A →ₙₐ[R] B) : A → B) = f := rfl -@[simp] lemma mk_coe (f : non_unital_alg_hom R A B) (h₁ h₂ h₃ h₄) : - (⟨f, h₁, h₂, h₃, h₄⟩ : non_unital_alg_hom R A B) = f := +@[simp] lemma mk_coe (f : A →ₙₐ[R] B) (h₁ h₂ h₃ h₄) : + (⟨f, h₁, h₂, h₃, h₄⟩ : A →ₙₐ[R] B) = f := by { ext, refl, } -instance : has_coe (non_unital_alg_hom R A B) (A →+[R] B) := +instance : has_coe (A →ₙₐ[R] B) (A →+[R] B) := ⟨to_distrib_mul_action_hom⟩ -instance : has_coe (non_unital_alg_hom R A B) (A →ₙ* B) := ⟨to_mul_hom⟩ +instance : has_coe (A →ₙₐ[R] B) (A →ₙ* B) := ⟨to_mul_hom⟩ -@[simp] lemma to_distrib_mul_action_hom_eq_coe (f : non_unital_alg_hom R A B) : +@[simp] lemma to_distrib_mul_action_hom_eq_coe (f : A →ₙₐ[R] B) : f.to_distrib_mul_action_hom = ↑f := rfl -@[simp] lemma to_mul_hom_eq_coe (f : non_unital_alg_hom R A B) : f.to_mul_hom = ↑f := +@[simp] lemma to_mul_hom_eq_coe (f : A →ₙₐ[R] B) : f.to_mul_hom = ↑f := rfl -@[simp, norm_cast] lemma coe_to_distrib_mul_action_hom (f : non_unital_alg_hom R A B) : +@[simp, norm_cast] lemma coe_to_distrib_mul_action_hom (f : A →ₙₐ[R] B) : ((f : A →+[R] B) : A → B) = f := rfl -@[simp, norm_cast] lemma coe_to_mul_hom (f : non_unital_alg_hom R A B) : +@[simp, norm_cast] lemma coe_to_mul_hom (f : A →ₙₐ[R] B) : ((f : A →ₙ* B) : A → B) = f := rfl -lemma to_distrib_mul_action_hom_injective {f g : non_unital_alg_hom R A B} +lemma to_distrib_mul_action_hom_injective {f g : A →ₙₐ[R] B} (h : (f : A →+[R] B) = (g : A →+[R] B)) : f = g := by { ext a, exact distrib_mul_action_hom.congr_fun h a, } -lemma to_mul_hom_injective {f g : non_unital_alg_hom R A B} +lemma to_mul_hom_injective {f g : A →ₙₐ[R] B} (h : (f : A →ₙ* B) = (g : A →ₙ* B)) : f = g := by { ext a, exact mul_hom.congr_fun h a, } -@[norm_cast] lemma coe_distrib_mul_action_hom_mk (f : non_unital_alg_hom R A B) (h₁ h₂ h₃ h₄) : - ((⟨f, h₁, h₂, h₃, h₄⟩ : non_unital_alg_hom R A B) : A →+[R] B) = +@[norm_cast] lemma coe_distrib_mul_action_hom_mk (f : A →ₙₐ[R] B) (h₁ h₂ h₃ h₄) : + ((⟨f, h₁, h₂, h₃, h₄⟩ : A →ₙₐ[R] B) : A →+[R] B) = ⟨f, h₁, h₂, h₃⟩ := by { ext, refl, } -@[norm_cast] lemma coe_mul_hom_mk (f : non_unital_alg_hom R A B) (h₁ h₂ h₃ h₄) : - ((⟨f, h₁, h₂, h₃, h₄⟩ : non_unital_alg_hom R A B) : A →ₙ* B) = ⟨f, h₄⟩ := +@[norm_cast] lemma coe_mul_hom_mk (f : A →ₙₐ[R] B) (h₁ h₂ h₃ h₄) : + ((⟨f, h₁, h₂, h₃, h₄⟩ : A →ₙₐ[R] B) : A →ₙ* B) = ⟨f, h₄⟩ := by { ext, refl, } -@[simp] lemma map_smul (f : non_unital_alg_hom R A B) (c : R) (x : A) : +@[simp] lemma map_smul (f : A →ₙₐ[R] B) (c : R) (x : A) : f (c • x) = c • f x := f.to_distrib_mul_action_hom.map_smul c x -@[simp] lemma map_add (f : non_unital_alg_hom R A B) (x y : A) : +@[simp] lemma map_add (f : A →ₙₐ[R] B) (x y : A) : f (x + y) = (f x) + (f y) := f.to_distrib_mul_action_hom.map_add x y -@[simp] lemma map_mul (f : non_unital_alg_hom R A B) (x y : A) : +@[simp] lemma map_mul (f : A →ₙₐ[R] B) (x y : A) : f (x * y) = (f x) * (f y) := f.to_mul_hom.map_mul x y -@[simp] lemma map_zero (f : non_unital_alg_hom R A B) : f 0 = 0 := +@[simp] lemma map_zero (f : A →ₙₐ[R] B) : f 0 = 0 := f.to_distrib_mul_action_hom.map_zero -instance : has_zero (non_unital_alg_hom R A B) := +instance : has_zero (A →ₙₐ[R] B) := ⟨{ map_mul' := by simp, .. (0 : A →+[R] B) }⟩ -instance : has_one (non_unital_alg_hom R A A) := +instance : has_one (A →ₙₐ[R] A) := ⟨{ map_mul' := by simp, .. (1 : A →+[R] A) }⟩ -@[simp] lemma coe_zero : ((0 : non_unital_alg_hom R A B) : A → B) = 0 := rfl +@[simp] lemma coe_zero : ((0 : A →ₙₐ[R] B) : A → B) = 0 := rfl -@[simp] lemma coe_one : ((1 : non_unital_alg_hom R A A) : A → A) = id := rfl +@[simp] lemma coe_one : ((1 : A →ₙₐ[R] A) : A → A) = id := rfl -lemma zero_apply (a : A) : (0 : non_unital_alg_hom R A B) a = 0 := rfl +lemma zero_apply (a : A) : (0 : A →ₙₐ[R] B) a = 0 := rfl -lemma one_apply (a : A) : (1 : non_unital_alg_hom R A A) a = a := rfl +lemma one_apply (a : A) : (1 : A →ₙₐ[R] A) a = a := rfl -instance : inhabited (non_unital_alg_hom R A B) := ⟨0⟩ +instance : inhabited (A →ₙₐ[R] B) := ⟨0⟩ /-- The composition of morphisms is a morphism. -/ -def comp (f : non_unital_alg_hom R B C) (g : non_unital_alg_hom R A B) : non_unital_alg_hom R A C := +def comp (f : B →ₙₐ[R] C) (g : A →ₙₐ[R] B) : A →ₙₐ[R] C := { .. (f : B →ₙ* C).comp (g : A →ₙ* B), .. (f : B →+[R] C).comp (g : A →+[R] B) } -@[simp, norm_cast] lemma coe_comp (f : non_unital_alg_hom R B C) (g : non_unital_alg_hom R A B) : +@[simp, norm_cast] lemma coe_comp (f : B →ₙₐ[R] C) (g : A →ₙₐ[R] B) : (f.comp g : A → C) = (f : B → C) ∘ (g : A → B) := rfl -lemma comp_apply (f : non_unital_alg_hom R B C) (g : non_unital_alg_hom R A B) (x : A) : +lemma comp_apply (f : B →ₙₐ[R] C) (g : A →ₙₐ[R] B) (x : A) : f.comp g x = f (g x) := rfl /-- The inverse of a bijective morphism is a morphism. -/ -def inverse (f : non_unital_alg_hom R A B) (g : B → A) +def inverse (f : A →ₙₐ[R] B) (g : B → A) (h₁ : function.left_inverse g f) (h₂ : function.right_inverse g f) : - non_unital_alg_hom R B A := + B →ₙₐ[R] A := { .. (f : A →ₙ* B).inverse g h₁ h₂, .. (f : A →+[R] B).inverse g h₁ h₂ } -@[simp] lemma coe_inverse (f : non_unital_alg_hom R A B) (g : B → A) +@[simp] lemma coe_inverse (f : A →ₙₐ[R] B) (g : B → A) (h₁ : function.left_inverse g f) (h₂ : function.right_inverse g f) : (inverse f g h₁ h₂ : B → A) = g := rfl @@ -193,17 +196,17 @@ namespace alg_hom variables {R A B} [comm_semiring R] [semiring A] [semiring B] [algebra R A] [algebra R B] /-- A unital morphism of algebras is a `non_unital_alg_hom`. -/ -def to_non_unital_alg_hom (f : A →ₐ[R] B) : non_unital_alg_hom R A B := +def to_non_unital_alg_hom (f : A →ₐ[R] B) : A →ₙₐ[R] B := { map_smul' := f.map_smul, .. f, } -instance non_unital_alg_hom.has_coe : has_coe (A →ₐ[R] B) (non_unital_alg_hom R A B) := +instance non_unital_alg_hom.has_coe : has_coe (A →ₐ[R] B) (A →ₙₐ[R] B) := ⟨to_non_unital_alg_hom⟩ @[simp] lemma to_non_unital_alg_hom_eq_coe (f : A →ₐ[R] B) : f.to_non_unital_alg_hom = f := rfl @[simp, norm_cast] lemma coe_to_non_unital_alg_hom (f : A →ₐ[R] B) : - ((f : non_unital_alg_hom R A B) : A → B) = f := + ((f : A →ₙₐ[R] B) : A → B) = f := rfl end alg_hom diff --git a/src/algebra/lie/free.lean b/src/algebra/lie/free.lean index 74cc4eff817a5..0bb0e5c04bd27 100644 --- a/src/algebra/lie/free.lean +++ b/src/algebra/lie/free.lean @@ -201,7 +201,7 @@ begin end /-- The quotient map as a `non_unital_alg_hom`. -/ -def mk : non_unital_alg_hom R (lib R X) (free_lie_algebra R X) := +def mk : lib R X →ₙₐ[R] free_lie_algebra R X := { to_fun := quot.mk (rel R X), map_smul' := λ t a, rfl, map_zero' := rfl, diff --git a/src/algebra/lie/non_unital_non_assoc_algebra.lean b/src/algebra/lie/non_unital_non_assoc_algebra.lean index 99891acb554e9..8ccd3e24c3417 100644 --- a/src/algebra/lie/non_unital_non_assoc_algebra.lean +++ b/src/algebra/lie/non_unital_non_assoc_algebra.lean @@ -66,14 +66,14 @@ variables {R L} {L₂ : Type w} [lie_ring L₂] [lie_algebra R L₂] /-- Regarding the `lie_ring` of a `lie_algebra` as a `non_unital_non_assoc_semiring`, we can regard a `lie_hom` as a `non_unital_alg_hom`. -/ @[simps] -def to_non_unital_alg_hom (f : L →ₗ⁅R⁆ L₂) : non_unital_alg_hom R L L₂ := +def to_non_unital_alg_hom (f : L →ₗ⁅R⁆ L₂) : L →ₙₐ[R] L₂ := { to_fun := f, map_zero' := f.map_zero, map_mul' := f.map_lie, ..f } lemma to_non_unital_alg_hom_injective : - function.injective (to_non_unital_alg_hom : _ → non_unital_alg_hom R L L₂) := + function.injective (to_non_unital_alg_hom : _ → (L →ₙₐ[R] L₂)) := λ f g h, ext $ non_unital_alg_hom.congr_fun h end lie_hom diff --git a/src/algebra/monoid_algebra/basic.lean b/src/algebra/monoid_algebra/basic.lean index 9b3b2d2f2dace..4c434ff6906b9 100644 --- a/src/algebra/monoid_algebra/basic.lean +++ b/src/algebra/monoid_algebra/basic.lean @@ -495,7 +495,7 @@ variables {A : Type u₃} [non_unital_non_assoc_semiring A] /-- A non_unital `k`-algebra homomorphism from `monoid_algebra k G` is uniquely defined by its values on the functions `single a 1`. -/ lemma non_unital_alg_hom_ext [distrib_mul_action k A] - {φ₁ φ₂ : non_unital_alg_hom k (monoid_algebra k G) A} + {φ₁ φ₂ : monoid_algebra k G →ₙₐ[k] A} (h : ∀ x, φ₁ (single x 1) = φ₂ (single x 1)) : φ₁ = φ₂ := non_unital_alg_hom.to_distrib_mul_action_hom_injective $ finsupp.distrib_mul_action_hom_ext' $ @@ -503,14 +503,14 @@ non_unital_alg_hom.to_distrib_mul_action_hom_injective $ /-- See note [partially-applied ext lemmas]. -/ @[ext] lemma non_unital_alg_hom_ext' [distrib_mul_action k A] - {φ₁ φ₂ : non_unital_alg_hom k (monoid_algebra k G) A} + {φ₁ φ₂ : monoid_algebra k G →ₙₐ[k] A} (h : φ₁.to_mul_hom.comp (of_magma k G) = φ₂.to_mul_hom.comp (of_magma k G)) : φ₁ = φ₂ := non_unital_alg_hom_ext k $ mul_hom.congr_fun h /-- The functor `G ↦ monoid_algebra k G`, from the category of magmas to the category of non-unital, non-associative algebras over `k` is adjoint to the forgetful functor in the other direction. -/ @[simps] def lift_magma [module k A] [is_scalar_tower k A A] [smul_comm_class k A A] : - (G →ₙ* A) ≃ non_unital_alg_hom k (monoid_algebra k G) A := + (G →ₙ* A) ≃ (monoid_algebra k G →ₙₐ[k] A) := { to_fun := λ f, { to_fun := λ a, a.sum (λ m t, t • f m), map_smul' := λ t' a, @@ -1307,13 +1307,13 @@ variables {A : Type u₃} [non_unital_non_assoc_semiring A] /-- A non_unital `k`-algebra homomorphism from `add_monoid_algebra k G` is uniquely defined by its values on the functions `single a 1`. -/ lemma non_unital_alg_hom_ext [distrib_mul_action k A] - {φ₁ φ₂ : non_unital_alg_hom k (add_monoid_algebra k G) A} + {φ₁ φ₂ : add_monoid_algebra k G →ₙₐ[k] A} (h : ∀ x, φ₁ (single x 1) = φ₂ (single x 1)) : φ₁ = φ₂ := @monoid_algebra.non_unital_alg_hom_ext k (multiplicative G) _ _ _ _ _ φ₁ φ₂ h /-- See note [partially-applied ext lemmas]. -/ @[ext] lemma non_unital_alg_hom_ext' [distrib_mul_action k A] - {φ₁ φ₂ : non_unital_alg_hom k (add_monoid_algebra k G) A} + {φ₁ φ₂ : add_monoid_algebra k G →ₙₐ[k] A} (h : φ₁.to_mul_hom.comp (of_magma k G) = φ₂.to_mul_hom.comp (of_magma k G)) : φ₁ = φ₂ := @monoid_algebra.non_unital_alg_hom_ext' k (multiplicative G) _ _ _ _ _ φ₁ φ₂ h @@ -1321,11 +1321,11 @@ lemma non_unital_alg_hom_ext [distrib_mul_action k A] non-unital, non-associative algebras over `k` is adjoint to the forgetful functor in the other direction. -/ @[simps] def lift_magma [module k A] [is_scalar_tower k A A] [smul_comm_class k A A] : - (multiplicative G →ₙ* A) ≃ non_unital_alg_hom k (add_monoid_algebra k G) A := + (multiplicative G →ₙ* A) ≃ (add_monoid_algebra k G →ₙₐ[k] A) := { to_fun := λ f, { to_fun := λ a, sum a (λ m t, t • f (multiplicative.of_add m)), .. (monoid_algebra.lift_magma k f : _)}, inv_fun := λ F, F.to_mul_hom.comp (of_magma k G), - .. (monoid_algebra.lift_magma k : (multiplicative G →ₙ* A) ≃ non_unital_alg_hom k _ A) } + .. (monoid_algebra.lift_magma k : (multiplicative G →ₙ* A) ≃ (_ →ₙₐ[k] A)) } end non_unital_non_assoc_algebra diff --git a/src/topology/algebra/module/character_space.lean b/src/topology/algebra/module/character_space.lean index dd571bad26213..52af6ec0680fb 100644 --- a/src/topology/algebra/module/character_space.lean +++ b/src/topology/algebra/module/character_space.lean @@ -63,7 +63,7 @@ def to_clm (φ : character_space 𝕜 A) : A →L[𝕜] 𝕜 := (φ : weak_dual lemma to_clm_apply (φ : character_space 𝕜 A) (x : A) : φ x = to_clm φ x := rfl /-- An element of the character space, as an non-unital algebra homomorphism. -/ -@[simps] def to_non_unital_alg_hom (φ : character_space 𝕜 A) : non_unital_alg_hom 𝕜 A 𝕜 := +@[simps] def to_non_unital_alg_hom (φ : character_space 𝕜 A) : A →ₙₐ[𝕜] 𝕜 := { to_fun := (φ : A → 𝕜), map_mul' := φ.prop.2, map_smul' := (to_clm φ).map_smul, diff --git a/src/topology/continuous_function/zero_at_infty.lean b/src/topology/continuous_function/zero_at_infty.lean index a318af726a967..22dd60256e6ea 100644 --- a/src/topology/continuous_function/zero_at_infty.lean +++ b/src/topology/continuous_function/zero_at_infty.lean @@ -521,7 +521,7 @@ def comp_linear_map [add_comm_monoid δ] [has_continuous_add δ] {R : Type*} /-- Composition as a non-unital algebra homomorphism. -/ def comp_non_unital_alg_hom {R : Type*} [semiring R] [non_unital_non_assoc_semiring δ] [topological_semiring δ] [module R δ] [has_continuous_const_smul R δ] (g : β →co γ) : - non_unital_alg_hom R C₀(γ, δ) C₀(β, δ) := + C₀(γ, δ) →ₙₐ[R] C₀(β, δ) := { to_fun := λ f, f.comp g, map_smul' := λ r f, rfl, map_zero' := rfl, From e0f78ab30b500480e68710c42dfdc5ec6dce1951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Thu, 21 Apr 2022 03:36:38 +0000 Subject: [PATCH 109/373] chore(data/list/cycle): Add basic `simp` lemmas + minor golfing (#13533) --- src/data/list/cycle.lean | 37 ++++++++++++++++++++++++------------ src/data/multiset/basic.lean | 2 +- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/data/list/cycle.lean b/src/data/list/cycle.lean index 5290cf8bdfc75..db014480d2972 100644 --- a/src/data/list/cycle.lean +++ b/src/data/list/cycle.lean @@ -440,7 +440,7 @@ lemma coe_cons_eq_coe_append (l : list α) (a : α) : (↑(a :: l) : cycle α) = quot.sound ⟨1, by rw [rotate_cons_succ, rotate_zero]⟩ /-- The unique empty cycle. -/ -def nil : cycle α := ↑([] : list α) +def nil : cycle α := ([] : list α) @[simp] lemma coe_nil : ↑([] : list α) = @nil α := rfl @@ -448,6 +448,7 @@ rfl @[simp] lemma coe_eq_nil (l : list α) : (l : cycle α) = nil ↔ l = [] := coe_eq_coe.trans is_rotated_nil_iff +/-- For consistency with `list.has_emptyc`. -/ instance : has_emptyc (cycle α) := ⟨nil⟩ @[simp] lemma empty_eq : ∅ = @nil α := @@ -462,7 +463,7 @@ quotient.induction_on' s $ λ l, by { apply list.rec_on l; simp, assumption' } /-- For `x : α`, `s : cycle α`, `x ∈ s` indicates that `x` occurs at least once in `s`. -/ def mem (a : α) (s : cycle α) : Prop := -quot.lift_on s (λ l, a ∈ l) (λ l₁ l₂ (e : l₁ ~r l₂), propext $ e.mem_iff) +quot.lift_on s (λ l, a ∈ l) (λ l₁ l₂ e, propext $ e.mem_iff) instance : has_mem α (cycle α) := ⟨mem⟩ @@ -480,7 +481,7 @@ quotient.rec_on_subsingleton' s (λ l, list.decidable_mem x l) /-- Reverse a `s : cycle α` by reversing the underlying `list`. -/ def reverse (s : cycle α) : cycle α := -quot.map reverse (λ l₁ l₂ (e : l₁ ~r l₂), e.reverse) s +quot.map reverse (λ l₁ l₂, is_rotated.reverse) s @[simp] lemma reverse_coe (l : list α) : (l : cycle α).reverse = l.reverse := rfl @@ -496,7 +497,7 @@ rfl /-- The length of the `s : cycle α`, which is the number of elements, counting duplicates. -/ def length (s : cycle α) : ℕ := -quot.lift_on s length (λ l₁ l₂ (e : l₁ ~r l₂), e.perm.length_eq) +quot.lift_on s length (λ l₁ l₂ e, e.perm.length_eq) @[simp] lemma length_coe (l : list α) : length (l : cycle α) = l.length := rfl @@ -563,7 +564,7 @@ end /-- The `s : cycle α` contains no duplicates. -/ def nodup (s : cycle α) : Prop := -quot.lift_on s nodup (λ l₁ l₂ (e : l₁ ~r l₂), propext $ e.nodup_iff) +quot.lift_on s nodup (λ l₁ l₂ e, propext $ e.nodup_iff) @[simp] lemma nodup_nil : nodup (@nil α) := nodup_nil @@ -595,14 +596,20 @@ end The `s : cycle α` as a `multiset α`. -/ def to_multiset (s : cycle α) : multiset α := -quotient.lift_on' s (λ l, (l : multiset α)) (λ l₁ l₂ (h : l₁ ~r l₂), multiset.coe_eq_coe.mpr h.perm) +quotient.lift_on' s coe (λ l₁ l₂ h, multiset.coe_eq_coe.mpr h.perm) @[simp] lemma coe_to_multiset (l : list α) : (l : cycle α).to_multiset = l := rfl -@[simp] lemma nil_to_multiset : nil.to_multiset = (∅ : multiset α) := +@[simp] lemma nil_to_multiset : nil.to_multiset = (0 : multiset α) := rfl +@[simp] lemma card_to_multiset (s : cycle α) : s.to_multiset.card = s.length := +quotient.induction_on' s (by simp) + +@[simp] lemma to_multiset_eq_nil {s : cycle α} : s.to_multiset = 0 ↔ s = cycle.nil := +quotient.induction_on' s (by simp) + /-- The lift of `list.map`. -/ def map {β : Type*} (f : α → β) : cycle α → cycle β := quotient.map' (list.map f) $ λ l₁ l₂ h, h.map _ @@ -614,13 +621,13 @@ rfl rfl @[simp] lemma map_eq_nil {β : Type*} (f : α → β) (s : cycle α) : map f s = nil ↔ s = nil := -quotient.induction_on' s $ λ l, by simp +quotient.induction_on' s (by simp) /-- The `multiset` of lists that can make the cycle. -/ def lists (s : cycle α) : multiset (list α) := quotient.lift_on' s (λ l, (l.cyclic_permutations : multiset (list α))) $ - λ l₁ l₂ (h : l₁ ~r l₂), by simpa using h.cyclic_permutations.perm + λ l₁ l₂ h, by simpa using h.cyclic_permutations.perm @[simp] lemma lists_coe (l : list α) : lists (l : cycle α) = ↑l.cyclic_permutations := rfl @@ -651,7 +658,7 @@ instance {s : cycle α} : decidable (nontrivial s) := quot.rec_on_subsingleton s decidable_nontrivial_coe instance {s : cycle α} : decidable (nodup s) := -quot.rec_on_subsingleton s (λ (l : list α), list.nodup_decidable l) +quot.rec_on_subsingleton s list.nodup_decidable instance fintype_nodup_cycle [fintype α] : fintype {s : cycle α // s.nodup} := fintype.of_surjective (λ (l : {l : list α // l.nodup}), ⟨l.val, by simpa using l.prop⟩) @@ -667,16 +674,22 @@ fintype.subtype (((finset.univ : finset {s : cycle α // s.nodup}).map def to_finset (s : cycle α) : finset α := s.to_multiset.to_finset +@[simp] theorem to_finset_to_multiset (s : cycle α) : s.to_multiset.to_finset = s.to_finset := +rfl + @[simp] lemma coe_to_finset (l : list α) : (l : cycle α).to_finset = l.to_finset := rfl @[simp] lemma nil_to_finset : (@nil α).to_finset = ∅ := rfl +@[simp] lemma to_finset_eq_nil {s : cycle α} : s.to_finset = ∅ ↔ s = cycle.nil := +quotient.induction_on' s (by simp) + /-- Given a `s : cycle α` such that `nodup s`, retrieve the next element after `x ∈ s`. -/ def next : Π (s : cycle α) (hs : nodup s) (x : α) (hx : x ∈ s), α := λ s, quot.hrec_on s (λ l hn x hx, next l x hx) - (λ l₁ l₂ (h : l₁ ~r l₂), + (λ l₁ l₂ h, function.hfunext (propext h.nodup_iff) (λ h₁ h₂ he, function.hfunext rfl (λ x y hxy, function.hfunext (propext (by simpa [eq_of_heq hxy] using h.mem_iff)) (λ hm hm' he', heq_of_eq (by simpa [eq_of_heq hxy] using is_rotated_next_eq h h₁ _))))) @@ -684,7 +697,7 @@ def next : Π (s : cycle α) (hs : nodup s) (x : α) (hx : x ∈ s), α := /-- Given a `s : cycle α` such that `nodup s`, retrieve the previous element before `x ∈ s`. -/ def prev : Π (s : cycle α) (hs : nodup s) (x : α) (hx : x ∈ s), α := λ s, quot.hrec_on s (λ l hn x hx, prev l x hx) - (λ l₁ l₂ (h : l₁ ~r l₂), + (λ l₁ l₂ h, function.hfunext (propext h.nodup_iff) (λ h₁ h₂ he, function.hfunext rfl (λ x y hxy, function.hfunext (propext (by simpa [eq_of_heq hxy] using h.mem_iff)) (λ hm hm' he', heq_of_eq (by simpa [eq_of_heq hxy] using is_rotated_prev_eq h h₁ _))))) diff --git a/src/data/multiset/basic.lean b/src/data/multiset/basic.lean index f9c3d755e7fc1..7b15c442460d7 100644 --- a/src/data/multiset/basic.lean +++ b/src/data/multiset/basic.lean @@ -56,7 +56,7 @@ instance inhabited_multiset : inhabited (multiset α) := ⟨0⟩ @[simp] theorem coe_nil_eq_zero : (@nil α : multiset α) = 0 := rfl @[simp] theorem empty_eq_zero : (∅ : multiset α) = 0 := rfl -theorem coe_eq_zero (l : list α) : (l : multiset α) = 0 ↔ l = [] := +@[simp] theorem coe_eq_zero (l : list α) : (l : multiset α) = 0 ↔ l = [] := iff.trans coe_eq_coe perm_nil /-! ### `multiset.cons` -/ From 6012c219cdbafff96b0fc939dfa946e6955f42d1 Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Thu, 21 Apr 2022 06:55:01 +0000 Subject: [PATCH 110/373] refactor(algebra/hom/group): generalize a few lemmas to `monoid_hom_class` (#13447) This generalizes a few lemmas to `monoid_hom_class` from `monoid_hom`. In particular, `monoid_hom.injective_iff` has been generalized and renamed to `injective_iff_map_eq_one`. This also deletes `add_monoid_hom.injective_iff`, `ring_hom.injective_iff` and `alg_hom.injective_iff`. All of these are superseded by the generically applicable `injective_iff_map_eq_zero`. --- src/algebra/algebra/basic.lean | 9 +--- src/algebra/field/basic.lean | 3 +- src/algebra/group/ext.lean | 2 +- src/algebra/hom/group.lean | 50 +++++++++---------- src/algebra/module/basic.lean | 2 +- src/algebra/ring/basic.lean | 10 ---- src/algebraic_geometry/function_field.lean | 2 +- src/algebraic_geometry/properties.lean | 2 +- src/data/polynomial/eval.lean | 2 +- src/data/zmod/basic.lean | 2 +- src/field_theory/abel_ruffini.lean | 4 +- src/field_theory/intermediate_field.lean | 2 +- src/field_theory/mv_polynomial.lean | 2 +- src/field_theory/polynomial_galois_group.lean | 2 +- src/field_theory/ratfunc.lean | 2 +- src/field_theory/splitting_field.lean | 4 +- src/group_theory/free_product.lean | 2 +- src/group_theory/perm/basic.lean | 4 +- src/linear_algebra/linear_independent.lean | 3 +- src/linear_algebra/matrix/charpoly/coeff.lean | 2 +- src/number_theory/class_number/finite.lean | 5 +- src/number_theory/function_field.lean | 4 +- src/number_theory/zsqrtd/basic.lean | 2 +- src/ring_theory/algebraic.lean | 6 +-- src/ring_theory/algebraic_independent.lean | 4 +- src/ring_theory/dedekind_domain/ideal.lean | 7 +-- .../dedekind_domain/integral_closure.lean | 4 +- src/ring_theory/fractional_ideal.lean | 5 +- src/ring_theory/ideal/operations.lean | 6 +-- src/ring_theory/ideal/over.lean | 4 +- src/ring_theory/integral_closure.lean | 2 +- src/ring_theory/jacobson.lean | 2 +- src/ring_theory/localization/basic.lean | 2 +- src/ring_theory/localization/integral.lean | 6 +-- src/ring_theory/nullstellensatz.lean | 2 +- src/ring_theory/polynomial/eisenstein.lean | 2 +- src/ring_theory/polynomial/gauss_lemma.lean | 3 +- src/ring_theory/roots_of_unity.lean | 2 +- test/import_order_timeout.lean | 2 +- 39 files changed, 84 insertions(+), 97 deletions(-) diff --git a/src/algebra/algebra/basic.lean b/src/algebra/algebra/basic.lean index b9d3ea1d22334..f2266e8f70a84 100644 --- a/src/algebra/algebra/basic.lean +++ b/src/algebra/algebra/basic.lean @@ -414,7 +414,7 @@ lemma of_algebra_map_injective [semiring A] [algebra R A] [no_zero_divisors A] (h : function.injective (algebra_map R A)) : no_zero_smul_divisors R A := ⟨λ c x hcx, (mul_eq_zero.mp ((smul_def c x).symm.trans hcx)).imp_left - ((algebra_map R A).injective_iff.mp h _)⟩ + ((injective_iff_map_eq_zero (algebra_map R A)).mp h _)⟩ variables (R A) lemma algebra_map_injective [ring A] [nontrivial A] @@ -744,11 +744,6 @@ variables [algebra R A] [algebra R B] (φ : A →ₐ[R] B) end division_ring -theorem injective_iff {R A B : Type*} [comm_semiring R] [ring A] [semiring B] - [algebra R A] [algebra R B] (f : A →ₐ[R] B) : - function.injective f ↔ (∀ x, f x = 0 → x = 0) := -ring_hom.injective_iff (f : A →+* B) - end alg_hom @[simp] lemma rat.smul_one_eq_coe {A : Type*} [division_ring A] [algebra ℚ A] (m : ℚ) : @@ -1434,7 +1429,7 @@ begin { have : function.injective (algebra_map R A) := no_zero_smul_divisors.iff_algebra_map_injective.1 infer_instance, left, - exact (ring_hom.injective_iff _).1 this _ H }, + exact (injective_iff_map_eq_zero _).1 this _ H }, { right, exact H } end diff --git a/src/algebra/field/basic.lean b/src/algebra/field/basic.lean index 0a9164f5a400a..39c1e1b51bf55 100644 --- a/src/algebra/field/basic.lean +++ b/src/algebra/field/basic.lean @@ -305,7 +305,8 @@ lemma map_inv : g x⁻¹ = (g x)⁻¹ := g.to_monoid_with_zero_hom.map_inv x lemma map_div : g (x / y) = g x / g y := g.to_monoid_with_zero_hom.map_div x y -protected lemma injective : function.injective f := f.injective_iff.2 $ λ x, f.map_eq_zero.1 +protected lemma injective : function.injective f := +(injective_iff_map_eq_zero f).2 $ λ x, f.map_eq_zero.1 end diff --git a/src/algebra/group/ext.lean b/src/algebra/group/ext.lean index de83716570013..4371ab068a610 100644 --- a/src/algebra/group/ext.lean +++ b/src/algebra/group/ext.lean @@ -114,7 +114,7 @@ begin exact @monoid_hom.map_zpow' M M m₁ m₂ f (congr_fun h_inv) x m }, have hdiv : m₁.div = m₂.div, { ext a b, - exact @monoid_hom.map_div' M M m₁ m₂ f (congr_fun h_inv) a b }, + exact @map_div' M M _ m₁ m₂ _ f (congr_fun h_inv) a b }, unfreezingI { cases m₁, cases m₂ }, congr, exacts [h_mul, h₁, hpow, h_inv, hdiv, hzpow] end diff --git a/src/algebra/hom/group.lean b/src/algebra/hom/group.lean index 73334b7ab39f9..8df94fc8fb90c 100644 --- a/src/algebra/hom/group.lean +++ b/src/algebra/hom/group.lean @@ -312,6 +312,11 @@ lemma map_div [group G] [group H] [monoid_hom_class F G H] (f : F) (x y : G) : f (x / y) = f x / f y := by rw [div_eq_mul_inv, div_eq_mul_inv, map_mul_inv] +@[to_additive] +theorem map_div' [div_inv_monoid G] [div_inv_monoid H] [monoid_hom_class F G H] (f : F) + (hf : ∀ x, f (x⁻¹) = (f x)⁻¹) (a b : G) : f (a / b) = f a / f b := +by rw [div_eq_mul_inv, div_eq_mul_inv, map_mul, hf] + -- to_additive puts the arguments in the wrong order, so generate an auxiliary lemma, then -- swap its arguments. @[to_additive map_nsmul.aux, simp] theorem map_pow [monoid G] [monoid H] [monoid_hom_class F G H] @@ -667,30 +672,26 @@ add_decl_doc add_monoid_hom.map_add namespace monoid_hom variables {mM : mul_one_class M} {mN : mul_one_class N} {mP : mul_one_class P} -variables [group G] [comm_group H] +variables [group G] [comm_group H] [monoid_hom_class F M N] include mM mN -@[to_additive] -lemma map_mul_eq_one (f : M →* N) {a b : M} (h : a * b = 1) : f a * f b = 1 := -map_mul_eq_one f h - /-- Given a monoid homomorphism `f : M →* N` and an element `x : M`, if `x` has a right inverse, then `f x` has a right inverse too. For elements invertible on both sides see `is_unit.map`. -/ @[to_additive "Given an add_monoid homomorphism `f : M →+ N` and an element `x : M`, if `x` has a right inverse, then `f x` has a right inverse too."] -lemma map_exists_right_inv (f : M →* N) {x : M} (hx : ∃ y, x * y = 1) : +lemma map_exists_right_inv (f : F) {x : M} (hx : ∃ y, x * y = 1) : ∃ y, f x * y = 1 := -let ⟨y, hy⟩ := hx in ⟨f y, f.map_mul_eq_one hy⟩ +let ⟨y, hy⟩ := hx in ⟨f y, map_mul_eq_one f hy⟩ /-- Given a monoid homomorphism `f : M →* N` and an element `x : M`, if `x` has a left inverse, then `f x` has a left inverse too. For elements invertible on both sides see `is_unit.map`. -/ @[to_additive "Given an add_monoid homomorphism `f : M →+ N` and an element `x : M`, if `x` has a left inverse, then `f x` has a left inverse too. For elements invertible on both sides see `is_add_unit.map`."] -lemma map_exists_left_inv (f : M →* N) {x : M} (hx : ∃ y, y * x = 1) : +lemma map_exists_left_inv (f : F) {x : M} (hx : ∃ y, y * x = 1) : ∃ y, y * f x = 1 := -let ⟨y, hy⟩ := hx in ⟨f y, f.map_mul_eq_one hy⟩ +let ⟨y, hy⟩ := hx in ⟨f y, map_mul_eq_one f hy⟩ end monoid_hom @@ -890,11 +891,6 @@ protected theorem monoid_hom.map_zpow' [div_inv_monoid M] [div_inv_monoid N] (f f (a ^ n) = (f a) ^ n := map_zpow' f hf a n -@[to_additive] -theorem monoid_hom.map_div' [div_inv_monoid M] [div_inv_monoid N] (f : M →* N) - (hf : ∀ x, f (x⁻¹) = (f x)⁻¹) (a b : M) : f (a / b) = f a / f b := -by rw [div_eq_mul_inv, div_eq_mul_inv, f.map_mul, hf] - section End namespace monoid @@ -1060,10 +1056,10 @@ by { ext, simp only [mul_apply, function.comp_app, map_mul, coe_comp] } /-- If two homomorphism from a group to a monoid are equal at `x`, then they are equal at `x⁻¹`. -/ @[to_additive "If two homomorphism from an additive group to an additive monoid are equal at `x`, then they are equal at `-x`." ] -lemma eq_on_inv {G} [group G] [monoid M] {f g : G →* M} {x : G} (h : f x = g x) : - f x⁻¹ = g x⁻¹ := +lemma eq_on_inv {G} [group G] [monoid M] [monoid_hom_class F G M] {f g : F} {x : G} + (h : f x = g x) : f x⁻¹ = g x⁻¹ := left_inv_eq_right_inv (map_mul_eq_one f $ inv_mul_self x) $ - h.symm ▸ g.map_mul_eq_one $ mul_inv_self x + h.symm ▸ map_mul_eq_one g $ mul_inv_self x /-- Group homomorphisms preserve inverse. -/ @[to_additive] @@ -1089,24 +1085,24 @@ protected theorem map_mul_inv {G H} [group G] [group H] (f : G →* H) (g h : G) map_mul_inv f g h /-- A homomorphism from a group to a monoid is injective iff its kernel is trivial. -For the iff statement on the triviality of the kernel, see `monoid_hom.injective_iff'`. -/ +For the iff statement on the triviality of the kernel, see `injective_iff_map_eq_one'`. -/ @[to_additive "A homomorphism from an additive group to an additive monoid is injective iff its kernel is trivial. For the iff statement on the triviality of the kernel, -see `add_monoid_hom.injective_iff'`."] -lemma injective_iff {G H} [group G] [mul_one_class H] (f : G →* H) : - function.injective f ↔ (∀ a, f a = 1 → a = 1) := +see `injective_iff_map_eq_zero'`."] +lemma _root_.injective_iff_map_eq_one {G H} [group G] [mul_one_class H] [monoid_hom_class F G H] + (f : F) : function.injective f ↔ (∀ a, f a = 1 → a = 1) := ⟨λ h x, (map_eq_one_iff f h).mp, - λ h x y hxy, mul_inv_eq_one.1 $ h _ $ by rw [f.map_mul, hxy, ← f.map_mul, mul_inv_self, f.map_one]⟩ + λ h x y hxy, mul_inv_eq_one.1 $ h _ $ by rw [map_mul, hxy, ← map_mul, mul_inv_self, map_one]⟩ /-- A homomorphism from a group to a monoid is injective iff its kernel is trivial, stated as an iff on the triviality of the kernel. -For the implication, see `monoid_hom.injective_iff`. -/ +For the implication, see `injective_iff_map_eq_one`. -/ @[to_additive "A homomorphism from an additive group to an additive monoid is injective iff its kernel is trivial, stated as an iff on the triviality of the kernel. For the implication, see -`add_monoid_hom.injective_iff`."] -lemma injective_iff' {G H} [group G] [mul_one_class H] (f : G →* H) : - function.injective f ↔ (∀ a, f a = 1 ↔ a = 1) := -f.injective_iff.trans $ forall_congr $ λ a, ⟨λ h, ⟨h, λ H, H.symm ▸ f.map_one⟩, iff.mp⟩ +`injective_iff_map_eq_zero`."] +lemma _root_.injective_iff_map_eq_one' {G H} [group G] [mul_one_class H] [monoid_hom_class F G H] + (f : F) : function.injective f ↔ (∀ a, f a = 1 ↔ a = 1) := +(injective_iff_map_eq_one f).trans $ forall_congr $ λ a, ⟨λ h, ⟨h, λ H, H.symm ▸ map_one f⟩, iff.mp⟩ include mM /-- Makes a group homomorphism from a proof that the map preserves multiplication. -/ diff --git a/src/algebra/module/basic.lean b/src/algebra/module/basic.lean index cbcc6cbd42a6e..d5a39b6689d19 100644 --- a/src/algebra/module/basic.lean +++ b/src/algebra/module/basic.lean @@ -550,7 +550,7 @@ variables (M) lemma smul_right_injective [no_zero_smul_divisors R M] {c : R} (hc : c ≠ 0) : function.injective ((•) c : M → M) := -(smul_add_hom R M c).injective_iff.2 $ λ a ha, (smul_eq_zero.mp ha).resolve_left hc +(injective_iff_map_eq_zero (smul_add_hom R M c)).2 $ λ a ha, (smul_eq_zero.mp ha).resolve_left hc variables {M} diff --git a/src/algebra/ring/basic.lean b/src/algebra/ring/basic.lean index 57bcef0fa13e1..500f6dd13176d 100644 --- a/src/algebra/ring/basic.lean +++ b/src/algebra/ring/basic.lean @@ -985,16 +985,6 @@ map_neg f x protected theorem map_sub {α β} [non_assoc_ring α] [non_assoc_ring β] (f : α →+* β) (x y : α) : f (x - y) = (f x) - (f y) := map_sub f x y -/-- A ring homomorphism is injective iff its kernel is trivial. -/ -theorem injective_iff {α β} [non_assoc_ring α] [non_assoc_semiring β] (f : α →+* β) : - function.injective f ↔ (∀ a, f a = 0 → a = 0) := -(f : α →+ β).injective_iff - -/-- A ring homomorphism is injective iff its kernel is trivial. -/ -theorem injective_iff' {α β} [non_assoc_ring α] [non_assoc_semiring β] (f : α →+* β) : - function.injective f ↔ (∀ a, f a = 0 ↔ a = 0) := -(f : α →+ β).injective_iff' - /-- Makes a ring homomorphism from a monoid homomorphism of rings which preserves addition. -/ def mk' {γ} [non_assoc_semiring α] [non_assoc_ring γ] (f : α →* γ) (map_add : ∀ a b : α, f (a + b) = f a + f b) : diff --git a/src/algebraic_geometry/function_field.lean b/src/algebraic_geometry/function_field.lean index a3a3ed90ca9c5..b5bbdfe4aaff2 100644 --- a/src/algebraic_geometry/function_field.lean +++ b/src/algebraic_geometry/function_field.lean @@ -65,7 +65,7 @@ end lemma germ_injective_of_is_integral [is_integral X] {U : opens X.carrier} (x : U) : function.injective (X.presheaf.germ x) := begin - rw ring_hom.injective_iff, + rw injective_iff_map_eq_zero, intros y hy, rw ← (X.presheaf.germ x).map_zero at hy, obtain ⟨W, hW, iU, iV, e⟩ := X.presheaf.germ_eq _ x.prop x.prop _ _ hy, diff --git a/src/algebraic_geometry/properties.lean b/src/algebraic_geometry/properties.lean index af4ca9a50fdcc..3bdcd876ef3bf 100644 --- a/src/algebraic_geometry/properties.lean +++ b/src/algebraic_geometry/properties.lean @@ -336,7 +336,7 @@ lemma map_injective_of_is_integral [is_integral X] {U V : opens X.carrier} (i : [H : nonempty U] : function.injective (X.presheaf.map i.op) := begin - rw ring_hom.injective_iff, + rw injective_iff_map_eq_zero, intros x hx, rw ← basic_open_eq_bot_iff at ⊢ hx, rw Scheme.basic_open_res at hx, diff --git a/src/data/polynomial/eval.lean b/src/data/polynomial/eval.lean index 7639dbbba6a04..2aa0a6b0f6d3d 100644 --- a/src/data/polynomial/eval.lean +++ b/src/data/polynomial/eval.lean @@ -866,7 +866,7 @@ by rw [is_root, eval_map, eval₂_hom, h.eq_zero, f.map_zero] lemma is_root.of_map {R} [comm_ring R] {f : R →+* S} {x : R} {p : R[X]} (h : is_root (p.map f) (f x)) (hf : function.injective f) : is_root p x := -by rwa [is_root, ←f.injective_iff'.mp hf, ←eval₂_hom, ←eval_map] +by rwa [is_root, ←(injective_iff_map_eq_zero' f).mp hf, ←eval₂_hom, ←eval_map] lemma is_root_map_iff {R : Type*} [comm_ring R] {f : R →+* S} {x : R} {p : R[X]} (hf : function.injective f) : is_root (p.map f) (f x) ↔ is_root p x := diff --git a/src/data/zmod/basic.lean b/src/data/zmod/basic.lean index bf37477aaa66e..4c5cbe8b11e2b 100644 --- a/src/data/zmod/basic.lean +++ b/src/data/zmod/basic.lean @@ -368,7 +368,7 @@ variables (R) lemma cast_hom_injective : function.injective (zmod.cast_hom (dvd_refl n) R) := begin - rw ring_hom.injective_iff, + rw injective_iff_map_eq_zero, intro x, obtain ⟨k, rfl⟩ := zmod.int_cast_surjective x, rw [ring_hom.map_int_cast, char_p.int_cast_eq_zero_iff R n, diff --git a/src/field_theory/abel_ruffini.lean b/src/field_theory/abel_ruffini.lean index a127bd921c556..fa008eb6e9400 100644 --- a/src/field_theory/abel_ruffini.lean +++ b/src/field_theory/abel_ruffini.lean @@ -123,7 +123,7 @@ begin { rw [ha, C_0, sub_zero], exact gal_X_pow_is_solvable n }, have ha' : algebra_map F (X ^ n - C a).splitting_field a ≠ 0 := - mt ((ring_hom.injective_iff _).mp (ring_hom.injective _) a) ha, + mt ((injective_iff_map_eq_zero _).mp (ring_hom.injective _) a) ha, by_cases hn : n = 0, { rw [hn, pow_zero, ←C_1, ←C_sub], exact gal_C_is_solvable (1 - a) }, @@ -159,7 +159,7 @@ end lemma splits_X_pow_sub_one_of_X_pow_sub_C {F : Type*} [field F] {E : Type*} [field E] (i : F →+* E) (n : ℕ) {a : F} (ha : a ≠ 0) (h : (X ^ n - C a).splits i) : (X ^ n - 1).splits i := begin - have ha' : i a ≠ 0 := mt (i.injective_iff.mp (i.injective) a) ha, + have ha' : i a ≠ 0 := mt ((injective_iff_map_eq_zero i).mp (i.injective) a) ha, by_cases hn : n = 0, { rw [hn, pow_zero, sub_self], exact splits_zero i }, diff --git a/src/field_theory/intermediate_field.lean b/src/field_theory/intermediate_field.lean index cb35c61de6725..ea88ad91f5247 100644 --- a/src/field_theory/intermediate_field.lean +++ b/src/field_theory/intermediate_field.lean @@ -310,7 +310,7 @@ lemma coe_is_integral_iff {R : Type*} [comm_ring R] [algebra R K] [algebra R L] begin refine ⟨λ h, _, λ h, _⟩, { obtain ⟨P, hPmo, hProot⟩ := h, - refine ⟨P, hPmo, (ring_hom.injective_iff _).1 (algebra_map ↥S L).injective _ _⟩, + refine ⟨P, hPmo, (injective_iff_map_eq_zero _).1 (algebra_map ↥S L).injective _ _⟩, letI : is_scalar_tower R S L := is_scalar_tower.of_algebra_map_eq (congr_fun rfl), rwa [eval₂_eq_eval_map, ← eval₂_at_apply, eval₂_eq_eval_map, polynomial.map_map, ← is_scalar_tower.algebra_map_eq, ← eval₂_eq_eval_map] }, diff --git a/src/field_theory/mv_polynomial.lean b/src/field_theory/mv_polynomial.lean index da9836b30caff..8627c5c743ac0 100644 --- a/src/field_theory/mv_polynomial.lean +++ b/src/field_theory/mv_polynomial.lean @@ -29,7 +29,7 @@ variables (σ K) [field K] lemma quotient_mk_comp_C_injective (I : ideal (mv_polynomial σ K)) (hI : I ≠ ⊤) : function.injective ((ideal.quotient.mk I).comp mv_polynomial.C) := begin - refine (ring_hom.injective_iff _).2 (λ x hx, _), + refine (injective_iff_map_eq_zero _).2 (λ x hx, _), rw [ring_hom.comp_apply, ideal.quotient.eq_zero_iff_mem] at hx, refine classical.by_contradiction (λ hx0, absurd (I.eq_top_iff_one.2 _) hI), have := I.mul_mem_left (mv_polynomial.C x⁻¹) hx, diff --git a/src/field_theory/polynomial_galois_group.lean b/src/field_theory/polynomial_galois_group.lean index eeba7342675e5..dd73712774cc3 100644 --- a/src/field_theory/polynomial_galois_group.lean +++ b/src/field_theory/polynomial_galois_group.lean @@ -199,7 +199,7 @@ restrict_smul ϕ x lemma gal_action_hom_injective [fact (p.splits (algebra_map F E))] : function.injective (gal_action_hom p E) := begin - rw monoid_hom.injective_iff, + rw injective_iff_map_eq_one, intros ϕ hϕ, ext x hx, have key := equiv.perm.ext_iff.mp hϕ (roots_equiv_roots p E ⟨x, hx⟩), diff --git a/src/field_theory/ratfunc.lean b/src/field_theory/ratfunc.lean index a68c3ffb0c6a1..cba314c27bc11 100644 --- a/src/field_theory/ratfunc.lean +++ b/src/field_theory/ratfunc.lean @@ -751,7 +751,7 @@ end @[simp] lemma algebra_map_eq_zero_iff {x : K[X]} : algebra_map K[X] (ratfunc K) x = 0 ↔ x = 0 := -⟨(ring_hom.injective_iff _).mp (algebra_map_injective K) _, λ hx, by rw [hx, ring_hom.map_zero]⟩ +⟨(injective_iff_map_eq_zero _).mp (algebra_map_injective K) _, λ hx, by rw [hx, ring_hom.map_zero]⟩ variables {K} diff --git a/src/field_theory/splitting_field.lean b/src/field_theory/splitting_field.lean index 5c147f2d00af9..06699d272c09f 100644 --- a/src/field_theory/splitting_field.lean +++ b/src/field_theory/splitting_field.lean @@ -68,7 +68,7 @@ f = 0 ∨ ∀ {g : L[X]}, irreducible g → g ∣ f.map i → degree g = 1 @[simp] lemma splits_C (a : K) : splits i (C a) := if ha : a = 0 then ha.symm ▸ (@C_0 K _).symm ▸ splits_zero i else -have hia : i a ≠ 0, from mt ((i.injective_iff).1 +have hia : i a ≠ 0, from mt ((injective_iff_map_eq_zero i).1 i.injective _) ha, or.inr $ λ g hg ⟨p, hp⟩, absurd hg.1 (not_not.2 (is_unit_iff_degree_eq_zero.2 $ by have := congr_arg degree hp; @@ -546,7 +546,7 @@ alg_equiv.symm $ alg_equiv.of_bijective (λ p, adjoin_root.induction_on _ p $ λ p, (algebra.adjoin_singleton_eq_range_aeval F x).symm ▸ (polynomial.aeval _).mem_range.mpr ⟨p, rfl⟩)) - ⟨(alg_hom.injective_cod_restrict _ _ _).2 $ (alg_hom.injective_iff _).2 $ λ p, + ⟨(alg_hom.injective_cod_restrict _ _ _).2 $ (injective_iff_map_eq_zero _).2 $ λ p, adjoin_root.induction_on _ p $ λ p hp, ideal.quotient.eq_zero_iff_mem.2 $ ideal.mem_span_singleton.2 $ minpoly.dvd F x hp, λ y, diff --git a/src/group_theory/free_product.lean b/src/group_theory/free_product.lean index f26c786d203bf..b36ecf6efa13a 100644 --- a/src/group_theory/free_product.lean +++ b/src/group_theory/free_product.lean @@ -687,7 +687,7 @@ theorem lift_injective_of_ping_pong: function.injective (lift f) := begin classical, - apply (monoid_hom.injective_iff (lift f)).mpr, + apply (injective_iff_map_eq_one (lift f)).mpr, rw free_product.word.equiv.forall_congr_left', { intros w Heq, dsimp [word.equiv] at *, diff --git a/src/group_theory/perm/basic.lean b/src/group_theory/perm/basic.lean index fc96c9c447c1f..0e0e1c801dbe3 100644 --- a/src/group_theory/perm/basic.lean +++ b/src/group_theory/perm/basic.lean @@ -208,12 +208,12 @@ extend_domain_trans _ _ _ map_mul' := λ e e', (extend_domain_mul f e e').symm } lemma extend_domain_hom_injective : function.injective (extend_domain_hom f) := -((extend_domain_hom f).injective_iff).mpr (λ e he, ext (λ x, f.injective (subtype.ext +(injective_iff_map_eq_one (extend_domain_hom f)).mpr (λ e he, ext (λ x, f.injective (subtype.ext ((extend_domain_apply_image e f x).symm.trans (ext_iff.mp he (f x)))))) @[simp] lemma extend_domain_eq_one_iff {e : perm α} {f : α ≃ subtype p} : e.extend_domain f = 1 ↔ e = 1 := -(extend_domain_hom f).injective_iff'.mp (extend_domain_hom_injective f) e +(injective_iff_map_eq_one' (extend_domain_hom f)).mp (extend_domain_hom_injective f) e end extend_domain diff --git a/src/linear_algebra/linear_independent.lean b/src/linear_algebra/linear_independent.lean index 7b6cd8b6ce506..a680248b08521 100644 --- a/src/linear_algebra/linear_independent.lean +++ b/src/linear_algebra/linear_independent.lean @@ -438,7 +438,8 @@ variables {a b : R} {x y : M} theorem linear_independent_iff_injective_total : linear_independent R v ↔ function.injective (finsupp.total ι M R v) := -linear_independent_iff.trans (finsupp.total ι M R v).to_add_monoid_hom.injective_iff.symm +linear_independent_iff.trans + (injective_iff_map_eq_zero (finsupp.total ι M R v).to_add_monoid_hom).symm alias linear_independent_iff_injective_total ↔ linear_independent.injective_total _ diff --git a/src/linear_algebra/matrix/charpoly/coeff.lean b/src/linear_algebra/matrix/charpoly/coeff.lean index 26294609ed39d..7db25d01c7c70 100644 --- a/src/linear_algebra/matrix/charpoly/coeff.lean +++ b/src/linear_algebra/matrix/charpoly/coeff.lean @@ -259,7 +259,7 @@ lemma charpoly_left_mul_matrix {K S : Type*} [field K] [comm_ring S] [algebra K begin apply minpoly.unique, { apply matrix.charpoly_monic }, - { apply (left_mul_matrix _).injective_iff.mp (left_mul_matrix_injective h.basis), + { apply (injective_iff_map_eq_zero (left_mul_matrix _)).mp (left_mul_matrix_injective h.basis), rw [← polynomial.aeval_alg_hom_apply, aeval_self_charpoly] }, { intros q q_monic root_q, rw [matrix.charpoly_degree_eq_dim, fintype.card_fin, degree_eq_nat_degree q_monic.ne_zero], diff --git a/src/number_theory/class_number/finite.lean b/src/number_theory/class_number/finite.lean index b380b9ee4f1ce..353d6ff7ca5a8 100644 --- a/src/number_theory/class_number/finite.lean +++ b/src/number_theory/class_number/finite.lean @@ -62,7 +62,8 @@ begin { by_contra' h, obtain ⟨i⟩ := bS.index_nonempty, apply bS.ne_zero i, - apply (algebra.left_mul_matrix bS).injective_iff.mp (algebra.left_mul_matrix_injective bS), + apply (injective_iff_map_eq_zero (algebra.left_mul_matrix bS)).mp + (algebra.left_mul_matrix_injective bS), ext j k, simp [h, dmatrix.zero_apply] }, simp only [norm_bound, algebra.smul_def, eq_nat_cast, int.nat_cast_eq_coe_nat], @@ -278,7 +279,7 @@ end real lemma prod_finset_approx_ne_zero : algebra_map R S (∏ m in finset_approx bS adm, m) ≠ 0 := begin - refine mt ((ring_hom.injective_iff _).mp bS.algebra_map_injective _) _, + refine mt ((injective_iff_map_eq_zero _).mp bS.algebra_map_injective _) _, simp only [finset.prod_eq_zero_iff, not_exists], rintros x hx rfl, exact finset_approx.zero_not_mem bS adm hx diff --git a/src/number_theory/function_field.lean b/src/number_theory/function_field.lean index 3afd993726b30..6746b06e8c525 100644 --- a/src/number_theory/function_field.lean +++ b/src/number_theory/function_field.lean @@ -114,10 +114,10 @@ begin { rw is_scalar_tower.algebra_map_eq Fq[X] (ratfunc Fq) F, exact function.injective.comp ((algebra_map (ratfunc Fq) F).injective) (is_fraction_ring.injective Fq[X] (ratfunc Fq)), }, - rw (algebra_map Fq[X] ↥(ring_of_integers Fq F)).injective_iff, + rw injective_iff_map_eq_zero (algebra_map Fq[X] ↥(ring_of_integers Fq F)), intros p hp, rw [← subtype.coe_inj, subalgebra.coe_zero] at hp, - rw (algebra_map Fq[X] F).injective_iff at hinj, + rw injective_iff_map_eq_zero (algebra_map Fq[X] F) at hinj, exact hinj p hp, end diff --git a/src/number_theory/zsqrtd/basic.lean b/src/number_theory/zsqrtd/basic.lean index f4f972c69b422..4406377bee55b 100644 --- a/src/number_theory/zsqrtd/basic.lean +++ b/src/number_theory/zsqrtd/basic.lean @@ -760,7 +760,7 @@ def lift {d : ℤ} : {r : R // r * r = ↑d} ≃ (ℤ√d →+* R) := `ℤ` into `R` is injective). -/ lemma lift_injective [char_zero R] {d : ℤ} (r : {r : R // r * r = ↑d}) (hd : ∀ n : ℤ, d ≠ n*n) : function.injective (lift r) := -(lift r).injective_iff.mpr $ λ a ha, +(injective_iff_map_eq_zero (lift r)).mpr $ λ a ha, begin have h_inj : function.injective (coe : ℤ → R) := int.cast_injective, suffices : lift r a.norm = 0, diff --git a/src/ring_theory/algebraic.lean b/src/ring_theory/algebraic.lean index 6861f8cdb66cd..4563dcd834d70 100644 --- a/src/ring_theory/algebraic.lean +++ b/src/ring_theory/algebraic.lean @@ -68,7 +68,7 @@ end lemma is_algebraic_iff_not_injective {x : A} : is_algebraic R x ↔ ¬ function.injective (polynomial.aeval x : R[X] →ₐ[R] A) := -by simp only [is_algebraic, alg_hom.injective_iff, not_forall, and.comm, exists_prop] +by simp only [is_algebraic, injective_iff_map_eq_zero, not_forall, and.comm, exists_prop] end @@ -210,13 +210,13 @@ lemma is_integral_closure.exists_smul_eq_mul {L : Type*} [field L] begin obtain ⟨c, d, d_ne, hx⟩ := exists_integral_multiple (h (algebra_map _ L a / algebra_map _ L b)) - ((ring_hom.injective_iff _).mp inj), + ((injective_iff_map_eq_zero _).mp inj), refine ⟨is_integral_closure.mk' S (c : L) c.2, d, d_ne, is_integral_closure.algebra_map_injective S R L _⟩, simp only [algebra.smul_def, ring_hom.map_mul, is_integral_closure.algebra_map_mk', ← hx, ← is_scalar_tower.algebra_map_apply], rw [← mul_assoc _ (_ / _), mul_div_cancel' (algebra_map S L a), mul_comm], - exact mt ((ring_hom.injective_iff _).mp (is_integral_closure.algebra_map_injective S R L) _) hb + exact mt ((injective_iff_map_eq_zero _).mp (is_integral_closure.algebra_map_injective S R L) _) hb end section field diff --git a/src/ring_theory/algebraic_independent.lean b/src/ring_theory/algebraic_independent.lean index 887b907c064cf..9b7ef29765d7c 100644 --- a/src/ring_theory/algebraic_independent.lean +++ b/src/ring_theory/algebraic_independent.lean @@ -62,7 +62,7 @@ ring_hom.injective_iff_ker_eq_bot _ theorem algebraic_independent_iff : algebraic_independent R x ↔ ∀p : mv_polynomial ι R, mv_polynomial.aeval (x : ι → A) p = 0 → p = 0 := -ring_hom.injective_iff _ +injective_iff_map_eq_zero _ theorem algebraic_independent.eq_zero_of_aeval_eq_zero (h : algebraic_independent R x) : ∀p : mv_polynomial ι R, mv_polynomial.aeval (x : ι → A) p = 0 → p = 0 := @@ -268,7 +268,7 @@ theorem algebraic_independent_comp_subtype {s : set ι} : have (aeval (x ∘ coe : s → A) : _ →ₐ[R] _) = (aeval x).comp (rename coe), by ext; simp, have ∀ p : mv_polynomial s R, rename (coe : s → ι) p = 0 ↔ p = 0, - from (ring_hom.injective_iff' (rename (coe : s → ι) : mv_polynomial s R →ₐ[R] _).to_ring_hom).1 + from (injective_iff_map_eq_zero' (rename (coe : s → ι) : mv_polynomial s R →ₐ[R] _).to_ring_hom).1 (rename_injective _ subtype.val_injective), by simp [algebraic_independent_iff, supported_eq_range_rename, *] diff --git a/src/ring_theory/dedekind_domain/ideal.lean b/src/ring_theory/dedekind_domain/ideal.lean index b1b5cf0c46cbe..63aef98528ce7 100644 --- a/src/ring_theory/dedekind_domain/ideal.lean +++ b/src/ring_theory/dedekind_domain/ideal.lean @@ -387,9 +387,9 @@ begin -- Choose an element `b` of the product that is not in `J`. obtain ⟨b, hbZ, hbJ⟩ := set_like.not_le_iff_exists.mp hnle, have hnz_fa : algebra_map A K a ≠ 0 := - mt ((ring_hom.injective_iff _).mp (is_fraction_ring.injective A K) a) ha0, + mt ((injective_iff_map_eq_zero _).mp (is_fraction_ring.injective A K) a) ha0, have hb0 : algebra_map A K b ≠ 0 := - mt ((ring_hom.injective_iff _).mp (is_fraction_ring.injective A K) b) + mt ((injective_iff_map_eq_zero _).mp (is_fraction_ring.injective A K) b) (λ h, hbJ $ h.symm ▸ J.zero_mem), -- Then `b a⁻¹ : K` is in `M⁻¹` but not in `1`. refine ⟨algebra_map A K b * (algebra_map A K a)⁻¹, (mem_inv_iff _).mpr _, _⟩, @@ -512,7 +512,8 @@ begin rw [mul_assoc, mul_left_comm (J : fractional_ideal A⁰ K), coe_ideal_mul_inv, mul_one, fractional_ideal.span_singleton_mul_span_singleton, inv_mul_cancel, fractional_ideal.span_singleton_one], - { exact mt ((algebra_map A K).injective_iff.mp (is_fraction_ring.injective A K) _) ha }, + { exact mt ((injective_iff_map_eq_zero (algebra_map A K)).mp + (is_fraction_ring.injective A K) _) ha }, { exact fractional_ideal.coe_ideal_ne_zero_iff.mp (right_ne_zero_of_mul hne) } end diff --git a/src/ring_theory/dedekind_domain/integral_closure.lean b/src/ring_theory/dedekind_domain/integral_closure.lean index c96367d782eed..a627b3548870d 100644 --- a/src/ring_theory/dedekind_domain/integral_closure.lean +++ b/src/ring_theory/dedekind_domain/integral_closure.lean @@ -110,7 +110,7 @@ begin { rintros x s hx ⟨y, hy, hs⟩, obtain ⟨x', y', hy', hx'⟩ := exists_integral_multiple ((is_fraction_ring.is_algebraic_iff A K L).mpr (is_algebraic_of_finite _ _ x)) - ((algebra_map A L).injective_iff.mp _), + ((injective_iff_map_eq_zero (algebra_map A L)).mp _), refine ⟨y * y', mul_ne_zero hy hy', λ x'' hx'', _⟩, rcases finset.mem_insert.mp hx'' with (rfl | hx''), { rw [mul_smul, algebra.smul_def, algebra.smul_def, mul_comm _ x'', hx'], @@ -135,7 +135,7 @@ begin let bs' := is_noetherian.finset_basis K L, obtain ⟨y, hy, his'⟩ := exists_integral_multiples A K (finset.univ.image bs'), have hy' : algebra_map A L y ≠ 0, - { refine mt ((algebra_map A L).injective_iff.mp _ _) hy, + { refine mt ((injective_iff_map_eq_zero (algebra_map A L)).mp _ _) hy, rw is_scalar_tower.algebra_map_eq A K L, exact (algebra_map K L).injective.comp (is_fraction_ring.injective A K) }, refine ⟨s', bs'.map { to_fun := λ x, algebra_map A L y * x, diff --git a/src/ring_theory/fractional_ideal.lean b/src/ring_theory/fractional_ideal.lean index 46ba334a5d9bf..a01ca08d79030 100644 --- a/src/ring_theory/fractional_ideal.lean +++ b/src/ring_theory/fractional_ideal.lean @@ -831,7 +831,7 @@ lemma _root_.is_fractional.div_of_nonzero {I J : submodule R₁ K} : have : algebra_map R₁ K aJ * y = 0, { rw [← algebra.smul_def, ←hy', y'_eq_zero, ring_hom.map_zero] }, have y_zero := (mul_eq_zero.mp this).resolve_left - (mt ((algebra_map R₁ K).injective_iff.1 (is_fraction_ring.injective _ _) _) + (mt ((injective_iff_map_eq_zero (algebra_map R₁ K)).1 (is_fraction_ring.injective _ _) _) (mem_non_zero_divisors_iff_ne_zero.mp haJ)), apply not_mem_zero, simpa only using (mem_zero_iff R₁⁰).mpr y_zero, }, @@ -1307,7 +1307,8 @@ begin { rw [hx, ring_hom.map_zero, _root_.inv_zero, span_singleton_zero, zero_mul], exact is_noetherian_zero }, have h_gx : algebra_map R₁ K x ≠ 0, - from mt ((algebra_map R₁ K).injective_iff.mp (is_fraction_ring.injective _ _) x) hx, + from mt ((injective_iff_map_eq_zero (algebra_map R₁ K)).mp + (is_fraction_ring.injective _ _) x) hx, have h_spanx : span_singleton R₁⁰ (algebra_map R₁ K x) ≠ 0, from span_singleton_ne_zero_iff.mpr h_gx, diff --git a/src/ring_theory/ideal/operations.lean b/src/ring_theory/ideal/operations.lean index 94436cec08633..ceb0517b0c1b5 100644 --- a/src/ring_theory/ideal/operations.lean +++ b/src/ring_theory/ideal/operations.lean @@ -1363,10 +1363,10 @@ section ring variables [ring R] [semiring S] (f : R →+* S) lemma injective_iff_ker_eq_bot : function.injective f ↔ ker f = ⊥ := -by { rw [set_like.ext'_iff, ker_eq, set.ext_iff], exact f.injective_iff' } +by { rw [set_like.ext'_iff, ker_eq, set.ext_iff], exact injective_iff_map_eq_zero' f } lemma ker_eq_bot_iff_eq_zero : ker f = ⊥ ↔ ∀ x, f x = 0 → x = 0 := -by { rw [← f.injective_iff, injective_iff_ker_eq_bot] } +by { rw [← injective_iff_map_eq_zero f, injective_iff_ker_eq_bot] } @[simp] lemma ker_coe_equiv (f : R ≃+* S) : ker (f : R →+* S) = ⊥ := by simpa only [←injective_iff_ker_eq_bot] using f.injective @@ -1730,7 +1730,7 @@ lemma quotient_equiv_symm_mk (I : ideal R) (J : ideal S) (f : R ≃+* S) lemma quotient_map_injective' {J : ideal R} {I : ideal S} {f : R →+* S} {H : J ≤ I.comap f} (h : I.comap f ≤ J) : function.injective (quotient_map I f H) := begin - refine (quotient_map I f H).injective_iff.2 (λ a ha, _), + refine (injective_iff_map_eq_zero (quotient_map I f H)).2 (λ a ha, _), obtain ⟨r, rfl⟩ := quotient.mk_surjective a, rw [quotient_map_mk, quotient.eq_zero_iff_mem] at ha, exact (quotient.eq_zero_iff_mem).mpr (h ha), diff --git a/src/ring_theory/ideal/over.lean b/src/ring_theory/ideal/over.lean index 557749ac10285..ab89c1bb2d87b 100644 --- a/src/ring_theory/ideal/over.lean +++ b/src/ring_theory/ideal/over.lean @@ -112,7 +112,7 @@ lemma exists_nonzero_mem_of_ne_bot {P : ideal R[X]} begin obtain ⟨m, hm⟩ := submodule.nonzero_mem_of_bot_lt (bot_lt_iff_ne_bot.mpr Pb), refine ⟨m, submodule.coe_mem m, λ pp0, hm (submodule.coe_eq_zero.mp _)⟩, - refine (ring_hom.injective_iff (polynomial.map_ring_hom (quotient.mk (P.comap C)))).mp _ _ pp0, + refine (injective_iff_map_eq_zero (polynomial.map_ring_hom (quotient.mk (P.comap C)))).mp _ _ pp0, refine map_injective _ ((quotient.mk (P.comap C)).injective_iff_ker_eq_bot.mpr _), rw [mk_ker], exact (submodule.eq_bot_iff _).mpr (λ x hx, hP x (mem_comap.mp hx)), @@ -137,7 +137,7 @@ begin quotient.mk_algebra_map, is_scalar_tower.algebra_map_apply _ (R ⧸ p), quotient.algebra_map_eq], { intro hx, - exact (algebra_map (R ⧸ p) (S ⧸ P)).injective_iff.mp h _ hx }, + exact (injective_iff_map_eq_zero (algebra_map (R ⧸ p) (S ⧸ P))).mp h _ hx }, { intro hx, rw [hx, ring_hom.map_zero] }, end diff --git a/src/ring_theory/integral_closure.lean b/src/ring_theory/integral_closure.lean index f6f066cff1e7d..8f9bac7420111 100644 --- a/src/ring_theory/integral_closure.lean +++ b/src/ring_theory/integral_closure.lean @@ -837,7 +837,7 @@ begin -- `q(a) = 0`, because multiplying everything with `a_inv^n` gives `p(a_inv) = 0`. -- TODO: this could be a lemma for `polynomial.reverse`. have hq : ∑ (i : ℕ) in finset.range (p.nat_degree + 1), (p.coeff i) * a ^ (p.nat_degree - i) = 0, - { apply (algebra_map R S).injective_iff.mp hRS, + { apply (injective_iff_map_eq_zero (algebra_map R S)).mp hRS, have a_inv_ne_zero : a_inv ≠ 0 := right_ne_zero_of_mul (mt ha_inv.symm.trans one_ne_zero), refine (mul_eq_zero.mp _).resolve_right (pow_ne_zero p.nat_degree a_inv_ne_zero), rw [eval₂_eq_sum_range] at hp, diff --git a/src/ring_theory/jacobson.lean b/src/ring_theory/jacobson.lean index 35aa49991fbd3..e1b15c79b4b3f 100644 --- a/src/ring_theory/jacobson.lean +++ b/src/ring_theory/jacobson.lean @@ -454,7 +454,7 @@ begin rw ← bot_quotient_is_maximal_iff, have hp0 : ((m : R[X]).map (quotient.mk (P.comap C : ideal R))).leading_coeff ≠ 0 := λ hp0', this $ map_injective (quotient.mk (P.comap C : ideal R)) - ((quotient.mk (P.comap C : ideal R)).injective_iff.2 (λ x hx, + ((injective_iff_map_eq_zero (quotient.mk (P.comap C : ideal R))).2 (λ x hx, by rwa [quotient.eq_zero_iff_mem, (by rwa eq_bot_iff : (P.comap C : ideal R) = ⊥)] at hx)) (by simpa only [leading_coeff_eq_zero, polynomial.map_zero] using hp0'), have hM : (0 : R ⧸ P.comap C) ∉ M := λ ⟨n, hn⟩, hp0 (pow_eq_zero hn), diff --git a/src/ring_theory/localization/basic.lean b/src/ring_theory/localization/basic.lean index 8822ada0d6485..43135298e9550 100644 --- a/src/ring_theory/localization/basic.lean +++ b/src/ring_theory/localization/basic.lean @@ -939,7 +939,7 @@ end protected lemma injective (hM : M ≤ non_zero_divisors R) : injective (algebra_map R S) := begin - rw ring_hom.injective_iff (algebra_map R S), + rw injective_iff_map_eq_zero (algebra_map R S), intros a ha, rwa to_map_eq_zero_iff S hM at ha end diff --git a/src/ring_theory/localization/integral.lean b/src/ring_theory/localization/integral.lean index fbebc3087b4e7..a2defcc55fc68 100644 --- a/src/ring_theory/localization/integral.lean +++ b/src/ring_theory/localization/integral.lean @@ -258,7 +258,7 @@ lemma is_fraction_ring_of_algebraic (alg : is_algebraic A L) is_fraction_ring C L := { map_units := λ ⟨y, hy⟩, is_unit.mk0 _ (show algebra_map C L y ≠ 0, from λ h, mem_non_zero_divisors_iff_ne_zero.mp hy - ((algebra_map C L).injective_iff.mp (algebra_map_injective C A L) _ h)), + ((injective_iff_map_eq_zero (algebra_map C L)).mp (algebra_map_injective C A L) _ h)), surj := λ z, let ⟨x, y, hy, hxy⟩ := exists_integral_multiple (alg z) inj in ⟨⟨mk' C (x : L) x.2, algebra_map _ _ y, mem_non_zero_divisors_iff_ne_zero.mpr (λ h, hy (inj _ @@ -336,7 +336,7 @@ begin from is_unit.invertible (is_unit_of_mem_non_zero_divisors (mem_non_zero_divisors_iff_ne_zero.2 (λ h, non_zero_divisors.ne_zero ha - ((ring_hom.injective_iff (algebra_map S K)).1 + ((injective_iff_map_eq_zero (algebra_map S K)).1 (no_zero_smul_divisors.algebra_map_injective _ _) b h)))), rw [polynomial.aeval_def, ← inv_of_eq_inv, polynomial.eval₂_reverse_eq_zero_iff, polynomial.eval₂_map, ← is_scalar_tower.algebra_map_eq, ← polynomial.aeval_def, @@ -345,7 +345,7 @@ begin obtain ⟨f, hf₁, hf₂⟩ := h (algebra_map S K x), use [f, hf₁], rw [← is_scalar_tower.algebra_map_aeval] at hf₂, - exact (algebra_map S K).injective_iff.1 + exact (injective_iff_map_eq_zero (algebra_map S K)).1 (no_zero_smul_divisors.algebra_map_injective _ _) _ hf₂ } end diff --git a/src/ring_theory/nullstellensatz.lean b/src/ring_theory/nullstellensatz.lean index 3ff45dacc364e..e182530ddc107 100644 --- a/src/ring_theory/nullstellensatz.lean +++ b/src/ring_theory/nullstellensatz.lean @@ -91,7 +91,7 @@ begin have : mv_polynomial σ k ⧸ vanishing_ideal {x} ≃+* k := ring_equiv.of_bijective (ideal.quotient.lift _ (eval x) (λ p h, (mem_vanishing_ideal_singleton_iff x p).mp h)) begin - refine ⟨(ring_hom.injective_iff _).mpr (λ p hp, _), λ z, + refine ⟨(injective_iff_map_eq_zero _).mpr (λ p hp, _), λ z, ⟨(ideal.quotient.mk (vanishing_ideal {x} : ideal (mv_polynomial σ k))) (C z), by simp⟩⟩, obtain ⟨q, rfl⟩ := quotient.mk_surjective p, rwa [ideal.quotient.lift_mk, ← mem_vanishing_ideal_singleton_iff, diff --git a/src/ring_theory/polynomial/eisenstein.lean b/src/ring_theory/polynomial/eisenstein.lean index 9bb3fa2383358..13c457b336a18 100644 --- a/src/ring_theory/polynomial/eisenstein.lean +++ b/src/ring_theory/polynomial/eisenstein.lean @@ -428,7 +428,7 @@ begin { have : function.injective (algebra_map R L), { rw [algebra_map_eq R K L], exact (algebra_map K L).injective.comp (is_fraction_ring.injective R K) }, exfalso, - exact hp.ne_zero ((ring_hom.injective_iff _).1 this _ H) }, + exact hp.ne_zero ((injective_iff_map_eq_zero _).1 this _ H) }, { rw [H₁], exact subalgebra.zero_mem _ } }, diff --git a/src/ring_theory/polynomial/gauss_lemma.lean b/src/ring_theory/polynomial/gauss_lemma.lean index fc1cc3df4bfeb..c0681583f97d5 100644 --- a/src/ring_theory/polynomial/gauss_lemma.lean +++ b/src/ring_theory/polynomial/gauss_lemma.lean @@ -83,7 +83,8 @@ begin ← ring_hom.map_mul, is_unit_iff], refine ⟨algebra_map R K ((integer_normalization R⁰ p).content * ↑u), is_unit_iff_ne_zero.2 (λ con, _), by simp⟩, - replace con := (algebra_map R K).injective_iff.1 (is_fraction_ring.injective _ _) _ con, + replace con := (injective_iff_map_eq_zero (algebra_map R K)).1 + (is_fraction_ring.injective _ _) _ con, rw [mul_eq_zero, content_eq_zero_iff, is_fraction_ring.integer_normalization_eq_zero_iff] at con, rcases con with con | con, { apply h0 con }, diff --git a/src/ring_theory/roots_of_unity.lean b/src/ring_theory/roots_of_unity.lean index 709ac4b128f71..2e53f390fe8f5 100644 --- a/src/ring_theory/roots_of_unity.lean +++ b/src/ring_theory/roots_of_unity.lean @@ -626,7 +626,7 @@ add_equiv.of_bijective end)⟩) begin split, - { rw add_monoid_hom.injective_iff, + { rw injective_iff_map_eq_zero, intros i hi, rw subtype.ext_iff at hi, have := (h.zpow_eq_one_iff_dvd _).mp hi, diff --git a/test/import_order_timeout.lean b/test/import_order_timeout.lean index ba68e6c53c593..ab34e9eb13a25 100644 --- a/test/import_order_timeout.lean +++ b/test/import_order_timeout.lean @@ -14,7 +14,7 @@ variables [add_comm_group N] [module R N] open function lemma injective_iff (f : M →ₗ[R] N) : function.injective f ↔ ∀ m, f m = 0 → m = 0 := -add_monoid_hom.injective_iff f.to_add_monoid_hom +injective_iff_map_eq_zero f lemma foo (L : submodule R (unit → R)) (H : ∀ (m : tensor_product R ↥L ↥L), (tensor_product.map L.subtype L.subtype) m = 0 → m = 0) : From 839f5086fad551f03cc57ec4c307549fa52c865e Mon Sep 17 00:00:00 2001 From: Bhavik Mehta Date: Thu, 21 Apr 2022 08:48:22 +0000 Subject: [PATCH 111/373] feat(measure_theory): allow measurability to prove ae_strongly_measurable (#13427) Adds `measurable.ae_strongly_measurable` to the `measurability` list Co-authored-by: Bhavik Mehta --- src/measure_theory/tactic.lean | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/measure_theory/tactic.lean b/src/measure_theory/tactic.lean index 65e1ebb20caa5..62aec3e070b0a 100644 --- a/src/measure_theory/tactic.lean +++ b/src/measure_theory/tactic.lean @@ -137,15 +137,17 @@ meta def measurability_tactics (md : transparency := semireducible) : list (tact apply_measurable.comp_ae_measurable >> pure "refine measurable.comp_ae_measurable _ _", `[ refine measurable.ae_measurable _ ] - >> pure "refine measurable.ae_measurable _" + >> pure "refine measurable.ae_measurable _", + `[ refine measurable.ae_strongly_measurable _ ] + >> pure "refine measurable.ae_strongly_measurable _" ] namespace interactive setup_tactic_parser /-- -Solve goals of the form `measurable f`, `ae_measurable f μ` or `measurable_set s`. -`measurability?` reports back the proof term it found. +Solve goals of the form `measurable f`, `ae_measurable f μ`, `ae_strongly_measurable f μ` or +`measurable_set s`. `measurability?` reports back the proof term it found. -/ meta def measurability (bang : parse $ optional (tk "!")) (trace : parse $ optional (tk "?")) (cfg : tidy.cfg := {}) : @@ -159,8 +161,9 @@ trace_fn measurability_core meta def measurability' : tactic unit := measurability none none {} /-- -`measurability` solves goals of the form `measurable f`, `ae_measurable f μ` or `measurable_set s` -by applying lemmas tagged with the `measurability` user attribute. +`measurability` solves goals of the form `measurable f`, `ae_measurable f μ`, +`ae_strongly_measurable f μ` or `measurable_set s` by applying lemmas tagged with the +`measurability` user attribute. You can also use `measurability!`, which applies lemmas with `{ md := semireducible }`. The default behaviour is more conservative, and only unfolds `reducible` definitions From 16ecb3d1b9650956becc50099545495351729252 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Thu, 21 Apr 2022 08:48:23 +0000 Subject: [PATCH 112/373] chore(algebra/group/type_tags): missing simp lemmas (#13553) To have `simps` generate these in an appropriate form, this inserts explicits coercions between the type synonyms. --- src/algebra/group/type_tags.lean | 35 +++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/algebra/group/type_tags.lean b/src/algebra/group/type_tags.lean index 15dea478bbff0..e954a21ee39f8 100644 --- a/src/algebra/group/type_tags.lean +++ b/src/algebra/group/type_tags.lean @@ -257,33 +257,48 @@ instance [comm_group α] : add_comm_group (additive α) := instance [add_comm_group α] : comm_group (multiplicative α) := { .. multiplicative.group, .. multiplicative.comm_monoid } +open multiplicative (of_add) +open additive (of_mul) + /-- Reinterpret `α →+ β` as `multiplicative α →* multiplicative β`. -/ -def add_monoid_hom.to_multiplicative [add_zero_class α] [add_zero_class β] : +@[simps] def add_monoid_hom.to_multiplicative [add_zero_class α] [add_zero_class β] : (α →+ β) ≃ (multiplicative α →* multiplicative β) := -⟨λ f, ⟨f.1, f.2, f.3⟩, λ f, ⟨f.1, f.2, f.3⟩, λ x, by { ext, refl, }, λ x, by { ext, refl, }⟩ +{ to_fun := λ f, ⟨λ a, of_add (f a.to_add), f.2, f.3⟩, + inv_fun := λ f, ⟨λ a, (f (of_add a)).to_add, f.2, f.3⟩, + left_inv := λ x, by { ext, refl, }, + right_inv := λ x, by { ext, refl, } } /-- Reinterpret `α →* β` as `additive α →+ additive β`. -/ -def monoid_hom.to_additive [mul_one_class α] [mul_one_class β] : +@[simps] def monoid_hom.to_additive [mul_one_class α] [mul_one_class β] : (α →* β) ≃ (additive α →+ additive β) := -⟨λ f, ⟨f.1, f.2, f.3⟩, λ f, ⟨f.1, f.2, f.3⟩, λ x, by { ext, refl, }, λ x, by { ext, refl, }⟩ +{ to_fun := λ f, ⟨λ a, of_mul (f a.to_mul), f.2, f.3⟩, + inv_fun := λ f, ⟨λ a, (f (of_mul a)).to_mul, f.2, f.3⟩, + left_inv := λ x, by { ext, refl, }, + right_inv := λ x, by { ext, refl, } } /-- Reinterpret `additive α →+ β` as `α →* multiplicative β`. -/ -def add_monoid_hom.to_multiplicative' [mul_one_class α] [add_zero_class β] : +@[simps] def add_monoid_hom.to_multiplicative' [mul_one_class α] [add_zero_class β] : (additive α →+ β) ≃ (α →* multiplicative β) := -⟨λ f, ⟨f.1, f.2, f.3⟩, λ f, ⟨f.1, f.2, f.3⟩, λ x, by { ext, refl, }, λ x, by { ext, refl, }⟩ +{ to_fun := λ f, ⟨λ a, of_add (f (of_mul a)), f.2, f.3⟩, + inv_fun := λ f, ⟨λ a, (f a.to_mul).to_add, f.2, f.3⟩, + left_inv := λ x, by { ext, refl, }, + right_inv := λ x, by { ext, refl, } } /-- Reinterpret `α →* multiplicative β` as `additive α →+ β`. -/ -def monoid_hom.to_additive' [mul_one_class α] [add_zero_class β] : +@[simps] def monoid_hom.to_additive' [mul_one_class α] [add_zero_class β] : (α →* multiplicative β) ≃ (additive α →+ β) := add_monoid_hom.to_multiplicative'.symm /-- Reinterpret `α →+ additive β` as `multiplicative α →* β`. -/ -def add_monoid_hom.to_multiplicative'' [add_zero_class α] [mul_one_class β] : +@[simps] def add_monoid_hom.to_multiplicative'' [add_zero_class α] [mul_one_class β] : (α →+ additive β) ≃ (multiplicative α →* β) := -⟨λ f, ⟨f.1, f.2, f.3⟩, λ f, ⟨f.1, f.2, f.3⟩, λ x, by { ext, refl, }, λ x, by { ext, refl, }⟩ +{ to_fun := λ f, ⟨λ a, (f a.to_add).to_mul, f.2, f.3⟩, + inv_fun := λ f, ⟨λ a, of_mul (f (of_add a)), f.2, f.3⟩, + left_inv := λ x, by { ext, refl, }, + right_inv := λ x, by { ext, refl, } } /-- Reinterpret `multiplicative α →* β` as `α →+ additive β`. -/ -def monoid_hom.to_additive'' [add_zero_class α] [mul_one_class β] : +@[simps] def monoid_hom.to_additive'' [add_zero_class α] [mul_one_class β] : (multiplicative α →* β) ≃ (α →+ additive β) := add_monoid_hom.to_multiplicative''.symm From 9f22a3670a326ea8f175b1254d55e40c1bd9366c Mon Sep 17 00:00:00 2001 From: Riccardo Brasca Date: Thu, 21 Apr 2022 11:02:56 +0000 Subject: [PATCH 113/373] feat(src/number_theory/cyclotomic/discriminant): add discr_prime_pow_ne_two (#13465) We add `discr_prime_pow_ne_two`, the discriminant of the `p^n`-th cyclotomic field. From flt-regular --- .../cyclotomic/discriminant.lean | 115 ++++++++++++++---- .../cyclotomic/primitive_roots.lean | 36 ++++++ 2 files changed, 124 insertions(+), 27 deletions(-) diff --git a/src/number_theory/cyclotomic/discriminant.lean b/src/number_theory/cyclotomic/discriminant.lean index 8475f77a0aeb6..0357923fc6b19 100644 --- a/src/number_theory/cyclotomic/discriminant.lean +++ b/src/number_theory/cyclotomic/discriminant.lean @@ -53,41 +53,102 @@ end is_primitive_root namespace is_cyclotomic_extension -variables {p : ℕ+} (k : ℕ) {K : Type u} {L : Type v} {ζ : L} [field K] [field L] -variables [algebra K L] [ne_zero ((p : ℕ) : K)] - -/-- If `p` is an odd prime and `is_cyclotomic_extension {p} K L`, then -`discr K (hζ.power_basis K).basis = (-1) ^ ((p - 1) / 2) * p ^ (p - 2)`. -/ -lemma discr_odd_prime [is_cyclotomic_extension {p} K L] [hp : fact (p : ℕ).prime] - (hζ : is_primitive_root ζ p) (hirr : irreducible (cyclotomic p K)) (hodd : p ≠ 2) : +variables {p : ℕ+} {k : ℕ} {K : Type u} {L : Type v} {ζ : L} [field K] [field L] +variables [algebra K L] + +/-- If `p` is a prime and `is_cyclotomic_extension {p ^ (k + 1)} K L`, then the discriminant of +`hζ.power_basis K` is `(-1) ^ ((p ^ (k + 1).totient) / 2) * p ^ (p ^ k * ((p - 1) * (k + 1) - 1))` +if `irreducible (cyclotomic (p ^ (k + 1)) K))`, `irreducible (cyclotomic p K)` and +`p ^ (k + 1) ≠ 2`. -/ +lemma discr_prime_pow_ne_two [is_cyclotomic_extension {p ^ (k + 1)} K L] [hp : fact (p : ℕ).prime] + [ne_zero ((p : ℕ) : K)] (hζ : is_primitive_root ζ ↑(p ^ (k + 1))) + (hirr : irreducible (cyclotomic (↑(p ^ (k + 1)) : ℕ) K)) + (hirr₁ : irreducible (cyclotomic (p : ℕ) K)) (hk : p ^ (k + 1) ≠ 2) : discr K (hζ.power_basis K).basis = - (-1) ^ (((p : ℕ) - 1) / 2) * p ^ ((p : ℕ) - 2) := + (-1) ^ (((p ^ (k + 1) : ℕ).totient) / 2) * p ^ ((p : ℕ) ^ k * ((p - 1) * (k + 1) - 1)) := begin - have hodd' : (p : ℕ) ≠ 2 := λ hn, by exact hodd.symm (pnat.coe_inj.1 hn.symm), - have hpos := pos_iff_ne_zero.2 (λ h, (tsub_pos_of_lt (prime.one_lt hp.out)).ne.symm h), + haveI : ne_zero ((↑(p ^ (k + 1)) : ℕ) : K), + { refine ⟨λ hzero, _⟩, + rw [pnat.pow_coe] at hzero, + simpa [ne_zero.ne ((p : ℕ) : K)] using hzero }, + have hp2 : p = 2 → 1 ≤ k, + { intro hp, + refine one_le_iff_ne_zero.2 (λ h, _), + rw [h, hp, zero_add, pow_one] at hk, + exact hk rfl }, rw [discr_power_basis_eq_norm, finrank _ hirr, hζ.power_basis_gen _, - ← hζ.minpoly_eq_cyclotomic_of_irreducible hirr, totient_prime hp.out], + ← hζ.minpoly_eq_cyclotomic_of_irreducible hirr, pnat.pow_coe, totient_prime_pow hp.out + (succ_pos k)], congr' 1, - { have h := even_sub_one_of_prime_ne_two hp.out hodd', - rw [← mul_one 2, ← nat.div_mul_div_comm (even_iff_two_dvd.1 h) (one_dvd _), nat.div_one, - mul_one, mul_comm, pow_mul], - congr' 1, - exact (nat.even.sub_odd (one_le_iff_ne_zero.2 hpos.ne') h $ odd_iff.2 rfl).neg_one_pow }, - { have H := congr_arg derivative (cyclotomic_prime_mul_X_sub_one K p), - rw [derivative_mul, derivative_sub, derivative_one, derivative_X, sub_zero, mul_one, - derivative_sub, derivative_one, sub_zero, derivative_X_pow] at H, + { by_cases hptwo : p = 2, + { obtain ⟨k₁, hk₁⟩ := nat.exists_eq_succ_of_ne_zero (one_le_iff_ne_zero.1 (hp2 hptwo)), + rw [hk₁, succ_sub_one, hptwo, pnat.coe_bit0, pnat.one_coe, succ_sub_succ_eq_sub, tsub_zero, + mul_one, pow_succ, mul_assoc, nat.mul_div_cancel_left _ zero_lt_two, + nat.mul_div_cancel_left _ zero_lt_two], + by_cases hk₁zero : k₁ = 0, + { simp [hk₁zero] }, + obtain ⟨k₂, rfl⟩ := nat.exists_eq_succ_of_ne_zero hk₁zero, + rw [pow_succ, mul_assoc, pow_mul (-1 : K), pow_mul (-1 : K), neg_one_sq, one_pow, one_pow] }, + { simp only [succ_sub_succ_eq_sub, tsub_zero], + replace hptwo : ↑p ≠ 2, + { intro h, + rw [← pnat.one_coe, ← pnat.coe_bit0, pnat.coe_inj] at h, + exact hptwo h }, + obtain ⟨a, ha⟩ := even_sub_one_of_prime_ne_two hp.out hptwo, + rw [mul_comm ((p : ℕ) ^ k), mul_assoc, ha], + nth_rewrite 0 [← mul_one a], + nth_rewrite 4 [← mul_one a], + rw [← nat.mul_succ, mul_comm a, mul_assoc, mul_assoc 2, nat.mul_div_cancel_left _ + zero_lt_two, nat.mul_div_cancel_left _ zero_lt_two, ← mul_assoc, mul_comm + (a * (p : ℕ) ^ k), pow_mul, ← ha], + congr' 1, + refine odd.neg_one_pow (nat.even.sub_odd (nat.succ_le_iff.2 (mul_pos (tsub_pos_iff_lt.2 + hp.out.one_lt) (pow_pos hp.out.pos _))) (even.mul_right (nat.even_sub_one_of_prime_ne_two + hp.out hptwo) _) odd_one) } }, + { have H := congr_arg derivative (cyclotomic_prime_pow_mul_X_pow_sub_one K p k), + rw [derivative_mul, derivative_sub, derivative_one, sub_zero, derivative_pow, + derivative_X, mul_one, derivative_sub, derivative_one, sub_zero, derivative_pow, + derivative_X, mul_one, ← pnat.pow_coe, hζ.minpoly_eq_cyclotomic_of_irreducible hirr] at H, replace H := congr_arg (λ P, aeval ζ P) H, - simp only [hζ.minpoly_eq_cyclotomic_of_irreducible hirr, aeval_add, _root_.map_mul, aeval_one, - _root_.map_sub, aeval_X, minpoly.aeval, add_zero, aeval_nat_cast, aeval_X_pow] at H, + simp only [aeval_add, aeval_mul, minpoly.aeval, zero_mul, add_zero, aeval_nat_cast, + _root_.map_sub, aeval_one, aeval_X_pow] at H, replace H := congr_arg (algebra.norm K) H, - rw [monoid_hom.map_mul, hζ.sub_one_norm_prime hirr hodd, monoid_hom.map_mul, monoid_hom.map_pow, - hζ.norm_eq_one hodd hirr, one_pow, mul_one, ← map_nat_cast (algebra_map K L), - norm_algebra_map, finrank _ hirr, totient_prime hp.out, ← succ_pred_eq_of_pos hpos, pow_succ, - mul_comm _ (p : K), coe_coe, ← hζ.minpoly_eq_cyclotomic_of_irreducible hirr] at H, - simpa [(mul_right_inj' $ ne_zero.ne ↑↑p).1 H], + have hnorm : (norm K) (ζ ^ (p : ℕ) ^ k - 1) = p ^ ((p : ℕ) ^ k), + { by_cases hp : p = 2, + { exact hζ.pow_sub_one_norm_prime_pow_of_one_le hirr (by simpa using hirr₁) rfl.le (hp2 hp) }, + { exact hζ.pow_sub_one_norm_prime_ne_two hirr (by simpa using hirr₁) rfl.le hp } }, + rw [monoid_hom.map_mul, hnorm, monoid_hom.map_mul, ← map_nat_cast (algebra_map K L), + norm_algebra_map, finrank _ hirr, pnat.pow_coe, totient_prime_pow hp.out (succ_pos k), + nat.sub_one, nat.pred_succ, ← hζ.minpoly_eq_cyclotomic_of_irreducible hirr, map_pow, + hζ.norm_eq_one hk hirr, one_pow, mul_one, cast_pow, ← coe_coe, ← pow_mul, ← mul_assoc, + mul_comm (k + 1), mul_assoc] at H, + { have := mul_pos (succ_pos k) (tsub_pos_iff_lt.2 hp.out.one_lt), + rw [← succ_pred_eq_of_pos this, mul_succ, pow_add _ _ ((p : ℕ) ^ k)] at H, + replace H := (mul_left_inj' (λ h, _)).1 H, + { simpa only [← pnat.pow_coe, H, mul_comm _ (k + 1)] }, + { replace h := pow_eq_zero h, + rw [coe_coe] at h, + exact ne_zero.ne _ h } }, + { apply_instance } }, + { apply_instance } +end + +/-- If `p` is an odd prime and `is_cyclotomic_extension {p} K L`, then +`discr K (hζ.power_basis K).basis = (-1) ^ ((p - 1) / 2) * p ^ (p - 2)` if +`irreducible (cyclotomic p K)`. -/ +lemma discr_odd_prime [is_cyclotomic_extension {p} K L] [hp : fact (p : ℕ).prime] + [ne_zero ((p : ℕ) : K)] (hζ : is_primitive_root ζ p) (hirr : irreducible (cyclotomic p K)) + (hodd : p ≠ 2) : + discr K (hζ.power_basis K).basis = (-1) ^ (((p : ℕ) - 1) / 2) * p ^ ((p : ℕ) - 2) := +begin + haveI : is_cyclotomic_extension {p ^ (0 + 1)} K L, + { rw [zero_add, pow_one], apply_instance }, - { apply_instance }, + have hζ' : is_primitive_root ζ ↑(p ^ (0 + 1)) := by simpa using hζ, + convert discr_prime_pow_ne_two hζ' (by simpa [hirr]) (by simp [hirr]) (by simp [hodd]), + { rw [zero_add, pow_one, totient_prime hp.out] }, + { rw [pow_zero, one_mul, zero_add, mul_one, nat.sub_sub] } end end is_cyclotomic_extension diff --git a/src/number_theory/cyclotomic/primitive_roots.lean b/src/number_theory/cyclotomic/primitive_roots.lean index c35d003374ec9..29d8cd386519e 100644 --- a/src/number_theory/cyclotomic/primitive_roots.lean +++ b/src/number_theory/cyclotomic/primitive_roots.lean @@ -439,6 +439,42 @@ begin simpa [hk₁] using sub_one_norm_eq_eval_cyclotomic hζ this hirr, end +/-- If `irreducible (cyclotomic (p ^ (k + 1)) K)` and +`irreducible (cyclotomic (p ^ (k - s + 1)) K))` (in particular for `K = ℚ`) and `p` is a prime, +then the norm of `ζ ^ (p ^ s) - 1` is `p ^ (p ^ s)` if `1 ≤ k`. -/ +lemma pow_sub_one_norm_prime_pow_of_one_le [hne : ne_zero ((p : ℕ) : K)] {k s : ℕ} + (hζ : is_primitive_root ζ ↑(p ^ (k + 1))) [hpri : fact (p : ℕ).prime] + [hcycl : is_cyclotomic_extension {p ^ (k + 1)} K L] + (hirr : irreducible (cyclotomic (↑(p ^ (k + 1)) : ℕ) K)) + (hirr₁ : irreducible (cyclotomic (↑(p ^ (k - s + 1)) : ℕ) K)) (hs : s ≤ k) + (hk : 1 ≤ k) : norm K (ζ ^ ((p : ℕ) ^ s) - 1) = p ^ ((p : ℕ) ^ s) := +begin + by_cases htwo : p ^ (k - s + 1) = 2, + { have hp : p = 2, + { rw [← pnat.coe_inj, pnat.coe_bit0, pnat.one_coe, pnat.pow_coe, ← pow_one 2] at htwo, + replace htwo := eq_of_prime_pow_eq (prime_iff.1 hpri.out) (prime_iff.1 nat.prime_two) + (succ_pos _) htwo, + rwa [show 2 = ((2 : ℕ+) : ℕ), by simp, pnat.coe_inj] at htwo }, + replace hs : s = k, + { rw [hp, ← pnat.coe_inj, pnat.pow_coe, pnat.coe_bit0, pnat.one_coe] at htwo, + nth_rewrite 1 [← pow_one 2] at htwo, + replace htwo := nat.pow_right_injective rfl.le htwo, + rw [add_left_eq_self, nat.sub_eq_zero_iff_le] at htwo, + refine le_antisymm hs htwo }, + haveI : ne_zero (2 : K), + { refine ⟨λ h, _⟩, + rw [hp, pnat.coe_bit0, one_coe, cast_bit0, cast_one, h] at hne, + simpa using hne.out }, + simp only [hs, hp, pnat.coe_bit0, one_coe, coe_coe, cast_bit0, cast_one, + pow_coe] at ⊢ hζ hirr hcycl, + haveI := hcycl, + obtain ⟨k₁, hk₁⟩ := nat.exists_eq_succ_of_ne_zero (one_le_iff_ne_zero.1 hk), + rw [hζ.pow_sub_one_norm_two hirr], + rw [hk₁, pow_succ, pow_mul, neg_eq_neg_one_mul, mul_pow, neg_one_sq, one_mul, ← pow_mul, + ← pow_succ] }, + { exact hζ.pow_sub_one_norm_prime_pow_ne_two hirr hirr₁ hs htwo } +end + end is_primitive_root namespace is_cyclotomic_extension From b87e193dcd6e60bdf3b41c57d54f24b92ceb3727 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 21 Apr 2022 11:02:57 +0000 Subject: [PATCH 114/373] fix(category_theory/monoidal): improve hygiene in coherence tactic (#13507) Co-authored-by: Scott Morrison --- src/category_theory/monoidal/coherence.lean | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/category_theory/monoidal/coherence.lean b/src/category_theory/monoidal/coherence.lean index 56a222dd23af6..4a6caca9a66b6 100644 --- a/src/category_theory/monoidal/coherence.lean +++ b/src/category_theory/monoidal/coherence.lean @@ -185,14 +185,23 @@ namespace tactic open tactic setup_tactic_parser +/-- +Auxilliary definition of `monoidal_coherence`, +being careful with namespaces to avoid shadowing. +-/ +meta def mk_project_map_expr (e : expr) : tactic expr := + to_expr ``(category_theory.free_monoidal_category.project_map _root_.id _ _ + (category_theory.monoidal_category.lift_hom.lift %%e)) + /-- Coherence tactic for monoidal categories. -/ meta def monoidal_coherence : tactic unit := do o ← get_options, set_options $ o.set_nat `class.instance_max_depth 128, try `[dsimp], `(%%lhs = %%rhs) ← target, - to_expr ``(project_map id _ _ (lift_hom.lift %%lhs) = project_map id _ _ (lift_hom.lift %%rhs)) - >>= tactic.change, + project_map_lhs ← mk_project_map_expr lhs, + project_map_rhs ← mk_project_map_expr rhs, + to_expr ``(%%project_map_lhs = %%project_map_rhs) >>= tactic.change, congr /-- From 21bbe9002372da584955f4ccae0a3e0c6d912070 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Thu, 21 Apr 2022 11:02:58 +0000 Subject: [PATCH 115/373] feat(analysis/normed): more lemmas about the sup norm on pi types and matrices (#13536) For now we name the matrix lemmas as `matrix.norm_*` and `matrix.nnnorm_*` to match `matrix.norm_le_iff` and `matrix.nnnorm_le_iff`. We should consider renaming these in future to indicate which norm they refer to, but should probably deal with agreeing on a name in a separate PR. --- src/analysis/matrix.lean | 50 +++++++++++++++++++--- src/analysis/normed/group/basic.lean | 6 +++ src/analysis/normed/normed_field.lean | 5 +++ src/analysis/normed_space/star/matrix.lean | 21 ++++----- 4 files changed, 64 insertions(+), 18 deletions(-) diff --git a/src/analysis/matrix.lean b/src/analysis/matrix.lean index 8996b3a54ae20..2b688866e78ac 100644 --- a/src/analysis/matrix.lean +++ b/src/analysis/matrix.lean @@ -20,16 +20,16 @@ of a matrix. noncomputable theory -open_locale nnreal +open_locale nnreal matrix namespace matrix -variables {R m n α : Type*} [fintype m] [fintype n] +variables {R m n α β : Type*} [fintype m] [fintype n] section semi_normed_group -variables [semi_normed_group α] +variables [semi_normed_group α] [semi_normed_group β] -/-- Seminormed group instance (using sup norm of sup norm) for matrices over a seminormed ring. Not +/-- Seminormed group instance (using sup norm of sup norm) for matrices over a seminormed group. Not declared as an instance because there are several natural choices for defining the norm of a matrix. -/ protected def semi_normed_group : semi_normed_group (matrix m n α) := @@ -61,9 +61,47 @@ lemma nnnorm_entry_le_entrywise_sup_nnorm (A : matrix m n α) {i : m} {j : n} : ∥A i j∥₊ ≤ ∥A∥₊ := (nnnorm_le_pi_nnnorm (A i) j).trans (nnnorm_le_pi_nnnorm A i) +@[simp] lemma nnnorm_transpose (A : matrix m n α) : ∥Aᵀ∥₊ = ∥A∥₊ := +by { simp_rw [pi.nnnorm_def], exact finset.sup_comm _ _ _ } +@[simp] lemma norm_transpose (A : matrix m n α) : ∥Aᵀ∥ = ∥A∥ := congr_arg coe $ nnnorm_transpose A + +@[simp] lemma nnnorm_map_eq (A : matrix m n α) (f : α → β) (hf : ∀ a, ∥f a∥₊ = ∥a∥₊) : + ∥A.map f∥₊ = ∥A∥₊ := +by simp_rw [pi.nnnorm_def, matrix.map, hf] +@[simp] lemma norm_map_eq (A : matrix m n α) (f : α → β) (hf : ∀ a, ∥f a∥ = ∥a∥) : + ∥A.map f∥ = ∥A∥ := +(congr_arg (coe : ℝ≥0 → ℝ) $ nnnorm_map_eq A f $ λ a, subtype.ext $ hf a : _) + +@[simp] lemma nnnorm_col (v : m → α) : ∥col v∥₊ = ∥v∥₊ := by simp [pi.nnnorm_def] +@[simp] lemma norm_col (v : m → α) : ∥col v∥ = ∥v∥ := congr_arg coe $ nnnorm_col v + +@[simp] lemma nnnorm_row (v : n → α) : ∥row v∥₊ = ∥v∥₊ := by simp [pi.nnnorm_def] +@[simp] lemma norm_row (v : n → α) : ∥row v∥ = ∥v∥ := congr_arg coe $ nnnorm_row v + +@[simp] lemma nnnorm_diagonal [decidable_eq n] (v : n → α) : ∥diagonal v∥₊ = ∥v∥₊ := +begin + simp_rw pi.nnnorm_def, + congr' 1 with i : 1, + refine le_antisymm (finset.sup_le $ λ j hj, _) _, + { obtain rfl | hij := eq_or_ne i j, + { rw diagonal_apply_eq }, + { rw [diagonal_apply_ne hij, nnnorm_zero], + exact zero_le _ }, }, + { refine eq.trans_le _ (finset.le_sup (finset.mem_univ i)), + rw diagonal_apply_eq } +end + +@[simp] lemma norm_diagonal [decidable_eq n] (v : n → α) : ∥diagonal v∥ = ∥v∥ := +congr_arg coe $ nnnorm_diagonal v + +/-- Note this is safe as an instance as it carries no data. -/ +instance [nonempty n] [decidable_eq n] [has_one α] [norm_one_class α] : + norm_one_class (matrix n n α) := +⟨(norm_diagonal _).trans $ norm_one⟩ + end semi_normed_group -/-- Normed group instance (using sup norm of sup norm) for matrices over a normed ring. Not +/-- Normed group instance (using sup norm of sup norm) for matrices over a normed group. Not declared as an instance because there are several natural choices for defining the norm of a matrix. -/ protected def normed_group [normed_group α] : normed_group (matrix m n α) := @@ -74,7 +112,7 @@ local attribute [instance] matrix.semi_normed_group variables [normed_field R] [semi_normed_group α] [normed_space R α] -/-- Normed space instance (using sup norm of sup norm) for matrices over a normed field. Not +/-- Normed space instance (using sup norm of sup norm) for matrices over a normed space. Not declared as an instance because there are several natural choices for defining the norm of a matrix. -/ protected def normed_space : normed_space R (matrix m n α) := diff --git a/src/analysis/normed/group/basic.lean b/src/analysis/normed/group/basic.lean index e25e5cbdf344a..53efaf81902df 100644 --- a/src/analysis/normed/group/basic.lean +++ b/src/analysis/normed/group/basic.lean @@ -765,6 +765,12 @@ noncomputable instance pi.semi_normed_group {π : ι → Type*} [fintype ι] congr_arg (coe : ℝ≥0 → ℝ) $ congr_arg (finset.sup finset.univ) $ funext $ assume a, show nndist (x a) (y a) = ∥x a - y a∥₊, from nndist_eq_nnnorm _ _ } +lemma pi.norm_def {π : ι → Type*} [fintype ι] [Π i, semi_normed_group (π i)] (f : Π i, π i) : + ∥f∥ = ↑(finset.univ.sup (λ b, ∥f b∥₊)) := rfl + +lemma pi.nnnorm_def {π : ι → Type*} [fintype ι] [Π i, semi_normed_group (π i)] (f : Π i, π i) : + ∥f∥₊ = finset.univ.sup (λ b, ∥f b∥₊) := subtype.eta _ _ + /-- The seminorm of an element in a product space is `≤ r` if and only if the norm of each component is. -/ lemma pi_norm_le_iff {π : ι → Type*} [fintype ι] [∀i, semi_normed_group (π i)] {r : ℝ} diff --git a/src/analysis/normed/normed_field.lean b/src/analysis/normed/normed_field.lean index 9edf04a48fd24..5b624a897991a 100644 --- a/src/analysis/normed/normed_field.lean +++ b/src/analysis/normed/normed_field.lean @@ -127,6 +127,11 @@ instance prod.norm_one_class [semi_normed_group α] [has_one α] [norm_one_class norm_one_class (α × β) := ⟨by simp [prod.norm_def]⟩ +instance pi.norm_one_class {ι : Type*} {α : ι → Type*} [nonempty ι] [fintype ι] + [Π i, semi_normed_group (α i)] [Π i, has_one (α i)] [∀ i, norm_one_class (α i)] : + norm_one_class (Π i, α i) := +⟨by simp [pi.norm_def, finset.sup_const finset.univ_nonempty]⟩ + section non_unital_semi_normed_ring variables [non_unital_semi_normed_ring α] diff --git a/src/analysis/normed_space/star/matrix.lean b/src/analysis/normed_space/star/matrix.lean index 5044a55c132d0..ec8f115cf4902 100644 --- a/src/analysis/normed_space/star/matrix.lean +++ b/src/analysis/normed_space/star/matrix.lean @@ -16,24 +16,21 @@ This file collects facts about the unitary matrices over `𝕜` (either `ℝ` or open_locale big_operators matrix -variables {𝕜 n E : Type*} +variables {𝕜 m n E : Type*} namespace matrix -variables [fintype n] [semi_normed_group E] [star_add_monoid E] [normed_star_group E] +variables [fintype m] [fintype n] [semi_normed_group E] [star_add_monoid E] [normed_star_group E] local attribute [instance] matrix.semi_normed_group -@[simp] lemma entrywise_sup_norm_star_eq_norm (M : matrix n n E) : ∥star M∥ = ∥M∥ := -begin - refine le_antisymm (by simp [matrix.norm_le_iff, M.norm_entry_le_entrywise_sup_norm]) _, - refine ((matrix.norm_le_iff (norm_nonneg _)).mpr (λ i j, _)).trans - (congr_arg _ M.star_eq_conj_transpose).ge, - exact (norm_star _).ge.trans Mᴴ.norm_entry_le_entrywise_sup_norm -end +@[simp] lemma norm_conj_transpose (M : matrix m n E) : ∥Mᴴ∥ = ∥M∥ := +(norm_map_eq _ _ norm_star).trans M.norm_transpose + +@[simp] lemma nnnorm_conj_transpose (M : matrix m n E) : ∥Mᴴ∥₊ = ∥M∥₊ := +subtype.ext M.norm_conj_transpose -@[priority 100] -- see Note [lower instance priority] -instance to_normed_star_group : normed_star_group (matrix n n E) := -⟨matrix.entrywise_sup_norm_star_eq_norm⟩ +instance : normed_star_group (matrix n n E) := +⟨matrix.norm_conj_transpose⟩ end matrix From 8261501767387260b49611e1ca9b7bcf22d70b1c Mon Sep 17 00:00:00 2001 From: Bolton Bailey Date: Thu, 21 Apr 2022 12:09:48 +0000 Subject: [PATCH 116/373] refactor(number_theory/padics/padic_norm): Switch nat and rat definitions (#12454) Switches the order in which `padic_val_nat` and `padic_val_rat` are defined. This PR has also expanded to add `padic_val_int` and some API lemmas for that. --- src/number_theory/padics/padic_norm.lean | 406 ++++++++++++-------- src/number_theory/padics/padic_numbers.lean | 26 +- 2 files changed, 250 insertions(+), 182 deletions(-) diff --git a/src/number_theory/padics/padic_norm.lean b/src/number_theory/padics/padic_norm.lean index 68bb11cdfd185..2f2e56389113a 100644 --- a/src/number_theory/padics/padic_norm.lean +++ b/src/number_theory/padics/padic_norm.lean @@ -52,131 +52,185 @@ open_locale rat open multiplicity /-- -For `p ≠ 1`, the p-adic valuation of an integer `z ≠ 0` is the largest natural number `n` such that -p^n divides z. +For `p ≠ 1`, the p-adic valuation of a natural `n ≠ 0` is the largest natural number `k` such that +p^k divides z. -`padic_val_rat` defines the valuation of a rational `q` to be the valuation of `q.num` minus the -valuation of `q.denom`. -If `q = 0` or `p = 1`, then `padic_val_rat p q` defaults to 0. +If `n = 0` or `p = 1`, then `padic_val_nat p q` defaults to 0. -/ -def padic_val_rat (p : ℕ) (q : ℚ) : ℤ := -if h : q ≠ 0 ∧ p ≠ 1 -then (multiplicity (p : ℤ) q.num).get - (multiplicity.finite_int_iff.2 ⟨h.2, rat.num_ne_zero_of_ne_zero h.1⟩) - - (multiplicity (p : ℤ) q.denom).get - (multiplicity.finite_int_iff.2 ⟨h.2, by exact_mod_cast rat.denom_ne_zero _⟩) +def padic_val_nat (p : ℕ) (n : ℕ) : ℕ := +if h : p ≠ 1 ∧ 0 < n +then (multiplicity p n).get (multiplicity.finite_nat_iff.2 h) else 0 +namespace padic_val_nat +open multiplicity +variables {p : ℕ} + +/-- `padic_val_nat p 0` is 0 for any `p`. -/ +@[simp] protected lemma zero : padic_val_nat p 0 = 0 := +by simp [padic_val_nat] + +/-- `padic_val_nat p 1` is 0 for any `p`. -/ +@[simp] protected lemma one : padic_val_nat p 1 = 0 := +by unfold padic_val_nat; split_ifs; simp * + +/-- For `p ≠ 0, p ≠ 1, `padic_val_rat p p` is 1. -/ +@[simp] lemma self (hp : 1 < p) : padic_val_nat p p = 1 := +begin + have neq_one : (¬ p = 1) ↔ true, + { exact iff_of_true ((ne_of_lt hp).symm) trivial, }, + have eq_zero_false : (p = 0) ↔ false, + { exact iff_false_intro ((ne_of_lt (trans zero_lt_one hp)).symm) }, + simp [padic_val_nat, neq_one, eq_zero_false], +end + +lemma eq_zero_of_not_dvd {n : ℕ} (h : ¬ p ∣ n) : padic_val_nat p n = 0 := +begin + rw padic_val_nat, + split_ifs, + { simp [multiplicity_eq_zero_of_not_dvd h], }, + refl, +end + +end padic_val_nat + /-- -A simplification of the definition of `padic_val_rat p q` when `q ≠ 0` and `p` is prime. +For `p ≠ 1`, the p-adic valuation of an integer `z ≠ 0` is the largest natural number `k` such that +p^k divides z. + +If `x = 0` or `p = 1`, then `padic_val_int p q` defaults to 0. -/ -lemma padic_val_rat_def (p : ℕ) [hp : fact p.prime] {q : ℚ} (hq : q ≠ 0) : padic_val_rat p q = - (multiplicity (p : ℤ) q.num).get (finite_int_iff.2 ⟨hp.1.ne_one, rat.num_ne_zero_of_ne_zero hq⟩) - - (multiplicity (p : ℤ) q.denom).get - (finite_int_iff.2 ⟨hp.1.ne_one, by exact_mod_cast rat.denom_ne_zero _⟩) := -dif_pos ⟨hq, hp.1.ne_one⟩ +def padic_val_int (p : ℕ) (z : ℤ) : ℕ := +padic_val_nat p (z.nat_abs) -namespace padic_val_rat +namespace padic_val_int open multiplicity variables {p : ℕ} -/-- -`padic_val_rat p q` is symmetric in `q`. --/ -@[simp] protected lemma neg (q : ℚ) : padic_val_rat p (-q) = padic_val_rat p q := +lemma of_ne_one_ne_zero {z : ℤ} (hp : p ≠ 1) (hz : z ≠ 0) : padic_val_int p z = + (multiplicity (p : ℤ) z).get (by {apply multiplicity.finite_int_iff.2, simp [hp, hz]}) := begin - unfold padic_val_rat, + rw [padic_val_int, padic_val_nat, dif_pos], + simp_rw multiplicity.int.nat_abs p z, + refl, + simp [hp, hz], + exact int.nat_abs_pos_of_ne_zero hz, +end + +/-- `padic_val_int p 0` is 0 for any `p`. -/ +@[simp] protected lemma zero : padic_val_int p 0 = 0 := +by simp [padic_val_int] + +/-- `padic_val_int p 1` is 0 for any `p`. -/ +@[simp] protected lemma one : padic_val_int p 1 = 0 := +by simp [padic_val_int] + +/-- The p-adic value of an natural is its p-adic_value as an integer -/ +@[simp] lemma of_nat {n : ℕ} : padic_val_int p (n : ℤ) = padic_val_nat p n := +by simp [padic_val_int] + +/-- For `p ≠ 0, p ≠ 1, `padic_val_int p p` is 1. -/ +lemma self (hp : 1 < p) : padic_val_int p p = 1 := +by simp [padic_val_nat.self hp] + +lemma eq_zero_of_not_dvd {z : ℤ} (h : ¬ (p : ℤ) ∣ z) : padic_val_int p z = 0 := +begin + rw [padic_val_int, padic_val_nat], split_ifs, - { simp [-add_comm]; refl }, - { exfalso, simp * at * }, - { exfalso, simp * at * }, - { refl } + { simp_rw multiplicity.int.nat_abs, + simp [multiplicity_eq_zero_of_not_dvd h], }, + refl, end +end padic_val_int + /-- -`padic_val_rat p 0` is 0 for any `p`. +`padic_val_rat` defines the valuation of a rational `q` to be the valuation of `q.num` minus the +valuation of `q.denom`. +If `q = 0` or `p = 1`, then `padic_val_rat p q` defaults to 0. -/ +def padic_val_rat (p : ℕ) (q : ℚ) : ℤ := +padic_val_int p q.num - padic_val_nat p q.denom + +namespace padic_val_rat +open multiplicity +variables {p : ℕ} + +/-- `padic_val_rat p q` is symmetric in `q`. -/ +@[simp] protected lemma neg (q : ℚ) : padic_val_rat p (-q) = padic_val_rat p q := +by simp [padic_val_rat, padic_val_int] + +/-- `padic_val_rat p 0` is 0 for any `p`. -/ @[simp] -protected lemma zero (m : nat) : padic_val_rat m 0 = 0 := rfl +protected lemma zero (m : nat) : padic_val_rat m 0 = 0 := by simp [padic_val_rat, padic_val_int] -/-- -`padic_val_rat p 1` is 0 for any `p`. --/ -@[simp] protected lemma one : padic_val_rat p 1 = 0 := -by unfold padic_val_rat; split_ifs; simp * +/-- `padic_val_rat p 1` is 0 for any `p`. -/ +@[simp] protected lemma one : padic_val_rat p 1 = 0 := by simp [padic_val_rat, padic_val_int] -/-- -For `p ≠ 0, p ≠ 1, `padic_val_rat p p` is 1. --/ -@[simp] lemma padic_val_rat_self (hp : 1 < p) : padic_val_rat p p = 1 := -by unfold padic_val_rat; split_ifs; simp [*, nat.one_lt_iff_ne_zero_and_ne_one] at * +/-- The p-adic value of an integer `z ≠ 0` is its p-adic_value as a rational -/ +@[simp] lemma of_int {z : ℤ} : padic_val_rat p (z : ℚ) = padic_val_int p z := +by simp [padic_val_rat] -/-- -The p-adic value of an integer `z ≠ 0` is the multiplicity of `p` in `z`. --/ -lemma padic_val_rat_of_int (z : ℤ) (hp : p ≠ 1) (hz : z ≠ 0) : +/-- The p-adic value of an integer `z ≠ 0` is the multiplicity of `p` in `z`. -/ +lemma of_int_multiplicity (z : ℤ) (hp : p ≠ 1) (hz : z ≠ 0) : padic_val_rat p (z : ℚ) = (multiplicity (p : ℤ) z).get (finite_int_iff.2 ⟨hp, hz⟩) := -by rw [padic_val_rat, dif_pos]; simp *; refl +by rw [of_int, padic_val_int.of_ne_one_ne_zero hp hz] -end padic_val_rat +lemma multiplicity_sub_multiplicity {q : ℚ} (hp : p ≠ 1) (hq : q ≠ 0) : + padic_val_rat p q = + (multiplicity (p : ℤ) q.num).get (finite_int_iff.2 ⟨hp, rat.num_ne_zero_of_ne_zero hq⟩) - + (multiplicity p q.denom).get + (by { rw [←finite_iff_dom, finite_nat_iff, and_iff_right hp], exact q.pos }) := +begin + rw [padic_val_rat, padic_val_int.of_ne_one_ne_zero hp, padic_val_nat, dif_pos], + refl, + simp only [hp, ne.def, not_false_iff, true_and], + exact q.pos, + exact rat.num_ne_zero_of_ne_zero hq, +end -/-- -A convenience function for the case of `padic_val_rat` when both inputs are natural numbers. --/ -def padic_val_nat (p : ℕ) (n : ℕ) : ℕ := -int.to_nat (padic_val_rat p n) +/-- The p-adic value of an integer `z ≠ 0` is its p-adic_value as a rational -/ +@[simp] lemma of_nat {n : ℕ} : padic_val_rat p (n : ℚ) = padic_val_nat p n := +by simp [padic_val_rat, padic_val_int] + +/-- For `p ≠ 0, p ≠ 1, `padic_val_rat p p` is 1. -/ +lemma self (hp : 1 < p) : padic_val_rat p p = 1 := by simp [of_nat, hp] + +end padic_val_rat section padic_val_nat -/-- -`padic_val_nat` is defined as an `int.to_nat` cast; -this lemma ensures that the cast is well-behaved. --/ -lemma zero_le_padic_val_rat_of_nat (p n : ℕ) : 0 ≤ padic_val_rat p n := -begin - unfold padic_val_rat, - split_ifs, - { simp, }, - { trivial, }, -end +lemma zero_le_padic_val_rat_of_nat (p n : ℕ) : 0 ≤ padic_val_rat p n := by simp -/-- -`padic_val_rat` coincides with `padic_val_nat`. --/ -@[simp, norm_cast] lemma padic_val_rat_of_nat (p n : ℕ) : +-- /-- `padic_val_rat` coincides with `padic_val_nat`. -/ +@[norm_cast] lemma padic_val_rat_of_nat (p n : ℕ) : ↑(padic_val_nat p n) = padic_val_rat p n := -begin - unfold padic_val_nat, - rw int.to_nat_of_nonneg (zero_le_padic_val_rat_of_nat p n), -end +by simp [padic_val_rat, padic_val_int] /-- A simplification of `padic_val_nat` when one input is prime, by analogy with `padic_val_rat_def`. -/ -lemma padic_val_nat_def {p : ℕ} [hp : fact p.prime] {n : ℕ} (hn : n ≠ 0) : +lemma padic_val_nat_def {p : ℕ} [hp : fact p.prime] {n : ℕ} (hn : 0 < n) : padic_val_nat p n = (multiplicity p n).get - (multiplicity.finite_nat_iff.2 ⟨nat.prime.ne_one hp.1, bot_lt_iff_ne_bot.mpr hn⟩) := + (multiplicity.finite_nat_iff.2 ⟨nat.prime.ne_one hp.1, hn⟩) := begin - have n_nonzero : (n : ℚ) ≠ 0, by simpa only [cast_eq_zero, ne.def], - -- Infinite loop with @simp padic_val_rat_of_nat unless we restrict the available lemmas here, - -- hence the very long list - simpa only - [ int.coe_nat_multiplicity p n, rat.coe_nat_denom n, (padic_val_rat_of_nat p n).symm, - int.coe_nat_zero, int.coe_nat_inj', sub_zero, get_one_right, int.coe_nat_succ, zero_add, - rat.coe_nat_num ] - using padic_val_rat_def p n_nonzero, + simp [padic_val_nat], + split_ifs, + { refl, }, + { exfalso, + apply h ⟨(hp.out).ne_one, hn⟩, } end @[simp] lemma padic_val_nat_self (p : ℕ) [fact p.prime] : padic_val_nat p p = 1 := -by simp [padic_val_nat_def (fact.out p.prime).ne_zero] +by simp [padic_val_nat_def (fact.out p.prime).pos] lemma one_le_padic_val_nat_of_dvd - {n p : nat} [prime : fact p.prime] (nonzero : n ≠ 0) (div : p ∣ n) : + {n p : nat} [prime : fact p.prime] (n_pos : 0 < n) (div : p ∣ n) : 1 ≤ padic_val_nat p n := begin - rw @padic_val_nat_def _ prime _ nonzero, + rw @padic_val_nat_def _ prime _ n_pos, let one_le_mul : _ ≤ multiplicity p n := @multiplicity.le_multiplicity_of_pow_dvd _ _ _ p n 1 (begin norm_num, exact div end), simp only [nat.cast_one] at one_le_mul, @@ -185,12 +239,6 @@ begin solve_by_elim, end -@[simp] -lemma padic_val_nat_zero (m : nat) : padic_val_nat m 0 = 0 := rfl - -@[simp] -lemma padic_val_nat_one (m : nat) : padic_val_nat m 1 = 0 := by simp [padic_val_nat] - end padic_val_nat namespace padic_val_rat @@ -198,15 +246,11 @@ open multiplicity variables (p : ℕ) [p_prime : fact p.prime] include p_prime -/-- -The multiplicity of `p : ℕ` in `a : ℤ` is finite exactly when `a ≠ 0`. --/ +/-- The multiplicity of `p : ℕ` in `a : ℤ` is finite exactly when `a ≠ 0`. -/ lemma finite_int_prime_iff {p : ℕ} [p_prime : fact p.prime] {a : ℤ} : finite (p : ℤ) a ↔ a ≠ 0 := by simp [finite_int_iff, ne.symm (ne_of_lt (p_prime.1.one_lt))] -/-- -A rewrite lemma for `padic_val_rat p q` when `q` is expressed in terms of `rat.mk`. --/ +/-- A rewrite lemma for `padic_val_rat p q` when `q` is expressed in terms of `rat.mk`. -/ protected lemma defn {q : ℚ} {n d : ℤ} (hqz : q ≠ 0) (qdf : q = n /. d) : padic_val_rat p q = (multiplicity (p : ℤ) n).get (finite_int_iff.2 ⟨ne.symm $ ne_of_lt p_prime.1.one_lt, λ hn, by simp * at *⟩) - @@ -214,13 +258,14 @@ protected lemma defn {q : ℚ} {n d : ℤ} (hqz : q ≠ 0) (qdf : q = n /. d) : λ hd, by simp * at *⟩) := have hd : d ≠ 0, from rat.mk_denom_ne_zero_of_ne_zero hqz qdf, let ⟨c, hc1, hc2⟩ := rat.num_denom_mk hd qdf in -by rw [padic_val_rat, dif_pos]; +begin + rw [padic_val_rat.multiplicity_sub_multiplicity]; simp [hc1, hc2, multiplicity.mul' (nat.prime_iff_prime_int.1 p_prime.1), - (ne.symm (ne_of_lt p_prime.1.one_lt)), hqz] + (ne.symm (ne_of_lt p_prime.1.one_lt)), hqz, pos_iff_ne_zero], + simp_rw [int.coe_nat_multiplicity p q.denom], +end -/-- -A rewrite lemma for `padic_val_rat p (q * r)` with conditions `q ≠ 0`, `r ≠ 0`. --/ +/-- A rewrite lemma for `padic_val_rat p (q * r)` with conditions `q ≠ 0`, `r ≠ 0`. -/ protected lemma mul {q r : ℚ} (hq : q ≠ 0) (hr : r ≠ 0) : padic_val_rat p (q * r) = padic_val_rat p q + padic_val_rat p r := have q*r = (q.num * r.num) /. (↑q.denom * ↑r.denom), by rw_mod_cast rat.mul_num_denom, @@ -234,9 +279,7 @@ begin rw [multiplicity.mul' hp', multiplicity.mul' hp']; simp [add_comm, add_left_comm, sub_eq_add_neg] end -/-- -A rewrite lemma for `padic_val_rat p (q^k)` with condition `q ≠ 0`. --/ +/-- A rewrite lemma for `padic_val_rat p (q^k)` with condition `q ≠ 0`. -/ protected lemma pow {q : ℚ} (hq : q ≠ 0) {k : ℕ} : padic_val_rat p (q ^ k) = k * padic_val_rat p q := by induction k; simp [*, padic_val_rat.mul _ hq (pow_ne_zero _ hq), @@ -254,9 +297,7 @@ begin inv_mul_cancel hq, padic_val_rat.one] }, end -/-- -A rewrite lemma for `padic_val_rat p (q / r)` with conditions `q ≠ 0`, `r ≠ 0`. --/ +/-- A rewrite lemma for `padic_val_rat p (q / r)` with conditions `q ≠ 0`, `r ≠ 0`. -/ protected lemma div {q r : ℚ} (hq : q ≠ 0) (hr : r ≠ 0) : padic_val_rat p (q / r) = padic_val_rat p q - padic_val_rat p r := by rw [div_eq_mul_inv, padic_val_rat.mul p hq (inv_ne_zero hr), @@ -353,9 +394,7 @@ end padic_val_rat namespace padic_val_nat -/-- -A rewrite lemma for `padic_val_nat p (q * r)` with conditions `q ≠ 0`, `r ≠ 0`. --/ +/-- A rewrite lemma for `padic_val_nat p (q * r)` with conditions `q ≠ 0`, `r ≠ 0`. -/ protected lemma mul (p : ℕ) [p_prime : fact p.prime] {q r : ℕ} (hq : q ≠ 0) (hr : r ≠ 0) : padic_val_nat p (q * r) = padic_val_nat p q + padic_val_nat p r := begin @@ -377,9 +416,7 @@ begin rw [mul_comm, k.mul_div_cancel hb.bot_lt, padic_val_nat.mul p hk hb, nat.add_sub_cancel] end -/-- -Dividing out by a prime factor reduces the padic_val_nat by 1. --/ +/-- Dividing out by a prime factor reduces the padic_val_nat by 1. -/ protected lemma div {p : ℕ} [p_prime : fact p.prime] {b : ℕ} (dvd : p ∣ b) : (padic_val_nat p (b / p)) = (padic_val_nat p b) - 1 := begin @@ -410,24 +447,11 @@ end padic_val_nat section padic_val_nat -/-- -If a prime doesn't appear in `n`, `padic_val_nat p n` is `0`. --/ -lemma padic_val_nat_of_not_dvd {p : ℕ} [fact p.prime] {n : ℕ} (not_dvd : ¬(p ∣ n)) : - padic_val_nat p n = 0 := -begin - by_cases hn : n = 0, - { subst hn, simp at not_dvd, trivial, }, - { rw padic_val_nat_def hn, - exact (@multiplicity.unique' _ _ _ p n 0 (by simp) (by simpa using not_dvd)).symm, - assumption, }, -end - -lemma dvd_of_one_le_padic_val_nat {n p : nat} [prime : fact p.prime] (hp : 1 ≤ padic_val_nat p n) : +lemma dvd_of_one_le_padic_val_nat {n p : nat} (hp : 1 ≤ padic_val_nat p n) : p ∣ n := begin by_contra h, - rw padic_val_nat_of_not_dvd h at hp, + rw padic_val_nat.eq_zero_of_not_dvd h at hp, exact lt_irrefl 0 (lt_of_lt_of_le zero_lt_one hp), end @@ -437,7 +461,7 @@ begin { rw hn, exact dvd_zero (p ^ padic_val_nat p 0) }, { rw multiplicity.pow_dvd_iff_le_multiplicity, apply le_of_eq, - rw padic_val_nat_def (ne_of_gt hn), + rw padic_val_nat_def hn, { apply enat.coe_get }, { apply_instance } } end @@ -446,16 +470,38 @@ lemma pow_succ_padic_val_nat_not_dvd {p n : ℕ} [hp : fact (nat.prime p)] (hn : ¬ p ^ (padic_val_nat p n + 1) ∣ n := begin rw multiplicity.pow_dvd_iff_le_multiplicity, - rw padic_val_nat_def (ne_of_gt hn), + rw padic_val_nat_def hn, { rw [nat.cast_add, enat.coe_get], simp only [nat.cast_one, not_le], - apply enat.lt_add_one (ne_top_iff_finite.2 (finite_nat_iff.2 ⟨hp.elim.ne_one, hn⟩)) }, + exact enat.lt_add_one (ne_top_iff_finite.mpr + (finite_nat_iff.mpr ⟨(fact.elim hp).ne_one, hn⟩)), }, { apply_instance } end +lemma padic_val_nat_dvd_iff (p : ℕ) [hp :fact p.prime] (n : ℕ) (a : ℕ) : + p^n ∣ a ↔ a = 0 ∨ n ≤ padic_val_nat p a := +begin + split, + { rw pow_dvd_iff_le_multiplicity, + rw padic_val_nat, + split_ifs, + rw enat.coe_le_iff, + intro hn, + right, + apply hn, + simp [hp.out.ne_one] at h, + rw h, + simp, }, + { intro h, + cases h, + rw h, + exact dvd_zero (p ^ n), + exact dvd_trans (pow_dvd_pow p h) pow_padic_val_nat_dvd, }, +end + lemma padic_val_nat_primes {p q : ℕ} [p_prime : fact p.prime] [q_prime : fact q.prime] (neq : p ≠ q) : padic_val_nat p q = 0 := -@padic_val_nat_of_not_dvd p p_prime q $ +@padic_val_nat.eq_zero_of_not_dvd p q $ (not_congr (iff.symm (prime_dvd_prime_iff_eq p_prime.1 q_prime.1))).mp neq protected lemma padic_val_nat.div' {p : ℕ} [p_prime : fact p.prime] : @@ -469,7 +515,7 @@ protected lemma padic_val_nat.div' {p : ℕ} [p_prime : fact p.prime] : { rw [hc, mul_zero] }, { rw padic_val_nat.mul, { suffices : ¬ p ∣ (n+1), - { rw [padic_val_nat_of_not_dvd this, zero_add] }, + { rw [padic_val_nat.eq_zero_of_not_dvd this, zero_add] }, contrapose! cpm, exact p_prime.1.dvd_iff_not_coprime.mp cpm }, { exact nat.succ_ne_zero _ }, @@ -480,7 +526,7 @@ lemma padic_val_nat_eq_factorization (p n : ℕ) [hp : fact p.prime] : padic_val_nat p n = n.factorization p := begin by_cases hn : n = 0, { subst hn, simp }, - rw @padic_val_nat_def p _ n hn, + rw @padic_val_nat_def p _ n (nat.pos_of_ne_zero hn), simp [@multiplicity_eq_factorization n p hp.elim hn], end @@ -532,6 +578,49 @@ end end padic_val_nat +section padic_val_int +variables (p : ℕ) [p_prime : fact p.prime] + +lemma padic_val_int_dvd_iff (p : ℕ) [fact p.prime] (n : ℕ) (a : ℤ) : + ↑p^n ∣ a ↔ a = 0 ∨ n ≤ padic_val_int p a := +by rw [padic_val_int, ←int.nat_abs_eq_zero, ←padic_val_nat_dvd_iff, ←int.coe_nat_dvd_left, + int.coe_nat_pow] + +lemma padic_val_int_dvd (p : ℕ) [fact p.prime] (a : ℤ) : ↑p^(padic_val_int p a) ∣ a := +begin + rw padic_val_int_dvd_iff, + simp only [le_refl, or_true], +end + +lemma padic_val_int_self (p : ℕ) [pp : fact p.prime] : padic_val_int p p = 1 := +begin + apply padic_val_int.self, + exact pp.out.one_lt, +end + +lemma padic_val_int.mul (p : ℕ) [fact p.prime] {a b : ℤ} (ha : a ≠ 0) (hb : b ≠ 0) : + padic_val_int p (a*b) = padic_val_int p a + padic_val_int p b := +begin + simp_rw padic_val_int, + rw int.nat_abs_mul, + rw padic_val_nat.mul; + rwa int.nat_abs_ne_zero, +end + +lemma padic_val_int_mul_eq_succ (p : ℕ) [pp : fact p.prime] (a : ℤ) (ha : a ≠ 0) : + padic_val_int p (a * p) = (padic_val_int p a) + 1 := +begin + rw padic_val_int.mul, + congr, + simp only [eq_self_iff_true, padic_val_int.of_nat, padic_val_nat_self], + assumption, + simp only [int.coe_nat_eq_zero, ne.def], + exact (pp.out).ne_zero, +end + +end padic_val_int + + /-- If `q ≠ 0`, the p-adic norm of a rational `q` is `p ^ (-(padic_val_rat p q))`. If `q = 0`, the p-adic norm of `q` is 0. @@ -545,16 +634,12 @@ section padic_norm open padic_val_rat variables (p : ℕ) -/-- -Unfolds the definition of the p-adic norm of `q` when `q ≠ 0`. --/ +/-- Unfolds the definition of the p-adic norm of `q` when `q ≠ 0`. -/ @[simp] protected lemma eq_zpow_of_nonzero {q : ℚ} (hq : q ≠ 0) : padic_norm p q = p ^ (-(padic_val_rat p q)) := by simp [hq, padic_norm] -/-- -The p-adic norm is nonnegative. --/ +/-- The p-adic norm is nonnegative. -/ protected lemma nonneg (q : ℚ) : 0 ≤ padic_norm p q := if hq : q = 0 then by simp [hq, padic_norm] else @@ -564,14 +649,10 @@ else exact_mod_cast nat.zero_le _ end -/-- -The p-adic norm of 0 is 0. --/ +/-- The p-adic norm of 0 is 0. -/ @[simp] protected lemma zero : padic_norm p 0 = 0 := by simp [padic_norm] -/-- -The p-adic norm of 1 is 1. --/ +/-- The p-adic norm of 1 is 1. -/ @[simp] protected lemma one : padic_norm p 1 = 1 := by simp [padic_norm] /-- @@ -580,7 +661,7 @@ The p-adic norm of `p` is `1/p` if `p > 1`. See also `padic_norm.padic_norm_p_of_prime` for a version that assumes `p` is prime. -/ lemma padic_norm_p {p : ℕ} (hp : 1 < p) : padic_norm p p = 1 / p := -by simp [padic_norm, (show p ≠ 0, by linarith), padic_val_rat.padic_val_rat_self hp] +by simp [padic_norm, (show p ≠ 0, by linarith), padic_val_nat.self hp] /-- The p-adic norm of `p` is `1/p` if `p` is prime. @@ -619,15 +700,11 @@ See also `padic_norm.padic_norm_p_lt_one` for a version assuming `1 < p`. lemma padic_norm_p_lt_one_of_prime (p : ℕ) [fact p.prime] : padic_norm p p < 1 := padic_norm_p_lt_one $ nat.prime.one_lt (fact.out _) -/-- -`padic_norm p q` takes discrete values `p ^ -z` for `z : ℤ`. --/ +/-- `padic_norm p q` takes discrete values `p ^ -z` for `z : ℤ`. -/ protected theorem values_discrete {q : ℚ} (hq : q ≠ 0) : ∃ z : ℤ, padic_norm p q = p ^ (-z) := ⟨ (padic_val_rat p q), by simp [padic_norm, hq] ⟩ -/-- -`padic_norm p` is symmetric. --/ +/-- `padic_norm p` is symmetric. -/ @[simp] protected lemma neg (q : ℚ) : padic_norm p (-q) = padic_norm p q := if hq : q = 0 then by simp [hq] else by simp [padic_norm, hq] @@ -635,9 +712,7 @@ else by simp [padic_norm, hq] variable [hp : fact p.prime] include hp -/-- -If `q ≠ 0`, then `padic_norm p q ≠ 0`. --/ +/-- If `q ≠ 0`, then `padic_norm p q ≠ 0`. -/ protected lemma nonzero {q : ℚ} (hq : q ≠ 0) : padic_norm p q ≠ 0 := begin rw padic_norm.eq_zpow_of_nonzero p hq, @@ -645,9 +720,7 @@ begin exact_mod_cast ne_of_gt hp.1.pos end -/-- -If the p-adic norm of `q` is 0, then `q` is 0. --/ +/-- If the p-adic norm of `q` is 0, then `q` is 0. -/ lemma zero_of_padic_norm_eq_zero {q : ℚ} (h : padic_norm p q = 0) : q = 0 := begin apply by_contradiction, intro hq, @@ -657,9 +730,7 @@ begin exact_mod_cast hp.1.ne_zero end -/-- -The p-adic norm is multiplicative. --/ +/-- The p-adic norm is multiplicative. -/ @[simp] protected theorem mul (q r : ℚ) : padic_norm p (q*r) = padic_norm p q * padic_norm p r := if hq : q = 0 then by simp [hq] @@ -670,16 +741,12 @@ else have (↑p : ℚ) ≠ 0, by simp [hp.1.ne_zero], by simp [padic_norm, *, padic_val_rat.mul, zpow_add₀ this, mul_comm] -/-- -The p-adic norm respects division. --/ +/-- The p-adic norm respects division. -/ @[simp] protected theorem div (q r : ℚ) : padic_norm p (q / r) = padic_norm p q / padic_norm p r := if hr : r = 0 then by simp [hr] else eq_div_of_mul_eq (padic_norm.nonzero _ hr) (by rw [←padic_norm.mul, div_mul_cancel _ hr]) -/-- -The p-adic norm of an integer is at most 1. --/ +/-- The p-adic norm of an integer is at most 1. -/ protected theorem of_int (z : ℤ) : padic_norm p ↑z ≤ 1 := if hz : z = 0 then by simp [hz, zero_le_one] else begin @@ -687,9 +754,9 @@ begin rw [if_neg _], { refine zpow_le_one_of_nonpos _ _, { exact_mod_cast le_of_lt hp.1.one_lt, }, - { rw [padic_val_rat_of_int _ hp.1.ne_one hz, neg_nonpos], + { rw [padic_val_rat.of_int, neg_nonpos], norm_cast, simp }}, - exact_mod_cast hz + exact_mod_cast hz, end private lemma nonarchimedean_aux {q r : ℚ} (h : padic_val_rat p q ≤ padic_val_rat p r) : @@ -794,7 +861,8 @@ begin { norm_cast at hz, have : 0 ≤ (p^n : ℚ), {apply pow_nonneg, exact_mod_cast le_of_lt hp.1.pos }, simp [hz, this] }, - { rw [zpow_le_iff_le, neg_le_neg_iff, padic_val_rat_of_int _ hp.1.ne_one _], + { rw [zpow_le_iff_le, neg_le_neg_iff, padic_val_rat.of_int, + padic_val_int.of_ne_one_ne_zero hp.1.ne_one _], { norm_cast, rw [← enat.coe_le_coe, enat.coe_get, ← multiplicity.pow_dvd_iff_le_multiplicity], simp }, diff --git a/src/number_theory/padics/padic_numbers.lean b/src/number_theory/padics/padic_numbers.lean index 5eac8cfc4797d..2cc7a6357e7b7 100644 --- a/src/number_theory/padics/padic_numbers.lean +++ b/src/number_theory/padics/padic_numbers.lean @@ -557,7 +557,7 @@ begin { have := stationary_point_spec hne le_rfl (le_of_not_le hngen), rw ←this, apply hN, - exact le_rfl, assumption } + exact le_rfl, assumption }, end protected lemma nonneg (q : ℚ_[p]) : 0 ≤ padic_norm_e q := @@ -817,7 +817,8 @@ end begin have p₀ : p ≠ 0 := hp.1.ne_zero, have p₁ : p ≠ 1 := hp.1.ne_one, - simp [p₀, p₁, norm, padic_norm, padic_val_rat, zpow_neg, padic.cast_eq_of_rat_of_nat], + simp [p₀, p₁, norm, padic_norm, padic_val_rat, padic_val_int, zpow_neg, + padic.cast_eq_of_rat_of_nat], end lemma norm_p_lt_one : ∥(p : ℚ_[p])∥ < 1 := @@ -865,13 +866,14 @@ theorem norm_rat_le_one : ∀ {q : ℚ} (hq : ¬ p ∣ q.denom), ∥(q : ℚ_[p] from mt rat.zero_iff_num_zero.1 hnz, rw [padic_norm_e.eq_padic_norm], norm_cast, - rw [padic_norm.eq_zpow_of_nonzero p hnz', padic_val_rat_def p hnz'], - have h : (multiplicity p d).get _ = 0, by simp [multiplicity_eq_zero_of_not_dvd, hq], - simp only, norm_cast, - rw_mod_cast [h, sub_zero], - apply zpow_le_one_of_nonpos, - { exact_mod_cast le_of_lt hp.1.one_lt, }, - { apply neg_nonpos_of_nonneg, norm_cast, simp, } + rw [padic_norm.eq_zpow_of_nonzero p hnz', padic_val_rat, neg_sub, + padic_val_nat.eq_zero_of_not_dvd hq], + norm_cast, + rw [zero_sub, zpow_neg₀, zpow_coe_nat], + apply inv_le_one, + { norm_cast, + apply one_le_pow, + exact hp.1.pos, }, end theorem norm_int_le_one (z : ℤ) : ∥(z : ℚ_[p])∥ ≤ 1 := @@ -897,11 +899,9 @@ begin apply dvd_zero }, { norm_cast at H ⊢, convert zpow_zero _, - simp only [neg_eq_zero], - rw padic_val_rat.padic_val_rat_of_int _ hp.1.ne_one H, + rw [neg_eq_zero, padic_val_rat.of_int], norm_cast, - rw [← enat.coe_inj, enat.coe_get, nat.cast_zero], - apply multiplicity.multiplicity_eq_zero_of_not_dvd h } }, + apply padic_val_int.eq_zero_of_not_dvd h, } }, { rintro ⟨x, rfl⟩, push_cast, rw padic_norm_e.mul, From 82ef19af142847cd52beac83576107c906f6557c Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 21 Apr 2022 12:09:49 +0000 Subject: [PATCH 117/373] feat(category_theory/path_category): canonical quotient of a path category (#13159) Co-authored-by: Scott Morrison --- src/category_theory/path_category.lean | 70 ++++++++++++++++++++++++++ src/category_theory/quotient.lean | 3 ++ 2 files changed, 73 insertions(+) diff --git a/src/category_theory/path_category.lean b/src/category_theory/path_category.lean index 6623c1350a54d..963973e54270a 100644 --- a/src/category_theory/path_category.lean +++ b/src/category_theory/path_category.lean @@ -4,10 +4,18 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Scott Morrison -/ import category_theory.eq_to_hom +import category_theory.quotient import combinatorics.quiver.path /-! # The category paths on a quiver. +When `C` is a quiver, `paths C` is the category of paths. + +## When the quiver is itself a category +We provide `path_composition : paths C ⥤ C`. + +We check that the quotient of the path category of a category by the canonical relation +(paths are related if they compose to the same path) is equivalent to the original category. -/ universes v₁ v₂ u₁ u₂ @@ -85,6 +93,10 @@ def compose_path {X : C} : Π {Y : C} (p : path X Y), X ⟶ Y | _ path.nil := 𝟙 X | _ (path.cons p e) := compose_path p ≫ e +@[simp] +lemma compose_path_to_path {X Y : C} (f : X ⟶ Y) : compose_path (f.to_path) = f := +category.id_comp _ + @[simp] lemma compose_path_comp {X Y Z : C} (f : path X Y) (g : path Y Z) : compose_path (f.comp g) = compose_path f ≫ compose_path g := @@ -94,6 +106,64 @@ begin { simp [ih], }, end +@[simp] +lemma compose_path_id {X : paths C} : compose_path (𝟙 X) = 𝟙 X := rfl + +@[simp] +lemma compose_path_comp' {X Y Z : paths C} (f : X ⟶ Y) (g : Y ⟶ Z) : + compose_path (f ≫ g) = compose_path f ≫ compose_path g := +compose_path_comp f g + +variables (C) + +/-- Composition of paths as functor from the path category of a category to the category. -/ +@[simps] +def path_composition : paths C ⥤ C := +{ obj := λ X, X, + map := λ X Y f, compose_path f, } + +/-- The canonical relation on the path category of a category: +two paths are related if they compose to the same morphism. -/ +-- TODO: This, and what follows, should be generalized to +-- the `hom_rel` for the kernel of any functor. +-- Indeed, this should be part of an equivalence between congruence relations on a category `C` +-- and full, essentially surjective functors out of `C`. +@[simp] +def paths_hom_rel : hom_rel (paths C) := +λ X Y p q, (path_composition C).map p = (path_composition C).map q + +/-- The functor from a category to the canonical quotient of its path category. -/ +@[simps] +def to_quotient_paths : C ⥤ quotient (paths_hom_rel C) := +{ obj := λ X, quotient.mk X, + map := λ X Y f, quot.mk _ f.to_path, + map_id' := λ X, quot.sound (quotient.comp_closure.of _ _ _ (by simp)), + map_comp' := λ X Y Z f g, quot.sound (quotient.comp_closure.of _ _ _ (by simp)), } + +/-- The functor from the canonical quotient of a path category of a category +to the original category. -/ +@[simps] +def quotient_paths_to : quotient (paths_hom_rel C) ⥤ C := +quotient.lift _ (path_composition C) (λ X Y p q w, w) + +/-- The canonical quotient of the path category of a category +is equivalent to the original category. -/ +def quotient_paths_equiv : quotient (paths_hom_rel C) ≌ C := +{ functor := quotient_paths_to C, + inverse := to_quotient_paths C, + unit_iso := nat_iso.of_components (λ X, by { cases X, refl, }) begin + intros, + cases X, cases Y, + induction f, + dsimp, + simp only [category.comp_id, category.id_comp], + apply quot.sound, + apply quotient.comp_closure.of, + simp [paths_hom_rel], + end, + counit_iso := nat_iso.of_components (λ X, iso.refl _) (by tidy), + functor_unit_iso_comp' := by { intros, cases X, dsimp, simp, refl, }, } + end end category_theory diff --git a/src/category_theory/quotient.lean b/src/category_theory/quotient.lean index 4bea125ea7b4d..94b63d2b1c21d 100644 --- a/src/category_theory/quotient.lean +++ b/src/category_theory/quotient.lean @@ -50,6 +50,9 @@ inductive comp_closure ⦃s t : C⦄ : (s ⟶ t) → (s ⟶ t) → Prop | intro {a b} (f : s ⟶ a) (m₁ m₂ : a ⟶ b) (g : b ⟶ t) (h : r m₁ m₂) : comp_closure (f ≫ m₁ ≫ g) (f ≫ m₂ ≫ g) +lemma comp_closure.of {a b} (m₁ m₂ : a ⟶ b) (h : r m₁ m₂) : comp_closure r m₁ m₂ := +by simpa using comp_closure.intro (𝟙 _) m₁ m₂ (𝟙 _) h + lemma comp_left {a b c : C} (f : a ⟶ b) : Π (g₁ g₂ : b ⟶ c) (h : comp_closure r g₁ g₂), comp_closure r (f ≫ g₁) (f ≫ g₂) | _ _ ⟨x, m₁, m₂, y, h⟩ := by simpa using comp_closure.intro (f ≫ x) m₁ m₂ y h From cf3b996e17af2aae5331c242d7cca6902bf5802b Mon Sep 17 00:00:00 2001 From: Julian Berman Date: Thu, 21 Apr 2022 12:09:50 +0000 Subject: [PATCH 118/373] feat(group_theory/torsion): extension closedness, and torsion scalars in modules (#13172) Co-authored by: Alex J. Best --- src/group_theory/order_of_element.lean | 33 ++++++++----- src/group_theory/torsion.lean | 67 ++++++++++++++++++++++---- 2 files changed, 80 insertions(+), 20 deletions(-) diff --git a/src/group_theory/order_of_element.lean b/src/group_theory/order_of_element.lean index 49fc7dbaf1178..06ba702839e36 100644 --- a/src/group_theory/order_of_element.lean +++ b/src/group_theory/order_of_element.lean @@ -68,23 +68,34 @@ lemma is_of_fin_order_iff_pow_eq_one (x : G) : is_of_fin_order x ↔ ∃ n, 0 < n ∧ x ^ n = 1 := by { convert iff.rfl, simp [is_periodic_pt_mul_iff_pow_eq_one] } -/-- Elements of finite order are of finite order in subgroups.-/ +/-- Elements of finite order are of finite order in submonoids.-/ @[to_additive is_of_fin_add_order_iff_coe] -lemma is_of_fin_order_iff_coe {G : Type u} [group G] (H : subgroup G) (x : H) : +lemma is_of_fin_order_iff_coe (H : submonoid G) (x : H) : is_of_fin_order x ↔ is_of_fin_order (x : G) := by { rw [is_of_fin_order_iff_pow_eq_one, is_of_fin_order_iff_pow_eq_one], norm_cast } -/-- Elements of finite order are of finite order in quotient groups.-/ -@[to_additive is_of_fin_add_order_iff_quotient] -lemma is_of_fin_order.quotient {G : Type u} [group G] (N : subgroup G) [N.normal] (x : G) : - is_of_fin_order x → is_of_fin_order (x : G ⧸ N) := begin - rw [is_of_fin_order_iff_pow_eq_one, is_of_fin_order_iff_pow_eq_one], - rintros ⟨n, ⟨npos, hn⟩⟩, - exact ⟨n, ⟨npos, (quotient_group.con N).eq.mpr $ hn ▸ (quotient_group.con N).eq.mp rfl⟩⟩, +/-- The image of an element of finite order has finite order. -/ +@[to_additive add_monoid_hom.is_of_fin_order + "The image of an element of finite additive order has finite additive order."] +lemma monoid_hom.is_of_fin_order + {H : Type v} [monoid H] (f : G →* H) {x : G} (h : is_of_fin_order x) : + is_of_fin_order $ f x := +(is_of_fin_order_iff_pow_eq_one _).mpr $ begin + rcases (is_of_fin_order_iff_pow_eq_one _).mp h with ⟨n, npos, hn⟩, + exact ⟨n, npos, by rw [←f.map_pow, hn, f.map_one]⟩, +end + +/-- If a direct product has finite order then so does each component. -/ +@[to_additive "If a direct product has finite additive order then so does each component."] +lemma is_of_fin_order.apply + {η : Type*} {Gs : η → Type*} [∀ i, monoid (Gs i)] {x : Π i, Gs i} (h : is_of_fin_order x) : +∀ i, is_of_fin_order (x i) := begin + rcases (is_of_fin_order_iff_pow_eq_one _).mp h with ⟨n, npos, hn⟩, + exact λ _, (is_of_fin_order_iff_pow_eq_one _).mpr ⟨n, npos, (congr_fun hn.symm _).symm⟩, end -/-- 1 is of finite order in any group. -/ -@[to_additive "0 is of finite order in any additive group."] +/-- 1 is of finite order in any monoid. -/ +@[to_additive "0 is of finite order in any additive monoid."] lemma is_of_fin_order_one : is_of_fin_order (1 : G) := (is_of_fin_order_iff_pow_eq_one 1).mpr ⟨1, _root_.one_pos, one_pow 1⟩ diff --git a/src/group_theory/torsion.lean b/src/group_theory/torsion.lean index 893f8ad6ddd02..82aff19a43d52 100644 --- a/src/group_theory/torsion.lean +++ b/src/group_theory/torsion.lean @@ -37,7 +37,7 @@ periodic group, torsion subgroup, torsion abelian group * torsion-free groups -/ -variable {G : Type*} +variables {G H : Type*} namespace monoid @@ -64,24 +64,52 @@ noncomputable def is_torsion.group [monoid G] (tG : is_torsion G) : group G := section group -variables [group G] {N : subgroup G} +variables [group G] {N : subgroup G} [group H] /-- Subgroups of torsion groups are torsion groups. -/ @[to_additive "Subgroups of additive torsion groups are additive torsion groups."] lemma is_torsion.subgroup (tG : is_torsion G) (H : subgroup G) : is_torsion H := -λ h, (is_of_fin_order_iff_coe _ h).mpr $ tG h +λ h, (is_of_fin_order_iff_coe H.to_submonoid h).mpr $ tG h + +/-- The image of a surjective torsion group homomorphism is torsion. -/ +@[to_additive add_is_torsion.of_surjective + "The image of a surjective additive torsion group homomorphism is torsion."] +lemma is_torsion.of_surjective {f : G →* H} (hf : function.surjective f) (tG : is_torsion G) : + is_torsion H := +λ h, begin + obtain ⟨g, hg⟩ := hf h, + rw ←hg, + exact f.is_of_fin_order (tG g), +end + +/-- Torsion groups are closed under extensions. -/ +@[to_additive add_is_torsion.extension_closed + "Additive torsion groups are closed under extensions."] +lemma is_torsion.extension_closed + {f : G →* H} (hN : N = f.ker) (tH : is_torsion H) (tN : is_torsion N) : + is_torsion G := +λ g, (is_of_fin_order_iff_pow_eq_one _).mpr $ begin + obtain ⟨ngn, ngnpos, hngn⟩ := (is_of_fin_order_iff_pow_eq_one _).mp (tH $ f g), + have hmem := f.mem_ker.mpr ((f.map_pow g ngn).trans hngn), + lift g ^ ngn to N using hN.symm ▸ hmem with gn, + obtain ⟨nn, nnpos, hnn⟩ := (is_of_fin_order_iff_pow_eq_one _).mp (tN gn), + exact ⟨ngn * nn, mul_pos ngnpos nnpos, by rw [pow_mul, ←h, ←subgroup.coe_pow, + hnn, subgroup.coe_one]⟩ +end -/-- Quotient groups of torsion groups are torsion groups. -/ -@[to_additive "Quotient groups of additive torsion groups are additive torsion groups."] -lemma is_torsion.quotient_group [nN : N.normal] (tG : is_torsion G) : is_torsion (G ⧸ N) := -λ h, quotient_group.induction_on' h $ λ g, (tG g).quotient N g +/-- The image of a quotient is torsion iff the group is torsion. -/ +@[to_additive add_is_torsion.quotient_iff + "The image of a quotient is additively torsion iff the group is torsion."] +lemma is_torsion.quotient_iff + {f : G →* H} (hf : function.surjective f) (hN : N = f.ker) (tN : is_torsion N) : + is_torsion H ↔ is_torsion G := +⟨λ tH, is_torsion.extension_closed hN tH tN, λ tG, is_torsion.of_surjective hf tG⟩ /-- If a group exponent exists, the group is torsion. -/ @[to_additive exponent_exists.is_add_torsion "If a group exponent exists, the group is additively torsion."] -lemma exponent_exists.is_torsion (h : exponent_exists G) : is_torsion G := begin +lemma exponent_exists.is_torsion (h : exponent_exists G) : is_torsion G := λ g, begin obtain ⟨n, npos, hn⟩ := h, - intro g, exact (is_of_fin_order_iff_pow_eq_one g).mpr ⟨n, npos, hn g⟩, end @@ -101,6 +129,27 @@ exponent_exists.is_torsion $ exponent_exists_iff_ne_zero.mpr exponent_ne_zero_of end group +section module + +-- A (semi/)ring of scalars and a commutative monoid of elements +variables (R M : Type*) [add_comm_monoid M] + +namespace add_monoid + +/-- A module whose scalars are additively torsion is additively torsion. -/ +lemma is_torsion.module_of_torsion [semiring R] [module R M] (tR : is_torsion R) : +is_torsion M := λ f, (is_of_fin_add_order_iff_nsmul_eq_zero _).mpr $ begin + obtain ⟨n, npos, hn⟩ := (is_of_fin_add_order_iff_nsmul_eq_zero _).mp (tR 1), + exact ⟨n, npos, by simp only [nsmul_eq_smul_cast R _ f, ←nsmul_one, hn, zero_smul]⟩, +end + +/-- A module with a finite ring of scalars is additively torsion. -/ +lemma is_torsion.module_of_fintype [ring R] [fintype R] [module R M] : is_torsion M := +(is_add_torsion_of_fintype : is_torsion R).module_of_torsion _ _ + +end add_monoid + +end module section comm_monoid From ba455ea6cbba9b9da9a4f2af32f979807dbf920b Mon Sep 17 00:00:00 2001 From: loefflerd Date: Thu, 21 Apr 2022 12:09:51 +0000 Subject: [PATCH 119/373] feat(special_functions/pow): continuity of real to complex power (#13244) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some lemmas excised from my Gamma-function project. The main result is that for a complex `s` with `re s > 0`, the function `(λ x, x ^ s : ℝ → ℂ)` is continuous on all of `ℝ`. Co-authored-by: Yury G. Kudryashov --- src/analysis/special_functions/pow.lean | 48 +++++++++++++++++++++++-- src/data/complex/basic.lean | 4 +++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/analysis/special_functions/pow.lean b/src/analysis/special_functions/pow.lean index 1bd538b548a94..7e0daa561c338 100644 --- a/src/analysis/special_functions/pow.lean +++ b/src/analysis/special_functions/pow.lean @@ -387,6 +387,17 @@ namespace complex lemma of_real_cpow {x : ℝ} (hx : 0 ≤ x) (y : ℝ) : ((x ^ y : ℝ) : ℂ) = (x : ℂ) ^ (y : ℂ) := by simp [real.rpow_def_of_nonneg hx, complex.cpow_def]; split_ifs; simp [complex.of_real_log hx] +lemma of_real_cpow_of_nonpos {x : ℝ} (hx : x ≤ 0) (y : ℂ) : + (x : ℂ) ^ y = ((-x) : ℂ) ^ y * exp (π * I * y) := +begin + rcases hx.eq_or_lt with rfl|hlt, + { rcases eq_or_ne y 0 with rfl|hy; simp * }, + have hne : (x : ℂ) ≠ 0, from of_real_ne_zero.mpr hlt.ne, + rw [cpow_def_of_ne_zero hne, cpow_def_of_ne_zero (neg_ne_zero.2 hne), ← exp_add, ← add_mul, + log, log, abs_neg, arg_of_real_of_neg hlt, ← of_real_neg, + arg_of_real_of_nonneg (neg_nonneg.2 hx), of_real_zero, zero_mul, add_zero] +end + lemma abs_cpow_of_ne_zero {z : ℂ} (hz : z ≠ 0) (w : ℂ) : abs (z ^ w) = abs z ^ w.re / real.exp (arg z * im w) := by rw [cpow_def_of_ne_zero hz, abs_exp, mul_re, log_re, log_im, real.exp_sub, @@ -412,7 +423,7 @@ by rw [abs_cpow_of_ne_zero (of_real_ne_zero.mpr hx.ne'), arg_of_real_of_nonneg h real.exp_zero, div_one, abs_of_nonneg hx.le] lemma abs_cpow_eq_rpow_re_of_nonneg {x : ℝ} (hx : 0 ≤ x) {y : ℂ} (hy : re y ≠ 0) : - abs (x ^ y) = x ^ y.re := + abs (x ^ y) = x ^ re y := begin rcases hx.eq_or_lt with rfl|hlt, { rw [of_real_zero, zero_cpow, abs_zero, real.zero_rpow hy], @@ -966,7 +977,7 @@ end limits namespace complex -/-- See also `complex.continuous_at_cpow`. -/ +/-- See also `complex.continuous_at_cpow` and `complex.continuous_at_cpow_of_re_pos`. -/ lemma continuous_at_cpow_zero_of_re_pos {z : ℂ} (hz : 0 < z.re) : continuous_at (λ x : ℂ × ℂ, x.1 ^ x.2) (0, z) := begin @@ -987,6 +998,39 @@ begin (_root_.abs_nonneg _) real.pi_pos.le } end +/-- See also `complex.continuous_at_cpow` for a version that assumes `p.1 ≠ 0` but makes no +assumptions about `p.2`. -/ +lemma continuous_at_cpow_of_re_pos {p : ℂ × ℂ} (h₁ : 0 ≤ p.1.re ∨ p.1.im ≠ 0) (h₂ : 0 < p.2.re) : + continuous_at (λ x : ℂ × ℂ, x.1 ^ x.2) p := +begin + cases p with z w, + rw [← not_lt_zero_iff, lt_iff_le_and_ne, not_and_distrib, ne.def, not_not, not_le_zero_iff] at h₁, + rcases h₁ with h₁|(rfl : z = 0), + exacts [continuous_at_cpow h₁, continuous_at_cpow_zero_of_re_pos h₂] +end + +/-- See also `complex.continuous_at_cpow_const` for a version that assumes `z ≠ 0` but makes no +assumptions about `w`. -/ +lemma continuous_at_cpow_const_of_re_pos {z w : ℂ} (hz : 0 ≤ re z ∨ im z ≠ 0) (hw : 0 < re w) : + continuous_at (λ x, x ^ w) z := +tendsto.comp (@continuous_at_cpow_of_re_pos (z, w) hz hw) + (continuous_at_id.prod continuous_at_const) + +lemma continuous_of_real_cpow_const {y : ℂ} (hs : 0 < y.re) : continuous (λ x, x ^ y : ℝ → ℂ) := +begin + rw continuous_iff_continuous_at, intro x, + cases le_or_lt 0 x with hx hx, + { refine (continuous_at_cpow_const_of_re_pos _ hs).comp continuous_of_real.continuous_at, + exact or.inl hx }, + { suffices : continuous_on (λ x, x ^ y : ℝ → ℂ) (set.Iio 0), + from continuous_on.continuous_at this (Iio_mem_nhds hx), + have : eq_on (λ x, x ^ y : ℝ → ℂ) (λ x, ((-x) : ℂ) ^ y * exp (π * I * y)) (set.Iio 0), + from λ y hy, of_real_cpow_of_nonpos (le_of_lt hy) _, + refine (continuous_on.mul (λ y hy, _) continuous_on_const).congr this, + refine continuous_of_real.continuous_within_at.neg.cpow continuous_within_at_const _, + left, simpa using hy } +end + end complex namespace nnreal diff --git a/src/data/complex/basic.lean b/src/data/complex/basic.lean index 71b96d9d9275f..abc0a81f71de2 100644 --- a/src/data/complex/basic.lean +++ b/src/data/complex/basic.lean @@ -599,7 +599,11 @@ lemma lt_def {z w : ℂ} : z < w ↔ z.re < w.re ∧ z.im = w.im := iff.rfl lemma not_le_iff {z w : ℂ} : ¬(z ≤ w) ↔ w.re < z.re ∨ z.im ≠ w.im := by rw [le_def, not_and_distrib, not_le] +lemma not_lt_iff {z w : ℂ} : ¬(z < w) ↔ w.re ≤ z.re ∨ z.im ≠ w.im := +by rw [lt_def, not_and_distrib, not_lt] + lemma not_le_zero_iff {z : ℂ} : ¬z ≤ 0 ↔ 0 < z.re ∨ z.im ≠ 0 := not_le_iff +lemma not_lt_zero_iff {z : ℂ} : ¬z < 0 ↔ 0 ≤ z.re ∨ z.im ≠ 0 := not_lt_iff /-- With `z ≤ w` iff `w - z` is real and nonnegative, `ℂ` is an ordered ring. From 7d61199acd9d7a469c8eeaf9ca4eb9ba065a2607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Thu, 21 Apr 2022 12:09:53 +0000 Subject: [PATCH 120/373] feat(set_theory/cofinality): Basic fundamental sequences (#13326) --- src/set_theory/cardinal/cofinality.lean | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/set_theory/cardinal/cofinality.lean b/src/set_theory/cardinal/cofinality.lean index 1495460b762b7..ebf76d959306b 100644 --- a/src/set_theory/cardinal/cofinality.lean +++ b/src/set_theory/cardinal/cofinality.lean @@ -426,6 +426,23 @@ hf.2.1 theorem is_fundamental_sequence.blsub_eq : blsub.{u u} o f = a := hf.2.2 +theorem is_fundamental_sequence_id_of_le_cof (h : o ≤ o.cof.ord) : + is_fundamental_sequence o o (λ a _, a) := +⟨h, λ _ _ _ _, id, blsub_id o⟩ + +theorem is_fundamental_sequence_zero {f : Π b < (0 : ordinal), ordinal} : + is_fundamental_sequence 0 0 f := +⟨by rw [cof_zero, ord_zero], λ i j hi, (ordinal.not_lt_zero i hi).elim, blsub_zero rfl f⟩ + +theorem is_fundamental_sequence_succ : is_fundamental_sequence o.succ 1 (λ _ _, o) := +begin + refine ⟨_, λ i j hi hj h, _, blsub_const ordinal.one_ne_zero o⟩, + { rw [cof_succ, ord_one] }, + { rw lt_one_iff_zero at hi hj, + rw [hi, hj] at h, + exact h.false.elim } +end + include hf theorem is_fundamental_sequence.monotone {i j : ordinal} (hi : i < o) (hj : j < o) (hij : i ≤ j) : f i hi ≤ f j hj := From 5c2088ed07d7c663b2d53b41c57e5e5467109de1 Mon Sep 17 00:00:00 2001 From: Joachim Breitner Date: Thu, 21 Apr 2022 12:09:54 +0000 Subject: [PATCH 121/373] =?UTF-8?q?feat(algebra/group/to=5Fadditive):=20le?= =?UTF-8?q?t=20@[to=5Fadditive]=20mimic=20alias=E2=80=99s=20docstrings=20(?= =?UTF-8?q?#13330)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit many of our `nolint.txt` entires are due to code of this shape: @[to_additive add_foo] lemma foo := .. /- no docstring -/ alias foo <- bar attribute [to_additive add_bar] bar where now `bar` has a docstring (from `alias`), but `bar_add` does not. This PR makes `to_additive` detect that `bar` is an alias, and unless an explicit docstring is passed to `to_additive`, creates an “alias of add_foo” docstring. --- src/algebra/group/to_additive.lean | 6 +++++- src/data/buffer/parser/basic.lean | 1 + src/tactic/alias.lean | 5 ++--- test/lint_to_additive_doc.lean | 15 ++++++++++++++- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/algebra/group/to_additive.lean b/src/algebra/group/to_additive.lean index 8de9b01f245f6..1b16d6cb7ad9f 100644 --- a/src/algebra/group/to_additive.lean +++ b/src/algebra/group/to_additive.lean @@ -6,6 +6,7 @@ Authors: Mario Carneiro, Yury Kudryashov, Floris van Doorn import tactic.transform_decl import tactic.algebra import tactic.lint.basic +import tactic.alias /-! # Transport multiplicative to additive @@ -551,7 +552,10 @@ protected meta def attr : user_attribute unit value_type := "versions after"), match val.doc with | some doc := add_doc_string tgt doc - | none := skip + | none := do + some alias_name ← tactic.alias.get_alias_target src | skip, + some add_alias_name ← pure (dict.find alias_name) | skip, + add_doc_string tgt ("**Alias** of `" ++ to_string add_alias_name ++ "`.") end } add_tactic_doc diff --git a/src/data/buffer/parser/basic.lean b/src/data/buffer/parser/basic.lean index 69ad6675304a8..f71151646758a 100644 --- a/src/data/buffer/parser/basic.lean +++ b/src/data/buffer/parser/basic.lean @@ -6,6 +6,7 @@ Authors: Yakov Pechersky import data.string.basic import data.buffer.basic import data.nat.digits +import data.buffer.parser /-! # Parsers diff --git a/src/tactic/alias.lean b/src/tactic/alias.lean index f4df7817a8415..bc09269102fff 100644 --- a/src/tactic/alias.lean +++ b/src/tactic/alias.lean @@ -3,7 +3,6 @@ Copyright (c) 2017 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ -import data.buffer.parser import tactic.core /-! @@ -43,7 +42,7 @@ The `..` notation attempts to generate the 'of'-names automatically when the input theorem has the form `A_iff_B` or `A_iff_B_left` etc. -/ -open lean.parser tactic interactive parser +open lean.parser tactic interactive namespace tactic.alias @@ -81,7 +80,7 @@ meta def alias_iff (d : declaration) (doc : string) (al : name) (iffmp : name) : meta def make_left_right : name → tactic (name × name) | (name.mk_string s p) := do let buf : char_buffer := s.to_char_buffer, - sum.inr parts ← pure $ run (sep_by1 (ch '_') (many_char (sat (≠ '_')))) s.to_char_buffer, + let parts := s.split_on '_', (left, _::right) ← pure $ parts.span (≠ "iff"), let pfx (a b : string) := a.to_list.is_prefix_of b.to_list, (suffix', right') ← pure $ right.reverse.span (λ s, pfx "left" s ∨ pfx "right" s), diff --git a/test/lint_to_additive_doc.lean b/test/lint_to_additive_doc.lean index 0ee82032af2d6..b61731f83fd43 100644 --- a/test/lint_to_additive_doc.lean +++ b/test/lint_to_additive_doc.lean @@ -1,4 +1,5 @@ import algebra.group.to_additive +import tactic.alias /-- Docstring -/ @[to_additive add_foo] @@ -11,11 +12,17 @@ def bar (α : Type*) [has_one α] : α := 1 @[to_additive add_baz "docstring"] def baz (α : Type*) [has_one α] : α := 1 -@[to_additive add_quuz] +@[to_additive add_quux] def quux (α : Type*) [has_one α] : α := 1 def no_to_additive (α : Type*) [has_one α] : α := 1 +-- Aliases always have docstrings, so we do not want to complain if their +-- additive version do not +alias quux <- quux_alias +attribute [to_additive add_quux_alias] quux_alias + + open tactic run_cmd do decl ← get_decl ``foo, @@ -46,3 +53,9 @@ run_cmd do res ← linter.to_additive_doc.test decl, -- linter is happy guard $ res.is_none + +run_cmd do + decl ← get_decl ``quux_alias, + res ← linter.to_additive_doc.test decl, + -- linter is happy + guard $ res.is_none From 761801fd7e1657e5e9cbe667b7dd1cae3d76654c Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Thu, 21 Apr 2022 12:09:55 +0000 Subject: [PATCH 122/373] feat(algebra/monoid_algebra/grading): Use the new graded_algebra API (#13360) This removes `to_grades_by` and `of_grades_by`, and prefers `graded_algebra.decompose` as the canonical spelling. This might undo some of the performance improvements in #13169, but it's not clear where to apply the analogous changes here, or whether they're really needed any more anyway, --- src/algebra/monoid_algebra/grading.lean | 177 +++++++----------------- 1 file changed, 52 insertions(+), 125 deletions(-) diff --git a/src/algebra/monoid_algebra/grading.lean b/src/algebra/monoid_algebra/grading.lean index f1df44861f531..4473ac2be768b 100644 --- a/src/algebra/monoid_algebra/grading.lean +++ b/src/algebra/monoid_algebra/grading.lean @@ -6,6 +6,7 @@ Authors: Eric Wieser import linear_algebra.finsupp import algebra.monoid_algebra.basic import algebra.direct_sum.internal +import ring_theory.graded_algebra.basic /-! # Internal grading of an `add_monoid_algebra` @@ -18,10 +19,10 @@ In this file, we show that an `add_monoid_algebra` has an internal direct sum st degree function `f`. * `add_monoid_algebra.grade R i`: the `i`th grade of an `add_monoid_algebra R M` when the degree function is the identity. -* `add_monoid_algebra.equiv_grade_by`: the equivalence between an `add_monoid_algebra` and the - direct sum of its grades. -* `add_monoid_algebra.equiv_grade`: the equivalence between an `add_monoid_algebra` and the direct - sum of its grades when the degree function is the identity. +* `add_monoid_algebra.grade_by.graded_algebra`: `add_monoid_algebra` is an algebra graded by + `add_monoid_algebra.grade_by`. +* `add_monoid_algebra.grade.graded_algebra`: `add_monoid_algebra` is an algebra graded by + `add_monoid_algebra.grade`. * `add_monoid_algebra.grade_by.is_internal`: propositionally, the statement that `add_monoid_algebra.grade_by` defines an internal graded structure. * `add_monoid_algebra.grade.is_internal`: propositionally, the statement that @@ -72,17 +73,15 @@ end lemma grade_eq_lsingle_range (m : M) : grade R m = (finsupp.lsingle m).range := submodule.ext (mem_grade_iff' R m) -lemma single_mem_grade_by {R} [comm_semiring R] (f : M → ι) (i : ι) (m : M) - (h : f m = i) (r : R) : - finsupp.single m r ∈ grade_by R f i := +lemma single_mem_grade_by {R} [comm_semiring R] (f : M → ι) (m : M) (r : R) : + finsupp.single m r ∈ grade_by R f (f m) := begin intros x hx, rw finset.mem_singleton.mp (finsupp.support_single_subset hx), - exact h end lemma single_mem_grade {R} [comm_semiring R] (i : M) (r : R) : finsupp.single i r ∈ grade R i := -single_mem_grade_by _ _ _ rfl _ +single_mem_grade_by _ _ _ end @@ -113,11 +112,12 @@ by apply grade_by.graded_monoid (add_monoid_hom.id _) variables {R} [add_monoid M] [decidable_eq ι] [add_monoid ι] [comm_semiring R] (f : M →+ ι) -/-- The canonical grade decomposition. -/ -def to_grades_by : add_monoid_algebra R M →ₐ[R] ⨁ i : ι, grade_by R f i := +/-- Auxiliary definition; the canonical grade decomposition, used to provide +`graded_algebra.decompose`. -/ +def decompose_aux : add_monoid_algebra R M →ₐ[R] ⨁ i : ι, grade_by R f i := add_monoid_algebra.lift R M _ { to_fun := λ m, direct_sum.of (λ i : ι, grade_by R f i) (f m.to_add) - ⟨finsupp.single m.to_add 1, single_mem_grade_by _ _ _ rfl _⟩, + ⟨finsupp.single m.to_add 1, single_mem_grade_by _ _ _⟩, map_one' := direct_sum.of_eq_of_graded_monoid_eq (by congr' 2; try {ext}; simp only [submodule.mem_to_add_submonoid, to_add_one, add_monoid_hom.map_zero]), map_mul' := λ i j, begin @@ -131,40 +131,22 @@ add_monoid_algebra.lift R M _ { exact eq.trans (by rw [one_mul, to_add_mul]) single_mul_single.symm } end } -/-- The canonical grade decomposition. -/ -def to_grades : add_monoid_algebra R M →ₐ[R] ⨁ i : M, grade R i := -to_grades_by (add_monoid_hom.id M) - -lemma to_grades_by_single' (i : ι) (m : M) (h : f m = i) (r : R) : - to_grades_by f (finsupp.single m r) = - direct_sum.of (λ i : ι, grade_by R f i) i - ⟨finsupp.single m r, single_mem_grade_by _ _ _ h _⟩ := +lemma decompose_aux_single (m : M) (r : R) : + decompose_aux f (finsupp.single m r) = + direct_sum.of (λ i : ι, grade_by R f i) (f m) + ⟨finsupp.single m r, single_mem_grade_by _ _ _⟩ := begin refine (lift_single _ _ _).trans _, refine (direct_sum.of_smul _ _ _ _).symm.trans _, apply direct_sum.of_eq_of_graded_monoid_eq, - ext, - { exact h }, - { rw graded_monoid.mk, - simp only [mul_one, to_add_of_add, submodule.coe_mk, finsupp.smul_single', - submodule.coe_smul_of_tower] } + refine sigma.subtype_ext rfl _, + refine (finsupp.smul_single' _ _ _).trans _, + rw mul_one, + refl, end -@[simp] -lemma to_grades_by_single (m : M) (r : R) : - to_grades_by f (finsupp.single m r) = direct_sum.of (λ i : ι, grade_by R f i) (f m) - ⟨finsupp.single m r, single_mem_grade_by _ _ _ rfl _⟩ := -by apply to_grades_by_single' - -@[simp] -lemma to_grades_single (i : ι) (r : R) : - to_grades (finsupp.single i r) = - direct_sum.of (λ i : ι, grade R i) i ⟨finsupp.single i r, single_mem_grade _ _⟩ := -by apply to_grades_by_single - -@[simp] -lemma to_grades_by_coe {i : ι} (x : grade_by R f i) : - to_grades_by f ↑x = direct_sum.of (λ i, grade_by R f i) i x := +lemma decompose_aux_coe {i : ι} (x : grade_by R f i) : + decompose_aux f ↑x = direct_sum.of (λ i, grade_by R f i) i x := begin obtain ⟨x, hx⟩ := x, revert hx, @@ -181,7 +163,8 @@ begin have : f m = i, { rwa [finsupp.support_single_ne_zero hb, finset.coe_singleton, set.singleton_subset_iff] at h1 }, - simp only [alg_hom.map_add, submodule.coe_mk, to_grades_by_single' f i m this], + subst this, + simp only [alg_hom.map_add, submodule.coe_mk, decompose_aux_single f m], let ih' := ih h2, dsimp at ih', rw [ih', ← add_monoid_hom.map_add], @@ -189,97 +172,41 @@ begin congr' 2 } end -@[simp] -lemma to_grades_coe {i : ι} (x : grade R i) : - to_grades ↑x = direct_sum.of (λ i, grade R i) i x := -by apply to_grades_by_coe - -/-- The canonical recombination of grades. -/ -def of_grades_by : (⨁ i : ι, grade_by R f i) →ₐ[R] add_monoid_algebra R M := -direct_sum.submodule_coe_alg_hom (grade_by R f) - -/-- The canonical recombination of grades. -/ -def of_grades : (⨁ i : ι, grade R i) →ₐ[R] add_monoid_algebra R ι := -of_grades_by (add_monoid_hom.id ι) +instance grade_by.graded_algebra : graded_algebra (grade_by R f) := +graded_algebra.of_alg_hom _ + (decompose_aux f) + (begin + ext : 2, + dsimp, + rw [decompose_aux_single, direct_sum.submodule_coe_alg_hom_of, subtype.coe_mk], + end) + (λ i x, by convert (decompose_aux_coe f x : _)) + +@[simp] lemma decompose_aux_eq_decompose : + ⇑(decompose_aux f : add_monoid_algebra R M →ₐ[R] ⨁ i : ι, grade_by R f i) = + (graded_algebra.decompose (grade_by R f)) := rfl + +@[simp] lemma grades_by.decompose_single (m : M) (r : R) : + graded_algebra.decompose (grade_by R f) (finsupp.single m r) = + direct_sum.of (λ i : ι, grade_by R f i) (f m) + ⟨finsupp.single m r, single_mem_grade_by _ _ _⟩ := +decompose_aux_single _ _ _ + +instance grade.graded_algebra : graded_algebra (grade R : ι → submodule _ _) := +add_monoid_algebra.grade_by.graded_algebra (add_monoid_hom.id _) @[simp] -lemma of_grades_by_of (i : ι) (x : grade_by R f i) : - of_grades_by f (direct_sum.of (λ i, grade_by R f i) i x) = x := --- Use `simpa only` to help the elaborator decide what to unfold. -by simpa only [of_grades_by] using direct_sum.submodule_coe_alg_hom_of (grade_by R f) i x - -@[simp] -lemma of_grades_of (i : ι) (x : grade R i) : - of_grades (direct_sum.of (λ i, grade R i) i x) = x := -by apply of_grades_by_of - -@[simp] -lemma of_grades_by_comp_to_grades_by : - (of_grades_by f).comp (to_grades_by f) = alg_hom.id R (add_monoid_algebra R M) := -begin - ext : 2, - dsimp only [monoid_hom.coe_comp, alg_hom.coe_to_monoid_hom, alg_hom.coe_comp, function.comp_app, - of_apply, alg_hom.coe_id, function.comp.left_id, id], - rw [to_grades_by_single, of_grades_by_of, subtype.coe_mk], -end - -@[simp] -lemma of_grades_comp_to_grades : - of_grades.comp to_grades = alg_hom.id R (add_monoid_algebra R ι) := -by apply of_grades_by_comp_to_grades_by - -@[simp] -lemma of_grades_by_to_grades_by (x : add_monoid_algebra R M) : - of_grades_by f (to_grades_by f x) = x := -alg_hom.congr_fun (of_grades_by_comp_to_grades_by f) x - -@[simp] -lemma of_grades_to_grades (x : add_monoid_algebra R ι) : of_grades x.to_grades = x := -by apply of_grades_by_to_grades_by - -@[simp] -lemma to_grades_by_comp_of_grades_by : - (to_grades_by f).comp (of_grades_by f) = alg_hom.id R (⨁ i : ι, grade_by R f i) := -begin - ext : 2, - dsimp only [direct_sum.lof_eq_of, linear_map.coe_comp, alg_hom.comp_to_linear_map, - alg_hom.to_linear_map_apply, function.comp_app, alg_hom.coe_id, id], - rw [of_grades_by_of, to_grades_by_coe], -end - -@[simp] -lemma to_grades_comp_of_grades : - to_grades.comp of_grades = alg_hom.id R (⨁ i : ι, grade R i) := -by apply to_grades_by_comp_of_grades_by - -@[simp] -lemma to_grades_by_of_grades_by (g : ⨁ i : ι, grade_by R f i) : - to_grades_by f (of_grades_by f g) = g := -alg_hom.congr_fun (to_grades_by_comp_of_grades_by f) g - -@[simp] -lemma to_grades_of_grades (g : ⨁ i : ι, grade R i) : (of_grades g).to_grades = g := -by apply to_grades_by_of_grades_by - -/-- An `add_monoid_algebra R M` is equivalent as an algebra to the direct sum of its grades. --/ -@[simps] -def equiv_grades_by : add_monoid_algebra R M ≃ₐ[R] ⨁ i : ι, grade_by R f i := -alg_equiv.of_alg_hom _ _ (to_grades_by_comp_of_grades_by f) (of_grades_by_comp_to_grades_by f) - -/-- An `add_monoid_algebra R ι` is equivalent as an algebra to the direct sum of its grades. --/ -@[simps] -def equiv_grades : add_monoid_algebra R ι ≃ₐ[R] ⨁ i : ι, grade R i := -equiv_grades_by (add_monoid_hom.id ι) +lemma grade.decompose_single (i : ι) (r : R) : + graded_algebra.decompose (grade R : ι → submodule _ _) (finsupp.single i r) = + direct_sum.of (λ i : ι, grade R i) i ⟨finsupp.single i r, single_mem_grade _ _⟩ := +decompose_aux_single _ _ _ /-- `add_monoid_algebra.gradesby` describe an internally graded algebra -/ lemma grade_by.is_internal : direct_sum.submodule_is_internal (grade_by R f) := -(equiv_grades_by f).symm.bijective +graded_algebra.is_internal _ /-- `add_monoid_algebra.grades` describe an internally graded algebra -/ lemma grade.is_internal : direct_sum.submodule_is_internal (grade R : ι → submodule R _) := --- Use `simpa only` to help the elaborator decide what to unfold. -by simpa only [grade_by_id] using grade_by.is_internal (add_monoid_hom.id ι) +graded_algebra.is_internal _ end add_monoid_algebra From c30131fb25d73d055d2fa98501dce55c6c4af5be Mon Sep 17 00:00:00 2001 From: negiizhao Date: Thu, 21 Apr 2022 12:09:56 +0000 Subject: [PATCH 123/373] feat(data/polynomial/{derivative, iterated_deriv}): reduce assumptions (#13368) --- src/data/polynomial/derivative.lean | 56 ++++++------ src/data/polynomial/iterated_deriv.lean | 114 +++++++++++------------- 2 files changed, 80 insertions(+), 90 deletions(-) diff --git a/src/data/polynomial/derivative.lean b/src/data/polynomial/derivative.lean index a975e71d46d65..e965a9a62c093 100644 --- a/src/data/polynomial/derivative.lean +++ b/src/data/polynomial/derivative.lean @@ -109,27 +109,25 @@ derivative.to_add_monoid_hom.iterate_map_add _ _ _ derivative (∑ b in s, f b) = ∑ b in s, derivative (f b) := derivative.map_sum -@[simp] lemma derivative_smul (r : R) (p : R[X]) : derivative (r • p) = r • derivative p := -derivative.map_smul _ _ - -@[simp] lemma iterate_derivative_smul (r : R) (p : R[X]) (k : ℕ) : - derivative^[k] (r • p) = r • (derivative^[k] p) := +@[simp] lemma derivative_smul {S : Type*} [monoid S] + [distrib_mul_action S R] [is_scalar_tower S R R] + (s : S) (p : R[X]) : derivative (s • p) = s • derivative p := +derivative.map_smul_of_tower s p + +@[simp] lemma iterate_derivative_smul {S : Type*} [monoid S] + [distrib_mul_action S R] [is_scalar_tower S R R] + (s : S) (p : R[X]) (k : ℕ) : + derivative^[k] (s • p) = s • (derivative^[k] p) := begin induction k with k ih generalizing p, { simp, }, { simp [ih], }, end -/- We can't use `derivative_mul` here because -we want to prove this statement also for noncommutative rings.-/ -@[simp] -lemma derivative_C_mul (a : R) (p : R[X]) : derivative (C a * p) = C a * derivative p := -by convert derivative_smul a p; apply C_mul' - @[simp] lemma iterate_derivative_C_mul (a : R) (p : R[X]) (k : ℕ) : derivative^[k] (C a * p) = C a * (derivative^[k] p) := -by convert iterate_derivative_smul a p k; apply C_mul' +by simp_rw [← smul_eq_C_mul, iterate_derivative_smul] theorem of_mem_support_derivative {p : R[X]} {n : ℕ} (h : n ∈ p.derivative.support) : n + 1 ∈ p.support := @@ -197,18 +195,9 @@ begin exact hf h2 end -end semiring - -section comm_semiring -variables [comm_semiring R] - -lemma derivative_eval (p : R[X]) (x : R) : - p.derivative.eval x = p.sum (λ n a, (a * n)*x^(n-1)) := -by simp only [derivative_apply, eval_sum, eval_pow, eval_C, eval_X, eval_nat_cast, eval_mul] - @[simp] lemma derivative_mul {f g : R[X]} : derivative (f * g) = derivative f * g + f * derivative g := -calc derivative (f * g) = f.sum (λn a, g.sum (λm b, C ((a * b) * (n + m : ℕ)) * X^((n + m) - 1))) : +calc derivative (f * g) = f.sum (λn a, g.sum (λm b, (n + m) • (C (a * b) * X^((n + m) - 1)))) : begin rw mul_eq_sum_sum, transitivity, exact derivative_sum, @@ -216,23 +205,32 @@ calc derivative (f * g) = f.sum (λn a, g.sum (λm b, C ((a * b) * (n + m : ℕ) apply finset.sum_congr rfl, assume n hn, apply finset.sum_congr rfl, assume m hm, transitivity, { apply congr_arg, exact monomial_eq_C_mul_X }, - exact derivative_C_mul_X_pow _ _ + dsimp, rw [← smul_mul_assoc, smul_C, nsmul_eq_mul'], exact derivative_C_mul_X_pow _ _ end ... = f.sum (λn a, g.sum (λm b, - (C (a * n) * X^(n - 1)) * (C b * X^m) + (C a * X^n) * (C (b * m) * X^(m - 1)))) : + (n • (C a * X^(n - 1))) * (C b * X^m) + (C a * X^n) * (m • (C b * X^(m - 1))))) : sum_congr rfl $ assume n hn, sum_congr rfl $ assume m hm, - by simp only [nat.cast_add, mul_add, add_mul, C_add, C_mul]; - cases n; simp only [nat.succ_sub_succ, pow_zero]; - cases m; simp only [nat.cast_zero, C_0, nat.succ_sub_succ, zero_mul, mul_zero, nat.add_succ, - tsub_zero, pow_zero, pow_add, one_mul, pow_succ, mul_comm, mul_left_comm] + by cases n; cases m; simp_rw [add_smul, mul_smul_comm, smul_mul_assoc, + X_pow_mul_assoc, ← mul_assoc, ← C_mul, mul_assoc, ← pow_add]; + simp only [nat.add_succ, nat.succ_add, nat.succ_sub_one, zero_smul, add_comm] ... = derivative f * g + f * derivative g : begin conv { to_rhs, congr, { rw [← sum_C_mul_X_eq g] }, { rw [← sum_C_mul_X_eq f] } }, - simp only [sum, sum_add_distrib, finset.mul_sum, finset.sum_mul, derivative_apply] + simp only [sum, sum_add_distrib, finset.mul_sum, finset.sum_mul, derivative_apply], + simp_rw [← smul_mul_assoc, smul_C, nsmul_eq_mul'], end +end semiring + +section comm_semiring +variables [comm_semiring R] + +lemma derivative_eval (p : R[X]) (x : R) : + p.derivative.eval x = p.sum (λ n a, (a * n)*x^(n-1)) := +by simp only [derivative_apply, eval_sum, eval_pow, eval_C, eval_X, eval_nat_cast, eval_mul] + theorem derivative_pow_succ (p : R[X]) (n : ℕ) : (p ^ (n + 1)).derivative = (n + 1) * (p ^ n) * p.derivative := nat.rec_on n (by rw [pow_one, nat.cast_zero, zero_add, one_mul, pow_zero, one_mul]) $ λ n ih, diff --git a/src/data/polynomial/iterated_deriv.lean b/src/data/polynomial/iterated_deriv.lean index f4a6fcfdffc47..2ec5217cc9e83 100644 --- a/src/data/polynomial/iterated_deriv.lean +++ b/src/data/polynomial/iterated_deriv.lean @@ -49,7 +49,9 @@ begin { simp only [iterated_deriv_succ, ih, derivative_add] } end -@[simp] lemma iterated_deriv_smul : iterated_deriv (r • p) n = r • iterated_deriv p n := +@[simp] lemma iterated_deriv_smul {S : Type*} [monoid S] + [distrib_mul_action S R] [is_scalar_tower S R R] + (s : S) : iterated_deriv (s • p) n = s • iterated_deriv p n := begin induction n with n ih, { simp only [iterated_deriv_zero_right] }, @@ -96,113 +98,86 @@ begin rw eq1, exact iterated_deriv_C _ _ h, end -end semiring - -section ring -variables [ring R] (p q : R[X]) (n : ℕ) - -@[simp] lemma iterated_deriv_neg : iterated_deriv (-p) n = - iterated_deriv p n := -begin - induction n with n ih, - { simp only [iterated_deriv_zero_right] }, - { simp only [iterated_deriv_succ, ih, derivative_neg] } -end - -@[simp] lemma iterated_deriv_sub : - iterated_deriv (p - q) n = iterated_deriv p n - iterated_deriv q n := -by rw [sub_eq_add_neg, iterated_deriv_add, iterated_deriv_neg, ←sub_eq_add_neg] - - -end ring - -section comm_semiring -variable [comm_semiring R] -variables (f p q : R[X]) (n k : ℕ) - lemma coeff_iterated_deriv_as_prod_Ico : - ∀ m : ℕ, (iterated_deriv f k).coeff m = (∏ i in Ico m.succ (m + k.succ), i) * (f.coeff (m+k)) := + ∀ m : ℕ, (iterated_deriv f k).coeff m = (∏ i in Ico m.succ (m + k.succ), i) • (f.coeff (m+k)) := begin induction k with k ih, - { simp only [add_zero, forall_const, one_mul, Ico_self, eq_self_iff_true, + { simp only [add_zero, forall_const, one_smul, Ico_self, eq_self_iff_true, iterated_deriv_zero_right, prod_empty] }, - { intro m, rw [iterated_deriv_succ, coeff_derivative, ih (m+1), mul_right_comm], + { intro m, rw [iterated_deriv_succ, coeff_derivative, ih (m+1), ← nat.cast_add_one, + ← nsmul_eq_mul', smul_smul, mul_comm], apply congr_arg2, { have set_eq : (Ico m.succ (m + k.succ.succ)) = (Ico (m + 1).succ (m + 1 + k.succ)) ∪ {m+1}, - { rw [union_comm, ←insert_eq, Ico_insert_succ_left, add_succ, add_succ, add_succ _ k, - ←succ_eq_add_one, succ_add], - rw succ_eq_add_one, - linarith }, - rw [set_eq, prod_union], - apply congr_arg2, - { refl }, - { simp only [prod_singleton], norm_cast }, + { simp_rw [← Ico_succ_singleton, union_comm, succ_eq_add_one, add_comm (k + 1), add_assoc], + rw [Ico_union_Ico_eq_Ico]; simp_rw [add_le_add_iff_left, le_add_self], }, + rw [set_eq, prod_union, prod_singleton], { rw [disjoint_singleton_right, mem_Ico], exact λ h, (nat.lt_succ_self _).not_le h.1 } }, { exact congr_arg _ (succ_add m k) } }, end lemma coeff_iterated_deriv_as_prod_range : - ∀ m : ℕ, (iterated_deriv f k).coeff m = f.coeff (m + k) * (∏ i in range k, ↑(m + k - i)) := + ∀ m : ℕ, (iterated_deriv f k).coeff m = (∏ i in range k, (m + k - i)) • f.coeff (m + k) := begin induction k with k ih, { simp }, intro m, calc (f.iterated_deriv k.succ).coeff m - = f.coeff (m + k.succ) * (∏ i in range k, ↑(m + k.succ - i)) * (m + 1) : + = (∏ i in range k, (m + k.succ - i)) • f.coeff (m + k.succ) * (m + 1) : by rw [iterated_deriv_succ, coeff_derivative, ih m.succ, succ_add, add_succ] - ... = f.coeff (m + k.succ) * (∏ i in range k, ↑(m + k.succ - i)) * ↑(m + 1) : - by push_cast - ... = f.coeff (m + k.succ) * (∏ i in range k.succ, ↑(m + k.succ - i)) : - by rw [prod_range_succ, add_tsub_assoc_of_le k.le_succ, succ_sub le_rfl, tsub_self, mul_assoc] + ... = ((∏ i in range k, (m + k.succ - i)) * (m + 1)) • f.coeff (m + k.succ) : + by rw [← nat.cast_add_one, ← nsmul_eq_mul', smul_smul, mul_comm] + ... = (∏ i in range k.succ, (m + k.succ - i)) • f.coeff (m + k.succ) : + by rw [prod_range_succ, add_tsub_assoc_of_le k.le_succ, succ_sub le_rfl, tsub_self] end lemma iterated_deriv_eq_zero_of_nat_degree_lt (h : f.nat_degree < n) : iterated_deriv f n = 0 := begin ext m, - rw [coeff_iterated_deriv_as_prod_range, coeff_zero, coeff_eq_zero_of_nat_degree_lt, zero_mul], + rw [coeff_iterated_deriv_as_prod_range, coeff_zero, coeff_eq_zero_of_nat_degree_lt, smul_zero], linarith end lemma iterated_deriv_mul : iterated_deriv (p * q) n = ∑ k in range n.succ, - (C (n.choose k : R)) * iterated_deriv p (n - k) * iterated_deriv q k := + n.choose k • (iterated_deriv p (n - k) * iterated_deriv q k) := begin induction n with n IH, { simp }, calc (p * q).iterated_deriv n.succ = (∑ (k : ℕ) in range n.succ, - C ↑(n.choose k) * p.iterated_deriv (n - k) * q.iterated_deriv k).derivative : + (n.choose k) • (p.iterated_deriv (n - k) * q.iterated_deriv k)).derivative : by rw [iterated_deriv_succ, IH] ... = ∑ (k : ℕ) in range n.succ, - C ↑(n.choose k) * p.iterated_deriv (n - k + 1) * q.iterated_deriv k + + (n.choose k) • (p.iterated_deriv (n - k + 1) * q.iterated_deriv k) + ∑ (k : ℕ) in range n.succ, - C ↑(n.choose k) * p.iterated_deriv (n - k) * q.iterated_deriv (k + 1) : - by simp_rw [derivative_sum, derivative_mul, derivative_C, zero_mul, zero_add, - iterated_deriv_succ, sum_add_distrib] + (n.choose k) • (p.iterated_deriv (n - k) * q.iterated_deriv (k + 1)) : + by simp_rw [derivative_sum, derivative_smul, derivative_mul, iterated_deriv_succ, smul_add, + sum_add_distrib] ... = (∑ (k : ℕ) in range n.succ, - C ↑(n.choose k.succ) * p.iterated_deriv (n - k) * q.iterated_deriv (k + 1) + - C ↑1 * p.iterated_deriv n.succ * q.iterated_deriv 0) + + (n.choose k.succ) • (p.iterated_deriv (n - k) * q.iterated_deriv (k + 1)) + + 1 • (p.iterated_deriv n.succ * q.iterated_deriv 0)) + ∑ (k : ℕ) in range n.succ, - C ↑(n.choose k) * p.iterated_deriv (n - k) * q.iterated_deriv (k + 1) : _ + (n.choose k) • (p.iterated_deriv (n - k) * q.iterated_deriv (k + 1)) : _ ... = ∑ (k : ℕ) in range n.succ, - C ↑(n.choose k) * p.iterated_deriv (n - k) * q.iterated_deriv (k + 1) + + (n.choose k) • (p.iterated_deriv (n - k) * q.iterated_deriv (k + 1)) + ∑ (k : ℕ) in range n.succ, - C ↑(n.choose k.succ) * p.iterated_deriv (n - k) * q.iterated_deriv (k + 1) + - C ↑1 * p.iterated_deriv n.succ * q.iterated_deriv 0 : - by ring + (n.choose k.succ) • (p.iterated_deriv (n - k) * q.iterated_deriv (k + 1)) + + 1 • (p.iterated_deriv n.succ * q.iterated_deriv 0) : + by rw [add_comm, add_assoc] ... = ∑ (i : ℕ) in range n.succ, - C ↑((n+1).choose (i+1)) * p.iterated_deriv (n + 1 - (i+1)) * q.iterated_deriv (i+1) + - C ↑1 * p.iterated_deriv n.succ * q.iterated_deriv 0 : - by simp_rw [choose_succ_succ, succ_sub_succ, cast_add, C.map_add, add_mul, sum_add_distrib] + ((n+1).choose (i+1)) • (p.iterated_deriv (n + 1 - (i+1)) * q.iterated_deriv (i+1)) + + 1 • (p.iterated_deriv n.succ * q.iterated_deriv 0) : + by simp_rw [choose_succ_succ, succ_sub_succ, add_smul, sum_add_distrib] ... = ∑ (k : ℕ) in range n.succ.succ, - C ↑(n.succ.choose k) * p.iterated_deriv (n.succ - k) * q.iterated_deriv k : + (n.succ.choose k) • (p.iterated_deriv (n.succ - k) * q.iterated_deriv k) : by rw [sum_range_succ' _ n.succ, choose_zero_right, tsub_zero], congr, refine (sum_range_succ' _ _).trans (congr_arg2 (+) _ _), - { rw [sum_range_succ, nat.choose_succ_self, cast_zero, C.map_zero, zero_mul, zero_mul, add_zero], + { rw [sum_range_succ, nat.choose_succ_self, zero_smul, add_zero], refine sum_congr rfl (λ k hk, _), rw mem_range at hk, congr, @@ -210,6 +185,23 @@ begin { rw [choose_zero_right, tsub_zero] }, end -end comm_semiring +end semiring + +section ring +variables [ring R] (p q : R[X]) (n : ℕ) + +@[simp] lemma iterated_deriv_neg : iterated_deriv (-p) n = - iterated_deriv p n := +begin + induction n with n ih, + { simp only [iterated_deriv_zero_right] }, + { simp only [iterated_deriv_succ, ih, derivative_neg] } +end + +@[simp] lemma iterated_deriv_sub : + iterated_deriv (p - q) n = iterated_deriv p n - iterated_deriv q n := +by rw [sub_eq_add_neg, iterated_deriv_add, iterated_deriv_neg, ←sub_eq_add_neg] + + +end ring end polynomial From f1091b38dcc06191b3899f6682417b7ef9db8b20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Thu, 21 Apr 2022 12:09:57 +0000 Subject: [PATCH 124/373] feat(set_theory/cardinal): A set of cardinals is small iff it's bounded (#13373) We move `mk_subtype_le` and `mk_set_le` earlier within the file in order to better accomodate for the new result, `bdd_above_iff_small`. We need this result right above the `Sup` stuff, as we'll make heavy use of it in a following refactor for `cardinal.sup`. --- src/set_theory/cardinal/basic.lean | 43 +++++++++++++++++++++++------- src/set_theory/ordinal/basic.lean | 1 - 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/set_theory/cardinal/basic.lean b/src/set_theory/cardinal/basic.lean index 45baab238be8d..66496a4fa224c 100644 --- a/src/set_theory/cardinal/basic.lean +++ b/src/set_theory/cardinal/basic.lean @@ -5,6 +5,7 @@ Authors: Johannes Hölzl, Mario Carneiro, Floris van Doorn -/ import data.nat.enat import data.set.countable +import logic.small import order.conditionally_complete_lattice import set_theory.schroeder_bernstein @@ -184,6 +185,12 @@ theorem le_mk_iff_exists_set {c : cardinal} {α : Type u} : ⟨set.range f, (equiv.of_injective f hf).cardinal_eq.symm⟩, λ ⟨p, e⟩, e ▸ ⟨⟨subtype.val, λ a b, subtype.eq⟩⟩⟩ +theorem mk_subtype_le {α : Type u} (p : α → Prop) : #(subtype p) ≤ #α := +⟨embedding.subtype p⟩ + +theorem mk_set_le (s : set α) : #s ≤ #α := +mk_subtype_le s + theorem out_embedding {c c' : cardinal} : c ≤ c' ↔ nonempty (c.out ↪ c'.out) := by { transitivity _, rw [←quotient.out_eq c, ←quotient.out_eq c'], refl } @@ -614,14 +621,38 @@ lemma mk_le_mk_mul_of_mk_preimage_le {c : cardinal} (f : α → β) (hf : ∀ b by simpa only [←mk_congr (@equiv.sigma_preimage_equiv α β f), mk_sigma, ←sum_const'] using sum_le_sum _ _ hf +/-- The range of an indexed cardinal function, whose outputs live in a higher universe than the + inputs, is always bounded above. -/ +theorem bdd_above_range {ι : Type u} (f : ι → cardinal.{max u v}) : bdd_above (set.range f) := +⟨_, by { rintros a ⟨i, rfl⟩, exact le_sum f i }⟩ + +instance (a : cardinal.{u}) : small.{u} (set.Iic a) := +begin + rw ←mk_out a, + apply @small_of_surjective (set a.out) (Iic (#a.out)) _ (λ x, ⟨#x, mk_set_le x⟩), + rintro ⟨x, hx⟩, + simpa using le_mk_iff_exists_set.1 hx +end + +/-- A set of cardinals is bounded above iff it's small, i.e. it corresponds to an usual ZFC set. -/ +theorem bdd_above_iff_small (s : set cardinal.{u}) : bdd_above s ↔ small.{u} s := +⟨λ ⟨a, ha⟩, @small_subset _ (Iic a) s (λ x h, ha h) _, begin + rintro ⟨ι, ⟨e⟩⟩, + suffices : range (λ x : ι, (e.symm x).1) = s, + { rw ←this, + apply bdd_above_range.{u u} }, + ext x, + refine ⟨_, λ hx, ⟨e ⟨x, hx⟩, _⟩⟩, + { rintro ⟨a, rfl⟩, + exact (e.symm a).prop }, + { simp_rw [subtype.val_eq_coe, equiv.symm_apply_apply], refl } +end⟩ + /-- The indexed supremum of cardinals is the smallest cardinal above everything in the family. -/ def sup {ι : Type u} (f : ι → cardinal.{max u v}) : cardinal := Sup (set.range f) -theorem bdd_above_range {ι : Type u} (f : ι → cardinal.{max u v}) : bdd_above (set.range f) := -⟨_, by { rintros a ⟨i, rfl⟩, exact le_sum f i }⟩ - theorem le_sup {ι} (f : ι → cardinal.{max u v}) (i) : f i ≤ sup f := le_cSup (bdd_above_range f) (mem_range_self i) @@ -1227,9 +1258,6 @@ mk_le_of_surjective quot.exists_rep theorem mk_quotient_le {α : Type u} {s : setoid α} : #(quotient s) ≤ #α := mk_quot_le -theorem mk_subtype_le {α : Type u} (p : α → Prop) : #(subtype p) ≤ #α := -⟨embedding.subtype p⟩ - theorem mk_subtype_le_of_subset {α : Type u} {p q : α → Prop} (h : ∀ ⦃x⦄, p x → q x) : #(subtype p) ≤ #(subtype q) := ⟨embedding.subtype_map (embedding.refl α) h⟩ @@ -1338,9 +1366,6 @@ lemma mk_le_mk_of_subset {α} {s t : set α} (h : s ⊆ t) : #s ≤ #t := lemma mk_subtype_mono {p q : α → Prop} (h : ∀x, p x → q x) : #{x // p x} ≤ #{x // q x} := ⟨embedding_of_subset _ _ h⟩ -lemma mk_set_le (s : set α) : #s ≤ #α := -mk_subtype_le s - lemma mk_union_le_omega {α} {P Q : set α} : #((P ∪ Q : set α)) ≤ ω ↔ #P ≤ ω ∧ #Q ≤ ω := by simp diff --git a/src/set_theory/ordinal/basic.lean b/src/set_theory/ordinal/basic.lean index 6db5f5f00a79a..8796ccd5482dc 100644 --- a/src/set_theory/ordinal/basic.lean +++ b/src/set_theory/ordinal/basic.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Floris van Doorn -/ import data.sum.order -import logic.small import order.succ_pred.basic import set_theory.cardinal.basic From 0821eef157b78424876a3b5ce6fb0b485095dab1 Mon Sep 17 00:00:00 2001 From: Jujian Zhang Date: Thu, 21 Apr 2022 12:09:58 +0000 Subject: [PATCH 125/373] feat(algebraic_geometry/projective_spectrum): degree zero part of a localized ring (#13398) If we have a graded ring A and some element f of A, the the localised ring A away from f has a degree zero part. This construction is useful because proj locally is spec of degree zero part of some localised ring. Perhaps this ring belongs to some other file or different name, suggestions are very welcome --- .../projective_spectrum/scheme.lean | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 src/algebraic_geometry/projective_spectrum/scheme.lean diff --git a/src/algebraic_geometry/projective_spectrum/scheme.lean b/src/algebraic_geometry/projective_spectrum/scheme.lean new file mode 100644 index 0000000000000..82bb7e9c258a6 --- /dev/null +++ b/src/algebraic_geometry/projective_spectrum/scheme.lean @@ -0,0 +1,155 @@ +/- +Copyright (c) 2022 Jujian Zhang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jujian Zhang +-/ +import algebraic_geometry.projective_spectrum.structure_sheaf +import algebraic_geometry.Spec + +/-! +# Proj as a scheme + +This file is to prove that `Proj` is a scheme. + +## Notation + +* `Proj` : `Proj` as a locally ringed space +* `Proj.T` : the underlying topological space of `Proj` +* `Proj| U` : `Proj` restricted to some open set `U` +* `Proj.T| U` : the underlying topological space of `Proj` restricted to open set `U` +* `pbo f` : basic open set at `f` in `Proj` +* `Spec` : `Spec` as a locally ringed space +* `Spec.T` : the underlying topological space of `Spec` +* `sbo g` : basic open set at `g` in `Spec` +* `A⁰_x` : the degree zero part of localized ring `Aₓ` + +## Implementation + +In `src/algebraic_geometry/projective_spectrum/structure_sheaf.lean`, we have given `Proj` a +structure sheaf so that `Proj` is a locally ringed space. In this file we will prove that `Proj` +equipped with this structure sheaf is a scheme. We achieve this by using an affine cover by basic +open sets in `Proj`, more specifically: + +1. We prove that `Proj` can be covered by basic open sets at homogeneous element of positive degree. +2. We prove that for any `f : A`, `Proj.T | (pbo f)` is homeomorphic to `Spec.T A⁰_f`: + - forward direction : + for any `x : pbo f`, i.e. a relevant homogeneous prime ideal `x`, send it to + `x ∩ span {g / 1 | g ∈ A}` (see `Top_component.forward.carrier`). This ideal is prime, the proof + is in `Top_component.forward.to_fun`. The fact that this function is continuous is found in + `Top_component.forward` + - backward direction : TBC + +## Main Definitions and Statements + +* `degree_zero_part`: the degree zero part of the localized ring `Aₓ` where `x` is a homogeneous + element of degree `n` is the subring of elements of the form `a/f^m` where `a` has degree `mn`. + +For a homogeneous element `f` of degree `n` +* `Top_component.forward`: `forward f` is the + continuous map between `Proj.T| pbo f` and `Spec.T A⁰_f` +* `Top_component.forward.preimage_eq`: for any `a: A`, if `a/f^m` has degree zero, then the preimage + of `sbo a/f^m` under `forward f` is `pbo f ∩ pbo a`. + + +* [Robin Hartshorne, *Algebraic Geometry*][Har77]: Chapter II.2 Proposition 2.5 +-/ + +noncomputable theory + +namespace algebraic_geometry + +open_locale direct_sum big_operators pointwise big_operators +open direct_sum set_like.graded_monoid localization finset (hiding mk_zero) + +variables {R A : Type*} +variables [comm_ring R] [comm_ring A] [algebra R A] + +variables (𝒜 : ℕ → submodule R A) +variables [graded_algebra 𝒜] + +open Top topological_space +open category_theory opposite +open projective_spectrum.structure_sheaf + +local notation `Proj` := Proj.to_LocallyRingedSpace 𝒜 +-- `Proj` as a locally ringed space +local notation `Proj.T` := Proj .1.1.1 +-- the underlying topological space of `Proj` +local notation `Proj| ` U := Proj .restrict (opens.open_embedding (U : opens Proj.T)) +-- `Proj` restrict to some open set +local notation `Proj.T| ` U := + (Proj .restrict (opens.open_embedding (U : opens Proj.T))).to_SheafedSpace.to_PresheafedSpace.1 +-- the underlying topological space of `Proj` restricted to some open set +local notation `pbo` x := projective_spectrum.basic_open 𝒜 x +-- basic open sets in `Proj` +local notation `sbo` f := prime_spectrum.basic_open f +-- basic open sets in `Spec` +local notation `Spec` ring := Spec.LocallyRingedSpace_obj (CommRing.of ring) +-- `Spec` as a locally ringed space +local notation `Spec.T` ring := + (Spec.LocallyRingedSpace_obj (CommRing.of ring)).to_SheafedSpace.to_PresheafedSpace.1 +-- the underlying topological space of `Spec` + +section +variable {𝒜} +/-- +The degree zero part of the localized ring `Aₓ` is the subring of elements of the form `a/x^n` such +that `a` and `x^n` have the same degree. +-/ +def degree_zero_part {f : A} {m : ℕ} (f_deg : f ∈ 𝒜 m) : subring (away f) := +{ carrier := { y | ∃ (n : ℕ) (a : 𝒜 (m * n)), y = mk a.1 ⟨f^n, ⟨n, rfl⟩⟩ }, + mul_mem' := λ _ _ ⟨n, ⟨a, h⟩⟩ ⟨n', ⟨b, h'⟩⟩, h.symm ▸ h'.symm ▸ + ⟨n+n', ⟨⟨a.1 * b.1, (mul_add m n n').symm ▸ mul_mem a.2 b.2⟩, + by {rw mk_mul, congr' 1, simp only [pow_add], refl }⟩⟩, + one_mem' := ⟨0, ⟨1, (mul_zero m).symm ▸ one_mem⟩, + by { symmetry, convert ← mk_self 1, simp only [pow_zero], refl, }⟩, + add_mem' := λ _ _ ⟨n, ⟨a, h⟩⟩ ⟨n', ⟨b, h'⟩⟩, h.symm ▸ h'.symm ▸ + ⟨n+n', ⟨⟨f ^ n * b.1 + f ^ n' * a.1, (mul_add m n n').symm ▸ + add_mem (mul_mem (by { rw mul_comm, exact set_like.graded_monoid.pow_mem n f_deg }) b.2) + begin + rw add_comm, + refine mul_mem _ a.2, + rw mul_comm, + exact set_like.graded_monoid.pow_mem _ f_deg + end⟩, begin + rw add_mk, + congr' 1, + simp only [pow_add], + refl, + end⟩⟩, + zero_mem' := ⟨0, ⟨0, (mk_zero _).symm⟩⟩, + neg_mem' := λ x ⟨n, ⟨a, h⟩⟩, h.symm ▸ ⟨n, ⟨-a, neg_mk _ _⟩⟩ } + +local notation `A⁰_` f_deg := degree_zero_part f_deg + +instance (f : A) {m : ℕ} (f_deg : f ∈ 𝒜 m) : comm_ring (degree_zero_part f_deg) := +(degree_zero_part f_deg).to_comm_ring + +/-- +Every element in the degree zero part of `Aₓ` can be written as `a/x^n` for some `a` and `n : ℕ`, +`degree_zero_part.deg` picks this natural number `n` +-/ +def degree_zero_part.deg {f : A} {m : ℕ} (f_deg : f ∈ 𝒜 m) (x : A⁰_ f_deg) : ℕ := +x.2.some + +/-- +Every element in the degree zero part of `Aₓ` can be written as `a/x^n` for some `a` and `n : ℕ`, +`degree_zero_part.deg` picks the numerator `a` +-/ +def degree_zero_part.num {f : A} {m : ℕ} (f_deg : f ∈ 𝒜 m) (x : A⁰_ f_deg) : A := +x.2.some_spec.some.1 + +lemma degree_zero_part.num_mem {f : A} {m : ℕ} (f_deg : f ∈ 𝒜 m) (x : A⁰_ f_deg) : + degree_zero_part.num f_deg x ∈ 𝒜 (m * degree_zero_part.deg f_deg x) := +x.2.some_spec.some.2 + +lemma degree_zero_part.eq {f : A} {m : ℕ} (f_deg : f ∈ 𝒜 m) (x : A⁰_ f_deg) : + x.1 = mk (degree_zero_part.num f_deg x) ⟨f^(degree_zero_part.deg f_deg x), ⟨_, rfl⟩⟩ := +x.2.some_spec.some_spec + +lemma degree_zero_part.mul_val {f : A} {m : ℕ} (f_deg : f ∈ 𝒜 m) (x y : A⁰_ f_deg) : + (x * y).1 = x.1 * y.1 := rfl + +end + +end algebraic_geometry From e5f823639a579aa0872de64005fdbf06a84ef777 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Thu, 21 Apr 2022 12:09:59 +0000 Subject: [PATCH 126/373] feat(analysis/normed_space/exponential): ring homomorphisms are preserved by the exponential (#13402) The new results here are: * `prod.fst_exp` * `prod.snd_exp` * `exp_units_conj` * `exp_conj` * `map_exp` * `map_exp_of_mem_ball` This last lemma does all the heavy lifting, and also lets us golf `algebra_map_exp_comm`. This doesn't bother to duplicate the rest of these lemmas for the `*_of_mem_ball` version, since the proofs are trivial and those lemmas probably wouldn't be used. This also generalizes some of the lemmas about infinite sums to work with `add_monoid_hom_class`. --- src/analysis/normed_space/exponential.lean | 66 ++++++++++++++++++---- src/topology/algebra/group.lean | 9 ++- src/topology/algebra/infinite_sum.lean | 6 +- 3 files changed, 64 insertions(+), 17 deletions(-) diff --git a/src/analysis/normed_space/exponential.lean b/src/analysis/normed_space/exponential.lean index 49327a5140938..4a49a2709a88d 100644 --- a/src/analysis/normed_space/exponential.lean +++ b/src/analysis/normed_space/exponential.lean @@ -62,7 +62,8 @@ open_locale nat topological_space big_operators ennreal section any_field_any_algebra -variables (𝕂 𝔸 : Type*) [nondiscrete_normed_field 𝕂] [normed_ring 𝔸] [normed_algebra 𝕂 𝔸] +variables (𝕂 𝔸 𝔹 : Type*) [nondiscrete_normed_field 𝕂] +variables [normed_ring 𝔸] [normed_ring 𝔹] [normed_algebra 𝕂 𝔸] [normed_algebra 𝕂 𝔹] /-- In a Banach algebra `𝔸` over a normed field `𝕂`, `exp_series 𝕂 𝔸` is the `formal_multilinear_series` whose `n`-th term is the map `(xᵢ) : 𝔸ⁿ ↦ (1/n! : 𝕂) • ∏ xᵢ`. @@ -75,7 +76,7 @@ determined by the action of `𝕂` on `𝔸`. It is defined as the sum of the `formal_multilinear_series` `exp_series 𝕂 𝔸`. -/ noncomputable def exp (x : 𝔸) : 𝔸 := (exp_series 𝕂 𝔸).sum x -variables {𝕂 𝔸} +variables {𝕂 𝔸 𝔹} lemma exp_series_apply_eq (x : 𝔸) (n : ℕ) : exp_series 𝕂 𝔸 n (λ _, x) = (1 / n! : 𝕂) • x^n := by simp [exp_series] @@ -246,18 +247,23 @@ lemma inv_of_exp_of_mem_ball [char_zero 𝕂] {x : 𝔸} ⅟(exp 𝕂 𝔸 x) = exp 𝕂 𝔸 (-x) := by { letI := invertible_exp_of_mem_ball hx, convert (rfl : ⅟(exp 𝕂 𝔸 x) = _) } +/-- Any continuous ring homomorphism commutes with `exp`. -/ +lemma map_exp_of_mem_ball {F} [ring_hom_class F 𝔸 𝔹] (f : F) (hf : continuous f) (x : 𝔸) + (hx : x ∈ emetric.ball (0 : 𝔸) (exp_series 𝕂 𝔸).radius) : + f (exp 𝕂 𝔸 x) = exp 𝕂 𝔹 (f x) := +begin + rw [exp_eq_tsum, exp_eq_tsum], + refine ((exp_series_summable_of_mem_ball' _ hx).has_sum.map f hf).tsum_eq.symm.trans _, + dsimp only [function.comp], + simp_rw [one_div, map_inv_nat_cast_smul f 𝕂 𝕂, map_pow], +end + end complete_algebra lemma algebra_map_exp_comm_of_mem_ball [complete_space 𝕂] (x : 𝕂) (hx : x ∈ emetric.ball (0 : 𝕂) (exp_series 𝕂 𝕂).radius) : algebra_map 𝕂 𝔸 (exp 𝕂 𝕂 x) = exp 𝕂 𝔸 (algebra_map 𝕂 𝔸 x) := -begin - convert (algebra_map_clm 𝕂 𝔸).map_tsum (exp_series_field_summable_of_mem_ball x hx), - { exact congr_fun exp_eq_tsum_field x }, - { convert congr_fun (exp_eq_tsum : exp 𝕂 𝔸 = _) (algebra_map 𝕂 𝔸 x), - simp_rw [←map_pow, ←algebra_map_clm_coe, ←(algebra_map_clm 𝕂 𝔸).map_smul, smul_eq_mul, - mul_comm, ←div_eq_mul_one_div], } -end +map_exp_of_mem_ball _ (algebra_map_clm _ _).continuous _ hx end any_field_any_algebra @@ -295,7 +301,8 @@ section is_R_or_C section any_algebra -variables (𝕂 𝔸 : Type*) [is_R_or_C 𝕂] [normed_ring 𝔸] [normed_algebra 𝕂 𝔸] +variables (𝕂 𝔸 𝔹 : Type*) [is_R_or_C 𝕂] [normed_ring 𝔸] [normed_algebra 𝕂 𝔸] +variables [normed_ring 𝔹] [normed_algebra 𝕂 𝔹] /-- In a normed algebra `𝔸` over `𝕂 = ℝ` or `𝕂 = ℂ`, the series defining the exponential map has an infinite radius of convergence. -/ @@ -317,7 +324,7 @@ begin exact with_top.zero_lt_top end -variables {𝕂 𝔸} +variables {𝕂 𝔸 𝔹} section complete_algebra @@ -431,11 +438,38 @@ begin { rw [succ_nsmul, pow_succ, exp_add_of_commute ((commute.refl x).smul_right n), ih] } end +variables (𝕂) + +/-- Any continuous ring homomorphism commutes with `exp`. -/ +lemma map_exp {F} [ring_hom_class F 𝔸 𝔹] (f : F) (hf : continuous f) (x : 𝔸) : + f (exp 𝕂 𝔸 x) = exp 𝕂 𝔹 (f x) := +map_exp_of_mem_ball f hf x $ (exp_series_radius_eq_top 𝕂 𝔸).symm ▸ edist_lt_top _ _ + +lemma exp_smul {G} [monoid G] [mul_semiring_action G 𝔸] [has_continuous_const_smul G 𝔸] + (g : G) (x : 𝔸) : + exp 𝕂 𝔸 (g • x) = g • exp 𝕂 𝔸 x := +(map_exp 𝕂 (mul_semiring_action.to_ring_hom G 𝔸 g) (continuous_const_smul _) x).symm + +lemma exp_units_conj (y : 𝔸ˣ) (x : 𝔸) : + exp 𝕂 𝔸 (y * x * ↑(y⁻¹)) = y * exp 𝕂 𝔸 x * ↑(y⁻¹) := +exp_smul _ (conj_act.to_conj_act y) x + +lemma exp_units_conj' (y : 𝔸ˣ) (x : 𝔸) : + exp 𝕂 𝔸 (↑(y⁻¹) * x * y) = ↑(y⁻¹) * exp 𝕂 𝔸 x * y := +exp_units_conj _ _ _ + +@[simp] lemma prod.fst_exp [complete_space 𝔹] (x : 𝔸 × 𝔹) : (exp 𝕂 (𝔸 × 𝔹) x).fst = exp 𝕂 𝔸 x.fst := +map_exp _ (ring_hom.fst 𝔸 𝔹) continuous_fst x + +@[simp] lemma prod.snd_exp [complete_space 𝔹] (x : 𝔸 × 𝔹) : (exp 𝕂 (𝔸 × 𝔹) x).snd = exp 𝕂 𝔹 x.snd := +map_exp _ (ring_hom.snd 𝔸 𝔹) continuous_snd x + end complete_algebra lemma algebra_map_exp_comm (x : 𝕂) : algebra_map 𝕂 𝔸 (exp 𝕂 𝕂 x) = exp 𝕂 𝔸 (algebra_map 𝕂 𝔸 x) := -algebra_map_exp_comm_of_mem_ball x (by simp [exp_series_radius_eq_top]) +algebra_map_exp_comm_of_mem_ball x $ + (exp_series_radius_eq_top 𝕂 𝕂).symm ▸ edist_lt_top _ _ end any_algebra @@ -454,6 +488,14 @@ begin { rw [zpow_neg₀, zpow_coe_nat, neg_smul, exp_neg, coe_nat_zsmul, exp_nsmul] }, end +lemma exp_conj (y : 𝔸) (x : 𝔸) (hy : y ≠ 0) : + exp 𝕂 𝔸 (y * x * y⁻¹) = y * exp 𝕂 𝔸 x * y⁻¹ := +exp_units_conj _ (units.mk0 y hy) x + +lemma exp_conj' (y : 𝔸) (x : 𝔸) (hy : y ≠ 0) : + exp 𝕂 𝔸 (y⁻¹ * x * y) = y⁻¹ * exp 𝕂 𝔸 x * y := +exp_units_conj' _ (units.mk0 y hy) x + end division_algebra section comm_algebra diff --git a/src/topology/algebra/group.lean b/src/topology/algebra/group.lean index 792e4dffa821f..19136f4387c95 100644 --- a/src/topology/algebra/group.lean +++ b/src/topology/algebra/group.lean @@ -3,6 +3,7 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro, Patrick Massot -/ +import group_theory.group_action.conj_act import group_theory.quotient_group import order.filter.pointwise import topology.algebra.monoid @@ -341,11 +342,15 @@ class topological_group (G : Type*) [topological_space G] [group G] section conj +instance conj_act.units_has_continuous_const_smul {M} [monoid M] [topological_space M] + [has_continuous_mul M] : + has_continuous_const_smul (conj_act Mˣ) M := +⟨λ m, (continuous_const.mul continuous_id).mul continuous_const⟩ + /-- we slightly weaken the type class assumptions here so that it will also apply to `ennreal`, but we nevertheless leave it in the `topological_group` namespace. -/ -variables [topological_space G] [has_inv G] [has_mul G] -[has_continuous_mul G] +variables [topological_space G] [has_inv G] [has_mul G] [has_continuous_mul G] /-- Conjugation is jointly continuous on `G × G` when both `mul` and `inv` are continuous. -/ @[to_additive "Conjugation is jointly continuous on `G × G` when both `mul` and `inv` are diff --git a/src/topology/algebra/infinite_sum.lean b/src/topology/algebra/infinite_sum.lean index 73c1fed9e5898..4cd81375e5a8f 100644 --- a/src/topology/algebra/infinite_sum.lean +++ b/src/topology/algebra/infinite_sum.lean @@ -196,15 +196,15 @@ lemma equiv.summable_iff_of_support {g : γ → α} (e : support f ≃ support g exists_congr $ λ _, e.has_sum_iff_of_support he protected lemma has_sum.map [add_comm_monoid γ] [topological_space γ] (hf : has_sum f a) - (g : α →+ γ) (hg : continuous g) : + {G} [add_monoid_hom_class G α γ] (g : G) (hg : continuous g) : has_sum (g ∘ f) (g a) := have g ∘ (λs:finset β, ∑ b in s, f b) = (λs:finset β, ∑ b in s, g (f b)), - from funext $ g.map_sum _, + from funext $ map_sum g _, show tendsto (λs:finset β, ∑ b in s, g (f b)) at_top (𝓝 (g a)), from this ▸ (hg.tendsto a).comp hf protected lemma summable.map [add_comm_monoid γ] [topological_space γ] (hf : summable f) - (g : α →+ γ) (hg : continuous g) : + {G} [add_monoid_hom_class G α γ] (g : G) (hg : continuous g) : summable (g ∘ f) := (hf.has_sum.map g hg).summable From 22c4291217925c6957c0f5a44551c9917b56c7cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Thu, 21 Apr 2022 12:10:00 +0000 Subject: [PATCH 127/373] chore(number_theory/dioph): Cleanup (#13403) Clean up, including: * Move prerequisites to the correct files * Make equalities in `poly` operations defeq * Remove defeq abuse around `set` * Slightly golf proofs by tweaking explicitness of lemma arguments Renames --- src/control/traversable/instances.lean | 3 +- src/data/int/basic.lean | 5 + src/data/list/basic.lean | 25 ++ src/data/list/defs.lean | 7 + src/data/option/basic.lean | 7 + src/number_theory/dioph.lean | 540 +++++++++++-------------- 6 files changed, 278 insertions(+), 309 deletions(-) diff --git a/src/control/traversable/instances.lean b/src/control/traversable/instances.lean index 5d8837eafd6b5..97fe4a08bf51e 100644 --- a/src/control/traversable/instances.lean +++ b/src/control/traversable/instances.lean @@ -60,8 +60,7 @@ variables [applicative F] [applicative G] section variables [is_lawful_applicative F] [is_lawful_applicative G] -open applicative functor -open list (cons) +open applicative functor list protected lemma id_traverse {α} (xs : list α) : list.traverse id.mk xs = xs := diff --git a/src/data/int/basic.lean b/src/data/int/basic.lean index a3aea134be6eb..df12711935907 100644 --- a/src/data/int/basic.lean +++ b/src/data/int/basic.lean @@ -285,6 +285,8 @@ end /-! ### nat abs -/ +variables {a b : ℤ} {n : ℕ} + attribute [simp] nat_abs nat_abs_of_nat nat_abs_zero nat_abs_one theorem nat_abs_add_le (a b : ℤ) : nat_abs (a + b) ≤ nat_abs a + nat_abs b := @@ -355,6 +357,9 @@ begin exact int.coe_nat_inj'.symm end +lemma eq_nat_abs_iff_mul_eq_zero : a.nat_abs = n ↔ (a - n) * (a + n) = 0 := +by rw [nat_abs_eq_iff, mul_eq_zero, sub_eq_zero, add_eq_zero_iff_eq_neg] + lemma nat_abs_lt_iff_mul_self_lt {a b : ℤ} : a.nat_abs < b.nat_abs ↔ a * a < b * b := begin rw [← abs_lt_iff_mul_self_lt, abs_eq_nat_abs, abs_eq_nat_abs], diff --git a/src/data/list/basic.lean b/src/data/list/basic.lean index b71d6fe96ebd8..422a28de0008c 100644 --- a/src/data/list/basic.lean +++ b/src/data/list/basic.lean @@ -3707,6 +3707,31 @@ end end to_chunks +/-! ### all₂ -/ + +section all₂ +variables {p q : α → Prop} {l : list α} + +@[simp] lemma all₂_cons (p : α → Prop) (x : α) : ∀ (l : list α), all₂ p (x :: l) ↔ p x ∧ all₂ p l +| [] := (and_true _).symm +| (x :: l) := iff.rfl + +lemma all₂_iff_forall : ∀ {l : list α}, all₂ p l ↔ ∀ x ∈ l, p x +| [] := (iff_true_intro $ ball_nil _).symm +| (x :: l) := by rw [ball_cons, all₂_cons, all₂_iff_forall] + +lemma all₂.imp (h : ∀ x, p x → q x) : ∀ {l : list α}, all₂ p l → all₂ q l +| [] := id +| (x :: l) := by simpa using and.imp (h x) all₂.imp + +@[simp] lemma all₂_map_iff {p : β → Prop} (f : α → β) : all₂ p (l.map f) ↔ all₂ (p ∘ f) l := +by induction l; simp * + +instance (p : α → Prop) [decidable_pred p] : decidable_pred (all₂ p) := +λ l, decidable_of_iff' _ all₂_iff_forall + +end all₂ + /-! ### Retroattributes The list definitions happen earlier than `to_additive`, so here we tag the few multiplicative diff --git a/src/data/list/defs.lean b/src/data/list/defs.lean index 43211d7a81a88..183faff24693a 100644 --- a/src/data/list/defs.lean +++ b/src/data/list/defs.lean @@ -398,6 +398,13 @@ attribute [simp] forall₂.nil end forall₂ +/-- `l.all₂ p` is equivalent to `∀ a ∈ l, p a`, but unfolds directly to a conjunction, i.e. +`list.all₂ p [0, 1, 2] = p 0 ∧ p 1 ∧ p 2`. -/ +@[simp] def all₂ (p : α → Prop) : list α → Prop +| [] := true +| (x :: []) := p x +| (x :: l) := p x ∧ all₂ l + /-- Auxiliary definition used to define `transpose`. `transpose_aux l L` takes each element of `l` and appends it to the start of each element of `L`. diff --git a/src/data/option/basic.lean b/src/data/option/basic.lean index 294a87ee98216..a126f5365a51b 100644 --- a/src/data/option/basic.lean +++ b/src/data/option/basic.lean @@ -490,4 +490,11 @@ rfl @[simp] lemma to_list_none (α : Type*) : (none : option α).to_list = [] := rfl +--TODO: Swap arguments to `option.elim` so that it is exactly `option.cons` +/-- Functions from `option` can be combined similarly to `vector.cons`. -/ +def cons (a : β) (f : α → β) : option α → β := λ o, o.elim a f + +@[simp] lemma cons_none_some (f : option α → β) : cons (f none) (f ∘ some) = f := +funext $ λ o, by cases o; refl + end option diff --git a/src/number_theory/dioph.lean b/src/number_theory/dioph.lean index 23fb212df4e76..dd5945c511e24 100644 --- a/src/number_theory/dioph.lean +++ b/src/number_theory/dioph.lean @@ -49,146 +49,97 @@ Matiyasevic's theorem, Hilbert's tenth problem * Connect `poly` to `mv_polynomial` -/ -universe u - -open nat function - -namespace int - -lemma eq_nat_abs_iff_mul (x n) : nat_abs x = n ↔ (x - n) * (x + n) = 0 := -begin - refine iff.trans _ mul_eq_zero.symm, - refine iff.trans _ (or_congr sub_eq_zero add_eq_zero_iff_eq_neg).symm, - exact ⟨λe, by rw ← e; apply nat_abs_eq, - λo, by cases o; subst x; simp [nat_abs_of_nat]⟩ -end - -end int - -open fin2 - -/-- `list_all p l` is equivalent to `∀ a ∈ l, p a`, but unfolds directly to a conjunction, - i.e. `list_all p [0, 1, 2] = p 0 ∧ p 1 ∧ p 2`. -/ -@[simp] def list_all {α} (p : α → Prop) : list α → Prop -| [] := true -| (x :: []) := p x -| (x :: l) := p x ∧ list_all l +open fin2 function nat sum -@[simp] theorem list_all_cons {α} (p : α → Prop) (x : α) : - ∀ (l : list α), list_all p (x :: l) ↔ p x ∧ list_all p l -| [] := (and_true _).symm -| (x :: l) := iff.rfl +local infixr ` ::ₒ `:67 := option.cons +local infixr ` ⊗ `:65 := sum.elim -theorem list_all_iff_forall {α} (p : α → Prop) : ∀ (l : list α), list_all p l ↔ ∀ x ∈ l, p x -| [] := (iff_true_intro $ list.ball_nil _).symm -| (x :: l) := by rw [list.ball_cons, ← list_all_iff_forall l]; simp - -theorem list_all.imp {α} {p q : α → Prop} (h : ∀ x, p x → q x) : - ∀ {l : list α}, list_all p l → list_all q l -| [] := id -| (x :: l) := by simpa using and.imp (h x) list_all.imp - -@[simp] theorem list_all_map {α β} {p : β → Prop} (f : α → β) {l : list α} : - list_all p (l.map f) ↔ list_all (p ∘ f) l := -by induction l; simp * +universe u -theorem list_all_congr {α} {p q : α → Prop} (h : ∀ x, p x ↔ q x) {l : list α} : - list_all p l ↔ list_all q l := -⟨list_all.imp (λx, (h x).1), list_all.imp (λx, (h x).2)⟩ +/-! +### Multivariate integer polynomials -instance decidable_list_all {α} (p : α → Prop) [decidable_pred p] (l : list α) : - decidable (list_all p l) := -decidable_of_decidable_of_iff (by apply_instance) (list_all_iff_forall _ _).symm +Note that this duplicates `mv_polynomial`. +-/ -/- poly -/ +section polynomials +variables {α β γ : Type*} /-- A predicate asserting that a function is a multivariate integer polynomial. (We are being a bit lazy here by allowing many representations for multiplication, rather than only allowing monomials and addition, but the definition is equivalent and this is easier to use.) -/ -inductive is_poly {α} : ((α → ℕ) → ℤ) → Prop -| proj : ∀ i, is_poly (λx : α → ℕ, x i) -| const : Π (n : ℤ), is_poly (λx : α → ℕ, n) -| sub : Π {f g : (α → ℕ) → ℤ}, is_poly f → is_poly g → is_poly (λx, f x - g x) -| mul : Π {f g : (α → ℕ) → ℤ}, is_poly f → is_poly g → is_poly (λx, f x * g x) +inductive is_poly : ((α → ℕ) → ℤ) → Prop +| proj : ∀ i, is_poly (λ x : α → ℕ, x i) +| const : Π (n : ℤ), is_poly (λ x : α → ℕ, n) +| sub : Π {f g : (α → ℕ) → ℤ}, is_poly f → is_poly g → is_poly (λ x, f x - g x) +| mul : Π {f g : (α → ℕ) → ℤ}, is_poly f → is_poly g → is_poly (λ x, f x * g x) + +lemma is_poly.neg {f : (α → ℕ) → ℤ} : is_poly f → is_poly (-f) := +by { rw ←zero_sub, exact (is_poly.const 0).sub } + +lemma is_poly.add {f g : (α → ℕ) → ℤ} (hf : is_poly f) (hg : is_poly g) : is_poly (f + g) := +by { rw ←sub_neg_eq_add, exact hf.sub hg.neg } /-- The type of multivariate integer polynomials -/ def poly (α : Type u) := {f : (α → ℕ) → ℤ // is_poly f} namespace poly section -parameter {α : Type u} -instance : has_coe_to_fun (poly α) (λ _, (α → ℕ) → ℤ) := ⟨λ f, f.1⟩ +instance fun_like : fun_like (poly α) (α → ℕ) (λ _, ℤ) := ⟨subtype.val, subtype.val_injective⟩ + +/-- Helper instance for when there are too many metavariables to apply `fun_like.has_coe_to_fun` +directly. -/ +instance : has_coe_to_fun (poly α) (λ _, (α → ℕ) → ℤ) := fun_like.has_coe_to_fun /-- The underlying function of a `poly` is a polynomial -/ -lemma isp (f : poly α) : is_poly f := f.2 +protected lemma is_poly (f : poly α) : is_poly f := f.2 /-- Extensionality for `poly α` -/ -lemma ext {f g : poly α} (e : ∀x, f x = g x) : f = g := -subtype.eq (funext e) - -/-- Construct a `poly` given an extensionally equivalent `poly`. -/ -def subst (f : poly α) (g : (α → ℕ) → ℤ) (e : ∀x, f x = g x) : poly α := -⟨g, by rw ← (funext e : coe_fn f = g); exact f.isp⟩ -@[simp] theorem subst_eval (f g e x) : subst f g e x = g x := rfl +@[ext] lemma ext {f g : poly α} : (∀ x, f x = g x) → f = g := fun_like.ext _ _ /-- The `i`th projection function, `x_i`. -/ def proj (i) : poly α := ⟨_, is_poly.proj i⟩ -@[simp] theorem proj_eval (i x) : proj i x = x i := rfl +@[simp] lemma proj_apply (i : α) (x) : proj i x = x i := rfl /-- The constant function with value `n : ℤ`. -/ def const (n) : poly α := ⟨_, is_poly.const n⟩ -@[simp] theorem const_eval (n x) : const n x = n := rfl - -/-- The zero polynomial -/ -def zero : poly α := const 0 -instance : has_zero (poly α) := ⟨poly.zero⟩ -@[simp] theorem zero_eval (x) : (0 : poly α) x = 0 := rfl - -/-- The zero polynomial -/ -def one : poly α := const 1 -instance : has_one (poly α) := ⟨poly.one⟩ -@[simp] theorem one_eval (x) : (1 : poly α) x = 1 := rfl - -/-- Subtraction of polynomials -/ -def sub : poly α → poly α → poly α | ⟨f, pf⟩ ⟨g, pg⟩ := -⟨_, is_poly.sub pf pg⟩ -instance : has_sub (poly α) := ⟨poly.sub⟩ -@[simp] theorem sub_eval : Π (f g x), (f - g : poly α) x = f x - g x -| ⟨f, pf⟩ ⟨g, pg⟩ x := rfl - -/-- Negation of a polynomial -/ -def neg (f : poly α) : poly α := 0 - f -instance : has_neg (poly α) := ⟨poly.neg⟩ -@[simp] theorem neg_eval (f x) : (-f : poly α) x = -f x := -show (0-f) x = _, by simp - -/-- Addition of polynomials -/ -def add : poly α → poly α → poly α | ⟨f, pf⟩ ⟨g, pg⟩ := -subst (⟨f, pf⟩ - -⟨g, pg⟩) _ - (λx, show f x - (0 - g x) = f x + g x, by simp) -instance : has_add (poly α) := ⟨poly.add⟩ -@[simp] theorem add_eval : Π (f g x), (f + g : poly α) x = f x + g x -| ⟨f, pf⟩ ⟨g, pg⟩ x := rfl - -/-- Multiplication of polynomials -/ -def mul : poly α → poly α → poly α | ⟨f, pf⟩ ⟨g, pg⟩ := -⟨_, is_poly.mul pf pg⟩ -instance : has_mul (poly α) := ⟨poly.mul⟩ -@[simp] theorem mul_eval : Π (f g x), (f * g : poly α) x = f x * g x -| ⟨f, pf⟩ ⟨g, pg⟩ x := rfl +@[simp] lemma const_apply (n) (x : α → ℕ) : const n x = n := rfl + +instance : has_zero (poly α) := ⟨const 0⟩ +instance : has_one (poly α) := ⟨const 1⟩ +instance : has_neg (poly α) := ⟨λ f, ⟨-f, f.2.neg⟩⟩ +instance : has_add (poly α) := ⟨λ f g, ⟨f + g, f.2.add g.2⟩⟩ +instance : has_sub (poly α) := ⟨λ f g, ⟨f - g, f.2.sub g.2⟩⟩ +instance : has_mul (poly α) := ⟨λ f g, ⟨f * g, f.2.mul g.2⟩⟩ + +@[simp] lemma coe_zero : ⇑(0 : poly α) = const 0 := rfl +@[simp] lemma coe_one : ⇑(1 : poly α) = const 1 := rfl +@[simp] lemma coe_neg (f : poly α) : ⇑(-f) = -f := rfl +@[simp] lemma coe_add (f g : poly α) : ⇑(f + g) = f + g := rfl +@[simp] lemma coe_sub (f g : poly α) : ⇑(f - g) = f - g := rfl +@[simp] lemma coe_mul (f g : poly α) : ⇑(f * g) = f * g := rfl + +@[simp] lemma zero_apply (x) : (0 : poly α) x = 0 := rfl +@[simp] lemma one_apply (x) : (1 : poly α) x = 1 := rfl +@[simp] lemma neg_apply (f : poly α) (x) : (-f) x = -f x := rfl +@[simp] lemma add_apply (f g : poly α) (x : α → ℕ) : (f + g) x = f x + g x := rfl +@[simp] lemma sub_apply (f g : poly α) (x : α → ℕ) : (f - g) x = f x - g x := rfl +@[simp] lemma mul_apply (f g : poly α) (x : α → ℕ) : (f * g) x = f x * g x := rfl + +instance (α : Type*) : inhabited (poly α) := ⟨0⟩ instance : comm_ring (poly α) := by refine_struct { add := ((+) : poly α → poly α → poly α), zero := 0, - neg := (has_neg.neg : poly α → poly α), - mul := ((*)), + neg := (has_neg.neg), + mul := (*), one := 1, sub := (has_sub.sub), npow := @npow_rec _ ⟨(1 : poly α)⟩ ⟨(*)⟩, nsmul := @nsmul_rec _ ⟨(0 : poly α)⟩ ⟨(+)⟩, - zsmul := @zsmul_rec _ ⟨(0 : poly α)⟩ ⟨(+)⟩ ⟨neg⟩ }; + zsmul := @zsmul_rec _ ⟨(0 : poly α)⟩ ⟨(+)⟩ ⟨has_neg.neg⟩ }; intros; try { refl }; refine ext (λ _, _); simp [sub_eq_add_neg, mul_add, mul_left_comm, mul_comm, add_comm, add_assoc] @@ -210,260 +161,234 @@ def sumsq : list (poly α) → poly α | [] := 0 | (p::ps) := p*p + sumsq ps -theorem sumsq_nonneg (x) : ∀ l, 0 ≤ sumsq l x +lemma sumsq_nonneg (x : α → ℕ) : ∀ l, 0 ≤ sumsq l x | [] := le_refl 0 | (p::ps) := by rw sumsq; simp [-add_comm]; exact add_nonneg (mul_self_nonneg _) (sumsq_nonneg ps) -theorem sumsq_eq_zero (x) : ∀ l, sumsq l x = 0 ↔ list_all (λa : poly α, a x = 0) l +lemma sumsq_eq_zero (x) : ∀ l, sumsq l x = 0 ↔ l.all₂ (λ a : poly α, a x = 0) | [] := eq_self_iff_true _ -| (p::ps) := by rw [list_all_cons, ← sumsq_eq_zero ps]; rw sumsq; simp [-add_comm]; exact - ⟨λ(h : p x * p x + sumsq ps x = 0), +| (p::ps) := by rw [list.all₂_cons, ← sumsq_eq_zero ps]; rw sumsq; simp [-add_comm]; exact + ⟨λ (h : p x * p x + sumsq ps x = 0), have p x = 0, from eq_zero_of_mul_self_eq_zero $ le_antisymm (by rw ← h; have t := add_le_add_left (sumsq_nonneg x ps) (p x * p x); rwa [add_zero] at t) (mul_self_nonneg _), ⟨this, by simp [this] at h; exact h⟩, - λ⟨h1, h2⟩, by rw [h1, h2]; refl⟩ + λ ⟨h1, h2⟩, by rw [h1, h2]; refl⟩ end /-- Map the index set of variables, replacing `x_i` with `x_(f i)`. -/ -def remap {α β} (f : α → β) (g : poly α) : poly β := -⟨λv, g $ v ∘ f, g.induction - (λi, by simp; apply is_poly.proj) - (λn, by simp; apply is_poly.const) - (λf g pf pg, by simp; apply is_poly.sub pf pg) - (λf g pf pg, by simp; apply is_poly.mul pf pg)⟩ -@[simp] theorem remap_eval {α β} (f : α → β) (g : poly α) (v) : remap f g v = g (v ∘ f) := rfl +def map {α β} (f : α → β) (g : poly α) : poly β := +⟨λ v, g $ v ∘ f, g.induction + (λ i, by simp; apply is_poly.proj) + (λ n, by simp; apply is_poly.const) + (λ f g pf pg, by simp; apply is_poly.sub pf pg) + (λ f g pf pg, by simp; apply is_poly.mul pf pg)⟩ +@[simp] lemma map_apply {α β} (f : α → β) (g : poly α) (v) : map f g v = g (v ∘ f) := rfl end poly +end polynomials -namespace sum - -/-- combine two functions into a function on the disjoint union -/ -def join {α β γ} (f : α → γ) (g : β → γ) : α ⊕ β → γ := -by {refine sum.rec _ _, exacts [f, g]} - -end sum - -local infixr ` ⊗ `:65 := sum.join - -open sum - -namespace option - -/-- Functions from `option` can be combined similarly to `vector.cons` -/ -def cons {α β} (a : β) (v : α → β) : option α → β := -by {refine option.rec _ _, exacts [a, v]} - -notation a :: b := cons a b - -@[simp] theorem cons_head_tail {α β} (v : option α → β) : v none :: v ∘ some = v := -funext $ λo, by cases o; refl -end option - -/- dioph -/ +/-! ### Diophantine sets -/ /-- A set `S ⊆ ℕ^α` is Diophantine if there exists a polynomial on `α ⊕ β` such that `v ∈ S` iff there exists `t : ℕ^β` with `p (v, t) = 0`. -/ def dioph {α : Type u} (S : set (α → ℕ)) : Prop := -∃ {β : Type u} (p : poly (α ⊕ β)), ∀ (v : α → ℕ), S v ↔ ∃t, p (v ⊗ t) = 0 +∃ {β : Type u} (p : poly (α ⊕ β)), ∀ v, S v ↔ ∃ t, p (v ⊗ t) = 0 namespace dioph section -variables {α β γ : Type u} -theorem ext {S S' : set (α → ℕ)} (d : dioph S) (H : ∀v, S v ↔ S' v) : dioph S' := -eq.rec d $ show S = S', from set.ext H +variables {α β γ : Type u} {S S' : set (α → ℕ)} -theorem of_no_dummies (S : set (α → ℕ)) (p : poly α) (h : ∀ (v : α → ℕ), S v ↔ p v = 0) : - dioph S := -⟨ulift empty, p.remap inl, λv, (h v).trans - ⟨λh, ⟨λt, empty.rec _ t.down, by simp; rw [ - show (v ⊗ λt:ulift empty, empty.rec _ t.down) ∘ inl = v, from rfl, h]⟩, - λ⟨t, ht⟩, by simp at ht; rwa [show (v ⊗ t) ∘ inl = v, from rfl] at ht⟩⟩ +lemma ext (d : dioph S) (H : ∀ v, v ∈ S ↔ v ∈ S') : dioph S' := by rwa ←set.ext H + +lemma of_no_dummies (S : set (α → ℕ)) (p : poly α) (h : ∀ v, S v ↔ p v = 0) : dioph S := +⟨pempty, p.map inl, λ v, (h v).trans ⟨λ h, ⟨pempty.rec _, h⟩, λ ⟨t, ht⟩, ht⟩⟩ lemma inject_dummies_lem (f : β → γ) (g : γ → option β) (inv : ∀ x, g (f x) = some x) - (p : poly (α ⊕ β)) (v : α → ℕ) : (∃t, p (v ⊗ t) = 0) ↔ - (∃t, p.remap (inl ⊗ (inr ∘ f)) (v ⊗ t) = 0) := + (p : poly (α ⊕ β)) (v : α → ℕ) : + (∃ t, p (v ⊗ t) = 0) ↔ ∃ t, p.map (inl ⊗ inr ∘ f) (v ⊗ t) = 0 := begin - simp, refine ⟨λt, _, λt, _⟩; cases t with t ht, - { have : (v ⊗ (0 :: t) ∘ g) ∘ (inl ⊗ inr ∘ f) = v ⊗ t := - funext (λs, by cases s with a b; dsimp [join, (∘)]; try {rw inv}; refl), - exact ⟨(0 :: t) ∘ g, by rwa this⟩ }, + dsimp, refine ⟨λ t, _, λ t, _⟩; cases t with t ht, + { have : (v ⊗ (0 ::ₒ t) ∘ g) ∘ (inl ⊗ inr ∘ f) = v ⊗ t := + funext (λ s, by cases s with a b; dsimp [(∘)]; try {rw inv}; refl), + exact ⟨(0 ::ₒ t) ∘ g, by rwa this⟩ }, { have : v ⊗ t ∘ f = (v ⊗ t) ∘ (inl ⊗ inr ∘ f) := - funext (λs, by cases s with a b; refl), + funext (λ s, by cases s with a b; refl), exact ⟨t ∘ f, by rwa this⟩ } end -theorem inject_dummies {S : set (α → ℕ)} (f : β → γ) (g : γ → option β) - (inv : ∀ x, g (f x) = some x) (p : poly (α ⊕ β)) (h : ∀ (v : α → ℕ), S v ↔ ∃t, p (v ⊗ t) = 0) : - ∃ q : poly (α ⊕ γ), ∀ (v : α → ℕ), S v ↔ ∃t, q (v ⊗ t) = 0 := -⟨p.remap (inl ⊗ (inr ∘ f)), λv, (h v).trans $ inject_dummies_lem f g inv _ _⟩ +lemma inject_dummies (f : β → γ) (g : γ → option β) (inv : ∀ x, g (f x) = some x) (p : poly (α ⊕ β)) + (h : ∀ v, S v ↔ ∃ t, p (v ⊗ t) = 0) : + ∃ q : poly (α ⊕ γ), ∀ v, S v ↔ ∃ t, q (v ⊗ t) = 0 := +⟨p.map (inl ⊗ (inr ∘ f)), λ v, (h v).trans $ inject_dummies_lem f g inv _ _⟩ + +variables (β) -theorem reindex_dioph {S : set (α → ℕ)} : Π (d : dioph S) (f : α → β), dioph (λv, S (v ∘ f)) -| ⟨γ, p, pe⟩ f := ⟨γ, p.remap ((inl ∘ f) ⊗ inr), λv, (pe _).trans $ exists_congr $ λt, +lemma reindex_dioph (f : α → β) : Π (d : dioph S), dioph {v | v ∘ f ∈ S} +| ⟨γ, p, pe⟩ := ⟨γ, p.map ((inl ∘ f) ⊗ inr), λ v, (pe _).trans $ exists_congr $ λ t, suffices v ∘ f ⊗ t = (v ⊗ t) ∘ (inl ∘ f ⊗ inr), by simp [this], - funext $ λs, by cases s with a b; refl⟩ + funext $ λ s, by cases s with a b; refl⟩ -theorem dioph_list_all (l) (d : list_all dioph l) : - dioph (λv, list_all (λS : set (α → ℕ), S v) l) := +variables {β} + +lemma dioph_list.all₂ (l : list (set $ α → ℕ)) (d : l.all₂ dioph) : + dioph {v | l.all₂ (λ S : set (α → ℕ), v ∈ S)} := suffices ∃ β (pl : list (poly (α ⊕ β))), ∀ v, - list_all (λS : set _, S v) l ↔ ∃t, list_all (λp : poly (α ⊕ β), p (v ⊗ t) = 0) pl, + list.all₂ (λ S : set _, S v) l ↔ ∃ t, list.all₂ (λ p : poly (α ⊕ β), p (v ⊗ t) = 0) pl, from let ⟨β, pl, h⟩ := this - in ⟨β, poly.sumsq pl, λv, (h v).trans $ exists_congr $ λt, (poly.sumsq_eq_zero _ _).symm⟩, + in ⟨β, poly.sumsq pl, λ v, (h v).trans $ exists_congr $ λ t, (poly.sumsq_eq_zero _ _).symm⟩, begin induction l with S l IH, - exact ⟨ulift empty, [], λv, by simp; exact ⟨λ⟨t⟩, empty.rec _ t, trivial⟩⟩, + exact ⟨ulift empty, [], λ v, by simp; exact ⟨λ ⟨t⟩, empty.rec _ t, trivial⟩⟩, simp at d, exact let ⟨⟨β, p, pe⟩, dl⟩ := d, ⟨γ, pl, ple⟩ := IH dl in - ⟨β ⊕ γ, p.remap (inl ⊗ inr ∘ inl) :: pl.map (λq, q.remap (inl ⊗ (inr ∘ inr))), λv, + ⟨β ⊕ γ, p.map (inl ⊗ inr ∘ inl) :: pl.map (λ q, q.map (inl ⊗ (inr ∘ inr))), λ v, by simp; exact iff.trans (and_congr (pe v) (ple v)) - ⟨λ⟨⟨m, hm⟩, ⟨n, hn⟩⟩, + ⟨λ ⟨⟨m, hm⟩, ⟨n, hn⟩⟩, ⟨m ⊗ n, by rw [ show (v ⊗ m ⊗ n) ∘ (inl ⊗ inr ∘ inl) = v ⊗ m, - from funext $ λs, by cases s with a b; refl]; exact hm, - by { refine list_all.imp (λq hq, _) hn, dsimp [(∘)], + from funext $ λ s, by cases s with a b; refl]; exact hm, + by { refine list.all₂.imp (λ q hq, _) hn, dsimp [(∘)], rw [show (λ (x : α ⊕ γ), (v ⊗ m ⊗ n) ((inl ⊗ λ (x : γ), inr (inr x)) x)) = v ⊗ n, - from funext $ λs, by cases s with a b; refl]; exact hq }⟩, - λ⟨t, hl, hr⟩, + from funext $ λ s, by cases s with a b; refl]; exact hq }⟩, + λ ⟨t, hl, hr⟩, ⟨⟨t ∘ inl, by rwa [ show (v ⊗ t) ∘ (inl ⊗ inr ∘ inl) = v ⊗ t ∘ inl, - from funext $ λs, by cases s with a b; refl] at hl⟩, + from funext $ λ s, by cases s with a b; refl] at hl⟩, ⟨t ∘ inr, by - { refine list_all.imp (λq hq, _) hr, dsimp [(∘)] at hq, + { refine list.all₂.imp (λ q hq, _) hr, dsimp [(∘)] at hq, rwa [show (λ (x : α ⊕ γ), (v ⊗ t) ((inl ⊗ λ (x : γ), inr (inr x)) x)) = v ⊗ t ∘ inr, - from funext $ λs, by cases s with a b; refl] at hq }⟩⟩⟩⟩ + from funext $ λ s, by cases s with a b; refl] at hq }⟩⟩⟩⟩ end -theorem and_dioph {S S' : set (α → ℕ)} (d : dioph S) (d' : dioph S') : dioph (λv, S v ∧ S' v) := -dioph_list_all [S, S'] ⟨d, d'⟩ +lemma inter (d : dioph S) (d' : dioph S') : dioph (S ∩ S') := dioph_list.all₂ [S, S'] ⟨d, d'⟩ -theorem or_dioph {S S' : set (α → ℕ)} : ∀ (d : dioph S) (d' : dioph S'), dioph (λv, S v ∨ S' v) -| ⟨β, p, pe⟩ ⟨γ, q, qe⟩ := ⟨β ⊕ γ, p.remap (inl ⊗ inr ∘ inl) * q.remap (inl ⊗ inr ∘ inr), λv, +lemma union : ∀ (d : dioph S) (d' : dioph S'), dioph (S ∪ S') +| ⟨β, p, pe⟩ ⟨γ, q, qe⟩ := ⟨β ⊕ γ, p.map (inl ⊗ inr ∘ inl) * q.map (inl ⊗ inr ∘ inr), λ v, begin refine iff.trans (or_congr ((pe v).trans _) ((qe v).trans _)) - (exists_or_distrib.symm.trans (exists_congr $ λt, + (exists_or_distrib.symm.trans (exists_congr $ λ t, (@mul_eq_zero _ _ _ (p ((v ⊗ t) ∘ (inl ⊗ inr ∘ inl))) (q ((v ⊗ t) ∘ (inl ⊗ inr ∘ inr)))).symm)), - exact inject_dummies_lem _ (some ⊗ (λ_, none)) (λx, rfl) _ _, - exact inject_dummies_lem _ ((λ_, none) ⊗ some) (λx, rfl) _ _, + exact inject_dummies_lem _ (some ⊗ (λ _, none)) (λ x, rfl) _ _, + exact inject_dummies_lem _ ((λ _, none) ⊗ some) (λ x, rfl) _ _, end⟩ /-- A partial function is Diophantine if its graph is Diophantine. -/ -def dioph_pfun (f : (α → ℕ) →. ℕ) := dioph (λv : option α → ℕ, f.graph (v ∘ some, v none)) +def dioph_pfun (f : (α → ℕ) →. ℕ) : Prop := dioph {v : option α → ℕ | f.graph (v ∘ some, v none)} /-- A function is Diophantine if its graph is Diophantine. -/ -def dioph_fn (f : (α → ℕ) → ℕ) := dioph (λv : option α → ℕ, f (v ∘ some) = v none) +def dioph_fn (f : (α → ℕ) → ℕ) : Prop := dioph {v : option α → ℕ | f (v ∘ some) = v none} -theorem reindex_dioph_fn {f : (α → ℕ) → ℕ} (d : dioph_fn f) (g : α → β) : - dioph_fn (λv, f (v ∘ g)) := -reindex_dioph d (functor.map g) +lemma reindex_dioph_fn {f : (α → ℕ) → ℕ} (g : α → β) (d : dioph_fn f) : dioph_fn (λ v, f (v ∘ g)) := +by convert reindex_dioph (option β) (option.map g) d -theorem ex_dioph {S : set (α ⊕ β → ℕ)} : dioph S → dioph (λv, ∃x, S (v ⊗ x)) -| ⟨γ, p, pe⟩ := ⟨β ⊕ γ, p.remap ((inl ⊗ inr ∘ inl) ⊗ inr ∘ inr), λv, - ⟨λ⟨x, hx⟩, let ⟨t, ht⟩ := (pe _).1 hx in ⟨x ⊗ t, by simp; rw [ +lemma ex_dioph {S : set (α ⊕ β → ℕ)} : dioph S → dioph {v | ∃ x, v ⊗ x ∈ S} +| ⟨γ, p, pe⟩ := ⟨β ⊕ γ, p.map ((inl ⊗ inr ∘ inl) ⊗ inr ∘ inr), λ v, + ⟨λ ⟨x, hx⟩, let ⟨t, ht⟩ := (pe _).1 hx in ⟨x ⊗ t, by simp; rw [ show (v ⊗ x ⊗ t) ∘ ((inl ⊗ inr ∘ inl) ⊗ inr ∘ inr) = (v ⊗ x) ⊗ t, - from funext $ λs, by cases s with a b; try {cases a}; refl]; exact ht⟩, - λ⟨t, ht⟩, ⟨t ∘ inl, (pe _).2 ⟨t ∘ inr, by simp at ht; rwa [ + from funext $ λ s, by cases s with a b; try {cases a}; refl]; exact ht⟩, + λ ⟨t, ht⟩, ⟨t ∘ inl, (pe _).2 ⟨t ∘ inr, by simp at ht; rwa [ show (v ⊗ t) ∘ ((inl ⊗ inr ∘ inl) ⊗ inr ∘ inr) = (v ⊗ t ∘ inl) ⊗ t ∘ inr, - from funext $ λs, by cases s with a b; try {cases a}; refl] at ht⟩⟩⟩⟩ + from funext $ λ s, by cases s with a b; try {cases a}; refl] at ht⟩⟩⟩⟩ -theorem ex1_dioph {S : set (option α → ℕ)} : dioph S → dioph (λv, ∃x, S (x :: v)) -| ⟨β, p, pe⟩ := ⟨option β, p.remap (inr none :: inl ⊗ inr ∘ some), λv, - ⟨λ⟨x, hx⟩, let ⟨t, ht⟩ := (pe _).1 hx in ⟨x :: t, by simp; rw [ - show (v ⊗ x :: t) ∘ (inr none :: inl ⊗ inr ∘ some) = x :: v ⊗ t, - from funext $ λs, by cases s with a b; try {cases a}; refl]; exact ht⟩, - λ⟨t, ht⟩, ⟨t none, (pe _).2 ⟨t ∘ some, by simp at ht; rwa [ - show (v ⊗ t) ∘ (inr none :: inl ⊗ inr ∘ some) = t none :: v ⊗ t ∘ some, - from funext $ λs, by cases s with a b; try {cases a}; refl] at ht⟩⟩⟩⟩ +lemma ex1_dioph {S : set (option α → ℕ)} : dioph S → dioph {v | ∃ x, x ::ₒ v ∈ S} +| ⟨β, p, pe⟩ := ⟨option β, p.map (inr none ::ₒ inl ⊗ inr ∘ some), λ v, + ⟨λ ⟨x, hx⟩, let ⟨t, ht⟩ := (pe _).1 hx in ⟨x ::ₒ t, by simp; rw [ + show (v ⊗ x ::ₒ t) ∘ (inr none ::ₒ inl ⊗ inr ∘ some) = x ::ₒ v ⊗ t, + from funext $ λ s, by cases s with a b; try {cases a}; refl]; exact ht⟩, + λ ⟨t, ht⟩, ⟨t none, (pe _).2 ⟨t ∘ some, by simp at ht; rwa [ + show (v ⊗ t) ∘ (inr none ::ₒ inl ⊗ inr ∘ some) = t none ::ₒ v ⊗ t ∘ some, + from funext $ λ s, by cases s with a b; try {cases a}; refl] at ht⟩⟩⟩⟩ theorem dom_dioph {f : (α → ℕ) →. ℕ} (d : dioph_pfun f) : dioph f.dom := -cast (congr_arg dioph $ set.ext $ λv, (pfun.dom_iff_graph _ _).symm) (ex1_dioph d) +cast (congr_arg dioph $ set.ext $ λ v, (pfun.dom_iff_graph _ _).symm) (ex1_dioph d) theorem dioph_fn_iff_pfun (f : (α → ℕ) → ℕ) : dioph_fn f = @dioph_pfun α f := -by refine congr_arg dioph (set.ext $ λv, _); exact pfun.lift_graph.symm +by refine congr_arg dioph (set.ext $ λ v, _); exact pfun.lift_graph.symm -theorem abs_poly_dioph (p : poly α) : dioph_fn (λv, (p v).nat_abs) := -by refine of_no_dummies _ ((p.remap some - poly.proj none) * (p.remap some + poly.proj none)) - (λv, _); apply int.eq_nat_abs_iff_mul +lemma abs_poly_dioph (p : poly α) : dioph_fn (λ v, (p v).nat_abs) := +of_no_dummies _ ((p.map some - poly.proj none) * (p.map some + poly.proj none)) $ λ v, + by { dsimp, exact int.eq_nat_abs_iff_mul_eq_zero } -theorem proj_dioph (i : α) : dioph_fn (λv, v i) := +theorem proj_dioph (i : α) : dioph_fn (λ v, v i) := abs_poly_dioph (poly.proj i) theorem dioph_pfun_comp1 {S : set (option α → ℕ)} (d : dioph S) {f} (df : dioph_pfun f) : - dioph (λv : α → ℕ, ∃ h : f.dom v, S (f.fn v h :: v)) := -ext (ex1_dioph (and_dioph d df)) $ λv, -⟨λ⟨x, hS, (h: Exists _)⟩, by - rw [show (x :: v) ∘ some = v, from funext $ λs, rfl] at h; + dioph {v : α → ℕ | ∃ h : f.dom v, f.fn v h ::ₒ v ∈ S} := +ext (ex1_dioph (d.inter df)) $ λ v, +⟨λ ⟨x, hS, (h: Exists _)⟩, by + rw [show (x ::ₒ v) ∘ some = v, from funext $ λ s, rfl] at h; cases h with hf h; refine ⟨hf, _⟩; rw [pfun.fn, h]; exact hS, -λ⟨x, hS⟩, ⟨f.fn v x, hS, show Exists _, - by rw [show (f.fn v x :: v) ∘ some = v, from funext $ λs, rfl]; exact ⟨x, rfl⟩⟩⟩ +λ ⟨x, hS⟩, ⟨f.fn v x, hS, show Exists _, + by rw [show (f.fn v x ::ₒ v) ∘ some = v, from funext $ λ s, rfl]; exact ⟨x, rfl⟩⟩⟩ theorem dioph_fn_comp1 {S : set (option α → ℕ)} (d : dioph S) {f : (α → ℕ) → ℕ} (df : dioph_fn f) : - dioph (λv : α → ℕ, S (f v :: v)) := -ext (dioph_pfun_comp1 d (cast (dioph_fn_iff_pfun f) df)) $ λv, -⟨λ⟨_, h⟩, h, λh, ⟨trivial, h⟩⟩ + dioph {v | f v ::ₒ v ∈ S} := +ext (dioph_pfun_comp1 d $ cast (dioph_fn_iff_pfun f) df) $ λ v, +⟨λ ⟨_, h⟩, h, λ h, ⟨trivial, h⟩⟩ end section -variables {α β γ : Type} +variables {α β : Type} {n : ℕ} + open vector3 open_locale vector3 -theorem dioph_fn_vec_comp1 {n} {S : set (vector3 ℕ (succ n))} (d : dioph S) {f : (vector3 ℕ n) → ℕ} + +local attribute [reducible] vector3 + +lemma dioph_fn_vec_comp1 {S : set (vector3 ℕ (succ n))} (d : dioph S) {f : vector3 ℕ n → ℕ} (df : dioph_fn f) : - dioph (λv : vector3 ℕ n, S (cons (f v) v)) := -ext (dioph_fn_comp1 (reindex_dioph d (none :: some)) df) $ λv, by rw [ - show option.cons (f v) v ∘ (cons none some) = f v :: v, - from funext $ λs, by cases s with a b; refl] + dioph {v : vector3 ℕ n | f v :: v ∈ S} := +ext (dioph_fn_comp1 (reindex_dioph _ (none :: some) d) df) $ λ v, + by { dsimp, congr', ext x, cases x; refl } theorem vec_ex1_dioph (n) {S : set (vector3 ℕ (succ n))} (d : dioph S) : - dioph (λv : vector3 ℕ n, ∃x, S (x :: v)) := -ext (ex1_dioph $ reindex_dioph d (none :: some)) $ λv, exists_congr $ λx, by rw [ - show (option.cons x v) ∘ (cons none some) = x :: v, - from funext $ λs, by cases s with a b; refl] + dioph {v : fin2 n → ℕ | ∃ x, x :: v ∈ S} := +ext (ex1_dioph $ reindex_dioph _ (none :: some) d) $ λ v, exists_congr $ λ x, by { dsimp, + rw [show (option.cons x v) ∘ (cons none some) = x :: v, + from funext $ λ s, by cases s with a b; refl] } -theorem dioph_fn_vec {n} (f : vector3 ℕ n → ℕ) : - dioph_fn f ↔ dioph (λv : vector3 ℕ (succ n), f (v ∘ fs) = v fz) := -⟨λh, reindex_dioph h (fz :: fs), λh, reindex_dioph h (none :: some)⟩ +lemma dioph_fn_vec (f : vector3 ℕ n → ℕ) : dioph_fn f ↔ dioph {v | f (v ∘ fs) = v fz} := +⟨reindex_dioph _ (fz ::ₒ fs), reindex_dioph _ (none :: some)⟩ -theorem dioph_pfun_vec {n} (f : vector3 ℕ n →. ℕ) : - dioph_pfun f ↔ dioph (λv : vector3 ℕ (succ n), f.graph (v ∘ fs, v fz)) := -⟨λh, reindex_dioph h (fz :: fs), λh, reindex_dioph h (none :: some)⟩ +lemma dioph_pfun_vec (f : vector3 ℕ n →. ℕ) : dioph_pfun f ↔ dioph {v | f.graph (v ∘ fs, v fz)} := +⟨reindex_dioph _ (fz ::ₒ fs), reindex_dioph _ (none :: some)⟩ -theorem dioph_fn_compn {α : Type} : ∀ {n} {S : set (α ⊕ fin2 n → ℕ)} (d : dioph S) +lemma dioph_fn_compn : ∀ {n} {S : set (α ⊕ fin2 n → ℕ)} (d : dioph S) {f : vector3 ((α → ℕ) → ℕ) n} (df : vector_allp dioph_fn f), - dioph (λv : α → ℕ, S (v ⊗ λi, f i v)) -| 0 S d f := λdf, ext (reindex_dioph d (id ⊗ fin2.elim0)) $ λv, - by refine eq.to_iff (congr_arg S $ funext $ λs, _); {cases s with a b, refl, cases b} -| (succ n) S d f := f.cons_elim $ λf fl, by simp; exact λ df dfl, - have dioph (λv, S (v ∘ inl ⊗ f (v ∘ inl) :: v ∘ inr)), - from ext (dioph_fn_comp1 (reindex_dioph d (some ∘ inl ⊗ none :: some ∘ inr)) - (reindex_dioph_fn df inl)) $ - λv, by {refine eq.to_iff (congr_arg S $ funext $ λs, _); cases s with a b, refl, cases b; refl}, - have dioph (λv, S (v ⊗ f v :: λ (i : fin2 n), fl i v)), - from @dioph_fn_compn n (λv, S (v ∘ inl ⊗ f (v ∘ inl) :: v ∘ inr)) this _ dfl, - ext this $ λv, by rw [ - show cons (f v) (λ (i : fin2 n), fl i v) = λ (i : fin2 (succ n)), (f :: fl) i v, - from funext $ λs, by cases s with a b; refl] - -theorem dioph_comp {n} {S : set (vector3 ℕ n)} (d : dioph S) - (f : vector3 ((α → ℕ) → ℕ) n) (df : vector_allp dioph_fn f) : dioph (λv, S (λi, f i v)) := -dioph_fn_compn (reindex_dioph d inr) df - -theorem dioph_fn_comp {n} {f : vector3 ℕ n → ℕ} (df : dioph_fn f) - (g : vector3 ((α → ℕ) → ℕ) n) (dg : vector_allp dioph_fn g) : dioph_fn (λv, f (λi, g i v)) := -dioph_comp ((dioph_fn_vec _).1 df) ((λv, v none) :: λi v, g i (v ∘ some)) $ -by simp; exact ⟨proj_dioph none, (vector_allp_iff_forall _ _).2 $ λi, - reindex_dioph_fn ((vector_allp_iff_forall _ _).1 dg _) _⟩ - -localized "notation x ` D∧ `:35 y := dioph.and_dioph x y" in dioph -localized "notation x ` D∨ `:35 y := dioph.or_dioph x y" in dioph + dioph {v : α → ℕ | v ⊗ (λ i, f i v) ∈ S} +| 0 S d f := λ df, ext (reindex_dioph _ (id ⊗ fin2.elim0) d) $ λ v, + by { dsimp, congr', ext x, obtain (_ | _ | _) := x, refl } +| (succ n) S d f := f.cons_elim $ λ f fl, by simp; exact λ df dfl, + have dioph {v |v ∘ inl ⊗ f (v ∘ inl) :: v ∘ inr ∈ S}, + from ext (dioph_fn_comp1 (reindex_dioph _ (some ∘ inl ⊗ none :: some ∘ inr) d) $ + reindex_dioph_fn inl df) $ λ v, + by { dsimp, congr', ext x, obtain (_ | _ | _) := x; refl }, + have dioph {v | v ⊗ f v :: (λ (i : fin2 n), fl i v) ∈ S}, + from @dioph_fn_compn n (λ v, S (v ∘ inl ⊗ f (v ∘ inl) :: v ∘ inr)) this _ dfl, + ext this $ λ v, by { dsimp, congr', ext x, obtain (_ | _ | _) := x; refl } + +lemma dioph_comp {S : set (vector3 ℕ n)} (d : dioph S) (f : vector3 ((α → ℕ) → ℕ) n) + (df : vector_allp dioph_fn f) : dioph {v | (λ i, f i v) ∈ S} := +dioph_fn_compn (reindex_dioph _ inr d) df + +lemma dioph_fn_comp {f : vector3 ℕ n → ℕ} (df : dioph_fn f) (g : vector3 ((α → ℕ) → ℕ) n) + (dg : vector_allp dioph_fn g) : dioph_fn (λ v, f (λ i, g i v)) := +dioph_comp ((dioph_fn_vec _).1 df) ((λ v, v none) :: λ i v, g i (v ∘ some)) $ +by simp; exact ⟨proj_dioph none, (vector_allp_iff_forall _ _).2 $ λ i, + reindex_dioph_fn _ $ (vector_allp_iff_forall _ _).1 dg _⟩ + +localized "notation x ` D∧ `:35 y := dioph.inter x y" in dioph +localized "notation x ` D∨ `:35 y := dioph.union x y" in dioph localized "notation `D∃`:30 := dioph.vec_ex1_dioph" in dioph localized "prefix `&`:max := fin2.of_nat'" in dioph -theorem proj_dioph_of_nat {n : ℕ} (m : ℕ) [is_lt m n] : dioph_fn (λv : vector3 ℕ n, v &m) := +theorem proj_dioph_of_nat {n : ℕ} (m : ℕ) [is_lt m n] : dioph_fn (λ v : vector3 ℕ n, v &m) := proj_dioph &m localized "prefix `D&`:100 := dioph.proj_dioph_of_nat" in dioph @@ -474,83 +399,84 @@ localized "prefix `D.`:100 := dioph.const_dioph" in dioph variables {f g : (α → ℕ) → ℕ} (df : dioph_fn f) (dg : dioph_fn g) include df dg -theorem dioph_comp2 {S : ℕ → ℕ → Prop} (d : dioph (λv:vector3 ℕ 2, S (v &0) (v &1))) : - dioph (λv, S (f v) (g v)) := +lemma dioph_comp2 {S : ℕ → ℕ → Prop} (d : dioph (λ v:vector3 ℕ 2, S (v &0) (v &1))) : + dioph (λ v, S (f v) (g v)) := dioph_comp d [f, g] (by exact ⟨df, dg⟩) -theorem dioph_fn_comp2 {h : ℕ → ℕ → ℕ} (d : dioph_fn (λv:vector3 ℕ 2, h (v &0) (v &1))) : - dioph_fn (λv, h (f v) (g v)) := +lemma dioph_fn_comp2 {h : ℕ → ℕ → ℕ} (d : dioph_fn (λ v:vector3 ℕ 2, h (v &0) (v &1))) : + dioph_fn (λ v, h (f v) (g v)) := dioph_fn_comp d [f, g] (by exact ⟨df, dg⟩) -theorem eq_dioph : dioph (λv, f v = g v) := +lemma eq_dioph : dioph (λ v, f v = g v) := dioph_comp2 df dg $ of_no_dummies _ (poly.proj &0 - poly.proj &1) - (λv, (int.coe_nat_eq_coe_nat_iff _ _).symm.trans + (λ v, (int.coe_nat_eq_coe_nat_iff _ _).symm.trans ⟨@sub_eq_zero_of_eq ℤ _ (v &0) (v &1), eq_of_sub_eq_zero⟩) localized "infix ` D= `:50 := dioph.eq_dioph" in dioph -theorem add_dioph : dioph_fn (λv, f v + g v) := +lemma add_dioph : dioph_fn (λ v, f v + g v) := dioph_fn_comp2 df dg $ abs_poly_dioph (poly.proj &0 + poly.proj &1) localized "infix ` D+ `:80 := dioph.add_dioph" in dioph -theorem mul_dioph : dioph_fn (λv, f v * g v) := +lemma mul_dioph : dioph_fn (λ v, f v * g v) := dioph_fn_comp2 df dg $ abs_poly_dioph (poly.proj &0 * poly.proj &1) localized "infix ` D* `:90 := dioph.mul_dioph" in dioph -theorem le_dioph : dioph (λv, f v ≤ g v) := -dioph_comp2 df dg $ ext (D∃2 $ D&1 D+ D&0 D= D&2) (λv, ⟨λ⟨x, hx⟩, le.intro hx, le.dest⟩) +lemma le_dioph : dioph {v | f v ≤ g v} := +dioph_comp2 df dg $ ext (D∃2 $ D&1 D+ D&0 D= D&2) (λ v, ⟨λ ⟨x, hx⟩, le.intro hx, le.dest⟩) localized "infix ` D≤ `:50 := dioph.le_dioph" in dioph -theorem lt_dioph : dioph (λv, f v < g v) := df D+ (D. 1) D≤ dg +lemma lt_dioph : dioph {v | f v < g v} := df D+ (D. 1) D≤ dg localized "infix ` D< `:50 := dioph.lt_dioph" in dioph -theorem ne_dioph : dioph (λv, f v ≠ g v) := -ext (df D< dg D∨ dg D< df) $ λv, ne_iff_lt_or_gt.symm +lemma ne_dioph : dioph {v | f v ≠ g v} := +ext (df D< dg D∨ dg D< df) $ λ v, by { dsimp, exact lt_or_lt_iff_ne } localized "infix ` D≠ `:50 := dioph.ne_dioph" in dioph -theorem sub_dioph : dioph_fn (λv, f v - g v) := +lemma sub_dioph : dioph_fn (λ v, f v - g v) := dioph_fn_comp2 df dg $ (dioph_fn_vec _).2 $ -ext (D&1 D= D&0 D+ D&2 D∨ D&1 D≤ D&2 D∧ D&0 D= D.0) $ (vector_all_iff_forall _).1 $ λx y z, +ext (D&1 D= D&0 D+ D&2 D∨ D&1 D≤ D&2 D∧ D&0 D= D.0) $ (vector_all_iff_forall _).1 $ λ x y z, show (y = x + z ∨ y ≤ z ∧ x = 0) ↔ y - z = x, from -⟨λo, begin +⟨λ o, begin rcases o with ae | ⟨yz, x0⟩, { rw [ae, add_tsub_cancel_right] }, { rw [x0, tsub_eq_zero_iff_le.mpr yz] } -end, λh, begin - subst x, +end, begin + rintro rfl, cases le_total y z with yz zy, { exact or.inr ⟨yz, tsub_eq_zero_iff_le.mpr yz⟩ }, { exact or.inl (tsub_add_cancel_of_le zy).symm }, end⟩ localized "infix ` D- `:80 := dioph.sub_dioph" in dioph -theorem dvd_dioph : dioph (λv, f v ∣ g v) := +lemma dvd_dioph : dioph (λ v, f v ∣ g v) := dioph_comp (D∃2 $ D&2 D= D&1 D* D&0) [f, g] (by exact ⟨df, dg⟩) localized "infix ` D∣ `:50 := dioph.dvd_dioph" in dioph -theorem mod_dioph : dioph_fn (λv, f v % g v) := -have dioph (λv : vector3 ℕ 3, (v &2 = 0 ∨ v &0 < v &2) ∧ ∃ (x : ℕ), v &0 + v &2 * x = v &1), +lemma mod_dioph : dioph_fn (λ v, f v % g v) := +have dioph (λ v : vector3 ℕ 3, (v &2 = 0 ∨ v &0 < v &2) ∧ ∃ (x : ℕ), v &0 + v &2 * x = v &1), from (D&2 D= D.0 D∨ D&0 D< D&2) D∧ (D∃3 $ D&1 D+ D&3 D* D&0 D= D&2), -dioph_fn_comp2 df dg $ (dioph_fn_vec _).2 $ ext this $ (vector_all_iff_forall _).1 $ λz x y, +dioph_fn_comp2 df dg $ (dioph_fn_vec _).2 $ ext this $ (vector_all_iff_forall _).1 $ λ z x y, show ((y = 0 ∨ z < y) ∧ ∃ c, z + y * c = x) ↔ x % y = z, from -⟨λ⟨h, c, hc⟩, begin rw ← hc; simp; cases h with x0 hl, rw [x0, mod_zero], exact mod_eq_of_lt hl end, -λe, by rw ← e; exact ⟨or_iff_not_imp_left.2 $ λh, mod_lt _ (nat.pos_of_ne_zero h), x / y, +⟨λ ⟨h, c, hc⟩, begin rw ← hc; simp; cases h with x0 hl, rw [x0, mod_zero], + exact mod_eq_of_lt hl end, +λ e, by rw ← e; exact ⟨or_iff_not_imp_left.2 $ λ h, mod_lt _ (nat.pos_of_ne_zero h), x / y, mod_add_div _ _⟩⟩ localized "infix ` D% `:80 := dioph.mod_dioph" in dioph -theorem modeq_dioph {h : (α → ℕ) → ℕ} (dh : dioph_fn h) : dioph (λv, f v ≡ g v [MOD h v]) := +lemma modeq_dioph {h : (α → ℕ) → ℕ} (dh : dioph_fn h) : dioph (λ v, f v ≡ g v [MOD h v]) := df D% dh D= dg D% dh localized "notation `D≡` := dioph.modeq_dioph" in dioph -theorem div_dioph : dioph_fn (λv, f v / g v) := -have dioph (λv : vector3 ℕ 3, v &2 = 0 ∧ v &0 = 0 ∨ v &0 * v &2 ≤ v &1 ∧ v &1 < (v &0 + 1) * v &2), +lemma div_dioph : dioph_fn (λ v, f v / g v) := +have dioph (λ v : vector3 ℕ 3, v &2 = 0 ∧ v &0 = 0 ∨ v &0 * v &2 ≤ v &1 ∧ v &1 < (v &0 + 1) * v &2), from (D&2 D= D.0 D∧ D&0 D= D.0) D∨ D&0 D* D&2 D≤ D&1 D∧ D&1 D< (D&0 D+ D.1) D* D&2, -dioph_fn_comp2 df dg $ (dioph_fn_vec _).2 $ ext this $ (vector_all_iff_forall _).1 $ λz x y, +dioph_fn_comp2 df dg $ (dioph_fn_vec _).2 $ ext this $ (vector_all_iff_forall _).1 $ λ z x y, show y = 0 ∧ z = 0 ∨ z * y ≤ x ∧ x < (z + 1) * y ↔ x / y = z, by refine iff.trans _ eq_comm; exact y.eq_zero_or_pos.elim - (λy0, by rw [y0, nat.div_zero]; exact - ⟨λo, (o.resolve_right $ λ⟨_, h2⟩, nat.not_lt_zero _ h2).right, λz0, or.inl ⟨rfl, z0⟩⟩) - (λypos, iff.trans ⟨λo, o.resolve_left $ λ⟨h1, _⟩, ne_of_gt ypos h1, or.inr⟩ + (λ y0, by rw [y0, nat.div_zero]; exact + ⟨λ o, (o.resolve_right $ λ ⟨_, h2⟩, nat.not_lt_zero _ h2).right, λ z0, or.inl ⟨rfl, z0⟩⟩) + (λ ypos, iff.trans ⟨λ o, o.resolve_left $ λ ⟨h1, _⟩, ne_of_gt ypos h1, or.inr⟩ (le_antisymm_iff.trans $ and_congr (nat.le_div_iff_mul_le _ _ ypos) $ iff.trans ⟨lt_succ_of_le, le_of_lt_succ⟩ (div_lt_iff_lt_mul _ _ ypos)).symm) localized "infix ` D/ `:80 := dioph.div_dioph" in dioph @@ -558,7 +484,7 @@ localized "infix ` D/ `:80 := dioph.div_dioph" in dioph omit df dg open pell -theorem pell_dioph : dioph (λv:vector3 ℕ 4, ∃ h : 1 < v &0, +lemma pell_dioph : dioph (λ v:vector3 ℕ 4, ∃ h : 1 < v &0, xn h (v &1) = v &2 ∧ yn h (v &1) = v &3) := have dioph {v : vector3 ℕ 4 | 1 < v &0 ∧ v &1 ≤ v &3 ∧ @@ -581,16 +507,16 @@ D.1 D< D&0 D∧ D&1 D≤ D&3 D∧ D.0 D< D&3 D∧ D&8 D* D&8 D∣ D&3 D∧ (D≡ (D&2) (D&7) D&4) D∧ (D≡ (D&1) (D&6) (D.4 D* D&8)))), -dioph.ext this $ λv, matiyasevic.symm +dioph.ext this $ λ v, matiyasevic.symm -theorem xn_dioph : dioph_pfun (λv:vector3 ℕ 2, ⟨1 < v &0, λh, xn h (v &1)⟩) := -have dioph (λv:vector3 ℕ 3, ∃ y, ∃ h : 1 < v &1, xn h (v &2) = v &0 ∧ yn h (v &2) = y), from -let D_pell := @reindex_dioph _ (fin2 4) _ pell_dioph [&2, &3, &1, &0] in D∃3 D_pell, -(dioph_pfun_vec _).2 $ dioph.ext this $ λv, ⟨λ⟨y, h, xe, ye⟩, ⟨h, xe⟩, λ⟨h, xe⟩, ⟨_, h, xe, rfl⟩⟩ +lemma xn_dioph : dioph_pfun (λ v:vector3 ℕ 2, ⟨1 < v &0, λ h, xn h (v &1)⟩) := +have dioph (λ v:vector3 ℕ 3, ∃ y, ∃ h : 1 < v &1, xn h (v &2) = v &0 ∧ yn h (v &2) = y), from +let D_pell := pell_dioph.reindex_dioph (fin2 4) [&2, &3, &1, &0] in D∃3 D_pell, +(dioph_pfun_vec _).2 $ dioph.ext this $ λ v, ⟨λ ⟨y, h, xe, ye⟩, ⟨h, xe⟩, λ ⟨h, xe⟩, ⟨_, h, xe, rfl⟩⟩ include df dg /-- A version of **Matiyasevic's theorem** -/ -theorem pow_dioph : dioph_fn (λv, f v ^ g v) := +theorem pow_dioph : dioph_fn (λ v, f v ^ g v) := have dioph {v : vector3 ℕ 3 | v &2 = 0 ∧ v &0 = 1 ∨ 0 < v &2 ∧ (v &1 = 0 ∧ v &0 = 0 ∨ 0 < v &1 ∧ @@ -600,7 +526,7 @@ v &2 = 0 ∧ v &0 = 1 ∨ 0 < v &2 ∧ 2 * a * v &1 = t + (v &1 * v &1 + 1) ∧ v &0 < t ∧ v &1 ≤ w ∧ v &2 ≤ w ∧ a * a - ((w + 1) * (w + 1) - 1) * (w * z) * (w * z) = 1)}, from -let D_pell := @reindex_dioph _ (fin2 9) _ pell_dioph [&4, &8, &1, &0] in +let D_pell := pell_dioph.reindex_dioph (fin2 9) [&4, &8, &1, &0] in (D&2 D= D.0 D∧ D&0 D= D.1) D∨ (D.0 D< D&2 D∧ ((D&1 D= D.0 D∧ D&0 D= D.0) D∨ (D.0 D< D&1 D∧ (D∃3 $ D∃4 $ D∃5 $ D∃6 $ D∃7 $ D∃8 $ D_pell D∧ @@ -608,10 +534,10 @@ let D_pell := @reindex_dioph _ (fin2 9) _ pell_dioph [&4, &8, &1, &0] in D.2 D* D&4 D* D&7 D= D&3 D+ (D&7 D* D&7 D+ D.1) D∧ D&6 D< D&3 D∧ D&7 D≤ D&5 D∧ D&8 D≤ D&5 D∧ D&4 D* D&4 D- ((D&5 D+ D.1) D* (D&5 D+ D.1) D- D.1) D* (D&5 D* D&2) D* (D&5 D* D&2) D= D.1)))), -dioph_fn_comp2 df dg $ (dioph_fn_vec _).2 $ dioph.ext this $ λv, iff.symm $ +dioph_fn_comp2 df dg $ (dioph_fn_vec _).2 $ dioph.ext this $ λ v, iff.symm $ eq_pow_of_pell.trans $ or_congr iff.rfl $ and_congr iff.rfl $ or_congr iff.rfl $ and_congr iff.rfl $ -⟨λ⟨w, a, t, z, a1, h⟩, ⟨w, a, t, z, _, _, ⟨a1, rfl, rfl⟩, h⟩, - λ⟨w, a, t, z, ._, ._, ⟨a1, rfl, rfl⟩, h⟩, ⟨w, a, t, z, a1, h⟩⟩ +⟨λ ⟨w, a, t, z, a1, h⟩, ⟨w, a, t, z, _, _, ⟨a1, rfl, rfl⟩, h⟩, + λ ⟨w, a, t, z, ._, ._, ⟨a1, rfl, rfl⟩, h⟩, ⟨w, a, t, z, a1, h⟩⟩ end end dioph From c956647c40ebed4b2e66cd9f9864dfd183babbc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Thu, 21 Apr 2022 12:10:02 +0000 Subject: [PATCH 128/373] feat(order/basic): Simple shortcut lemmas (#13421) Add convenience lemmas to make the API a bit more symmetric and easier to translate between `transitive` and `is_trans`. Also rename `_ge'` to `_le` in lemmas and fix the `is_max_` aliases. --- src/algebra/order/floor.lean | 2 +- src/algebra/parity.lean | 4 +- src/analysis/special_functions/pow.lean | 4 +- src/data/real/hyperreal.lean | 4 +- src/group_theory/subgroup/basic.lean | 2 +- src/order/basic.lean | 80 ++++++++++++++++++------- src/order/bounded.lean | 2 +- src/order/bounded_order.lean | 4 +- src/order/rel_classes.lean | 9 +++ src/ring_theory/perfection.lean | 6 +- src/ring_theory/polynomial/basic.lean | 2 +- test/finish4.lean | 2 +- 12 files changed, 85 insertions(+), 36 deletions(-) diff --git a/src/algebra/order/floor.lean b/src/algebra/order/floor.lean index 60ed6b0f42556..a0fc7fcb5026b 100644 --- a/src/algebra/order/floor.lean +++ b/src/algebra/order/floor.lean @@ -93,7 +93,7 @@ lemma le_floor (h : (n : α) ≤ a) : n ≤ ⌊a⌋₊ := (le_floor_iff $ n.cast lemma floor_lt (ha : 0 ≤ a) : ⌊a⌋₊ < n ↔ a < n := lt_iff_lt_of_le_iff_le $ le_floor_iff ha -lemma lt_of_floor_lt (h : ⌊a⌋₊ < n) : a < n := lt_of_not_ge' $ λ h', (le_floor h').not_lt h +lemma lt_of_floor_lt (h : ⌊a⌋₊ < n) : a < n := lt_of_not_le $ λ h', (le_floor h').not_lt h lemma floor_le (ha : 0 ≤ a) : (⌊a⌋₊ : α) ≤ a := (le_floor_iff ha).1 le_rfl diff --git a/src/algebra/parity.lean b/src/algebra/parity.lean index 431356e122061..69f2c7620ec19 100644 --- a/src/algebra/parity.lean +++ b/src/algebra/parity.lean @@ -296,10 +296,10 @@ lemma odd.pow_nonpos_iff (hn : odd n) : a ^ n ≤ 0 ↔ a ≤ 0 := ⟨λ h, le_of_not_lt (λ ha, h.not_lt $ pow_pos ha _), hn.pow_nonpos⟩ lemma odd.pow_pos_iff (hn : odd n) : 0 < a ^ n ↔ 0 < a := -⟨λ h, lt_of_not_ge' (λ ha, h.not_le $ hn.pow_nonpos ha), λ ha, pow_pos ha n⟩ +⟨λ h, lt_of_not_le (λ ha, h.not_le $ hn.pow_nonpos ha), λ ha, pow_pos ha n⟩ lemma odd.pow_neg_iff (hn : odd n) : a ^ n < 0 ↔ a < 0 := -⟨λ h, lt_of_not_ge' (λ ha, h.not_le $ pow_nonneg ha _), hn.pow_neg⟩ +⟨λ h, lt_of_not_le (λ ha, h.not_le $ pow_nonneg ha _), hn.pow_neg⟩ lemma even.pow_pos_iff (hn : even n) (h₀ : 0 < n) : 0 < a ^ n ↔ a ≠ 0 := ⟨λ h ha, by { rw [ha, zero_pow h₀] at h, exact lt_irrefl 0 h }, hn.pow_pos⟩ diff --git a/src/analysis/special_functions/pow.lean b/src/analysis/special_functions/pow.lean index 7e0daa561c338..916c3db4e14f6 100644 --- a/src/analysis/special_functions/pow.lean +++ b/src/analysis/special_functions/pow.lean @@ -603,7 +603,7 @@ begin end @[simp] lemma rpow_lt_rpow_left_iff (hx : 1 < x) : x ^ y < x ^ z ↔ y < z := -by rw [lt_iff_not_ge', rpow_le_rpow_left_iff hx, lt_iff_not_ge'] +by rw [lt_iff_not_le, rpow_le_rpow_left_iff hx, lt_iff_not_le] lemma rpow_lt_rpow_of_exponent_gt (hx0 : 0 < x) (hx1 : x < 1) (hyz : z < y) : x^y < x^z := @@ -628,7 +628,7 @@ end @[simp] lemma rpow_lt_rpow_left_iff_of_base_lt_one (hx0 : 0 < x) (hx1 : x < 1) : x ^ y < x ^ z ↔ z < y := -by rw [lt_iff_not_ge', rpow_le_rpow_left_iff_of_base_lt_one hx0 hx1, lt_iff_not_ge'] +by rw [lt_iff_not_le, rpow_le_rpow_left_iff_of_base_lt_one hx0 hx1, lt_iff_not_le] lemma rpow_lt_one {x z : ℝ} (hx1 : 0 ≤ x) (hx2 : x < 1) (hz : 0 < z) : x^z < 1 := by { rw ← one_rpow z, exact rpow_lt_rpow hx1 hx2 hz } diff --git a/src/data/real/hyperreal.lean b/src/data/real/hyperreal.lean index d9eb46eb76860..c12906fec6491 100644 --- a/src/data/real/hyperreal.lean +++ b/src/data/real/hyperreal.lean @@ -170,10 +170,10 @@ have HR₁ : S.nonempty := have HR₂ : bdd_above S := ⟨ r₂, λ y hy, le_of_lt (coe_lt_coe.1 (lt_of_lt_of_le hy (not_lt.mp hr₂))) ⟩, λ δ hδ, - ⟨ lt_of_not_ge' $ λ c, + ⟨ lt_of_not_le $ λ c, have hc : ∀ y ∈ S, y ≤ R - δ := λ y hy, coe_le_coe.1 $ le_of_lt $ lt_of_lt_of_le hy c, not_lt_of_le (cSup_le HR₁ hc) $ sub_lt_self R hδ, - lt_of_not_ge' $ λ c, + lt_of_not_le $ λ c, have hc : ↑(R + δ / 2) < x := lt_of_lt_of_le (add_lt_add_left (coe_lt_coe.2 (half_lt_self hδ)) R) c, not_lt_of_le (le_cSup HR₂ hc) $ (lt_add_iff_pos_right _).mpr $ half_pos hδ⟩ diff --git a/src/group_theory/subgroup/basic.lean b/src/group_theory/subgroup/basic.lean index bec98f8438bf0..2582b885efd70 100644 --- a/src/group_theory/subgroup/basic.lean +++ b/src/group_theory/subgroup/basic.lean @@ -714,7 +714,7 @@ end λ h, by simp [h]⟩ @[to_additive] lemma one_lt_card_iff_ne_bot [fintype H] : 1 < fintype.card H ↔ H ≠ ⊥ := -lt_iff_not_ge'.trans (not_iff_not.mpr H.card_le_one_iff_eq_bot) +lt_iff_not_le.trans H.card_le_one_iff_eq_bot.not /-- The inf of two subgroups is their intersection. -/ @[to_additive "The inf of two `add_subgroups`s is their intersection."] diff --git a/src/order/basic.lean b/src/order/basic.lean index 142ec8804ba70..4017d5159659e 100644 --- a/src/order/basic.lean +++ b/src/order/basic.lean @@ -57,24 +57,46 @@ open function universes u v w variables {α : Type u} {β : Type v} {γ : Type w} {r : α → α → Prop} -lemma ge_antisymm [partial_order α] {a b : α} (hab : a ≤ b) (hba : b ≤ a) : b = a := -le_antisymm hba hab +section preorder +variables [preorder α] {a b c : α} + +lemma le_trans' : b ≤ c → a ≤ b → a ≤ c := flip le_trans +lemma lt_trans' : b < c → a < b → a < c := flip lt_trans +lemma lt_of_le_of_lt' : b ≤ c → a < b → a < c := flip lt_of_lt_of_le +lemma lt_of_lt_of_le' : b < c → a ≤ b → a < c := flip lt_of_le_of_lt + +end preorder + +section partial_order +variables [partial_order α] {a b : α} + +lemma ge_antisymm : a ≤ b → b ≤ a → b = a := flip le_antisymm +lemma lt_of_le_of_ne' : a ≤ b → b ≠ a → a < b := λ h₁ h₂, lt_of_le_of_ne h₁ h₂.symm +lemma ne.lt_of_le : a ≠ b → a ≤ b → a < b := flip lt_of_le_of_ne +lemma ne.lt_of_le' : b ≠ a → a ≤ b → a < b := flip lt_of_le_of_ne' + +end partial_order attribute [simp] le_refl attribute [ext] has_le alias le_trans ← has_le.le.trans +alias le_trans' ← has_le.le.trans' alias lt_of_le_of_lt ← has_le.le.trans_lt +alias lt_of_le_of_lt' ← has_le.le.trans_lt' alias le_antisymm ← has_le.le.antisymm alias ge_antisymm ← has_le.le.antisymm' alias lt_of_le_of_ne ← has_le.le.lt_of_ne +alias lt_of_le_of_ne' ← has_le.le.lt_of_ne' alias lt_of_le_not_le ← has_le.le.lt_of_not_le alias lt_or_eq_of_le ← has_le.le.lt_or_eq alias decidable.lt_or_eq_of_le ← has_le.le.lt_or_eq_dec alias le_of_lt ← has_lt.lt.le alias lt_trans ← has_lt.lt.trans +alias lt_trans' ← has_lt.lt.trans' alias lt_of_lt_of_le ← has_lt.lt.trans_le +alias lt_of_lt_of_le' ← has_lt.lt.trans_le' alias ne_of_lt ← has_lt.lt.ne alias lt_asymm ← has_lt.lt.asymm has_lt.lt.not_lt @@ -82,23 +104,43 @@ alias le_of_eq ← eq.le attribute [nolint decidable_classical] has_le.le.lt_or_eq_dec +section +variables [preorder α] {a b c : α} + /-- A version of `le_refl` where the argument is implicit -/ -lemma le_rfl [preorder α] {x : α} : x ≤ x := le_refl x +lemma le_rfl : a ≤ a := le_refl a + +@[simp] lemma lt_self_iff_false (x : α) : x < x ↔ false := ⟨lt_irrefl x, false.elim⟩ + +lemma le_of_le_of_eq (hab : a ≤ b) (hbc : b = c) : a ≤ c := hab.trans hbc.le +lemma le_of_eq_of_le (hab : a = b) (hbc : b ≤ c) : a ≤ c := hab.le.trans hbc +lemma lt_of_lt_of_eq (hab : a < b) (hbc : b = c) : a < c := hab.trans_le hbc.le +lemma lt_of_eq_of_lt (hab : a = b) (hbc : b < c) : a < c := hab.le.trans_lt hbc +lemma le_of_le_of_eq' : b ≤ c → a = b → a ≤ c := flip le_of_eq_of_le +lemma le_of_eq_of_le' : b = c → a ≤ b → a ≤ c := flip le_of_le_of_eq +lemma lt_of_lt_of_eq' : b < c → a = b → a < c := flip lt_of_eq_of_lt +lemma lt_of_eq_of_lt' : b = c → a < b → a < c := flip lt_of_lt_of_eq + +alias le_of_le_of_eq ← has_le.le.trans_eq +alias le_of_le_of_eq' ← has_le.le.trans_eq' +alias lt_of_lt_of_eq ← has_lt.lt.trans_eq +alias lt_of_lt_of_eq' ← has_lt.lt.trans_eq' +alias le_of_eq_of_le ← eq.trans_le +alias le_of_eq_of_le' ← eq.trans_ge +alias lt_of_eq_of_lt ← eq.trans_lt +alias lt_of_eq_of_lt' ← eq.trans_gt -@[simp] lemma lt_self_iff_false [preorder α] (x : α) : x < x ↔ false := -⟨lt_irrefl x, false.elim⟩ +end namespace eq +variables [preorder α] {x y z : α} /-- If `x = y` then `y ≤ x`. Note: this lemma uses `y ≤ x` instead of `x ≥ y`, because `le` is used almost exclusively in mathlib. -/ -protected lemma ge [preorder α] {x y : α} (h : x = y) : y ≤ x := h.symm.le - -lemma trans_le [preorder α] {x y z : α} (h1 : x = y) (h2 : y ≤ z) : x ≤ z := h1.le.trans h2 +protected lemma ge (h : x = y) : y ≤ x := h.symm.le -lemma not_lt [preorder α] {x y : α} (h : x = y) : ¬(x < y) := λ h', h'.ne h - -lemma not_gt [preorder α] {x y : α} (h : x = y) : ¬(y < x) := h.symm.not_lt +lemma not_lt (h : x = y) : ¬ x < y := λ h', h'.ne h +lemma not_gt (h : x = y) : ¬ y < x := h.symm.not_lt end eq @@ -107,8 +149,6 @@ namespace has_le.le @[nolint ge_or_gt] -- see Note [nolint_ge] protected lemma ge [has_le α] {x y : α} (h : x ≤ y) : y ≥ x := h -lemma trans_eq [preorder α] {x y z : α} (h1 : x ≤ y) (h2 : y = z) : x ≤ z := h1.trans h2.le - lemma lt_iff_ne [partial_order α] {x y : α} (h : x ≤ y) : x < y ↔ x ≠ y := ⟨λ h, h.ne, h.lt_of_ne⟩ lemma le_iff_eq [partial_order α] {x y : α} (h : x ≤ y) : y ≤ x ↔ y = x := @@ -148,9 +188,9 @@ protected lemma gt.lt [has_lt α] {x y : α} (h : x > y) : y < x := h theorem ge_of_eq [preorder α] {a b : α} (h : a = b) : a ≥ b := h.ge @[simp, nolint ge_or_gt] -- see Note [nolint_ge] -lemma ge_iff_le [preorder α] {a b : α} : a ≥ b ↔ b ≤ a := iff.rfl +lemma ge_iff_le [has_le α] {a b : α} : a ≥ b ↔ b ≤ a := iff.rfl @[simp, nolint ge_or_gt] -- see Note [nolint_ge] -lemma gt_iff_lt [preorder α] {a b : α} : a > b ↔ b < a := iff.rfl +lemma gt_iff_lt [has_lt α] {a b : α} : a > b ↔ b < a := iff.rfl lemma not_le_of_lt [preorder α] {a b : α} (h : a < b) : ¬ b ≤ a := (le_not_le_of_lt h).right @@ -205,17 +245,17 @@ lemma ne.le_iff_lt [partial_order α] {a b : α} (h : a ≠ b) : a ≤ b ↔ a < ⟨λ h', lt_of_le_of_ne h' h, λ h, h.le⟩ -- See Note [decidable namespace] -protected lemma decidable.ne_iff_lt_iff_le [partial_order α] [decidable_eq α] - {a b : α} : (a ≠ b ↔ a < b) ↔ a ≤ b := +protected lemma decidable.ne_iff_lt_iff_le [partial_order α] [decidable_eq α] {a b : α} : + (a ≠ b ↔ a < b) ↔ a ≤ b := ⟨λ h, decidable.by_cases le_of_eq (le_of_lt ∘ h.mp), λ h, ⟨lt_of_le_of_ne h, ne_of_lt⟩⟩ @[simp] lemma ne_iff_lt_iff_le [partial_order α] {a b : α} : (a ≠ b ↔ a < b) ↔ a ≤ b := by haveI := classical.dec; exact decidable.ne_iff_lt_iff_le -lemma lt_of_not_ge' [linear_order α] {a b : α} (h : ¬ b ≤ a) : a < b := +lemma lt_of_not_le [linear_order α] {a b : α} (h : ¬ b ≤ a) : a < b := ((le_total _ _).resolve_right h).lt_of_not_le h -lemma lt_iff_not_ge' [linear_order α] {x y : α} : x < y ↔ ¬ y ≤ x := ⟨not_le_of_gt, lt_of_not_ge'⟩ +lemma lt_iff_not_le [linear_order α] {x y : α} : x < y ↔ ¬ y ≤ x := ⟨not_le_of_lt, lt_of_not_le⟩ lemma ne.lt_or_lt [linear_order α] {x y : α} (h : x ≠ y) : x < y ∨ y < x := lt_or_gt_of_ne h @@ -234,7 +274,7 @@ end lemma lt_imp_lt_of_le_imp_le {β} [linear_order α] [preorder β] {a b : α} {c d : β} (H : a ≤ b → c ≤ d) (h : d < c) : b < a := -lt_of_not_ge' $ λ h', (H h').not_lt h +lt_of_not_le $ λ h', (H h').not_lt h lemma le_imp_le_iff_lt_imp_lt {β} [linear_order α] [linear_order β] {a b : α} {c d : β} : (a ≤ b → c ≤ d) ↔ (d < c → b < a) := diff --git a/src/order/bounded.lean b/src/order/bounded.lean index 31e3f9ec7d658..a2ee26dd25ee9 100644 --- a/src/order/bounded.lean +++ b/src/order/bounded.lean @@ -240,7 +240,7 @@ by simp_rw [← not_le, bounded_le_inter_not_le] theorem unbounded_le_inter_lt [linear_order α] (a : α) : unbounded (≤) (s ∩ {b | a < b}) ↔ unbounded (≤) s := -by { convert unbounded_le_inter_not_le a, ext, exact lt_iff_not_ge' } +by { convert unbounded_le_inter_not_le a, ext, exact lt_iff_not_le } theorem bounded_le_inter_le [linear_order α] (a : α) : bounded (≤) (s ∩ {b | a ≤ b}) ↔ bounded (≤) s := diff --git a/src/order/bounded_order.lean b/src/order/bounded_order.lean index ddd7f7dac49d2..020791e8681b7 100644 --- a/src/order/bounded_order.lean +++ b/src/order/bounded_order.lean @@ -183,8 +183,8 @@ variables [partial_order α] [order_bot α] [preorder β] {f : α → β} {a b : lemma not_is_min_iff_ne_bot : ¬ is_min a ↔ a ≠ ⊥ := is_min_iff_eq_bot.not lemma not_is_bot_iff_ne_bot : ¬ is_bot a ↔ a ≠ ⊥ := is_bot_iff_eq_bot.not -alias is_min_iff_eq_bot ↔ _ is_min.eq_bot -alias is_bot_iff_eq_bot ↔ _ is_bot.eq_bot +alias is_min_iff_eq_bot ↔ is_min.eq_bot _ +alias is_bot_iff_eq_bot ↔ is_bot.eq_bot _ @[simp] lemma le_bot_iff : a ≤ ⊥ ↔ a = ⊥ := bot_le.le_iff_eq lemma bot_unique (h : a ≤ ⊥) : a = ⊥ := h.antisymm bot_le diff --git a/src/order/rel_classes.lean b/src/order/rel_classes.lean index 9f57a53672cdc..c2cead66cf327 100644 --- a/src/order/rel_classes.lean +++ b/src/order/rel_classes.lean @@ -20,6 +20,8 @@ variables {α : Type u} {β : Type v} {r : α → α → Prop} {s : β → β open function +lemma of_eq [is_refl α r] : ∀ {a b}, a = b → r a b | _ _ ⟨h⟩ := refl _ + lemma comm [is_symm α r] {a b : α} : r a b ↔ r b a := ⟨symm, symm⟩ lemma antisymm' [is_antisymm α r] {a b : α} : r a b → r b a → b = a := λ h h', antisymm h' h @@ -95,6 +97,8 @@ begin exact trans h₁ h₃, rw ←h₃, exact h₁, exfalso, exact h₂ h₃ end +lemma transitive_of_trans (r : α → α → Prop) [is_trans α r] : transitive r := λ _ _ _, trans + /-- Construct a partial order from a `is_strict_order` relation. See note [reducible non-instances]. -/ @@ -449,6 +453,11 @@ instance [linear_order α] : is_order_connected α (<) := by apply_instance instance [linear_order α] : is_incomp_trans α (<) := by apply_instance instance [linear_order α] : is_strict_weak_order α (<) := by apply_instance +lemma transitive_le [preorder α] : transitive (@has_le.le α _) := transitive_of_trans _ +lemma transitive_lt [preorder α] : transitive (@has_lt.lt α _) := transitive_of_trans _ +lemma transitive_ge [preorder α] : transitive (@ge α _) := transitive_of_trans _ +lemma transitive_gt [preorder α] : transitive (@gt α _) := transitive_of_trans _ + instance order_dual.is_total_le [has_le α] [is_total α (≤)] : is_total (order_dual α) (≤) := @is_total.swap α _ _ diff --git a/src/ring_theory/perfection.lean b/src/ring_theory/perfection.lean index e7ad746761654..c4f8b0bb7bb69 100644 --- a/src/ring_theory/perfection.lean +++ b/src/ring_theory/perfection.lean @@ -353,7 +353,7 @@ lemma pre_val_mk {x : O} (hx : (ideal.quotient.mk _ x : mod_p K v O hv p) ≠ 0) begin obtain ⟨r, hr⟩ := ideal.mem_span_singleton'.1 (ideal.quotient.eq.1 $ quotient.sound' $ @quotient.mk_out' O (ideal.span {p} : ideal O).quotient_rel x), - refine (if_neg hx).trans (v.map_eq_of_sub_lt $ lt_of_not_ge' _), + refine (if_neg hx).trans (v.map_eq_of_sub_lt $ lt_of_not_le _), erw [← ring_hom.map_sub, ← hr, hv.le_iff_dvd], exact λ hprx, hx (ideal.quotient.eq_zero_iff_mem.2 $ ideal.mem_span_singleton.2 $ dvd_of_mul_left_dvd hprx), @@ -388,7 +388,7 @@ end lemma v_p_lt_pre_val {x : mod_p K v O hv p} : v p < pre_val K v O hv p x ↔ x ≠ 0 := begin refine ⟨λ h hx, by { rw [hx, pre_val_zero] at h, exact not_lt_zero' h }, - λ h, lt_of_not_ge' $ λ hp, h _⟩, + λ h, lt_of_not_le $ λ hp, h _⟩, obtain ⟨r, rfl⟩ := ideal.quotient.mk_surjective x, rw [pre_val_mk h, ← map_nat_cast (algebra_map O K) p, hv.le_iff_dvd] at hp, rw [ideal.quotient.eq_zero_iff_mem, ideal.mem_span_singleton], exact hp @@ -402,7 +402,7 @@ lemma pre_val_eq_zero {x : mod_p K v O hv p} : pre_val K v O hv p x = 0 ↔ x = variables (hv hvp) lemma v_p_lt_val {x : O} : v p < v (algebra_map O K x) ↔ (ideal.quotient.mk _ x : mod_p K v O hv p) ≠ 0 := -by rw [lt_iff_not_ge', not_iff_not, ← map_nat_cast (algebra_map O K) p, hv.le_iff_dvd, +by rw [lt_iff_not_le, not_iff_not, ← map_nat_cast (algebra_map O K) p, hv.le_iff_dvd, ideal.quotient.eq_zero_iff_mem, ideal.mem_span_singleton] open nnreal diff --git a/src/ring_theory/polynomial/basic.lean b/src/ring_theory/polynomial/basic.lean index 58e2b3c8b4dde..f65af429b3f10 100644 --- a/src/ring_theory/polynomial/basic.lean +++ b/src/ring_theory/polynomial/basic.lean @@ -77,7 +77,7 @@ theorem mem_degree_lt {n : ℕ} {f : R[X]} : f ∈ degree_lt R n ↔ degree f < n := by { simp_rw [degree_lt, submodule.mem_infi, linear_map.mem_ker, degree, finset.sup_lt_iff (with_bot.bot_lt_coe n), mem_support_iff, with_bot.some_eq_coe, - with_bot.coe_lt_coe, lt_iff_not_ge', ne, not_imp_not], refl } + with_bot.coe_lt_coe, lt_iff_not_le, ne, not_imp_not], refl } @[mono] theorem degree_lt_mono {m n : ℕ} (H : m ≤ n) : degree_lt R m ≤ degree_lt R n := diff --git a/test/finish4.lean b/test/finish4.lean index 292c38c4e6104..3bc84021728a6 100644 --- a/test/finish4.lean +++ b/test/finish4.lean @@ -56,4 +56,4 @@ constant exp_add : ∀ x y, exp (x + y) = exp x * exp y theorem log_mul' {x y : real} (hx : x > 0) (hy : y > 0) : log (x * y) = log x + log y := -by finish using [log_exp_eq, exp_log_eq, exp_add] +by rw [←log_exp_eq (log x + log y), exp_add, exp_log_eq hx, exp_log_eq hy] From 0f9edf98f8cd8a99a6694f19e0b3f47e7e12c165 Mon Sep 17 00:00:00 2001 From: Floris van Doorn Date: Thu, 21 Apr 2022 12:10:04 +0000 Subject: [PATCH 129/373] =?UTF-8?q?feat(data/set/[basic|prod]):=20make=20`?= =?UTF-8?q?=C3=97=CB=A2`=20bind=20more=20strongly,=20and=20define=20`mem.o?= =?UTF-8?q?ut`=20(#13422)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * This means that `×ˢ` does not behave the same as `∪` or `∩` around `⁻¹'` or `''`, but I think that is fine. * From the sphere eversion project --- src/data/set/basic.lean | 11 ++++- src/data/set/pointwise.lean | 8 +-- src/data/set/prod.lean | 49 ++++++++++--------- src/logic/equiv/fin.lean | 4 +- src/logic/equiv/set.lean | 13 +++-- src/measure_theory/constructions/prod.lean | 2 +- src/measure_theory/integral/lebesgue.lean | 2 +- src/measure_theory/measurable_space.lean | 4 +- src/order/filter/basic.lean | 2 +- .../uniform_space/uniform_embedding.lean | 4 +- 10 files changed, 53 insertions(+), 46 deletions(-) diff --git a/src/data/set/basic.lean b/src/data/set/basic.lean index 4cad16996589f..43def1ccb9328 100644 --- a/src/data/set/basic.lean +++ b/src/data/set/basic.lean @@ -185,9 +185,16 @@ by tauto /-! ### Lemmas about `mem` and `set_of` -/ -@[simp] theorem mem_set_of_eq {a : α} {p : α → Prop} : a ∈ {a | p a} = p a := rfl +@[simp] theorem mem_set_of_eq {a : α} {p : α → Prop} : a ∈ {x | p x} = p a := rfl -theorem nmem_set_of_eq {a : α} {P : α → Prop} : a ∉ {a : α | P a} = ¬ P a := rfl +lemma mem_set_of {a : α} {p : α → Prop} : a ∈ {x | p x} ↔ p a := iff.rfl + +/-- If `h : a ∈ {x | p x}` then `h.out : p x`. These are definitionally equal, but this can +nevertheless be useful for various reasons, e.g. to apply further projection notation or in an +argument to `simp`. -/ +lemma has_mem.mem.out {p : α → Prop} {a : α} (h : a ∈ {x | p x}) : p a := h + +theorem nmem_set_of_eq {a : α} {p : α → Prop} : a ∉ {x | p x} = ¬ p a := rfl @[simp] theorem set_of_mem_eq {s : set α} : {x | x ∈ s} = s := rfl diff --git a/src/data/set/pointwise.lean b/src/data/set/pointwise.lean index bdee911b76418..27cadc02865a8 100644 --- a/src/data/set/pointwise.lean +++ b/src/data/set/pointwise.lean @@ -122,7 +122,7 @@ lemma mul_mem_mul (ha : a ∈ s) (hb : b ∈ t) : a * b ∈ s * t := mem_image2_ lemma mul_subset_mul (h₁ : s₁ ⊆ t₁) (h₂ : s₂ ⊆ t₂) : s₁ * s₂ ⊆ t₁ * t₂ := image2_subset h₁ h₂ @[to_additive add_image_prod] -lemma image_mul_prod : (λ x : α × α, x.fst * x.snd) '' (s ×ˢ t) = s * t := image_prod _ +lemma image_mul_prod : (λ x : α × α, x.fst * x.snd) '' s ×ˢ t = s * t := image_prod _ @[simp, to_additive] lemma empty_mul : ∅ * s = ∅ := image2_empty_left @[simp, to_additive] lemma mul_empty : s * ∅ = ∅ := image2_empty_right @@ -551,7 +551,7 @@ lemma div_mem_div (ha : a ∈ s) (hb : b ∈ t) : a / b ∈ s / t := mem_image2_ lemma div_subset_div (h₁ : s₁ ⊆ t₁) (h₂ : s₂ ⊆ t₂) : s₁ / s₂ ⊆ t₁ / t₂ := image2_subset h₁ h₂ @[to_additive add_image_prod] -lemma image_div_prod : (λ x : α × α, x.fst / x.snd) '' (s ×ˢ t) = s / t := image_prod _ +lemma image_div_prod : (λ x : α × α, x.fst / x.snd) '' s ×ˢ t = s / t := image_prod _ @[simp, to_additive] lemma empty_div : ∅ / s = ∅ := image2_empty_left @[simp, to_additive] lemma div_empty : s / ∅ = ∅ := image2_empty_right @@ -683,7 +683,7 @@ variables {ι : Sort*} {κ : ι → Sort*} [has_scalar α β] {s s₁ s₂ : set lemma image2_smul : image2 has_scalar.smul s t = s • t := rfl @[to_additive add_image_prod] -lemma image_smul_prod : (λ x : α × β, x.fst • x.snd) '' (s ×ˢ t) = s • t := image_prod _ +lemma image_smul_prod : (λ x : α × β, x.fst • x.snd) '' s ×ˢ t = s • t := image_prod _ @[to_additive] lemma mem_smul : b ∈ s • t ↔ ∃ x y, x ∈ s ∧ y ∈ t ∧ x • y = b := iff.rfl @@ -912,7 +912,7 @@ instance has_vsub : has_vsub (set α) (set β) := ⟨image2 (-ᵥ)⟩ @[simp] lemma image2_vsub : (image2 has_vsub.vsub s t : set α) = s -ᵥ t := rfl -lemma image_vsub_prod : (λ x : β × β, x.fst -ᵥ x.snd) '' (s ×ˢ t) = s -ᵥ t := image_prod _ +lemma image_vsub_prod : (λ x : β × β, x.fst -ᵥ x.snd) '' s ×ˢ t = s -ᵥ t := image_prod _ lemma mem_vsub : a ∈ s -ᵥ t ↔ ∃ x y, x ∈ s ∧ y ∈ t ∧ x -ᵥ y = a := iff.rfl diff --git a/src/data/set/prod.lean b/src/data/set/prod.lean index de2e0be25a530..6175c014cbcf1 100644 --- a/src/data/set/prod.lean +++ b/src/data/set/prod.lean @@ -25,7 +25,8 @@ open function class has_set_prod (α β : Type*) (γ : out_param Type*) := (prod : α → β → γ) -infixr ` ×ˢ `:72 := has_set_prod.prod +/- This notation binds more strongly than (pre)images, unions and intersections. -/ +infixr ` ×ˢ `:82 := has_set_prod.prod namespace set @@ -52,7 +53,7 @@ lemma mk_mem_prod (ha : a ∈ s) (hb : b ∈ t) : (a, b) ∈ s ×ˢ t := ⟨ha, lemma prod_mono (hs : s₁ ⊆ s₂) (ht : t₁ ⊆ t₂) : s₁ ×ˢ t₁ ⊆ s₂ ×ˢ t₂ := λ x ⟨h₁, h₂⟩, ⟨hs h₁, ht h₂⟩ -lemma prod_subset_iff {P : set (α × β)} : (s ×ˢ t ⊆ P) ↔ ∀ (x ∈ s) (y ∈ t), (x, y) ∈ P := +lemma prod_subset_iff {P : set (α × β)} : s ×ˢ t ⊆ P ↔ ∀ (x ∈ s) (y ∈ t), (x, y) ∈ P := ⟨λ h _ hx _ hy, h (mk_mem_prod hx hy), λ h ⟨_, _⟩ hp, h _ hp.1 _ hp.2⟩ lemma forall_prod_set {p : α × β → Prop} : (∀ x ∈ s ×ˢ t, p x) ↔ ∀ (x ∈ s) (y ∈ t), p (x, y) := @@ -95,57 +96,57 @@ lemma prod_insert : s ×ˢ (insert b t) = ((λa, (a, b)) '' s) ∪ s ×ˢ t := by { ext ⟨x, y⟩, simp [image, iff_def, or_imp_distrib, imp.swap] {contextual := tt} } lemma prod_preimage_eq {f : γ → α} {g : δ → β} : - (f ⁻¹' s) ×ˢ (g ⁻¹' t) = (λ p : γ × δ, (f p.1, g p.2)) ⁻¹' (s ×ˢ t) := rfl + (f ⁻¹' s) ×ˢ (g ⁻¹' t) = (λ p : γ × δ, (f p.1, g p.2)) ⁻¹' s ×ˢ t := rfl lemma prod_preimage_left {f : γ → α} : - (f ⁻¹' s) ×ˢ t = (λ p : γ × β, (f p.1, p.2)) ⁻¹' (s ×ˢ t) := rfl + (f ⁻¹' s) ×ˢ t = (λ p : γ × β, (f p.1, p.2)) ⁻¹' s ×ˢ t := rfl lemma prod_preimage_right {g : δ → β} : - s ×ˢ (g ⁻¹' t) = (λ p : α × δ, (p.1, g p.2)) ⁻¹' (s ×ˢ t) := rfl + s ×ˢ (g ⁻¹' t) = (λ p : α × δ, (p.1, g p.2)) ⁻¹' s ×ˢ t := rfl lemma preimage_prod_map_prod (f : α → β) (g : γ → δ) (s : set β) (t : set δ) : - prod.map f g ⁻¹' (s ×ˢ t) = (f ⁻¹' s) ×ˢ (g ⁻¹' t) := + prod.map f g ⁻¹' s ×ˢ t = (f ⁻¹' s) ×ˢ (g ⁻¹' t) := rfl lemma mk_preimage_prod (f : γ → α) (g : γ → β) : - (λ x, (f x, g x)) ⁻¹' (s ×ˢ t) = f ⁻¹' s ∩ g ⁻¹' t := rfl + (λ x, (f x, g x)) ⁻¹' s ×ˢ t = f ⁻¹' s ∩ g ⁻¹' t := rfl -@[simp] lemma mk_preimage_prod_left (hb : b ∈ t) : (λ a, (a, b)) ⁻¹' (s ×ˢ t) = s := +@[simp] lemma mk_preimage_prod_left (hb : b ∈ t) : (λ a, (a, b)) ⁻¹' s ×ˢ t = s := by { ext a, simp [hb] } -@[simp] lemma mk_preimage_prod_right (ha : a ∈ s) : prod.mk a ⁻¹' (s ×ˢ t) = t := +@[simp] lemma mk_preimage_prod_right (ha : a ∈ s) : prod.mk a ⁻¹' s ×ˢ t = t := by { ext b, simp [ha] } -@[simp] lemma mk_preimage_prod_left_eq_empty (hb : b ∉ t) : (λ a, (a, b)) ⁻¹' (s ×ˢ t) = ∅ := +@[simp] lemma mk_preimage_prod_left_eq_empty (hb : b ∉ t) : (λ a, (a, b)) ⁻¹' s ×ˢ t = ∅ := by { ext a, simp [hb] } -@[simp] lemma mk_preimage_prod_right_eq_empty (ha : a ∉ s) : prod.mk a ⁻¹' (s ×ˢ t) = ∅ := +@[simp] lemma mk_preimage_prod_right_eq_empty (ha : a ∉ s) : prod.mk a ⁻¹' s ×ˢ t = ∅ := by { ext b, simp [ha] } lemma mk_preimage_prod_left_eq_if [decidable_pred (∈ t)] : - (λ a, (a, b)) ⁻¹' (s ×ˢ t) = if b ∈ t then s else ∅ := + (λ a, (a, b)) ⁻¹' s ×ˢ t = if b ∈ t then s else ∅ := by split_ifs; simp [h] lemma mk_preimage_prod_right_eq_if [decidable_pred (∈ s)] : - prod.mk a ⁻¹' (s ×ˢ t) = if a ∈ s then t else ∅ := + prod.mk a ⁻¹' s ×ˢ t = if a ∈ s then t else ∅ := by split_ifs; simp [h] lemma mk_preimage_prod_left_fn_eq_if [decidable_pred (∈ t)] (f : γ → α) : - (λ a, (f a, b)) ⁻¹' (s ×ˢ t) = if b ∈ t then f ⁻¹' s else ∅ := + (λ a, (f a, b)) ⁻¹' s ×ˢ t = if b ∈ t then f ⁻¹' s else ∅ := by rw [← mk_preimage_prod_left_eq_if, prod_preimage_left, preimage_preimage] lemma mk_preimage_prod_right_fn_eq_if [decidable_pred (∈ s)] (g : δ → β) : - (λ b, (a, g b)) ⁻¹' (s ×ˢ t) = if a ∈ s then g ⁻¹' t else ∅ := + (λ b, (a, g b)) ⁻¹' s ×ˢ t = if a ∈ s then g ⁻¹' t else ∅ := by rw [← mk_preimage_prod_right_eq_if, prod_preimage_right, preimage_preimage] -lemma preimage_swap_prod {s : set α} {t : set β} : prod.swap ⁻¹' (t ×ˢ s) = s ×ˢ t := +lemma preimage_swap_prod {s : set α} {t : set β} : prod.swap ⁻¹' t ×ˢ s = s ×ˢ t := by { ext ⟨x, y⟩, simp [and_comm] } -lemma image_swap_prod : prod.swap '' (t ×ˢ s) = s ×ˢ t := +lemma image_swap_prod : prod.swap '' t ×ˢ s = s ×ˢ t := by rw [image_swap_eq_preimage_swap, preimage_swap_prod] lemma prod_image_image_eq {m₁ : α → γ} {m₂ : β → δ} : - (m₁ '' s) ×ˢ (m₂ '' t) = image (λ p : α × β, (m₁ p.1, m₂ p.2)) (s ×ˢ t) := + (m₁ '' s) ×ˢ (m₂ '' t) = (λ p : α × β, (m₁ p.1, m₂ p.2)) '' s ×ˢ t := ext $ by simp [-exists_and_distrib_right, exists_and_distrib_right.symm, and.left_comm, and.assoc, and.comm] @@ -179,7 +180,7 @@ lemma nonempty.snd : (s ×ˢ t : set _).nonempty → t.nonempty := λ ⟨x, hx lemma prod_nonempty_iff : (s ×ˢ t : set _).nonempty ↔ s.nonempty ∧ t.nonempty := ⟨λ h, ⟨h.fst, h.snd⟩, λ h, h.1.prod h.2⟩ -lemma prod_eq_empty_iff : s ×ˢ t = ∅ ↔ (s = ∅ ∨ t = ∅) := +lemma prod_eq_empty_iff : s ×ˢ t = ∅ ↔ s = ∅ ∨ t = ∅ := by simp only [not_nonempty_iff_eq_empty.symm, prod_nonempty_iff, not_and_distrib] lemma prod_sub_preimage_iff {W : set γ} {f : α × β → γ} : @@ -192,22 +193,22 @@ by { rintro _ ⟨a, ha, rfl⟩, exact ⟨ha, hb⟩ } lemma image_prod_mk_subset_prod_right (ha : a ∈ s) : prod.mk a '' t ⊆ s ×ˢ t := by { rintro _ ⟨b, hb, rfl⟩, exact ⟨ha, hb⟩ } -lemma fst_image_prod_subset (s : set α) (t : set β) : prod.fst '' (s ×ˢ t) ⊆ s := +lemma fst_image_prod_subset (s : set α) (t : set β) : prod.fst '' s ×ˢ t ⊆ s := λ _ h, let ⟨_, ⟨h₂, _⟩, h₁⟩ := (set.mem_image _ _ _).1 h in h₁ ▸ h₂ lemma prod_subset_preimage_fst (s : set α) (t : set β) : s ×ˢ t ⊆ prod.fst ⁻¹' s := image_subset_iff.1 (fst_image_prod_subset s t) -lemma fst_image_prod (s : set β) {t : set α} (ht : t.nonempty) : prod.fst '' (s ×ˢ t) = s := +lemma fst_image_prod (s : set β) {t : set α} (ht : t.nonempty) : prod.fst '' s ×ˢ t = s := (fst_image_prod_subset _ _).antisymm $ λ y hy, let ⟨x, hx⟩ := ht in ⟨(y, x), ⟨hy, hx⟩, rfl⟩ -lemma snd_image_prod_subset (s : set α) (t : set β) : prod.snd '' (s ×ˢ t) ⊆ t := +lemma snd_image_prod_subset (s : set α) (t : set β) : prod.snd '' s ×ˢ t ⊆ t := λ _ h, let ⟨_, ⟨_, h₂⟩, h₁⟩ := (set.mem_image _ _ _).1 h in h₁ ▸ h₂ lemma prod_subset_preimage_snd (s : set α) (t : set β) : s ×ˢ t ⊆ prod.snd ⁻¹' t := image_subset_iff.1 (snd_image_prod_subset s t) -lemma snd_image_prod {s : set α} (hs : s.nonempty) (t : set β) : prod.snd '' (s ×ˢ t) = t := +lemma snd_image_prod {s : set α} (hs : s.nonempty) (t : set β) : prod.snd '' s ×ˢ t = t := (snd_image_prod_subset _ _).antisymm $ λ y y_in, let ⟨x, x_in⟩ := hs in ⟨(x, y), ⟨x_in, y_in⟩, rfl⟩ lemma prod_diff_prod : s ×ˢ t \ s₁ ×ˢ t₁ = s ×ˢ (t \ t₁) ∪ (s \ s₁) ×ˢ t := @@ -241,7 +242,7 @@ begin refl }, end -@[simp] lemma image_prod (f : α → β → γ) : (λ x : α × β, f x.1 x.2) '' (s ×ˢ t) = image2 f s t := +@[simp] lemma image_prod (f : α → β → γ) : (λ x : α × β, f x.1 x.2) '' s ×ˢ t = image2 f s t := set.ext $ λ a, ⟨ by { rintro ⟨_, _, rfl⟩, exact ⟨_, _, (mem_prod.mp ‹_›).1, (mem_prod.mp ‹_›).2, rfl⟩ }, by { rintro ⟨_, _, _, _, rfl⟩, exact ⟨(_, _), mem_prod.mpr ⟨‹_›, ‹_›⟩, rfl⟩ }⟩ diff --git a/src/logic/equiv/fin.lean b/src/logic/equiv/fin.lean index 4c3f2ccf2db8d..eae5b663119c0 100644 --- a/src/logic/equiv/fin.lean +++ b/src/logic/equiv/fin.lean @@ -51,7 +51,7 @@ non-dependent version and `prod_equiv_pi_fin_two` for a version with inputs `α right_inv := λ ⟨x, y⟩, rfl } lemma fin.preimage_apply_01_prod {α : fin 2 → Type u} (s : set (α 0)) (t : set (α 1)) : - (λ f : Π i, α i, (f 0, f 1)) ⁻¹' (s ×ˢ t) = + (λ f : Π i, α i, (f 0, f 1)) ⁻¹' s ×ˢ t = set.pi set.univ (fin.cons s $ fin.cons t fin.elim0) := begin ext f, @@ -60,7 +60,7 @@ begin end lemma fin.preimage_apply_01_prod' {α : Type u} (s t : set α) : - (λ f : fin 2 → α, (f 0, f 1)) ⁻¹' (s ×ˢ t) = set.pi set.univ ![s, t] := + (λ f : fin 2 → α, (f 0, f 1)) ⁻¹' s ×ˢ t = set.pi set.univ ![s, t] := fin.preimage_apply_01_prod s t /-- A product space `α × β` is equivalent to the space `Π i : fin 2, γ i`, where diff --git a/src/logic/equiv/set.lean b/src/logic/equiv/set.lean index fe94870a70fc1..0ac322429b1f3 100644 --- a/src/logic/equiv/set.lean +++ b/src/logic/equiv/set.lean @@ -101,32 +101,31 @@ lemma eq_preimage_iff_image_eq {α β} (e : α ≃ β) (s t) : s = e ⁻¹' t set.eq_preimage_iff_image_eq e.bijective @[simp] lemma prod_comm_preimage {α β} {s : set α} {t : set β} : - equiv.prod_comm α β ⁻¹' (t ×ˢ s) = (s ×ˢ t) := + equiv.prod_comm α β ⁻¹' t ×ˢ s = s ×ˢ t := set.preimage_swap_prod -lemma prod_comm_image {α β} {s : set α} {t : set β} : - equiv.prod_comm α β '' (s ×ˢ t) = (t ×ˢ s) := +lemma prod_comm_image {α β} {s : set α} {t : set β} : equiv.prod_comm α β '' s ×ˢ t = t ×ˢ s := set.image_swap_prod @[simp] lemma prod_assoc_preimage {α β γ} {s : set α} {t : set β} {u : set γ} : - equiv.prod_assoc α β γ ⁻¹' (s ×ˢ (t ×ˢ u)) = (s ×ˢ t) ×ˢ u := + equiv.prod_assoc α β γ ⁻¹' s ×ˢ (t ×ˢ u) = (s ×ˢ t) ×ˢ u := by { ext, simp [and_assoc] } @[simp] lemma prod_assoc_symm_preimage {α β γ} {s : set α} {t : set β} {u : set γ} : - (equiv.prod_assoc α β γ).symm ⁻¹' ((s ×ˢ t) ×ˢ u) = s ×ˢ (t ×ˢ u) := + (equiv.prod_assoc α β γ).symm ⁻¹' (s ×ˢ t) ×ˢ u = s ×ˢ (t ×ˢ u) := by { ext, simp [and_assoc] } -- `@[simp]` doesn't like these lemmas, as it uses `set.image_congr'` to turn `equiv.prod_assoc` -- into a lambda expression and then unfold it. lemma prod_assoc_image {α β γ} {s : set α} {t : set β} {u : set γ} : - equiv.prod_assoc α β γ '' ((s ×ˢ t) ×ˢ u) = s ×ˢ (t ×ˢ u) := + equiv.prod_assoc α β γ '' (s ×ˢ t) ×ˢ u = s ×ˢ (t ×ˢ u) := by simpa only [equiv.image_eq_preimage] using prod_assoc_symm_preimage lemma prod_assoc_symm_image {α β γ} {s : set α} {t : set β} {u : set γ} : - (equiv.prod_assoc α β γ).symm '' (s ×ˢ (t ×ˢ u)) = (s ×ˢ t) ×ˢ u := + (equiv.prod_assoc α β γ).symm '' s ×ˢ (t ×ˢ u) = (s ×ˢ t) ×ˢ u := by simpa only [equiv.image_eq_preimage] using prod_assoc_preimage /-- A set `s` in `α × β` is equivalent to the sigma-type `Σ x, {y | (x, y) ∈ s}`. -/ diff --git a/src/measure_theory/constructions/prod.lean b/src/measure_theory/constructions/prod.lean index 950eec94f87b2..c9ff36da8ea06 100644 --- a/src/measure_theory/constructions/prod.lean +++ b/src/measure_theory/constructions/prod.lean @@ -583,7 +583,7 @@ begin refine ⟨this, (prod_eq $ λ s t hs ht, _).symm⟩, rw [map_apply this (hs.prod ht)], refine (prod_apply (this $ hs.prod ht)).trans _, - have : ∀ᵐ x ∂μa, μc ((λ y, (f x, g x y)) ⁻¹' (s ×ˢ t)) = indicator (f ⁻¹' s) (λ y, μd t) x, + have : ∀ᵐ x ∂μa, μc ((λ y, (f x, g x y)) ⁻¹' s ×ˢ t) = indicator (f ⁻¹' s) (λ y, μd t) x, { refine hg.mono (λ x hx, _), unfreezingI { subst hx }, simp only [mk_preimage_prod_right_fn_eq_if, indicator_apply, mem_preimage], split_ifs, diff --git a/src/measure_theory/integral/lebesgue.lean b/src/measure_theory/integral/lebesgue.lean index b190341a4868e..5d76c691b60f5 100644 --- a/src/measure_theory/integral/lebesgue.lean +++ b/src/measure_theory/integral/lebesgue.lean @@ -313,7 +313,7 @@ def pair (f : α →ₛ β) (g : α →ₛ γ) : α →ₛ (β × γ) := (f.map @[simp] lemma pair_apply (f : α →ₛ β) (g : α →ₛ γ) (a) : pair f g a = (f a, g a) := rfl lemma pair_preimage (f : α →ₛ β) (g : α →ₛ γ) (s : set β) (t : set γ) : - (pair f g) ⁻¹' (s ×ˢ t) = (f ⁻¹' s) ∩ (g ⁻¹' t) := rfl + pair f g ⁻¹' s ×ˢ t = (f ⁻¹' s) ∩ (g ⁻¹' t) := rfl /- A special form of `pair_preimage` -/ lemma pair_preimage_singleton (f : α →ₛ β) (g : α →ₛ γ) (b : β) (c : γ) : diff --git a/src/measure_theory/measurable_space.lean b/src/measure_theory/measurable_space.lean index db26adea3cbf7..c8d506b485f73 100644 --- a/src/measure_theory/measurable_space.lean +++ b/src/measure_theory/measurable_space.lean @@ -561,8 +561,8 @@ lemma measurable_set_prod_of_nonempty {s : set α} {t : set β} (h : (s ×ˢ t : begin rcases h with ⟨⟨x, y⟩, hx, hy⟩, refine ⟨λ hst, _, λ h, h.1.prod h.2⟩, - have : measurable_set ((λ x, (x, y)) ⁻¹' (s ×ˢ t)) := measurable_id.prod_mk measurable_const hst, - have : measurable_set (prod.mk x ⁻¹' (s ×ˢ t)) := measurable_const.prod_mk measurable_id hst, + have : measurable_set ((λ x, (x, y)) ⁻¹' s ×ˢ t) := measurable_id.prod_mk measurable_const hst, + have : measurable_set (prod.mk x ⁻¹' s ×ˢ t) := measurable_const.prod_mk measurable_id hst, simp * at * end diff --git a/src/order/filter/basic.lean b/src/order/filter/basic.lean index 9dfbbe9432f8c..be1a8c560c35d 100644 --- a/src/order/filter/basic.lean +++ b/src/order/filter/basic.lean @@ -2620,7 +2620,7 @@ le_antisymm (λ s hs, let ⟨s₁, hs₁, s₂, hs₂, h⟩ := mem_prod_iff.mp hs in filter.sets_of_superset _ (prod_mem_prod (image_mem_map hs₁) (image_mem_map hs₂)) $ - calc m₁ '' s₁ ×ˢ m₂ '' s₂ = (λ p : α₁×α₂, (m₁ p.1, m₂ p.2)) '' (s₁ ×ˢ s₂) : + calc (m₁ '' s₁) ×ˢ (m₂ '' s₂) = (λ p : α₁×α₂, (m₁ p.1, m₂ p.2)) '' s₁ ×ˢ s₂ : set.prod_image_image_eq ... ⊆ _ : by rwa [image_subset_iff]) ((tendsto.comp le_rfl tendsto_fst).prod_mk (tendsto.comp le_rfl tendsto_snd)) diff --git a/src/topology/uniform_space/uniform_embedding.lean b/src/topology/uniform_space/uniform_embedding.lean index 8247432bb94ee..52b0efe157caf 100644 --- a/src/topology/uniform_space/uniform_embedding.lean +++ b/src/topology/uniform_space/uniform_embedding.lean @@ -512,9 +512,9 @@ show preimage (λp:(α×α), (ψ p.1, ψ p.2)) d ∈ 𝓤 α, from calc _ ⊆ preimage (λp:(β×β), (e p.1, e p.2)) (interior t) : preimage_mono hm ... ⊆ preimage (λp:(β×β), (e p.1, e p.2)) t : preimage_mono interior_subset ... ⊆ preimage (λp:(β×β), (f p.1, f p.2)) s : ts, - have f '' (e ⁻¹' m₁) ×ˢ f '' (e ⁻¹' m₂) ⊆ s, + have (f '' (e ⁻¹' m₁)) ×ˢ (f '' (e ⁻¹' m₂)) ⊆ s, from calc (f '' (e ⁻¹' m₁)) ×ˢ (f '' (e ⁻¹' m₂)) = - (λp:(β×β), (f p.1, f p.2)) '' (e ⁻¹' m₁ ×ˢ e ⁻¹' m₂) : prod_image_image_eq + (λp:(β×β), (f p.1, f p.2)) '' ((e ⁻¹' m₁) ×ˢ (e ⁻¹' m₂)) : prod_image_image_eq ... ⊆ (λp:(β×β), (f p.1, f p.2)) '' ((λp:(β×β), (f p.1, f p.2)) ⁻¹' s) : monotone_image this ... ⊆ s : image_preimage_subset _ _, have (a, b) ∈ s, from @this (a, b) ⟨ha₁, hb₁⟩, From e8b581a70d9ab0873052e2d4e48ca1e1c6659753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Thu, 21 Apr 2022 15:19:56 +0000 Subject: [PATCH 130/373] feat(order/countable_dense_linear_order): Relax conditions of `embedding_from_countable_to_dense` (#12928) We prove that any countable order embeds in any nontrivial dense order. We also slightly golf the rest of the file. --- src/order/countable_dense_linear_order.lean | 80 ++++++++++----------- 1 file changed, 37 insertions(+), 43 deletions(-) diff --git a/src/order/countable_dense_linear_order.lean b/src/order/countable_dense_linear_order.lean index c10246e06fca2..969aeef14f134 100644 --- a/src/order/countable_dense_linear_order.lean +++ b/src/order/countable_dense_linear_order.lean @@ -10,14 +10,13 @@ import order.ideal ## Results -Suppose `α β` are linear orders, with `α` countable and `β` dense, nonempty, without endpoints. -Then there is an order embedding `α ↪ β`. If in addition `α` is dense, nonempty, without -endpoints and `β` is countable, then we can upgrade this to an order isomorphism `α ≃ β`. +Suppose `α β` are orders, with `α` countable and `β` dense, nontrivial. Then there is an order +embedding `α ↪ β`. If in addition `α` is dense, nonempty, without endpoints and `β` is countable, +without endpoints, then we can upgrade this to an order isomorphism `α ≃ β`. -The idea for both results is to consider "partial isomorphisms", which -identify a finite subset of `α` with a finite subset of `β`, and prove that -for any such partial isomorphism `f` and `a : α`, we can extend `f` to -include `a` in its domain. +The idea for both results is to consider "partial isomorphisms", which identify a finite subset of +`α` with a finite subset of `β`, and prove that for any such partial isomorphism `f` and `a : α`, we +can extend `f` to include `a` in its domain. ## References @@ -26,7 +25,6 @@ https://en.wikipedia.org/wiki/Back-and-forth_method ## Tags back and forth, dense, countable, order - -/ noncomputable theory @@ -87,7 +85,7 @@ lemma exists_across [densely_ordered β] [no_min_order β] [no_max_order β] [no ∃ b : β, ∀ (p ∈ f.val), cmp (prod.fst p) a = cmp (prod.snd p) b := begin by_cases h : ∃ b, (a, b) ∈ f.val, - { cases h with b hb, exact ⟨b, λ p hp, f.property _ hp _ hb⟩, }, + { cases h with b hb, exact ⟨b, λ p hp, f.prop _ hp _ hb⟩, }, have : ∀ (x ∈ (f.val.filter (λ (p : α × β), p.fst < a)).image prod.snd) (y ∈ (f.val.filter (λ (p : α × β), a < p.fst)).image prod.snd), x < y, @@ -96,7 +94,7 @@ begin rcases hx with ⟨p, hp1, rfl⟩, rcases hy with ⟨q, hq1, rfl⟩, rw finset.mem_filter at hp1 hq1, - rw ←lt_iff_lt_of_cmp_eq_cmp (f.property _ hp1.1 _ hq1.1), + rw ←lt_iff_lt_of_cmp_eq_cmp (f.prop _ hp1.1 _ hq1.1), exact lt_trans hp1.right hq1.right, }, cases exists_between_finsets _ _ this with b hb, use b, @@ -125,19 +123,17 @@ variable (β) def defined_at_left [densely_ordered β] [no_min_order β] [no_max_order β] [nonempty β] (a : α) : cofinal (partial_iso α β) := { carrier := λ f, ∃ b : β, (a, b) ∈ f.val, - mem_gt := - begin - intro f, + mem_gt := λ f, begin cases exists_across f a with b a_b, - refine ⟨⟨insert (a, b) f.val, _⟩, ⟨b, finset.mem_insert_self _ _⟩, finset.subset_insert _ _⟩, - intros p hp q hq, + refine ⟨⟨insert (a, b) f.val, λ p hp q hq, _⟩, ⟨b, finset.mem_insert_self _ _⟩, + finset.subset_insert _ _⟩, rw finset.mem_insert at hp hq, rcases hp with rfl | pf; rcases hq with rfl | qf, - { simp }, + { simp only [cmp_self_eq_eq] }, { rw cmp_eq_cmp_symm, exact a_b _ qf }, { exact a_b _ pf }, - { exact f.property _ pf _ qf }, + { exact f.prop _ pf _ qf }, end } variables (α) {β} @@ -146,14 +142,10 @@ variables (α) {β} def defined_at_right [densely_ordered α] [no_min_order α] [no_max_order α] [nonempty α] (b : β) : cofinal (partial_iso α β) := { carrier := λ f, ∃ a, (a, b) ∈ f.val, - mem_gt := - begin - intro f, + mem_gt := λ f, begin rcases (defined_at_left α b).mem_gt f.comm with ⟨f', ⟨a, ha⟩, hl⟩, - use f'.comm, - split, - { use a, - change (a, b) ∈ f'.val.image _, + refine ⟨f'.comm, ⟨a, _⟩, _⟩, + { change (a, b) ∈ f'.val.image _, rwa [←finset.mem_coe, finset.coe_image, equiv.image_eq_preimage] }, { change _ ⊆ f'.val.image _, rw [←finset.coe_subset, finset.coe_image, ← equiv.subset_image], @@ -182,38 +174,40 @@ open partial_iso variables (α β) -/-- Any countable linear order embeds in any nonempty dense linear order without endpoints. -/ -def embedding_from_countable_to_dense - [encodable α] [densely_ordered β] [no_min_order β] [no_max_order β] [nonempty β] : - α ↪o β := -let our_ideal : ideal (partial_iso α β) := ideal_of_cofinals default $ defined_at_left β in -let F := λ a, fun_of_ideal a our_ideal (cofinal_meets_ideal_of_cofinals _ _ a) in -order_embedding.of_strict_mono (λ a, (F a).val) +/-- Any countable order embeds in any nontrivial dense linear order. -/ +theorem embedding_from_countable_to_dense [encodable α] [densely_ordered β] [nontrivial β] : + nonempty (α ↪o β) := begin - intros a₁ a₂, - rcases (F a₁).property with ⟨f, hf, ha₁⟩, - rcases (F a₂).property with ⟨g, hg, ha₂⟩, + rcases exists_pair_lt β with ⟨x, y, hxy⟩, + cases exists_between hxy with a ha, + haveI : nonempty (set.Ioo x y) := ⟨⟨a, ha⟩⟩, + let our_ideal : ideal (partial_iso α _) := + ideal_of_cofinals default (defined_at_left (set.Ioo x y)), + let F := λ a, fun_of_ideal a our_ideal (cofinal_meets_ideal_of_cofinals _ _ a), + refine ⟨rel_embedding.trans (order_embedding.of_strict_mono (λ a, (F a).val) (λ a₁ a₂, _)) + (order_embedding.subtype _)⟩, + rcases (F a₁).prop with ⟨f, hf, ha₁⟩, + rcases (F a₂).prop with ⟨g, hg, ha₂⟩, rcases our_ideal.directed _ hf _ hg with ⟨m, hm, fm, gm⟩, - exact (lt_iff_lt_of_cmp_eq_cmp $ m.property (a₁, _) (fm ha₁) (a₂, _) (gm ha₂)).mp + exact (lt_iff_lt_of_cmp_eq_cmp $ m.prop (a₁, _) (fm ha₁) (a₂, _) (gm ha₂)).mp end /-- Any two countable dense, nonempty linear orders without endpoints are order isomorphic. -/ -def iso_of_countable_dense +theorem iso_of_countable_dense [encodable α] [densely_ordered α] [no_min_order α] [no_max_order α] [nonempty α] [encodable β] [densely_ordered β] [no_min_order β] [no_max_order β] [nonempty β] : - α ≃o β := + nonempty (α ≃o β) := let to_cofinal : α ⊕ β → cofinal (partial_iso α β) := λ p, sum.rec_on p (defined_at_left β) (defined_at_right α) in let our_ideal : ideal (partial_iso α β) := ideal_of_cofinals default to_cofinal in let F := λ a, fun_of_ideal a our_ideal (cofinal_meets_ideal_of_cofinals _ to_cofinal (sum.inl a)) in let G := λ b, inv_of_ideal b our_ideal (cofinal_meets_ideal_of_cofinals _ to_cofinal (sum.inr b)) in -order_iso.of_cmp_eq_cmp (λ a, (F a).val) (λ b, (G b).val) +⟨order_iso.of_cmp_eq_cmp (λ a, (F a).val) (λ b, (G b).val) $ λ a b, begin - intros a b, - rcases (F a).property with ⟨f, hf, ha⟩, - rcases (G b).property with ⟨g, hg, hb⟩, + rcases (F a).prop with ⟨f, hf, ha⟩, + rcases (G b).prop with ⟨g, hg, hb⟩, rcases our_ideal.directed _ hf _ hg with ⟨m, hm, fm, gm⟩, - exact m.property (a, _) (fm ha) (_, b) (gm hb) -end + exact m.prop (a, _) (fm ha) (_, b) (gm hb) +end⟩ end order From 79abf670d5f946912964c232736e97a761f29ebb Mon Sep 17 00:00:00 2001 From: Rob Lewis Date: Thu, 21 Apr 2022 15:19:58 +0000 Subject: [PATCH 131/373] fix(tactic/apply_rules): separate single rules and attribute names in syntax (#13227) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @hrmacbeth reported an issue with `apply_rules` [on Zulip](https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/monotonicity.2Eattr.20with.20apply_rules). It boiled down to `apply_rules` not properly distinguishing between attribute names, the names of `user_attribute` declarations, and the names of normal declarations. There's an example of using `apply_rules` with attributes in the docs: ```lean @[user_attribute] meta def mono_rules : user_attribute := { name := `mono_rules, descr := "lemmas usable to prove monotonicity" } local attribute [mono_rules] add_le_add example (a b c d : α) : a + b ≤ c + d := begin apply_rules mono_rules, -- takes action end ``` but this only worked by coincidence because the attribute name and the name of the `user_attribute` declaration were the same. With this change, expressions and names of attributes are now separated: the latter are specified after `with`. The call above becomes `apply_rules with mono_rules`. This mirrors the syntax of `simp`. Note that this feature was only used in meta code in mathlib. The example from Zulip (modified for proper syntax) still doesn't work with my change: ```lean import tactic.monotonicity variables {α : Type*} [linear_ordered_add_comm_group α] example (a b c d : α) : a + b ≤ c + d := begin apply_rules with mono, end ``` but it seems to fail because the `mono` rules cause `apply_rules` to loop -- that is, the rule set is getting applied correctly. Co-authored-by: Rob Lewis --- src/measure_theory/tactic.lean | 4 ++-- src/tactic/core.lean | 43 ++++++++++++++-------------------- src/tactic/interactive.lean | 15 ++++++------ src/topology/tactic.lean | 4 ++-- test/apply_rules.lean | 23 ++++++++++++++++-- 5 files changed, 50 insertions(+), 39 deletions(-) diff --git a/src/measure_theory/tactic.lean b/src/measure_theory/tactic.lean index 62aec3e070b0a..9b414c2682dc2 100644 --- a/src/measure_theory/tactic.lean +++ b/src/measure_theory/tactic.lean @@ -131,8 +131,8 @@ meta def measurability_tactics (md : transparency := semireducible) : list (tact >> pure "apply_assumption", goal_is_not_measurable >> intro1 >>= λ ns, pure ("intro " ++ ns.to_string), - apply_rules [``(measurability)] 50 { md := md } - >> pure "apply_rules measurability", + apply_rules [] [``measurability] 50 { md := md } + >> pure "apply_rules with measurability", apply_measurable.comp >> pure "refine measurable.comp _ _", apply_measurable.comp_ae_measurable >> pure "refine measurable.comp_ae_measurable _ _", diff --git a/src/tactic/core.lean b/src/tactic/core.lean index 1a0920131ab8d..0d169db89fc70 100644 --- a/src/tactic/core.lean +++ b/src/tactic/core.lean @@ -977,36 +977,29 @@ meta def apply_list_expr (opt : apply_cfg) : list (tactic expr) → tactic unit | (h::t) := (do e ← h, interactive.concat_tags (apply e opt)) <|> apply_list_expr t /-- -Constructs a list of `tactic expr` given a list of p-expressions, as follows: -- if the p-expression is the name of a theorem, use `i_to_expr_for_apply` on it -- if the p-expression is a user attribute, add all the theorems with this attribute - to the list. - -We need to return a list of `tactic expr`, rather than just `expr`, because these expressions -will be repeatedly applied against goals, and we need to ensure that metavariables don't get stuck. +Given the name of a user attribute, produces a list of `tactic expr`s, each of which is the +application of `i_to_expr_for_apply` to a declaration with that attribute. -/ -meta def build_list_expr_for_apply : list pexpr → tactic (list (tactic expr)) -| [] := return [] -| (h::t) := do - tail ← build_list_expr_for_apply t, - a ← i_to_expr_for_apply h, - (do l ← attribute.get_instances (expr.const_name a), - m ← l.mmap (λ n, _root_.to_pexpr <$> mk_const n), - -- We reverse the list of lemmas marked with an attribute, - -- on the assumption that lemmas proved earlier are more often applicable - -- than lemmas proved later. This is a performance optimization. - build_list_expr_for_apply (m.reverse ++ t)) - <|> return ((i_to_expr_for_apply h) :: tail) - -/--`apply_rules hs n`: apply the list of rules `hs` (given as pexpr) and `assumption` on the -first goal and the resulting subgoals, iteratively, at most `n` times. +meta def resolve_attribute_expr_list (attr_name : name) : tactic (list (tactic expr)) := do + l ← attribute.get_instances attr_name, + list.map i_to_expr_for_apply <$> list.reverse <$> l.mmap resolve_name + + +/--`apply_rules args attrs n`: apply the lists of rules `args` (given as pexprs) and `attrs` (given +as names of attributes) and `the tactic assumption` on the first goal and the resulting subgoals, +iteratively, at most `n` times. Unlike `solve_by_elim`, `apply_rules` does not do any backtracking, and just greedily applies a lemma from the list until it can't. -/ -meta def apply_rules (hs : list pexpr) (n : nat) (opt : apply_cfg) : tactic unit := -do l ← lock_tactic_state $ build_list_expr_for_apply hs, - iterate_at_most_on_subgoals n (assumption <|> apply_list_expr opt l) +meta def apply_rules (args : list pexpr) (attrs : list name) (n : nat) (opt : apply_cfg) : + tactic unit := do + attr_exprs ← lock_tactic_state $ attrs.mfoldl + (λ l n, list.append l <$> resolve_attribute_expr_list n) [], + let args_exprs := args.map i_to_expr_for_apply ++ attr_exprs, +-- `args_exprs` is a list of `tactic expr`, rather than just `expr`, because these expressions will +-- be repeatedly applied against goals, and we need to ensure that metavariables don't get stuck. + iterate_at_most_on_subgoals n (assumption <|> apply_list_expr opt args_exprs) /-- `replace h p` elaborates the pexpr `p`, clears the existing hypothesis named `h` from the local context, and adds a new hypothesis named `h`. The type of this hypothesis is the type of `p`. diff --git a/src/tactic/interactive.lean b/src/tactic/interactive.lean index c278ea7f94029..3fa89e69cb0b5 100644 --- a/src/tactic/interactive.lean +++ b/src/tactic/interactive.lean @@ -506,7 +506,8 @@ add_tactic_doc inherit_description_from := `tactic.interactive.refine_struct } /-- -`apply_rules hs n` applies the list of lemmas `hs` and `assumption` on the +`apply_rules hs with attrs n` applies the list of lemmas `hs` and all lemmas tagged with an +attribute from the list `attrs`, as well as the `assumption` tactic on the first goal and the resulting subgoals, iteratively, at most `n` times. `n` is optional, equal to 50 by default. You can pass an `apply_cfg` option argument as `apply_rules hs n opt`. @@ -514,9 +515,6 @@ You can pass an `apply_cfg` option argument as `apply_rules hs n opt`. which asks `apply_rules` to not unfold `semireducible` definitions (i.e. most) when checking if a lemma matches the goal.) -`hs` can contain user attributes: in this case all theorems with this -attribute are added to the list of rules. - For instance: ```lean @@ -532,13 +530,14 @@ a + c * e + a + c + 0 ≤ b + d * e + b + d + e := -- any of the following lines solve the goal: add_le_add (add_le_add (add_le_add (add_le_add h1 (mul_le_mul_of_nonneg_right h2 h3)) h1 ) h2) h3 by apply_rules [add_le_add, mul_le_mul_of_nonneg_right] -by apply_rules [mono_rules] -by apply_rules mono_rules +by apply_rules with mono_rules +by apply_rules [add_le_add] with mono_rules ``` -/ -meta def apply_rules (hs : parse pexpr_list_or_texpr) (n : nat := 50) (opt : apply_cfg := {}) : +meta def apply_rules (args : parse opt_pexpr_list) (attrs : parse with_ident_list) + (n : nat := 50) (opt : apply_cfg := {}) : tactic unit := -tactic.apply_rules hs n opt +tactic.apply_rules args attrs n opt add_tactic_doc { name := "apply_rules", diff --git a/src/topology/tactic.lean b/src/topology/tactic.lean index fc9e47d7b1357..9339cd4426749 100644 --- a/src/topology/tactic.lean +++ b/src/topology/tactic.lean @@ -68,8 +68,8 @@ meta def apply_continuous.comp : tactic unit := meta def continuity_tactics (md : transparency := reducible) : list (tactic string) := [ intros1 >>= λ ns, pure ("intros " ++ (" ".intercalate (ns.map (λ e, e.to_string)))), - apply_rules [``(continuity)] 50 { md := md } - >> pure "apply_rules continuity", + apply_rules [] [``continuity] 50 { md := md } + >> pure "apply_rules with continuity", apply_continuous.comp >> pure "refine continuous.comp _ _" ] diff --git a/test/apply_rules.lean b/test/apply_rules.lean index 529d3dd7889aa..ca0595b9b710e 100644 --- a/test/apply_rules.lean +++ b/test/apply_rules.lean @@ -19,14 +19,33 @@ attribute [mono_rules] add_le_add mul_le_mul_of_nonneg_right example {a b c d e : nat} (h1 : a ≤ b) (h2 : c ≤ d) (h3 : 0 ≤ e) : a + c * e + a + c + 0 ≤ b + d * e + b + d + e := -by apply_rules [mono_rules] +by apply_rules with mono_rules example {a b c d e : nat} (h1 : a ≤ b) (h2 : c ≤ d) (h3 : 0 ≤ e) : a + c * e + a + c + 0 ≤ b + d * e + b + d + e := -by apply_rules mono_rules +by apply_rules with mono_rules -- test that metavariables created for implicit arguments don't get stuck example (P : ℕ → Type) (f : Π {n : ℕ}, P n → P (n + 1)) (g : P 0) : P 2 := begin apply_rules [f, g], end + +/- +Test that there are no conflicts between attribute and declaration names. +After #13227 there is little chance of ambiguity here, but this is still a valid test. +-/ + +@[user_attribute] +meta def p_rules_attr : user_attribute := +{ name := `p_rules, + descr := "testing" } + +constant P : ℕ → Prop + +axiom p_rules : P 0 + +@[p_rules] axiom foo : P 10 + +example : P 0 := by success_if_fail {apply_rules with p_rules}; apply_rules [p_rules] +example : P 10 := by apply_rules with p_rules 60 From 8044794f20dd04221951384569cf8788c629af3e Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Thu, 21 Apr 2022 15:19:59 +0000 Subject: [PATCH 132/373] feat(topology/algebra/module/basic): continuous linear maps are automatically uniformly continuous (#13276) Generalize `continuous_linear_map.uniform_continuous`, `continuous_linear_equiv.uniform_embedding` and `linear_equiv.uniform_embedding` form `normed_space`s to `uniform_add_group`s and move them to `topology/algebra/module/basic`. --- src/analysis/normed_space/operator_norm.lean | 51 ++++++------------- src/topology/algebra/module/basic.lean | 26 ++++++++++ .../uniform_space/uniform_embedding.lean | 13 +++++ 3 files changed, 54 insertions(+), 36 deletions(-) diff --git a/src/analysis/normed_space/operator_norm.lean b/src/analysis/normed_space/operator_norm.lean index dfa6a1ca83df8..abf47d429b8c3 100644 --- a/src/analysis/normed_space/operator_norm.lean +++ b/src/analysis/normed_space/operator_norm.lean @@ -479,10 +479,6 @@ f.to_linear_map.to_add_monoid_hom.isometry_iff_norm variables [ring_hom_isometric σ₁₂] (f : E →SL[σ₁₂] F) -/-- A continuous linear map is automatically uniformly continuous. -/ -protected theorem uniform_continuous : uniform_continuous f := -f.lipschitz.uniform_continuous - @[simp, nontriviality] lemma op_norm_subsingleton [subsingleton E] : ∥f∥ = 0 := begin refine le_antisymm _ (norm_nonneg _), @@ -1164,10 +1160,11 @@ section variables [nondiscrete_normed_field 𝕜] [nondiscrete_normed_field 𝕜₂] [nondiscrete_normed_field 𝕜₃] [normed_space 𝕜 E] [normed_space 𝕜₂ F] [normed_space 𝕜₃ G] [normed_space 𝕜 Fₗ] (c : 𝕜) {σ₁₂ : 𝕜 →+* 𝕜₂} {σ₂₃ : 𝕜₂ →+* 𝕜₃} - [ring_hom_isometric σ₁₂] (f g : E →SL[σ₁₂] F) (x y z : E) + (f g : E →SL[σ₁₂] F) (x y z : E) -lemma linear_map.bound_of_shell (f : E →ₛₗ[σ₁₂] F) {ε C : ℝ} (ε_pos : 0 < ε) {c : 𝕜} - (hc : 1 < ∥c∥) (hf : ∀ x, ε / ∥c∥ ≤ ∥x∥ → ∥x∥ < ε → ∥f x∥ ≤ C * ∥x∥) (x : E) : +lemma linear_map.bound_of_shell [ring_hom_isometric σ₁₂] (f : E →ₛₗ[σ₁₂] F) {ε C : ℝ} + (ε_pos : 0 < ε) {c : 𝕜} (hc : 1 < ∥c∥) + (hf : ∀ x, ε / ∥c∥ ≤ ∥x∥ → ∥x∥ < ε → ∥f x∥ ≤ C * ∥x∥) (x : E) : ∥f x∥ ≤ C * ∥x∥ := begin by_cases hx : x = 0, { simp [hx] }, @@ -1200,7 +1197,7 @@ section op_norm open set real /-- An operator is zero iff its norm vanishes. -/ -theorem op_norm_zero_iff : ∥f∥ = 0 ↔ f = 0 := +theorem op_norm_zero_iff [ring_hom_isometric σ₁₂] : ∥f∥ = 0 ↔ f = 0 := iff.intro (λ hn, continuous_linear_map.ext (λ x, norm_le_zero_iff.1 (calc _ ≤ ∥f∥ * ∥x∥ : le_op_norm _ _ @@ -1221,8 +1218,8 @@ instance norm_one_class [nontrivial E] : norm_one_class (E →L[𝕜] E) := ⟨n /-- Continuous linear maps themselves form a normed space with respect to the operator norm. -/ -instance to_normed_group : normed_group (E →SL[σ₁₂] F) := -normed_group.of_core _ ⟨op_norm_zero_iff, op_norm_add_le, op_norm_neg⟩ +instance to_normed_group [ring_hom_isometric σ₁₂] : normed_group (E →SL[σ₁₂] F) := +normed_group.of_core _ ⟨λ f, op_norm_zero_iff f, op_norm_add_le, op_norm_neg⟩ /-- Continuous linear maps form a normed ring with respect to the operator norm. -/ instance to_normed_ring : normed_ring (E →L[𝕜] E) := @@ -1238,7 +1235,8 @@ instance to_normed_algebra [nontrivial E] : normed_algebra 𝕜 (E →L[𝕜] E) variable {f} -lemma homothety_norm [nontrivial E] (f : E →SL[σ₁₂] F) {a : ℝ} (hf : ∀x, ∥f x∥ = a * ∥x∥) : +lemma homothety_norm [ring_hom_isometric σ₁₂] [nontrivial E] (f : E →SL[σ₁₂] F) {a : ℝ} + (hf : ∀x, ∥f x∥ = a * ∥x∥) : ∥f∥ = a := begin obtain ⟨x, hx⟩ : ∃ (x : E), x ≠ 0 := exists_ne 0, @@ -1296,7 +1294,7 @@ section completeness open_locale topological_space open filter -variables {E' : Type*} [semi_normed_group E'] [normed_space 𝕜 E'] +variables {E' : Type*} [semi_normed_group E'] [normed_space 𝕜 E'] [ring_hom_isometric σ₁₂] /-- Construct a bundled continuous (semi)linear map from a map `f : E → F` and a proof of the fact that it belongs to the closure of the image of a bounded set `s : set (E →SL[σ₁₂] F)` under coercion @@ -1417,7 +1415,7 @@ extend_unique _ _ _ _ _ (zero_comp _) end section -variables {N : ℝ≥0} (h_e : ∀x, ∥x∥ ≤ N * ∥e x∥) +variables {N : ℝ≥0} (h_e : ∀x, ∥x∥ ≤ N * ∥e x∥) [ring_hom_isometric σ₁₂] local notation `ψ` := f.extend e h_dense (uniform_embedding_of_bound _ h_e).to_uniform_inducing @@ -1457,7 +1455,8 @@ end continuous_linear_map namespace linear_isometry -@[simp] lemma norm_to_continuous_linear_map [nontrivial E] (f : E →ₛₗᵢ[σ₁₂] F) : +@[simp] lemma norm_to_continuous_linear_map [nontrivial E] [ring_hom_isometric σ₁₂] + (f : E →ₛₗᵢ[σ₁₂] F) : ∥f.to_continuous_linear_map∥ = 1 := f.to_continuous_linear_map.homothety_norm $ by simp @@ -1466,7 +1465,8 @@ variables {σ₁₃ : 𝕜 →+* 𝕜₃} [ring_hom_comp_triple σ₁₂ σ₂ include σ₁₃ /-- Postcomposition of a continuous linear map with a linear isometry preserves the operator norm. -/ -lemma norm_to_continuous_linear_map_comp (f : F →ₛₗᵢ[σ₂₃] G) {g : E →SL[σ₁₂] F} : +lemma norm_to_continuous_linear_map_comp [ring_hom_isometric σ₁₂] (f : F →ₛₗᵢ[σ₂₃] G) + {g : E →SL[σ₁₂] F} : ∥f.to_continuous_linear_map.comp g∥ = ∥g∥ := op_norm_ext (f.to_continuous_linear_map.comp g) g (λ x, by simp only [norm_map, coe_to_continuous_linear_map, coe_comp']) @@ -1594,12 +1594,6 @@ protected lemma antilipschitz (e : E ≃SL[σ₁₂] F) : antilipschitz_with (nnnorm (e.symm : F →SL[σ₂₁] E)) e := e.symm.lipschitz.to_right_inverse e.left_inv -include σ₂₁ -/-- A continuous linear equiv is a uniform embedding. -/ -lemma uniform_embedding [ring_hom_isometric σ₁₂] (e : E ≃SL[σ₁₂] F) : uniform_embedding e := -e.antilipschitz.uniform_embedding e.lipschitz.uniform_continuous -omit σ₂₁ - lemma one_le_norm_mul_norm_symm [ring_hom_isometric σ₁₂] [nontrivial E] (e : E ≃SL[σ₁₂] F) : 1 ≤ ∥(e : E →SL[σ₁₂] F)∥ * ∥(e.symm : F →SL[σ₂₁] E)∥ := begin @@ -1676,21 +1670,6 @@ end end continuous_linear_equiv -variables [nondiscrete_normed_field 𝕜] [nondiscrete_normed_field 𝕜₂] - [normed_space 𝕜 E] [normed_space 𝕜₂ F] {σ₁₂ : 𝕜 →+* 𝕜₂} {σ₂₁ : 𝕜₂ →+* 𝕜} - [ring_hom_inv_pair σ₁₂ σ₂₁] [ring_hom_inv_pair σ₂₁ σ₁₂] - [ring_hom_isometric σ₁₂] [ring_hom_isometric σ₂₁] - -include σ₂₁ -lemma linear_equiv.uniform_embedding (e : E ≃ₛₗ[σ₁₂] F) (h₁ : continuous e) - (h₂ : continuous e.symm) : uniform_embedding e := -continuous_linear_equiv.uniform_embedding -({ continuous_to_fun := h₁, - continuous_inv_fun := h₂, - .. e } : E ≃SL[σ₁₂] F) - -omit σ₂₁ - end normed /-- diff --git a/src/topology/algebra/module/basic.lean b/src/topology/algebra/module/basic.lean index 41b96bb59996c..2461e16ba5ee3 100644 --- a/src/topology/algebra/module/basic.lean +++ b/src/topology/algebra/module/basic.lean @@ -6,6 +6,7 @@ Authors: Jan-David Salchow, Sébastien Gouëzel, Jean Lo, Yury Kudryashov, Fréd -/ import topology.algebra.ring import topology.algebra.mul_action +import topology.algebra.uniform_group import topology.uniform_space.uniform_embedding import algebra.algebra.basic import linear_algebra.projection @@ -360,6 +361,12 @@ instance to_fun : has_coe_to_fun (M₁ →SL[σ₁₂] M₂) (λ _, M₁ → M @[continuity] protected lemma continuous (f : M₁ →SL[σ₁₂] M₂) : continuous f := f.2 +protected lemma uniform_continuous {E₁ E₂ : Type*} [uniform_space E₁] [uniform_space E₂] + [add_comm_group E₁] [add_comm_group E₂] [module R₁ E₁] [module R₂ E₂] + [uniform_add_group E₁] [uniform_add_group E₂] (f : E₁ →SL[σ₁₂] E₂) : + uniform_continuous f := +uniform_continuous_add_monoid_hom_of_continuous f.continuous + @[simp, norm_cast] lemma coe_inj {f g : M₁ →SL[σ₁₂] M₂} : (f : M₁ →ₛₗ[σ₁₂] M₂) = g ↔ f = g := coe_injective.eq_iff @@ -1496,6 +1503,25 @@ by rw [e.symm.image_eq_preimage, e.symm_symm] @[simp] protected lemma preimage_symm_preimage (e : M₁ ≃SL[σ₁₂] M₂) (s : set M₁) : e ⁻¹' (e.symm ⁻¹' s) = s := e.symm.symm_preimage_preimage s +protected lemma uniform_embedding {E₁ E₂ : Type*} [uniform_space E₁] [uniform_space E₂] + [add_comm_group E₁] [add_comm_group E₂] [module R₁ E₁] [module R₂ E₂] + [uniform_add_group E₁] [uniform_add_group E₂] + (e : E₁ ≃SL[σ₁₂] E₂) : + uniform_embedding e := +e.to_linear_equiv.to_equiv.uniform_embedding + e.to_continuous_linear_map.uniform_continuous + e.symm.to_continuous_linear_map.uniform_continuous + +protected lemma _root_.linear_equiv.uniform_embedding {E₁ E₂ : Type*} [uniform_space E₁] + [uniform_space E₂] [add_comm_group E₁] [add_comm_group E₂] [module R₁ E₁] [module R₂ E₂] + [uniform_add_group E₁] [uniform_add_group E₂] + (e : E₁ ≃ₛₗ[σ₁₂] E₂) (h₁ : continuous e) (h₂ : continuous e.symm) : + uniform_embedding e := +continuous_linear_equiv.uniform_embedding +({ continuous_to_fun := h₁, + continuous_inv_fun := h₂, + .. e } : E₁ ≃SL[σ₁₂] E₂) + omit σ₂₁ /-- Create a `continuous_linear_equiv` from two `continuous_linear_map`s that are diff --git a/src/topology/uniform_space/uniform_embedding.lean b/src/topology/uniform_space/uniform_embedding.lean index 52b0efe157caf..7764ede6e6918 100644 --- a/src/topology/uniform_space/uniform_embedding.lean +++ b/src/topology/uniform_space/uniform_embedding.lean @@ -90,6 +90,19 @@ by simp only [uniform_embedding_def, uniform_continuous_def]; exact λ ⟨I, H₁, H₂⟩, ⟨I, λ s, ⟨H₂ s, λ ⟨t, tu, h⟩, mem_of_superset (H₁ t tu) (λ ⟨a, b⟩, h a b)⟩⟩⟩ +lemma equiv.uniform_embedding {α β : Type*} [uniform_space α] [uniform_space β] (f : α ≃ β) + (h₁ : uniform_continuous f) (h₂ : uniform_continuous f.symm) : uniform_embedding f := +{ comap_uniformity := + begin + refine le_antisymm _ _, + { change comap (f.prod_congr f) _ ≤ _, + rw ← map_equiv_symm (f.prod_congr f), + exact h₂ }, + { rw ← map_le_iff_le_comap, + exact h₁ } + end, + inj := f.injective } + theorem uniform_embedding_inl : uniform_embedding (sum.inl : α → α ⊕ β) := begin apply uniform_embedding_def.2 ⟨sum.inl_injective, λ s, ⟨_, _⟩⟩, From 91cbe460db457941f40b9dbea8b7ce8af211f94e Mon Sep 17 00:00:00 2001 From: damiano Date: Thu, 21 Apr 2022 15:20:01 +0000 Subject: [PATCH 133/373] feat(algebra/monoid_algebra/basic): lifts of (add_)monoid_algebras (#13382) We show that homomorphisms of the grading (add) monoids of (add) monoid algebras lift to ring/algebra homs of the algebras themselves. This PR is preparation for introducing Laurent polynomials (see [adomani_laurent_polynomials](https://github.com/leanprover-community/mathlib/tree/adomani_laurent_polynomials), file `data/polynomial/laurent` for a preliminary version). [Zulip](https://leanprover.zulipchat.com/#narrow/stream/116395-maths/topic/Laurent.20polynomials) Co-authored-by: Eric Wieser --- src/algebra/monoid_algebra/basic.lean | 77 +++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 5 deletions(-) diff --git a/src/algebra/monoid_algebra/basic.lean b/src/algebra/monoid_algebra/basic.lean index 4c434ff6906b9..c16ba8b5eca88 100644 --- a/src/algebra/monoid_algebra/basic.lean +++ b/src/algebra/monoid_algebra/basic.lean @@ -548,14 +548,24 @@ lemma single_one_comm [comm_semiring k] [mul_one_class G] (r : k) (f : monoid_al by { ext, rw [single_one_mul_apply, mul_single_one_apply, mul_comm] } /-- `finsupp.single 1` as a `ring_hom` -/ -@[simps] def single_one_ring_hom [semiring k] [monoid G] : k →+* monoid_algebra k G := +@[simps] def single_one_ring_hom [semiring k] [mul_one_class G] : k →+* monoid_algebra k G := { map_one' := rfl, map_mul' := λ x y, by rw [single_add_hom, single_mul_single, one_mul], ..finsupp.single_add_hom 1} +/-- If `f : G → H` is a multiplicative homomorphism between two monoids, then +`finsupp.map_domain f` is a ring homomorphism between their monoid algebras. -/ +@[simps] +def map_domain_ring_hom (k : Type*) {H F : Type*} [semiring k] [monoid G] [monoid H] + [monoid_hom_class F G H] (f : F) : + monoid_algebra k G →+* monoid_algebra k H := +{ map_one' := map_domain_one f, + map_mul' := λ x y, map_domain_mul f x y, + ..(finsupp.map_domain.add_monoid_hom f : monoid_algebra k G →+ monoid_algebra k H) } + /-- If two ring homomorphisms from `monoid_algebra k G` are equal on all `single a 1` and `single 1 b`, then they are equal. -/ -lemma ring_hom_ext {R} [semiring k] [monoid G] [semiring R] +lemma ring_hom_ext {R} [semiring k] [mul_one_class G] [semiring R] {f g : monoid_algebra k G →+* R} (h₁ : ∀ b, f (single 1 b) = g (single 1 b)) (h_of : ∀ a, f (single a 1) = g (single a 1)) : f = g := ring_hom.coe_add_monoid_hom_injective $ add_hom_ext $ λ a b, @@ -566,7 +576,7 @@ ring_hom.coe_add_monoid_hom_injective $ add_hom_ext $ λ a b, and `single 1 b`, then they are equal. See note [partially-applied ext lemmas]. -/ -@[ext] lemma ring_hom_ext' {R} [semiring k] [monoid G] [semiring R] +@[ext] lemma ring_hom_ext' {R} [semiring k] [mul_one_class G] [semiring R] {f g : monoid_algebra k G →+* R} (h₁ : f.comp single_one_ring_hom = g.comp single_one_ring_hom) (h_of : (f : monoid_algebra k G →* R).comp (of k G) = (g : monoid_algebra k G →* R).comp (of k G)) : @@ -684,6 +694,31 @@ lemma lift_unique (F : monoid_algebra k G →ₐ[k] A) (f : monoid_algebra k G) F f = f.sum (λ a b, b • F (single a 1)) := by conv_lhs { rw lift_unique' F, simp [lift_apply] } +/-- If `f : G → H` is a homomorphism between two magmas, then +`finsupp.map_domain f` is a non-unital algebra homomorphism between their magma algebras. -/ +@[simps] +def map_domain_non_unital_alg_hom (k A : Type*) [comm_semiring k] [semiring A] [algebra k A] + {G H F : Type*} [has_mul G] [has_mul H] [mul_hom_class F G H] (f : F) : + monoid_algebra A G →ₙₐ[k] monoid_algebra A H := +{ map_mul' := λ x y, map_domain_mul f x y, + map_smul' := λ r x, map_domain_smul r x, + ..(finsupp.map_domain.add_monoid_hom f : monoid_algebra A G →+ monoid_algebra A H) } + +lemma map_domain_algebra_map (k A : Type*) {H F : Type*} [comm_semiring k] [semiring A] + [algebra k A] [monoid H] [monoid_hom_class F G H] (f : F) (r : k) : + map_domain f (algebra_map k (monoid_algebra A G) r) = + algebra_map k (monoid_algebra A H) r := +by simp only [coe_algebra_map, map_domain_single, map_one] + +/-- If `f : G → H` is a multiplicative homomorphism between two monoids, then +`finsupp.map_domain f` is an algebra homomorphism between their monoid algebras. -/ +@[simps] +def map_domain_alg_hom (k A : Type*) [comm_semiring k] [semiring A] [algebra k A] {H F : Type*} + [monoid H] [monoid_hom_class F G H] (f : F) : + monoid_algebra A G →ₐ[k] monoid_algebra A H := +{ commutes' := map_domain_algebra_map k A f, + ..map_domain_ring_hom A f} + end lift section @@ -1211,8 +1246,6 @@ lemma lift_nc_smul {R : Type*} [add_zero_class G] [semiring R] (f : k →+* R) lift_nc (f : k →+ R) g (c • φ) = f c * lift_nc (f : k →+ R) g φ := @monoid_algebra.lift_nc_smul k (multiplicative G) _ _ _ _ f g c φ -variables {k G} - lemma induction_on [add_monoid G] {p : add_monoid_algebra k G → Prop} (f : add_monoid_algebra k G) (hM : ∀ g, p (of k G (multiplicative.of_add g))) (hadd : ∀ f g : add_monoid_algebra k G, p f → p g → p (f + g)) @@ -1224,6 +1257,16 @@ begin simp only [mul_one, to_add_of_add, smul_single', of_apply] }, end +/-- If `f : G → H` is an additive homomorphism between two additive monoids, then +`finsupp.map_domain f` is a ring homomorphism between their add monoid algebras. -/ +@[simps] +def map_domain_ring_hom (k : Type*) [semiring k] {H F : Type*} [add_monoid G] [add_monoid H] + [add_monoid_hom_class F G H] (f : F) : + add_monoid_algebra k G →+* add_monoid_algebra k H := +{ map_one' := map_domain_one f, + map_mul' := λ x y, map_domain_mul f x y, + ..(finsupp.map_domain.add_monoid_hom f : monoid_algebra k G →+ monoid_algebra k H) } + end misc_theorems section span @@ -1503,6 +1546,30 @@ finset.induction_on s rfl $ λ a s has ih, by rw [prod_insert has, ih, end +lemma map_domain_algebra_map {A H F : Type*} [comm_semiring k] [semiring A] + [algebra k A] [add_monoid G] [add_monoid H] [add_monoid_hom_class F G H] (f : F) (r : k) : + map_domain f (algebra_map k (add_monoid_algebra A G) r) = + algebra_map k (add_monoid_algebra A H) r := +by simp only [function.comp_app, map_domain_single, add_monoid_algebra.coe_algebra_map, map_zero] + +/-- If `f : G → H` is a homomorphism between two additive magmas, then `finsupp.map_domain f` is a +non-unital algebra homomorphism between their additive magma algebras. -/ +@[simps] +def map_domain_non_unital_alg_hom (k A : Type*) [comm_semiring k] [semiring A] [algebra k A] + {G H F : Type*} [has_add G] [has_add H] [add_hom_class F G H] (f : F) : + add_monoid_algebra A G →ₙₐ[k] add_monoid_algebra A H := +{ map_mul' := λ x y, map_domain_mul f x y, + map_smul' := λ r x, map_domain_smul r x, + ..(finsupp.map_domain.add_monoid_hom f : monoid_algebra A G →+ monoid_algebra A H) } + +/-- If `f : G → H` is an additive homomorphism between two additive monoids, then +`finsupp.map_domain f` is an algebra homomorphism between their add monoid algebras. -/ +@[simps] def map_domain_alg_hom (k A : Type*) [comm_semiring k] [semiring A] [algebra k A] + [add_monoid G] {H F : Type*} [add_monoid H] [add_monoid_hom_class F G H] (f : F) : + add_monoid_algebra A G →ₐ[k] add_monoid_algebra A H := +{ commutes' := map_domain_algebra_map f, + ..map_domain_ring_hom A f} + end add_monoid_algebra variables [comm_semiring R] (k G) From 6490ee3aafd58e915f1bc6462b1fdcdd16d65d0c Mon Sep 17 00:00:00 2001 From: kkytola Date: Thu, 21 Apr 2022 17:29:10 +0000 Subject: [PATCH 134/373] feat(topology/instances/ennreal): Add lemmas about continuity of ennreal subtraction. (#13448) `ennreal` does not have continuous `sub`. This PR adds `ennreal.continuous_on_sub` and related lemmas, which give the continuity of the subtraction in more restricted/specialized setups. --- src/topology/instances/ennreal.lean | 43 +++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/topology/instances/ennreal.lean b/src/topology/instances/ennreal.lean index 47592de1baf4f..aaa2edfca4536 100644 --- a/src/topology/instances/ennreal.lean +++ b/src/topology/instances/ennreal.lean @@ -387,6 +387,49 @@ begin { simp only [H, true_or, ne.def, not_false_iff] } end +lemma continuous_on_sub : + continuous_on (λ p : ℝ≥0∞ × ℝ≥0∞, p.fst - p.snd) { p : ℝ≥0∞ × ℝ≥0∞ | p ≠ ⟨∞, ∞⟩ } := +begin + rw continuous_on, + rintros ⟨x, y⟩ hp, + simp only [ne.def, set.mem_set_of_eq, prod.mk.inj_iff] at hp, + refine tendsto_nhds_within_of_tendsto_nhds (tendsto_sub (not_and_distrib.mp hp)), +end + +lemma continuous_sub_left {a : ℝ≥0∞} (a_ne_top : a ≠ ⊤) : + continuous (λ x, a - x) := +begin + rw (show (λ x, a - x) = (λ p : ℝ≥0∞ × ℝ≥0∞, p.fst - p.snd) ∘ (λ x, ⟨a, x⟩), by refl), + apply continuous_on.comp_continuous continuous_on_sub (continuous.prod.mk a), + intro x, + simp only [a_ne_top, ne.def, mem_set_of_eq, prod.mk.inj_iff, false_and, not_false_iff], +end + +lemma continuous_nnreal_sub {a : ℝ≥0} : + continuous (λ (x : ℝ≥0∞), (a : ℝ≥0∞) - x) := +continuous_sub_left coe_ne_top + +lemma continuous_on_sub_left (a : ℝ≥0∞) : + continuous_on (λ x, a - x) {x : ℝ≥0∞ | x ≠ ∞} := +begin + rw (show (λ x, a - x) = (λ p : ℝ≥0∞ × ℝ≥0∞, p.fst - p.snd) ∘ (λ x, ⟨a, x⟩), by refl), + apply continuous_on.comp continuous_on_sub (continuous.continuous_on (continuous.prod.mk a)), + rintros _ h (_|_), + exact h none_eq_top, +end + +lemma continuous_sub_right (a : ℝ≥0∞) : + continuous (λ x : ℝ≥0∞, x - a) := +begin + by_cases a_infty : a = ∞, + { simp [a_infty, continuous_const], }, + { rw (show (λ x, x - a) = (λ p : ℝ≥0∞ × ℝ≥0∞, p.fst - p.snd) ∘ (λ x, ⟨x, a⟩), by refl), + apply continuous_on.comp_continuous + continuous_on_sub (continuous_id'.prod_mk continuous_const), + intro x, + simp only [a_infty, ne.def, mem_set_of_eq, prod.mk.inj_iff, and_false, not_false_iff], }, +end + protected lemma tendsto.pow {f : filter α} {m : α → ℝ≥0∞} {a : ℝ≥0∞} {n : ℕ} (hm : tendsto m f (𝓝 a)) : tendsto (λ x, (m x) ^ n) f (𝓝 (a ^ n)) := From 777d1ec1f57c158551df64b81e52db6228a2226a Mon Sep 17 00:00:00 2001 From: Kexing Ying Date: Thu, 21 Apr 2022 17:29:11 +0000 Subject: [PATCH 135/373] feat(measure_theory/measure/measure_space): add some lemmas for the counting measure (#13485) --- src/measure_theory/measure/measure_space.lean | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/measure_theory/measure/measure_space.lean b/src/measure_theory/measure/measure_space.lean index b29391b96c74e..a955690b55450 100644 --- a/src/measure_theory/measure/measure_space.lean +++ b/src/measure_theory/measure/measure_space.lean @@ -1616,6 +1616,9 @@ calc (∑' i : s, 1 : ℝ≥0∞) = ∑' i, indicator s 1 i : tsum_subtype s 1 lemma count_apply (hs : measurable_set s) : count s = ∑' i : s, 1 := by simp only [count, sum_apply, hs, dirac_apply', ← tsum_subtype s 1, pi.one_apply] +@[simp] lemma count_empty : count (∅ : set α) = 0 := +by rw [count_apply measurable_set.empty, tsum_empty] + @[simp] lemma count_apply_finset [measurable_singleton_class α] (s : finset α) : count (↑s : set α) = s.card := calc count (↑s : set α) = ∑' i : (↑s : set α), 1 : count_apply s.measurable_set @@ -1637,7 +1640,9 @@ begin ... ≤ count s : measure_mono ht end -@[simp] lemma count_apply_eq_top [measurable_singleton_class α] : count s = ∞ ↔ s.infinite := +variable [measurable_singleton_class α] + +@[simp] lemma count_apply_eq_top : count s = ∞ ↔ s.infinite := begin by_cases hs : s.finite, { simp [set.infinite, hs, count_apply_finite] }, @@ -1645,11 +1650,35 @@ begin simp [hs, count_apply_infinite] } end -@[simp] lemma count_apply_lt_top [measurable_singleton_class α] : count s < ∞ ↔ s.finite := +@[simp] lemma count_apply_lt_top : count s < ∞ ↔ s.finite := calc count s < ∞ ↔ count s ≠ ∞ : lt_top_iff_ne_top ... ↔ ¬s.infinite : not_congr count_apply_eq_top ... ↔ s.finite : not_not +lemma empty_of_count_eq_zero (hsc : count s = 0) : s = ∅ := +begin + have hs : s.finite, + { rw [← count_apply_lt_top, hsc], + exact with_top.zero_lt_top }, + rw count_apply_finite _ hs at hsc, + simpa using hsc, +end + +@[simp] lemma count_eq_zero_iff : count s = 0 ↔ s = ∅ := +⟨empty_of_count_eq_zero, λ h, h.symm ▸ count_empty⟩ + +lemma count_ne_zero (hs' : s.nonempty) : count s ≠ 0 := +begin + rw [ne.def, count_eq_zero_iff], + exact hs'.ne_empty, +end + +@[simp] lemma count_singleton (a : α) : count ({a} : set α) = 1 := +begin + rw [count_apply_finite ({a} : set α) (set.finite_singleton _), set.finite.to_finset], + simp, +end + end count /-! ### Absolute continuity -/ From 62b33339aebf6a57cb772e85ed647994d92b5eaf Mon Sep 17 00:00:00 2001 From: damiano Date: Thu, 21 Apr 2022 17:29:12 +0000 Subject: [PATCH 136/373] chore(algebra/star/chsh): `repeat`ed golf (#13499) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of having a real Gröbner tactic, we can leverage a loop of `ring, simp` to reach a goal. --- src/algebra/star/chsh.lean | 51 ++++++++++++++------------------------ 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/src/algebra/star/chsh.lean b/src/algebra/star/chsh.lean index 3b3bc4f0c4e19..dbe8db59554e5 100644 --- a/src/algebra/star/chsh.lean +++ b/src/algebra/star/chsh.lean @@ -90,6 +90,22 @@ structure is_CHSH_tuple {R} [monoid R] [star_semigroup R] (A₀ A₁ B₀ B₁ : variables {R : Type u} +lemma CHSH_id [comm_ring R] {A₀ A₁ B₀ B₁ : R} + (A₀_inv : A₀^2 = 1) (A₁_inv : A₁^2 = 1) (B₀_inv : B₀^2 = 1) (B₁_inv : B₁^2 = 1) : + (2 - A₀ * B₀ - A₀ * B₁ - A₁ * B₀ + A₁ * B₁) * + (2 - A₀ * B₀ - A₀ * B₁ - A₁ * B₀ + A₁ * B₁) = + 4 * (2 - A₀ * B₀ - A₀ * B₁ - A₁ * B₀ + A₁ * B₁) := + -- If we had a Gröbner basis algorithm, this would be trivial. + -- Without one, it is somewhat tedious! +begin + rw ← sub_eq_zero, + repeat + { ring_nf, + simp only [A₁_inv, B₁_inv, sub_eq_add_neg, add_mul, mul_add, sub_mul, mul_sub, add_assoc, + neg_add, neg_sub, sub_add, sub_sub, neg_mul, ←sq, A₀_inv, B₀_inv, ←sq, ←mul_assoc, one_mul, + mul_one, add_right_neg, add_zero, sub_eq_add_neg, A₀_inv, mul_one, add_right_neg, zero_mul] } +end + /-- Given a CHSH tuple (A₀, A₁, B₀, B₁) in a *commutative* ordered `*`-algebra over ℝ, `A₀ * B₀ + A₀ * B₁ + A₁ * B₀ - A₁ * B₁ ≤ 2`. @@ -103,38 +119,7 @@ lemma CHSH_inequality_of_comm begin let P := (2 - A₀ * B₀ - A₀ * B₁ - A₁ * B₀ + A₁ * B₁), have i₁ : 0 ≤ P, - { have idem : P * P = 4 * P, - { -- If we had a Gröbner basis algorithm, this would be trivial. - -- Without one, it is somewhat tedious! - dsimp [P], - simp only [add_mul, mul_add, sub_mul, mul_sub, mul_comm, mul_assoc, add_assoc], - repeat { conv in (B₀ * (A₀ * B₀)) - { rw [T.A₀B₀_commutes, ←mul_assoc B₀ B₀ A₀, ←sq, T.B₀_inv, one_mul], } }, - repeat { conv in (B₀ * (A₁ * B₀)) - { rw [T.A₁B₀_commutes, ←mul_assoc B₀ B₀ A₁, ←sq, T.B₀_inv, one_mul], } }, - repeat { conv in (B₁ * (A₀ * B₁)) - { rw [T.A₀B₁_commutes, ←mul_assoc B₁ B₁ A₀, ←sq, T.B₁_inv, one_mul], } }, - repeat { conv in (B₁ * (A₁ * B₁)) - { rw [T.A₁B₁_commutes, ←mul_assoc B₁ B₁ A₁, ←sq, T.B₁_inv, one_mul], } }, - conv in (A₀ * (B₀ * (A₀ * B₁))) - { rw [←mul_assoc, T.A₀B₀_commutes, mul_assoc, ←mul_assoc A₀, ←sq, T.A₀_inv, one_mul], }, - conv in (A₀ * (B₁ * (A₀ * B₀))) - { rw [←mul_assoc, T.A₀B₁_commutes, mul_assoc, ←mul_assoc A₀, ←sq, T.A₀_inv, one_mul], }, - conv in (A₁ * (B₀ * (A₁ * B₁))) - { rw [←mul_assoc, T.A₁B₀_commutes, mul_assoc, ←mul_assoc A₁, ←sq, T.A₁_inv, one_mul], }, - conv in (A₁ * (B₁ * (A₁ * B₀))) - { rw [←mul_assoc, T.A₁B₁_commutes, mul_assoc, ←mul_assoc A₁, ←sq, T.A₁_inv, one_mul], }, - simp only [←sq, T.A₀_inv, T.A₁_inv], - simp only [mul_comm A₁ A₀, mul_comm B₁ B₀, mul_left_comm A₁ A₀, mul_left_comm B₁ B₀, - mul_left_comm B₀ A₀, mul_left_comm B₀ A₁, mul_left_comm B₁ A₀, mul_left_comm B₁ A₁], - norm_num, - simp only [mul_comm _ (2 : R), mul_comm _ (4 : R), - mul_left_comm _ (2 : R), mul_left_comm _ (4 : R)], - abel, - simp only [neg_mul, mul_one, int.cast_bit0, one_mul, int.cast_one, - zsmul_eq_mul, int.cast_neg], - simp only [←mul_assoc, ←add_assoc], - norm_num, }, + { have idem : P * P = 4 * P := CHSH_id T.A₀_inv T.A₁_inv T.B₀_inv T.B₁_inv, have idem' : P = (1 / 4 : ℝ) • (P * P), { have h : 4 * P = (4 : ℝ) • P := by simp [algebra.smul_def], rw [idem, h, ←mul_smul], @@ -148,7 +133,7 @@ begin convert smul_le_smul_of_nonneg (star_mul_self_nonneg : 0 ≤ star P * P) _, { simp, }, { apply_instance, }, - { norm_num, }, }, + { norm_num, } }, apply le_of_sub_nonneg, simpa only [sub_add_eq_sub_sub, ←sub_add] using i₁, end From e49ac91b4c0e531c8ba209db3d6dd20addb8a484 Mon Sep 17 00:00:00 2001 From: Floris van Doorn Date: Thu, 21 Apr 2022 17:29:13 +0000 Subject: [PATCH 137/373] feat(analysis/calculus/cont_diff): add more prod lemmas (#13521) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add `cont_diff.fst`, `cont_diff.comp₂`, `cont_diff_prod_mk_left` and many variants. * From the sphere eversion project * Required for convolutions * PR #13423 is similar for continuity --- src/analysis/calculus/cont_diff.lean | 162 ++++++++++++++++++++------- src/analysis/calculus/fderiv.lean | 10 +- 2 files changed, 129 insertions(+), 43 deletions(-) diff --git a/src/analysis/calculus/cont_diff.lean b/src/analysis/calculus/cont_diff.lean index f0e55623f35f6..fca4828fa13d1 100644 --- a/src/analysis/calculus/cont_diff.lean +++ b/src/analysis/calculus/cont_diff.lean @@ -1273,13 +1273,12 @@ variable (𝕜) order `n`, which are continuous. Contrary to the case of definitions in domains (where derivatives might not be unique) we do not need to localize the definition in space or time. -/ -definition cont_diff (n : with_top ℕ) (f : E → F) := +definition cont_diff (n : with_top ℕ) (f : E → F) := ∃ p : E → formal_multilinear_series 𝕜 E F, has_ftaylor_series_up_to n f p variable {𝕜} -theorem cont_diff_on_univ : - cont_diff_on 𝕜 n f univ ↔ cont_diff 𝕜 n f := +theorem cont_diff_on_univ : cont_diff_on 𝕜 n f univ ↔ cont_diff 𝕜 n f := begin split, { assume H, @@ -1290,39 +1289,31 @@ begin exact ⟨univ, filter.univ_sets _, p, (hp.has_ftaylor_series_up_to_on univ).of_le hm⟩ } end -lemma cont_diff_iff_cont_diff_at : - cont_diff 𝕜 n f ↔ ∀ x, cont_diff_at 𝕜 n f x := +lemma cont_diff_iff_cont_diff_at : cont_diff 𝕜 n f ↔ ∀ x, cont_diff_at 𝕜 n f x := by simp [← cont_diff_on_univ, cont_diff_on, cont_diff_at] -lemma cont_diff.cont_diff_at (h : cont_diff 𝕜 n f) : - cont_diff_at 𝕜 n f x := +lemma cont_diff.cont_diff_at (h : cont_diff 𝕜 n f) : cont_diff_at 𝕜 n f x := cont_diff_iff_cont_diff_at.1 h x -lemma cont_diff.cont_diff_within_at (h : cont_diff 𝕜 n f) : - cont_diff_within_at 𝕜 n f s x := +lemma cont_diff.cont_diff_within_at (h : cont_diff 𝕜 n f) : cont_diff_within_at 𝕜 n f s x := h.cont_diff_at.cont_diff_within_at -lemma cont_diff_top : - cont_diff 𝕜 ∞ f ↔ ∀ (n : ℕ), cont_diff 𝕜 n f := +lemma cont_diff_top : cont_diff 𝕜 ∞ f ↔ ∀ (n : ℕ), cont_diff 𝕜 n f := by simp [cont_diff_on_univ.symm, cont_diff_on_top] -lemma cont_diff_all_iff_nat : - (∀ n, cont_diff 𝕜 n f) ↔ (∀ n : ℕ, cont_diff 𝕜 n f) := +lemma cont_diff_all_iff_nat : (∀ n, cont_diff 𝕜 n f) ↔ (∀ n : ℕ, cont_diff 𝕜 n f) := by simp only [← cont_diff_on_univ, cont_diff_on_all_iff_nat] -lemma cont_diff.cont_diff_on - (h : cont_diff 𝕜 n f) : cont_diff_on 𝕜 n f s := +lemma cont_diff.cont_diff_on (h : cont_diff 𝕜 n f) : cont_diff_on 𝕜 n f s := (cont_diff_on_univ.2 h).mono (subset_univ _) -@[simp] lemma cont_diff_zero : - cont_diff 𝕜 0 f ↔ continuous f := +@[simp] lemma cont_diff_zero : cont_diff 𝕜 0 f ↔ continuous f := begin rw [← cont_diff_on_univ, continuous_iff_continuous_on_univ], exact cont_diff_on_zero end -lemma cont_diff_at_zero : - cont_diff_at 𝕜 0 f x ↔ ∃ u ∈ 𝓝 x, continuous_on f u := +lemma cont_diff_at_zero : cont_diff_at 𝕜 0 f x ↔ ∃ u ∈ 𝓝 x, continuous_on f u := by { rw ← cont_diff_within_at_univ, simp [cont_diff_within_at_zero, nhds_within_univ] } theorem cont_diff_at_one_iff : cont_diff_at 𝕜 1 f x ↔ @@ -1331,18 +1322,20 @@ by simp_rw [show (1 : with_top ℕ) = (0 + 1 : ℕ), from (zero_add 1).symm, cont_diff_at_succ_iff_has_fderiv_at, show ((0 : ℕ) : with_top ℕ) = 0, from rfl, cont_diff_at_zero, exists_mem_and_iff antitone_bforall antitone_continuous_on, and_comm] -lemma cont_diff.of_le - (h : cont_diff 𝕜 n f) (hmn : m ≤ n) : - cont_diff 𝕜 m f := +lemma cont_diff.of_le (h : cont_diff 𝕜 n f) (hmn : m ≤ n) : cont_diff 𝕜 m f := cont_diff_on_univ.1 $ (cont_diff_on_univ.2 h).of_le hmn -lemma cont_diff.continuous - (h : cont_diff 𝕜 n f) : continuous f := +lemma cont_diff.of_succ {n : ℕ} (h : cont_diff 𝕜 (n + 1) f) : cont_diff 𝕜 n f := +h.of_le $ with_top.coe_le_coe.mpr le_self_add + +lemma cont_diff.one_of_succ {n : ℕ} (h : cont_diff 𝕜 (n + 1) f) : cont_diff 𝕜 1 f := +h.of_le $ with_top.coe_le_coe.mpr le_add_self + +lemma cont_diff.continuous (h : cont_diff 𝕜 n f) : continuous f := cont_diff_zero.1 (h.of_le bot_le) /-- If a function is `C^n` with `n ≥ 1`, then it is differentiable. -/ -lemma cont_diff.differentiable - (h : cont_diff 𝕜 n f) (hn : 1 ≤ n) : differentiable 𝕜 f := +lemma cont_diff.differentiable (h : cont_diff 𝕜 n f) (hn : 1 ≤ n) : differentiable 𝕜 f := differentiable_on_univ.1 $ (cont_diff_on_univ.2 h).differentiable_on hn @@ -2020,27 +2013,53 @@ begin exact this.comp x hf (subset_univ _), end -lemma cont_diff.comp_cont_diff_at - {g : F → G} {f : E → F} (x : E) - (hg : cont_diff 𝕜 n g) - (hf : cont_diff_at 𝕜 n f x) : - cont_diff_at 𝕜 n (g ∘ f) x := +lemma cont_diff.comp_cont_diff_at {g : F → G} {f : E → F} (x : E) + (hg : cont_diff 𝕜 n g) (hf : cont_diff_at 𝕜 n f x) : cont_diff_at 𝕜 n (g ∘ f) x := hg.comp_cont_diff_within_at hf +/-! +### Smoothness of projections +-/ + /-- The first projection in a product is `C^∞`. -/ lemma cont_diff_fst : cont_diff 𝕜 n (prod.fst : E × F → E) := is_bounded_linear_map.cont_diff is_bounded_linear_map.fst +/-- Postcomposing `f` with `prod.fst` is `C^n` -/ +lemma cont_diff.fst {f : E → F × G} (hf : cont_diff 𝕜 n f) : cont_diff 𝕜 n (λ x, (f x).1) := +cont_diff_fst.comp hf + +/-- Precomposing `f` with `prod.fst` is `C^n` -/ +lemma cont_diff.fst' {f : E → G} (hf : cont_diff 𝕜 n f) : cont_diff 𝕜 n (λ x : E × F, f x.1) := +hf.comp cont_diff_fst + /-- The first projection on a domain in a product is `C^∞`. -/ -lemma cont_diff_on_fst {s : set (E×F)} : - cont_diff_on 𝕜 n (prod.fst : E × F → E) s := +lemma cont_diff_on_fst {s : set (E × F)} : cont_diff_on 𝕜 n (prod.fst : E × F → E) s := cont_diff.cont_diff_on cont_diff_fst +lemma cont_diff_on.fst {f : E → F × G} {s : set E} (hf : cont_diff_on 𝕜 n f s) : + cont_diff_on 𝕜 n (λ x, (f x).1) s := +cont_diff_fst.comp_cont_diff_on hf + /-- The first projection at a point in a product is `C^∞`. -/ -lemma cont_diff_at_fst {p : E × F} : - cont_diff_at 𝕜 n (prod.fst : E × F → E) p := +lemma cont_diff_at_fst {p : E × F} : cont_diff_at 𝕜 n (prod.fst : E × F → E) p := cont_diff_fst.cont_diff_at +/-- Postcomposing `f` with `prod.fst` is `C^n` at `(x, y)` -/ +lemma cont_diff_at.fst {f : E → F × G} {x : E} (hf : cont_diff_at 𝕜 n f x) : + cont_diff_at 𝕜 n (λ x, (f x).1) x := +cont_diff_at_fst.comp x hf + +/-- Precomposing `f` with `prod.fst` is `C^n` at `(x, y)` -/ +lemma cont_diff_at.fst' {f : E → G} {x : E} {y : F} (hf : cont_diff_at 𝕜 n f x) : + cont_diff_at 𝕜 n (λ x : E × F, f x.1) (x, y) := +cont_diff_at.comp (x, y) hf cont_diff_at_fst + +/-- Precomposing `f` with `prod.fst` is `C^n` at `x : E × F` -/ +lemma cont_diff_at.fst'' {f : E → G} {x : E × F} (hf : cont_diff_at 𝕜 n f x.1) : + cont_diff_at 𝕜 n (λ x : E × F, f x.1) x := +hf.comp x cont_diff_at_fst + /-- The first projection within a domain at a point in a product is `C^∞`. -/ lemma cont_diff_within_at_fst {s : set (E × F)} {p : E × F} : cont_diff_within_at 𝕜 n (prod.fst : E × F → E) s p := @@ -2050,21 +2069,64 @@ cont_diff_fst.cont_diff_within_at lemma cont_diff_snd : cont_diff 𝕜 n (prod.snd : E × F → F) := is_bounded_linear_map.cont_diff is_bounded_linear_map.snd +/-- Postcomposing `f` with `prod.snd` is `C^n` -/ +lemma cont_diff.snd {f : E → F × G} (hf : cont_diff 𝕜 n f) : cont_diff 𝕜 n (λ x, (f x).2) := +cont_diff_snd.comp hf + +/-- Precomposing `f` with `prod.snd` is `C^n` -/ +lemma cont_diff.snd' {f : F → G} (hf : cont_diff 𝕜 n f) : cont_diff 𝕜 n (λ x : E × F, f x.2) := +hf.comp cont_diff_snd + /-- The second projection on a domain in a product is `C^∞`. -/ -lemma cont_diff_on_snd {s : set (E×F)} : - cont_diff_on 𝕜 n (prod.snd : E × F → F) s := +lemma cont_diff_on_snd {s : set (E × F)} : cont_diff_on 𝕜 n (prod.snd : E × F → F) s := cont_diff.cont_diff_on cont_diff_snd +lemma cont_diff_on.snd {f : E → F × G} {s : set E} (hf : cont_diff_on 𝕜 n f s) : + cont_diff_on 𝕜 n (λ x, (f x).2) s := +cont_diff_snd.comp_cont_diff_on hf + /-- The second projection at a point in a product is `C^∞`. -/ -lemma cont_diff_at_snd {p : E × F} : - cont_diff_at 𝕜 n (prod.snd : E × F → F) p := +lemma cont_diff_at_snd {p : E × F} : cont_diff_at 𝕜 n (prod.snd : E × F → F) p := cont_diff_snd.cont_diff_at +/-- Postcomposing `f` with `prod.snd` is `C^n` at `x` -/ +lemma cont_diff_at.snd {f : E → F × G} {x : E} (hf : cont_diff_at 𝕜 n f x) : + cont_diff_at 𝕜 n (λ x, (f x).2) x := +cont_diff_at_snd.comp x hf + +/-- Precomposing `f` with `prod.snd` is `C^n` at `(x, y)` -/ +lemma cont_diff_at.snd' {f : F → G} {x : E} {y : F} (hf : cont_diff_at 𝕜 n f y) : + cont_diff_at 𝕜 n (λ x : E × F, f x.2) (x, y) := +cont_diff_at.comp (x, y) hf cont_diff_at_snd + +/-- Precomposing `f` with `prod.snd` is `C^n` at `x : E × F` -/ +lemma cont_diff_at.snd'' {f : F → G} {x : E × F} (hf : cont_diff_at 𝕜 n f x.2) : + cont_diff_at 𝕜 n (λ x : E × F, f x.2) x := +hf.comp x cont_diff_at_snd + /-- The second projection within a domain at a point in a product is `C^∞`. -/ lemma cont_diff_within_at_snd {s : set (E × F)} {p : E × F} : cont_diff_within_at 𝕜 n (prod.snd : E × F → F) s p := cont_diff_snd.cont_diff_within_at +section n_ary + +variables {E₁ E₂ E₃ E₄ : Type*} +variables [normed_group E₁] [normed_group E₂] [normed_group E₃] [normed_group E₄] +variables [normed_space 𝕜 E₁] [normed_space 𝕜 E₂] [normed_space 𝕜 E₃] [normed_space 𝕜 E₄] + +lemma cont_diff.comp₂ {g : E₁ × E₂ → G} {f₁ : F → E₁} {f₂ : F → E₂} + (hg : cont_diff 𝕜 n g) (hf₁ : cont_diff 𝕜 n f₁) (hf₂ : cont_diff 𝕜 n f₂) : + cont_diff 𝕜 n (λ x, g (f₁ x, f₂ x)) := +hg.comp $ hf₁.prod hf₂ + +lemma cont_diff.comp₃ {g : E₁ × E₂ × E₃ → G} {f₁ : F → E₁} {f₂ : F → E₂} {f₃ : F → E₃} + (hg : cont_diff 𝕜 n g) (hf₁ : cont_diff 𝕜 n f₁) (hf₂ : cont_diff 𝕜 n f₂) + (hf₃ : cont_diff 𝕜 n f₃) : cont_diff 𝕜 n (λ x, g (f₁ x, f₂ x, f₃ x)) := +hg.comp₂ hf₁ $ hf₂.prod hf₃ + +end n_ary + /-- The natural equivalence `(E × F) × G ≃ E × (F × G)` is smooth. @@ -2083,6 +2145,8 @@ Warning: see remarks attached to `cont_diff_prod_assoc` lemma cont_diff_prod_assoc_symm : cont_diff 𝕜 ⊤ $ (equiv.prod_assoc E F G).symm := (linear_isometry_equiv.prod_assoc 𝕜 E F G).symm.cont_diff +/-! ### Bundled derivatives -/ + /-- The bundled derivative of a `C^{n+1}` function is `C^n`. -/ lemma cont_diff_on_fderiv_within_apply {m n : with_top ℕ} {s : set E} {f : E → F} (hf : cont_diff_on 𝕜 n f s) (hs : unique_diff_on 𝕜 s) (hmn : m + 1 ≤ n) : @@ -2121,7 +2185,7 @@ end section pi -variables {ι : Type*} [fintype ι] {F' : ι → Type*} [Π i, normed_group (F' i)] +variables {ι ι' : Type*} [fintype ι] [fintype ι'] {F' : ι → Type*} [Π i, normed_group (F' i)] [Π i, normed_space 𝕜 (F' i)] {φ : Π i, E → F' i} {p' : Π i, E → formal_multilinear_series 𝕜 E (F' i)} {Φ : E → Π i, F' i} {P' : E → formal_multilinear_series 𝕜 E (Π i, F' i)} @@ -2179,6 +2243,15 @@ lemma cont_diff_pi : cont_diff 𝕜 n Φ ↔ ∀ i, cont_diff 𝕜 n (λ x, Φ x i) := by simp only [← cont_diff_on_univ, cont_diff_on_pi] +variables (𝕜 E) +lemma cont_diff_apply (i : ι) : cont_diff 𝕜 n (λ (f : ι → E), f i) := +cont_diff_pi.mp cont_diff_id i + +lemma cont_diff_apply_apply (i : ι) (j : ι') : cont_diff 𝕜 n (λ (f : ι → ι' → E), f i j) := +cont_diff_pi.mp (cont_diff_apply 𝕜 (ι' → E) i) j + +variables {𝕜 E} + end pi /-! ### Sum of two functions -/ @@ -2391,13 +2464,12 @@ lemma cont_diff_on.smul {s : set E} {f : E → 𝕜} {g : E → F} cont_diff_on 𝕜 n (λ x, f x • g x) s := λ x hx, (hf x hx).smul (hg x hx) -/-! ### Cartesian product of two functions-/ +/-! ### Cartesian product of two functions -/ section prod_map variables {E' : Type*} [normed_group E'] [normed_space 𝕜 E'] variables {F' : Type*} [normed_group F'] [normed_space 𝕜 F'] - /-- The product map of two `C^n` functions within a set at a point is `C^n` within the product set at the product point. -/ lemma cont_diff_within_at.prod_map' @@ -2452,6 +2524,12 @@ begin exact λ ⟨x, y⟩, (hf x).prod_map (hg y) end +lemma cont_diff_prod_mk_left (f₀ : F) : cont_diff 𝕜 n (λ e : E, (e, f₀)) := +cont_diff_id.prod cont_diff_const + +lemma cont_diff_prod_mk_right (e₀ : E) : cont_diff 𝕜 n (λ f : F, (e₀, f)) := +cont_diff_const.prod cont_diff_id + end prod_map /-! ### Inversion in a complete normed algebra -/ diff --git a/src/analysis/calculus/fderiv.lean b/src/analysis/calculus/fderiv.lean index 84ded8adab358..605efad24ed3a 100644 --- a/src/analysis/calculus/fderiv.lean +++ b/src/analysis/calculus/fderiv.lean @@ -1230,9 +1230,17 @@ lemma has_fderiv_within_at.prod hf₁.prod hf₂ lemma has_fderiv_at.prod (hf₁ : has_fderiv_at f₁ f₁' x) (hf₂ : has_fderiv_at f₂ f₂' x) : - has_fderiv_at (λx, (f₁ x, f₂ x)) (continuous_linear_map.prod f₁' f₂') x := + has_fderiv_at (λx, (f₁ x, f₂ x)) (f₁'.prod f₂') x := hf₁.prod hf₂ +lemma has_fderiv_at_prod_mk_left (e₀ : E) (f₀ : F) : + has_fderiv_at (λ e : E, (e, f₀)) (inl 𝕜 E F) e₀ := +(has_fderiv_at_id e₀).prod (has_fderiv_at_const f₀ e₀) + +lemma has_fderiv_at_prod_mk_right (e₀ : E) (f₀ : F) : + has_fderiv_at (λ f : F, (e₀, f)) (inr 𝕜 E F) f₀ := +(has_fderiv_at_const e₀ f₀).prod (has_fderiv_at_id f₀) + lemma differentiable_within_at.prod (hf₁ : differentiable_within_at 𝕜 f₁ s x) (hf₂ : differentiable_within_at 𝕜 f₂ s x) : differentiable_within_at 𝕜 (λx:E, (f₁ x, f₂ x)) s x := From b6c96ef7f0aa040dc3437e81b1d6f7d724d03259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Thu, 21 Apr 2022 17:29:14 +0000 Subject: [PATCH 138/373] feat(combinatorics/simple_graph/clique): Clique-free graphs (#13552) ... and the finset of cliques of a finite graph. Co-authored-by: Bhavik Mehta --- src/combinatorics/simple_graph/clique.lean | 114 +++++++++++++++++++-- src/data/set/pairwise.lean | 5 + 2 files changed, 111 insertions(+), 8 deletions(-) diff --git a/src/combinatorics/simple_graph/clique.lean b/src/combinatorics/simple_graph/clique.lean index 1be63fe7f20fe..87996e7e1e54e 100644 --- a/src/combinatorics/simple_graph/clique.lean +++ b/src/combinatorics/simple_graph/clique.lean @@ -9,18 +9,21 @@ import data.finset.pairwise /-! # Graph cliques -This file defines cliques in simple graphs. A clique is a set of vertices which are pairwise -connected. +This file defines cliques in simple graphs. A clique is a set of vertices that are pairwise +adjacent. ## Main declarations * `simple_graph.is_clique`: Predicate for a set of vertices to be a clique. * `simple_graph.is_n_clique`: Predicate for a set of vertices to be a `n`-clique. +* `simple_graph.clique_finset`: Finset of `n`-cliques of a graph. +* `simple_graph.clique_free`: Predicate for a graph to have no `n`-cliques. -## Todo +## TODO * Clique numbers * Going back and forth between cliques and complete subgraphs or embeddings of complete graphs. +* Do we need `clique_set`, a version of `clique_finset` for infinite graphs? -/ open finset fintype @@ -28,14 +31,15 @@ open finset fintype namespace simple_graph variables {α : Type*} (G H : simple_graph α) +/-! ### Cliques -/ + section clique variables {s t : set α} -/-- A clique in a graph is a set of vertices which are pairwise connected. -/ -structure is_clique (s : set α) : Prop := -(pairwise : s.pairwise G.adj) +/-- A clique in a graph is a set of vertices that are pairwise adjacent. -/ +abbreviation is_clique (s : set α) : Prop := s.pairwise G.adj -lemma is_clique_iff : G.is_clique s ↔ s.pairwise G.adj := ⟨λ h, h.pairwise, λ h, ⟨h⟩⟩ +lemma is_clique_iff : G.is_clique s ↔ s.pairwise G.adj := iff.rfl instance [decidable_eq α] [decidable_rel G.adj] {s : finset α} : decidable (G.is_clique s) := decidable_of_iff' _ G.is_clique_iff @@ -48,12 +52,21 @@ by { simp_rw is_clique_iff, exact set.pairwise.mono' h } lemma is_clique.subset (h : t ⊆ s) : G.is_clique s → G.is_clique t := by { simp_rw is_clique_iff, exact set.pairwise.mono h } +@[simp] lemma is_clique_bot_iff : (⊥ : simple_graph α).is_clique s ↔ (s : set α).subsingleton := +set.pairwise_bot_iff + +alias is_clique_bot_iff ↔ simple_graph.is_clique.subsingleton _ + end clique +/-! ### `n`-cliques -/ + +section n_clique variables {n : ℕ} {s : finset α} /-- A `n`-clique in a graph is a set of `n` vertices which are pairwise connected. -/ -structure is_n_clique (n : ℕ) (s : finset α) extends is_clique G s : Prop := +structure is_n_clique (n : ℕ) (s : finset α) : Prop := +(clique : G.is_clique s) (card_eq : s.card = n) lemma is_n_clique_iff : G.is_n_clique n s ↔ G.is_clique s ∧ s.card = n := @@ -68,4 +81,89 @@ variables {G H} lemma is_n_clique.mono (h : G ≤ H) : G.is_n_clique n s → H.is_n_clique n s := by { simp_rw is_n_clique_iff, exact and.imp_left (is_clique.mono h) } +@[simp] lemma is_n_clique_bot_iff : (⊥ : simple_graph α).is_n_clique n s ↔ n ≤ 1 ∧ s.card = n := +begin + rw [is_n_clique_iff, is_clique_bot_iff], + refine and_congr_left _, + rintro rfl, + exact card_le_one.symm, +end + +variables [decidable_eq α] {a b c : α} + +lemma is_3_clique_triple_iff : G.is_n_clique 3 {a, b, c} ↔ G.adj a b ∧ G.adj a c ∧ G.adj b c := +begin + simp only [is_n_clique_iff, is_clique_iff, set.pairwise_insert_of_symmetric G.symm, coe_insert], + have : ¬ 1 + 1 = 3 := by norm_num, + by_cases hab : a = b; by_cases hbc : b = c; by_cases hac : a = c; + subst_vars; simp [G.ne_of_adj, and_rotate, *], +end + +lemma is_3_clique_iff : + G.is_n_clique 3 s ↔ ∃ a b c, G.adj a b ∧ G.adj a c ∧ G.adj b c ∧ s = {a, b, c} := +begin + refine ⟨λ h, _, _⟩, + { obtain ⟨a, b, c, -, -, -, rfl⟩ := card_eq_three.1 h.card_eq, + refine ⟨a, b, c, _⟩, + rw is_3_clique_triple_iff at h, + tauto }, + { rintro ⟨a, b, c, hab, hbc, hca, rfl⟩, + exact is_3_clique_triple_iff.2 ⟨hab, hbc, hca⟩ } +end + +end n_clique + +/-! ### Graphs without cliques -/ + +section clique_free +variables {m n : ℕ} + +/-- `G.clique_free n` means that `G` has no `n`-cliques. -/ +def clique_free (n : ℕ) : Prop := ∀ t, ¬ G.is_n_clique n t + +variables {G H} + +lemma clique_free_bot (h : 2 ≤ n) : (⊥ : simple_graph α).clique_free n := +begin + rintro t ht, + rw is_n_clique_bot_iff at ht, + linarith, +end + +lemma clique_free.mono (h : m ≤ n) : G.clique_free m → G.clique_free n := +begin + rintro hG s hs, + obtain ⟨t, hts, ht⟩ := s.exists_smaller_set _ (h.trans hs.card_eq.ge), + exact hG _ ⟨hs.clique.subset hts, ht⟩, +end + +lemma clique_free.anti (h : G ≤ H) : H.clique_free n → G.clique_free n := +forall_imp $ λ s, mt $ is_n_clique.mono h + +end clique_free + +/-! ### Finset of cliques -/ + +section clique_finset +variables (G) [fintype α] [decidable_eq α] [decidable_rel G.adj] {n : ℕ} {a b c : α} {s : finset α} + +/-- The `n`-cliques in a graph as a finset. -/ +def clique_finset (n : ℕ) : finset (finset α) := univ.filter $ G.is_n_clique n + +lemma mem_clique_finset_iff (s : finset α) : s ∈ G.clique_finset n ↔ G.is_n_clique n s := +mem_filter.trans $ and_iff_right $ mem_univ _ + +@[simp] lemma clique_finset_eq_empty_iff : G.clique_finset n = ∅ ↔ G.clique_free n := +by simp_rw [clique_free, eq_empty_iff_forall_not_mem, mem_clique_finset_iff] + +alias clique_finset_eq_empty_iff ↔ _ simple_graph.clique_free.clique_finset + +attribute [protected] clique_free.clique_finset + +variables {G} [decidable_rel H.adj] + +lemma clique_finset_mono (h : G ≤ H) : G.clique_finset n ⊆ H.clique_finset n := +monotone_filter_right _ $ λ _, is_n_clique.mono h + +end clique_finset end simple_graph diff --git a/src/data/set/pairwise.lean b/src/data/set/pairwise.lean index 292a83e08eff7..9f129c8460bf8 100644 --- a/src/data/set/pairwise.lean +++ b/src/data/set/pairwise.lean @@ -179,6 +179,11 @@ by simp [pairwise_insert_of_symmetric hr] lemma pairwise_univ : (univ : set α).pairwise r ↔ pairwise r := by simp only [set.pairwise, pairwise, mem_univ, forall_const] +@[simp] lemma pairwise_bot_iff : s.pairwise (⊥ : α → α → Prop) ↔ (s : set α).subsingleton := +⟨λ h a ha b hb, h.eq ha hb id, λ h, h.pairwise _⟩ + +alias pairwise_bot_iff ↔ set.pairwise.subsingleton _ + lemma pairwise.on_injective (hs : s.pairwise r) (hf : function.injective f) (hfs : ∀ x, f x ∈ s) : pairwise (r on f) := From b7cba57674fc37bca24fa9f3da3939db6e434ddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Thu, 21 Apr 2022 17:29:16 +0000 Subject: [PATCH 139/373] chore(set_theory/game/*): Protect ambiguous lemmas (#13557) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Protect `pgame.neg_zero` and inline `pgame.add_le_add_left` and friends into `covariant_class` instances. Co-authored-by: Violeta Hernández --- src/set_theory/game/basic.lean | 24 ++++---- src/set_theory/game/impartial.lean | 6 +- src/set_theory/game/pgame.lean | 97 ++++++++++++++++-------------- src/set_theory/surreal/basic.lean | 32 +++++----- src/set_theory/surreal/dyadic.lean | 14 ++--- 5 files changed, 92 insertions(+), 81 deletions(-) diff --git a/src/set_theory/game/basic.lean b/src/set_theory/game/basic.lean index f58729e041508..2c2691ecea4fe 100644 --- a/src/set_theory/game/basic.lean +++ b/src/set_theory/game/basic.lean @@ -22,6 +22,8 @@ not imply `(x*z).equiv (y*z)`. Hence, multiplication is not a well-defined opera Nevertheless, the abelian group structure on games allows us to simplify many proofs for pre-games. -/ +open function + universes u local infix ` ≈ ` := pgame.equiv @@ -145,8 +147,11 @@ instance : add_comm_group game := { ..game.add_comm_semigroup, ..game.add_group } -theorem add_le_add_left : ∀ (a b : game), a ≤ b → ∀ (c : game), c + a ≤ c + b := -begin rintro ⟨a⟩ ⟨b⟩ h ⟨c⟩, apply pgame.add_le_add_left h, end +instance covariant_class_add_le : covariant_class game game (+) (≤) := +⟨begin rintro ⟨a⟩ ⟨b⟩ ⟨c⟩ h, exact @add_le_add_left _ _ _ _ b c h a end⟩ + +instance covariant_class_swap_add_le : covariant_class game game (swap (+)) (≤) := +⟨begin rintro ⟨a⟩ ⟨b⟩ ⟨c⟩ h, exact @add_le_add_right _ _ _ _ b c h a end⟩ -- While it is very tempting to define a `partial_order` on games, and prove -- that games form an `ordered_add_comm_group`, it is a bit dangerous. @@ -169,7 +174,7 @@ def game_partial_order : partial_order game := /-- The `<` operation provided by this `ordered_add_comm_group` is not the usual `<` on games! -/ def ordered_add_comm_group_game : ordered_add_comm_group game := -{ add_le_add_left := add_le_add_left, +{ add_le_add_left := @add_le_add_left _ _ _ game.covariant_class_add_le, ..game.add_comm_group, ..game_partial_order } @@ -277,18 +282,15 @@ begin ... ≃ yl × xr ⊕ yr × xl : equiv.sum_congr (equiv.prod_comm _ _) (equiv.prod_comm _ _), { rintro (⟨i, j⟩ | ⟨i, j⟩), { change ⟦xL i * y⟧ + ⟦x * yL j⟧ - ⟦xL i * yL j⟧ = ⟦yL j * x⟧ + ⟦y * xL i⟧ - ⟦yL j * xL i⟧, - rw [quot_mul_comm (xL i) y, quot_mul_comm x (yL j), quot_mul_comm (xL i) (yL j)], - abel }, + rw [quot_mul_comm (xL i) y, quot_mul_comm x (yL j), quot_mul_comm (xL i) (yL j), add_comm] }, { change ⟦xR i * y⟧ + ⟦x * yR j⟧ - ⟦xR i * yR j⟧ = ⟦yR j * x⟧ + ⟦y * xR i⟧ - ⟦yR j * xR i⟧, - rw [quot_mul_comm (xR i) y, quot_mul_comm x (yR j), quot_mul_comm (xR i) (yR j)], - abel } }, + rw [quot_mul_comm (xR i) y, quot_mul_comm x (yR j), quot_mul_comm (xR i) (yR j), + add_comm] } }, { rintro (⟨j, i⟩ | ⟨j, i⟩), { change ⟦xR i * y⟧ + ⟦x * yL j⟧ - ⟦xR i * yL j⟧ = ⟦yL j * x⟧ + ⟦y * xR i⟧ - ⟦yL j * xR i⟧, - rw [quot_mul_comm (xR i) y, quot_mul_comm x (yL j), quot_mul_comm (xR i) (yL j)], - abel }, + rw [quot_mul_comm (xR i) y, quot_mul_comm x (yL j), quot_mul_comm (xR i) (yL j), add_comm] }, { change ⟦xL i * y⟧ + ⟦x * yR j⟧ - ⟦xL i * yR j⟧ = ⟦yR j * x⟧ + ⟦y * xL i⟧ - ⟦yR j * xL i⟧, - rw [quot_mul_comm (xL i) y, quot_mul_comm x (yR j), quot_mul_comm (xL i) (yR j)], - abel } } + rw [quot_mul_comm (xL i) y, quot_mul_comm x (yR j), quot_mul_comm (xL i) (yR j), add_comm] } } end using_well_founded { dec_tac := pgame_wf_tac } diff --git a/src/set_theory/game/impartial.lean b/src/set_theory/game/impartial.lean index bb2005f648e98..7ca38792a2a04 100644 --- a/src/set_theory/game/impartial.lean +++ b/src/set_theory/game/impartial.lean @@ -107,12 +107,12 @@ begin { cases hl with hpos hnonneg, rw ←not_lt at hnonneg, have hneg := lt_of_lt_of_equiv hpos (neg_equiv_self G), - rw [lt_iff_neg_gt, neg_neg, neg_zero] at hneg, + rw [lt_iff_neg_gt, neg_neg, pgame.neg_zero] at hneg, contradiction }, { cases hr with hnonpos hneg, rw ←not_lt at hnonpos, have hpos := lt_of_equiv_of_lt (neg_equiv_self G).symm hneg, - rw [lt_iff_neg_gt, neg_neg, neg_zero] at hpos, + rw [lt_iff_neg_gt, neg_neg, pgame.neg_zero] at hpos, contradiction }, { left, assumption }, { right, assumption } @@ -152,7 +152,7 @@ lemma le_zero_iff {G : pgame} [G.impartial] : G ≤ 0 ↔ 0 ≤ G := by rw [le_zero_iff_zero_le_neg, le_congr (equiv_refl 0) (neg_equiv_self G)] lemma lt_zero_iff {G : pgame} [G.impartial] : G < 0 ↔ 0 < G := -by rw [lt_iff_neg_gt, neg_zero, lt_congr (equiv_refl 0) (neg_equiv_self G)] +by rw [lt_iff_neg_gt, pgame.neg_zero, lt_congr (equiv_refl 0) (neg_equiv_self G)] lemma first_loses_symm (G : pgame) [G.impartial] : G.first_loses ↔ G ≤ 0 := ⟨and.left, λ h, ⟨h, le_zero_iff.1 h⟩⟩ diff --git a/src/set_theory/game/pgame.lean b/src/set_theory/game/pgame.lean index 26a0efedb5c02..4926c1feea896 100644 --- a/src/set_theory/game/pgame.lean +++ b/src/set_theory/game/pgame.lean @@ -104,6 +104,8 @@ An interested reader may like to formalise some of the material from * [André Joyal, *Remarques sur la théorie des jeux à deux personnes*][joyal1997] -/ +open function + universes u /-- The type of pre-games, before we have quotiented @@ -479,6 +481,8 @@ inductive restricted : pgame.{u} → pgame.{u} → Type (u+1) (λ i, restricted.refl _) (λ j, restricted.refl _) using_well_founded { dec_tac := pgame_wf_tac } +instance (x : pgame) : inhabited (restricted x x) := ⟨restricted.refl _⟩ + -- TODO trans for restricted theorem restricted.le : Π {x y : pgame} (r : restricted x y), x ≤ y @@ -504,7 +508,7 @@ inductive relabelling : pgame.{u} → pgame.{u} → Type (u+1) /-- If `x` is a relabelling of `y`, then Left and Right have the same moves in either game, so `x` is a restriction of `y`. -/ -def relabelling.restricted: Π {x y : pgame} (r : relabelling x y), restricted x y +def relabelling.restricted : Π {x y : pgame} (r : relabelling x y), restricted x y | (mk xl xr xL xR) (mk yl yr yL yR) (relabelling.mk L_equiv R_equiv L_relabelling R_relabelling) := restricted.mk L_equiv.to_embedding R_equiv.symm.to_embedding (λ i, (L_relabelling i).restricted) @@ -521,6 +525,8 @@ restricted.mk L_equiv.to_embedding R_equiv.symm.to_embedding (λ i, relabelling.refl _) (λ j, relabelling.refl _) using_well_founded { dec_tac := pgame_wf_tac } +instance (x : pgame) : inhabited (relabelling x x) := ⟨relabelling.refl _⟩ + /-- Reverse a relabelling. -/ @[symm] def relabelling.symm : Π {x y : pgame}, relabelling x y → relabelling y x | (mk xl xr xL xR) (mk yl yr yL yR) (relabelling.mk L_equiv R_equiv L_relabelling R_relabelling) := @@ -587,14 +593,15 @@ instance : has_neg pgame := ⟨neg⟩ @[simp] lemma neg_def {xl xr xL xR} : -(mk xl xr xL xR) = mk xr xl (λ j, -(xR j)) (λ i, -(xL i)) := rfl -@[simp] theorem neg_neg : Π {x : pgame}, -(-x) = x -| (mk xl xr xL xR) := -begin - dsimp [has_neg.neg, neg], - congr; funext i; apply neg_neg -end +instance : has_involutive_neg pgame := +{ neg_neg := λ x, begin + induction x with xl xr xL xR ihL ihR, + simp_rw [neg_def, ihL, ihR], + exact ⟨rfl, rfl, heq.rfl, heq.rfl⟩, + end, + ..pgame.has_neg } -@[simp] theorem neg_zero : -(0 : pgame) = 0 := +@[simp] protected lemma neg_zero : -(0 : pgame) = 0 := begin dsimp [has_zero.zero, has_neg.neg, neg], congr; funext i; cases i @@ -613,7 +620,7 @@ by { cases x, refl } move_right x ((left_moves_neg x) i) = -(move_left (-x) i) := begin induction x, - exact neg_neg.symm + exact (neg_neg _).symm end @[simp] lemma move_left_left_moves_neg_symm {x : pgame} (i : right_moves x) : move_left (-x) ((left_moves_neg x).symm i) = -(move_right x i) := @@ -622,7 +629,7 @@ by { cases x, refl } move_left x ((right_moves_neg x) i) = -(move_right (-x) i) := begin induction x, - exact neg_neg.symm + exact (neg_neg _).symm end @[simp] lemma move_right_right_moves_neg_symm {x : pgame} (i : left_moves x) : move_right (-x) ((right_moves_neg x).symm i) = -(move_left x i) := @@ -683,13 +690,13 @@ end theorem zero_le_iff_neg_le_zero {x : pgame} : 0 ≤ x ↔ -x ≤ 0 := begin convert le_iff_neg_ge, - rw neg_zero + rw pgame.neg_zero end theorem le_zero_iff_zero_le_neg {x : pgame} : x ≤ 0 ↔ 0 ≤ -x := begin convert le_iff_neg_ge, - rw neg_zero + rw pgame.neg_zero end /-- The sum of `x = {xL | xR}` and `y = {yL | yR}` is `{xL + y, x + yL | xR + y, x + yR}`. -/ @@ -871,7 +878,7 @@ using_well_founded { dec_tac := pgame_wf_tac } theorem add_assoc_equiv {x y z : pgame} : (x + y) + z ≈ x + (y + z) := (add_assoc_relabelling x y z).equiv -theorem add_le_add_right : Π {x y z : pgame} (h : x ≤ y), x + z ≤ y + z +private lemma add_le_add_right : Π {x y z : pgame} (h : x ≤ y), x + z ≤ y + z | (mk xl xr xL xR) (mk yl yr yL yR) (mk zl zr zL zR) := begin intros h, @@ -920,16 +927,19 @@ begin end using_well_founded { dec_tac := pgame_wf_tac } -theorem add_le_add_left {x y z : pgame} (h : y ≤ z) : x + y ≤ x + z := -calc x + y ≤ y + x : add_comm_le - ... ≤ z + x : add_le_add_right h - ... ≤ x + z : add_comm_le +instance covariant_class_swap_add_le : covariant_class pgame pgame (swap (+)) (≤) := +⟨λ x y z, add_le_add_right⟩ + +instance covariant_class_add_le : covariant_class pgame pgame (+) (≤) := +⟨λ x y z h, calc x + y ≤ y + x : add_comm_le + ... ≤ z + x : add_le_add_right h _ + ... ≤ x + z : add_comm_le⟩ theorem add_congr {w x y z : pgame} (h₁ : w ≈ x) (h₂ : y ≈ z) : w + y ≈ x + z := -⟨calc w + y ≤ w + z : add_le_add_left h₂.1 - ... ≤ x + z : add_le_add_right h₁.1, - calc x + z ≤ x + y : add_le_add_left h₂.2 - ... ≤ w + y : add_le_add_right h₁.2⟩ +⟨calc w + y ≤ w + z : add_le_add_left h₂.1 _ + ... ≤ x + z : add_le_add_right h₁.1 _, + calc x + z ≤ x + y : add_le_add_left h₂.2 _ + ... ≤ w + y : add_le_add_right h₁.2 _⟩ theorem sub_congr {w x y z : pgame} (h₁ : w ≈ x) (h₂ : y ≈ z) : w - y ≈ x - z := add_congr h₁ (neg_congr h₂) @@ -960,7 +970,7 @@ using_well_founded { dec_tac := pgame_wf_tac } theorem zero_le_add_left_neg : Π {x : pgame}, 0 ≤ (-x) + x := begin intro x, - rw [le_iff_neg_ge, neg_zero], + rw [le_iff_neg_ge, pgame.neg_zero], exact le_trans neg_add_le add_left_neg_le_zero end @@ -978,37 +988,36 @@ calc 0 ≤ (-x) + x : zero_le_add_left_neg theorem add_right_neg_equiv {x : pgame} : x + (-x) ≈ 0 := ⟨add_right_neg_le_zero, zero_le_add_right_neg⟩ -theorem add_lt_add_right {x y z : pgame} (h : x < y) : x + z < y + z := -suffices y + z ≤ x + z → y ≤ x, by { rw ←not_le at ⊢ h, exact mt this h }, -assume w, -calc y ≤ y + 0 : (add_zero_relabelling _).symm.le - ... ≤ y + (z + -z) : add_le_add_left zero_le_add_right_neg - ... ≤ (y + z) + (-z) : (add_assoc_relabelling _ _ _).symm.le - ... ≤ (x + z) + (-z) : add_le_add_right w - ... ≤ x + (z + -z) : (add_assoc_relabelling _ _ _).le - ... ≤ x + 0 : add_le_add_left add_right_neg_le_zero - ... ≤ x : (add_zero_relabelling _).le - -theorem add_lt_add_left {x y z : pgame} (h : y < z) : x + y < x + z := -calc x + y ≤ y + x : add_comm_le - ... < z + x : add_lt_add_right h - ... ≤ x + z : add_comm_le +instance covariant_class_swap_add_lt : covariant_class pgame pgame (swap (+)) (<) := +⟨λ x y z h, suffices z + x ≤ y + x → z ≤ y, by { rw ←not_le at ⊢ h, exact mt this h }, λ w, + calc z ≤ z + 0 : (add_zero_relabelling _).symm.le + ... ≤ z + (x + -x) : add_le_add_left zero_le_add_right_neg _ + ... ≤ z + x + -x : (add_assoc_relabelling _ _ _).symm.le + ... ≤ y + x + -x : add_le_add_right w _ + ... ≤ y + (x + -x) : (add_assoc_relabelling _ _ _).le + ... ≤ y + 0 : add_le_add_left add_right_neg_le_zero _ + ... ≤ y : (add_zero_relabelling _).le⟩ + +instance covariant_class_add_lt : covariant_class pgame pgame (+) (<) := +⟨λ x y z h, calc x + y ≤ y + x : add_comm_le + ... < z + x : add_lt_add_right h _ + ... ≤ x + z : add_comm_le⟩ theorem le_iff_sub_nonneg {x y : pgame} : x ≤ y ↔ 0 ≤ y - x := -⟨λ h, le_trans zero_le_add_right_neg (add_le_add_right h), +⟨λ h, le_trans zero_le_add_right_neg (add_le_add_right h _), λ h, calc x ≤ 0 + x : (zero_add_relabelling x).symm.le - ... ≤ (y - x) + x : add_le_add_right h + ... ≤ y - x + x : add_le_add_right h _ ... ≤ y + (-x + x) : (add_assoc_relabelling _ _ _).le - ... ≤ y + 0 : add_le_add_left (add_left_neg_le_zero) + ... ≤ y + 0 : add_le_add_left (add_left_neg_le_zero) _ ... ≤ y : (add_zero_relabelling y).le⟩ theorem lt_iff_sub_pos {x y : pgame} : x < y ↔ 0 < y - x := -⟨λ h, lt_of_le_of_lt zero_le_add_right_neg (add_lt_add_right h), +⟨λ h, lt_of_le_of_lt zero_le_add_right_neg (add_lt_add_right h _), λ h, calc x ≤ 0 + x : (zero_add_relabelling x).symm.le - ... < (y - x) + x : add_lt_add_right h + ... < y - x + x : add_lt_add_right h _ ... ≤ y + (-x + x) : (add_assoc_relabelling _ _ _).le - ... ≤ y + 0 : add_le_add_left (add_left_neg_le_zero) + ... ≤ y + 0 : add_le_add_left (add_left_neg_le_zero) _ ... ≤ y : (add_zero_relabelling y).le⟩ /-- The pre-game `star`, which is fuzzy/confused with zero. -/ @@ -1039,7 +1048,7 @@ def half : pgame := ⟨punit, punit, 0, 1⟩ @[simp] lemma half_move_right : half.move_right punit.star = 1 := rfl -theorem zero_lt_half : 0 < half := +protected theorem zero_lt_half : 0 < half := begin rw lt_def, left, diff --git a/src/set_theory/surreal/basic.lean b/src/set_theory/surreal/basic.lean index 7545656a8a66c..60ec8e90bb428 100644 --- a/src/set_theory/surreal/basic.lean +++ b/src/set_theory/surreal/basic.lean @@ -144,27 +144,27 @@ begin { left, use (left_moves_add x z).symm (sum.inl ix), simp only [add_move_left_inl], - calc w + y ≤ move_left x ix + y : add_le_add_right hix - ... ≤ move_left x ix + move_left z iz : add_le_add_left hiz - ... ≤ move_left x ix + z : add_le_add_left (oz.move_left_le iz) }, + calc w + y ≤ move_left x ix + y : add_le_add_right hix _ + ... ≤ move_left x ix + move_left z iz : add_le_add_left hiz _ + ... ≤ move_left x ix + z : add_le_add_left (oz.move_left_le iz) _ }, { left, use (left_moves_add x z).symm (sum.inl ix), simp only [add_move_left_inl], - calc w + y ≤ move_left x ix + y : add_le_add_right hix - ... ≤ move_left x ix + move_right y jy : add_le_add_left (oy.le_move_right jy) - ... ≤ move_left x ix + z : add_le_add_left hjy }, + calc w + y ≤ move_left x ix + y : add_le_add_right hix _ + ... ≤ move_left x ix + move_right y jy : add_le_add_left (oy.le_move_right jy) _ + ... ≤ move_left x ix + z : add_le_add_left hjy _ }, { right, use (right_moves_add w y).symm (sum.inl jw), simp only [add_move_right_inl], - calc move_right w jw + y ≤ x + y : add_le_add_right hjw - ... ≤ x + move_left z iz : add_le_add_left hiz - ... ≤ x + z : add_le_add_left (oz.move_left_le iz), }, + calc move_right w jw + y ≤ x + y : add_le_add_right hjw _ + ... ≤ x + move_left z iz : add_le_add_left hiz _ + ... ≤ x + z : add_le_add_left (oz.move_left_le iz) _ }, { right, use (right_moves_add w y).symm (sum.inl jw), simp only [add_move_right_inl], - calc move_right w jw + y ≤ x + y : add_le_add_right hjw - ... ≤ x + move_right y jy : add_le_add_left (oy.le_move_right jy) - ... ≤ x + z : add_le_add_left hjy, }, + calc move_right w jw + y ≤ x + y : add_le_add_right hjw _ + ... ≤ x + move_right y jy : add_le_add_left (oy.le_move_right jy) _ + ... ≤ x + z : add_le_add_left hjy _ }, end theorem numeric_add : Π {x y : pgame} (ox : numeric x) (oy : numeric y), numeric (x + y) @@ -172,13 +172,13 @@ theorem numeric_add : Π {x y : pgame} (ox : numeric x) (oy : numeric y), numeri ⟨begin rintros (ix|iy) (jx|jy), { show xL ix + ⟨yl, yr, yL, yR⟩ < xR jx + ⟨yl, yr, yL, yR⟩, - exact add_lt_add_right (ox.1 ix jx), }, + exact add_lt_add_right (ox.1 ix jx) _ }, { show xL ix + ⟨yl, yr, yL, yR⟩ < ⟨xl, xr, xL, xR⟩ + yR jy, exact add_lt_add oy (oy.move_right jy) (ox.move_left_lt _) (oy.lt_move_right _), }, { -- show ⟨xl, xr, xL, xR⟩ + yL iy < xR jx + ⟨yl, yr, yL, yR⟩, -- fails? exact add_lt_add (oy.move_left iy) oy (ox.lt_move_right _) (oy.move_left_lt _), }, { -- show ⟨xl, xr, xL, xR⟩ + yL iy < ⟨xl, xr, xL, xR⟩ + yR jy, -- fails? - exact @add_lt_add_left ⟨xl, xr, xL, xR⟩ _ _ (oy.1 iy jy), } + exact @add_lt_add_left pgame _ _ _ _ _ (oy.1 iy jy) ⟨xl, xr, xL, xR⟩ } end, begin split, @@ -233,7 +233,7 @@ begin { rintro ⟨ ⟩, left, use (sum.inl punit.star), - calc 0 ≤ half : le_of_lt numeric_zero numeric_half zero_lt_half + calc 0 ≤ half : le_of_lt numeric_zero numeric_half pgame.zero_lt_half ... ≈ 0 + half : (zero_add_equiv half).symm ... = (half + half).move_left (sum.inl punit.star) : by fsplit }, { rintro (⟨⟨ ⟩⟩ | ⟨⟨ ⟩⟩); left, @@ -327,7 +327,7 @@ instance : ordered_add_comm_group surreal := le_trans := by { rintros ⟨_⟩ ⟨_⟩ ⟨_⟩, exact pgame.le_trans }, lt_iff_le_not_le := by { rintros ⟨_, ox⟩ ⟨_, oy⟩, exact pgame.lt_iff_le_not_le ox oy }, le_antisymm := by { rintros ⟨_⟩ ⟨_⟩ h₁ h₂, exact quotient.sound ⟨h₁, h₂⟩ }, - add_le_add_left := by { rintros ⟨_⟩ ⟨_⟩ hx ⟨_⟩, exact pgame.add_le_add_left hx } } + add_le_add_left := by { rintros ⟨_⟩ ⟨_⟩ hx ⟨_⟩, exact @add_le_add_left pgame _ _ _ _ _ hx _ } } noncomputable instance : linear_ordered_add_comm_group surreal := { le_total := by rintro ⟨⟨x, ox⟩⟩ ⟨⟨y, oy⟩⟩; classical; exact diff --git a/src/set_theory/surreal/dyadic.lean b/src/set_theory/surreal/dyadic.lean index c03bd59a2675f..b57c4e895e5ea 100644 --- a/src/set_theory/surreal/dyadic.lean +++ b/src/set_theory/surreal/dyadic.lean @@ -97,19 +97,19 @@ begin right, use sum.inl punit.star, calc pow_half (n.succ) + pow_half (n.succ + 1) - ≤ pow_half (n.succ) + pow_half (n.succ) : add_le_add_left pow_half_succ_le_pow_half + ≤ pow_half (n.succ) + pow_half (n.succ) : add_le_add_left pow_half_succ_le_pow_half _ ... ≈ pow_half n : hn }, { rintro ⟨ ⟩, calc 0 ≈ 0 + 0 : (add_zero_equiv _).symm - ... ≤ pow_half (n.succ + 1) + 0 : add_le_add_right zero_le_pow_half - ... < pow_half (n.succ + 1) + pow_half (n.succ + 1) : add_lt_add_left zero_lt_pow_half }, + ... ≤ pow_half (n.succ + 1) + 0 : add_le_add_right zero_le_pow_half _ + ... < pow_half (n.succ + 1) + pow_half (n.succ + 1) : add_lt_add_left zero_lt_pow_half _ }, { rintro (⟨⟨ ⟩⟩ | ⟨⟨ ⟩⟩), { calc pow_half n.succ - ≈ pow_half n.succ + 0 : (add_zero_equiv _).symm - ... < pow_half (n.succ) + pow_half (n.succ + 1) : add_lt_add_left zero_lt_pow_half }, + ≈ pow_half n.succ + 0 : (add_zero_equiv _).symm + ... < pow_half (n.succ) + pow_half (n.succ + 1) : add_lt_add_left zero_lt_pow_half _ }, { calc pow_half n.succ - ≈ 0 + pow_half n.succ : (zero_add_equiv _).symm - ... < pow_half (n.succ + 1) + pow_half (n.succ) : add_lt_add_right zero_lt_pow_half }}} + ≈ 0 + pow_half n.succ : (zero_add_equiv _).symm + ... < pow_half (n.succ + 1) + pow_half (n.succ) : add_lt_add_right zero_lt_pow_half _ } } } end end pgame From 3a061790136d13594ec10c7c90d202335ac5d854 Mon Sep 17 00:00:00 2001 From: Jakob von Raumer Date: Thu, 21 Apr 2022 20:30:49 +0000 Subject: [PATCH 140/373] refactor(category_theory): reverse simp lemmas about (co)forks (#13519) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes `fork.ι` instead of `t.π.app zero` so that we avoid any unnecessary references to `walking_parallel_pair` in (co)fork homs. This induces quite a lot of changes in other files, but I think it's worth the pain. The PR also changes `fork.is_limit.mk` to avoid stating redundant morphisms. --- src/algebra/category/Module/kernels.lean | 10 +- .../normed/group/SemiNormedGroup/kernels.lean | 10 +- src/category_theory/abelian/basic.lean | 4 +- .../abelian/non_preadditive.lean | 2 +- src/category_theory/idempotents/basic.lean | 8 +- .../limits/preserves/shapes/equalizers.lean | 10 +- .../limits/preserves/shapes/kernels.lean | 7 +- .../limits/shapes/biproducts.lean | 42 ++--- .../limits/shapes/equalizers.lean | 150 +++++++++--------- .../limits/shapes/kernel_pair.lean | 4 +- .../limits/shapes/kernels.lean | 22 +-- .../limits/shapes/multiequalizer.lean | 71 ++++----- .../limits/shapes/normal_mono/equalizers.lean | 12 +- .../limits/shapes/regular_mono.lean | 4 +- .../limits/shapes/split_coequalizer.lean | 5 +- src/category_theory/monad/coequalizer.lean | 7 +- src/category_theory/monad/monadicity.lean | 10 +- src/category_theory/preadditive/default.lean | 8 +- src/category_theory/sites/limits.lean | 4 +- src/category_theory/sites/sheaf.lean | 2 +- .../pairwise_intersections.lean | 3 +- 21 files changed, 198 insertions(+), 197 deletions(-) diff --git a/src/algebra/category/Module/kernels.lean b/src/algebra/category/Module/kernels.lean index 6c48b46f78f0f..6ec79a873ac7f 100644 --- a/src/algebra/category/Module/kernels.lean +++ b/src/algebra/category/Module/kernels.lean @@ -11,7 +11,6 @@ import algebra.category.Module.epi_mono open category_theory open category_theory.limits -open category_theory.limits.walking_parallel_pair universes u v @@ -32,10 +31,7 @@ fork.is_limit.mk _ by { rw [←@function.comp_apply _ _ _ f (fork.ι s) c, ←coe_comp, fork.condition, has_zero_morphisms.comp_zero (fork.ι s) N], refl })) (λ s, linear_map.subtype_comp_cod_restrict _ _ _) - (λ s m h, linear_map.ext $ λ x, subtype.ext_iff_val.2 $ - have h₁ : (m ≫ (kernel_cone f).π.app zero).to_fun = (s.π.app zero).to_fun, - by { congr, exact h zero }, - by convert @congr_fun _ _ _ _ h₁ x ) + (λ s m h, linear_map.ext $ λ x, subtype.ext_iff_val.2 (by simpa [←h])) /-- The cokernel cocone induced by the projection onto the quotient. -/ def cokernel_cocone : cokernel_cofork f := @@ -50,7 +46,7 @@ cofork.is_colimit.mk _ begin haveI : epi (as_hom f.range.mkq) := (epi_iff_range_eq_top _).mpr (submodule.range_mkq _), apply (cancel_epi (as_hom f.range.mkq)).1, - convert h walking_parallel_pair.one, + convert h, exact submodule.liftq_mkq _ _ _ end) end @@ -86,7 +82,7 @@ limit.iso_limit_cone_inv_π _ _ @[simp, elementwise] lemma kernel_iso_ker_hom_ker_subtype : (kernel_iso_ker f).hom ≫ f.ker.subtype = kernel.ι f := -is_limit.cone_point_unique_up_to_iso_inv_comp _ (limit.is_limit _) zero +is_limit.cone_point_unique_up_to_iso_inv_comp _ (limit.is_limit _) walking_parallel_pair.zero /-- The categorical cokernel of a morphism in `Module` diff --git a/src/analysis/normed/group/SemiNormedGroup/kernels.lean b/src/analysis/normed/group/SemiNormedGroup/kernels.lean index 1769c78efedd5..29102a8b0c423 100644 --- a/src/analysis/normed/group/SemiNormedGroup/kernels.lean +++ b/src/analysis/normed/group/SemiNormedGroup/kernels.lean @@ -86,8 +86,7 @@ namespace SemiNormedGroup section equalizers_and_kernels /-- The equalizer cone for a parallel pair of morphisms of seminormed groups. -/ -def parallel_pair_cone {V W : SemiNormedGroup.{u}} (f g : V ⟶ W) : - cone (parallel_pair f g) := +def fork {V W : SemiNormedGroup.{u}} (f g : V ⟶ W) : fork f g := @fork.of_ι _ _ _ _ _ _ (of (f - g).ker) (normed_group_hom.incl (f - g).ker) $ begin ext v, @@ -100,7 +99,7 @@ end instance has_limit_parallel_pair {V W : SemiNormedGroup.{u}} (f g : V ⟶ W) : has_limit (parallel_pair f g) := { exists_limit := nonempty.intro - { cone := parallel_pair_cone f g, + { cone := fork f g, is_limit := fork.is_limit.mk _ (λ c, normed_group_hom.ker.lift (fork.ι c) _ $ show normed_group_hom.comp_hom (f - g) c.ι = 0, @@ -297,7 +296,7 @@ def explicit_cokernel_iso {X Y : SemiNormedGroup.{u}} (f : X ⟶ Y) : @[simp] lemma explicit_cokernel_iso_hom_π {X Y : SemiNormedGroup.{u}} (f : X ⟶ Y) : explicit_cokernel_π f ≫ (explicit_cokernel_iso f).hom = cokernel.π _ := -by simp [explicit_cokernel_π, explicit_cokernel_iso] +by simp [explicit_cokernel_π, explicit_cokernel_iso, is_colimit.cocone_point_unique_up_to_iso] @[simp] lemma explicit_cokernel_iso_inv_π {X Y : SemiNormedGroup.{u}} (f : X ⟶ Y) : @@ -310,7 +309,8 @@ lemma explicit_cokernel_iso_hom_desc {X Y Z : SemiNormedGroup.{u}} {f : X ⟶ Y} (explicit_cokernel_iso f).hom ≫ cokernel.desc f g w = explicit_cokernel_desc w := begin ext1, - simp [explicit_cokernel_desc, explicit_cokernel_π, explicit_cokernel_iso], + simp [explicit_cokernel_desc, explicit_cokernel_π, explicit_cokernel_iso, + is_colimit.cocone_point_unique_up_to_iso], end /-- A special case of `category_theory.limits.cokernel.map` adapted to `explicit_cokernel`. -/ diff --git a/src/category_theory/abelian/basic.lean b/src/category_theory/abelian/basic.lean index 3bff58debf47f..ad4d7f56e058e 100644 --- a/src/category_theory/abelian/basic.lean +++ b/src/category_theory/abelian/basic.lean @@ -498,7 +498,7 @@ fork.is_limit.mk _ { rw [biprod.lift_fst, pullback.lift_fst] }, { rw [biprod.lift_snd, pullback.lift_snd] } end) - (λ s m h, by ext; simp [fork.ι_eq_app_zero, ←h walking_parallel_pair.zero]) + (λ s m h, by ext; simp [←h]) end pullback_to_biproduct_is_kernel @@ -523,7 +523,7 @@ cofork.is_colimit.mk _ sub_eq_zero.1 $ by rw [←category.assoc, ←category.assoc, ←sub_comp, sub_eq_add_neg, ←neg_comp, ←biprod.lift_eq, cofork.condition s, zero_comp]) (λ s, by ext; simp) - (λ s m h, by ext; simp [cofork.π_eq_app_one, ←h walking_parallel_pair.one] ) + (λ s m h, by ext; simp [←h] ) end biproduct_to_pushout_is_cokernel diff --git a/src/category_theory/abelian/non_preadditive.lean b/src/category_theory/abelian/non_preadditive.lean index ad4af162f700d..3b86071992c8c 100644 --- a/src/category_theory/abelian/non_preadditive.lean +++ b/src/category_theory/abelian/non_preadditive.lean @@ -230,7 +230,7 @@ begin { intros s m h, haveI : mono (prod.lift (𝟙 A) (0 : A ⟶ A)) := mono_of_mono_fac (prod.lift_fst _ _), apply (cancel_mono (prod.lift (𝟙 A) (0 : A ⟶ A))).1, - convert h walking_parallel_pair.zero, + convert h, ext; simp } }, let hp2 : is_colimit (cokernel_cofork.of_π (limits.prod.snd : A ⨯ A ⟶ A) hlp), { exact epi_is_cokernel_of_kernel _ hp1 }, diff --git a/src/category_theory/idempotents/basic.lean b/src/category_theory/idempotents/basic.lean index 481434a99733f..a19ef233af3e8 100644 --- a/src/category_theory/idempotents/basic.lean +++ b/src/category_theory/idempotents/basic.lean @@ -68,10 +68,10 @@ begin split, { erw [assoc, h₂, ← limits.fork.condition s, comp_id], }, { intros m hm, - erw [← hm], - simp only [← hm, assoc, fork.ι_eq_app_zero, - fork.of_ι_π_app, h₁], - erw comp_id m, } + rw fork.ι_of_ι at hm, + rw [← hm], + simp only [← hm, assoc, h₁], + exact (comp_id m).symm } end }⟩, }, { intro h, refine ⟨_⟩, diff --git a/src/category_theory/limits/preserves/shapes/equalizers.lean b/src/category_theory/limits/preserves/shapes/equalizers.lean index c2af61a3abd0f..a499268a22f5d 100644 --- a/src/category_theory/limits/preserves/shapes/equalizers.lean +++ b/src/category_theory/limits/preserves/shapes/equalizers.lean @@ -39,7 +39,7 @@ def is_limit_map_cone_fork_equiv : is_limit (G.map_cone (fork.of_ι h w)) ≃ is_limit (fork.of_ι (G.map h) (by simp only [←G.map_comp, w]) : fork (G.map f) (G.map g)) := (is_limit.postcompose_hom_equiv (diagram_iso_parallel_pair.{v} _) _).symm.trans - (is_limit.equiv_iso_limit (fork.ext (iso.refl _) (by simp))) + (is_limit.equiv_iso_limit (fork.ext (iso.refl _) (by { simp [fork.ι] }))) /-- The property of preserving equalizers expressed in terms of forks. -/ def is_limit_fork_map_of_is_limit [preserves_limit (parallel_pair f g) G] @@ -115,8 +115,12 @@ This essentially lets us commute `cofork.of_π` with `functor.map_cocone`. def is_colimit_map_cocone_cofork_equiv : is_colimit (G.map_cocone (cofork.of_π h w)) ≃ is_colimit (cofork.of_π (G.map h) (by simp only [←G.map_comp, w]) : cofork (G.map f) (G.map g)) := -(is_colimit.precompose_inv_equiv (diagram_iso_parallel_pair.{v} _) _).symm.trans - (is_colimit.equiv_iso_colimit (cofork.ext (iso.refl _) (by { dsimp, simp }))) +(is_colimit.precompose_inv_equiv (diagram_iso_parallel_pair.{v} _) _).symm.trans $ +is_colimit.equiv_iso_colimit $ cofork.ext (iso.refl _) $ +begin + dsimp only [cofork.π, cofork.of_π_ι_app], + dsimp, rw [category.comp_id, category.id_comp] +end /-- The property of preserving coequalizers expressed in terms of coforks. -/ def is_colimit_cofork_map_of_is_colimit [preserves_colimit (parallel_pair f g) G] diff --git a/src/category_theory/limits/preserves/shapes/kernels.lean b/src/category_theory/limits/preserves/shapes/kernels.lean index 9b00de49ade9c..21448cec3dca3 100644 --- a/src/category_theory/limits/preserves/shapes/kernels.lean +++ b/src/category_theory/limits/preserves/shapes/kernels.lean @@ -48,7 +48,7 @@ begin refine (is_limit.postcompose_hom_equiv _ _).symm.trans (is_limit.equiv_iso_limit _), refine parallel_pair.ext (iso.refl _) (iso.refl _) _ _; simp, refine fork.ext (iso.refl _) _, - simp, + simp [fork.ι] end /-- @@ -137,7 +137,10 @@ begin refine (is_colimit.precompose_hom_equiv _ _).symm.trans (is_colimit.equiv_iso_colimit _), refine parallel_pair.ext (iso.refl _) (iso.refl _) _ _; simp, refine cofork.ext (iso.refl _) _, - simp, dsimp, simp, + simp only [cofork.π, iso.refl_hom, id_comp, cocones.precompose_obj_ι, + nat_trans.comp_app, parallel_pair.ext_hom_app, functor.map_cocone_ι_app, + cofork.of_π_ι_app], + apply category.comp_id end /-- diff --git a/src/category_theory/limits/shapes/biproducts.lean b/src/category_theory/limits/shapes/biproducts.lean index b97b77328f837..deba88d9fedfe 100644 --- a/src/category_theory/limits/shapes/biproducts.lean +++ b/src/category_theory/limits/shapes/biproducts.lean @@ -1408,16 +1408,7 @@ ht.hom_ext $ λ j, by { rw ht.fac, cases j; simp } bicone. -/ def is_binary_bilimit_of_is_limit {X Y : C} (t : binary_bicone X Y) (ht : is_limit t.to_cone) : t.is_bilimit := -is_binary_bilimit_of_total _ -begin - refine binary_fan.is_limit.hom_ext ht _ _, - { rw [inl_of_is_limit ht, inr_of_is_limit ht, add_comp, category.assoc, category.assoc, ht.fac, - ht.fac, binary_fan.mk_π_app_left, binary_fan.mk_π_app_left, comp_zero, add_zero, - binary_bicone.binary_fan_fst_to_cone, category.comp_id, category.id_comp] }, - { rw [inr_of_is_limit ht, inl_of_is_limit ht, add_comp, category.assoc, category.assoc, ht.fac, - ht.fac, binary_fan.mk_π_app_right, binary_fan.mk_π_app_right, comp_zero, zero_add, - binary_bicone.binary_fan_snd_to_cone, category.comp_id, category.id_comp] } -end +is_binary_bilimit_of_total _ (by refine binary_fan.is_limit.hom_ext ht _ _; simp) /-- We can turn any limit cone over a pair into a bilimit bicone. -/ def binary_bicone_is_bilimit_of_limit_cone_of_is_limit {X Y : C} {t : cone (pair X Y)} @@ -1477,15 +1468,9 @@ def is_binary_bilimit_of_is_colimit {X Y : C} (t : binary_bicone X Y) (ht : is_colimit t.to_cocone) : t.is_bilimit := is_binary_bilimit_of_total _ begin - refine binary_cofan.is_colimit.hom_ext ht _ _, - { rw [fst_of_is_colimit ht, snd_of_is_colimit ht, comp_add, ht.fac_assoc, ht.fac_assoc, - binary_cofan.mk_ι_app_left, binary_cofan.mk_ι_app_left, - binary_bicone.binary_cofan_inl_to_cocone, zero_comp, add_zero, category.id_comp t.inl, - category.comp_id t.inl] }, - { rw [fst_of_is_colimit ht, snd_of_is_colimit ht, comp_add, ht.fac_assoc, ht.fac_assoc, - binary_cofan.mk_ι_app_right, binary_cofan.mk_ι_app_right, - binary_bicone.binary_cofan_inr_to_cocone, zero_comp, zero_add, category.comp_id t.inr, - category.id_comp t.inr] } + refine binary_cofan.is_colimit.hom_ext ht _ _; simp, + { rw [category.comp_id t.inl] }, + { rw [category.comp_id t.inr] } end /-- We can turn any colimit cocone over a pair into a bilimit bicone. -/ @@ -1565,10 +1550,10 @@ def binary_bicone_of_split_mono_of_cokernel {X Y : C} {f : X ⟶ Y} [split_mono rw [split_epi_of_idempotent_of_is_colimit_cofork_section_, is_colimit_cofork_of_cokernel_cofork_desc, is_cokernel_epi_comp_desc], dsimp only [cokernel_cofork_of_cofork_of_π], - letI := epi_of_is_colimit_parallel_pair i, + letI := epi_of_is_colimit_cofork i, apply zero_of_epi_comp c.π, - simp only [sub_comp, category.comp_id, category.assoc, split_mono.id, is_colimit.fac_assoc, - cofork.of_π_ι_app, category.id_comp, cofork.π_of_π], + simp only [sub_comp, comp_sub, category.comp_id, category.assoc, split_mono.id, sub_self, + cofork.is_colimit.π_comp_desc_assoc, cokernel_cofork.π_of_π, split_mono.id_assoc], apply sub_eq_zero_of_eq, apply category.id_comp end, @@ -1586,8 +1571,8 @@ begin split_epi_of_idempotent_of_is_colimit_cofork_section_], dsimp only [binary_bicone_of_split_mono_of_cokernel_X], rw [is_colimit_cofork_of_cokernel_cofork_desc, is_cokernel_epi_comp_desc], - simp only [cofork.is_colimit.π_desc_of_π, cokernel_cofork_of_cofork_π, - cofork.π_of_π, binary_bicone_of_split_mono_of_cokernel_inl, add_sub_cancel'_right], + simp only [binary_bicone_of_split_mono_of_cokernel_inl, cofork.is_colimit.π_comp_desc, + cokernel_cofork_of_cofork_π, cofork.π_of_π, add_sub_cancel'_right] end /-- @@ -1616,10 +1601,10 @@ def binary_bicone_of_split_epi_of_kernel {X Y : C} {f : X ⟶ Y} [split_epi f] rw [split_mono_of_idempotent_of_is_limit_fork_retraction, is_limit_fork_of_kernel_fork_lift, is_kernel_comp_mono_lift], dsimp only [kernel_fork_of_fork_ι], - letI := mono_of_is_limit_parallel_pair i, + letI := mono_of_is_limit_fork i, apply zero_of_comp_mono c.ι, - simp only [comp_sub, category.comp_id, category.assoc, sub_self, fork.ι_eq_app_zero, - fork.is_limit.lift_of_ι_ι, fork.of_ι_π_app, split_epi.id_assoc] + simp only [comp_sub, category.comp_id, category.assoc, sub_self, fork.is_limit.lift_comp_ι, + fork.ι_of_ι, split_epi.id_assoc] end, inr_snd' := by simp } @@ -1635,8 +1620,7 @@ begin split_mono_of_idempotent_of_is_limit_fork_retraction], dsimp only [binary_bicone_of_split_epi_of_kernel_X], rw [is_limit_fork_of_kernel_fork_lift, is_kernel_comp_mono_lift], - simp only [fork.ι_eq_app_zero, kernel_fork.condition, comp_zero, zero_comp, eq_self_iff_true, - fork.is_limit.lift_of_ι_ι, kernel_fork_of_fork_ι, fork.of_ι_π_app, sub_add_cancel] + simp only [fork.is_limit.lift_comp_ι, fork.ι_of_ι, kernel_fork_of_fork_ι, sub_add_cancel] end end diff --git a/src/category_theory/limits/shapes/equalizers.lean b/src/category_theory/limits/shapes/equalizers.lean index a14c6643b41bb..85859db0360d1 100644 --- a/src/category_theory/limits/shapes/equalizers.lean +++ b/src/category_theory/limits/shapes/equalizers.lean @@ -217,31 +217,28 @@ variables {f g : X ⟶ Y} /-- A fork `t` on the parallel pair `f g : X ⟶ Y` consists of two morphisms `t.π.app zero : t.X ⟶ X` and `t.π.app one : t.X ⟶ Y`. Of these, only the first one is interesting, and we give it the shorter name `fork.ι t`. -/ -abbreviation fork.ι (t : fork f g) := t.π.app zero +def fork.ι (t : fork f g) := t.π.app zero + +@[simp] lemma fork.app_zero_eq_ι (t : fork f g) : t.π.app zero = t.ι := rfl /-- A cofork `t` on the parallel_pair `f g : X ⟶ Y` consists of two morphisms `t.ι.app zero : X ⟶ t.X` and `t.ι.app one : Y ⟶ t.X`. Of these, only the second one is interesting, and we give it the shorter name `cofork.π t`. -/ -abbreviation cofork.π (t : cofork f g) := t.ι.app one +def cofork.π (t : cofork f g) := t.ι.app one -@[simp] lemma fork.ι_eq_app_zero (t : fork f g) : t.ι = t.π.app zero := rfl -@[simp] lemma cofork.π_eq_app_one (t : cofork f g) : t.π = t.ι.app one := rfl +@[simp] lemma cofork.app_one_eq_π (t : cofork f g) : t.ι.app one = t.π := rfl -@[simp, reassoc] lemma fork.app_zero_left (s : fork f g) : - s.π.app zero ≫ f = s.π.app one := -by rw [←s.w left, parallel_pair_map_left] +@[simp] lemma fork.app_one_eq_ι_comp_left (s : fork f g) : s.π.app one = s.ι ≫ f := +by rw [←s.app_zero_eq_ι, ←s.w left, parallel_pair_map_left] -@[simp, reassoc] lemma fork.app_zero_right (s : fork f g) : - s.π.app zero ≫ g = s.π.app one := -by rw [←s.w right, parallel_pair_map_right] +@[reassoc] lemma fork.app_one_eq_ι_comp_right (s : fork f g) : s.π.app one = s.ι ≫ g := +by rw [←s.app_zero_eq_ι, ←s.w right, parallel_pair_map_right] -@[simp, reassoc] lemma cofork.left_app_one (s : cofork f g) : - f ≫ s.ι.app one = s.ι.app zero := -by rw [←s.w left, parallel_pair_map_left] +@[simp] lemma cofork.app_zero_eq_comp_π_left (s : cofork f g) : s.ι.app zero = f ≫ s.π := +by rw [←s.app_one_eq_π, ←s.w left, parallel_pair_map_left] -@[simp, reassoc] lemma cofork.right_app_one (s : cofork f g) : - g ≫ s.ι.app one = s.ι.app zero := -by rw [←s.w right, parallel_pair_map_right] +@[reassoc] lemma cofork.app_zero_eq_comp_π_right (s : cofork f g) : s.ι.app zero = g ≫ s.π := +by rw [←s.app_one_eq_π, ←s.w right, parallel_pair_map_right] /-- A fork on `f g : X ⟶ Y` is determined by the morphism `ι : P ⟶ X` satisfying `ι ≫ f = ι ≫ g`. -/ @@ -267,32 +264,32 @@ def cofork.of_π {P : C} (π : Y ⟶ P) (w : f ≫ π = g ≫ π) : cofork f g : { app := λ X, walking_parallel_pair.cases_on X (f ≫ π) π, naturality' := λ i j f, by { cases f; dsimp; simp [w] } } } -- See note [dsimp, simp] -lemma fork.ι_of_ι {P : C} (ι : P ⟶ X) (w : ι ≫ f = ι ≫ g) : +@[simp] lemma fork.ι_of_ι {P : C} (ι : P ⟶ X) (w : ι ≫ f = ι ≫ g) : (fork.of_ι ι w).ι = ι := rfl -lemma cofork.π_of_π {P : C} (π : Y ⟶ P) (w : f ≫ π = g ≫ π) : +@[simp] lemma cofork.π_of_π {P : C} (π : Y ⟶ P) (w : f ≫ π = g ≫ π) : (cofork.of_π π w).π = π := rfl -@[reassoc] +@[simp, reassoc] lemma fork.condition (t : fork f g) : t.ι ≫ f = t.ι ≫ g := -by rw [t.app_zero_left, t.app_zero_right] -@[reassoc] +by rw [←t.app_one_eq_ι_comp_left, ←t.app_one_eq_ι_comp_right] + +@[simp, reassoc] lemma cofork.condition (t : cofork f g) : f ≫ t.π = g ≫ t.π := -by rw [t.left_app_one, t.right_app_one] +by rw [←t.app_zero_eq_comp_π_left, ←t.app_zero_eq_comp_π_right] /-- To check whether two maps are equalized by both maps of a fork, it suffices to check it for the first map -/ -lemma fork.equalizer_ext (s : fork f g) {W : C} {k l : W ⟶ s.X} - (h : k ≫ fork.ι s = l ≫ fork.ι s) : ∀ (j : walking_parallel_pair), - k ≫ s.π.app j = l ≫ s.π.app j +lemma fork.equalizer_ext (s : fork f g) {W : C} {k l : W ⟶ s.X} (h : k ≫ s.ι = l ≫ s.ι) : + ∀ (j : walking_parallel_pair), k ≫ s.π.app j = l ≫ s.π.app j | zero := h -| one := by rw [←fork.app_zero_left, reassoc_of h] +| one := by rw [s.app_one_eq_ι_comp_left, reassoc_of h] /-- To check whether two maps are coequalized by both maps of a cofork, it suffices to check it for the second map -/ lemma cofork.coequalizer_ext (s : cofork f g) {W : C} {k l : s.X ⟶ W} (h : cofork.π s ≫ k = cofork.π s ≫ l) : ∀ (j : walking_parallel_pair), s.ι.app j ≫ k = s.ι.app j ≫ l -| zero := by simp only [←cofork.left_app_one, category.assoc, h] +| zero := by simp only [s.app_zero_eq_comp_π_left, category.assoc, h] | one := h lemma fork.is_limit.hom_ext {s : fork f g} (hs : is_limit s) {W : C} {k l : W ⟶ s.X} @@ -303,12 +300,12 @@ lemma cofork.is_colimit.hom_ext {s : cofork f g} (hs : is_colimit s) {W : C} {k (h : cofork.π s ≫ k = cofork.π s ≫ l) : k = l := hs.hom_ext $ cofork.coequalizer_ext _ h -@[simp] lemma fork.is_limit.lift_of_ι_ι {s : fork f g} (hs : is_limit s) {W : C} - {k : W ⟶ X} (hk : k ≫ f = k ≫ g) : hs.lift (fork.of_ι k hk) ≫ s.ι = k := +@[simp, reassoc] lemma fork.is_limit.lift_comp_ι {s t : fork f g} (hs : is_limit s) : + hs.lift t ≫ s.ι = t.ι := hs.fac _ _ -@[simp] lemma cofork.is_colimit.π_desc_of_π {s : cofork f g} (hs : is_colimit s) {W : C} - {k : Y ⟶ W} (hk : f ≫ k = g ≫ k) : s.π ≫ hs.desc (cofork.of_π k hk) = k := +@[simp, reassoc] lemma cofork.is_colimit.π_comp_desc {s t : cofork f g} (hs : is_colimit s) : + s.π ≫ hs.desc t = t.π := hs.fac _ _ /-- If `s` is a limit fork over `f` and `g`, then a morphism `k : W ⟶ X` satisfying @@ -335,16 +332,16 @@ lemma cofork.is_colimit.exists_unique {s : cofork f g} (hs : is_colimit s) {W : /-- This is a slightly more convenient method to verify that a fork is a limit cone. It only asks for a proof of facts that carry any mathematical content -/ +@[simps lift] def fork.is_limit.mk (t : fork f g) (lift : Π (s : fork f g), s.X ⟶ t.X) (fac : ∀ (s : fork f g), lift s ≫ fork.ι t = fork.ι s) - (uniq : ∀ (s : fork f g) (m : s.X ⟶ t.X) - (w : ∀ j : walking_parallel_pair, m ≫ t.π.app j = s.π.app j), m = lift s) : + (uniq : ∀ (s : fork f g) (m : s.X ⟶ t.X) (w : m ≫ t.ι = s.ι), m = lift s) : is_limit t := { lift := lift, fac' := λ s j, walking_parallel_pair.cases_on j (fac s) $ by erw [←s.w left, ←t.w left, ←category.assoc, fac]; refl, - uniq' := uniq } + uniq' := λ s m j, by tidy } /-- This is another convenient method to verify that a fork is a limit cone. It only asks for a proof of facts that carry any mathematical content, and allows access to the @@ -355,21 +352,19 @@ is_limit t := fork.is_limit.mk t (λ s, (create s).1) (λ s, (create s).2.1) - (λ s m w, (create s).2.2 (w zero)) + (λ s m w, (create s).2.2 w) /-- This is a slightly more convenient method to verify that a cofork is a colimit cocone. It only asks for a proof of facts that carry any mathematical content -/ -@[simps] def cofork.is_colimit.mk (t : cofork f g) (desc : Π (s : cofork f g), t.X ⟶ s.X) (fac : ∀ (s : cofork f g), cofork.π t ≫ desc s = cofork.π s) - (uniq : ∀ (s : cofork f g) (m : t.X ⟶ s.X) - (w : ∀ j : walking_parallel_pair, t.ι.app j ≫ m = s.ι.app j), m = desc s) : + (uniq : ∀ (s : cofork f g) (m : t.X ⟶ s.X) (w : t.π ≫ m = s.π), m = desc s) : is_colimit t := { desc := desc, fac' := λ s j, walking_parallel_pair.cases_on j (by erw [←s.w left, ←t.w left, category.assoc, fac]; refl) (fac s), - uniq' := uniq } + uniq' := by tidy } /-- This is another convenient method to verify that a fork is a limit cone. It only asks for a proof of facts that carry any mathematical content, and allows access to the @@ -380,17 +375,17 @@ is_colimit t := cofork.is_colimit.mk t (λ s, (create s).1) (λ s, (create s).2.1) - (λ s m w, (create s).2.2 (w one)) + (λ s m w, (create s).2.2 w) /-- Noncomputably make a limit cone from the existence of unique factorizations. -/ def fork.is_limit.of_exists_unique {t : fork f g} (hs : ∀ (s : fork f g), ∃! l : s.X ⟶ t.X, l ≫ fork.ι t = fork.ι s) : is_limit t := -by { choose d hd hd' using hs, exact fork.is_limit.mk _ d hd (λ s m hm, hd' _ _ (hm _)) } +by { choose d hd hd' using hs, exact fork.is_limit.mk _ d hd (λ s m hm, hd' _ _ hm) } /-- Noncomputably make a colimit cocone from the existence of unique factorizations. -/ def cofork.is_colimit.of_exists_unique {t : cofork f g} (hs : ∀ (s : cofork f g), ∃! d : t.X ⟶ s.X, cofork.π t ≫ d = cofork.π s) : is_colimit t := -by { choose d hd hd' using hs, exact cofork.is_colimit.mk _ d hd (λ s m hm, hd' _ _ (hm _)) } +by { choose d hd hd' using hs, exact cofork.is_colimit.mk _ d hd (λ s m hm, hd' _ _ hm) } /-- Given a limit cone for the pair `f g : X ⟶ Y`, for any `Z`, morphisms from `Z` to its point are in @@ -401,7 +396,7 @@ This is a special case of `is_limit.hom_iso'`, often useful to construct adjunct @[simps] def fork.is_limit.hom_iso {X Y : C} {f g : X ⟶ Y} {t : fork f g} (ht : is_limit t) (Z : C) : (Z ⟶ t.X) ≃ {h : Z ⟶ X // h ≫ f = h ≫ g} := -{ to_fun := λ k, ⟨k ≫ t.ι, by simp⟩, +{ to_fun := λ k, ⟨k ≫ t.ι, by simp only [category.assoc, t.condition]⟩, inv_fun := λ h, (fork.is_limit.lift' ht _ h.prop).1, left_inv := λ k, fork.is_limit.hom_ext ht (fork.is_limit.lift' _ _ _).prop, right_inv := λ h, subtype.ext (fork.is_limit.lift' ht _ _).prop } @@ -421,7 +416,7 @@ This is a special case of `is_colimit.hom_iso'`, often useful to construct adjun @[simps] def cofork.is_colimit.hom_iso {X Y : C} {f g : X ⟶ Y} {t : cofork f g} (ht : is_colimit t) (Z : C) : (t.X ⟶ Z) ≃ {h : Y ⟶ Z // f ≫ h = g ≫ h} := -{ to_fun := λ k, ⟨t.π ≫ k, by simp⟩, +{ to_fun := λ k, ⟨t.π ≫ k, by simp only [←category.assoc, t.condition]⟩, inv_fun := λ h, (cofork.is_colimit.desc' ht _ h.prop).1, left_inv := λ k, cofork.is_colimit.hom_ext ht (cofork.is_colimit.desc' _ _ _).prop, right_inv := λ h, subtype.ext (cofork.is_colimit.desc' ht _ _).prop } @@ -501,7 +496,7 @@ def fork.mk_hom {s t : fork f g} (k : s.X ⟶ t.X) (w : k ≫ t.ι = s.ι) : s begin rintro ⟨_|_⟩, { exact w }, - { simpa using w =≫ f }, + { simp only [fork.app_one_eq_ι_comp_left, reassoc_of w] }, end } /-- @@ -523,10 +518,16 @@ def cofork.mk_hom {s t : cofork f g} (k : s.X ⟶ t.X) (w : s.π ≫ k = t.π) : w' := begin rintro ⟨_|_⟩, - simpa using f ≫= w, - exact w, + { simp [cofork.app_zero_eq_comp_π_left, w] }, + { exact w } end } +@[simp, reassoc] lemma fork.hom_comp_ι {s t : fork f g} (f : s ⟶ t) : f.hom ≫ t.ι = s.ι := +by tidy + +@[simp, reassoc] lemma fork.π_comp_hom {s t : cofork f g} (f : s ⟶ t) : s.π ≫ f.hom = t.π := +by tidy + /-- To construct an isomorphism between coforks, it suffices to give an isomorphism between the cocone points @@ -612,8 +613,7 @@ end section variables {f g} /-- The equalizer morphism in any limit cone is a monomorphism. -/ -lemma mono_of_is_limit_parallel_pair {c : cone (parallel_pair f g)} (i : is_limit c) : - mono (fork.ι c) := +lemma mono_of_is_limit_fork {c : fork f g} (i : is_limit c) : mono (fork.ι c) := { right_cancellation := λ Z h k w, fork.is_limit.hom_ext i w } end @@ -630,11 +630,11 @@ def is_limit_id_fork (h : f = g) : is_limit (id_fork h) := fork.is_limit.mk _ (λ s, fork.ι s) (λ s, category.comp_id _) - (λ s m h, by { convert h zero, exact (category.comp_id _).symm }) + (λ s m h, by { convert h, exact (category.comp_id _).symm }) /-- Every equalizer of `(f, g)`, where `f = g`, is an isomorphism. -/ -lemma is_iso_limit_cone_parallel_pair_of_eq (h₀ : f = g) {c : cone (parallel_pair f g)} - (h : is_limit c) : is_iso (c.π.app zero) := +lemma is_iso_limit_cone_parallel_pair_of_eq (h₀ : f = g) {c : fork f g} + (h : is_limit c) : is_iso c.ι := is_iso.of_iso $ is_limit.cone_point_unique_up_to_iso h $ is_limit_id_fork h₀ /-- The equalizer of `(f, g)`, where `f = g`, is an isomorphism. -/ @@ -642,13 +642,12 @@ lemma equalizer.ι_of_eq [has_equalizer f g] (h : f = g) : is_iso (equalizer.ι is_iso_limit_cone_parallel_pair_of_eq h $ limit.is_limit _ /-- Every equalizer of `(f, f)` is an isomorphism. -/ -lemma is_iso_limit_cone_parallel_pair_of_self {c : cone (parallel_pair f f)} (h : is_limit c) : - is_iso (c.π.app zero) := +lemma is_iso_limit_cone_parallel_pair_of_self {c : fork f f} (h : is_limit c) : is_iso c.ι := is_iso_limit_cone_parallel_pair_of_eq rfl h /-- An equalizer that is an epimorphism is an isomorphism. -/ -lemma is_iso_limit_cone_parallel_pair_of_epi {c : cone (parallel_pair f g)} - (h : is_limit c) [epi (c.π.app zero)] : is_iso (c.π.app zero) := +lemma is_iso_limit_cone_parallel_pair_of_epi {c : fork f g} + (h : is_limit c) [epi (c.ι)] : is_iso c.ι := is_iso_limit_cone_parallel_pair_of_eq ((cancel_epi _).1 (fork.condition c)) h /-- Two morphisms are equal if there is a fork whose inclusion is epi. -/ @@ -757,8 +756,7 @@ section variables {f g} /-- The coequalizer morphism in any colimit cocone is an epimorphism. -/ -lemma epi_of_is_colimit_parallel_pair {c : cocone (parallel_pair f g)} (i : is_colimit c) : - epi (c.ι.app one) := +lemma epi_of_is_colimit_cofork {c : cofork f g} (i : is_colimit c) : epi c.π := { left_cancellation := λ Z h k w, cofork.is_colimit.hom_ext i w } end @@ -775,26 +773,25 @@ def is_colimit_id_cofork (h : f = g) : is_colimit (id_cofork h) := cofork.is_colimit.mk _ (λ s, cofork.π s) (λ s, category.id_comp _) - (λ s m h, by { convert h one, exact (category.id_comp _).symm }) + (λ s m h, by { convert h, exact (category.id_comp _).symm }) /-- Every coequalizer of `(f, g)`, where `f = g`, is an isomorphism. -/ -lemma is_iso_colimit_cocone_parallel_pair_of_eq (h₀ : f = g) {c : cocone (parallel_pair f g)} - (h : is_colimit c) : is_iso (c.ι.app one) := +lemma is_iso_colimit_cocone_parallel_pair_of_eq (h₀ : f = g) {c : cofork f g} (h : is_colimit c) : + is_iso c.π := is_iso.of_iso $ is_colimit.cocone_point_unique_up_to_iso (is_colimit_id_cofork h₀) h /-- The coequalizer of `(f, g)`, where `f = g`, is an isomorphism. -/ -lemma coequalizer.π_of_eq [has_coequalizer f g] (h : f = g) : - is_iso (coequalizer.π f g) := +lemma coequalizer.π_of_eq [has_coequalizer f g] (h : f = g) : is_iso (coequalizer.π f g) := is_iso_colimit_cocone_parallel_pair_of_eq h $ colimit.is_colimit _ /-- Every coequalizer of `(f, f)` is an isomorphism. -/ -lemma is_iso_colimit_cocone_parallel_pair_of_self {c : cocone (parallel_pair f f)} - (h : is_colimit c) : is_iso (c.ι.app one) := +lemma is_iso_colimit_cocone_parallel_pair_of_self {c : cofork f f} (h : is_colimit c) : + is_iso c.π := is_iso_colimit_cocone_parallel_pair_of_eq rfl h /-- A coequalizer that is a monomorphism is an isomorphism. -/ -lemma is_iso_limit_cocone_parallel_pair_of_epi {c : cocone (parallel_pair f g)} - (h : is_colimit c) [mono (c.ι.app one)] : is_iso (c.ι.app one) := +lemma is_iso_limit_cocone_parallel_pair_of_epi {c : cofork f g} + (h : is_colimit c) [mono c.π] : is_iso c.π := is_iso_colimit_cocone_parallel_pair_of_eq ((cancel_mono _).1 (cofork.condition c)) h /-- Two morphisms are equal if there is a cofork whose projection is mono. -/ @@ -900,9 +897,11 @@ A split mono `f` equalizes `(retraction f ≫ f)` and `(𝟙 Y)`. Here we build the cone, and show in `split_mono_equalizes` that it is a limit cone. -/ @[simps {rhs_md := semireducible}] -def cone_of_split_mono : cone (parallel_pair (𝟙 Y) (retraction f ≫ f)) := +def cone_of_split_mono : fork (𝟙 Y) (retraction f ≫ f) := fork.of_ι f (by simp) +@[simp] lemma cone_of_split_mono_ι : (cone_of_split_mono f).ι = f := rfl + /-- A split mono `f` equalizes `(retraction f ≫ f)` and `(𝟙 Y)`. -/ @@ -927,7 +926,7 @@ variables {C f g} /-- The fork obtained by postcomposing an equalizer fork with a monomorphism is an equalizer. -/ def is_equalizer_comp_mono {c : fork f g} (i : is_limit c) {Z : C} (h : Y ⟶ Z) [hm : mono h] : - is_limit (fork.of_ι c.ι (by simp) : fork (f ≫ h) (g ≫ h)) := + is_limit (fork.of_ι c.ι (by simp [reassoc_of c.condition]) : fork (f ≫ h) (g ≫ h)) := fork.is_limit.mk' _ $ λ s, let s' : fork f g := fork.of_ι s.ι (by apply hm.right_cancellation; simp [s.condition]) in let l := fork.is_limit.lift' i s'.ι s'.condition in @@ -947,8 +946,8 @@ def split_mono_of_idempotent_of_is_limit_fork {X : C} {f : X ⟶ X} (hf : f ≫ { retraction := i.lift (fork.of_ι f (by simp [hf])), id' := begin - letI := mono_of_is_limit_parallel_pair i, - rw [←cancel_mono_id c.ι, category.assoc, fork.is_limit.lift_of_ι_ι, ←c.condition], + letI := mono_of_is_limit_fork i, + rw [←cancel_mono_id c.ι, category.assoc, fork.is_limit.lift_comp_ι, fork.ι_of_ι, ←c.condition], exact category.comp_id c.ι end } @@ -966,9 +965,11 @@ A split epi `f` coequalizes `(f ≫ section_ f)` and `(𝟙 X)`. Here we build the cocone, and show in `split_epi_coequalizes` that it is a colimit cocone. -/ @[simps {rhs_md := semireducible}] -def cocone_of_split_epi : cocone (parallel_pair (𝟙 X) (f ≫ section_ f)) := +def cocone_of_split_epi : cofork (𝟙 X) (f ≫ section_ f) := cofork.of_π f (by simp) +@[simp] lemma cocone_of_split_epi_π : (cocone_of_split_epi f).π = f := rfl + /-- A split epi `f` coequalizes `(f ≫ section_ f)` and `(𝟙 X)`. -/ @@ -1016,8 +1017,9 @@ def split_epi_of_idempotent_of_is_colimit_cofork {X : C} {f : X ⟶ X} (hf : f { section_ := i.desc (cofork.of_π f (by simp [hf])), id' := begin - letI := epi_of_is_colimit_parallel_pair i, - rw [← cancel_epi_id c.π, ← category.assoc, cofork.is_colimit.π_desc_of_π, ← c.condition], + letI := epi_of_is_colimit_cofork i, + rw [← cancel_epi_id c.π, ← category.assoc, cofork.is_colimit.π_comp_desc, + cofork.π_of_π, ← c.condition], exact category.id_comp _, end } diff --git a/src/category_theory/limits/shapes/kernel_pair.lean b/src/category_theory/limits/shapes/kernel_pair.lean index 8ede928ca3455..222a172f72cca 100644 --- a/src/category_theory/limits/shapes/kernel_pair.lean +++ b/src/category_theory/limits/shapes/kernel_pair.lean @@ -155,9 +155,9 @@ begin rw [assoc, assoc], congr' 1, erw (cofork.is_colimit.desc' r.is_colimit s.π _).2, - apply w walking_parallel_pair.one, + apply w, erw (cofork.is_colimit.desc' r.is_colimit s.π _).2, - apply w walking_parallel_pair.one } + apply w } end end is_kernel_pair diff --git a/src/category_theory/limits/shapes/kernels.lean b/src/category_theory/limits/shapes/kernels.lean index 74f6e34418893..bddff1b2357ec 100644 --- a/src/category_theory/limits/shapes/kernels.lean +++ b/src/category_theory/limits/shapes/kernels.lean @@ -13,6 +13,7 @@ the equalizer of `f` and `0 : X ⟶ Y`. (Similarly the cokernel is the coequaliz The basic definitions are * `kernel : (X ⟶ Y) → C` + * `kernel.ι : kernel f ⟶ X` * `kernel.condition : kernel.ι f ≫ f = 0` and * `kernel.lift (k : W ⟶ X) (h : k ≫ f = 0) : W ⟶ kernel f` (as well as the dual versions) @@ -74,7 +75,7 @@ variables {f} by erw [fork.condition, has_zero_morphisms.comp_zero] @[simp] lemma kernel_fork.app_one (s : kernel_fork f) : s.π.app one = 0 := -by rw [←fork.app_zero_left, kernel_fork.condition] +by simp [fork.app_one_eq_ι_comp_right] /-- A morphism `ι` satisfying `ι ≫ f = 0` determines a kernel fork over `f`. -/ abbreviation kernel_fork.of_ι {Z : C} (ι : Z ⟶ X) (w : ι ≫ f = 0) : kernel_fork f := @@ -324,12 +325,12 @@ variables [has_zero_object C] open_locale zero_object /-- The morphism from the zero object determines a cone on a kernel diagram -/ -def kernel.zero_cone : cone (parallel_pair f 0) := +def kernel.zero_kernel_fork : kernel_fork f := { X := 0, π := { app := λ j, 0 }} /-- The map from the zero object is a kernel of a monomorphism -/ -def kernel.is_limit_cone_zero_cone [mono f] : is_limit (kernel.zero_cone f) := +def kernel.is_limit_cone_zero_cone [mono f] : is_limit (kernel.zero_kernel_fork f) := fork.is_limit.mk _ (λ s, 0) (λ s, by { erw zero_comp, convert (zero_of_comp_mono f _).symm, @@ -364,7 +365,7 @@ def is_kernel.of_comp_iso {Z : C} (l : X ⟶ Z) (i : Z ≅ Y) (h : l ≫ i.hom = fork.is_limit.mk _ (λ s, hs.lift $ kernel_fork.of_ι (fork.ι s) $ by simp [←h]) (λ s, by simp) - (λ s m h, by { apply fork.is_limit.hom_ext hs, simpa using h walking_parallel_pair.zero }) + (λ s m h, by { apply fork.is_limit.hom_ext hs, simpa using h }) /-- If `i` is an isomorphism such that `l ≫ i.hom = f`, then the kernel of `f` is a kernel of `l`.-/ def kernel.of_comp_iso [has_kernel f] @@ -405,11 +406,11 @@ abbreviation cokernel_cofork := cofork f 0 variables {f} -@[simp, reassoc] lemma cokernel_cofork.condition (s : cokernel_cofork f) : f ≫ cofork.π s = 0 := +@[simp, reassoc] lemma cokernel_cofork.condition (s : cokernel_cofork f) : f ≫ s.π = 0 := by rw [cofork.condition, zero_comp] -@[simp] lemma cokernel_cofork.app_zero (s : cokernel_cofork f) : s.ι.app zero = 0 := -by rw [←cofork.left_app_one, cokernel_cofork.condition] +@[simp] lemma cokernel_cofork.π_eq_zero (s : cokernel_cofork f) : s.ι.app zero = 0 := +by simp [cofork.app_zero_eq_comp_π_right] /-- A morphism `π` satisfying `f ≫ π = 0` determines a cokernel cofork on `f`. -/ abbreviation cokernel_cofork.of_π {Z : C} (π : Y ⟶ Z) (w : f ≫ π = 0) : cokernel_cofork f := @@ -657,12 +658,13 @@ variables [has_zero_object C] open_locale zero_object /-- The morphism to the zero object determines a cocone on a cokernel diagram -/ -def cokernel.zero_cocone : cocone (parallel_pair f 0) := +def cokernel.zero_cokernel_cofork : cokernel_cofork f := { X := 0, ι := { app := λ j, 0 } } /-- The morphism to the zero object is a cokernel of an epimorphism -/ -def cokernel.is_colimit_cocone_zero_cocone [epi f] : is_colimit (cokernel.zero_cocone f) := +def cokernel.is_colimit_cocone_zero_cocone [epi f] : + is_colimit (cokernel.zero_cokernel_cofork f) := cofork.is_colimit.mk _ (λ s, 0) (λ s, by { erw zero_comp, convert (zero_of_epi_comp f _).symm, @@ -763,7 +765,7 @@ def is_cokernel.of_iso_comp {Z : C} (l : Z ⟶ Y) (i : X ≅ Z) (h : i.hom ≫ l cofork.is_colimit.mk _ (λ s, hs.desc $ cokernel_cofork.of_π (cofork.π s) $ by simp [←h]) (λ s, by simp) - (λ s m h, by { apply cofork.is_colimit.hom_ext hs, simpa using h walking_parallel_pair.one }) + (λ s m h, by { apply cofork.is_colimit.hom_ext hs, simpa using h }) /-- If `i` is an isomorphism such that `i.hom ≫ l = f`, then the cokernel of `f` is a cokernel of `l`. -/ diff --git a/src/category_theory/limits/shapes/multiequalizer.lean b/src/category_theory/limits/shapes/multiequalizer.lean index b094fe7be5d54..b0930c9f55178 100644 --- a/src/category_theory/limits/shapes/multiequalizer.lean +++ b/src/category_theory/limits/shapes/multiequalizer.lean @@ -264,21 +264,21 @@ namespace multifork variables {I : multicospan_index C} (K : multifork I) /-- The maps from the cone point of a multifork to the objects on the left. -/ -def ι (a : I.L) : K.X ⟶ I.left a := -K.π.app (walking_multicospan.left _) +def ι (a : I.L) : K.X ⟶ I.left a := K.π.app (walking_multicospan.left _) -@[simp] lemma ι_eq_app_left (a) : K.ι a = K.π.app (walking_multicospan.left _) := rfl +@[simp] lemma app_left_eq_ι (a) : K.π.app (walking_multicospan.left a) = K.ι a := rfl -@[simp] lemma app_left_fst (b) : - K.π.app (walking_multicospan.left (I.fst_to b)) ≫ I.fst b = - K.π.app (walking_multicospan.right b) := +@[simp] lemma app_right_eq_ι_comp_fst (b) : + K.π.app (walking_multicospan.right b) = K.ι (I.fst_to b) ≫ I.fst b := by { rw ← K.w (walking_multicospan.hom.fst b), refl } -@[simp] lemma app_left_snd (b) : - K.π.app (walking_multicospan.left (I.snd_to b)) ≫ I.snd b = - K.π.app (walking_multicospan.right b) := +@[reassoc] lemma app_right_eq_ι_comp_snd (b) : + K.π.app (walking_multicospan.right b) = K.ι (I.snd_to b) ≫ I.snd b := by { rw ← K.w (walking_multicospan.hom.snd b), refl } +@[simp, reassoc] lemma hom_comp_ι (K₁ K₂ : multifork I) (f : K₁ ⟶ K₂) (j : I.L) : + f.hom ≫ K₂.ι j = K₁.ι j := f.w (walking_multicospan.left j) + /-- Construct a multifork using a collection `ι` of morphisms. -/ @[simps] def of_ι (I : multicospan_index C) (P : C) (ι : Π a, P ⟶ I.left a) @@ -298,9 +298,10 @@ def of_ι (I : multicospan_index C) (P : C) (ι : Π a, P ⟶ I.left a) { dsimp, rw category.id_comp, apply w } end } } -@[reassoc] +@[simp, reassoc] lemma condition (b) : - K.ι (I.fst_to b) ≫ I.fst b = K.ι (I.snd_to b) ≫ I.snd b := by simp + K.ι (I.fst_to b) ≫ I.fst b = K.ι (I.snd_to b) ≫ I.snd b := +by rw [←app_right_eq_ι_comp_fst, ←app_right_eq_ι_comp_snd] /-- This definition provides a convenient way to show that a multifork is a limit. -/ @[simps] @@ -329,8 +330,8 @@ def is_limit.mk variables [has_product I.left] [has_product I.right] @[simp, reassoc] -lemma pi_condition : - pi.lift K.ι ≫ I.fst_pi_map = pi.lift K.ι ≫ I.snd_pi_map := by { ext, simp } +lemma pi_condition : pi.lift K.ι ≫ I.fst_pi_map = pi.lift K.ι ≫ I.snd_pi_map := +by { ext, simp } /-- Given a multifork, we may obtain a fork over `∏ I.left ⇉ ∏ I.right`. -/ @[simps X] noncomputable @@ -349,8 +350,7 @@ def to_pi_fork (K : multifork I) : fork I.fst_pi_map I.snd_pi_map := all_goals { change 𝟙 _ ≫ _ ≫ _ = pi.lift _ ≫ _, simp } end } } -@[simp] lemma to_pi_fork_π_app_zero : - K.to_pi_fork.π.app walking_parallel_pair.zero = pi.lift K.ι := rfl +@[simp] lemma to_pi_fork_π_app_zero : K.to_pi_fork.ι = pi.lift K.ι := rfl @[simp] lemma to_pi_fork_π_app_one : K.to_pi_fork.π.app walking_parallel_pair.one = pi.lift K.ι ≫ I.fst_pi_map := rfl @@ -376,7 +376,7 @@ def of_pi_fork (c : fork I.fst_pi_map I.snd_pi_map) : multifork I := end } } @[simp] lemma of_pi_fork_π_app_left (c : fork I.fst_pi_map I.snd_pi_map) (a) : - (of_pi_fork I c).π.app (walking_multicospan.left a) = c.ι ≫ pi.π _ _ := rfl + (of_pi_fork I c).ι a = c.ι ≫ pi.π _ _ := rfl @[simp] lemma of_pi_fork_π_app_right (c : fork I.fst_pi_map I.snd_pi_map) (a) : (of_pi_fork I c).π.app (walking_multicospan.right a) = c.ι ≫ I.fst_pi_map ≫ pi.π _ _ := rfl @@ -408,7 +408,8 @@ preserves and reflects limit cones. def multifork_equiv_pi_fork : multifork I ≌ fork I.fst_pi_map I.snd_pi_map := { functor := to_pi_fork_functor I, inverse := of_pi_fork_functor I, - unit_iso := nat_iso.of_components (λ K, cones.ext (iso.refl _) (by rintros (_|_); dsimp; simp)) + unit_iso := nat_iso.of_components (λ K, cones.ext (iso.refl _) + (by { rintros (_|_); dsimp; simp[←fork.app_one_eq_ι_comp_left, -fork.app_one_eq_ι_comp_left] })) (λ K₁ K₂ f, by { ext, simp }), counit_iso := nat_iso.of_components (λ K, fork.ext (iso.refl _) (by { ext, dsimp, simp })) (λ K₁ K₂ f, by { ext, simp }) } @@ -423,16 +424,14 @@ variables {I : multispan_index C} (K : multicofork I) def π (b : I.R) : I.right b ⟶ K.X := K.ι.app (walking_multispan.right _) -@[simp] lemma π_eq_app_right (b) : K.π b = K.ι.app (walking_multispan.right _) := rfl +@[simp] lemma π_eq_app_right (b) : K.ι.app (walking_multispan.right _) = K.π b := rfl @[simp] lemma fst_app_right (a) : - I.fst a ≫ K.ι.app (walking_multispan.right (I.fst_from a)) = - K.ι.app (walking_multispan.left a) := + K.ι.app (walking_multispan.left a) = I.fst a ≫ K.π _ := by { rw ← K.w (walking_multispan.hom.fst a), refl } -@[simp] lemma snd_app_right (a) : - I.snd a ≫ K.ι.app (walking_multispan.right (I.snd_from a)) = - K.ι.app (walking_multispan.left a) := +@[reassoc] lemma snd_app_right (a) : + K.ι.app (walking_multispan.left a) = I.snd a ≫ K.π _ := by { rw ← K.w (walking_multispan.hom.snd a), refl } /-- Construct a multicofork using a collection `π` of morphisms. -/ @@ -454,9 +453,9 @@ def of_π (I : multispan_index C) (P : C) (π : Π b, I.right b ⟶ P) { dsimp, rw category.comp_id, apply (w _).symm } end } } -@[reassoc] -lemma condition (a) : - I.fst a ≫ K.π (I.fst_from a) = I.snd a ≫ K.π (I.snd_from a) := by simp +@[simp, reassoc] +lemma condition (a) : I.fst a ≫ K.π (I.fst_from a) = I.snd a ≫ K.π (I.snd_from a) := +by rw [←K.snd_app_right, ←K.fst_app_right] /-- This definition provides a convenient way to show that a multicofork is a colimit. -/ @[simps] @@ -504,11 +503,7 @@ def to_sigma_cofork (K : multicofork I) : cofork I.fst_sigma_map I.snd_sigma_map all_goals { change _ ≫ sigma.desc _ = (_ ≫ _) ≫ 𝟙 _, simp } end } } -@[simp] lemma to_sigma_cofork_ι_app_zero : - K.to_sigma_cofork.ι.app walking_parallel_pair.zero = I.fst_sigma_map ≫ sigma.desc K.π := rfl - -@[simp] lemma to_sigma_cofork_ι_app_one : - K.to_sigma_cofork.ι.app walking_parallel_pair.one = sigma.desc K.π := rfl +@[simp] lemma to_sigma_cofork_π : K.to_sigma_cofork.π = sigma.desc K.π := rfl variable (I) @@ -526,11 +521,11 @@ def of_sigma_cofork (c : cofork I.fst_sigma_map I.snd_sigma_map) : multicofork I begin rintros (_|_) (_|_) (_|_|_), any_goals { dsimp, rw category.comp_id, apply category.id_comp }, - { change _ ≫ _ ≫ _ = (_ ≫ _) ≫ _, - dsimp, simp [←cofork.left_app_one, -cofork.left_app_one] }, + { change _ ≫ _ ≫ _ = (_ ≫ _) ≫ _, dsimp, + simp only [cofork.condition, category.comp_id], + rw [←I.ι_fst_sigma_map_assoc, c.condition] }, { change _ ≫ _ ≫ _ = (_ ≫ _) ≫ 𝟙 _, - rw c.condition, - dsimp, simp [←cofork.right_app_one, -cofork.right_app_one] } + rw c.condition, simp } end } } @[simp] lemma of_sigma_cofork_ι_app_left (c : cofork I.fst_sigma_map I.snd_sigma_map) (a) : @@ -568,9 +563,11 @@ it preserves and reflects colimit cocones. def multicofork_equiv_sigma_cofork : multicofork I ≌ cofork I.fst_sigma_map I.snd_sigma_map := { functor := to_sigma_cofork_functor I, inverse := of_sigma_cofork_functor I, - unit_iso := nat_iso.of_components (λ K, cocones.ext (iso.refl _) (by rintros (_|_); dsimp; simp)) + unit_iso := nat_iso.of_components (λ K, cocones.ext (iso.refl _) + (by { rintros (_|_); dsimp; simp })) (λ K₁ K₂ f, by { ext, simp }), - counit_iso := nat_iso.of_components (λ K, cofork.ext (iso.refl _) (by { ext, dsimp, simp })) + counit_iso := nat_iso.of_components (λ K, cofork.ext (iso.refl _) + (by { ext, dsimp, simp only [category.comp_id, colimit.ι_desc, cofan.mk_ι_app], refl })) (λ K₁ K₂ f, by { ext, dsimp, simp, }) } end multispan_index diff --git a/src/category_theory/limits/shapes/normal_mono/equalizers.lean b/src/category_theory/limits/shapes/normal_mono/equalizers.lean index 14586a9a14e7c..2fd7929120b71 100644 --- a/src/category_theory/limits/shapes/normal_mono/equalizers.lean +++ b/src/category_theory/limits/shapes/normal_mono/equalizers.lean @@ -91,11 +91,11 @@ has_limit.mk { cone := fork.of_ι pullback.fst huu, is_limit := fork.is_limit.mk _ (λ s, pullback.lift (fork.ι s) (fork.ι s) $ prod.hom_ext (by simp only [prod.lift_fst, category.assoc]) - (by simp only [fork.app_zero_right, fork.app_zero_left, prod.lift_snd, category.assoc])) + (by simp only [prod.comp_lift, fork.condition])) (λ s, by simp only [fork.ι_of_ι, pullback.lift_fst]) (λ s m h, pullback.hom_ext - (by simpa only [pullback.lift_fst] using h walking_parallel_pair.zero) - (by simpa only [huv.symm, pullback.lift_fst] using h walking_parallel_pair.zero)) } + (by simpa only [pullback.lift_fst] using h) + (by simpa only [huv.symm, pullback.lift_fst] using h)) } end @@ -213,11 +213,11 @@ has_colimit.mk { cocone := cofork.of_π pushout.inl huu, is_colimit := cofork.is_colimit.mk _ (λ s, pushout.desc (cofork.π s) (cofork.π s) $ coprod.hom_ext (by simp only [coprod.inl_desc_assoc]) - (by simp only [cofork.right_app_one, coprod.inr_desc_assoc, cofork.left_app_one])) + (by simp only [coprod.desc_comp, cofork.condition])) (λ s, by simp only [pushout.inl_desc, cofork.π_of_π]) (λ s m h, pushout.hom_ext - (by simpa only [pushout.inl_desc] using h walking_parallel_pair.one) - (by simpa only [huv.symm, pushout.inl_desc] using h walking_parallel_pair.one)) } + (by simpa only [pushout.inl_desc] using h) + (by simpa only [huv.symm, pushout.inl_desc] using h)) } end diff --git a/src/category_theory/limits/shapes/regular_mono.lean b/src/category_theory/limits/shapes/regular_mono.lean index 799d706a8dacf..5713672ddc2bc 100644 --- a/src/category_theory/limits/shapes/regular_mono.lean +++ b/src/category_theory/limits/shapes/regular_mono.lean @@ -47,7 +47,7 @@ attribute [reassoc] regular_mono.w /-- Every regular monomorphism is a monomorphism. -/ @[priority 100] instance regular_mono.mono (f : X ⟶ Y) [regular_mono f] : mono f := -mono_of_is_limit_parallel_pair regular_mono.is_limit +mono_of_is_limit_fork regular_mono.is_limit instance equalizer_regular (g h : X ⟶ Y) [has_limit (parallel_pair g h)] : regular_mono (equalizer.ι g h) := @@ -172,7 +172,7 @@ attribute [reassoc] regular_epi.w /-- Every regular epimorphism is an epimorphism. -/ @[priority 100] instance regular_epi.epi (f : X ⟶ Y) [regular_epi f] : epi f := -epi_of_is_colimit_parallel_pair regular_epi.is_colimit +epi_of_is_colimit_cofork regular_epi.is_colimit instance coequalizer_regular (g h : X ⟶ Y) [has_colimit (parallel_pair g h)] : regular_epi (coequalizer.π g h) := diff --git a/src/category_theory/limits/shapes/split_coequalizer.lean b/src/category_theory/limits/shapes/split_coequalizer.lean index a22d5a4f57971..e670a6ec31db1 100644 --- a/src/category_theory/limits/shapes/split_coequalizer.lean +++ b/src/category_theory/limits/shapes/split_coequalizer.lean @@ -87,11 +87,14 @@ section open limits /-- A split coequalizer clearly induces a cofork. -/ -@[simps] +@[simps X] def is_split_coequalizer.as_cofork {Z : C} {h : Y ⟶ Z} (t : is_split_coequalizer f g h) : cofork f g := cofork.of_π h t.condition +@[simp] lemma is_split_coequalizer.as_cofork_π {Z : C} {h : Y ⟶ Z} + (t : is_split_coequalizer f g h) : t.as_cofork.π = h := rfl + /-- The cofork induced by a split coequalizer is a coequalizer, justifying the name. In some cases it is more convenient to show a given cofork is a coequalizer by showing it is split. diff --git a/src/category_theory/monad/coequalizer.lean b/src/category_theory/monad/coequalizer.lean index cf6e1c7a21767..8e08c1c3ff8c6 100644 --- a/src/category_theory/monad/coequalizer.lean +++ b/src/category_theory/monad/coequalizer.lean @@ -101,13 +101,18 @@ def beck_split_coequalizer : is_split_coequalizer (T.map X.a) (T.μ.app _) X.a : ⟨T.η.app _, T.η.app _, X.assoc.symm, X.unit, T.left_unit _, (T.η.naturality _).symm⟩ /-- This is the Beck cofork. It is a split coequalizer, in particular a coequalizer. -/ -@[simps] +@[simps X] def beck_cofork : cofork (T.map X.a) (T.μ.app _) := (beck_split_coequalizer X).as_cofork +@[simp] lemma beck_cofork_π : (beck_cofork X).π = X.a := rfl + /-- The Beck cofork is a coequalizer. -/ def beck_coequalizer : is_colimit (beck_cofork X) := (beck_split_coequalizer X).is_coequalizer +@[simp] lemma beck_coequalizer_desc (s : cofork (T.to_functor.map X.a) (T.μ.app X.A)) : + (beck_coequalizer X).desc s = T.η.app _ ≫ s.π := rfl + end monad end category_theory diff --git a/src/category_theory/monad/monadicity.lean b/src/category_theory/monad/monadicity.lean index 284fa7bacef4c..b96ecf8ae5998 100644 --- a/src/category_theory/monad/monadicity.lean +++ b/src/category_theory/monad/monadicity.lean @@ -151,7 +151,7 @@ congr_arg (adj .hom_equiv _ _) (category.comp_id _) This is a cofork which is helpful for establishing monadicity: the morphism from the Beck coequalizer to this cofork is the unit for the adjunction on the comparison functor. -/ -@[simps] +@[simps X] def unit_cofork (A : adj .to_monad.algebra) [has_coequalizer (F .map A.a) (adj .counit.app (F .obj A.A))] : cofork (G.map (F .map A.a)) (G.map (adj .counit.app (F .obj A.A))) := @@ -161,6 +161,10 @@ begin rw [← G.map_comp, coequalizer.condition, G.map_comp], end +@[simp] lemma unit_cofork_π (A : adj .to_monad.algebra) + [has_coequalizer (F .map A.a) (adj .counit.app (F .obj A.A))] : + (unit_cofork A).π = G.map (coequalizer.π (F .map A.a) (adj .counit.app (F .obj A.A))) := rfl + lemma comparison_adjunction_unit_f [∀ (A : adj .to_monad.algebra), has_coequalizer (F .map A.a) (adj .counit.app (F .obj A.A))] (A : adj .to_monad.algebra) : @@ -168,8 +172,8 @@ lemma comparison_adjunction_unit_f (beck_coequalizer A).desc (unit_cofork A) := begin apply limits.cofork.is_colimit.hom_ext (beck_coequalizer A), - rw is_colimit.fac, - dsimp only [cofork.π_eq_app_one, beck_cofork_ι_app, unit_cofork_ι_app], + rw [cofork.is_colimit.π_comp_desc], + dsimp only [beck_cofork_π, unit_cofork_π], rw [comparison_adjunction_unit_f_aux, ← adj .hom_equiv_naturality_left A.a, coequalizer.condition, adj .hom_equiv_naturality_right, adj .hom_equiv_unit, category.assoc], apply adj .right_triangle_components_assoc, diff --git a/src/category_theory/preadditive/default.lean b/src/category_theory/preadditive/default.lean index cfa2ddd21cb06..e7e601d26845e 100644 --- a/src/category_theory/preadditive/default.lean +++ b/src/category_theory/preadditive/default.lean @@ -243,7 +243,7 @@ def is_limit_fork_of_kernel_fork {c : kernel_fork (f - g)} (i : is_limit c) : is_limit (fork_of_kernel_fork c) := fork.is_limit.mk' _ $ λ s, ⟨i.lift (kernel_fork_of_fork s), i.fac _ _, - λ m h, by { apply fork.is_limit.hom_ext i, rw [i.fac], exact h }⟩ + λ m h, by apply fork.is_limit.hom_ext i; tidy⟩ @[simp] lemma is_limit_fork_of_kernel_fork_lift {c : kernel_fork (f - g)} (i : is_limit c) (s : fork f g) : @@ -254,7 +254,7 @@ def is_limit_kernel_fork_of_fork {c : fork f g} (i : is_limit c) : is_limit (kernel_fork_of_fork c) := fork.is_limit.mk' _ $ λ s, ⟨i.lift (fork_of_kernel_fork s), i.fac _ _, - λ m h, by { apply fork.is_limit.hom_ext i, rw [i.fac], exact h }⟩ + λ m h, by apply fork.is_limit.hom_ext i; tidy⟩ variables (f g) @@ -289,7 +289,7 @@ def is_colimit_cofork_of_cokernel_cofork {c : cokernel_cofork (f - g)} (i : is_c is_colimit (cofork_of_cokernel_cofork c) := cofork.is_colimit.mk' _ $ λ s, ⟨i.desc (cokernel_cofork_of_cofork s), i.fac _ _, - λ m h, by { apply cofork.is_colimit.hom_ext i, rw [i.fac], exact h }⟩ + λ m h, by apply cofork.is_colimit.hom_ext i; tidy⟩ @[simp] lemma is_colimit_cofork_of_cokernel_cofork_desc {c : cokernel_cofork (f - g)} @@ -301,7 +301,7 @@ def is_colimit_cokernel_cofork_of_cofork {c : cofork f g} (i : is_colimit c) : is_colimit (cokernel_cofork_of_cofork c) := cofork.is_colimit.mk' _ $ λ s, ⟨i.desc (cofork_of_cokernel_cofork s), i.fac _ _, - λ m h, by { apply cofork.is_colimit.hom_ext i, rw [i.fac], exact h }⟩ + λ m h, by apply cofork.is_colimit.hom_ext i; tidy⟩ variables (f g) diff --git a/src/category_theory/sites/limits.lean b/src/category_theory/sites/limits.lean index d2e843e3f9f83..af9b4b93f99ca 100644 --- a/src/category_theory/sites/limits.lean +++ b/src/category_theory/sites/limits.lean @@ -75,8 +75,8 @@ def multifork_evaluation_cone (F : K ⥤ Sheaf J D) rw [presheaf.is_sheaf.amalgamate_map, category.assoc, ← (F.map f).val.naturality, ← category.assoc, presheaf.is_sheaf.amalgamate_map], dsimp [multifork.of_ι], - rw [category.assoc, ← E.w f], - simp, + erw [category.assoc, ← E.w f], + tidy, end } } diff --git a/src/category_theory/sites/sheaf.lean b/src/category_theory/sites/sheaf.lean index 161851d05f381..75045308bddd5 100644 --- a/src/category_theory/sites/sheaf.lean +++ b/src/category_theory/sites/sheaf.lean @@ -472,7 +472,7 @@ begin simp } } }, { refine fork.ext (iso.refl _) _, dsimp [equalizer.fork_map, fork_map], - simp } + simp [fork.ι] } end /-- The equalizer definition of a sheaf given by `is_sheaf'` is equivalent to `is_sheaf`. -/ diff --git a/src/topology/sheaves/sheaf_condition/pairwise_intersections.lean b/src/topology/sheaves/sheaf_condition/pairwise_intersections.lean index 4ba40d535ad13..3e3af1f912d78 100644 --- a/src/topology/sheaves/sheaf_condition/pairwise_intersections.lean +++ b/src/topology/sheaves/sheaf_condition/pairwise_intersections.lean @@ -173,7 +173,7 @@ def cone_equiv_inverse_obj (F : presheaf C X) simp only [category.id_comp] at h, have h' := h =≫ pi.π _ (i, j), rw h', - simp, + simp only [category.assoc, limit.lift_π, fan.mk_π_app], refl, }, { dsimp, simp only [category.id_comp, category.assoc], have h := c.π.naturality (walking_parallel_pair_hom.right), @@ -201,6 +201,7 @@ def cone_equiv_inverse (F : presheaf C X) induction x using opposite.rec, rcases x with (⟨i⟩|⟨i,j⟩), { dsimp, + dunfold fork.ι, rw [←(f.w walking_parallel_pair.zero), category.assoc], }, { dsimp, rw [←(f.w walking_parallel_pair.one), category.assoc], }, From 08323cda859128765d861be8462563093aafdd70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Thu, 21 Apr 2022 20:30:50 +0000 Subject: [PATCH 141/373] feat(data/real/ennreal): `tsub` lemmas (#13525) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inherit lemmas about subtraction on `ℝ≥0∞` from `algebra.order.sub`. Generalize `add_le_cancellable.tsub_lt_self` in passing. New `ennreal` lemmas --- src/algebra/order/sub.lean | 22 +++------- src/data/real/ennreal.lean | 58 ++++++++++++++++--------- src/measure_theory/measure/regular.lean | 2 +- src/topology/instances/ennreal.lean | 2 +- 4 files changed, 46 insertions(+), 38 deletions(-) diff --git a/src/algebra/order/sub.lean b/src/algebra/order/sub.lean index 841041b0807ef..d6fd57b7a295d 100644 --- a/src/algebra/order/sub.lean +++ b/src/algebra/order/sub.lean @@ -693,23 +693,16 @@ protected lemma tsub_lt_tsub_iff_right (hc : add_le_cancellable c) (h : c ≤ a) a - c < b - c ↔ a < b := by rw [hc.lt_tsub_iff_left, add_tsub_cancel_of_le h] -protected lemma tsub_lt_self (ha : add_le_cancellable a) (hb : add_le_cancellable b) - (h₁ : 0 < a) (h₂ : 0 < b) : a - b < a := +protected lemma tsub_lt_self (ha : add_le_cancellable a) (h₁ : 0 < a) (h₂ : 0 < b) : a - b < a := begin - refine tsub_le_self.lt_of_ne _, - intro h, + refine tsub_le_self.lt_of_ne (λ h, _), rw [← h, tsub_pos_iff_lt] at h₁, - have := h.ge, - rw [hb.le_tsub_iff_left h₁.le, ha.add_le_iff_nonpos_left] at this, - exact h₂.not_le this, + exact h₂.not_le (ha.add_le_iff_nonpos_left.1 $ add_le_of_le_tsub_left_of_le h₁.le h.ge), end -protected lemma tsub_lt_self_iff (ha : add_le_cancellable a) (hb : add_le_cancellable b) : - a - b < a ↔ 0 < a ∧ 0 < b := +protected lemma tsub_lt_self_iff (ha : add_le_cancellable a) : a - b < a ↔ 0 < a ∧ 0 < b := begin - refine ⟨_, λ h, ha.tsub_lt_self hb h.1 h.2⟩, - intro h, - refine ⟨(zero_le _).trans_lt h, (zero_le b).lt_of_ne _⟩, + refine ⟨λ h, ⟨(zero_le _).trans_lt h, (zero_le b).lt_of_ne _⟩, λ h, ha.tsub_lt_self h.1 h.2⟩, rintro rfl, rw [tsub_zero] at h, exact h.false @@ -729,11 +722,10 @@ variable [contravariant_class α α (+) (≤)] lemma tsub_lt_tsub_iff_right (h : c ≤ a) : a - c < b - c ↔ a < b := contravariant.add_le_cancellable.tsub_lt_tsub_iff_right h -lemma tsub_lt_self (h₁ : 0 < a) (h₂ : 0 < b) : a - b < a := -contravariant.add_le_cancellable.tsub_lt_self contravariant.add_le_cancellable h₁ h₂ +lemma tsub_lt_self : 0 < a → 0 < b → a - b < a := contravariant.add_le_cancellable.tsub_lt_self lemma tsub_lt_self_iff : a - b < a ↔ 0 < a ∧ 0 < b := -contravariant.add_le_cancellable.tsub_lt_self_iff contravariant.add_le_cancellable +contravariant.add_le_cancellable.tsub_lt_self_iff /-- See `lt_tsub_iff_left_of_le_of_le` for a weaker statement in a partial order. -/ lemma tsub_lt_tsub_iff_left_of_le (h : b ≤ a) : a - b < a - c ↔ c < b := diff --git a/src/data/real/ennreal.lean b/src/data/real/ennreal.lean index f8e728045d543..0738b25560f24 100644 --- a/src/data/real/ennreal.lean +++ b/src/data/real/ennreal.lean @@ -743,37 +743,54 @@ by { cases a; cases b; simp [← with_top.coe_sub] } lemma sub_ne_top (ha : a ≠ ∞) : a - b ≠ ∞ := mt sub_eq_top_iff.mp $ mt and.left ha -protected lemma sub_lt_of_lt_add (hac : c ≤ a) (h : a < b + c) : a - c < b := -((cancel_of_lt' $ hac.trans_lt h).tsub_lt_iff_right hac).mpr h +protected lemma sub_eq_of_eq_add (hb : b ≠ ∞) : a = c + b → a - b = c := +(cancel_of_ne hb).tsub_eq_of_eq_add -@[simp] lemma add_sub_self (hb : b ≠ ∞) : (a + b) - b = a := -(cancel_of_ne hb).add_tsub_cancel_right +protected lemma eq_sub_of_add_eq (hc : c ≠ ∞) : a + c = b → a = b - c := +(cancel_of_ne hc).eq_tsub_of_add_eq -@[simp] lemma add_sub_self' (ha : a ≠ ∞) : (a + b) - a = b := -(cancel_of_ne ha).add_tsub_cancel_left +protected lemma sub_eq_of_eq_add_rev (hb : b ≠ ∞) : a = b + c → a - b = c := +(cancel_of_ne hb).tsub_eq_of_eq_add_rev lemma sub_eq_of_add_eq (hb : b ≠ ∞) (hc : a + b = c) : c - b = a := -(cancel_of_ne hb).tsub_eq_of_eq_add hc.symm +ennreal.sub_eq_of_eq_add hb hc.symm -protected lemma lt_add_of_sub_lt (ht : a ≠ ∞ ∨ b ≠ ∞) (h : a - b < c) : a < c + b := +@[simp] protected lemma add_sub_cancel_left (ha : a ≠ ∞) : a + b - a = b := +(cancel_of_ne ha).add_tsub_cancel_left + +@[simp] protected lemma add_sub_cancel_right (hb : b ≠ ∞) : a + b - b = a := +(cancel_of_ne hb).add_tsub_cancel_right + +protected lemma lt_add_of_sub_lt_left (h : a ≠ ∞ ∨ b ≠ ∞) : a - b < c → a < b + c := begin - rcases eq_or_ne b ∞ with rfl|hb, - { rw [add_top, lt_top_iff_ne_top], exact ht.resolve_right (not_not.2 rfl) }, - { exact (cancel_of_ne hb).lt_add_of_tsub_lt_right h } + obtain rfl | hb := eq_or_ne b ∞, + { rw [top_add, lt_top_iff_ne_top], + exact λ _, h.resolve_right (not_not.2 rfl) }, + { exact (cancel_of_ne hb).lt_add_of_tsub_lt_left } end -protected lemma sub_lt_iff_lt_add (hb : b ≠ ∞) (hab : b ≤ a) : a - b < c ↔ a < c + b := -(cancel_of_ne hb).tsub_lt_iff_right hab - -protected lemma sub_lt_self (hat : a ≠ ∞) (ha0 : a ≠ 0) (hb : b ≠ 0) : a - b < a := +protected lemma lt_add_of_sub_lt_right (h : a ≠ ∞ ∨ c ≠ ∞) : a - c < b → a < b + c := begin - cases b, { simp [pos_iff_ne_zero, ha0] }, - exact (cancel_of_ne hat).tsub_lt_self cancel_coe (pos_iff_ne_zero.mpr ha0) - (pos_iff_ne_zero.mpr hb) + obtain rfl | hc := eq_or_ne c ∞, + { rw [add_top, lt_top_iff_ne_top], + exact λ _, h.resolve_right (not_not.2 rfl) }, + { exact (cancel_of_ne hc).lt_add_of_tsub_lt_right } end +protected lemma sub_lt_of_lt_add (hac : c ≤ a) (h : a < b + c) : a - c < b := +((cancel_of_lt' $ hac.trans_lt h).tsub_lt_iff_right hac).mpr h + +protected lemma sub_lt_iff_lt_right (hb : b ≠ ∞) (hab : b ≤ a) : a - b < c ↔ a < c + b := +(cancel_of_ne hb).tsub_lt_iff_right hab + +protected lemma sub_lt_self (ha : a ≠ ∞) (ha₀ : a ≠ 0) (hb : b ≠ 0) : a - b < a := +(cancel_of_ne ha).tsub_lt_self (pos_iff_ne_zero.2 ha₀) (pos_iff_ne_zero.2 hb) + +protected lemma sub_lt_self_iff (ha : a ≠ ∞) : a - b < a ↔ 0 < a ∧ 0 < b := +(cancel_of_ne ha).tsub_lt_self_iff + lemma sub_lt_of_sub_lt (h₂ : c ≤ a) (h₃ : a ≠ ∞ ∨ b ≠ ∞) (h₁ : a - b < c) : a - c < b := -ennreal.sub_lt_of_lt_add h₂ (add_comm c b ▸ ennreal.lt_add_of_sub_lt h₃ h₁) +ennreal.sub_lt_of_lt_add h₂ (add_comm c b ▸ ennreal.lt_add_of_sub_lt_right h₃ h₁) lemma sub_sub_cancel (h : a ≠ ∞) (h2 : b ≤ a) : a - (a - b) = b := (cancel_of_ne $ sub_ne_top h).tsub_tsub_cancel_of_le h2 @@ -1190,8 +1207,7 @@ le_of_forall_nnreal_lt $ λ r hr, (zero_le r).eq_or_lt.elim (λ h, h ▸ zero_le lemma eq_top_of_forall_nnreal_le {x : ℝ≥0∞} (h : ∀ r : ℝ≥0, ↑r ≤ x) : x = ∞ := top_unique $ le_of_forall_nnreal_lt $ λ r hr, h r -lemma add_div {a b c : ℝ≥0∞} : (a + b) / c = a / c + b / c := -right_distrib a b (c⁻¹) +lemma add_div : (a + b) / c = a / c + b / c := right_distrib a b (c⁻¹) lemma div_add_div_same {a b c : ℝ≥0∞} : a / c + b / c = (a + b) / c := eq.symm $ right_distrib a b (c⁻¹) diff --git a/src/measure_theory/measure/regular.lean b/src/measure_theory/measure/regular.lean index 1e4e074cadeb7..49c5c34b32eb7 100644 --- a/src/measure_theory/measure/regular.lean +++ b/src/measure_theory/measure/regular.lean @@ -163,7 +163,7 @@ begin { refine ⟨∅, empty_subset _, h0, _⟩, rwa [measure_empty, h₀, zero_add, pos_iff_ne_zero] }, { rcases H hU _ (ennreal.sub_lt_self hμU h₀ hε) with ⟨K, hKU, hKc, hrK⟩, - exact ⟨K, hKU, hKc, ennreal.lt_add_of_sub_lt (or.inl hμU) hrK⟩ } + exact ⟨K, hKU, hKc, ennreal.lt_add_of_sub_lt_right (or.inl hμU) hrK⟩ } end lemma map {α β} [measurable_space α] [measurable_space β] {μ : measure α} {pa qa : set α → Prop} diff --git a/src/topology/instances/ennreal.lean b/src/topology/instances/ennreal.lean index aaa2edfca4536..1a0b69d972ba8 100644 --- a/src/topology/instances/ennreal.lean +++ b/src/topology/instances/ennreal.lean @@ -830,7 +830,7 @@ lemma tsum_sub {f : ℕ → ℝ≥0∞} {g : ℕ → ℝ≥0∞} (h₁ : ∑' i, ∑' i, (f i - g i) = (∑' i, f i) - (∑' i, g i) := begin have h₃: ∑' i, (f i - g i) = ∑' i, (f i - g i + g i) - ∑' i, g i, - { rw [ennreal.tsum_add, add_sub_self h₁]}, + { rw [ennreal.tsum_add, ennreal.add_sub_cancel_right h₁]}, have h₄:(λ i, (f i - g i) + (g i)) = f, { ext n, rw tsub_add_cancel_of_le (h₂ n)}, rw h₄ at h₃, apply h₃, From 8430aae360fa454c4d5ece0b80d41c21a557bbb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Thu, 21 Apr 2022 20:30:51 +0000 Subject: [PATCH 142/373] feat(algebra/group_power/lemmas): More lemmas through `to_additive` (#13537) Use `to_additive` to generate a bunch of old `nsmul`/`zsmul` lemmas from new `pow`/`zpow` ones. Also protect `nat.nsmul_eq_mul` as it should have been. --- src/algebra/group_power/basic.lean | 16 +- src/algebra/group_power/lemmas.lean | 242 +++++++++++++--------------- src/algebra/group_power/order.lean | 13 ++ src/data/nat/basic.lean | 3 +- src/data/nat/periodic.lean | 2 +- 5 files changed, 138 insertions(+), 138 deletions(-) diff --git a/src/algebra/group_power/basic.lean b/src/algebra/group_power/basic.lean index 15a0dde867fe0..ce8b27f87e5de 100644 --- a/src/algebra/group_power/basic.lean +++ b/src/algebra/group_power/basic.lean @@ -452,7 +452,8 @@ lemma of_mul_zpow [div_inv_monoid G] (x : G) (n : ℤ) : additive.of_mul (x ^ n) = n • additive.of_mul x := rfl -@[simp] lemma semiconj_by.zpow_right [group G] {a x y : G} (h : semiconj_by a x y) : +@[simp, to_additive] +lemma semiconj_by.zpow_right [group G] {a x y : G} (h : semiconj_by a x y) : ∀ m : ℤ, semiconj_by a (x^m) (y^m) | (n : ℕ) := by simp [zpow_coe_nat, h.pow_right n] | -[1+n] := by simp [(h.pow_right n.succ).inv_right] @@ -461,18 +462,19 @@ namespace commute variables [group G] {a b : G} -@[simp] lemma zpow_right (h : commute a b) (m : ℤ) : commute a (b^m) := -h.zpow_right m +@[simp, to_additive] lemma zpow_right (h : commute a b) (m : ℤ) : commute a (b^m) := h.zpow_right m -@[simp] lemma zpow_left (h : commute a b) (m : ℤ) : commute (a^m) b := +@[simp, to_additive] lemma zpow_left (h : commute a b) (m : ℤ) : commute (a^m) b := (h.symm.zpow_right m).symm +@[to_additive] lemma zpow_zpow (h : commute a b) (m n : ℤ) : commute (a^m) (b^n) := (h.zpow_left m).zpow_right n variables (a) (m n : ℤ) -@[simp] theorem self_zpow : commute a (a ^ n) := (commute.refl a).zpow_right n -@[simp] theorem zpow_self : commute (a ^ n) a := (commute.refl a).zpow_left n -@[simp] theorem zpow_zpow_self : commute (a ^ m) (a ^ n) := (commute.refl a).zpow_zpow m n +@[simp, to_additive] lemma self_zpow : commute a (a ^ n) := (commute.refl a).zpow_right n +@[simp, to_additive] lemma zpow_self : commute (a ^ n) a := (commute.refl a).zpow_left n +@[simp, to_additive] lemma zpow_zpow_self : commute (a ^ m) (a ^ n) := +(commute.refl a).zpow_zpow m n end commute diff --git a/src/algebra/group_power/lemmas.lean b/src/algebra/group_power/lemmas.lean index 1c1443ed08cfc..39df5aeb588a6 100644 --- a/src/algebra/group_power/lemmas.lean +++ b/src/algebra/group_power/lemmas.lean @@ -13,9 +13,11 @@ This file contains lemmas about `monoid.pow`, `group.pow`, `nsmul`, `zsmul` which require additional imports besides those available in `algebra.group_power.basic`. -/ +open function int nat + universes u v w x y z u₁ u₂ -variables {M : Type u} {N : Type v} {G : Type w} {H : Type x} {A : Type y} {B : Type z} +variables {α : Type*} {M : Type u} {N : Type v} {G : Type w} {H : Type x} {A : Type y} {B : Type z} {R : Type u₁} {S : Type u₂} /-! @@ -96,16 +98,15 @@ end end monoid -section group -variables [group G] [group H] [add_group A] [add_group B] +section sub_neg_monoid +variables [sub_neg_monoid A] -open int +lemma zsmul_one [has_one A] (n : ℤ) : n • (1 : A) = n := by cases n; simp -local attribute [ematch] le_of_lt -open nat +end sub_neg_monoid -theorem zsmul_one [has_one A] (n : ℤ) : n • (1 : A) = n := -by cases n; simp +section group +variables [group G] @[to_additive add_one_zsmul] lemma zpow_add_one (a : G) : ∀ n : ℤ, a ^ (n + 1) = a ^ n * a @@ -168,73 +169,107 @@ by rw [bit1, zpow_add, zpow_bit0, zpow_one] end group -section ordered_add_comm_group +/-! +### `zpow`/`zsmul` and an order -variables [ordered_add_comm_group A] -/-! Lemmas about `zsmul` under ordering, placed here (rather than in `algebra.group_power.order` -with their friends) because they require facts from `data.int.basic`-/ -open int +Those lemmas are placed here (rather than in `algebra.group_power.order` with their friends) because +they require facts from `data.int.basic`. +-/ -lemma zsmul_pos {a : A} (ha : 0 < a) {k : ℤ} (hk : (0:ℤ) < k) : 0 < k • a := +section ordered_add_comm_group +variables [ordered_comm_group α] {m n : ℤ} {a b : α} + +@[to_additive zsmul_pos] +lemma one_lt_zpow' (ha : 1 < a) {k : ℤ} (hk : (0:ℤ) < k) : 1 < a^k := begin lift k to ℕ using int.le_of_lt hk, - rw coe_nat_zsmul, - apply nsmul_pos ha, - exact (coe_nat_pos.mp hk).ne', + rw zpow_coe_nat, + exact one_lt_pow' ha (coe_nat_pos.mp hk).ne', end -theorem zsmul_strict_mono_left {a : A} (ha : 0 < a) : strict_mono (λ n : ℤ, n • a) := -λ n m h, - calc n • a = n • a + 0 : (add_zero _).symm - ... < n • a + (m - n) • a : add_lt_add_left (zsmul_pos ha (sub_pos.mpr h)) _ - ... = m • a : by { rw [← add_zsmul], simp } +@[to_additive zsmul_strict_mono_left] +lemma zpow_strict_mono_right (ha : 1 < a) : strict_mono (λ n : ℤ, a ^ n) := +λ m n h, + calc a ^ m = a ^ m * 1 : (mul_one _).symm + ... < a ^ m * a ^ (n - m) : mul_lt_mul_left' (one_lt_zpow' ha $ sub_pos_of_lt h) _ + ... = a ^ n : by { rw ←zpow_add, simp } -theorem zsmul_mono_left {a : A} (ha : 0 ≤ a) : monotone (λ n : ℤ, n • a) := -λ n m h, - calc n • a = n • a + 0 : (add_zero _).symm - ... ≤ n • a + (m - n) • a : add_le_add_left (zsmul_nonneg ha (sub_nonneg.mpr h)) _ - ... = m • a : by { rw [← add_zsmul], simp } +@[to_additive zsmul_mono_left] +lemma zpow_mono_right (ha : 1 ≤ a) : monotone (λ n : ℤ, a ^ n) := +λ m n h, + calc a ^ m = a ^ m * 1 : (mul_one _).symm + ... ≤ a ^ m * a ^ (n - m) : mul_le_mul_left' (one_le_zpow ha $ sub_nonneg_of_le h) _ + ... = a ^ n : by { rw ←zpow_add, simp } -theorem zsmul_le_zsmul {a : A} {n m : ℤ} (ha : 0 ≤ a) (h : n ≤ m) : n • a ≤ m • a := -zsmul_mono_left ha h +@[to_additive] +lemma zpow_le_zpow (ha : 1 ≤ a) (h : m ≤ n) : a ^ m ≤ a ^ n := zpow_mono_right ha h -theorem zsmul_lt_zsmul {a : A} {n m : ℤ} (ha : 0 < a) (h : n < m) : n • a < m • a := -zsmul_strict_mono_left ha h +@[to_additive] +lemma zpow_lt_zpow (ha : 1 < a) (h : m < n) : a ^ m < a ^ n := zpow_strict_mono_right ha h -theorem zsmul_le_zsmul_iff {a : A} {n m : ℤ} (ha : 0 < a) : n • a ≤ m • a ↔ n ≤ m := -(zsmul_strict_mono_left ha).le_iff_le +@[to_additive] +lemma zpow_le_zpow_iff (ha : 1 < a) : a ^ m ≤ a ^ n ↔ m ≤ n := (zpow_strict_mono_right ha).le_iff_le -theorem zsmul_lt_zsmul_iff {a : A} {n m : ℤ} (ha : 0 < a) : n • a < m • a ↔ n < m := -(zsmul_strict_mono_left ha).lt_iff_lt +@[to_additive] +lemma zpow_lt_zpow_iff (ha : 1 < a) : a ^ m < a ^ n ↔ m < n := (zpow_strict_mono_right ha).lt_iff_lt -variables (A) +variables (α) -lemma zsmul_strict_mono_right {n : ℤ} (hn : 0 < n) : - strict_mono ((•) n : A → A) := -λ a b hab, begin - rw ← sub_pos at hab, - rw [← sub_pos, ← zsmul_sub], - exact zsmul_pos hab hn, -end +@[to_additive zsmul_strict_mono_right] +lemma zpow_strict_mono_left (hn : 0 < n) : strict_mono ((^ n) : α → α) := +λ a b hab, by { rw [←one_lt_div', ←div_zpow], exact one_lt_zpow' (one_lt_div'.2 hab) hn } + +@[to_additive zsmul_mono_right] +lemma zpow_mono_left (hn : 0 ≤ n) : monotone ((^ n) : α → α) := +λ a b hab, by { rw [←one_le_div', ←div_zpow], exact one_le_zpow (one_le_div'.2 hab) hn } + +variables {α} + +@[to_additive] +lemma zpow_le_zpow' (hn : 0 ≤ n) (h : a ≤ b) : a ^ n ≤ b ^ n := zpow_mono_left α hn h + +@[to_additive] +lemma zpow_lt_zpow' (hn : 0 < n) (h : a < b) : a ^ n < b ^ n := zpow_strict_mono_left α hn h + +end ordered_add_comm_group + +section linear_ordered_comm_group +variables [linear_ordered_comm_group α] {n : ℤ} {a b : α} + +@[to_additive] +lemma zpow_le_zpow_iff' (hn : 0 < n) {a b : α} : a ^ n ≤ b ^ n ↔ a ≤ b := +(zpow_strict_mono_left α hn).le_iff_le + +@[to_additive] +lemma zpow_lt_zpow_iff' (hn : 0 < n) {a b : α} : a ^ n < b ^ n ↔ a < b := +(zpow_strict_mono_left α hn).lt_iff_lt -lemma zsmul_mono_right {n : ℤ} (hn : 0 ≤ n) : - monotone ((•) n : A → A) := -λ a b hab, begin - rw ← sub_nonneg at hab, - rw [← sub_nonneg, ← zsmul_sub], - exact zsmul_nonneg hab hn, +@[nolint to_additive_doc, to_additive zsmul_right_injective +"See also `smul_right_injective`. TODO: provide a `no_zero_smul_divisors` instance. We can't do that +here because importing that definition would create import cycles."] +lemma zpow_left_injective (hn : n ≠ 0) : function.injective ((^ n) : α → α) := +begin + cases hn.symm.lt_or_lt, + { exact (zpow_strict_mono_left α h).injective }, + { refine λ a b (hab : a ^ n = b ^ n), (zpow_strict_mono_left α (neg_pos.mpr h)).injective _, + rw [zpow_neg, zpow_neg, hab] } end -variables {A} +@[to_additive zsmul_right_inj] +lemma zpow_left_inj (hn : n ≠ 0) : a ^ n = b ^ n ↔ a = b := (zpow_left_injective hn).eq_iff -theorem zsmul_le_zsmul' {n : ℤ} (hn : 0 ≤ n) {a₁ a₂ : A} (h : a₁ ≤ a₂) : n • a₁ ≤ n • a₂ := -zsmul_mono_right A hn h +/-- Alias of `zsmul_right_inj`, for ease of discovery alongside `zsmul_le_zsmul_iff'` and +`zsmul_lt_zsmul_iff'`. -/ +@[to_additive "Alias of `zsmul_right_inj`, for ease of discovery alongside `zsmul_le_zsmul_iff'` and +`zsmul_lt_zsmul_iff'`."] +lemma zpow_eq_zpow_iff' (hn : n ≠ 0) : a ^ n = b ^ n ↔ a = b := zpow_left_inj hn -theorem zsmul_lt_zsmul' {n : ℤ} (hn : 0 < n) {a₁ a₂ : A} (h : a₁ < a₂) : n • a₁ < n • a₂ := -zsmul_strict_mono_right A hn h +end linear_ordered_comm_group -lemma abs_nsmul {α : Type*} [linear_ordered_add_comm_group α] (n : ℕ) (a : α) : - |n • a| = n • |a| := +section linear_ordered_add_comm_group +variables [linear_ordered_add_comm_group α] {a b : α} + +lemma abs_nsmul (n : ℕ) (a : α) : |n • a| = n • |a| := begin cases le_total a 0 with hneg hpos, { rw [abs_of_nonpos hneg, ← abs_neg, ← neg_nsmul, abs_of_nonneg], @@ -243,91 +278,42 @@ begin exact nsmul_nonneg hpos n } end -lemma abs_zsmul {α : Type*} [linear_ordered_add_comm_group α] (n : ℤ) (a : α) : - |n • a| = |n| • |a| := +lemma abs_zsmul (n : ℤ) (a : α) : |n • a| = |n| • |a| := begin - by_cases n0 : 0 ≤ n, + obtain n0 | n0 := le_total 0 n, { lift n to ℕ using n0, simp only [abs_nsmul, coe_nat_abs, coe_nat_zsmul] }, - { lift (- n) to ℕ using int.le_of_lt (neg_pos.mpr (not_le.mp n0)) with m h, + { lift (- n) to ℕ using neg_nonneg.2 n0 with m h, rw [← abs_neg (n • a), ← neg_zsmul, ← abs_neg n, ← h, coe_nat_zsmul, coe_nat_abs, coe_nat_zsmul], exact abs_nsmul m _ }, end -lemma abs_add_eq_add_abs_le {α : Type*} [linear_ordered_add_comm_group α] {a b : α} (hle : a ≤ b) : - |a + b| = |a| + |b| ↔ (0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0) := +lemma abs_add_eq_add_abs_le (hle : a ≤ b) : |a + b| = |a| + |b| ↔ 0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0 := begin - by_cases a0 : 0 ≤ a; by_cases b0 : 0 ≤ b, + obtain a0 | a0 := le_or_lt 0 a; obtain b0 | b0 := le_or_lt 0 b, { simp [a0, b0, abs_of_nonneg, add_nonneg a0 b0] }, - { exact (lt_irrefl (0 : α) (a0.trans_lt (hle.trans_lt (not_le.mp b0)))).elim }, - any_goals { simp [(not_le.mp a0).le, (not_le.mp b0).le, abs_of_nonpos, add_nonpos, add_comm] }, - obtain F := (not_le.mp a0), + { exact (lt_irrefl (0 : α) $ a0.trans_lt $ hle.trans_lt b0).elim }, + any_goals { simp [a0.le, b0.le, abs_of_nonpos, add_nonpos, add_comm] }, have : (|a + b| = -a + b ↔ b ≤ 0) ↔ (|a + b| = |a| + |b| ↔ 0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0), - { simp [a0, b0, abs_of_neg, abs_of_nonneg, F, F.le] }, - refine this.mp ⟨λ h, _, λ h, by simp only [le_antisymm h b0, abs_of_neg F, add_zero]⟩, - by_cases ba : a + b ≤ 0, + { simp [a0, a0.le, a0.not_le, b0, abs_of_neg, abs_of_nonneg] }, + refine this.mp ⟨λ h, _, λ h, by simp only [le_antisymm h b0, abs_of_neg a0, add_zero]⟩, + obtain ab | ab := le_or_lt (a + b) 0, { refine le_of_eq (eq_zero_of_neg_eq _), - rwa [abs_of_nonpos ba, neg_add_rev, add_comm, add_right_inj] at h }, + rwa [abs_of_nonpos ab, neg_add_rev, add_comm, add_right_inj] at h }, { refine (lt_irrefl (0 : α) _).elim, - rw [abs_of_pos (not_le.mp ba), add_left_inj] at h, - rwa eq_zero_of_neg_eq h.symm at F } + rw [abs_of_pos ab, add_left_inj] at h, + rwa eq_zero_of_neg_eq h.symm at a0 } end -lemma abs_add_eq_add_abs_iff {α : Type*} [linear_ordered_add_comm_group α] (a b : α) : - |a + b| = |a| + |b| ↔ (0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0) := +lemma abs_add_eq_add_abs_iff (a b : α) : |a + b| = |a| + |b| ↔ 0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0 := begin - by_cases ab : a ≤ b, + obtain ab | ab := le_total a b, { exact abs_add_eq_add_abs_le ab }, - { rw [add_comm a, add_comm (abs _), abs_add_eq_add_abs_le ((not_le.mp ab).le), and.comm, - @and.comm (b ≤ 0 ) _] } + { rw [add_comm a, add_comm (abs _), abs_add_eq_add_abs_le ab, and.comm, @and.comm (b ≤ 0)] } end -end ordered_add_comm_group - -section linear_ordered_add_comm_group -variable [linear_ordered_add_comm_group A] - -theorem zsmul_le_zsmul_iff' {n : ℤ} (hn : 0 < n) {a₁ a₂ : A} : n • a₁ ≤ n • a₂ ↔ a₁ ≤ a₂ := -(zsmul_strict_mono_right A hn).le_iff_le - -theorem zsmul_lt_zsmul_iff' {n : ℤ} (hn : 0 < n) {a₁ a₂ : A} : n • a₁ < n • a₂ ↔ a₁ < a₂ := -(zsmul_strict_mono_right A hn).lt_iff_lt - -theorem nsmul_le_nsmul_iff {a : A} {n m : ℕ} (ha : 0 < a) : n • a ≤ m • a ↔ n ≤ m := -begin - refine ⟨λ h, _, nsmul_le_nsmul $ le_of_lt ha⟩, - by_contra H, - exact lt_irrefl _ (lt_of_lt_of_le (nsmul_lt_nsmul ha (not_le.mp H)) h) -end - -theorem nsmul_lt_nsmul_iff {a : A} {n m : ℕ} (ha : 0 < a) : n • a < m • a ↔ n < m := -begin - refine ⟨λ h, _, nsmul_lt_nsmul ha⟩, - by_contra H, - exact lt_irrefl _ (lt_of_le_of_lt (nsmul_le_nsmul (le_of_lt ha) $ not_lt.mp H) h) -end - -/-- See also `smul_right_injective`. TODO: provide a `no_zero_smul_divisors` instance. We can't -do that here because importing that definition would create import cycles. -/ -lemma zsmul_right_injective {m : ℤ} (hm : m ≠ 0) : function.injective ((•) m : A → A) := -begin - cases hm.symm.lt_or_lt, - { exact (zsmul_strict_mono_right A h).injective, }, - { intros a b hab, - refine (zsmul_strict_mono_right A (neg_pos.mpr h)).injective _, - rw [neg_zsmul, neg_zsmul, hab], }, -end - -lemma zsmul_right_inj {a b : A} {m : ℤ} (hm : m ≠ 0) : m • a = m • b ↔ a = b := -(zsmul_right_injective hm).eq_iff - -/-- Alias of `zsmul_right_inj`, for ease of discovery alongside `zsmul_le_zsmul_iff'` and -`zsmul_lt_zsmul_iff'`. -/ -lemma zsmul_eq_zsmul_iff' {a b : A} {m : ℤ} (hm : m ≠ 0) : m • a = m • b ↔ a = b := -zsmul_right_inj hm - end linear_ordered_add_comm_group @[simp] lemma with_bot.coe_nsmul [add_monoid A] (a : A) (n : ℕ) : @@ -774,16 +760,16 @@ h.cast_nat_mul_right n h.cast_nat_mul_left n @[simp] theorem cast_nat_mul_cast_nat_mul (h : commute a b) (m n : ℕ) : - commute ((m : R) * a) (n * b) := + commute (m * a : R) (n * b : R) := h.cast_nat_mul_cast_nat_mul m n -@[simp] theorem self_cast_nat_mul (n : ℕ) : commute a (n * a) := +@[simp] theorem self_cast_nat_mul (n : ℕ) : commute a (n * a : R) := (commute.refl a).cast_nat_mul_right n @[simp] theorem cast_nat_mul_self (n : ℕ) : commute ((n : R) * a) a := (commute.refl a).cast_nat_mul_left n -@[simp] theorem self_cast_nat_mul_cast_nat_mul (m n : ℕ) : commute ((m : R) * a) (n * a) := +@[simp] theorem self_cast_nat_mul_cast_nat_mul (m n : ℕ) : commute (m * a : R) (n * a : R) := (commute.refl a).cast_nat_mul_cast_nat_mul m n end @@ -800,13 +786,13 @@ h.units_zpow_right m variables {a b : R} -@[simp] lemma cast_int_mul_right (h : commute a b) (m : ℤ) : commute a (m * b) := +@[simp] lemma cast_int_mul_right (h : commute a b) (m : ℤ) : commute a (m * b : R) := h.cast_int_mul_right m @[simp] lemma cast_int_mul_left (h : commute a b) (m : ℤ) : commute ((m : R) * a) b := h.cast_int_mul_left m -lemma cast_int_mul_cast_int_mul (h : commute a b) (m n : ℤ) : commute ((m : R) * a) (n * b) := +lemma cast_int_mul_cast_int_mul (h : commute a b) (m n : ℤ) : commute (m * a : R) (n * b : R) := h.cast_int_mul_cast_int_mul m n variables (a) (m n : ℤ) @@ -817,11 +803,11 @@ by { rw [← mul_one (m : R)], exact (one_left a).cast_int_mul_left m } @[simp] lemma cast_int_right : commute a m := by { rw [← mul_one (m : R)], exact (one_right a).cast_int_mul_right m } -@[simp] theorem self_cast_int_mul : commute a (n * a) := (commute.refl a).cast_int_mul_right n +@[simp] theorem self_cast_int_mul : commute a (n * a : R) := (commute.refl a).cast_int_mul_right n @[simp] theorem cast_int_mul_self : commute ((n : R) * a) a := (commute.refl a).cast_int_mul_left n -theorem self_cast_int_mul_cast_int_mul : commute ((m : R) * a) (n * a) := +theorem self_cast_int_mul_cast_int_mul : commute (m * a : R) (n * a : R) := (commute.refl a).cast_int_mul_cast_int_mul m n end commute diff --git a/src/algebra/group_power/order.lean b/src/algebra/group_power/order.lean index c4f272c95aa92..f8cfbf4430102 100644 --- a/src/algebra/group_power/order.lean +++ b/src/algebra/group_power/order.lean @@ -71,6 +71,11 @@ begin exact lt_mul_of_one_lt_right' _ (one_lt_pow' ha k.succ_ne_zero) end +@[to_additive nsmul_strict_mono_right] +lemma pow_strict_mono_left [covariant_class M M (*) (<)] {a : M} (ha : 1 < a) : + strict_mono ((^) a : ℕ → M) := +λ m n, pow_lt_pow' ha + end preorder section linear_order @@ -97,6 +102,14 @@ lt_iff_lt_of_le_iff_le (one_le_pow_iff hn) lemma pow_eq_one_iff {x : M} {n : ℕ} (hn : n ≠ 0) : x ^ n = 1 ↔ x = 1 := by simp only [le_antisymm_iff, pow_le_one_iff hn, one_le_pow_iff hn] +variables [covariant_class M M (*) (<)] {a : M} {m n : ℕ} + +@[to_additive nsmul_le_nsmul_iff] +lemma pow_le_pow_iff' (ha : 1 < a) : a ^ m ≤ a ^ n ↔ m ≤ n := (pow_strict_mono_left ha).le_iff_le + +@[to_additive nsmul_lt_nsmul_iff] +lemma pow_lt_pow_iff' (ha : 1 < a) : a ^ m < a ^ n ↔ m < n := (pow_strict_mono_left ha).lt_iff_lt + end linear_order section div_inv_monoid diff --git a/src/data/nat/basic.lean b/src/data/nat/basic.lean index b722cb1d05dd3..6903ff1ac2f78 100644 --- a/src/data/nat/basic.lean +++ b/src/data/nat/basic.lean @@ -116,8 +116,7 @@ instance nat.subtype.semilattice_sup (s : set ℕ) : lemma nat.subtype.coe_bot {s : set ℕ} [decidable_pred (∈ s)] [h : nonempty s] : ((⊥ : s) : ℕ) = nat.find (nonempty_subtype.1 h) := rfl -theorem nat.nsmul_eq_mul (m n : ℕ) : m • n = m * n := -rfl +protected lemma nat.nsmul_eq_mul (m n : ℕ) : m • n = m * n := rfl theorem nat.eq_of_mul_eq_mul_right {n m k : ℕ} (Hm : 0 < m) (H : n * m = k * m) : n = k := by rw [mul_comm n m, mul_comm k m] at H; exact nat.eq_of_mul_eq_mul_left Hm H diff --git a/src/data/nat/periodic.lean b/src/data/nat/periodic.lean index 1adf5012fd993..a5a14e738006c 100644 --- a/src/data/nat/periodic.lean +++ b/src/data/nat/periodic.lean @@ -29,7 +29,7 @@ by simp only [forall_const, eq_self_iff_true, add_mod_right, periodic] lemma _root_.function.periodic.map_mod_nat {α : Type*} {f : ℕ → α} {a : ℕ} (hf : periodic f a) : ∀ n, f (n % a) = f n := -λ n, by conv_rhs { rw [← nat.mod_add_div n a, mul_comm, ← nsmul_eq_mul, hf.nsmul] } +λ n, by conv_rhs { rw [← nat.mod_add_div n a, mul_comm, ← nat.nsmul_eq_mul, hf.nsmul] } section multiset open multiset From 090e59d08005f984e112aa4a765031c2c0f384bc Mon Sep 17 00:00:00 2001 From: Floris van Doorn Date: Thu, 21 Apr 2022 20:30:53 +0000 Subject: [PATCH 143/373] feat(analysis/normed_space/operator_norm): norm of `lsmul` (#13538) * From the sphere eversion project * Required for convolutions --- src/analysis/normed_space/operator_norm.lean | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/analysis/normed_space/operator_norm.lean b/src/analysis/normed_space/operator_norm.lean index abf47d429b8c3..8e8456d198aef 100644 --- a/src/analysis/normed_space/operator_norm.lean +++ b/src/analysis/normed_space/operator_norm.lean @@ -840,6 +840,7 @@ section smul_linear variables (𝕜) (𝕜' : Type*) [normed_field 𝕜'] [normed_algebra 𝕜 𝕜'] [normed_space 𝕜' E] [is_scalar_tower 𝕜 𝕜' E] + [normed_space 𝕜' M₁] [is_scalar_tower 𝕜 𝕜' M₁] /-- Scalar multiplication as a continuous bilinear map. -/ def lsmul : 𝕜' →L[𝕜] E →L[𝕜] E := @@ -859,6 +860,31 @@ begin exact (mul_le_mul_right (by simp)).mp h, }, end +variables {𝕜} + +/-- The norm of `lsmul` is at most 1 in any semi-normed group. -/ +lemma op_norm_lsmul_le : ∥(lsmul 𝕜 𝕜' : 𝕜' →L[𝕜] E →L[𝕜] E)∥ ≤ 1 := +begin + refine continuous_linear_map.op_norm_le_bound _ zero_le_one (λ x, _), + simp_rw [one_mul], + refine continuous_linear_map.op_norm_le_bound _ (norm_nonneg x) (λ y, _), + simp_rw [lsmul_apply, norm_smul], +end + +/-- The norm of `lsmul` equals 1 in any nontrivial normed group. -/ +@[simp] lemma op_norm_lsmul [nontrivial M₁] : ∥(lsmul 𝕜 𝕜' : 𝕜' →L[𝕜] M₁ →L[𝕜] M₁)∥ = 1 := +begin + refine continuous_linear_map.op_norm_eq_of_bounds zero_le_one (λ x, _) (λ N hN h, _), + { simp_rw [one_mul], + refine continuous_linear_map.op_norm_le_bound _ (norm_nonneg x) (λ y, _), + simp_rw [lsmul_apply, norm_smul] }, + obtain ⟨y, hy⟩ := exists_ne (0 : M₁), + have := le_of_op_norm_le _ (h 1) y, + simp_rw [lsmul_apply, one_smul, norm_one, mul_one] at this, + refine le_of_mul_le_mul_right _ (norm_pos_iff.mpr hy), + simp_rw [one_mul, this] +end + end smul_linear section restrict_scalars From afe14217a12abee4b585c99e687f889ca2a22eab Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Thu, 21 Apr 2022 20:30:54 +0000 Subject: [PATCH 144/373] feat(data/nat/pow): add theorem `nat.pow_mod` (#13551) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add theorem that states `∀ (a b n : ℕ) : a ^ b % n = (a % n) ^ b % n`. --- src/data/nat/pow.lean | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/data/nat/pow.lean b/src/data/nat/pow.lean index 5c6f42c853680..622d772c432c5 100644 --- a/src/data/nat/pow.lean +++ b/src/data/nat/pow.lean @@ -115,6 +115,12 @@ alias nat.sq_sub_sq ← nat.pow_two_sub_pow_two /-! ### `pow` and `mod` / `dvd` -/ +theorem pow_mod (a b n : ℕ) : a ^ b % n = (a % n) ^ b % n := +begin + induction b with b ih, + refl, simp [pow_succ, nat.mul_mod, ih], +end + theorem mod_pow_succ {b : ℕ} (w m : ℕ) : m % (b^succ w) = b * (m/b % b^w) + m % b := begin From efab188aa1176e5cbbcedd25ab9ef984b97429d1 Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Thu, 21 Apr 2022 20:30:55 +0000 Subject: [PATCH 145/373] refactor(group_theory/{submonoid, subsemigroup}/basic): move `mul_mem_class` (#13559) This moves `mul_mem_class` (and `add_mem_class`) from `group_theory/submonoid/basic` to `group_theory/subsemigroup/basic` so that `subsemigroup` can be an instance. We then protect `subsemigroup.mul_mem`. In addition, we add an induction principle for binary predicates to better parallel `group_theory/submonoid/basic`. --- src/group_theory/submonoid/basic.lean | 14 +-------- src/group_theory/subsemigroup/basic.lean | 37 +++++++++++++++++++++--- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/group_theory/submonoid/basic.lean b/src/group_theory/submonoid/basic.lean index 9693929f3f6e7..625fa2d15baa6 100644 --- a/src/group_theory/submonoid/basic.lean +++ b/src/group_theory/submonoid/basic.lean @@ -69,19 +69,7 @@ class zero_mem_class (S : Type*) (M : out_param $ Type*) [has_zero M] [set_like export zero_mem_class (zero_mem) -/-- `mul_mem_class S M` says `S` is a type of subsets `s ≤ M` that are closed under `(*)` -/ -class mul_mem_class (S : Type*) (M : out_param $ Type*) [has_mul M] [set_like S M] := -(mul_mem : ∀ {s : S} {a b : M}, a ∈ s → b ∈ s → a * b ∈ s) - -export mul_mem_class (mul_mem) - -/-- `add_mem_class S M` says `S` is a type of subsets `s ≤ M` that are closed under `(+)` -/ -class add_mem_class (S : Type*) (M : out_param $ Type*) [has_add M] [set_like S M] := -(add_mem : ∀ {s : S} {a b : M}, a ∈ s → b ∈ s → a + b ∈ s) - -export add_mem_class (add_mem) - -attribute [to_additive] one_mem_class mul_mem_class +attribute [to_additive] one_mem_class section diff --git a/src/group_theory/subsemigroup/basic.lean b/src/group_theory/subsemigroup/basic.lean index 445eaa37c0fc1..54b1b5cc5c2b8 100644 --- a/src/group_theory/subsemigroup/basic.lean +++ b/src/group_theory/subsemigroup/basic.lean @@ -10,8 +10,8 @@ import data.set_like.basic /-! # Subsemigroups: definition and `complete_lattice` structure -This file defines bundled multiplicative and additive subsemigrousp. We also define -a `complete_lattice` structure on `subsemigroups`s, +This file defines bundled multiplicative and additive subsemigroups. We also define +a `complete_lattice` structure on `subsemigroup`s, and define the closure of a set as the minimal subsemigroup that includes this set. ## Main definitions @@ -52,6 +52,20 @@ section non_assoc variables [has_mul M] {s : set M} variables [has_add A] {t : set A} +/-- `mul_mem_class S M` says `S` is a type of subsets `s ≤ M` that are closed under `(*)` -/ +class mul_mem_class (S : Type*) (M : out_param $ Type*) [has_mul M] [set_like S M] := +(mul_mem : ∀ {s : S} {a b : M}, a ∈ s → b ∈ s → a * b ∈ s) + +export mul_mem_class (mul_mem) + +/-- `add_mem_class S M` says `S` is a type of subsets `s ≤ M` that are closed under `(+)` -/ +class add_mem_class (S : Type*) (M : out_param $ Type*) [has_add M] [set_like S M] := +(add_mem : ∀ {s : S} {a b : M}, a ∈ s → b ∈ s → a + b ∈ s) + +export add_mem_class (add_mem) + +attribute [to_additive] mul_mem_class + /-- A subsemigroup of a magma `M` is a subset closed under multiplication. -/ structure subsemigroup (M : Type*) [has_mul M] := (carrier : set M) @@ -70,6 +84,10 @@ namespace subsemigroup instance : set_like (subsemigroup M) M := ⟨subsemigroup.carrier, λ p q h, by cases p; cases q; congr'⟩ +@[to_additive] +instance : mul_mem_class (subsemigroup M) M := +{ mul_mem := subsemigroup.mul_mem' } + /-- See Note [custom simps projection] -/ @[to_additive " See Note [custom simps projection]"] def simps.coe (S : subsemigroup M) : set M := S @@ -114,7 +132,7 @@ variable (S) /-- A subsemigroup is closed under multiplication. -/ @[to_additive "An `add_subsemigroup` is closed under addition."] -theorem mul_mem {x y : M} : x ∈ S → y ∈ S → x * y ∈ S := subsemigroup.mul_mem' S +protected theorem mul_mem {x y : M} : x ∈ S → y ∈ S → x * y ∈ S := subsemigroup.mul_mem' S /-- The subsemigroup `M` of the magma `M`. -/ @[to_additive "The additive subsemigroup `M` of the magma `M`."] @@ -256,7 +274,7 @@ lemma closure_induction {p : M → Prop} {x} (h : x ∈ closure s) @[elab_as_eliminator, to_additive "A dependent version of `add_subsemigroup.closure_induction`. "] lemma closure_induction' (s : set M) {p : Π x, x ∈ closure s → Prop} (Hs : ∀ x (h : x ∈ s), p x (subset_closure h)) - (Hmul : ∀ x hx y hy, p x hx → p y hy → p (x * y) (mul_mem _ hx hy)) + (Hmul : ∀ x hx y hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) {x} (hx : x ∈ closure s) : p x hx := begin @@ -265,6 +283,17 @@ begin (λ x hx, ⟨_, Hs x hx⟩) (λ x y ⟨hx', hx⟩ ⟨hy', hy⟩, ⟨_, Hmul _ _ _ _ hx hy⟩), end +/-- An induction principle for closure membership for predicates with two arguments. -/ +@[elab_as_eliminator, to_additive "An induction principle for additive closure membership for +predicates with two arguments."] +lemma closure_induction₂ {p : M → M → Prop} {x} {y : M} (hx : x ∈ closure s) (hy : y ∈ closure s) + (Hs : ∀ (x ∈ s) (y ∈ s), p x y) + (Hmul_left : ∀ x y z, p x z → p y z → p (x * y) z) + (Hmul_right : ∀ x y z, p z x → p z y → p z (x * y)) : p x y := +closure_induction hx + (λ x xs, closure_induction hy (Hs x xs) (λ z y h₁ h₂, Hmul_right z _ _ h₁ h₂)) + (λ x z h₁ h₂, Hmul_left _ _ _ h₁ h₂) + /-- If `s` is a dense set in a magma `M`, `subsemigroup.closure s = ⊤`, then in order to prove that some predicate `p` holds for all `x : M` it suffices to verify `p x` for `x ∈ s`, and verify that `p x` and `p y` imply `p (x * y)`. -/ From aeef727f262897cd8c87803078995f16d36080a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Thu, 21 Apr 2022 20:30:56 +0000 Subject: [PATCH 146/373] chore(set_theory/ordinal/basic): Small style tweaks (#13561) --- src/set_theory/ordinal/basic.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/set_theory/ordinal/basic.lean b/src/set_theory/ordinal/basic.lean index 8796ccd5482dc..e339684e5b056 100644 --- a/src/set_theory/ordinal/basic.lean +++ b/src/set_theory/ordinal/basic.lean @@ -467,9 +467,9 @@ end Well_order isomorphism. -/ instance ordinal.is_equivalent : setoid Well_order := { r := λ ⟨α, r, wo⟩ ⟨β, s, wo'⟩, nonempty (r ≃r s), - iseqv := ⟨λ⟨α, r, _⟩, ⟨rel_iso.refl _⟩, - λ⟨α, r, _⟩ ⟨β, s, _⟩ ⟨e⟩, ⟨e.symm⟩, - λ⟨α, r, _⟩ ⟨β, s, _⟩ ⟨γ, t, _⟩ ⟨e₁⟩ ⟨e₂⟩, ⟨e₁.trans e₂⟩⟩ } + iseqv := ⟨λ ⟨α, r, _⟩, ⟨rel_iso.refl _⟩, + λ ⟨α, r, _⟩ ⟨β, s, _⟩ ⟨e⟩, ⟨e.symm⟩, + λ ⟨α, r, _⟩ ⟨β, s, _⟩ ⟨γ, t, _⟩ ⟨e₁⟩ ⟨e₂⟩, ⟨e₁.trans e₂⟩⟩ } /-- `ordinal.{u}` is the type of well orders in `Type u`, up to order isomorphism. -/ def ordinal : Type (u + 1) := quotient ordinal.is_equivalent @@ -503,7 +503,7 @@ theorem type_eq {α β} {r : α → α → Prop} {s : β → β → Prop} [is_well_order α r] [is_well_order β s] : type r = type s ↔ nonempty (r ≃r s) := quotient.eq -@[simp] lemma type_lt (o : ordinal) : type ((<) : o.out.α → o.out.α → Prop) = o := +@[simp] theorem type_lt (o : ordinal) : type ((<) : o.out.α → o.out.α → Prop) = o := begin change type o.out.r = _, refine eq.trans _ (quotient.out_eq o), From 8145333431f1c22ce4a7a4e2c6a1ea8c33b52ec2 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Thu, 21 Apr 2022 20:30:57 +0000 Subject: [PATCH 147/373] ci(gitpod): update leanproject version (#13567) --- .docker/gitpod/mathlib/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.docker/gitpod/mathlib/Dockerfile b/.docker/gitpod/mathlib/Dockerfile index 1a37ea6bd6563..234b6100f0f5f 100644 --- a/.docker/gitpod/mathlib/Dockerfile +++ b/.docker/gitpod/mathlib/Dockerfile @@ -19,7 +19,7 @@ RUN curl https://raw.githubusercontent.com/Kha/elan/master/elan-init.sh -sSf | s RUN . ~/.profile && elan toolchain install $(curl https://raw.githubusercontent.com/leanprover-community/mathlib/master/leanpkg.toml | grep lean_version | awk -F'"' '{print $2}') # install `leanproject` using `pip` # RUN python3 -m pip install --user mathlibtools -RUN python3 -m pip install --user pipx && python3 -m pipx ensurepath && source ~/.profile && pipx install mathlibtools==1.1.0 +RUN python3 -m pip install --user pipx && python3 -m pipx ensurepath && source ~/.profile && pipx install mathlibtools==1.1.1 ENV PATH="/home/gitpod/.local/bin:/home/gitpod/.elan/bin:${PATH}" From ba556a7017b27baeef76fff957bb67e6f246313d Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Thu, 21 Apr 2022 20:30:58 +0000 Subject: [PATCH 148/373] chore(algebra/algebra/spectrum): lemmas about the zero ring (#13568) --- src/algebra/algebra/spectrum.lean | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/algebra/algebra/spectrum.lean b/src/algebra/algebra/spectrum.lean index 097b179a8e732..84d5b91579a33 100644 --- a/src/algebra/algebra/spectrum.lean +++ b/src/algebra/algebra/spectrum.lean @@ -109,6 +109,15 @@ lemma mem_resolvent_set_iff {r : R} {a : A} : r ∈ resolvent_set R a ↔ is_unit (↑ₐr - a) := iff.rfl +@[simp] lemma resolvent_set_of_subsingleton [subsingleton A] (a : A) : + resolvent_set R a = set.univ := +by simp_rw [resolvent_set, subsingleton.elim (algebra_map R A _ - a) 1, is_unit_one, + set.set_of_true] + +@[simp] lemma of_subsingleton [subsingleton A] (a : A) : + spectrum R a = ∅ := +by rw [spectrum, resolvent_set_of_subsingleton, set.compl_univ] + lemma resolvent_eq {a : A} {r : R} (h : r ∈ resolvent_set R a) : resolvent a r = ↑h.unit⁻¹ := ring.inverse_unit h.unit From 8110ab9dec832ae17c9d31102ee131b0dfc04706 Mon Sep 17 00:00:00 2001 From: AlexKontorovich <58564076+AlexKontorovich@users.noreply.github.com> Date: Thu, 21 Apr 2022 23:36:46 +0000 Subject: [PATCH 149/373] feat(number_theory/modular): fundamental domain part 2 (#8985) This completes the argument that the standard open domain `{z : |z|>1, |\Re(z)|<1/2}` is a fundamental domain for the action of `SL(2,\Z)` on `\H`. The first PR (#8611) showed that every point in the upper half plane has a representative inside its closure, and here we show that representatives in the open domain are unique. Co-authored-by: Heather Macbeth <25316162+hrmacbeth@users.noreply.github.com> Co-authored-by: Marc Masdeu Co-authored-by: Heather Macbeth <25316162+hrmacbeth@users.noreply.github.com> Co-authored-by: Marc Masdeu --- src/algebra/group_power/order.lean | 3 + src/algebra/order/group.lean | 3 + src/analysis/complex/upper_half_plane.lean | 9 + src/data/int/basic.lean | 15 ++ src/data/int/cast.lean | 51 ++++- src/number_theory/modular.lean | 249 ++++++++++++++++++--- 6 files changed, 287 insertions(+), 43 deletions(-) diff --git a/src/algebra/group_power/order.lean b/src/algebra/group_power/order.lean index f8cfbf4430102..04d0ff5c15b5f 100644 --- a/src/algebra/group_power/order.lean +++ b/src/algebra/group_power/order.lean @@ -400,6 +400,9 @@ have t : 1^2 ≤ x^2 ↔ |1| ≤ |x| := ⟨abs_le_abs_of_sq_le_sq, sq_le_sq⟩, @[simp] lemma one_lt_sq_iff_one_lt_abs (x : R) : 1 < x^2 ↔ 1 < |x| := have t : 1^2 < x^2 ↔ |1| < |x| := ⟨abs_lt_abs_of_sq_lt_sq, sq_lt_sq⟩, by simpa using t +lemma pow_four_le_pow_two_of_pow_two_le {x y : R} (h : x^2 ≤ y) : x^4 ≤ y^2 := +(pow_mul x 2 2).symm ▸ pow_le_pow_of_le_left (sq_nonneg x) h 2 + end linear_ordered_ring section linear_ordered_comm_ring diff --git a/src/algebra/order/group.lean b/src/algebra/order/group.lean index 58629b2788e7c..9d8eb627db075 100644 --- a/src/algebra/order/group.lean +++ b/src/algebra/order/group.lean @@ -1146,6 +1146,9 @@ abs_le.2 ⟨(neg_add (|a|) (|b|)).symm ▸ add_le_add (neg_le.2 $ neg_le_abs_self _) (neg_le.2 $ neg_le_abs_self _), add_le_add (le_abs_self _) (le_abs_self _)⟩ +lemma abs_add' (a b : α) : |a| ≤ |b| + |b + a| := +by simpa using abs_add (-b) (b + a) + theorem abs_sub (a b : α) : |a - b| ≤ |a| + |b| := by { rw [sub_eq_add_neg, ←abs_neg b], exact abs_add a _ } diff --git a/src/analysis/complex/upper_half_plane.lean b/src/analysis/complex/upper_half_plane.lean index 1d74afb9e11b0..82bafe1df3ed8 100644 --- a/src/analysis/complex/upper_half_plane.lean +++ b/src/analysis/complex/upper_half_plane.lean @@ -159,4 +159,13 @@ begin ring, end +lemma c_mul_im_sq_le_norm_sq_denom (z : ℍ) (g : SL(2, ℝ)) : + ((↑ₘg 1 0 : ℝ) * (z.im))^2 ≤ complex.norm_sq (denom g z) := +begin + let c := (↑ₘg 1 0 : ℝ), + let d := (↑ₘg 1 1 : ℝ), + calc (c * z.im)^2 ≤ (c * z.im)^2 + (c * z.re + d)^2 : by nlinarith + ... = complex.norm_sq (denom g z) : by simp [complex.norm_sq]; ring, +end + end upper_half_plane diff --git a/src/data/int/basic.lean b/src/data/int/basic.lean index df12711935907..f2b2f11851f94 100644 --- a/src/data/int/basic.lean +++ b/src/data/int/basic.lean @@ -221,6 +221,9 @@ le_sub_iff_add_le lemma abs_le_one_iff {a : ℤ} : |a| ≤ 1 ↔ a = 0 ∨ a = 1 ∨ a = -1 := by rw [le_iff_lt_or_eq, abs_lt_one_iff, abs_eq (@zero_le_one ℤ _)] +lemma one_le_abs {z : ℤ} (h₀: z ≠ 0) : 1 ≤ |z| := +add_one_le_iff.mpr (abs_pos.mpr h₀) + @[elab_as_eliminator] protected lemma induction_on {p : ℤ → Prop} (i : ℤ) (hz : p 0) (hp : ∀ i : ℕ, p i → p (i + 1)) (hn : ∀ i : ℕ, p (-i) → p (-i - 1)) : p i := begin @@ -1290,6 +1293,18 @@ begin { exact is_unit_one.neg } end +lemma eq_one_or_neg_one_of_mul_eq_one {z w : ℤ} (h : z * w = 1) : z = 1 ∨ z = -1 := +is_unit_iff.mp (is_unit_of_mul_eq_one z w h) + +lemma eq_one_or_neg_one_of_mul_eq_one' {z w : ℤ} (h : z * w = 1) : + (z = 1 ∧ w = 1) ∨ (z = -1 ∧ w = -1) := +begin + have h' : w * z = 1 := (mul_comm z w) ▸ h, + rcases eq_one_or_neg_one_of_mul_eq_one h with rfl | rfl; + rcases eq_one_or_neg_one_of_mul_eq_one h' with rfl | rfl; + tauto, +end + theorem is_unit_iff_nat_abs_eq {n : ℤ} : is_unit n ↔ n.nat_abs = 1 := by simp [nat_abs_eq_iff, is_unit_iff] diff --git a/src/data/int/cast.lean b/src/data/int/cast.lean index a458a47270ce7..0d5b983deb0cc 100644 --- a/src/data/int/cast.lean +++ b/src/data/int/cast.lean @@ -143,6 +143,10 @@ by rw [bit1, cast_add, cast_one, cast_bit0]; refl lemma cast_two [ring α] : ((2 : ℤ) : α) = 2 := by simp +lemma cast_three [ring α] : ((3 : ℤ) : α) = 3 := by simp + +lemma cast_four [ring α] : ((4 : ℤ) : α) = 4 := by simp + theorem cast_mono [ordered_ring α] : monotone (coe : ℤ → α) := begin intros m n h, @@ -177,22 +181,49 @@ by rw [← cast_zero, cast_lt] @[simp] theorem cast_lt_zero [ordered_ring α] [nontrivial α] {n : ℤ} : (n : α) < 0 ↔ n < 0 := by rw [← cast_zero, cast_lt] -@[simp, norm_cast] theorem cast_min [linear_ordered_ring α] {a b : ℤ} : - (↑(min a b) : α) = min a b := +section linear_ordered_ring + +variables [linear_ordered_ring α] {a b : ℤ} (n : ℤ) + +@[simp, norm_cast] theorem cast_min : (↑(min a b) : α) = min a b := monotone.map_min cast_mono -@[simp, norm_cast] theorem cast_max [linear_ordered_ring α] {a b : ℤ} : - (↑(max a b) : α) = max a b := +@[simp, norm_cast] theorem cast_max : (↑(max a b) : α) = max a b := monotone.map_max cast_mono -@[simp, norm_cast] theorem cast_abs [linear_ordered_ring α] {q : ℤ} : - ((|q| : ℤ) : α) = |q| := +@[simp, norm_cast] theorem cast_abs : ((|a| : ℤ) : α) = |a| := by simp [abs_eq_max_neg] -lemma cast_nat_abs {R : Type*} [linear_ordered_ring R] : ∀ (n : ℤ), (n.nat_abs : R) = |n| -| (n : ℕ) := by simp only [int.nat_abs_of_nat, int.cast_coe_nat, nat.abs_cast] -| -[1+n] := by simp only [int.nat_abs, int.cast_neg_succ_of_nat, abs_neg, - ← nat.cast_succ, nat.abs_cast] +lemma cast_one_le_of_pos (h : 0 < a) : (1 : α) ≤ a := +by exact_mod_cast int.add_one_le_of_lt h + +lemma cast_le_neg_one_of_neg (h : a < 0) : (a : α) ≤ -1 := +by exact_mod_cast int.le_sub_one_of_lt h + +lemma nneg_mul_add_sq_of_abs_le_one {x : α} (hx : |x| ≤ 1) : + (0 : α) ≤ n * x + n * n := +begin + have hnx : 0 < n → 0 ≤ x + n := λ hn, by + { convert add_le_add (neg_le_of_abs_le hx) (cast_one_le_of_pos hn), + rw add_left_neg, }, + have hnx' : n < 0 → x + n ≤ 0 := λ hn, by + { convert add_le_add (le_of_abs_le hx) (cast_le_neg_one_of_neg hn), + rw add_right_neg, }, + rw [← mul_add, mul_nonneg_iff], + rcases lt_trichotomy n 0 with h | rfl | h, + { exact or.inr ⟨by exact_mod_cast h.le, hnx' h⟩, }, + { simp [le_total 0 x], }, + { exact or.inl ⟨by exact_mod_cast h.le, hnx h⟩, }, +end + +lemma cast_nat_abs : (n.nat_abs : α) = |n| := +begin + cases n, + { simp, }, + { simp only [int.nat_abs, int.cast_neg_succ_of_nat, abs_neg, ← nat.cast_succ, nat.abs_cast], }, +end + +end linear_ordered_ring lemma coe_int_dvd [comm_ring α] (m n : ℤ) (h : m ∣ n) : (m : α) ∣ (n : α) := diff --git a/src/number_theory/modular.lean b/src/number_theory/modular.lean index 12ff429688694..b8310760d4f24 100644 --- a/src/number_theory/modular.lean +++ b/src/number_theory/modular.lean @@ -13,10 +13,30 @@ import analysis.matrix We define the action of `SL(2,ℤ)` on `ℍ` (via restriction of the `SL(2,ℝ)` action in `analysis.complex.upper_half_plane`). We then define the standard fundamental domain -(`modular_group.fundamental_domain`, `𝒟`) for this action and show -(`modular_group.exists_smul_mem_fundamental_domain`) that any point in `ℍ` can be +(`modular_group.fd`, `𝒟`) for this action and show +(`modular_group.exists_smul_mem_fd`) that any point in `ℍ` can be moved inside `𝒟`. +## Main definitions + +The standard (closed) fundamental domain of the action of `SL(2,ℤ)` on `ℍ`, denoted `𝒟`: +`fd := {z | 1 ≤ (z : ℂ).norm_sq ∧ |z.re| ≤ (1 : ℝ) / 2}` + +The standard open fundamental domain of the action of `SL(2,ℤ)` on `ℍ`, denoted `𝒟ᵒ`: +`fdo := {z | 1 < (z : ℂ).norm_sq ∧ |z.re| < (1 : ℝ) / 2}` + +These notations are localized in the `modular` locale and can be enabled via `open_locale modular`. + +## Main results + +Any `z : ℍ` can be moved to `𝒟` by an element of `SL(2,ℤ)`: +`exists_smul_mem_fd (z : ℍ) : ∃ g : SL(2,ℤ), g • z ∈ 𝒟` + +If both `z` and `γ • z` are in the open domain `𝒟ᵒ` then `z = γ • z`: +`eq_smul_self_of_mem_fdo_mem_fdo {z : ℍ} {g : SL(2,ℤ)} (hz : z ∈ 𝒟ᵒ) (hg : g • z ∈ 𝒟ᵒ) : z = g • z` + +# Discussion + Standard proofs make use of the identity `g • z = a / c - 1 / (c (cz + d))` @@ -42,7 +62,8 @@ we state lemmas in this file without spurious `coe_fn` terms. -/ local attribute [-instance] matrix.special_linear_group.has_coe_to_fun local attribute [-instance] matrix.general_linear_group.has_coe_to_fun -open complex matrix matrix.special_linear_group upper_half_plane +open complex (hiding abs_one abs_two abs_mul abs_add) +open matrix (hiding mul_smul) matrix.special_linear_group upper_half_plane noncomputable theory local notation `SL(` n `, ` R `)`:= special_linear_group (fin n) R @@ -55,6 +76,8 @@ local attribute [instance] fintype.card_fin_even namespace modular_group +variables (g : SL(2, ℤ)) (z : ℍ) + section upper_half_plane_action /-- For a subring `R` of `ℝ`, the action of `SL(2, R)` on the upper half-plane, as a restriction of @@ -62,23 +85,27 @@ the `SL(2, ℝ)`-action defined by `upper_half_plane.mul_action`. -/ instance {R : Type*} [comm_ring R] [algebra R ℝ] : mul_action SL(2, R) ℍ := mul_action.comp_hom ℍ (map (algebra_map R ℝ)) -lemma coe_smul (g : SL(2, ℤ)) (z : ℍ) : ↑(g • z) = num g z / denom g z := rfl -lemma re_smul (g : SL(2, ℤ)) (z : ℍ) : (g • z).re = (num g z / denom g z).re := rfl -@[simp] lemma smul_coe (g : SL(2, ℤ)) (z : ℍ) : (g : SL(2,ℝ)) • z = g • z := rfl +lemma coe_smul : ↑(g • z) = num g z / denom g z := rfl + +lemma re_smul : (g • z).re = (num g z / denom g z).re := rfl + +@[simp] lemma smul_coe : (g : SL(2,ℝ)) • z = g • z := rfl -@[simp] lemma neg_smul (g : SL(2, ℤ)) (z : ℍ) : -g • z = g • z := +@[simp] lemma neg_smul : -g • z = g • z := show ↑(-g) • _ = _, by simp [neg_smul g z] -lemma im_smul (g : SL(2, ℤ)) (z : ℍ) : (g • z).im = (num g z / denom g z).im := rfl +lemma im_smul : (g • z).im = (num g z / denom g z).im := rfl -lemma im_smul_eq_div_norm_sq (g : SL(2, ℤ)) (z : ℍ) : +lemma im_smul_eq_div_norm_sq : (g • z).im = z.im / (complex.norm_sq (denom g z)) := im_smul_eq_div_norm_sq g z -@[simp] lemma denom_apply (g : SL(2, ℤ)) (z : ℍ) : denom g z = ↑ₘg 1 0 * z + ↑ₘg 1 1 := by simp +@[simp] lemma denom_apply : denom g z = ↑ₘg 1 0 * z + ↑ₘg 1 1 := by simp end upper_half_plane_action +variables {g} + section bottom_row /-- The two numbers `c`, `d` in the "bottom_row" of `g=[[*,*],[c,d]]` in `SL(2, ℤ)` are coprime. -/ @@ -115,7 +142,7 @@ local attribute [simp] coe_smul /-- The function `(c,d) → |cz+d|^2` is proper, that is, preimages of bounded-above sets are finite. -/ -lemma tendsto_norm_sq_coprime_pair (z : ℍ) : +lemma tendsto_norm_sq_coprime_pair : filter.tendsto (λ p : fin 2 → ℤ, ((p 0 : ℂ) * z + p 1).norm_sq) cofinite at_top := begin @@ -174,10 +201,6 @@ def lc_row0 (p : fin 2 → ℤ) : (matrix (fin 2) (fin 2) ℝ) →ₗ[ℝ] ℝ : lc_row0 p g = p 0 * g 0 0 + p 1 * g 0 1 := rfl -lemma lc_row0_apply' (a b : ℝ) (c d : ℤ) (v : fin 2 → ℝ) : - lc_row0 ![c, d] ![![a, b], v] = c * a + d * b := -by simp - /-- Linear map sending the matrix [a, b; c, d] to the matrix [ac₀ + bd₀, - ad₀ + bc₀; c, d], for some fixed `(c₀, d₀)`. -/ @[simps] def lc_row0_extend {cd : fin 2 → ℤ} (hcd : is_coprime (cd 0) (cd 1)) : @@ -239,8 +262,7 @@ end `g • z = (a c + b d) / (c^2 + d^2) + (d z - c) / ((c^2 + d^2) (c z + d))` which does not need to be decomposed depending on whether `c = 0`. -/ -lemma smul_eq_lc_row0_add {p : fin 2 → ℤ} (hp : is_coprime (p 0) (p 1)) (z : ℍ) {g : SL(2,ℤ)} - (hg : ↑ₘg 1 = p) : +lemma smul_eq_lc_row0_add {p : fin 2 → ℤ} (hp : is_coprime (p 0) (p 1)) (hg : ↑ₘg 1 = p) : ↑(g • z) = ((lc_row0 p ↑(g : SL(2, ℝ))) : ℂ) / (p 0 ^ 2 + p 1 ^ 2) + ((p 1 : ℂ) * z - p 0) / ((p 0 ^ 2 + p 1 ^ 2) * (p 0 * z + p 1)) := begin @@ -255,7 +277,7 @@ begin ring, end -lemma tendsto_abs_re_smul (z:ℍ) {p : fin 2 → ℤ} (hp : is_coprime (p 0) (p 1)) : +lemma tendsto_abs_re_smul {p : fin 2 → ℤ} (hp : is_coprime (p 0) (p 1)) : tendsto (λ g : {g : SL(2, ℤ) // ↑ₘg 1 = p}, |((g : SL(2, ℤ)) • z).re|) cofinite at_top := begin @@ -271,7 +293,7 @@ begin ext g, change ((g : SL(2, ℤ)) • z).re = (lc_row0 p ↑(↑g : SL(2, ℝ))) / (p 0 ^ 2 + p 1 ^ 2) + (((p 1:ℂ )* z - p 0) / ((p 0 ^ 2 + p 1 ^ 2) * (p 0 * z + p 1))).re, - exact_mod_cast (congr_arg complex.re (smul_eq_lc_row0_add hp z g.2)) + exact_mod_cast (congr_arg complex.re (smul_eq_lc_row0_add z hp g.2)) end end tendsto_lemmas @@ -281,7 +303,7 @@ section fundamental_domain local attribute [simp] coe_smul re_smul /-- For `z : ℍ`, there is a `g : SL(2,ℤ)` maximizing `(g•z).im` -/ -lemma exists_max_im (z : ℍ) : +lemma exists_max_im : ∃ g : SL(2, ℤ), ∀ g' : SL(2, ℤ), (g' • z).im ≤ (g • z).im := begin classical, @@ -300,7 +322,7 @@ end /-- Given `z : ℍ` and a bottom row `(c,d)`, among the `g : SL(2,ℤ)` with this bottom row, minimize `|(g•z).re|`. -/ -lemma exists_row_one_eq_and_min_re (z:ℍ) {cd : fin 2 → ℤ} (hcd : is_coprime (cd 0) (cd 1)) : +lemma exists_row_one_eq_and_min_re {cd : fin 2 → ℤ} (hcd : is_coprime (cd 0) (cd 1)) : ∃ g : SL(2,ℤ), ↑ₘg 1 = cd ∧ (∀ g' : SL(2,ℤ), ↑ₘg 1 = ↑ₘg' 1 → |(g • z).re| ≤ |(g' • z).re|) := begin @@ -318,20 +340,66 @@ end /-- The matrix `T = [[1,1],[0,1]]` as an element of `SL(2,ℤ)` -/ def T : SL(2,ℤ) := ⟨![![1, 1], ![0, 1]], by norm_num [matrix.det_fin_two]⟩ -/-- The matrix `T' (= T⁻¹) = [[1,-1],[0,1]]` as an element of `SL(2,ℤ)` -/ -def T' : SL(2,ℤ) := ⟨![![1, -1], ![0, 1]], by norm_num [matrix.det_fin_two]⟩ - /-- The matrix `S = [[0,-1],[1,0]]` as an element of `SL(2,ℤ)` -/ def S : SL(2,ℤ) := ⟨![![0, -1], ![1, 0]], by norm_num [matrix.det_fin_two]⟩ -/-- The standard (closed) fundamental domain of the action of `SL(2,ℤ)` on `ℍ` -/ -def fundamental_domain : set ℍ := -{z | 1 ≤ (complex.norm_sq z) ∧ |z.re| ≤ (1 : ℝ) / 2} +lemma coe_S : ↑ₘS = ![![0, -1], ![1, 0]] := rfl -localized "notation `𝒟` := modular_group.fundamental_domain" in modular +lemma coe_T : ↑ₘT = ![![1, 1], ![0, 1]] := rfl -/-- If `|z|<1`, then applying `S` strictly decreases `im` -/ -lemma im_lt_im_S_smul {z : ℍ} (h: norm_sq z < 1) : z.im < (S • z).im := +lemma coe_T_inv : ↑ₘ(T⁻¹) = ![![1, -1], ![0, 1]] := by simp [coe_inv, coe_T, adjugate_fin_two] + +lemma coe_T_zpow (n : ℤ) : ↑ₘ(T ^ n) = ![![1, n], ![0,1]] := +begin + induction n using int.induction_on with n h n h, + { ext i j, fin_cases i; fin_cases j; + simp, }, + { rw [zpow_add, zpow_one, coe_mul, h, coe_T], + ext i j, fin_cases i; fin_cases j; + simp [matrix.mul_apply, fin.sum_univ_succ, add_comm (1 : ℤ)], }, + { rw [zpow_sub, zpow_one, coe_mul, h, coe_T_inv], + ext i j, fin_cases i; fin_cases j; + simp [matrix.mul_apply, fin.sum_univ_succ, neg_add_eq_sub (1 : ℤ)], }, +end + +variables {z} + +@[simp] lemma coe_T_zpow_smul_eq {n : ℤ} : (↑((T^n) • z) : ℂ) = z + n := +by simp [coe_T_zpow] + +-- If instead we had `g` and `T` of type `PSL(2, ℤ)`, then we could simply state `g = T^n`. +lemma exists_eq_T_zpow_of_c_eq_zero (hc : ↑ₘg 1 0 = 0) : + ∃ (n : ℤ), ∀ (z : ℍ), g • z = T^n • z := +begin + have had := g.det_coe, + replace had : ↑ₘg 0 0 * ↑ₘg 1 1 = 1, { rw [det_fin_two, hc] at had, linarith, }, + rcases int.eq_one_or_neg_one_of_mul_eq_one' had with ⟨ha, hd⟩ | ⟨ha, hd⟩, + { use ↑ₘg 0 1, + suffices : g = T^(↑ₘg 0 1), { intros z, conv_lhs { rw this, }, }, + ext i j, fin_cases i; fin_cases j; + simp [ha, hc, hd, coe_T_zpow], }, + { use -↑ₘg 0 1, + suffices : g = -T^(-↑ₘg 0 1), { intros z, conv_lhs { rw [this, neg_smul], }, }, + ext i j, fin_cases i; fin_cases j; + simp [ha, hc, hd, coe_T_zpow], }, +end + +/- If `c = 1`, then `g` factorises into a product terms involving only `T` and `S`. -/ +lemma g_eq_of_c_eq_one (hc : ↑ₘg 1 0 = 1) : + g = T^(↑ₘg 0 0) * S * T^(↑ₘg 1 1) := +begin + have hg := g.det_coe.symm, + replace hg : ↑ₘg 0 1 = ↑ₘg 0 0 * ↑ₘg 1 1 - 1, { rw [det_fin_two, hc] at hg, linarith, }, + ext i j, fin_cases i; fin_cases j; + simp [coe_S, coe_T_zpow, matrix.mul_apply, fin.sum_univ_succ, hg, hc], +end + +/-- If `1 < |z|`, then `|S • z| < 1`. -/ +lemma norm_sq_S_smul_lt_one (h: 1 < norm_sq z) : norm_sq ↑(S • z) < 1 := +by simpa [coe_S] using (inv_lt_inv z.norm_sq_pos zero_lt_one).mpr h + +/-- If `|z| < 1`, then applying `S` strictly decreases `im`. -/ +lemma im_lt_im_S_smul (h: norm_sq z < 1) : z.im < (S • z).im := begin have : z.im < z.im / norm_sq (z:ℂ), { have imz : 0 < z.im := im_pos z, @@ -342,8 +410,55 @@ begin field_simp [norm_sq_denom_ne_zero, norm_sq_ne_zero, S] end +/-- The standard (closed) fundamental domain of the action of `SL(2,ℤ)` on `ℍ`. -/ +def fd : set ℍ := +{z | 1 ≤ (z : ℂ).norm_sq ∧ |z.re| ≤ (1 : ℝ) / 2} + +/-- The standard open fundamental domain of the action of `SL(2,ℤ)` on `ℍ`. -/ +def fdo : set ℍ := +{z | 1 < (z : ℂ).norm_sq ∧ |z.re| < (1 : ℝ) / 2} + +localized "notation `𝒟` := modular_group.fd" in modular + +localized "notation `𝒟ᵒ` := modular_group.fdo" in modular + +lemma abs_two_mul_re_lt_one_of_mem_fdo (h : z ∈ 𝒟ᵒ) : |2 * z.re| < 1 := +begin + rw [abs_mul, abs_two, ← lt_div_iff' (@two_pos ℝ _ _)], + exact h.2, +end + +lemma three_lt_four_mul_im_sq_of_mem_fdo (h : z ∈ 𝒟ᵒ) : 3 < 4 * z.im^2 := +begin + have : 1 < z.re * z.re + z.im * z.im := by simpa [complex.norm_sq_apply] using h.1, + have := h.2, + cases abs_cases z.re; + nlinarith, +end + +/-- If `z ∈ 𝒟ᵒ`, and `n : ℤ`, then `|z + n| > 1`. -/ +lemma one_lt_norm_sq_T_zpow_smul (hz : z ∈ 𝒟ᵒ) (n : ℤ) : 1 < norm_sq (((T^n) • z) : ℍ) := +begin + have hz₁ : 1 < z.re * z.re + z.im * z.im := hz.1, + have hzn := int.nneg_mul_add_sq_of_abs_le_one n (abs_two_mul_re_lt_one_of_mem_fdo hz).le, + have : 1 < (z.re + ↑n) * (z.re + ↑n) + z.im * z.im, { linarith, }, + simpa [coe_T_zpow, norm_sq], +end + +lemma eq_zero_of_mem_fdo_of_T_zpow_mem_fdo {n : ℤ} (hz : z ∈ 𝒟ᵒ) (hg : (T^n) • z ∈ 𝒟ᵒ) : n = 0 := +begin + suffices : |(n : ℝ)| < 1, + { rwa [← int.cast_abs, ← int.cast_one, int.cast_lt, int.abs_lt_one_iff] at this, }, + have h₁ := hz.2, + have h₂ := hg.2, + rw [← coe_re, coe_T_zpow_smul_eq, add_re, int_cast_re, coe_re] at h₂, + calc |(n : ℝ)| ≤ |z.re| + |z.re + (n : ℝ)| : abs_add' (n : ℝ) z.re + ... < 1/2 + 1/2 : add_lt_add h₁ h₂ + ... = 1 : add_halves 1, +end + /-- Any `z : ℍ` can be moved to `𝒟` by an element of `SL(2,ℤ)` -/ -lemma exists_smul_mem_fundamental_domain (z : ℍ) : ∃ g : SL(2,ℤ), g • z ∈ 𝒟 := +lemma exists_smul_mem_fd (z : ℍ) : ∃ g : SL(2,ℤ), g • z ∈ 𝒟 := begin -- obtain a g₀ which maximizes im (g • z), obtain ⟨g₀, hg₀⟩ := exists_max_im z, @@ -372,14 +487,82 @@ begin convert this, simp [T] }, { contrapose! hg', - refine ⟨T' * g, by simp [T', matrix.mul, matrix.dot_product, fin.sum_univ_succ], _⟩, + refine ⟨T⁻¹ * g, by simp [coe_T_inv, matrix.mul, matrix.dot_product, fin.sum_univ_succ], _⟩, rw mul_action.mul_smul, have : |(g • z).re - 1| < |(g • z).re| := by cases abs_cases ((g • z).re - 1); cases abs_cases (g • z).re; linarith, convert this, - simp [T', sub_eq_add_neg] } } + simp [coe_T_inv, sub_eq_add_neg] } } end +section unique_representative + +variables {z} + +/-- An auxiliary result en route to `modular_group.c_eq_zero`. -/ +lemma abs_c_le_one (hz : z ∈ 𝒟ᵒ) (hg : g • z ∈ 𝒟ᵒ) : |↑ₘg 1 0| ≤ 1 := +begin + let c' : ℤ := ↑ₘg 1 0, + let c : ℝ := (c' : ℝ), + suffices : 3 * c^2 < 4, + { rw [← int.cast_pow, ← int.cast_three, ← int.cast_four, ← int.cast_mul, int.cast_lt] at this, + replace this : c'^2 ≤ 1^2, { linarith, }, + rw ← abs_one, + exact abs_le_abs_of_sq_le_sq this, }, + suffices : c ≠ 0 → 9 * c^4 < 16, + { rcases eq_or_ne c 0 with hc | hc, + { rw hc, norm_num, }, + { refine (abs_lt_of_sq_lt_sq' _ (by norm_num)).2, + specialize this hc, + linarith, }, }, + intros hc, + replace hc : 0 < c^4, { rw pow_bit0_pos_iff; trivial, }, + have h₁ := mul_lt_mul_of_pos_right (mul_lt_mul'' (three_lt_four_mul_im_sq_of_mem_fdo hg) + (three_lt_four_mul_im_sq_of_mem_fdo hz) (by linarith) (by linarith)) hc, + have h₂ : (c * z.im) ^ 4 / norm_sq (denom ↑g z) ^ 2 ≤ 1 := + div_le_one_of_le (pow_four_le_pow_two_of_pow_two_le + (upper_half_plane.c_mul_im_sq_le_norm_sq_denom z g)) (sq_nonneg _), + let nsq := norm_sq (denom g z), + calc 9 * c^4 < c^4 * z.im^2 * (g • z).im^2 * 16 : by linarith + ... = c^4 * z.im^4 / nsq^2 * 16 : by { rw [im_smul_eq_div_norm_sq, div_pow], ring, } + ... ≤ 16 : by { rw ← mul_pow, linarith, }, +end + +/-- An auxiliary result en route to `modular_group.eq_smul_self_of_mem_fdo_mem_fdo`. -/ +lemma c_eq_zero (hz : z ∈ 𝒟ᵒ) (hg : g • z ∈ 𝒟ᵒ) : ↑ₘg 1 0 = 0 := +begin + have hp : ∀ {g' : SL(2, ℤ)} (hg' : g' • z ∈ 𝒟ᵒ), ↑ₘg' 1 0 ≠ 1, + { intros, + by_contra hc, + let a := ↑ₘg' 0 0, + let d := ↑ₘg' 1 1, + have had : T^(-a) * g' = S * T^d, { rw g_eq_of_c_eq_one hc, group, }, + let w := T^(-a) • (g' • z), + have h₁ : w = S • (T^d • z), { simp only [w, ← mul_smul, had], }, + replace h₁ : norm_sq w < 1 := h₁.symm ▸ norm_sq_S_smul_lt_one (one_lt_norm_sq_T_zpow_smul hz d), + have h₂ : 1 < norm_sq w := one_lt_norm_sq_T_zpow_smul hg' (-a), + linarith, }, + have hn : ↑ₘg 1 0 ≠ -1, + { intros hc, + replace hc : ↑ₘ(-g) 1 0 = 1, { simp [eq_neg_of_eq_neg hc], }, + replace hg : (-g) • z ∈ 𝒟ᵒ := (neg_smul g z).symm ▸ hg, + exact hp hg hc, }, + specialize hp hg, + rcases (int.abs_le_one_iff.mp $ abs_c_le_one hz hg); + tauto, +end + +/-- Second Main Fundamental Domain Lemma: if both `z` and `g • z` are in the open domain `𝒟ᵒ`, +where `z : ℍ` and `g : SL(2,ℤ)`, then `z = g • z`. -/ +lemma eq_smul_self_of_mem_fdo_mem_fdo (hz : z ∈ 𝒟ᵒ) (hg : g • z ∈ 𝒟ᵒ) : z = g • z := +begin + obtain ⟨n, hn⟩ := exists_eq_T_zpow_of_c_eq_zero (c_eq_zero hz hg), + rw hn at hg ⊢, + simp [eq_zero_of_mem_fdo_of_T_zpow_mem_fdo hz hg], +end + +end unique_representative + end fundamental_domain end modular_group From e728cfd459d3e5d2a291594fad2523f5bb557b46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Thu, 21 Apr 2022 23:36:48 +0000 Subject: [PATCH 150/373] feat(order/grade): Graded orders (#11308) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define graded orders. To be the most general, we use `is_min`/`is_max` rather than `order_bot`/`order_top`. A grade is a function that respects the covering relation and eventually minimality/maximality. Co-authored-by: Violeta Hernández Palacios Co-authored-by: Grayson Burton Co-authored-by: Vladimir Ivanov @astOwOlfo --- docs/references.bib | 16 ++ src/data/fin/basic.lean | 2 + src/data/int/basic.lean | 2 + src/data/int/succ_pred.lean | 13 +- src/data/nat/succ_pred.lean | 11 +- src/order/grade.lean | 287 ++++++++++++++++++++++++++++++++++++ 6 files changed, 328 insertions(+), 3 deletions(-) create mode 100644 src/order/grade.lean diff --git a/docs/references.bib b/docs/references.bib index 8add1e22cf478..180e8c9d71c18 100644 --- a/docs/references.bib +++ b/docs/references.bib @@ -459,6 +459,14 @@ @Book{ Elephant publisher = {Oxford University Press} } +@book{ engel1997, + title = {Sperner theory}, + author = {Engel, Konrad}, + publisher = {Cambridge University Press}, + place = {Cambridge}, + year = {1997} +} + @Article{ erdosrenyisos, author = {P. Erd\"os, A.R\'enyi, and V. S\'os}, title = {On a problem of graph theory}, @@ -1426,6 +1434,14 @@ @Book{ soare1987 doi = {10.1007/978-3-662-02460-7} } +@book{ stanley2012, + author = {Stanley, Richard P.}, + title = {Enumerative combinatorics}, + place = {Cambridge}, + publisher = {Cambridge Univ. Press}, + year = {2012} +} + @Article{ Stone1935, author = {Stone, M. H.}, year = {1935}, diff --git a/src/data/fin/basic.lean b/src/data/fin/basic.lean index d99c1f6a81086..e319ac332600b 100644 --- a/src/data/fin/basic.lean +++ b/src/data/fin/basic.lean @@ -202,6 +202,8 @@ instance {n : ℕ} : linear_order (fin n) := instance {n : ℕ} : partial_order (fin n) := linear_order.to_partial_order (fin n) +lemma coe_strict_mono : strict_mono (coe : fin n → ℕ) := λ _ _, id + /-- The inclusion map `fin n → ℕ` is a relation embedding. -/ def coe_embedding (n) : (fin n) ↪o ℕ := ⟨⟨coe, @fin.eq_of_veq _⟩, λ a b, iff.rfl⟩ diff --git a/src/data/int/basic.lean b/src/data/int/basic.lean index f2b2f11851f94..d674800ff7598 100644 --- a/src/data/int/basic.lean +++ b/src/data/int/basic.lean @@ -129,6 +129,8 @@ theorem coe_nat_lt {m n : ℕ} : (↑m : ℤ) < ↑n ↔ m < n := coe_nat_lt_coe @[simp, norm_cast] theorem coe_nat_inj' {m n : ℕ} : (↑m : ℤ) = ↑n ↔ m = n := int.coe_nat_eq_coe_nat_iff m n +lemma coe_nat_strict_mono : strict_mono (coe : ℕ → ℤ) := λ _ _, int.coe_nat_lt.2 + @[simp] theorem coe_nat_pos {n : ℕ} : (0 : ℤ) < n ↔ 0 < n := by rw [← int.coe_nat_zero, coe_nat_lt] diff --git a/src/data/int/succ_pred.lean b/src/data/int/succ_pred.lean index 997e79611115a..1e8cf596bda21 100644 --- a/src/data/int/succ_pred.lean +++ b/src/data/int/succ_pred.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ import data.int.basic -import order.succ_pred.basic +import data.nat.succ_pred /-! # Successors and predecessors of integers @@ -12,7 +12,7 @@ import order.succ_pred.basic In this file, we show that `ℤ` is both an archimedean `succ_order` and an archimedean `pred_order`. -/ -open function +open function order namespace int @@ -49,4 +49,13 @@ instance : is_succ_archimedean ℤ := instance : is_pred_archimedean ℤ := ⟨λ a b h, ⟨(b - a).to_nat, by rw [pred_eq_pred, pred_iterate, to_nat_sub_of_le h, sub_sub_cancel]⟩⟩ +/-! ### Covering relation -/ + +protected lemma covby_iff_succ_eq {m n : ℤ} : m ⋖ n ↔ m + 1 = n := succ_eq_iff_covby.symm + end int + +@[simp, norm_cast] lemma nat.cast_int_covby_iff {a b : ℕ} : (a : ℤ) ⋖ b ↔ a ⋖ b := +by { rw [nat.covby_iff_succ_eq, int.covby_iff_succ_eq], exact int.coe_nat_inj' } + +alias nat.cast_int_covby_iff ↔ _ covby.cast_int diff --git a/src/data/nat/succ_pred.lean b/src/data/nat/succ_pred.lean index 524dfad7c4153..47ef60b006391 100644 --- a/src/data/nat/succ_pred.lean +++ b/src/data/nat/succ_pred.lean @@ -11,7 +11,7 @@ import order.succ_pred.basic In this file, we show that `ℕ` is both an archimedean `succ_order` and an archimedean `pred_order`. -/ -open function +open function order namespace nat @@ -57,4 +57,13 @@ instance : is_succ_archimedean ℕ := instance : is_pred_archimedean ℕ := ⟨λ a b h, ⟨b - a, by rw [pred_eq_pred, pred_iterate, tsub_tsub_cancel_of_le h]⟩⟩ +/-! ### Covering relation -/ + +protected lemma covby_iff_succ_eq {m n : ℕ} : m ⋖ n ↔ m + 1 = n := succ_eq_iff_covby.symm + end nat + +@[simp, norm_cast] lemma fin.coe_covby_iff {n : ℕ} {a b : fin n} : (a : ℕ) ⋖ b ↔ a ⋖ b := +and_congr_right' ⟨λ h c hc, h hc, λ h c ha hb, @h ⟨c, hb.trans b.prop⟩ ha hb⟩ + +alias fin.coe_covby_iff ↔ _ covby.coe_fin diff --git a/src/order/grade.lean b/src/order/grade.lean new file mode 100644 index 0000000000000..1aa5a116184b6 --- /dev/null +++ b/src/order/grade.lean @@ -0,0 +1,287 @@ +/- +Copyright (c) 2022 Yaël Dillies, Violeta Hernández Palacios. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yaël Dillies, Violeta Hernández Palacios, Grayson Burton, Vladimir Ivanov +-/ +import data.nat.interval +import data.int.succ_pred +import order.atoms + +/-! +# Graded orders + +This file defines graded orders, also known as ranked orders. + +A `𝕆`-graded order is an order `α` equipped with a distinguished "grade" function `α → 𝕆` which +should be understood as giving the "height" of the elements. Usual graded orders are `ℕ`-graded, +cograded orders are `order_dual ℕ`-graded, but we can also grade by `ℤ`, and polytopes are naturally +`fin n`-graded. + +Visually, `grade ℕ a` is the height of `a` in the Hasse diagram of `α`. + +## Main declarations + +* `grade_order`: Graded order. +* `grade_min_order`: Graded order where minimal elements have minimal grades. +* `grade_max_order`: Graded order where maximal elements have maximal grades. +* `grade_bounded_order`: Graded order where minimal elements have minimal grades and maximal + elements have maximal grades. +* `grade`: The grade of an element. Because an order can admit several gradings, the first argument + is the order we grade by. +* `grade_max_order`: Graded orders with maximal elements. All maximal elements have the same grade. +* `max_grade`: The maximum grade in a `grade_max_order`. +* `order_embedding.grade`: The grade of an element in a linear order as an order embedding. + +## How to grade your order + +Here are the translations between common references and our `grade_order`: +* [Stanley][stanley2012] defines a graded order of rank `n` as an order where all maximal chains + have "length" `n` (so the number of elements of a chain is `n + 1`). This corresponds to + `grade_bounded_order (fin (n + 1)) α`. +* [Engel][engel1997]'s ranked orders are somewhere between `grade_order ℕ α` and + `grade_min_order ℕ α`, in that he requires `∃ a, is_min a ∧ grade ℕ a + 0` rather than + `∀ a, is_min a → grade ℕ a = 0`. He defines a graded order as an order where all minimal elements + have grade `0` and all maximal elements have the same grade. This is roughly a less bundled + version of `grade_bounded_order (fin n) α`, assuming we discard orders with infinite chains. + +## Implementation notes + +One possible definition of graded orders is as the bounded orders whose flags (maximal chains) +all have the same finite length (see Stanley p. 99). However, this means that all graded orders must +have minimal and maximal elements and that the grade is not data. + +Instead, we define graded orders by their grade function, without talking about flags yet. + +## References + +* [Konrad Engel, *Sperner Theory*][engel1997] +* [Richard Stanley, *Enumerative Combinatorics*][stanley2012] +-/ + +set_option old_structure_cmd true + +open finset nat order_dual + +variables {𝕆 ℙ α β : Type*} + +/-- An `𝕆`-graded order is an order `α` equipped with a strictly monotone function `grade 𝕆 : α → 𝕆` +which preserves order covering (`covby`). -/ +class grade_order (𝕆 α : Type*) [preorder 𝕆] [preorder α] := +(grade : α → 𝕆) +(grade_strict_mono : strict_mono grade) +(covby_grade ⦃a b : α⦄ : a ⋖ b → grade a ⋖ grade b) + +/-- A `𝕆`-graded order where minimal elements have minimal grades. -/ +class grade_min_order (𝕆 α : Type*) [preorder 𝕆] [preorder α] extends grade_order 𝕆 α := +(is_min_grade ⦃a : α⦄ : is_min a → is_min (grade a)) + +/-- A `𝕆`-graded order where maximal elements have maximal grades. -/ +class grade_max_order (𝕆 α : Type*) [preorder 𝕆] [preorder α] extends grade_order 𝕆 α := +(is_max_grade ⦃a : α⦄ : is_max a → is_max (grade a)) + +/-- A `𝕆`-graded order where minimal elements have minimal grades and maximal elements have maximal +grades. -/ +class grade_bounded_order (𝕆 α : Type*) [preorder 𝕆] [preorder α] + extends grade_min_order 𝕆 α, grade_max_order 𝕆 α + +section preorder -- grading +variables [preorder 𝕆] + +section preorder -- graded order +variables [preorder α] + +section grade_order +variables (𝕆) [grade_order 𝕆 α] {a b : α} + +/-- The grade of an element in a graded order. Morally, this is the number of elements you need to +go down by to get to `⊥`. -/ +def grade : α → 𝕆 := grade_order.grade + +protected lemma covby.grade (h : a ⋖ b) : grade 𝕆 a ⋖ grade 𝕆 b := grade_order.covby_grade h + +variables {𝕆} + +lemma grade_strict_mono : strict_mono (grade 𝕆 : α → 𝕆) := grade_order.grade_strict_mono + +lemma covby_iff_lt_covby_grade : a ⋖ b ↔ a < b ∧ grade 𝕆 a ⋖ grade 𝕆 b := +⟨λ h, ⟨h.1, h.grade _⟩, and.imp_right $ λ h c ha hb, + h.2 (grade_strict_mono ha) $ grade_strict_mono hb⟩ + +end grade_order + +section grade_min_order +variables (𝕆) [grade_min_order 𝕆 α] {a : α} + +protected lemma is_min.grade (h : is_min a) : is_min (grade 𝕆 a) := grade_min_order.is_min_grade h + +variables {𝕆} + +@[simp] lemma is_min_grade_iff : is_min (grade 𝕆 a) ↔ is_min a := +⟨grade_strict_mono.is_min_of_apply, is_min.grade _⟩ + +end grade_min_order + +section grade_max_order +variables (𝕆) [grade_max_order 𝕆 α] {a : α} + +protected lemma is_max.grade (h : is_max a) : is_max (grade 𝕆 a) := grade_max_order.is_max_grade h + +variables {𝕆} + +@[simp] lemma is_max_grade_iff : is_max (grade 𝕆 a) ↔ is_max a := +⟨grade_strict_mono.is_max_of_apply, is_max.grade _⟩ + +end grade_max_order +end preorder -- graded order + +lemma grade_mono [partial_order α] [grade_order 𝕆 α] : monotone (grade 𝕆 : α → 𝕆) := +grade_strict_mono.monotone + +section linear_order -- graded order +variables [linear_order α] [grade_order 𝕆 α] {a b : α} + +lemma grade_injective : function.injective (grade 𝕆 : α → 𝕆) := grade_strict_mono.injective +@[simp] lemma grade_le_grade_iff : grade 𝕆 a ≤ grade 𝕆 b ↔ a ≤ b := grade_strict_mono.le_iff_le +@[simp] lemma grade_lt_grade_iff : grade 𝕆 a < grade 𝕆 b ↔ a < b := grade_strict_mono.lt_iff_lt +@[simp] lemma grade_eq_grade_iff : grade 𝕆 a = grade 𝕆 b ↔ a = b := grade_injective.eq_iff +lemma grade_ne_grade_iff : grade 𝕆 a ≠ grade 𝕆 b ↔ a ≠ b := grade_injective.ne_iff + +lemma grade_covby_grade_iff : grade 𝕆 a ⋖ grade 𝕆 b ↔ a ⋖ b := +(covby_iff_lt_covby_grade.trans $ and_iff_right_of_imp $ λ h, grade_lt_grade_iff.1 h.1).symm + +end linear_order -- graded order +end preorder -- grading + +section partial_order +variables [partial_order 𝕆] [preorder α] + +@[simp] lemma grade_bot [order_bot 𝕆] [order_bot α] [grade_min_order 𝕆 α] : grade 𝕆 (⊥ : α) = ⊥ := +(is_min_bot.grade _).eq_bot + +@[simp] lemma grade_top [order_top 𝕆] [order_top α] [grade_max_order 𝕆 α] : grade 𝕆 (⊤ : α) = ⊤ := +(is_max_top.grade _).eq_top + +end partial_order + +/-! ### Instances -/ + +variables [preorder 𝕆] [preorder ℙ] [preorder α] [preorder β] + +instance preorder.to_grade_bounded_order : grade_bounded_order α α := +{ grade := id, + is_min_grade := λ _, id, + is_max_grade := λ _, id, + grade_strict_mono := strict_mono_id, + covby_grade := λ a b, id } + +@[simp] lemma grade_self (a : α) : grade α a = a := rfl + +/-! #### Dual -/ + +instance [grade_order 𝕆 α] : grade_order (order_dual 𝕆) (order_dual α) := +{ grade := to_dual ∘ grade 𝕆 ∘ of_dual, + grade_strict_mono := grade_strict_mono.dual, + covby_grade := λ a b h, (h.of_dual.grade _).to_dual } + +instance [grade_max_order 𝕆 α] : grade_min_order (order_dual 𝕆) (order_dual α) := +{ is_min_grade := λ _, is_max.grade _, + ..order_dual.grade_order } + +instance [grade_min_order 𝕆 α] : grade_max_order (order_dual 𝕆) (order_dual α) := +{ is_max_grade := λ _, is_min.grade _, + ..order_dual.grade_order } + +instance [grade_bounded_order 𝕆 α] : grade_bounded_order (order_dual 𝕆) (order_dual α) := +{ ..order_dual.grade_min_order, ..order_dual.grade_max_order } + +@[simp] lemma grade_to_dual [grade_order 𝕆 α] (a : α) : + grade (order_dual 𝕆) (to_dual a) = to_dual (grade 𝕆 a) := rfl +@[simp] lemma grade_of_dual [grade_order 𝕆 α] (a : order_dual α) : + grade 𝕆 (of_dual a) = of_dual (grade (order_dual 𝕆) a) := rfl + +/-! #### Lifting a graded order -/ + +/-- Lifts a graded order along a strictly monotone function. -/ +@[reducible] -- See note [reducible non-instances] +def grade_order.lift_left [grade_order 𝕆 α] (f : 𝕆 → ℙ) (hf : strict_mono f) + (hcovby : ∀ a b, a ⋖ b → f a ⋖ f b) : grade_order ℙ α := +{ grade := f ∘ grade 𝕆, + grade_strict_mono := hf.comp grade_strict_mono, + covby_grade := λ a b h, hcovby _ _ $ h.grade _ } + +/-- Lifts a graded order along a strictly monotone function. -/ +@[reducible] -- See note [reducible non-instances] +def grade_min_order.lift_left [grade_min_order 𝕆 α] (f : 𝕆 → ℙ) (hf : strict_mono f) + (hcovby : ∀ a b, a ⋖ b → f a ⋖ f b) (hmin : ∀ a, is_min a → is_min (f a)) : + grade_min_order ℙ α := +{ is_min_grade := λ a ha, hmin _ $ ha.grade _, + ..grade_order.lift_left f hf hcovby } + +/-- Lifts a graded order along a strictly monotone function. -/ +@[reducible] -- See note [reducible non-instances] +def grade_max_order.lift_left [grade_max_order 𝕆 α] (f : 𝕆 → ℙ) (hf : strict_mono f) + (hcovby : ∀ a b, a ⋖ b → f a ⋖ f b) (hmax : ∀ a, is_max a → is_max (f a)) : + grade_max_order ℙ α := +{ is_max_grade := λ a ha, hmax _ $ ha.grade _, + ..grade_order.lift_left f hf hcovby } + +/-- Lifts a graded order along a strictly monotone function. -/ +@[reducible] -- See note [reducible non-instances] +def grade_bounded_order.lift_left [grade_bounded_order 𝕆 α] (f : 𝕆 → ℙ) (hf : strict_mono f) + (hcovby : ∀ a b, a ⋖ b → f a ⋖ f b) (hmin : ∀ a, is_min a → is_min (f a)) + (hmax : ∀ a, is_max a → is_max (f a)) : + grade_bounded_order ℙ α := +{ ..grade_min_order.lift_left f hf hcovby hmin, ..grade_max_order.lift_left f hf hcovby hmax } + +/-- Lifts a graded order along a strictly monotone function. -/ +@[reducible] -- See note [reducible non-instances] +def grade_order.lift_right [grade_order 𝕆 β] (f : α → β) (hf : strict_mono f) + (hcovby : ∀ a b, a ⋖ b → f a ⋖ f b) : grade_order 𝕆 α := +{ grade := grade 𝕆 ∘ f, + grade_strict_mono := grade_strict_mono.comp hf, + covby_grade := λ a b h, (hcovby _ _ h).grade _ } + +/-- Lifts a graded order along a strictly monotone function. -/ +@[reducible] -- See note [reducible non-instances] +def grade_min_order.lift_right [grade_min_order 𝕆 β] (f : α → β) (hf : strict_mono f) + (hcovby : ∀ a b, a ⋖ b → f a ⋖ f b) (hmin : ∀ a, is_min a → is_min (f a)) : + grade_min_order 𝕆 α := +{ is_min_grade := λ a ha, (hmin _ ha).grade _, + ..grade_order.lift_right f hf hcovby } + +/-- Lifts a graded order along a strictly monotone function. -/ +@[reducible] -- See note [reducible non-instances] +def grade_max_order.lift_right [grade_max_order 𝕆 β] (f : α → β) (hf : strict_mono f) + (hcovby : ∀ a b, a ⋖ b → f a ⋖ f b) (hmax : ∀ a, is_max a → is_max (f a)) : + grade_max_order 𝕆 α := +{ is_max_grade := λ a ha, (hmax _ ha).grade _, + ..grade_order.lift_right f hf hcovby } + +/-- Lifts a graded order along a strictly monotone function. -/ +@[reducible] -- See note [reducible non-instances] +def grade_bounded_order.lift_right [grade_bounded_order 𝕆 β] (f : α → β) (hf : strict_mono f) + (hcovby : ∀ a b, a ⋖ b → f a ⋖ f b) (hmin : ∀ a, is_min a → is_min (f a)) + (hmax : ∀ a, is_max a → is_max (f a)) : grade_bounded_order 𝕆 α := +{ ..grade_min_order.lift_right f hf hcovby hmin, ..grade_max_order.lift_right f hf hcovby hmax } + +/-! #### `fin n`-graded to `ℕ`-graded to `ℤ`-graded -/ + +/-- A `fin n`-graded order is also `ℕ`-graded. We do not mark this an instance because `n` is not +inferrable. -/ +@[reducible] -- See note [reducible non-instances] +def grade_order.fin_to_nat (n : ℕ) [grade_order (fin n) α] : grade_order ℕ α := +grade_order.lift_left (_ : fin n → ℕ) fin.coe_strict_mono $ λ _ _, covby.coe_fin + +/-- A `fin n`-graded order is also `ℕ`-graded. We do not mark this an instance because `n` is not +inferrable. -/ +@[reducible] -- See note [reducible non-instances] +def grade_min_order.fin_to_nat (n : ℕ) [grade_min_order (fin n) α] : grade_min_order ℕ α := +grade_min_order.lift_left (_ : fin n → ℕ) fin.coe_strict_mono (λ _ _, covby.coe_fin) $ λ a h, begin + unfreezingI { cases n }, + { exact (@fin.elim0 (λ _, false) $ grade (fin 0) a).elim }, + rw [h.eq_bot, fin.bot_eq_zero], + exact is_min_bot, + end + +instance grade_order.nat_to_int [grade_order ℕ α] : grade_order ℤ α := +grade_order.lift_left _ int.coe_nat_strict_mono $ λ _ _, covby.cast_int From 4d7683b272a5d5a70c7f85f8c5a9f68edf8aab59 Mon Sep 17 00:00:00 2001 From: Julian Berman Date: Thu, 21 Apr 2022 23:36:49 +0000 Subject: [PATCH 151/373] feat(group_theory/torsion): torsion-free groups and quotients by torsion subgroups (#13173) --- src/group_theory/torsion.lean | 93 +++++++++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 3 deletions(-) diff --git a/src/group_theory/torsion.lean b/src/group_theory/torsion.lean index 82aff19a43d52..405dbf5396758 100644 --- a/src/group_theory/torsion.lean +++ b/src/group_theory/torsion.lean @@ -18,9 +18,10 @@ This file defines torsion groups, i.e. groups where all elements have finite ord * `monoid.is_torsion` a predicate asserting `G` is torsion, i.e. that all elements are of finite order. -* `add_monoid.is_torsion` the additive version of `monoid.is_torsion`. * `comm_group.torsion G`, the torsion subgroup of an abelian group `G` * `comm_monoid.torsion G`, the above stated for commutative monoids +* `monoid.is_torsion_free`, asserting no nontrivial elements have finite order in `G` +* `add_monoid.is_torsion` and `add_monoid.is_torsion_free` the additive versions of the above ## Implementation @@ -30,11 +31,14 @@ the group theory library. ## Tags -periodic group, torsion subgroup, torsion abelian group +periodic group, aperiodic group, torsion subgroup, torsion abelian group ## Future work -* torsion-free groups +* generalize to π-torsion(-free) groups for a set of primes π +* free, free solvable and free abelian groups are torsion free +* complete direct and free products of torsion free groups are torsion free +* groups which are residually finite p-groups with respect to 2 distinct primes are torsion free -/ variables {G H : Type*} @@ -47,6 +51,12 @@ variables (G) [monoid G] @[to_additive "A predicate on an additive monoid saying that all elements are of finite order."] def is_torsion := ∀ g : G, is_of_fin_order g +/-- A monoid is not a torsion monoid if it has an element of infinite order. -/ +@[simp, to_additive + "An additive monoid is not a torsion monoid if it has an element of infinite order."] +lemma not_is_torsion_iff : ¬ is_torsion G ↔ ∃ g : G, ¬is_of_fin_order g := +by rw [is_torsion, not_forall] + end monoid open monoid @@ -219,3 +229,80 @@ def torsion : subgroup G := { comm_monoid.torsion G with inv_mem' := λ x, is_of lemma torsion_eq_torsion_submonoid : comm_monoid.torsion G = (torsion G).to_submonoid := rfl end comm_group + +namespace monoid + +variables (G) [monoid G] + +/-- A predicate on a monoid saying that only 1 is of finite order. -/ +@[to_additive "A predicate on an additive monoid saying that only 0 is of finite order."] +def is_torsion_free := ∀ g : G, g ≠ 1 → ¬is_of_fin_order g + +/-- A nontrivial monoid is not torsion-free if any nontrivial element has finite order. -/ +@[simp, to_additive + "An additive monoid is not torsion free if any nontrivial element has finite order."] +lemma not_is_torsion_free_iff : ¬ (is_torsion_free G) ↔ ∃ g : G, g ≠ 1 ∧ is_of_fin_order g := +by simp_rw [is_torsion_free, ne.def, not_forall, not_not, exists_prop] + +end monoid + +section group + +open monoid + +variables [group G] + +/-- A nontrivial torsion group is not torsion-free. -/ +@[to_additive add_monoid.is_torsion.not_torsion_free + "A nontrivial additive torsion group is not torsion-free."] +lemma is_torsion.not_torsion_free [hN : nontrivial G] : is_torsion G → ¬is_torsion_free G := +λ tG, (not_is_torsion_free_iff _).mpr $ begin + obtain ⟨x, hx⟩ := (nontrivial_iff_exists_ne (1 : G)).mp hN, + exact ⟨x, hx, tG x⟩, +end + +/-- A nontrivial torsion-free group is not torsion. -/ +@[to_additive add_monoid.is_torsion_free.not_torsion + "A nontrivial torsion-free additive group is not torsion."] +lemma is_torsion_free.not_torsion [hN : nontrivial G] : is_torsion_free G → ¬is_torsion G := +λ tfG, (not_is_torsion_iff _).mpr $ begin + obtain ⟨x, hx⟩ := (nontrivial_iff_exists_ne (1 : G)).mp hN, + exact ⟨x, (tfG x) hx⟩, +end + +/-- Subgroups of torsion-free groups are torsion-free. -/ +@[to_additive "Subgroups of additive torsion-free groups are additively torsion-free."] +lemma is_torsion_free.subgroup (tG : is_torsion_free G) (H : subgroup G) : is_torsion_free H := +λ h hne, (is_of_fin_order_iff_coe H.to_submonoid h).not.mpr $ + tG h $ by norm_cast; simp [hne, not_false_iff] + +/-- Direct products of torsion free groups are torsion free. -/ +@[to_additive add_monoid.is_torsion_free.prod + "Direct products of additive torsion free groups are torsion free."] +lemma is_torsion_free.prod + {η : Type*} {Gs : η → Type*} [∀ i, group (Gs i)] (tfGs : ∀ i, is_torsion_free (Gs i)) : +is_torsion_free $ Π i, Gs i := +λ w hne h, hne $ funext $ λ i, not_not.mp $ mt (tfGs i (w i)) $ not_not.mpr $ h.apply i + +end group + +section comm_group + +open monoid (is_torsion_free) + +variables (G) [comm_group G] + +/-- Quotienting a group by its torsion subgroup yields a torsion free group. -/ +@[to_additive add_is_torsion_free.quotient_torsion + "Quotienting a group by its additive torsion subgroup yields an additive torsion free group."] +lemma is_torsion_free.quotient_torsion : is_torsion_free $ G ⧸ (torsion G) := +λ g hne hfin, hne $ begin + induction g using quotient_group.induction_on', + obtain ⟨m, mpos, hm⟩ := (is_of_fin_order_iff_pow_eq_one _).mp hfin, + obtain ⟨n, npos, hn⟩ := + (is_of_fin_order_iff_pow_eq_one _).mp ((quotient_group.eq_one_iff _).mp hm), + exact (quotient_group.eq_one_iff g).mpr + ((is_of_fin_order_iff_pow_eq_one _).mpr ⟨m * n, mul_pos mpos npos, (pow_mul g m n).symm ▸ hn⟩), +end + +end comm_group From 63ee558225806eae8f0c7b671d3bd86323d7270c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Riou?= Date: Thu, 21 Apr 2022 23:36:50 +0000 Subject: [PATCH 152/373] feat(algebra/big_operators): split products and sums over fin (a+b) (#13291) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Joël Riou <37772949+joelriou@users.noreply.github.com> --- src/algebra/big_operators/basic.lean | 20 ++++++++++++++++++++ src/algebra/big_operators/fin.lean | 24 ++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/algebra/big_operators/basic.lean b/src/algebra/big_operators/basic.lean index d6870ea7d8e23..6aa45a6135c7f 100644 --- a/src/algebra/big_operators/basic.lean +++ b/src/algebra/big_operators/basic.lean @@ -343,6 +343,26 @@ begin cases H } end +@[simp, to_additive] +lemma prod_on_sum [fintype α] [fintype γ] (f : α ⊕ γ → β) : + ∏ (x : α ⊕ γ), f x = + (∏ (x : α), f (sum.inl x)) * (∏ (x : γ), f (sum.inr x)) := +begin + haveI := classical.dec_eq (α ⊕ γ), + convert prod_sum_elim univ univ (λ x, f (sum.inl x)) (λ x, f (sum.inr x)), + { ext a, + split, + { intro x, + cases a, + { simp only [mem_union, mem_map, mem_univ, function.embedding.inl_apply, or_false, + exists_true_left, exists_apply_eq_apply, function.embedding.inr_apply, exists_false], }, + { simp only [mem_union, mem_map, mem_univ, function.embedding.inl_apply, false_or, + exists_true_left, exists_false, function.embedding.inr_apply, + exists_apply_eq_apply], }, }, + { simp only [mem_univ, implies_true_iff], }, }, + { simp only [sum.elim_comp_inl_inr], }, +end + @[to_additive] lemma prod_bUnion [decidable_eq α] {s : finset γ} {t : γ → finset α} (hs : set.pairwise_disjoint ↑s t) : diff --git a/src/algebra/big_operators/fin.lean b/src/algebra/big_operators/fin.lean index 3b62524fa8d0b..58d446967966e 100644 --- a/src/algebra/big_operators/fin.lean +++ b/src/algebra/big_operators/fin.lean @@ -6,6 +6,7 @@ Authors: Yury Kudryashov, Anne Baanen import algebra.big_operators.basic import data.fintype.fin import data.fintype.card +import logic.equiv.fin /-! # Big operators and `fin` @@ -113,6 +114,29 @@ lemma prod_filter_succ_lt {M : Type*} [comm_monoid M] {n : ℕ} (j : fin n) (v : ∏ j in univ.filter (λ i, j < i), v j.succ := by rw [univ_filter_succ_lt, finset.prod_map, rel_embedding.coe_fn_to_embedding, coe_succ_embedding] +@[to_additive] +lemma prod_congr' {M : Type*} [comm_monoid M] {a b : ℕ} (f : fin b → M) (h : a = b) : + ∏ (i : fin a), f (cast h i) = ∏ (i : fin b), f i := +by { subst h, congr, ext, congr, ext, rw coe_cast, } + +@[to_additive] +lemma prod_univ_add {M : Type*} [comm_monoid M] {a b : ℕ} (f : fin (a+b) → M) : + ∏ (i : fin (a+b)), f i = + (∏ (i : fin a), f (cast_add b i)) * ∏ (i : fin b), f (nat_add a i) := +begin + rw fintype.prod_equiv fin_sum_fin_equiv.symm f (λ i, f (fin_sum_fin_equiv.to_fun i)), swap, + { intro x, + simp only [equiv.to_fun_as_coe, equiv.apply_symm_apply], }, + apply prod_on_sum, +end + +@[to_additive] +lemma prod_trunc {M : Type*} [comm_monoid M] {a b : ℕ} (f : fin (a+b) → M) + (hf : ∀ (j : fin b), f (nat_add a j) = 1) : + ∏ (i : fin (a+b)), f i = + ∏ (i : fin a), f (cast_le (nat.le.intro rfl) i) := +by simpa only [prod_univ_add, fintype.prod_eq_one _ hf, mul_one] + end fin namespace list From 1e76b9ebd2c6396d2bf1439bc39a391f6b8536dd Mon Sep 17 00:00:00 2001 From: Floris van Doorn Date: Thu, 21 Apr 2022 23:36:51 +0000 Subject: [PATCH 153/373] feat(topology/constructions): more convenient lemmas (#13423) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Define `continuous.fst'` and friends and `continuous.comp₂` and friends for convenience (and to help with elaborator issues) * Cleanup in `topology/constructions` * Define `set.preimage_inl_image_inr` and `set.preimage_inr_image_inl` and prove the `range` versions in terms of these. This required reordering some lemmas (moving general lemmas about `range` above the lemmas of interactions with `range` and specific functions). * From the sphere eversion project --- src/data/set/basic.lean | 110 ++++++++++++++------------ src/topology/constructions.lean | 136 +++++++++++++++++++------------- 2 files changed, 141 insertions(+), 105 deletions(-) diff --git a/src/data/set/basic.lean b/src/data/set/basic.lean index 43def1ccb9328..54bc6b39782f2 100644 --- a/src/data/set/basic.lean +++ b/src/data/set/basic.lean @@ -1751,51 +1751,6 @@ eq_univ_iff_forall alias range_iff_surjective ↔ _ function.surjective.range_eq -@[simp] theorem range_id : range (@id α) = univ := range_iff_surjective.2 surjective_id - -@[simp] theorem range_id' : range (λ (x : α), x) = univ := range_id - -@[simp] theorem _root_.prod.range_fst [nonempty β] : range (prod.fst : α × β → α) = univ := -prod.fst_surjective.range_eq - -@[simp] theorem _root_.prod.range_snd [nonempty α] : range (prod.snd : α × β → β) = univ := -prod.snd_surjective.range_eq - -@[simp] theorem range_eval {ι : Type*} {α : ι → Sort*} [Π i, nonempty (α i)] (i : ι) : - range (eval i : (Π i, α i) → α i) = univ := -(surjective_eval i).range_eq - -theorem is_compl_range_inl_range_inr : is_compl (range $ @sum.inl α β) (range sum.inr) := -⟨by { rintro y ⟨⟨x₁, rfl⟩, ⟨x₂, _⟩⟩, cc }, - by { rintro (x|y) -; [left, right]; exact mem_range_self _ }⟩ - -@[simp] theorem range_inl_union_range_inr : range (sum.inl : α → α ⊕ β) ∪ range sum.inr = univ := -is_compl_range_inl_range_inr.sup_eq_top - -@[simp] theorem range_inl_inter_range_inr : range (sum.inl : α → α ⊕ β) ∩ range sum.inr = ∅ := -is_compl_range_inl_range_inr.inf_eq_bot - -@[simp] theorem range_inr_union_range_inl : range (sum.inr : β → α ⊕ β) ∪ range sum.inl = univ := -is_compl_range_inl_range_inr.symm.sup_eq_top - -@[simp] theorem range_inr_inter_range_inl : range (sum.inr : β → α ⊕ β) ∩ range sum.inl = ∅ := -is_compl_range_inl_range_inr.symm.inf_eq_bot - -@[simp] theorem preimage_inl_range_inr : sum.inl ⁻¹' range (sum.inr : β → α ⊕ β) = ∅ := -by { ext, simp } - -@[simp] theorem preimage_inr_range_inl : sum.inr ⁻¹' range (sum.inl : α → α ⊕ β) = ∅ := -by { ext, simp } - -@[simp] lemma compl_range_inl : (range (sum.inl : α → α ⊕ β))ᶜ = range (sum.inr : β → α ⊕ β) := -is_compl_range_inl_range_inr.compl_eq - -@[simp] lemma compl_range_inr : (range (sum.inr : β → α ⊕ β))ᶜ = range (sum.inl : α → α ⊕ β) := -is_compl_range_inl_range_inr.symm.compl_eq - -@[simp] theorem range_quot_mk (r : α → α → Prop) : range (quot.mk r) = univ := -(surjective_quot_mk r).range_eq - @[simp] theorem image_univ {f : α → β} : f '' univ = range f := by { ext, simp [image, range] } @@ -1851,12 +1806,6 @@ lemma image_preimage_eq_of_subset {f : α → β} {s : set β} (hs : s ⊆ range f '' (f ⁻¹' s) = s := by rw [image_preimage_eq_inter_range, inter_eq_self_of_subset_left hs] -instance set.can_lift [can_lift α β] : can_lift (set α) (set β) := -{ coe := λ s, can_lift.coe '' s, - cond := λ s, ∀ x ∈ s, can_lift.cond β x, - prf := λ s hs, ⟨can_lift.coe ⁻¹' s, image_preimage_eq_of_subset $ - λ x hx, can_lift.prf _ (hs x hx)⟩ } - lemma image_preimage_eq_iff {f : α → β} {s : set β} : f '' (f ⁻¹' s) = s ↔ s ⊆ range f := ⟨by { intro h, rw [← h], apply image_subset_range }, image_preimage_eq_of_subset⟩ @@ -1887,10 +1836,67 @@ theorem preimage_image_preimage {f : α → β} {s : set β} : f ⁻¹' (f '' (f ⁻¹' s)) = f ⁻¹' s := by rw [image_preimage_eq_inter_range, preimage_inter_range] +@[simp] theorem range_id : range (@id α) = univ := range_iff_surjective.2 surjective_id + +@[simp] theorem range_id' : range (λ (x : α), x) = univ := range_id + +@[simp] theorem _root_.prod.range_fst [nonempty β] : range (prod.fst : α × β → α) = univ := +prod.fst_surjective.range_eq + +@[simp] theorem _root_.prod.range_snd [nonempty α] : range (prod.snd : α × β → β) = univ := +prod.snd_surjective.range_eq + +@[simp] theorem range_eval {ι : Type*} {α : ι → Sort*} [Π i, nonempty (α i)] (i : ι) : + range (eval i : (Π i, α i) → α i) = univ := +(surjective_eval i).range_eq + +theorem is_compl_range_inl_range_inr : is_compl (range $ @sum.inl α β) (range sum.inr) := +⟨by { rintro y ⟨⟨x₁, rfl⟩, ⟨x₂, _⟩⟩, cc }, + by { rintro (x|y) -; [left, right]; exact mem_range_self _ }⟩ + +@[simp] theorem range_inl_union_range_inr : range (sum.inl : α → α ⊕ β) ∪ range sum.inr = univ := +is_compl_range_inl_range_inr.sup_eq_top + +@[simp] theorem range_inl_inter_range_inr : range (sum.inl : α → α ⊕ β) ∩ range sum.inr = ∅ := +is_compl_range_inl_range_inr.inf_eq_bot + +@[simp] theorem range_inr_union_range_inl : range (sum.inr : β → α ⊕ β) ∪ range sum.inl = univ := +is_compl_range_inl_range_inr.symm.sup_eq_top + +@[simp] theorem range_inr_inter_range_inl : range (sum.inr : β → α ⊕ β) ∩ range sum.inl = ∅ := +is_compl_range_inl_range_inr.symm.inf_eq_bot + +@[simp] theorem preimage_inl_image_inr (s : set β) : sum.inl ⁻¹' (@sum.inr α β '' s) = ∅ := +by { ext, simp } + +@[simp] theorem preimage_inr_image_inl (s : set α) : sum.inr ⁻¹' (@sum.inl α β '' s) = ∅ := +by { ext, simp } + +@[simp] theorem preimage_inl_range_inr : sum.inl ⁻¹' range (sum.inr : β → α ⊕ β) = ∅ := +by rw [← image_univ, preimage_inl_image_inr] + +@[simp] theorem preimage_inr_range_inl : sum.inr ⁻¹' range (sum.inl : α → α ⊕ β) = ∅ := +by rw [← image_univ, preimage_inr_image_inl] + +@[simp] lemma compl_range_inl : (range (sum.inl : α → α ⊕ β))ᶜ = range (sum.inr : β → α ⊕ β) := +is_compl_range_inl_range_inr.compl_eq + +@[simp] lemma compl_range_inr : (range (sum.inr : β → α ⊕ β))ᶜ = range (sum.inl : α → α ⊕ β) := +is_compl_range_inl_range_inr.symm.compl_eq + +@[simp] theorem range_quot_mk (r : α → α → Prop) : range (quot.mk r) = univ := +(surjective_quot_mk r).range_eq + +instance set.can_lift [can_lift α β] : can_lift (set α) (set β) := +{ coe := λ s, can_lift.coe '' s, + cond := λ s, ∀ x ∈ s, can_lift.cond β x, + prf := λ s hs, ⟨can_lift.coe ⁻¹' s, image_preimage_eq_of_subset $ + λ x hx, can_lift.prf _ (hs x hx)⟩ } + @[simp] theorem quot_mk_range_eq [setoid α] : range (λx : α, ⟦x⟧) = univ := range_iff_surjective.2 quot.exists_rep -lemma range_const_subset {c : α} : range (λx:ι, c) ⊆ {c} := +lemma range_const_subset {c : α} : range (λ x : ι, c) ⊆ {c} := range_subset_iff.2 $ λ x, rfl @[simp] lemma range_const : ∀ [nonempty ι] {c : α}, range (λx:ι, c) = {c} diff --git a/src/topology/constructions.lean b/src/topology/constructions.lean index a8fa2094fc6a8..12f3bc9a2658f 100644 --- a/src/topology/constructions.lean +++ b/src/topology/constructions.lean @@ -36,8 +36,8 @@ noncomputable theory open topological_space set filter open_locale classical topological_space filter -universes u v w x -variables {α : Type u} {β : Type v} {γ : Type w} {δ : Type x} +universes u v +variables {α : Type u} {β : Type v} {γ δ ε ζ : Type*} section constructions @@ -172,43 +172,94 @@ end constructions section prod variables [topological_space α] [topological_space β] [topological_space γ] [topological_space δ] + [topological_space ε] [topological_space ζ] @[continuity] lemma continuous_fst : continuous (@prod.fst α β) := continuous_inf_dom_left continuous_induced_dom -lemma continuous_at_fst {p : α × β} : continuous_at prod.fst p := -continuous_fst.continuous_at - +/-- Postcomposing `f` with `prod.fst` is continuous -/ lemma continuous.fst {f : α → β × γ} (hf : continuous f) : continuous (λ a : α, (f a).1) := continuous_fst.comp hf +/-- Precomposing `f` with `prod.fst` is continuous -/ +lemma continuous.fst' {f : α → γ} (hf : continuous f) : continuous (λ x : α × β, f x.fst) := +hf.comp continuous_fst + +lemma continuous_at_fst {p : α × β} : continuous_at prod.fst p := +continuous_fst.continuous_at + +/-- Postcomposing `f` with `prod.fst` is continuous at `x` -/ lemma continuous_at.fst {f : α → β × γ} {x : α} (hf : continuous_at f x) : continuous_at (λ a : α, (f a).1) x := continuous_at_fst.comp hf +/-- Precomposing `f` with `prod.fst` is continuous at `(x, y)` -/ +lemma continuous_at.fst' {f : α → γ} {x : α} {y : β} (hf : continuous_at f x) : + continuous_at (λ x : α × β, f x.fst) (x, y) := +continuous_at.comp hf continuous_at_fst + +/-- Precomposing `f` with `prod.fst` is continuous at `x : α × β` -/ +lemma continuous_at.fst'' {f : α → γ} {x : α × β} (hf : continuous_at f x.fst) : + continuous_at (λ x : α × β, f x.fst) x := +hf.comp continuous_at_fst + @[continuity] lemma continuous_snd : continuous (@prod.snd α β) := continuous_inf_dom_right continuous_induced_dom -lemma continuous_at_snd {p : α × β} : continuous_at prod.snd p := -continuous_snd.continuous_at - +/-- Postcomposing `f` with `prod.snd` is continuous -/ lemma continuous.snd {f : α → β × γ} (hf : continuous f) : continuous (λ a : α, (f a).2) := continuous_snd.comp hf +/-- Precomposing `f` with `prod.snd` is continuous -/ +lemma continuous.snd' {f : β → γ} (hf : continuous f) : continuous (λ x : α × β, f x.snd) := +hf.comp continuous_snd + +lemma continuous_at_snd {p : α × β} : continuous_at prod.snd p := +continuous_snd.continuous_at + +/-- Postcomposing `f` with `prod.snd` is continuous at `x` -/ lemma continuous_at.snd {f : α → β × γ} {x : α} (hf : continuous_at f x) : continuous_at (λ a : α, (f a).2) x := continuous_at_snd.comp hf +/-- Precomposing `f` with `prod.snd` is continuous at `(x, y)` -/ +lemma continuous_at.snd' {f : β → γ} {x : α} {y : β} (hf : continuous_at f y) : + continuous_at (λ x : α × β, f x.snd) (x, y) := +continuous_at.comp hf continuous_at_snd + +/-- Precomposing `f` with `prod.snd` is continuous at `x : α × β` -/ +lemma continuous_at.snd'' {f : β → γ} {x : α × β} (hf : continuous_at f x.snd) : + continuous_at (λ x : α × β, f x.snd) x := +hf.comp continuous_at_snd + @[continuity] lemma continuous.prod_mk {f : γ → α} {g : γ → β} (hf : continuous f) (hg : continuous g) : continuous (λx, (f x, g x)) := continuous_inf_rng (continuous_induced_rng hf) (continuous_induced_rng hg) -@[continuity] lemma continuous.prod.mk (a : α) : continuous (prod.mk a : β → α × β) := +@[continuity] lemma continuous.prod.mk (a : α) : continuous (λ b : β, (a, b)) := continuous_const.prod_mk continuous_id' +@[continuity] lemma continuous.prod.mk_left (b : β) : continuous (λ a : α, (a, b)) := +continuous_id'.prod_mk continuous_const + +lemma continuous.comp₂ {g : α × β → γ} (hg : continuous g) {e : δ → α} (he : continuous e) + {f : δ → β} (hf : continuous f) : continuous (λ x, g (e x, f x)) := +hg.comp $ he.prod_mk hf + +lemma continuous.comp₃ {g : α × β × γ → ε} (hg : continuous g) + {e : δ → α} (he : continuous e) {f : δ → β} (hf : continuous f) + {k : δ → γ} (hk : continuous k) : continuous (λ x, g (e x, f x, k x)) := +hg.comp₂ he $ hf.prod_mk hk + +lemma continuous.comp₄ {g : α × β × γ × ζ → ε} (hg : continuous g) + {e : δ → α} (he : continuous e) {f : δ → β} (hf : continuous f) + {k : δ → γ} (hk : continuous k) {l : δ → ζ} (hl : continuous l) : + continuous (λ x, g (e x, f x, k x, l x)) := +hg.comp₃ he hf $ hk.prod_mk hl + lemma continuous.prod_map {f : γ → α} {g : δ → β} (hf : continuous f) (hg : continuous g) : continuous (λ x : γ × δ, (f x.1, g x.2)) := -(hf.comp continuous_fst).prod_mk (hg.comp continuous_snd) +hf.fst'.prod_mk hg.snd' /-- A version of `continuous_inf_dom_left` for binary functions -/ lemma continuous_inf_dom_left₂ {α β γ} {f : α → β → γ} @@ -279,7 +330,7 @@ show continuous (g ∘ (λ b, (a, b))), from h.comp (by continuity) lemma is_open.prod {s : set α} {t : set β} (hs : is_open s) (ht : is_open t) : is_open (s ×ˢ t) := -is_open.inter (hs.preimage continuous_fst) (ht.preimage continuous_snd) +(hs.preimage continuous_fst).inter (ht.preimage continuous_snd) lemma nhds_prod_eq {a : α} {b : β} : 𝓝 (a, b) = 𝓝 a ×ᶠ 𝓝 b := by rw [filter.prod, prod.topological_space, nhds_inf, nhds_induced, nhds_induced] @@ -361,47 +412,41 @@ hf.prod_mk_nhds hg lemma continuous_at.prod_map {f : α → γ} {g : β → δ} {p : α × β} (hf : continuous_at f p.fst) (hg : continuous_at g p.snd) : continuous_at (λ p : α × β, (f p.1, g p.2)) p := -(hf.comp continuous_at_fst).prod (hg.comp continuous_at_snd) +hf.fst''.prod hg.snd'' lemma continuous_at.prod_map' {f : α → γ} {g : β → δ} {x : α} {y : β} (hf : continuous_at f x) (hg : continuous_at g y) : continuous_at (λ p : α × β, (f p.1, g p.2)) (x, y) := -have hf : continuous_at f (x, y).fst, from hf, -have hg : continuous_at g (x, y).snd, from hg, -hf.prod_map hg +hf.fst'.prod hg.snd' lemma prod_generate_from_generate_from_eq {α β : Type*} {s : set (set α)} {t : set (set β)} (hs : ⋃₀ s = univ) (ht : ⋃₀ t = univ) : @prod.topological_space α β (generate_from s) (generate_from t) = - generate_from {g | ∃u∈s, ∃v∈t, g = u ×ˢ v} := -let G := generate_from {g | ∃u∈s, ∃v∈t, g = u ×ˢ v} in + generate_from {g | ∃ u ∈ s, ∃ v ∈ t, g = u ×ˢ v} := +let G := generate_from {g | ∃ u ∈ s, ∃ v ∈ t, g = u ×ˢ v} in le_antisymm - (le_generate_from $ assume g ⟨u, hu, v, hv, g_eq⟩, g_eq.symm ▸ + (le_generate_from $ λ g ⟨u, hu, v, hv, g_eq⟩, g_eq.symm ▸ @is_open.prod _ _ (generate_from s) (generate_from t) _ _ (generate_open.basic _ hu) (generate_open.basic _ hv)) (le_inf - (coinduced_le_iff_le_induced.mp $ le_generate_from $ assume u hu, - have (⋃v∈t, u ×ˢ v) = prod.fst ⁻¹' u, - from calc (⋃v∈t, u ×ˢ v) = u ×ˢ (univ : set β) : - set.ext $ assume ⟨a, b⟩, by rw ← ht; simp [and.left_comm] {contextual:=tt} - ... = prod.fst ⁻¹' u : set.prod_univ, + (coinduced_le_iff_le_induced.mp $ le_generate_from $ λ u hu, + have (⋃ v ∈ t, u ×ˢ v) = prod.fst ⁻¹' u, + by simp_rw [← prod_Union, ← sUnion_eq_bUnion, ht, prod_univ], show G.is_open (prod.fst ⁻¹' u), - from this ▸ @is_open_Union _ _ G _ $ assume v, @is_open_Union _ _ G _ $ assume hv, - generate_open.basic _ ⟨_, hu, _, hv, rfl⟩) - (coinduced_le_iff_le_induced.mp $ le_generate_from $ assume v hv, - have (⋃u∈s, u ×ˢ v) = prod.snd ⁻¹' v, - from calc (⋃u∈s, u ×ˢ v) = (univ : set α) ×ˢ v: - set.ext $ assume ⟨a, b⟩, by rw [←hs]; by_cases b ∈ v; simp [h] {contextual:=tt} - ... = prod.snd ⁻¹' v : set.univ_prod, + by { rw [← this], exactI is_open_Union (λ v, is_open_Union $ λ hv, + generate_open.basic _ ⟨_, hu, _, hv, rfl⟩) }) + (coinduced_le_iff_le_induced.mp $ le_generate_from $ λ v hv, + have (⋃ u ∈ s, u ×ˢ v) = prod.snd ⁻¹' v, + by simp_rw [← Union_prod_const, ← sUnion_eq_bUnion, hs, univ_prod], show G.is_open (prod.snd ⁻¹' v), - from this ▸ @is_open_Union _ _ G _ $ assume u, @is_open_Union _ _ G _ $ assume hu, - generate_open.basic _ ⟨_, hu, _, hv, rfl⟩)) + by { rw [← this], exactI is_open_Union (λ u, is_open_Union $ λ hu, + generate_open.basic _ ⟨_, hu, _, hv, rfl⟩) })) lemma prod_eq_generate_from : prod.topological_space = generate_from {g | ∃(s:set α) (t:set β), is_open s ∧ is_open t ∧ g = s ×ˢ t} := le_antisymm - (le_generate_from $ assume g ⟨s, t, hs, ht, g_eq⟩, g_eq.symm ▸ hs.prod ht) + (le_generate_from $ λ g ⟨s, t, hs, ht, g_eq⟩, g_eq.symm ▸ hs.prod ht) (le_inf (ball_image_of_ball $ λt ht, generate_open.basic _ ⟨t, univ, by simpa [set.prod_eq] using ht⟩) (ball_image_of_ball $ λt ht, generate_open.basic _ ⟨univ, t, by simpa [set.prod_eq] using ht⟩)) @@ -420,16 +465,7 @@ end lemma prod_induced_induced {α γ : Type*} (f : α → β) (g : γ → δ) : @prod.topological_space α γ (induced f ‹_›) (induced g ‹_›) = induced (λ p, (f p.1, g p.2)) prod.topological_space := -begin - set fxg := (λ p : α × γ, (f p.1, g p.2)), - have key1 : f ∘ (prod.fst : α × γ → α) = (prod.fst : β × δ → β) ∘ fxg, from rfl, - have key2 : g ∘ (prod.snd : α × γ → γ) = (prod.snd : β × δ → δ) ∘ fxg, from rfl, - unfold prod.topological_space, - conv_lhs - { rw [induced_compose, induced_compose, key1, key2], - congr, rw ← induced_compose, skip, rw ← induced_compose, }, - rw induced_inf -end +by simp_rw [prod.topological_space, induced_inf, induced_compose] lemma continuous_uncurry_of_discrete_topology_left [discrete_topology α] {f : α → β → γ} (h : ∀ a, continuous (f a)) : continuous (function.uncurry f) := @@ -568,11 +604,11 @@ begin end protected lemma open_embedding.prod {f : α → β} {g : γ → δ} - (hf : open_embedding f) (hg : open_embedding g) : open_embedding (λx:α×γ, (f x.1, g x.2)) := + (hf : open_embedding f) (hg : open_embedding g) : open_embedding (λ x : α × γ, (f x.1, g x.2)) := open_embedding_of_embedding_open (hf.1.prod_mk hg.1) (hf.is_open_map.prod hg.is_open_map) -lemma embedding_graph {f : α → β} (hf : continuous f) : embedding (λx, (x, f x)) := +lemma embedding_graph {f : α → β} (hf : continuous f) : embedding (λ x, (x, f x)) := embedding_of_embedding_compose (continuous_id.prod_mk hf) continuous_fst embedding_id end prod @@ -622,10 +658,7 @@ lemma embedding_inl : embedding (@inl α β) := (is_open (inl ⁻¹' (@inl α β '' u)) ∧ is_open (inr ⁻¹' (@inl α β '' u))) ∧ inl ⁻¹' (inl '' u) = u, - have : inl ⁻¹' (@inl α β '' u) = u := - preimage_image_eq u (λ _ _, inl.inj_iff.mp), rw this, - have : inr ⁻¹' (@inl α β '' u) = ∅ := - eq_empty_iff_forall_not_mem.mpr (assume a ⟨b, _, h⟩, inl_ne_inr h), rw this, + rw [preimage_image_eq u sum.inl_injective, preimage_inr_image_inl], exact ⟨⟨hu, is_open_empty⟩, rfl⟩ } end, inj := λ _ _, inl.inj_iff.mp } @@ -640,10 +673,7 @@ lemma embedding_inr : embedding (@inr α β) := (is_open (inl ⁻¹' (@inr α β '' u)) ∧ is_open (inr ⁻¹' (@inr α β '' u))) ∧ inr ⁻¹' (inr '' u) = u, - have : inl ⁻¹' (@inr α β '' u) = ∅ := - eq_empty_iff_forall_not_mem.mpr (assume b ⟨a, _, h⟩, inr_ne_inl h), rw this, - have : inr ⁻¹' (@inr α β '' u) = u := - preimage_image_eq u (λ _ _, inr.inj_iff.mp), rw this, + rw [preimage_inl_image_inr, preimage_image_eq u sum.inr_injective], exact ⟨⟨is_open_empty, hu⟩, rfl⟩ } end, inj := λ _ _, inr.inj_iff.mp } From b1a1ece31c0e794d3849d447067499646e9dd871 Mon Sep 17 00:00:00 2001 From: Adam Topaz Date: Thu, 21 Apr 2022 23:36:53 +0000 Subject: [PATCH 154/373] feat(ring_theory/valuation/valuation_subring): The order structure on valuation subrings of a field (#13429) This PR shows that for a valuation subring `R` of a field `K`, the coarsenings of `R` are in (anti)ordered bijections with the prime ideals of `R`. As a corollary, the collection of such coarsenings is totally ordered. Co-authored-by: Junyan Xu --- src/algebra/hom/units.lean | 3 +- src/ring_theory/localization/as_subring.lean | 132 +++++++++ .../valuation/valuation_subring.lean | 278 ++++++++++++++---- 3 files changed, 357 insertions(+), 56 deletions(-) create mode 100644 src/ring_theory/localization/as_subring.lean diff --git a/src/algebra/hom/units.lean b/src/algebra/hom/units.lean index 81ed23832af68..47a65c30dcdf3 100644 --- a/src/algebra/hom/units.lean +++ b/src/algebra/hom/units.lean @@ -113,8 +113,7 @@ units.lift_right f (λ x, (hf x).unit) $ λ x, rfl @[to_additive] lemma is_unit.coe_lift_right [monoid M] [monoid N] (f : M →* N) (hf : ∀ x, is_unit (f x)) (x) : - (is_unit.lift_right f hf x : N) = f x := -units.coe_lift_right _ x + (is_unit.lift_right f hf x : N) = f x := rfl @[simp, to_additive] lemma is_unit.mul_lift_right_inv [monoid M] [monoid N] (f : M →* N) (h : ∀ x, is_unit (f x)) (x) : f x * ↑(is_unit.lift_right f h x)⁻¹ = 1 := diff --git a/src/ring_theory/localization/as_subring.lean b/src/ring_theory/localization/as_subring.lean new file mode 100644 index 0000000000000..c3457a89f702b --- /dev/null +++ b/src/ring_theory/localization/as_subring.lean @@ -0,0 +1,132 @@ +/- +Copyright (c) 2022 Adam Topaz. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Topaz, Junyan Xu +-/ +import ring_theory.localization.localization_localization + +/-! + +# Localizations of domains as subalgebras of the fraction field. + +Given a domain `A` with fraction field `K`, and a submonoid `S` of `A` which +does not contain zero, this file constructs the localization of `A` at `S` +as a subalgebra of the field `K` over `A`. + +-/ + +namespace localization +open_locale non_zero_divisors +variables {A : Type*} (K : Type*) [comm_ring A] (S : submonoid A) (hS : S ≤ A⁰) + +section comm_ring +variables [comm_ring K] [algebra A K] [is_fraction_ring A K] + +lemma map_is_unit_of_le (hS : S ≤ A⁰) (s : S) : is_unit (algebra_map A K s) := +by apply is_localization.map_units K (⟨s.1, hS s.2⟩ : A⁰) + +/-- The canonical map from a localization of `A` at `S` to the fraction ring + of `A`, given that `S ≤ A⁰`. -/ +noncomputable +def map_to_fraction_ring (B : Type*) [comm_ring B] [algebra A B] + [is_localization S B] (hS : S ≤ A⁰) : + B →ₐ[A] K := +{ commutes' := λ a, by simp, + ..is_localization.lift (map_is_unit_of_le K S hS) } + +@[simp] +lemma map_to_fraction_ring_apply {B : Type*} [comm_ring B] [algebra A B] + [is_localization S B] (hS : S ≤ A⁰) (b : B) : + map_to_fraction_ring K S B hS b = is_localization.lift (map_is_unit_of_le K S hS) b := rfl + +lemma mem_range_map_to_fraction_ring_iff (B : Type*) [comm_ring B] [algebra A B] + [is_localization S B] (hS : S ≤ A⁰) (x : K) : + x ∈ (map_to_fraction_ring K S B hS).range ↔ + ∃ (a s : A) (hs : s ∈ S), x = is_localization.mk' K a ⟨s, hS hs⟩ := +⟨ by { rintro ⟨x,rfl⟩, obtain ⟨a,s,rfl⟩ := is_localization.mk'_surjective S x, + use [a, s, s.2], apply is_localization.lift_mk' }, + by { rintro ⟨a,s,hs,rfl⟩, use is_localization.mk' _ a ⟨s,hs⟩, + apply is_localization.lift_mk' } ⟩ + +instance is_localization_range_map_to_fraction_ring (B : Type*) [comm_ring B] [algebra A B] + [is_localization S B] (hS : S ≤ A⁰) : + is_localization S (map_to_fraction_ring K S B hS).range := +is_localization.is_localization_of_alg_equiv S $ show B ≃ₐ[A] _, from alg_equiv.of_bijective +(map_to_fraction_ring K S B hS).range_restrict +begin + refine ⟨λ a b h, _, set.surjective_onto_range⟩, + refine (is_localization.lift_injective_iff _).2 (λ a b, _) (subtype.ext_iff.1 h), + exact ⟨λ h, congr_arg _ (is_localization.injective _ hS h), + λ h, congr_arg _ (is_fraction_ring.injective A K h)⟩, +end + +instance is_fraction_ring_range_map_to_fraction_ring + (B : Type*) [comm_ring B] [algebra A B] + [is_localization S B] (hS : S ≤ A⁰) : + is_fraction_ring (map_to_fraction_ring K S B hS).range K := +is_fraction_ring.is_fraction_ring_of_is_localization S _ _ hS + +/-- +Given a commutative ring `A` with fraction ring `K`, and a submonoid `S` of `A` which +contains no zero divisor, this is the localization of `A` at `S`, considered as +a subalgebra of `K` over `A`. + +The carrier of this subalgebra is defined as the set of all `x : K` of the form +`is_localization.mk' K a ⟨s, _⟩`, where `s ∈ S`. +-/ +noncomputable +def subalgebra (hS : S ≤ A⁰) : subalgebra A K := +(map_to_fraction_ring K S (localization S) hS).range.copy +{ x | ∃ (a s : A) (hs : s ∈ S), x = is_localization.mk' K a ⟨s, hS hs⟩ } $ +by { ext, symmetry, apply mem_range_map_to_fraction_ring_iff } + +namespace subalgebra + +instance is_localization_subalgebra : + is_localization S (subalgebra K S hS) := +by { dunfold localization.subalgebra, rw subalgebra.copy_eq, apply_instance } + +instance is_fraction_ring : is_fraction_ring (subalgebra K S hS) K := +is_fraction_ring.is_fraction_ring_of_is_localization S _ _ hS + +end subalgebra +end comm_ring + +section field +variables [field K] [algebra A K] [is_fraction_ring A K] +namespace subalgebra + +lemma mem_range_map_to_fraction_ring_iff_of_field + (B : Type*) [comm_ring B] [algebra A B] [is_localization S B] (x : K) : + x ∈ (map_to_fraction_ring K S B hS).range ↔ + ∃ (a s : A) (hs : s ∈ S), x = algebra_map A K a * (algebra_map A K s)⁻¹ := +begin + rw mem_range_map_to_fraction_ring_iff, + iterate 3 { congr' with }, convert iff.rfl, rw units.coe_inv', refl, +end + +/-- +Given a domain `A` with fraction field `K`, and a submonoid `S` of `A` which +contains no zero divisor, this is the localization of `A` at `S`, considered as +a subalgebra of `K` over `A`. + +The carrier of this subalgebra is defined as the set of all `x : K` of the form +`algebra_map A K a * (algebra_map A K s)⁻¹` where `a s : A` and `s ∈ S`. +-/ +noncomputable +def of_field : _root_.subalgebra A K := +(map_to_fraction_ring K S (localization S) hS).range.copy +{ x | ∃ (a s : A) (hs : s ∈ S), x = algebra_map A K a * (algebra_map A K s)⁻¹ } $ +by { ext, symmetry, apply mem_range_map_to_fraction_ring_iff_of_field } + +instance is_localization_of_field : + is_localization S (subalgebra.of_field K S hS) := +by { dunfold localization.subalgebra.of_field, rw subalgebra.copy_eq, apply_instance } + +instance is_fraction_ring_of_field : is_fraction_ring (subalgebra.of_field K S hS) K := +is_fraction_ring.is_fraction_ring_of_is_localization S _ _ hS + +end subalgebra +end field + +end localization diff --git a/src/ring_theory/valuation/valuation_subring.lean b/src/ring_theory/valuation/valuation_subring.lean index cd3fdc627228e..9da94e1ba2550 100644 --- a/src/ring_theory/valuation/valuation_subring.lean +++ b/src/ring_theory/valuation/valuation_subring.lean @@ -1,9 +1,11 @@ /- Copyright (c) 2022 Adam Topaz. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Adam Topaz +Authors: Adam Topaz, Junyan Xu -/ import ring_theory.valuation.valuation_ring +import ring_theory.localization.as_subring +import algebraic_geometry.prime_spectrum.basic /-! @@ -15,6 +17,9 @@ The order structure on `valuation_subring K`. -/ +open_locale classical +noncomputable theory + variables (K : Type*) [field K] /-- A valuation subring of a field `K` is a subring `A` such that for every `x : K`, @@ -28,11 +33,7 @@ variables {K} (A : valuation_subring K) instance : set_like (valuation_subring K) K := { coe := λ A, A.to_subring, - coe_injective' := begin - intros A B h, - cases A, cases B, congr, apply set_like.ext, - exact set.ext_iff.mp h, - end } + coe_injective' := by { rintro ⟨⟨⟩⟩ ⟨⟨⟩⟩ _, congr' } } @[simp] lemma mem_carrier (x : K) : x ∈ A.carrier ↔ x ∈ A := iff.refl _ @[simp] lemma mem_to_subring (x : K) : x ∈ A.to_subring ↔ x ∈ A := iff.refl _ @@ -40,6 +41,12 @@ instance : set_like (valuation_subring K) K := @[ext] lemma ext (A B : valuation_subring K) (h : ∀ x, x ∈ A ↔ x ∈ B) : A = B := set_like.ext h +lemma zero_mem : (0 : K) ∈ A := A.to_subring.zero_mem +lemma one_mem : (1 : K) ∈ A := A.to_subring.one_mem +lemma add_mem (x y : K) : x ∈ A → y ∈ A → x + y ∈ A := A.to_subring.add_mem +lemma mul_mem (x y : K) : x ∈ A → y ∈ A → x * y ∈ A := A.to_subring.mul_mem +lemma neg_mem (x : K) : x ∈ A → (-x) ∈ A := A.to_subring.neg_mem + lemma mem_or_inv_mem (x : K) : x ∈ A ∨ x⁻¹ ∈ A := A.mem_or_inv_mem' _ instance : comm_ring A := show comm_ring A.to_subring, by apply_instance @@ -53,19 +60,22 @@ lemma mem_top (x : K) : x ∈ (⊤ : valuation_subring K) := trivial lemma le_top : A ≤ ⊤ := λ a ha, mem_top _ +instance : order_top (valuation_subring K) := +{ top := ⊤, + le_top := le_top } + instance : inhabited (valuation_subring K) := ⟨⊤⟩ instance : valuation_ring A := -begin - constructor, - intros a b, - by_cases (b : K) = 0, { use 0, left, rw mul_zero, exact_mod_cast h.symm }, - by_cases (a : K) = 0, { use 0, right, rw mul_zero, exact_mod_cast h.symm }, - cases A.mem_or_inv_mem (a/b) with hh hh, - { use ⟨a/b,hh⟩, right, apply subtype.ext, field_simp, ring }, - { rw (show ((a : K)/b)⁻¹ = b/a, by field_simp) at hh, - use ⟨b/a,hh⟩, left, apply subtype.ext, field_simp, ring } -end +{ cond := λ a b, + begin + by_cases (b : K) = 0, { use 0, left, ext, simp [h] }, + by_cases (a : K) = 0, { use 0, right, ext, simp [h] }, + cases A.mem_or_inv_mem (a/b) with hh hh, + { use ⟨a/b,hh⟩, right, ext, field_simp, ring }, + { rw (show (a/b : K)⁻¹ = b/a, by field_simp) at hh, + use ⟨b/a,hh⟩, left, ext, field_simp, ring }, + end } instance : algebra A K := show algebra A.to_subring K, by apply_instance @@ -75,62 +85,222 @@ lemma algebra_map_apply (a : A) : algebra_map A K a = a := rfl instance : is_fraction_ring A K := { map_units := λ ⟨y,hy⟩, - (units.mk0 (y : K) - (λ c, non_zero_divisors.ne_zero hy (by exact_mod_cast c))).is_unit, - surj := begin - intros z, + (units.mk0 (y : K) (λ c, non_zero_divisors.ne_zero hy $ subtype.ext c)).is_unit, + surj := λ z, begin by_cases z = 0, { use (0,1), simp [h] }, cases A.mem_or_inv_mem z with hh hh, { use (⟨z,hh⟩,1), simp }, - { refine ⟨⟨1,⟨⟨_,hh⟩,_⟩⟩,_⟩, - { rw mem_non_zero_divisors_iff_ne_zero, - intro c, apply h, - exact inv_eq_zero.mp (congr_arg coe c) }, - { dsimp, exact mul_inv_cancel h } } + { refine ⟨⟨1,⟨⟨_,hh⟩,_⟩⟩, mul_inv_cancel h⟩, + exact mem_non_zero_divisors_iff_ne_zero.2 (λ c, h (inv_eq_zero.mp (congr_arg coe c))) }, end, - eq_iff_exists := begin - intros a b, - dsimp, - split, - { intro h, use 1, simp only [submonoid.coe_one, mul_one], exact_mod_cast h }, - { rintro ⟨c,h⟩, - simp only [mul_eq_mul_right_iff] at h, - cases h, - { exact_mod_cast h }, - { exact false.elim (non_zero_divisors.ne_zero c.2 h) } }, - end } + eq_iff_exists := λ a b, ⟨ λ h, ⟨1, by { ext, simpa using h }⟩, λ ⟨c,h⟩, + congr_arg coe ((mul_eq_mul_right_iff.1 h).resolve_right (non_zero_divisors.ne_zero c.2)) ⟩ } + +/-- The value group of the valuation associated to `A`. -/ +@[derive linear_ordered_comm_group_with_zero] +def value_group := valuation_ring.value_group A K /-- Any valuation subring of `K` induces a natural valuation on `K`. -/ -def valuation := valuation_ring.valuation A K +def valuation : valuation K A.value_group := valuation_ring.valuation A K + +instance inhabited_value_group : inhabited A.value_group := ⟨A.valuation 0⟩ lemma valuation_le_one (a : A) : A.valuation a ≤ 1 := -begin - change (a : K) ∈ A.valuation.integer, - erw valuation_ring.mem_integer_iff, - use a, refl, -end +(valuation_ring.mem_integer_iff A K _).2 ⟨a,rfl⟩ -lemma mem_of_valuation_le_one (x : K) : A.valuation x ≤ 1 → x ∈ A := -begin - rintro (h : x ∈ A.valuation.integer), - erw valuation_ring.mem_integer_iff at h, - obtain ⟨a,ha⟩ := h, - rw ← ha, exact a.2, -end +lemma mem_of_valuation_le_one (x : K) (h : A.valuation x ≤ 1) : x ∈ A := +let ⟨a,ha⟩ := (valuation_ring.mem_integer_iff A K x).1 h in ha ▸ a.2 lemma valuation_le_one_iff (x : K) : A.valuation x ≤ 1 ↔ x ∈ A := ⟨mem_of_valuation_le_one _ _, λ ha, A.valuation_le_one ⟨x,ha⟩⟩ lemma valuation_eq_iff (x y : K) : A.valuation x = A.valuation y ↔ - ∃ a : Aˣ, (a : K) * y = x := -begin - change quotient.mk' _ = quotient.mk' _ ↔ _, - rw quotient.eq', apply iff.refl, -end + ∃ a : Aˣ, (a : K) * y = x := quotient.eq' lemma valuation_le_iff (x y : K) : A.valuation x ≤ A.valuation y ↔ ∃ a : A, (a : K) * y = x := iff.rfl lemma valuation_surjective : function.surjective A.valuation := surjective_quot_mk _ +lemma valuation_unit (a : Aˣ) : A.valuation a = 1 := +by { rw [← A.valuation.map_one, valuation_eq_iff], use a, simp } + +lemma valuation_eq_one_iff (a : A) : is_unit a ↔ A.valuation a = 1 := +⟨ λ h, A.valuation_unit h.unit, + λ h, begin + have ha : (a : K) ≠ 0, + { intro c, rw [c, A.valuation.map_zero] at h, exact zero_ne_one h }, + have ha' : (a : K)⁻¹ ∈ A, + { rw [← valuation_le_one_iff, A.valuation.map_inv, h, inv_one] }, + apply is_unit_of_mul_eq_one a ⟨a⁻¹, ha'⟩, ext, field_simp, + end ⟩ + +lemma valuation_lt_one_or_eq_one (a : A) : A.valuation a < 1 ∨ A.valuation a = 1 := +lt_or_eq_of_le (A.valuation_le_one a) + +lemma valuation_lt_one_iff (a : A) : a ∈ local_ring.maximal_ideal A ↔ A.valuation a < 1 := +begin + rw local_ring.mem_maximal_ideal, + dsimp [nonunits], rw valuation_eq_one_iff, + exact (A.valuation_le_one a).lt_iff_ne.symm, +end + +/-- A subring `R` of `K` such that for all `x : K` either `x ∈ R` or `x⁻¹ ∈ R` is + a valuation subring of `K`. -/ +def of_subring (R : subring K) (hR : ∀ x : K, x ∈ R ∨ x⁻¹ ∈ R) : valuation_subring K := +{ mem_or_inv_mem' := hR, ..R } + +@[simp] +lemma mem_of_subring (R : subring K) (hR : ∀ x : K, x ∈ R ∨ x⁻¹ ∈ R) (x : K) : + x ∈ of_subring R hR ↔ x ∈ R := iff.refl _ + +/-- An overring of a valuation ring is a valuation ring. -/ +def of_le (R : valuation_subring K) (S : subring K) (h : R.to_subring ≤ S) : + valuation_subring K := +{ mem_or_inv_mem' := λ x, (R.mem_or_inv_mem x).imp (@h x) (@h _), ..S} + +section order + +instance : semilattice_sup (valuation_subring K) := +{ sup := λ R S, of_le R (R.to_subring ⊔ S.to_subring) $ le_sup_left, + le_sup_left := λ R S x hx, (le_sup_left : R.to_subring ≤ R.to_subring ⊔ S.to_subring) hx, + le_sup_right := λ R S x hx, (le_sup_right : S.to_subring ≤ R.to_subring ⊔ S.to_subring) hx, + sup_le := λ R S T hR hT x hx, (sup_le hR hT : R.to_subring ⊔ S.to_subring ≤ T.to_subring) hx, + ..(infer_instance : partial_order (valuation_subring K)) } + +/-- The ring homomorphism induced by the partial order. -/ +def inclusion (R S : valuation_subring K) (h : R ≤ S) : R →+* S := +subring.inclusion h + +/-- The canonical ring homomorphism from a valuation ring to its field of fractions. -/ +def subtype (R : valuation_subring K) : R →+* K := +subring.subtype R.to_subring + +/-- The canonical map on value groups induced by a coarsening of valuation rings. -/ +def map_of_le (R S : valuation_subring K) (h : R ≤ S) : + R.value_group →*₀ S.value_group := +{ to_fun := quotient.map' id $ λ x y ⟨u,hu⟩, ⟨units.map (R.inclusion S h).to_monoid_hom u, hu⟩, + map_zero' := rfl, + map_one' := rfl, + map_mul' := by { rintro ⟨⟩ ⟨⟩, refl } } + +@[mono] +lemma monotone_map_of_le (R S : valuation_subring K) (h : R ≤ S) : + monotone (R.map_of_le S h) := +by { rintros ⟨⟩ ⟨⟩ ⟨a,ha⟩, exact ⟨R.inclusion S h a, ha⟩ } + +@[simp] +lemma map_of_le_comp_valuation (R S : valuation_subring K) (h : R ≤ S) : + R.map_of_le S h ∘ R.valuation = S.valuation := by { ext, refl } + +@[simp] +lemma map_of_le_valuation_apply (R S : valuation_subring K) (h : R ≤ S) (x : K) : + R.map_of_le S h (R.valuation x) = S.valuation x := rfl + +/-- The ideal corresponding to a coarsening of a valuation ring. -/ +def ideal_of_le (R S : valuation_subring K) (h : R ≤ S) : ideal R := +(local_ring.maximal_ideal S).comap (R.inclusion S h) + +instance prime_ideal_of_le (R S : valuation_subring K) (h : R ≤ S) : + (ideal_of_le R S h).is_prime := (local_ring.maximal_ideal S).comap_is_prime _ + +/-- The coarsening of a valuation ring associated to a prime ideal. -/ +def of_prime (A : valuation_subring K) (P : ideal A) [P.is_prime] : + valuation_subring K := +of_le A (localization.subalgebra.of_field K P.prime_compl $ + le_non_zero_divisors_of_no_zero_divisors $ not_not_intro P.zero_mem).to_subring $ + λ a ha, subalgebra.algebra_map_mem _ (⟨a,ha⟩ : A) + +instance of_prime_algebra (A : valuation_subring K) (P : ideal A) [P.is_prime] : + algebra A (A.of_prime P) := subalgebra.algebra _ + +instance of_prime_scalar_tower (A : valuation_subring K) (P : ideal A) [P.is_prime] : + is_scalar_tower A (A.of_prime P) K := is_scalar_tower.subalgebra' A K K _ + +instance of_prime_localization (A : valuation_subring K) (P : ideal A) [P.is_prime] : + is_localization.at_prime (A.of_prime P) P := +by apply localization.subalgebra.is_localization_of_field K + +lemma le_of_prime (A : valuation_subring K) (P : ideal A) [P.is_prime] : + A ≤ of_prime A P := +λ a ha, subalgebra.algebra_map_mem _ (⟨a,ha⟩ : A) + +lemma of_prime_valuation_eq_one_iff_mem_prime_compl + (A : valuation_subring K) + (P : ideal A) [P.is_prime] (x : A) : + (of_prime A P).valuation x = 1 ↔ x ∈ P.prime_compl := +begin + rw [← is_localization.at_prime.is_unit_to_map_iff (A.of_prime P) P x, valuation_eq_one_iff], refl, +end + +@[simp] +lemma ideal_of_le_of_prime (A : valuation_subring K) (P : ideal A) [P.is_prime] : + ideal_of_le A (of_prime A P) (le_of_prime A P) = P := +by { ext, apply is_localization.at_prime.to_map_mem_maximal_iff } + +@[simp] +lemma of_prime_ideal_of_le (R S : valuation_subring K) (h : R ≤ S) : + of_prime R (ideal_of_le R S h) = S := +begin + ext x, split, + { rintro ⟨a,r,hr,rfl⟩, apply mul_mem, { exact h a.2 }, + { rw [← valuation_le_one_iff, valuation.map_inv, ← inv_one, inv_le_inv₀], + { exact not_lt.1 ((not_iff_not.2 $ valuation_lt_one_iff S _).1 hr) }, + { intro hh, erw [valuation.zero_iff, subring.coe_eq_zero_iff] at hh, + apply hr, rw hh, apply ideal.zero_mem (R.ideal_of_le S h) }, + { exact one_ne_zero } } }, + { intro hx, by_cases hr : x ∈ R, { exact R.le_of_prime _ hr }, + have : x ≠ 0 := λ h, hr (by { rw h, exact R.zero_mem }), + replace hr := (R.mem_or_inv_mem x).resolve_left hr, + { use [1, x⁻¹, hr], split, + { change (⟨x⁻¹, h hr⟩ : S) ∉ nonunits S, + erw [mem_nonunits_iff, not_not], + apply is_unit_of_mul_eq_one _ (⟨x,hx⟩ : S), + ext, field_simp }, + { field_simp } } }, +end + +lemma of_prime_le_of_le (P Q : ideal A) [P.is_prime] [Q.is_prime] + (h : P ≤ Q) : of_prime A Q ≤ of_prime A P := +λ x ⟨a, s, hs, he⟩, ⟨a, s, λ c, hs (h c), he⟩ + +lemma ideal_of_le_le_of_le (R S : valuation_subring K) + (hR : A ≤ R) (hS : A ≤ S) (h : R ≤ S) : + ideal_of_le A S hS ≤ ideal_of_le A R hR := +λ x hx, (valuation_lt_one_iff R _).2 begin + by_contra c, push_neg at c, replace c := monotone_map_of_le R S h c, + rw [(map_of_le _ _ _).map_one, map_of_le_valuation_apply] at c, + apply not_le_of_lt ((valuation_lt_one_iff S _).1 hx) c, +end + +/-- The equivalence between coarsenings of a valuation ring and its prime ideals.-/ +@[simps] +def prime_spectrum_equiv : + prime_spectrum A ≃ { S | A ≤ S } := +{ to_fun := λ P, ⟨of_prime A P.as_ideal, le_of_prime _ _⟩, + inv_fun := λ S, ⟨ideal_of_le _ S S.2, infer_instance⟩, + left_inv := λ P, by { ext1, simpa }, + right_inv := λ S, by { ext1, simp } } + +/-- An ordered variant of `prime_spectrum_equiv`. -/ +@[simps] +def prime_spectrum_order_equiv : + order_dual (prime_spectrum A) ≃o { S | A ≤ S } := +{ map_rel_iff' := λ P Q, + ⟨ λ h, begin + have := ideal_of_le_le_of_le A _ _ _ _ h, + iterate 2 { erw ideal_of_le_of_prime at this }, + exact this, + end, + λ h, by { apply of_prime_le_of_le, exact h } ⟩, + ..(prime_spectrum_equiv A) } + +instance linear_order_overring : linear_order { S | A ≤ S } := +{ le_total := let i : is_total (prime_spectrum A) (≤) := (subtype.rel_embedding _ _).is_total in + by exactI (prime_spectrum_order_equiv A).symm.to_rel_embedding.is_total.total, + decidable_le := infer_instance, + ..(infer_instance : partial_order _) } + +end order + end valuation_subring From d444a279b3cb694963893ed84382689d939b83e8 Mon Sep 17 00:00:00 2001 From: tb65536 Date: Thu, 21 Apr 2022 23:36:54 +0000 Subject: [PATCH 155/373] feat(group_theory/transfer): Define the transfer homomorphism (#13446) This PR adds a definition of the transfer homomorphism. Co-authored-by: tb65536 --- src/group_theory/transfer.lean | 82 ++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 src/group_theory/transfer.lean diff --git a/src/group_theory/transfer.lean b/src/group_theory/transfer.lean new file mode 100644 index 0000000000000..e64ff5bf7670a --- /dev/null +++ b/src/group_theory/transfer.lean @@ -0,0 +1,82 @@ +/- +Copyright (c) 2022 Thomas Browning. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Thomas Browning +-/ + +import group_theory.complement +import group_theory.group_action.basic +import group_theory.index + +/-! +# The Transfer Homomorphism + +In this file we construct the transfer homomorphism. + +## Main definitions + +- `diff ϕ S T` : The difference of two left transversals `S` and `T` under the homomorphism `ϕ`. +- `transfer ϕ` : The transfer homomorphism induced by `ϕ`. +-/ + +open_locale big_operators + +variables {G : Type*} [group G] {H : subgroup G} {A : Type*} [comm_group A] (ϕ : H →* A) + +namespace subgroup + +namespace left_transversals + +open finset mul_action + +open_locale pointwise + +variables (R S T : left_transversals (H : set G)) [fintype (G ⧸ H)] + +/-- The difference of two left transversals -/ +@[to_additive "The difference of two left transversals"] +noncomputable def diff : A := +let α := mem_left_transversals.to_equiv S.2, β := mem_left_transversals.to_equiv T.2 in +∏ q, ϕ ⟨(α q)⁻¹ * β q, quotient.exact' ((α.symm_apply_apply q).trans (β.symm_apply_apply q).symm)⟩ + +@[to_additive] lemma diff_mul_diff : diff ϕ R S * diff ϕ S T = diff ϕ R T := +prod_mul_distrib.symm.trans (prod_congr rfl (λ q hq, (ϕ.map_mul _ _).symm.trans (congr_arg ϕ + (by simp_rw [subtype.ext_iff, coe_mul, coe_mk, mul_assoc, mul_inv_cancel_left])))) + +@[to_additive] lemma diff_self : diff ϕ T T = 1 := +mul_right_eq_self.mp (diff_mul_diff ϕ T T T) + +@[to_additive] lemma diff_inv : (diff ϕ S T)⁻¹ = diff ϕ T S := +inv_eq_of_mul_eq_one ((diff_mul_diff ϕ S T S).trans (diff_self ϕ S)) + +@[to_additive] lemma smul_diff_smul (g : G) : diff ϕ (g • S) (g • T) = diff ϕ S T := +prod_bij' (λ q _, g⁻¹ • q) (λ _ _, mem_univ _) (λ _ _, congr_arg ϕ (by simp_rw [coe_mk, + smul_apply_eq_smul_apply_inv_smul, smul_eq_mul, mul_inv_rev, mul_assoc, inv_mul_cancel_left])) + (λ q _, g • q) (λ _ _, mem_univ _) (λ q _, smul_inv_smul g q) (λ q _, inv_smul_smul g q) + +end left_transversals + +end subgroup + +namespace monoid_hom + +variables [fintype (G ⧸ H)] + +open subgroup subgroup.left_transversals + +/-- Given `ϕ : H →* A` from `H : subgroup G` to a commutative group `A`, +the transfer homomorphism is `transfer ϕ : G →* A`. -/ +@[to_additive "Given `ϕ : H →+ A` from `H : add_subgroup G` to an additive commutative group `A`, +the transfer homomorphism is `transfer ϕ : G →+ A`."] +noncomputable def transfer : G →* A := +let T : left_transversals (H : set G) := inhabited.default in +{ to_fun := λ g, diff ϕ T (g • T), + map_one' := by rw [one_smul, diff_self], + map_mul' := λ g h, by rw [mul_smul, ←diff_mul_diff, smul_diff_smul] } + +variables (T : left_transversals (H : set G)) + +@[to_additive] lemma transfer_def (g : G) : transfer ϕ g = diff ϕ T (g • T) := +by rw [transfer, ←diff_mul_diff, ←smul_diff_smul, mul_comm, diff_mul_diff]; refl + +end monoid_hom From afb43923c074b7e43aa3705e2764440c5f68ad4b Mon Sep 17 00:00:00 2001 From: antoinelab01 Date: Thu, 21 Apr 2022 23:36:55 +0000 Subject: [PATCH 156/373] feat(linear_algebra/prod): two lemmas about prod_map (#13572) Co-authored-by: antoinelab01 <66086247+antoinelab01@users.noreply.github.com> --- src/linear_algebra/prod.lean | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/linear_algebra/prod.lean b/src/linear_algebra/prod.lean index 9312be682ff39..f1dead99d12d7 100644 --- a/src/linear_algebra/prod.lean +++ b/src/linear_algebra/prod.lean @@ -33,7 +33,7 @@ It contains theorems relating these to each other, as well as to `submodule.prod universes u v w x y z u' v' w' y' variables {R : Type u} {K : Type u'} {M : Type v} {V : Type v'} {M₂ : Type w} {V₂ : Type w'} variables {M₃ : Type y} {V₃ : Type y'} {M₄ : Type z} {ι : Type x} - +variables {M₅ M₆ : Type*} section prod @@ -41,7 +41,9 @@ namespace linear_map variables (S : Type*) [semiring R] [semiring S] variables [add_comm_monoid M] [add_comm_monoid M₂] [add_comm_monoid M₃] [add_comm_monoid M₄] +variables [add_comm_monoid M₅] [add_comm_monoid M₆] variables [module R M] [module R M₂] [module R M₃] [module R M₄] +variables [module R M₅] [module R M₆] variables (f : M →ₗ[R] M₂) section @@ -234,6 +236,27 @@ begin rw [←prod_map_comap_prod, submodule.prod_bot], end +@[simp] +lemma prod_map_id : (id : M →ₗ[R] M).prod_map (id : M₂ →ₗ[R] M₂) = id := +linear_map.ext $ λ _, prod.mk.eta + +@[simp] +lemma prod_map_one : (1 : M →ₗ[R] M).prod_map (1 : M₂ →ₗ[R] M₂) = 1 := +linear_map.ext $ λ _, prod.mk.eta + +lemma prod_map_comp (f₁₂ : M →ₗ[R] M₂) (f₂₃ : M₂ →ₗ[R] M₃) (g₁₂ : M₄ →ₗ[R] M₅) (g₂₃ : M₅ →ₗ[R] M₆) : + f₂₃.prod_map g₂₃ ∘ₗ f₁₂.prod_map g₁₂ = (f₂₃ ∘ₗ f₁₂).prod_map (g₂₃ ∘ₗ g₁₂) := rfl + +lemma prod_map_mul (f₁₂ : M →ₗ[R] M) (f₂₃ : M →ₗ[R] M) (g₁₂ : M₂ →ₗ[R] M₂) (g₂₃ : M₂ →ₗ[R] M₂) : + f₂₃.prod_map g₂₃ * f₁₂.prod_map g₁₂ = (f₂₃ * f₁₂).prod_map (g₂₃ * g₁₂) := rfl + +/-- `linear_map.prod_map` as a `monoid_hom` -/ +@[simps] +def prod_map_monoid_hom : (M →ₗ[R] M) × (M₂ →ₗ[R] M₂) →* ((M × M₂) →ₗ[R] (M × M₂)) := +{ to_fun := λ f, prod_map f.1 f.2, + map_one' := prod_map_one, + map_mul' := λ _ _, prod_map_mul _ _ _ _ } + section map_mul variables {A : Type*} [non_unital_non_assoc_semiring A] [module R A] From bb9d1c5085e0b7ea619806a68c5021927cecb2a6 Mon Sep 17 00:00:00 2001 From: Eric Rodriguez Date: Fri, 22 Apr 2022 01:34:14 +0000 Subject: [PATCH 157/373] chore(*): remove `subst` when not necessary (#13453) Where possible, this replaces `subst` with `obtain rfl` (which is equivalent to `have` and then `subst`, golfing a line). This also tidies some non-terminal `simp`s. Co-authored-by: Eric Rodriguez <37984851+ericrbg@users.noreply.github.com> --- archive/imo/imo1960_q1.lean | 2 +- src/algebra/homology/additive.lean | 11 ++--- src/algebraic_geometry/ringed_space.lean | 9 ++--- src/algebraic_topology/simplex_category.lean | 3 +- src/analysis/box_integral/integrability.lean | 4 +- src/analysis/normed/group/quotient.lean | 7 +--- src/analysis/normed_space/multilinear.lean | 2 +- src/category_theory/category/basic.lean | 6 +-- src/category_theory/eq_to_hom.lean | 3 +- .../limits/shapes/strict_initial.lean | 2 +- src/control/applicative.lean | 7 ++-- src/control/lawful_fix.lean | 10 ++--- src/data/buffer/parser/basic.lean | 27 +++++-------- src/data/dfinsupp/basic.lean | 7 ++-- src/data/fin/tuple/basic.lean | 6 +-- src/data/fin_enum.lean | 2 +- src/data/hash_map.lean | 4 +- src/data/int/basic.lean | 6 +-- src/data/list/forall2.lean | 2 +- src/data/list/pairwise.lean | 2 +- src/data/list/permutation.lean | 6 +-- src/data/list/sort.lean | 2 +- src/data/multiset/pi.lean | 14 +++---- src/data/nat/gcd.lean | 4 +- src/data/nat/pow.lean | 9 ++--- src/data/ordmap/ordset.lean | 8 ++-- src/data/pfunctor/univariate/M.lean | 33 ++++++++------- src/data/rat/basic.lean | 10 ++--- src/data/rbtree/insert.lean | 18 ++++----- src/data/real/irrational.lean | 3 +- src/data/set/basic.lean | 2 +- src/data/set/function.lean | 3 +- src/data/sigma/basic.lean | 7 ++-- src/field_theory/adjoin.lean | 3 +- .../affine_space/affine_map.lean | 3 +- .../affine_space/independent.lean | 40 ++++++++----------- src/linear_algebra/dimension.lean | 3 +- src/linear_algebra/free_module/pid.lean | 3 +- src/linear_algebra/linear_pmap.lean | 4 +- src/logic/relator.lean | 5 +-- src/order/complete_lattice.lean | 2 +- src/order/order_iso_nat.lean | 3 +- src/ring_theory/algebra_tower.lean | 3 +- src/ring_theory/artinian.lean | 2 +- src/ring_theory/discrete_valuation_ring.lean | 4 +- src/ring_theory/noetherian.lean | 2 +- src/ring_theory/power_series/basic.lean | 7 ++-- src/set_theory/ordinal/basic.lean | 5 +-- src/set_theory/ordinal/notation.lean | 11 ++--- src/set_theory/zfc.lean | 32 +++++++-------- src/topology/homotopy/path.lean | 4 +- src/topology/sets/opens.lean | 2 +- .../uniform_space/compact_separated.lean | 3 +- 53 files changed, 167 insertions(+), 215 deletions(-) diff --git a/archive/imo/imo1960_q1.lean b/archive/imo/imo1960_q1.lean index f53742efa6ead..7caef8294f29b 100644 --- a/archive/imo/imo1960_q1.lean +++ b/archive/imo/imo1960_q1.lean @@ -73,7 +73,7 @@ begin refine ⟨by ring, λ m l p, _⟩, obtain ⟨h₁, ⟨m, rfl⟩, h₂⟩ := id p, by_cases h : 11 * m < c * 11, { exact H _ h p }, - have : m = c, {linarith}, subst m, + obtain rfl : m = c := by linarith, rw [nat.mul_div_cancel_left _ (by norm_num : 11 > 0), mul_comm] at h₂, refine (H' h₂).imp _ _; {rintro rfl, norm_num} end diff --git a/src/algebra/homology/additive.lean b/src/algebra/homology/additive.lean index 90a900157ef6f..af7261722dc07 100644 --- a/src/algebra/homology/additive.lean +++ b/src/algebra/homology/additive.lean @@ -151,13 +151,10 @@ lemma map_chain_complex_of (F : V ⥤ W) [F.additive] (X : α → V) (d : Π n, chain_complex.of (λ n, F.obj (X n)) (λ n, F.map (d n)) (λ n, by rw [ ← F.map_comp, sq n, functor.map_zero]) := begin - apply homological_complex.ext, - intros i j hij, - { have h : j+1=i := hij, - subst h, - simp only [category_theory.functor.map_homological_complex_obj_d, of_d, - eq_to_hom_refl, comp_id, id_comp], }, - { refl, } + refine homological_complex.ext rfl _, + rintro i j (rfl : j + 1 = i), + simp only [category_theory.functor.map_homological_complex_obj_d, of_d, + eq_to_hom_refl, comp_id, id_comp], end end chain_complex diff --git a/src/algebraic_geometry/ringed_space.lean b/src/algebraic_geometry/ringed_space.lean index 449ce64cd61de..5160fbe37e580 100644 --- a/src/algebraic_geometry/ringed_space.lean +++ b/src/algebraic_geometry/ringed_space.lean @@ -148,13 +148,12 @@ begin induction V using opposite.rec, let g := i.unop, have : i = g.op := rfl, clear_value g, subst this, ext, split, - { rintro ⟨x, (hx : is_unit _), rfl⟩, rw germ_res_apply at hx, + { rintro ⟨x, (hx : is_unit _), rfl⟩, + rw germ_res_apply at hx, exact ⟨x.2, g x, hx, rfl⟩ }, { rintros ⟨hxV, x, hx, rfl⟩, - use ⟨x, hxV⟩, - split, - { change is_unit _, rw germ_res_apply, exact hx }, - { refl } } + refine ⟨⟨x, hxV⟩, (_ : is_unit _), rfl⟩, + rwa germ_res_apply } end -- This should fire before `basic_open_res`. diff --git a/src/algebraic_topology/simplex_category.lean b/src/algebraic_topology/simplex_category.lean index c192fa1bbe89c..0445dbca20df5 100644 --- a/src/algebraic_topology/simplex_category.lean +++ b/src/algebraic_topology/simplex_category.lean @@ -666,8 +666,7 @@ begin erw [fin.succ_above_above i _, fin.succ_pred], simpa only [fin.le_iff_coe_le_coe, fin.coe_cast_succ, fin.coe_pred] using nat.le_pred_of_lt (fin.lt_iff_coe_lt_coe.mp h'), }, }, - { have h' := le_antisymm (fin.le_last i) (not_lt.mp h), - subst h', + { obtain rfl := le_antisymm (fin.le_last i) (not_lt.mp h), use θ ≫ σ (fin.last _), ext1, ext1, ext1 x, simp only [hom.to_order_hom_mk, function.comp_app, order_hom.comp_coe, hom.comp, diff --git a/src/analysis/box_integral/integrability.lean b/src/analysis/box_integral/integrability.lean index 1a7a8af4b7d08..df7802c704605 100644 --- a/src/analysis/box_integral/integrability.lean +++ b/src/analysis/box_integral/integrability.lean @@ -273,7 +273,9 @@ begin from λ J hJ, (π.mem_filter.1 hJ).2, have hrn : ∀ J ∈ π.filter (λ J, Nx (π.tag J) = n), r c (π.tag J) = (hfi' n).convergence_r (δ n) c (π.tag J), - { intros J hJ, have := hNxn J hJ, clear hJ, subst n }, + { intros J hJ, + obtain rfl := hNxn J hJ, + refl }, have : l.mem_base_set I c ((hfi' n).convergence_r (δ n) c) (π.filter (λ J, Nx (π.tag J) = n)), from (hπ.filter _).mono' _ le_rfl le_rfl (λ J hJ, (hrn J hJ).le), convert (hfi' n).dist_integral_sum_sum_integral_le_of_mem_base_set (δ0 _) this using 2, diff --git a/src/analysis/normed/group/quotient.lean b/src/analysis/normed/group/quotient.lean index 856999c847c2c..a8f5f4110438c 100644 --- a/src/analysis/normed/group/quotient.lean +++ b/src/analysis/normed/group/quotient.lean @@ -117,14 +117,11 @@ begin by simp only [this, norm], ext r, split, - { rintros ⟨m, hm : mk' S m = x, rfl⟩, - subst hm, + { rintros ⟨m, rfl : mk' S m = x, rfl⟩, rw ← norm_neg, exact ⟨-m, by simp only [(mk' S).map_neg, set.mem_set_of_eq], rfl⟩ }, { rintros ⟨m, hm : mk' S m = -x, rfl⟩, - use -m, - simp at hm, - simp [hm], } + exact ⟨-m, by simpa [eq_comm] using eq_neg_iff_eq_neg.mp ((mk'_apply _ _).symm.trans hm)⟩ } end lemma quotient_norm_sub_rev {S : add_subgroup M} (x y : M ⧸ S) : ∥x - y∥ = ∥y - x∥ := diff --git a/src/analysis/normed_space/multilinear.lean b/src/analysis/normed_space/multilinear.lean index b7771c2f0721e..18947e090488f 100644 --- a/src/analysis/normed_space/multilinear.lean +++ b/src/analysis/normed_space/multilinear.lean @@ -1264,7 +1264,7 @@ variables {𝕜 G} @[simp] lemma continuous_multilinear_map.fin0_apply_norm (f : G [×0]→L[𝕜] G') {x : fin 0 → G} : ∥f x∥ = ∥f∥ := begin - have : x = 0 := subsingleton.elim _ _, subst this, + obtain rfl : x = 0 := subsingleton.elim _ _, refine le_antisymm (by simpa using f.le_op_norm 0) _, have : ∥continuous_multilinear_map.curry0 𝕜 G (f.uncurry0)∥ ≤ ∥f.uncurry0∥ := continuous_multilinear_map.op_norm_le_bound _ (norm_nonneg _) (λm, diff --git a/src/category_theory/category/basic.lean b/src/category_theory/category/basic.lean index 1de3fae786fda..0462f0410fe96 100644 --- a/src/category_theory/category/basic.lean +++ b/src/category_theory/category/basic.lean @@ -182,10 +182,10 @@ instance (X : C) : epi (𝟙 X) := instance (X : C) : mono (𝟙 X) := ⟨λ Z g h w, by simpa using w⟩ -lemma cancel_epi (f : X ⟶ Y) [epi f] {g h : Y ⟶ Z} : (f ≫ g = f ≫ h) ↔ g = h := -⟨ λ p, epi.left_cancellation g h p, begin intro a, subst a end ⟩ +lemma cancel_epi (f : X ⟶ Y) [epi f] {g h : Y ⟶ Z} : (f ≫ g = f ≫ h) ↔ g = h := +⟨λ p, epi.left_cancellation g h p, congr_arg _⟩ lemma cancel_mono (f : X ⟶ Y) [mono f] {g h : Z ⟶ X} : (g ≫ f = h ≫ f) ↔ g = h := -⟨ λ p, mono.right_cancellation g h p, begin intro a, subst a end ⟩ +⟨λ p, mono.right_cancellation g h p, congr_arg _⟩ lemma cancel_epi_id (f : X ⟶ Y) [epi f] {h : Y ⟶ Y} : (f ≫ h = f) ↔ h = 𝟙 Y := by { convert cancel_epi f, simp, } diff --git a/src/category_theory/eq_to_hom.lean b/src/category_theory/eq_to_hom.lean index 855f267e6c871..0a7c7aecfbfcc 100644 --- a/src/category_theory/eq_to_hom.lean +++ b/src/category_theory/eq_to_hom.lean @@ -114,8 +114,7 @@ lemma ext {F G : C ⥤ D} (h_obj : ∀ X, F.obj X = G.obj X) F = G := begin cases F with F_obj _ _ _, cases G with G_obj _ _ _, - have : F_obj = G_obj, by ext X; apply h_obj, - subst this, + obtain rfl : F_obj = G_obj, by { ext X, apply h_obj }, congr, funext X Y f, simpa using h_map X Y f diff --git a/src/category_theory/limits/shapes/strict_initial.lean b/src/category_theory/limits/shapes/strict_initial.lean index 8e78962313e96..f75fb39581491 100644 --- a/src/category_theory/limits/shapes/strict_initial.lean +++ b/src/category_theory/limits/shapes/strict_initial.lean @@ -203,7 +203,7 @@ begin { exact λ j, dite (j = i) (λ h, eq_to_hom (by { cases h, refl })) (λ h, (H _ h).from _) }, { intros j k f, split_ifs, - { cases h, cases h_1, have : f = 𝟙 _ := subsingleton.elim _ _, subst this, simpa }, + { cases h, cases h_1, obtain rfl : f = 𝟙 _ := subsingleton.elim _ _, simpa }, { cases h, erw category.comp_id, haveI : is_iso (F.map f) := (H _ h_1).is_iso_from _, rw ← is_iso.comp_inv_eq, diff --git a/src/control/applicative.lean b/src/control/applicative.lean index 84ce23162a5fb..ffa4df13e1e84 100644 --- a/src/control/applicative.lean +++ b/src/control/applicative.lean @@ -43,13 +43,12 @@ theorem applicative.ext {F} : ∀ {A1 : applicative F} {A2 : applicative F} | {to_functor := F1, seq := s1, pure := p1, seq_left := sl1, seq_right := sr1} {to_functor := F2, seq := s2, pure := p2, seq_left := sl2, seq_right := sr2} L1 L2 H1 H2 := begin - have : @p1 = @p2, {funext α x, apply H1}, subst this, - have : @s1 = @s2, {funext α β f x, apply H2}, subst this, + obtain rfl : @p1 = @p2, {funext α x, apply H1}, + obtain rfl : @s1 = @s2, {funext α β f x, apply H2}, cases L1, cases L2, - have : F1 = F2, + obtain rfl : F1 = F2, { resetI, apply functor.ext, intros, exact (L1_pure_seq_eq_map _ _).symm.trans (L2_pure_seq_eq_map _ _) }, - subst this, congr; funext α β x y, { exact (L1_seq_left_eq _ _).trans (L2_seq_left_eq _ _).symm }, { exact (L1_seq_right_eq _ _).trans (L2_seq_right_eq _ _).symm } diff --git a/src/control/lawful_fix.lean b/src/control/lawful_fix.lean index 848160436766d..94bd04d7e3b37 100644 --- a/src/control/lawful_fix.lean +++ b/src/control/lawful_fix.lean @@ -92,8 +92,8 @@ begin { rcases hh with ⟨i,b,hb⟩, existsi i, intros b' h', have hb' := approx_le_fix f i _ _ hb, - have hh := part.mem_unique h' hb', - subst hh, exact hb }, + obtain rfl := part.mem_unique h' hb', + exact hb }, { simp only [not_exists] at hh, existsi 0, intros b' h', simp only [mem_iff f] at h', @@ -106,10 +106,10 @@ include f /-- The series of approximations of `fix f` (see `approx`) as a `chain` -/ def approx_chain : chain (Π a, part $ β a) := ⟨approx f, approx_mono f⟩ -lemma le_f_of_mem_approx {x} (hx : x ∈ approx_chain f) : x ≤ f x := +lemma le_f_of_mem_approx {x} : x ∈ approx_chain f → x ≤ f x := begin - revert hx, simp [(∈)], - intros i hx, subst x, + simp only [(∈), forall_exists_index], + rintro i rfl, apply approx_mono' end diff --git a/src/data/buffer/parser/basic.lean b/src/data/buffer/parser/basic.lean index f71151646758a..4c9b11621f64b 100644 --- a/src/data/buffer/parser/basic.lean +++ b/src/data/buffer/parser/basic.lean @@ -1466,11 +1466,9 @@ begin haveI := hr, intros cb n, obtain ⟨np, a, h⟩ := p.exists_done cb n, - have : n = np := static.of_done h, - subst this, + obtain rfl : n = np := static.of_done h, obtain ⟨np, b', hf⟩ := exists_done (foldr_core f p b (reps + 1)) cb n, - have : n = np := static.of_done hf, - subst this, + obtain rfl : n = np := static.of_done hf, refine ⟨n, f a b', _⟩, rw foldr_core_eq_done, simp [h, hf, and.comm, and.left_comm, and.assoc] } @@ -1861,8 +1859,7 @@ begin { rw ←@IH hd' tl' at hm, swap, refl, simp only [many1_eq_done, many, foldr] at hm, obtain ⟨np, hp', hf⟩ := hm, - have : np = n + 1 + 1 := step.of_done hp', - subst this, + obtain rfl : np = n + 1 + 1 := step.of_done hp', simpa [nat.sub_succ, many_eq_done, hp, hk, foldr_core_eq_done, hp'] using hf } }, { simp only [many_eq_done, many1_eq_done, and_imp, exists_imp_distrib], intros np hp hm, @@ -1883,8 +1880,7 @@ begin { simpa using hm }, simp only at hm, obtain ⟨rfl, rfl⟩ := hm, - have : np = n + 1 + 1 := step.of_done hp', - subst this, + obtain rfl : np = n + 1 + 1 := step.of_done hp', simp [nat.sub_succ, many, many1_eq_done, hp, hk, foldr_core_eq_done, hp', ←hf, foldr] } } end @@ -2111,8 +2107,7 @@ begin subst hk, simp only [many1_eq_done] at h, obtain ⟨_, hp, h⟩ := h, - have := step.of_done hp, - subst this, + obtain rfl := step.of_done hp, cases tl, { simp only [many_eq_done_nil, add_left_inj, exists_and_distrib_right, self_eq_add_right] at h, rcases h with ⟨rfl, -⟩, @@ -2130,8 +2125,7 @@ begin { simpa using h }, { simp only [many1_eq_done] at h, obtain ⟨np, hp, h⟩ := h, - have := step.of_done hp, - subst this, + obtain rfl := step.of_done hp, cases tl, { simp only [many_eq_done_nil, exists_and_distrib_right] at h, simpa [←h.left] using bounded.of_done hp }, @@ -2223,8 +2217,7 @@ begin -- In fact, we know that this new position is `n + 1`, by the `step` property of -- `parser.digit`. obtain ⟨_, hp, -⟩ := hp, - have := step.of_done hp, - subst this, + obtain rfl := step.of_done hp, -- We now unfold what it means for `parser.digit` to succeed, which means that the character -- parsed in was "numeric" (for some definition of that property), and, more importantly, -- that the `n`th character of `cb`, let's say `c`, when converted to a `ℕ` via @@ -2269,8 +2262,7 @@ begin -- This means we must have failed parsing with `parser.digit` at some other position, -- which we prove must be `n + 1` via the `step` property. obtain ⟨_, hp, rfl, hp'⟩ := hp, - have := step.of_done hp, - subst this, + obtain rfl := step.of_done hp, -- Now we rely on the simplifier, which simplfies the LHS, which is a fold over a singleton -- list. On the RHS, `list.take (n + 1 - n)` also produces a singleton list, which, when -- reversed, is the same list. `nat.of_digits` of a singleton list is precisely the value in @@ -2655,8 +2647,7 @@ begin -- `n + m + 1 - n = m + 1` proof and `mul_comm`. simp [this, hpow, nat.of_digits_append, mul_comm, ←pow_succ 10, hml, ltll] }, { -- Consider the case that `n' ≤ n + 1`. But then since `n < n' ≤ n + 1`, `n' = n + 1`. - have : n' = n + 1 := le_antisymm hn'' (nat.succ_le_of_lt hn), - subst this, + obtain rfl : n' = n + 1 := le_antisymm hn'' (nat.succ_le_of_lt hn), -- This means we have only parsed in a single character, so the resulting parsed in list -- is explicitly formed from an expression we can construct from `hd`. use [[hd.to_nat - '0'.to_nat]], diff --git a/src/data/dfinsupp/basic.lean b/src/data/dfinsupp/basic.lean index 665cf625df4ff..9e43ed9591b97 100644 --- a/src/data/dfinsupp/basic.lean +++ b/src/data/dfinsupp/basic.lean @@ -524,9 +524,8 @@ begin rw dfinsupp.single_eq_of_ne (ne.symm hij) at hci, rw dfinsupp.single_eq_of_ne (hij) at hcj, exact or.inr ⟨hci, hcj.symm⟩, }, }, - { rintros (⟨hi, hxi⟩ | ⟨hi, hj⟩), - { subst hi, - rw eq_of_heq hxi, }, + { rintros (⟨rfl, hxi⟩ | ⟨hi, hj⟩), + { rw eq_of_heq hxi, }, { rw [hi, hj, dfinsupp.single_zero, dfinsupp.single_zero], }, }, end @@ -1042,7 +1041,7 @@ assume f g, decidable_of_iff (f.support = g.support ∧ (∀i∈f.support, f i = have hf : f i = 0, by rwa [mem_support_iff, not_not] at h, have hg : g i = 0, by rwa [h₁, mem_support_iff, not_not] at h, by rw [hf, hg], - by intro h; subst h; simp⟩ + by { rintro rfl, simp }⟩ section equiv open finset diff --git a/src/data/fin/tuple/basic.lean b/src/data/fin/tuple/basic.lean index e4f9770167b61..d392b685dfa32 100644 --- a/src/data/fin/tuple/basic.lean +++ b/src/data/fin/tuple/basic.lean @@ -603,15 +603,13 @@ lemma find_min : Π {n : ℕ} {p : fin n → Prop} [decidable_pred p] {i : fin n cases h : find (λ i : fin n, (p (i.cast_lt (nat.lt_succ_of_lt i.2)))) with k, { rw [h] at hi, split_ifs at hi with hl hl, - { have := option.some_inj.1 hi, - subst this, + { obtain rfl := option.some_inj.1 hi, rw [find_eq_none_iff] at h, exact h ⟨j, hj⟩ hpj }, { exact option.no_confusion hi } }, { rw h at hi, dsimp at hi, - have := option.some_inj.1 hi, - subst this, + obtain rfl := option.some_inj.1 hi, exact find_min h (show (⟨j, lt_trans hj k.2⟩ : fin n) < k, from hj) hpj } end diff --git a/src/data/fin_enum.lean b/src/data/fin_enum.lean index bba5565c6918f..338b1b1bb5db0 100644 --- a/src/data/fin_enum.lean +++ b/src/data/fin_enum.lean @@ -126,7 +126,7 @@ begin eq_self_iff_true], }, { left, symmetry, simp only [sdiff_eq_self], intro a, simp only [and_imp, mem_inter, mem_singleton, not_mem_empty], - intros h₀ h₁, subst a, apply h h₀, } } + rintro h₀ rfl, apply h h₀, } } end instance finset.fin_enum [fin_enum α] : fin_enum (finset α) := diff --git a/src/data/hash_map.lean b/src/data/hash_map.lean index f4d72e283c6e7..60f9ec9b3f180 100644 --- a/src/data/hash_map.lean +++ b/src/data/hash_map.lean @@ -616,12 +616,12 @@ theorem mem_erase : Π (m : hash_map α β) (a a' b'), { simp [eq_comm, not_and_self_iff, and_iff_right_of_imp this] }, simpa [hl, show bkts'.as_list = _, from hfl, and_or_distrib_left, and_comm, and.left_comm, or.left_comm] }, - intros m e, subst a', revert m, apply not_or_distrib.2, + rintro m rfl, revert m, apply not_or_distrib.2, have nd' := v.as_list_nodup _, simp [hl, list.nodup_append] at nd', simp [nd'] }, { suffices : ∀_:sigma.mk a' b' ∈ bucket_array.as_list bkts, a ≠ a', { simp [erase, @dif_neg (contains_aux a bkt) _ Hc, entries, and_iff_right_of_imp this] }, - intros m e, subst a', + rintro m rfl, exact Hc ((v.contains_aux_iff _ _).2 (list.mem_map_of_mem sigma.fst m)) } end diff --git a/src/data/int/basic.lean b/src/data/int/basic.lean index d674800ff7598..6c0a073f65b8f 100644 --- a/src/data/int/basic.lean +++ b/src/data/int/basic.lean @@ -298,9 +298,9 @@ theorem nat_abs_add_le (a b : ℤ) : nat_abs (a + b) ≤ nat_abs a + nat_abs b : begin have : ∀ (a b : ℕ), nat_abs (sub_nat_nat a (nat.succ b)) ≤ nat.succ (a + b), { refine (λ a b : ℕ, sub_nat_nat_elim a b.succ - (λ m n i, n = b.succ → nat_abs i ≤ (m + b).succ) _ _ rfl); - intros i n e, - { subst e, rw [add_comm _ i, add_assoc], + (λ m n i, n = b.succ → nat_abs i ≤ (m + b).succ) _ (λ i n e, _) rfl), + { rintro i n rfl, + rw [add_comm _ i, add_assoc], exact nat.le_add_right i (b.succ + b).succ }, { apply succ_le_succ, rw [← succ.inj e, ← add_assoc, add_comm], diff --git a/src/data/list/forall2.lean b/src/data/list/forall2.lean index e5b80d2279113..20b448701ff50 100644 --- a/src/data/list/forall2.lean +++ b/src/data/list/forall2.lean @@ -54,7 +54,7 @@ begin funext a b, apply propext, split, { intro h, induction h, {refl}, simp only [*]; split; refl }, - { intro h, subst h, exact forall₂_refl _ } + { rintro rfl, exact forall₂_refl _ } end @[simp, priority 900] lemma forall₂_nil_left_iff {l} : forall₂ r nil l ↔ l = nil := diff --git a/src/data/list/pairwise.lean b/src/data/list/pairwise.lean index ffe81a3dc1811..0007a381a5bf2 100644 --- a/src/data/list/pairwise.lean +++ b/src/data/list/pairwise.lean @@ -310,7 +310,7 @@ theorem pairwise.sublists' {R} : ∀ {l : list α}, pairwise R l → simp only [sublists'_cons, pairwise_append, pairwise_map, mem_sublists', mem_map, exists_imp_distrib, and_imp], refine ⟨H₂.sublists', H₂.sublists'.imp (λ l₁ l₂, lex.cons), _⟩, - intros l₁ sl₁ x l₂ sl₂ e, subst e, + rintro l₁ sl₁ x l₂ sl₂ rfl, cases l₁ with b l₁, {constructor}, exact lex.rel (H₁ _ $ sl₁.subset $ mem_cons_self _ _) end diff --git a/src/data/list/permutation.lean b/src/data/list/permutation.lean index 9ef8ea26c1b3f..982f019d7cae1 100644 --- a/src/data/list/permutation.lean +++ b/src/data/list/permutation.lean @@ -141,9 +141,9 @@ begin { simp {contextual := tt} }, rw [permutations_aux2_snd_cons, show (λ (x : list α), l ++ y :: x) = append (l ++ [y]), by funext; simp, mem_cons_iff, ih], split, - { rintro (e | ⟨l₁, l₂, l0, ye, _⟩), - { subst l', exact ⟨[], y::ys, by simp⟩ }, - { substs l' ys, exact ⟨y::l₁, l₂, l0, by simp⟩ } }, + { rintro (rfl | ⟨l₁, l₂, l0, rfl, rfl⟩), + { exact ⟨[], y::ys, by simp⟩ }, + { exact ⟨y::l₁, l₂, l0, by simp⟩ } }, { rintro ⟨_ | ⟨y', l₁⟩, l₂, l0, ye, rfl⟩, { simp [ye] }, { simp only [cons_append] at ye, rcases ye with ⟨rfl, rfl⟩, diff --git a/src/data/list/sort.lean b/src/data/list/sort.lean index 8e87cbeb8ce8b..4a5e7e1ab8070 100644 --- a/src/data/list/sort.lean +++ b/src/data/list/sort.lean @@ -61,7 +61,7 @@ begin { have : a ∈ l₂ := p.subset (mem_cons_self _ _), rcases mem_split this with ⟨u₂, v₂, rfl⟩, have p' := (perm_cons a).1 (p.trans perm_middle), - have := IH p' (s₂.sublist $ by simp), subst l₁, + obtain rfl := IH p' (s₂.sublist $ by simp), change a::u₂ ++ v₂ = u₂ ++ ([a] ++ v₂), rw ← append_assoc, congr, have : ∀ (x : α) (h : x ∈ u₂), x = a := λ x m, antisymm ((pairwise_append.1 s₂).2.2 _ m a (mem_cons_self _ _)) diff --git a/src/data/multiset/pi.lean b/src/data/multiset/pi.lean index 4adacb82958d4..13e166c86da7c 100644 --- a/src/data/multiset/pi.lean +++ b/src/data/multiset/pi.lean @@ -39,14 +39,12 @@ dif_neg h lemma pi.cons_swap {a a' : α} {b : δ a} {b' : δ a'} {m : multiset α} {f : Πa∈m, δ a} (h : a ≠ a') : pi.cons (a' ::ₘ m) a b (pi.cons m a' b' f) == pi.cons (a ::ₘ m) a' b' (pi.cons m a b f) := begin - apply hfunext, { refl }, intros a'' _ h, subst h, - apply hfunext, { rw [cons_swap] }, intros ha₁ ha₂ h, - by_cases h₁ : a'' = a, - simp [*, pi.cons_same, pi.cons_ne] at *, - { subst h₁, rw [pi.cons_same, pi.cons_same] }, - by_cases h₂ : a'' = a'; - simp [*, pi.cons_same, pi.cons_ne] at *; - subst h₂; rw [pi.cons_same, pi.cons_same] + apply hfunext rfl, + rintro a'' _ rfl, + refine hfunext (by rw [cons_swap]) (λ ha₁ ha₂ _, _), + rcases ne_or_eq a'' a with h₁ | rfl, + rcases eq_or_ne a'' a' with rfl | h₂, + all_goals { simp [*, pi.cons_same, pi.cons_ne] }, end /-- `pi m t` constructs the Cartesian product over `t` indexed by `m`. -/ diff --git a/src/data/nat/gcd.lean b/src/data/nat/gcd.lean index 9d229c8234497..9cedc4bc7a558 100644 --- a/src/data/nat/gcd.lean +++ b/src/data/nat/gcd.lean @@ -506,8 +506,8 @@ def prod_dvd_and_dvd_of_dvd_prod {m n k : ℕ} (H : k ∣ m * n) : begin cases h0 : (gcd k m), case nat.zero -{ have : k = 0 := eq_zero_of_gcd_eq_zero_left h0, subst this, - have : m = 0 := eq_zero_of_gcd_eq_zero_right h0, subst this, +{ obtain rfl : k = 0 := eq_zero_of_gcd_eq_zero_left h0, + obtain rfl : m = 0 := eq_zero_of_gcd_eq_zero_right h0, exact ⟨⟨⟨0, dvd_refl 0⟩, ⟨n, dvd_refl n⟩⟩, (zero_mul n).symm⟩ }, case nat.succ : tmp { have hpos : 0 < gcd k m := h0.symm ▸ nat.zero_lt_succ _; clear h0 tmp, diff --git a/src/data/nat/pow.lean b/src/data/nat/pow.lean index 622d772c432c5..d8201c1f32127 100644 --- a/src/data/nat/pow.lean +++ b/src/data/nat/pow.lean @@ -262,12 +262,11 @@ begin cases b, {exact absurd rfl h}, have : shiftl' tt m n + 1 = 1 := congr_arg (+1) s0, rw [shiftl'_tt_eq_mul_pow] at this, - have m0 := succ.inj (eq_one_of_dvd_one ⟨_, this.symm⟩), - subst m0, - simp at this, - have : n = 0 := nat.eq_zero_of_le_zero (le_of_not_gt $ λ hn, + obtain rfl := succ.inj (eq_one_of_dvd_one ⟨_, this.symm⟩), + rw one_mul at this, + obtain rfl : n = 0 := nat.eq_zero_of_le_zero (le_of_not_gt $ λ hn, ne_of_gt (pow_lt_pow_of_lt_right dec_trivial hn) this), - subst n, refl + refl end @[simp] theorem size_shiftl {m} (h : m ≠ 0) (n) : diff --git a/src/data/ordmap/ordset.lean b/src/data/ordmap/ordset.lean index a89840f61df0a..a19fea78f2afa 100644 --- a/src/data/ordmap/ordset.lean +++ b/src/data/ordmap/ordset.lean @@ -568,7 +568,7 @@ begin nat.le_zero_iff, add_eq_zero_iff] at this }, cases sr.2.2.2.1.size_eq_zero.1 this.1, cases sr.2.2.2.2.size_eq_zero.1 this.2, - have : rrs = 1 := sr.2.2.1, subst rrs, + obtain rfl : rrs = 1 := sr.2.2.1, rw [if_neg, if_pos, rotate_l, if_pos], {refl}, all_goals {exact dec_trivial} }, { have : size rll = 0 ∧ size rlr = 0, @@ -577,7 +577,7 @@ begin nat.le_zero_iff, add_eq_zero_iff] at this }, cases sr.2.1.2.1.size_eq_zero.1 this.1, cases sr.2.1.2.2.size_eq_zero.1 this.2, - have : rls = 1 := sr.2.1.1, subst rls, + obtain rfl : rls = 1 := sr.2.1.1, rw [if_neg, if_pos, rotate_l, if_neg], {refl}, all_goals {exact dec_trivial} }, { symmetry, rw [zero_add, if_neg, if_pos, rotate_l], @@ -598,7 +598,7 @@ begin nat.le_zero_iff, add_eq_zero_iff] at this }, cases sl.2.2.2.1.size_eq_zero.1 this.1, cases sl.2.2.2.2.size_eq_zero.1 this.2, - have : lrs = 1 := sl.2.2.1, subst lrs, + obtain rfl : lrs = 1 := sl.2.2.1, rw [if_neg, if_neg, if_pos, rotate_r, if_neg], {refl}, all_goals {exact dec_trivial} }, { have : size lll = 0 ∧ size llr = 0, @@ -607,7 +607,7 @@ begin nat.le_zero_iff, add_eq_zero_iff] at this }, cases sl.2.1.2.1.size_eq_zero.1 this.1, cases sl.2.1.2.2.size_eq_zero.1 this.2, - have : lls = 1 := sl.2.1.1, subst lls, + obtain rfl : lls = 1 := sl.2.1.1, rw [if_neg, if_neg, if_pos, rotate_r, if_pos], {refl}, all_goals {exact dec_trivial} }, { symmetry, rw [if_neg, if_neg, if_pos, rotate_r], diff --git a/src/data/pfunctor/univariate/M.lean b/src/data/pfunctor/univariate/M.lean index 7f0b29b916e58..cdcedad8b350e 100644 --- a/src/data/pfunctor/univariate/M.lean +++ b/src/data/pfunctor/univariate/M.lean @@ -384,23 +384,22 @@ inductive is_path : path F → M F → Prop is_path xs (f i) → is_path (⟨a,i⟩ :: xs) x -lemma is_path_cons {xs : path F} {a a'} {f : F.B a → M F} {i : F.B a'} - (h : is_path (⟨a',i⟩ :: xs) (M.mk ⟨a,f⟩)) : - a = a' := +lemma is_path_cons {xs : path F} {a a'} {f : F.B a → M F} {i : F.B a'} : + is_path (⟨a',i⟩ :: xs) (M.mk ⟨a,f⟩) → a = a' := begin - revert h, generalize h : (M.mk ⟨a,f⟩) = x, - intros h', cases h', subst x, - cases mk_inj ‹_›, refl, + generalize h : (M.mk ⟨a,f⟩) = x, + rintro (_ | ⟨_, _, _, _, _, rfl, _⟩), + cases mk_inj h, + refl end -lemma is_path_cons' {xs : path F} {a} {f : F.B a → M F} {i : F.B a} - (h : is_path (⟨a,i⟩ :: xs) (M.mk ⟨a,f⟩)) : - is_path xs (f i) := +lemma is_path_cons' {xs : path F} {a} {f : F.B a → M F} {i : F.B a} : + is_path (⟨a,i⟩ :: xs) (M.mk ⟨a,f⟩) → is_path xs (f i) := begin - revert h, generalize h : (M.mk ⟨a,f⟩) = x, - intros h', cases h', subst x, - have := mk_inj ‹_›, cases this, cases this, - assumption, + generalize h : (M.mk ⟨a,f⟩) = x, + rintro (_ | ⟨_, _, _, _, _, rfl, hp⟩), + cases mk_inj h, + exact hp end /-- follow a path through a value of `M F` and return the subtree @@ -555,20 +554,20 @@ begin intros h₀ hh, induction s₁ using pfunctor.M.cases_on' with a f, induction s₂ using pfunctor.M.cases_on' with a' f', - have : a = a' := bisim.head h₀, subst a', + obtain rfl : a = a' := bisim.head h₀, induction ps with i ps generalizing a f f', { existsi [rfl,a,f,f',rfl,rfl], apply bisim.tail h₀ }, cases i with a' i, - have : a = a', + obtain rfl : a = a', { cases hh; cases is_path_cons hh; refl }, - subst a', dsimp only [iselect] at ps_ih ⊢, + dsimp only [iselect] at ps_ih ⊢, have h₁ := bisim.tail h₀ i, induction h : (f i) using pfunctor.M.cases_on' with a₀ f₀, induction h' : (f' i) using pfunctor.M.cases_on' with a₁ f₁, simp only [h,h',isubtree_cons] at ps_ih ⊢, rw [h,h'] at h₁, - have : a₀ = a₁ := bisim.head h₁, subst a₁, + obtain rfl : a₀ = a₁ := bisim.head h₁, apply (ps_ih _ _ _ h₁), rw [← h,← h'], apply or_of_or_of_imp_of_imp hh is_path_cons' is_path_cons' end diff --git a/src/data/rat/basic.lean b/src/data/rat/basic.lean index fcfa62d8ed2be..892223b9477fe 100644 --- a/src/data/rat/basic.lean +++ b/src/data/rat/basic.lean @@ -126,13 +126,13 @@ int.dvd_nat_abs.1 $ int.coe_nat_dvd.2 $ nat.gcd_dvd_left (int.nat_abs a) b @[simp] theorem mk_eq_zero {a b : ℤ} (b0 : b ≠ 0) : a /. b = 0 ↔ a = 0 := begin - constructor; intro h; [skip, {subst a, simp}], + refine ⟨λ h, _, by { rintro rfl, simp }⟩, have : ∀ {a b}, mk_pnat a b = 0 → a = 0, - { intros a b e, cases b with b h, + { rintro a ⟨b, h⟩ e, injection e with e, apply int.eq_mul_of_div_eq_right gcd_abs_dvd_left e }, - cases b with b; simp [mk, mk_nat] at h, - { simp [mt (congr_arg int.of_nat) b0] at h, + cases b with b; simp only [mk, mk_nat, int.of_nat_eq_coe, dite_eq_left_iff] at h, + { simp only [mt (congr_arg int.of_nat) b0, not_false_iff, forall_true_left] at h, exact this h }, { apply neg_injective, simp [this h] } end @@ -430,7 +430,7 @@ by { rw [← mk_one_one, mk_eq_zero one_ne_zero], exact one_ne_zero } protected theorem mul_inv_cancel : a ≠ 0 → a * a⁻¹ = 1 := num_denom_cases_on' a $ λ n d h a0, -have n0 : n ≠ 0, from mt (by intro e; subst e; simp) a0, +have n0 : n ≠ 0, from mt (by { rintro rfl, simp }) a0, by simpa [h, n0, mul_comm] using @div_mk_div_cancel_left 1 1 _ n0 protected theorem inv_mul_cancel (h : a ≠ 0) : a⁻¹ * a = 1 := diff --git a/src/data/rbtree/insert.lean b/src/data/rbtree/insert.lean index f2ec9570eab08..9103dd71a7b32 100644 --- a/src/data/rbtree/insert.lean +++ b/src/data/rbtree/insert.lean @@ -755,11 +755,11 @@ def ins_rb_result : rbnode α → color → nat → Prop variables {lt : α → α → Prop} [decidable_rel lt] lemma of_get_color_eq_red {t : rbnode α} {c n} : get_color t = red → is_red_black t c n → c = red := -begin intros h₁ h₂, cases h₂; simp [get_color] at h₁; contradiction end +begin intros h₁ h₂, cases h₂; simp only [get_color] at h₁; contradiction end lemma of_get_color_ne_red {t : rbnode α} {c n} : get_color t ≠ red → is_red_black t c n → c = black := -begin intros h₁ h₂, cases h₂; simp [get_color] at h₁; contradiction end +begin intros h₁ h₂, cases h₂; simp only [get_color] at h₁; contradiction end variable (lt) @@ -772,21 +772,19 @@ begin { constructor; assumption }, { specialize ih h_rb_r, cases ih, constructor; assumption }, { specialize ih h_rb_l, - have := of_get_color_eq_red hr h_rb_l, subst h_c₁, - simp [ins_rb_result] at ih, + cases of_get_color_eq_red hr h_rb_l, apply balance1_node_rb; assumption }, { specialize ih h_rb_l, - have := of_get_color_ne_red hnr h_rb_l, subst h_c₁, - simp [ins_rb_result] at ih, cases ih, + cases of_get_color_ne_red hnr h_rb_l, + cases ih, constructor, constructor; assumption }, { constructor, constructor; assumption }, { specialize ih h_rb_r, - have := of_get_color_eq_red hr h_rb_r, subst h_c₂, - simp [ins_rb_result] at ih, + cases of_get_color_eq_red hr h_rb_r, apply balance2_node_rb; assumption }, { specialize ih h_rb_r, - have := of_get_color_ne_red hnr h_rb_r, subst h_c₂, - simp [ins_rb_result] at ih, cases ih, + cases of_get_color_ne_red hnr h_rb_r, + cases ih, constructor, constructor; assumption } end diff --git a/src/data/real/irrational.lean b/src/data/real/irrational.lean index a27fe29962c25..ce41461f9adef 100644 --- a/src/data/real/irrational.lean +++ b/src/data/real/irrational.lean @@ -53,8 +53,7 @@ begin have hdivn : ↑D ^ n ∣ N ^ n := dvd.intro_left m hxr, rw [← int.dvd_nat_abs, ← int.coe_nat_pow, int.coe_nat_dvd, int.nat_abs_pow, nat.pow_dvd_pow_iff hnpos] at hdivn, - have hD : D = 1 := by rw [← nat.gcd_eq_right hdivn, C.gcd_eq_one], - subst D, + obtain rfl : D = 1 := by rw [← nat.gcd_eq_right hdivn, C.gcd_eq_one], refine hv ⟨N, _⟩, rw [num_denom', int.coe_nat_one, mk_eq_div, int.cast_one, div_one, cast_coe_int] end diff --git a/src/data/set/basic.lean b/src/data/set/basic.lean index 54bc6b39782f2..66661fff7682b 100644 --- a/src/data/set/basic.lean +++ b/src/data/set/basic.lean @@ -1416,7 +1416,7 @@ theorem mem_compl_image (t : set α) (S : set (set α)) : t ∈ compl '' S ↔ tᶜ ∈ S := begin suffices : ∀ x, xᶜ = t ↔ tᶜ = x, { simp [this] }, - intro x, split; { intro e, subst e, simp } + intro x, split; { rintro rfl, simp } end /-- A variant of `image_id` -/ diff --git a/src/data/set/function.lean b/src/data/set/function.lean index 938fa8ed1b5ea..846ea1a7b647d 100644 --- a/src/data/set/function.lean +++ b/src/data/set/function.lean @@ -455,8 +455,7 @@ begin intros y hy, rcases h₁ hy.1 with ⟨x₁, hx₁, rfl⟩, rcases h₂ hy.2 with ⟨x₂, hx₂, heq⟩, - have : x₁ = x₂, from h (or.inl hx₁) (or.inr hx₂) heq.symm, - subst x₂, + obtain rfl : x₁ = x₂ := h (or.inl hx₁) (or.inr hx₂) heq.symm, exact mem_image_of_mem f ⟨hx₁, hx₂⟩ end diff --git a/src/data/sigma/basic.lean b/src/data/sigma/basic.lean index 8a6bdf33d0a16..0df3a86f44787 100644 --- a/src/data/sigma/basic.lean +++ b/src/data/sigma/basic.lean @@ -95,10 +95,9 @@ lemma function.injective.sigma_map {f₁ : α₁ → α₂} {f₂ : Πa, β₁ a function.injective (sigma.map f₁ f₂) | ⟨i, x⟩ ⟨j, y⟩ h := begin - have : i = j, from h₁ (sigma.mk.inj_iff.mp h).1, - subst j, - have : x = y, from h₂ i (eq_of_heq (sigma.mk.inj_iff.mp h).2), - subst y + obtain rfl : i = j, from h₁ (sigma.mk.inj_iff.mp h).1, + obtain rfl : x = y, from h₂ i (eq_of_heq (sigma.mk.inj_iff.mp h).2), + refl end lemma function.surjective.sigma_map {f₁ : α₁ → α₂} {f₂ : Πa, β₁ a → β₂ (f₁ a)} diff --git a/src/field_theory/adjoin.lean b/src/field_theory/adjoin.lean index 103a31c492135..58faf14ce24b0 100644 --- a/src/field_theory/adjoin.lean +++ b/src/field_theory/adjoin.lean @@ -653,8 +653,7 @@ instance : partial_order (lifts F E K) := le_antisymm := begin rintros ⟨x1, x2⟩ ⟨y1, y2⟩ ⟨hxy1, hxy2⟩ ⟨hyx1, hyx2⟩, - have : x1 = y1 := le_antisymm hxy1 hyx1, - subst this, + obtain rfl : x1 = y1 := le_antisymm hxy1 hyx1, congr, exact alg_hom.ext (λ s, hxy2 s s rfl), end } diff --git a/src/linear_algebra/affine_space/affine_map.lean b/src/linear_algebra/affine_space/affine_map.lean index 7190f5c99b37f..bb3fa4390f21f 100644 --- a/src/linear_algebra/affine_space/affine_map.lean +++ b/src/linear_algebra/affine_space/affine_map.lean @@ -117,8 +117,7 @@ by conv_rhs { rw [←vsub_vadd p1 p2, map_vadd, vadd_vsub] } begin rcases f with ⟨f, f_linear, f_add⟩, rcases g with ⟨g, g_linear, g_add⟩, - have : f = g := funext h, - subst g, + obtain rfl : f = g := funext h, congr' with v, cases (add_torsor.nonempty : nonempty P1) with p, apply vadd_right_cancel (f p), diff --git a/src/linear_algebra/affine_space/independent.lean b/src/linear_algebra/affine_space/independent.lean index 5a04e39cbb696..14e34c0e048f4 100644 --- a/src/linear_algebra/affine_space/independent.lean +++ b/src/linear_algebra/affine_space/independent.lean @@ -658,30 +658,22 @@ faces are given by the same subset of points. -/ {fs₁ fs₂ : finset (fin (n + 1))} {m₁ m₂ : ℕ} (h₁ : fs₁.card = m₁ + 1) (h₂ : fs₂.card = m₂ + 1) : fs₁.centroid k s.points = fs₂.centroid k s.points ↔ fs₁ = fs₂ := begin - split, - { intro h, - rw [finset.centroid_eq_affine_combination_fintype, - finset.centroid_eq_affine_combination_fintype] at h, - have ha := (affine_independent_iff_indicator_eq_of_affine_combination_eq k s.points).1 - s.independent _ _ _ _ (fs₁.sum_centroid_weights_indicator_eq_one_of_card_eq_add_one k h₁) - (fs₂.sum_centroid_weights_indicator_eq_one_of_card_eq_add_one k h₂) h, - simp_rw [finset.coe_univ, set.indicator_univ, function.funext_iff, - finset.centroid_weights_indicator_def, finset.centroid_weights, h₁, h₂] at ha, - ext i, - replace ha := ha i, - split, - all_goals - { intro hi, - by_contradiction hni, - simp [hi, hni] at ha, - norm_cast at ha } }, - { intro h, - have hm : m₁ = m₂, - { subst h, - simpa [h₁] using h₂ }, - subst hm, - congr, - exact h } + refine ⟨λ h, _, congr_arg _⟩, + rw [finset.centroid_eq_affine_combination_fintype, + finset.centroid_eq_affine_combination_fintype] at h, + have ha := (affine_independent_iff_indicator_eq_of_affine_combination_eq k s.points).1 + s.independent _ _ _ _ (fs₁.sum_centroid_weights_indicator_eq_one_of_card_eq_add_one k h₁) + (fs₂.sum_centroid_weights_indicator_eq_one_of_card_eq_add_one k h₂) h, + simp_rw [finset.coe_univ, set.indicator_univ, function.funext_iff, + finset.centroid_weights_indicator_def, finset.centroid_weights, h₁, h₂] at ha, + ext i, + specialize ha i, + have key : ∀ n : ℕ, (n : k) + 1 ≠ 0 := λ n h, by norm_cast at h, + -- we should be able to golf this to `refine ⟨λ hi, decidable.by_contradiction (λ hni, _), ...⟩`, + -- but for some unknown reason it doesn't work. + split; intro hi; by_contra hni, + { simpa [hni, hi, key] using ha }, + { simpa [hni, hi, key] using ha.symm } end /-- Over a characteristic-zero division ring, the centroids of two diff --git a/src/linear_algebra/dimension.lean b/src/linear_algebra/dimension.lean index d058093538b46..773ec53060c5c 100644 --- a/src/linear_algebra/dimension.lean +++ b/src/linear_algebra/dimension.lean @@ -1105,8 +1105,7 @@ dim_add_dim_split (of_le le_sup_left) (of_le le_sup_right) (of_le inf_le_left) ( begin ext ⟨x, hx⟩, refl end begin rintros ⟨b₁, hb₁⟩ ⟨b₂, hb₂⟩ eq, - have : b₁ = b₂ := congr_arg subtype.val eq, - subst this, + obtain rfl : b₁ = b₂ := congr_arg subtype.val eq, exact ⟨⟨b₁, hb₁, hb₂⟩, rfl, rfl⟩ end diff --git a/src/linear_algebra/free_module/pid.lean b/src/linear_algebra/free_module/pid.lean index 39cd1c498b6ae..5f1726359916b 100644 --- a/src/linear_algebra/free_module/pid.lean +++ b/src/linear_algebra/free_module/pid.lean @@ -321,8 +321,7 @@ lemma submodule.basis_of_pid_bot {ι : Type*} [fintype ι] (b : basis ι R M) : begin obtain ⟨n, b'⟩ := submodule.basis_of_pid b ⊥, let e : fin n ≃ fin 0 := b'.index_equiv (basis.empty _ : basis (fin 0) R (⊥ : submodule R M)), - have : n = 0 := by simpa using fintype.card_eq.mpr ⟨e⟩, - subst this, + obtain rfl : n = 0 := by simpa using fintype.card_eq.mpr ⟨e⟩, exact sigma.eq rfl (basis.eq_of_apply_eq $ fin_zero_elim) end diff --git a/src/linear_algebra/linear_pmap.lean b/src/linear_algebra/linear_pmap.lean index 1219c832a44db..51eeab7cd1ddb 100644 --- a/src/linear_algebra/linear_pmap.lean +++ b/src/linear_algebra/linear_pmap.lean @@ -153,8 +153,8 @@ begin rcases g with ⟨g_dom, g⟩, change f_dom = g_dom at heq, subst g_dom, - have : f = g, from linear_map.ext (λ x, hle.2 rfl), - subst g + obtain rfl : f = g := linear_map.ext (λ x, hle.2 rfl), + refl, end /-- Given two partial linear maps `f`, `g`, the set of points `x` such that diff --git a/src/logic/relator.lean b/src/logic/relator.lean index 225cb3b08f536..30aa8a5230e81 100644 --- a/src/logic/relator.lean +++ b/src/logic/relator.lean @@ -92,9 +92,6 @@ lemma rel_iff : ((↔) ⇒ (↔) ⇒ (↔)) (↔) (↔) := assume a b h₁ c d h₂, iff_congr h₁ h₂ lemma rel_eq {r : α → β → Prop} (hr : bi_unique r) : (r ⇒ r ⇒ (↔)) (=) (=) := -assume a b h₁ c d h₂, -iff.intro - begin intro h, subst h, exact hr.right h₁ h₂ end - begin intro h, subst h, exact hr.left h₁ h₂ end +λ a b h₁ c d h₂, ⟨λ h, hr.right h₁ $ h.symm ▸ h₂, λ h, hr.left h₁ $ h.symm ▸ h₂⟩ end relator diff --git a/src/order/complete_lattice.lean b/src/order/complete_lattice.lean index 12910501ad2e5..5ab8354a8a17f 100644 --- a/src/order/complete_lattice.lean +++ b/src/order/complete_lattice.lean @@ -428,7 +428,7 @@ by { convert h1.supr_comp g, exact (funext h2).symm } @[congr] lemma supr_congr_Prop {p q : Prop} {f₁ : p → α} {f₂ : q → α} (pq : p ↔ q) (f : ∀ x, f₁ (pq.mpr x) = f₂ x) : supr f₁ = supr f₂ := begin - have := propext pq, subst this, + obtain rfl := propext pq, congr' with x, apply f end diff --git a/src/order/order_iso_nat.lean b/src/order/order_iso_nat.lean index 0e9b9f56ec8fd..2fd69aadeb8e7 100644 --- a/src/order/order_iso_nat.lean +++ b/src/order/order_iso_nat.lean @@ -45,7 +45,8 @@ theorem well_founded_iff_no_descending_seq : ⟨λ ⟨h⟩, ⟨λ ⟨f, o⟩, suffices ∀ a, acc r a → ∀ n, a ≠ f n, from this (f 0) (h _) 0 rfl, λ a ac, begin - induction ac with a _ IH, intros n h, subst a, + induction ac with a _ IH, + rintro n rfl, exact IH (f (n+1)) (o.2 (nat.lt_succ_self _)) _ rfl end⟩, λ E, ⟨λ a, classical.by_contradiction $ λ na, diff --git a/src/ring_theory/algebra_tower.lean b/src/ring_theory/algebra_tower.lean index 31c0841cb6f67..08200852bcf18 100644 --- a/src/ring_theory/algebra_tower.lean +++ b/src/ring_theory/algebra_tower.lean @@ -318,8 +318,7 @@ def alg_hom_equiv_sigma : right_inv := begin rintros ⟨⟨f, _, _, _, _, _⟩, g, _, _, _, _, hg⟩, - have : f = λ x, g (algebra_map B C x) := by { ext, exact (hg x).symm }, - subst this, + obtain rfl : f = λ x, g (algebra_map B C x) := by { ext, exact (hg x).symm }, refl, end } diff --git a/src/ring_theory/artinian.lean b/src/ring_theory/artinian.lean index 5f153c27ece09..3add0c5b5d499 100644 --- a/src/ring_theory/artinian.lean +++ b/src/ring_theory/artinian.lean @@ -170,7 +170,7 @@ begin (well_founded_submodule_lt R M)).elim' _), have f : ℕ ↪ s, from @infinite.nat_embedding s ⟨λ f, hf ⟨f⟩⟩, have : ∀ n, (coe ∘ f) '' {m | n ≤ m} ⊆ s, - { rintros n x ⟨y, hy₁, hy₂⟩, subst hy₂, exact (f y).2 }, + { rintros n x ⟨y, hy₁, rfl⟩, exact (f y).2 }, have : ∀ a b : ℕ, a ≤ b ↔ span R ((coe ∘ f) '' {m | b ≤ m}) ≤ span R ((coe ∘ f) '' {m | a ≤ m}), { assume a b, diff --git a/src/ring_theory/discrete_valuation_ring.lean b/src/ring_theory/discrete_valuation_ring.lean index 4e4685eb833e1..90f2457dfa66f 100644 --- a/src/ring_theory/discrete_valuation_ring.lean +++ b/src/ring_theory/discrete_valuation_ring.lean @@ -371,8 +371,8 @@ begin have := multiset.card_eq_card_of_rel (unique_factorization_monoid.factors_unique _ _ key), { simpa only [multiset.card_repeat] }, all_goals - { intros x hx, replace hx := multiset.eq_of_mem_repeat hx, - unfreezingI { subst hx, assumption } }, + { intros x hx, + unfreezingI { obtain rfl := multiset.eq_of_mem_repeat hx, assumption } }, end lemma unit_mul_pow_congr_unit {ϖ : R} (hirr : irreducible ϖ) (u v : Rˣ) (m n : ℕ) diff --git a/src/ring_theory/noetherian.lean b/src/ring_theory/noetherian.lean index c0055a5c30835..d38413b7d0e6d 100644 --- a/src/ring_theory/noetherian.lean +++ b/src/ring_theory/noetherian.lean @@ -545,7 +545,7 @@ begin (well_founded_submodule_gt R M)).elim' _), have f : ℕ ↪ s, from @infinite.nat_embedding s ⟨λ f, hf ⟨f⟩⟩, have : ∀ n, (coe ∘ f) '' {m | m ≤ n} ⊆ s, - { rintros n x ⟨y, hy₁, hy₂⟩, subst hy₂, exact (f y).2 }, + { rintros n x ⟨y, hy₁, rfl⟩, exact (f y).2 }, have : ∀ a b : ℕ, a ≤ b ↔ span R ((coe ∘ f) '' {m | m ≤ a}) ≤ span R ((coe ∘ f) '' {m | m ≤ b}), { assume a b, diff --git a/src/ring_theory/power_series/basic.lean b/src/ring_theory/power_series/basic.lean index 71cdb8daf2b9e..e160605a16c38 100644 --- a/src/ring_theory/power_series/basic.lean +++ b/src/ring_theory/power_series/basic.lean @@ -514,7 +514,7 @@ begin { subst m, simp }, { symmetry, rw mv_polynomial.coeff_one, exact if_neg (ne.symm H'), }, { symmetry, rw mv_polynomial.coeff_one, refine if_neg _, - intro H', apply H, subst m, exact ne.bot_lt hnn, } + rintro rfl, apply H, exact ne.bot_lt hnn, } end @[simp] lemma trunc_C (hnn : n ≠ 0) (a : R) : trunc R n (C σ R a) = mv_polynomial.C a := @@ -1309,7 +1309,7 @@ begin { subst m, rw [if_pos rfl] }, { symmetry, exact if_neg (ne.elim (ne.symm H')) }, { symmetry, refine if_neg _, - intro H', apply H, subst m, exact nat.zero_lt_succ _ } + rintro rfl, apply H, exact nat.zero_lt_succ _ } end @[simp] lemma trunc_C (n) (a : R) : trunc (n + 1) (C R a) = polynomial.C a := @@ -1443,7 +1443,8 @@ begin suffices : m < i, { have : m + n < i + j := add_lt_add_of_lt_of_le this hj, exfalso, exact ne_of_lt this hij.symm }, - contrapose! hne, have : i = m := le_antisymm hne hi, subst i, clear hi hne, + contrapose! hne, + obtain rfl := le_antisymm hi hne, simpa [ne.def, prod.mk.inj_iff] using (add_right_inj m).mp hij }, { contrapose!, intro h, rw finset.nat.mem_antidiagonal } end diff --git a/src/set_theory/ordinal/basic.lean b/src/set_theory/ordinal/basic.lean index e339684e5b056..b5eed328bf5b4 100644 --- a/src/set_theory/ordinal/basic.lean +++ b/src/set_theory/ordinal/basic.lean @@ -785,9 +785,8 @@ end @[simp] theorem out_empty_iff_eq_zero {o : ordinal} : is_empty o.out.α ↔ o = 0 := begin refine ⟨@eq_zero_of_out_empty o, λ h, ⟨λ i, _⟩⟩, - have := typein_lt_self i, - subst h, - exact not_lt_of_le (ordinal.zero_le _) this + subst o, + exact (ordinal.zero_le _).not_lt (typein_lt_self i) end @[simp] theorem out_nonempty_iff_ne_zero {o : ordinal} : nonempty o.out.α ↔ o ≠ 0 := diff --git a/src/set_theory/ordinal/notation.lean b/src/set_theory/ordinal/notation.lean index c1bd6c3c109dd..ffe759818abeb 100644 --- a/src/set_theory/ordinal/notation.lean +++ b/src/set_theory/ordinal/notation.lean @@ -120,13 +120,14 @@ theorem eq_of_cmp_eq : ∀ {o₁ o₂}, cmp o₁ o₂ = ordering.eq → o₁ = o | (oadd e n a) 0 h := by injection h | 0 (oadd e n a) h := by injection h | o₁@(oadd e₁ n₁ a₁) o₂@(oadd e₂ n₂ a₂) h := begin - revert h, simp [cmp], + revert h, simp only [cmp], cases h₁ : cmp e₁ e₂; intro h; try {cases h}, - have := eq_of_cmp_eq h₁, subst e₂, + obtain rfl := eq_of_cmp_eq h₁, revert h, cases h₂ : _root_.cmp (n₁:ℕ) n₂; intro h; try {cases h}, - have := eq_of_cmp_eq h, subst a₂, + obtain rfl := eq_of_cmp_eq h, rw [_root_.cmp, cmp_using_eq_eq] at h₂, - have := subtype.eq (eq_of_incomp h₂), subst n₂, simp + obtain rfl := subtype.eq (eq_of_incomp h₂), + simp end theorem zero_lt_one : (0 : onote) < 1 := @@ -264,7 +265,7 @@ theorem cmp_compares : ∀ (a b : onote) [NF a] [NF b], (cmp a b).compares a b case ordering.gt { rw cmp_using_eq_gt at nh, exact oadd_lt_oadd_2 h₂ nh }, rw cmp_using_eq_eq at nh, - have := subtype.eq (eq_of_incomp nh), subst n₂, + obtain rfl := subtype.eq (eq_of_incomp nh), have IHa := @cmp_compares _ _ h₁.snd h₂.snd, cases cmp a₁ a₂, case ordering.lt { exact oadd_lt_oadd_3 IHa }, diff --git a/src/set_theory/zfc.lean b/src/set_theory/zfc.lean index a96863bde7ca5..66acff2680d8a 100644 --- a/src/set_theory/zfc.lean +++ b/src/set_theory/zfc.lean @@ -587,31 +587,27 @@ begin { rintro (rfl|rfl); [left, right]; assumption } end -theorem pair_inj {x y x' y' : Set.{u}} (H : pair x y = pair x' y') : x = x' ∧ y = y' := begin +theorem pair_inj {x y x' y' : Set.{u}} (H : pair x y = pair x' y') : x = x' ∧ y = y' := +begin have ae := ext_iff.2 H, - simp [pair] at ae, - have : x = x', + simp only [pair, mem_pair] at ae, + obtain rfl : x = x', { cases (ae {x}).1 (by simp) with h h, { exact singleton_inj h }, { have m : x' ∈ ({x} : Set), - { rw h, simp }, - simp at m, simp [*] } }, - subst x', - have he : y = x → y = y', - { intro yx, subst y, + { simp [h] }, + rw mem_singleton.mp m } }, + have he : x = y → y = y', + { rintro rfl, cases (ae {x, y'}).2 (by simp only [eq_self_iff_true, or_true]) with xy'x xy'xx, { rw [eq_comm, ←mem_singleton, ←xy'x, mem_pair], exact or.inr rfl }, - { have yxx := (ext_iff.2 xy'xx y').1 (by simp), - simp at yxx, subst y' } }, - have xyxy' := (ae {x, y}).1 (by simp), - cases xyxy' with xyx xyy', - { have yx := (ext_iff.2 xyx y).1 (by simp), - simp at yx, simp [he yx] }, - { have yxy' := (ext_iff.2 xyy' y).1 (by simp), - simp at yxy', - cases yxy' with yx yy', - { simp [he yx] }, + { simpa [eq_comm] using (ext_iff.2 xy'xx y').1 (by simp) } }, + obtain xyx | xyy' := (ae {x, y}).1 (by simp), + { obtain rfl := mem_singleton.mp ((ext_iff.2 xyx y).1 $ by simp), + simp [he rfl] }, + { obtain rfl | yy' := mem_pair.mp ((ext_iff.2 xyy' y).1 $ by simp), + { simp [he rfl] }, { simp [yy'] } } end diff --git a/src/topology/homotopy/path.lean b/src/topology/homotopy/path.lean index 5ad4d21dd8bb8..9e0a73787fb85 100644 --- a/src/topology/homotopy/path.lean +++ b/src/topology/homotopy/path.lean @@ -311,8 +311,8 @@ lemma map_lift (P₀ : path x₀ x₁) (f : C(X, Y)) : lemma hpath_hext {p₁ : path x₀ x₁} {p₂ : path x₂ x₃} (hp : ∀ t, p₁ t = p₂ t) : ⟦p₁⟧ == ⟦p₂⟧ := begin - have : x₀ = x₂ := by { convert hp 0; simp, }, subst this, - have : x₁ = x₃ := by { convert hp 1; simp, }, subst this, + obtain rfl : x₀ = x₂ := by { convert hp 0; simp, }, + obtain rfl : x₁ = x₃ := by { convert hp 1; simp, }, rw heq_iff_eq, congr, ext t, exact hp t, end diff --git a/src/topology/sets/opens.lean b/src/topology/sets/opens.lean index dad87ef147880..8c33856bc9a4d 100644 --- a/src/topology/sets/opens.lean +++ b/src/topology/sets/opens.lean @@ -150,7 +150,7 @@ begin refine ⟨V, H₁, _⟩, cases V, dsimp at H₂, subst H₂, exact hsV }, { refine is_topological_basis_of_open_of_nhds _ _, - { rintros sU ⟨U, ⟨H₁, H₂⟩⟩, subst H₂, exact U.property }, + { rintros sU ⟨U, ⟨H₁, rfl⟩⟩, exact U.property }, { intros x sU hx hsU, rcases @h (⟨sU, hsU⟩ : opens α) x hx with ⟨V, hV, H⟩, exact ⟨V, ⟨V, hV, rfl⟩, H⟩ } } diff --git a/src/topology/uniform_space/compact_separated.lean b/src/topology/uniform_space/compact_separated.lean index ce1563adc95e4..3682251092133 100644 --- a/src/topology/uniform_space/compact_separated.lean +++ b/src/topology/uniform_space/compact_separated.lean @@ -52,8 +52,7 @@ begin cluster_point_of_compact F, have : cluster_pt (x, y) (𝓤 α) := hx.of_inf_left, - have hxy : x = y := eq_of_uniformity_inf_nhds this, - subst hxy, + obtain rfl : x = y := eq_of_uniformity_inf_nhds this, have : cluster_pt (x, x) (𝓟 Vᶜ) := hx.of_inf_right, have : (x, x) ∉ interior V, From dced133600d6368fd52fc21f4fc0940eed3a96a5 Mon Sep 17 00:00:00 2001 From: tb65536 Date: Fri, 22 Apr 2022 01:34:15 +0000 Subject: [PATCH 158/373] feat(group_theory/group_action/basic): Right multiplication satisfies the `quotient_action` axiom (#13475) This PR adds a `quotient_action` instance for right multiplication. --- src/group_theory/group_action/basic.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/group_theory/group_action/basic.lean b/src/group_theory/group_action/basic.lean index 4c125527b417b..9fe4dd48e4658 100644 --- a/src/group_theory/group_action/basic.lean +++ b/src/group_theory/group_action/basic.lean @@ -331,6 +331,10 @@ attribute [to_additive add_action.quotient_action] mul_action.quotient_action ⟨λ b c _ _, by rwa [smul_def, smul_def, smul_eq_mul_unop, smul_eq_mul_unop, mul_inv_rev, ←mul_assoc, mem_normalizer_iff'.mp b.prop, mul_assoc, mul_inv_cancel_left]⟩ +@[to_additive] instance right_quotient_action' [hH : H.normal] : quotient_action αᵐᵒᵖ H := +⟨λ _ _ _ _, by rwa [smul_eq_mul_unop, smul_eq_mul_unop, mul_inv_rev, mul_assoc, hH.mem_comm_iff, + mul_assoc, mul_inv_cancel_right]⟩ + @[to_additive] instance quotient [quotient_action β H] : mul_action β (α ⧸ H) := { smul := λ b, quotient.map' ((•) b) (λ a a' h, quotient_action.inv_mul_mem b h), one_smul := λ q, quotient.induction_on' q (λ a, congr_arg quotient.mk' (one_smul β a)), From 77236cd233234c60ba164aaaeb6752102444caf5 Mon Sep 17 00:00:00 2001 From: Johan Commelin Date: Fri, 22 Apr 2022 01:34:16 +0000 Subject: [PATCH 159/373] refactor(category_theory): make has_zero_object a Prop (#13517) --- src/algebra/category/Group/basic.lean | 18 +--- src/algebra/category/Group/zero.lean | 24 +++-- src/algebra/category/Module/basic.lean | 25 +++-- src/algebra/homology/augment.lean | 2 + src/algebra/homology/homological_complex.lean | 16 ++-- src/algebra/homology/single.lean | 12 ++- .../normed/group/SemiNormedGroup.lean | 45 +++++---- src/category_theory/abelian/basic.lean | 4 +- .../abelian/right_derived.lean | 3 +- src/category_theory/differential_object.lean | 6 +- src/category_theory/functor/left_derived.lean | 3 +- src/category_theory/graded_object.lean | 4 +- .../limits/shapes/biproducts.lean | 7 +- .../limits/shapes/zero_morphisms.lean | 49 +++++----- .../limits/shapes/zero_objects.lean | 94 ++++++++++++++----- 15 files changed, 192 insertions(+), 120 deletions(-) diff --git a/src/algebra/category/Group/basic.lean b/src/algebra/category/Group/basic.lean index 2517abb858b27..6791adc480959 100644 --- a/src/algebra/category/Group/basic.lean +++ b/src/algebra/category/Group/basic.lean @@ -59,15 +59,10 @@ instance (G : Group) : group G := G.str @[simp, to_additive] lemma coe_of (R : Type u) [group R] : (Group.of R : Type u) = R := rfl @[to_additive] -instance : has_one Group := ⟨Group.of punit⟩ +instance : inhabited Group := ⟨Group.of punit⟩ @[to_additive] -instance : inhabited Group := ⟨1⟩ - -@[to_additive] -instance one.unique : unique (1 : Group) := -{ default := 1, - uniq := λ a, begin cases a, refl, end } +instance of_unique (G : Type*) [group G] [i : unique G] : unique (Group.of G) := i @[simp, to_additive] lemma one_apply (G H : Group) (g : G) : (1 : G ⟶ H) g = 1 := rfl @@ -123,14 +118,11 @@ instance comm_group_instance (G : CommGroup) : comm_group G := G.str @[simp, to_additive] lemma coe_of (R : Type u) [comm_group R] : (CommGroup.of R : Type u) = R := rfl -@[to_additive] instance : has_one CommGroup := ⟨CommGroup.of punit⟩ - -@[to_additive] instance : inhabited CommGroup := ⟨1⟩ +@[to_additive] +instance : inhabited CommGroup := ⟨CommGroup.of punit⟩ @[to_additive] -instance one.unique : unique (1 : CommGroup) := -{ default := 1, - uniq := λ a, begin cases a, refl, end } +instance of_unique (G : Type*) [comm_group G] [i : unique G] : unique (CommGroup.of G) := i @[simp, to_additive] lemma one_apply (G H : CommGroup) (g : G) : (1 : G ⟶ H) g = 1 := rfl diff --git a/src/algebra/category/Group/zero.lean b/src/algebra/category/Group/zero.lean index 47e5e3ec3d166..b613d33acfaad 100644 --- a/src/algebra/category/Group/zero.lean +++ b/src/algebra/category/Group/zero.lean @@ -20,20 +20,32 @@ universe u namespace Group +@[to_additive] lemma is_zero_of_subsingleton (G : Group) [subsingleton G] : + is_zero G := +begin + refine ⟨λ X, ⟨⟨⟨1⟩, λ f, _⟩⟩, λ X, ⟨⟨⟨1⟩, λ f, _⟩⟩⟩, + { ext, have : x = 1 := subsingleton.elim _ _, rw [this, map_one, map_one], }, + { ext, apply subsingleton.elim } +end + @[to_additive AddGroup.has_zero_object] instance : has_zero_object Group := -{ zero := 1, - unique_to := λ X, ⟨⟨1⟩, λ f, by { ext, cases x, erw monoid_hom.map_one, refl, }⟩, - unique_from := λ X, ⟨⟨1⟩, λ f, by ext⟩, } +⟨⟨of punit, is_zero_of_subsingleton _⟩⟩ end Group namespace CommGroup +@[to_additive] lemma is_zero_of_subsingleton (G : CommGroup) [subsingleton G] : + is_zero G := +begin + refine ⟨λ X, ⟨⟨⟨1⟩, λ f, _⟩⟩, λ X, ⟨⟨⟨1⟩, λ f, _⟩⟩⟩, + { ext, have : x = 1 := subsingleton.elim _ _, rw [this, map_one, map_one], }, + { ext, apply subsingleton.elim } +end + @[to_additive AddCommGroup.has_zero_object] instance : has_zero_object CommGroup := -{ zero := 1, - unique_to := λ X, ⟨⟨1⟩, λ f, by { ext, cases x, erw monoid_hom.map_one, refl, }⟩, - unique_from := λ X, ⟨⟨1⟩, λ f, by ext⟩, } +⟨⟨of punit, is_zero_of_subsingleton _⟩⟩ end CommGroup diff --git a/src/algebra/category/Module/basic.lean b/src/algebra/category/Module/basic.lean index 464cbd5d08b87..4d93857824f82 100644 --- a/src/algebra/category/Module/basic.lean +++ b/src/algebra/category/Module/basic.lean @@ -116,8 +116,10 @@ def of_hom {R : Type u} [ring R] {X Y : Type v} [add_comm_group X] [module R X] {X Y : Type v} [add_comm_group X] [module R X] [add_comm_group Y] [module R Y] (f : X →ₗ[R] Y) (x : X) : of_hom f x = f x := rfl -instance : has_zero (Module R) := ⟨of R punit⟩ -instance : inhabited (Module R) := ⟨0⟩ +instance : inhabited (Module R) := ⟨of R punit⟩ + +instance of_unique {X : Type v} [add_comm_group X] [module R X] [i : unique X] : + unique (of R X) := i @[simp] lemma coe_of (X : Type u) [add_comm_group X] [module R X] : (of R X : Type u) = X := rfl @@ -130,19 +132,16 @@ module. -/ def of_self_iso (M : Module R) : Module.of R M ≅ M := { hom := 𝟙 M, inv := 𝟙 M } -instance : subsingleton (of R punit) := -by { rw coe_of R punit, apply_instance } +lemma is_zero_of_subsingleton (M : Module R) [subsingleton M] : + is_zero M := +begin + refine ⟨λ X, ⟨⟨⟨0⟩, λ f, _⟩⟩, λ X, ⟨⟨⟨0⟩, λ f, _⟩⟩⟩, + { ext, have : x = 0 := subsingleton.elim _ _, rw [this, map_zero, map_zero], }, + { ext, apply subsingleton.elim } +end instance : has_zero_object (Module.{v} R) := -{ zero := 0, - unique_to := λ X, - { default := (0 : punit →ₗ[R] X), - uniq := λ _, linear_map.ext $ λ x, - have h : x = 0, from dec_trivial, - by simp only [h, linear_map.map_zero]}, - unique_from := λ X, - { default := (0 : X →ₗ[R] punit), - uniq := λ _, linear_map.ext $ λ x, dec_trivial } } +⟨⟨of R punit, is_zero_of_subsingleton _⟩⟩ variables {R} {M N U : Module.{v} R} diff --git a/src/algebra/homology/augment.lean b/src/algebra/homology/augment.lean index 1b26ec1f02249..6904f0708305b 100644 --- a/src/algebra/homology/augment.lean +++ b/src/algebra/homology/augment.lean @@ -10,6 +10,8 @@ import tactic.linarith # Augmentation and truncation of `ℕ`-indexed (co)chain complexes. -/ +noncomputable theory + open category_theory open category_theory.limits open homological_complex diff --git a/src/algebra/homology/homological_complex.lean b/src/algebra/homology/homological_complex.lean index e9e84c05e9290..7c4851e060cc3 100644 --- a/src/algebra/homology/homological_complex.lean +++ b/src/algebra/homology/homological_complex.lean @@ -210,14 +210,18 @@ instance : has_zero_morphisms (homological_complex V c) := open_locale zero_object +/-- The zero complex -/ +noncomputable def zero [has_zero_object V] : homological_complex V c := +{ X := λ i, 0, d := λ i j, 0 } + +lemma is_zero_zero [has_zero_object V] : is_zero (zero : homological_complex V c) := +by { refine ⟨λ X, ⟨⟨⟨0⟩, λ f, _⟩⟩, λ X, ⟨⟨⟨0⟩, λ f, _⟩⟩⟩; ext, } + instance [has_zero_object V] : has_zero_object (homological_complex V c) := -{ zero := - { X := λ i, 0, - d := λ i j, 0 }, - unique_from := λ C, ⟨⟨0⟩, λ f, by ext⟩, - unique_to := λ C, ⟨⟨0⟩, λ f, by ext⟩ } +⟨⟨zero, is_zero_zero⟩⟩ -instance [has_zero_object V] : inhabited (homological_complex V c) := ⟨0⟩ +noncomputable +instance [has_zero_object V] : inhabited (homological_complex V c) := ⟨zero⟩ lemma congr_hom {C D : homological_complex V c} {f g : C ⟶ D} (w : f = g) (i : ι) : f.f i = g.f i := congr_fun (congr_arg hom.f w) i diff --git a/src/algebra/homology/single.lean b/src/algebra/homology/single.lean index 22ced8ccea2d9..82ff2975d8030 100644 --- a/src/algebra/homology/single.lean +++ b/src/algebra/homology/single.lean @@ -21,6 +21,8 @@ they are equivalent to `{ f : C.X 0 ⟶ X // C.d 1 0 ≫ f = 0 }`. an augmented exact complex of projectives.) -/ +noncomputable theory + open category_theory open category_theory.limits @@ -164,8 +166,9 @@ is the same as the zero functor. -/ noncomputable def homology_functor_succ_single₀ (n : ℕ) : single₀ V ⋙ homology_functor V _ (n+1) ≅ 0 := -nat_iso.of_components (λ X, homology.congr _ _ (by simp) (by simp) ≪≫ homology_zero_zero) - (λ X Y f, by ext) +nat_iso.of_components (λ X, homology.congr _ _ (by simp) (by simp) ≪≫ + homology_zero_zero ≪≫ (functor.zero_obj _).iso_zero.symm) + (λ X Y f, by { exact (functor.zero_obj _).eq_of_tgt _ _ }) end @@ -277,8 +280,9 @@ is the same as the zero functor. -/ noncomputable def homology_functor_succ_single₀ (n : ℕ) : single₀ V ⋙ homology_functor V _ (n+1) ≅ 0 := -nat_iso.of_components (λ X, homology.congr _ _ (by simp) (by simp) ≪≫ homology_zero_zero) - (λ X Y f, by ext) +nat_iso.of_components (λ X, homology.congr _ _ (by simp) (by simp) ≪≫ + homology_zero_zero ≪≫ (functor.zero_obj _).iso_zero.symm) + (λ X Y f, by { exact (functor.zero_obj _).eq_of_tgt _ _ }) end diff --git a/src/analysis/normed/group/SemiNormedGroup.lean b/src/analysis/normed/group/SemiNormedGroup.lean index 46a5a9d9646c5..ed81f24be1cd3 100644 --- a/src/analysis/normed/group/SemiNormedGroup.lean +++ b/src/analysis/normed/group/SemiNormedGroup.lean @@ -42,21 +42,25 @@ instance (M : SemiNormedGroup) : semi_normed_group M := M.str @[simp] lemma coe_comp {M N K : SemiNormedGroup} (f : M ⟶ N) (g : N ⟶ K) : ((f ≫ g) : M → K) = g ∘ f := rfl -instance : has_zero SemiNormedGroup := ⟨of punit⟩ -instance : inhabited SemiNormedGroup := ⟨0⟩ +instance : inhabited SemiNormedGroup := ⟨of punit⟩ + +instance of_unique (V : Type u) [semi_normed_group V] [i : unique V] : + unique (SemiNormedGroup.of V) := i instance : limits.has_zero_morphisms.{u (u+1)} SemiNormedGroup := {} @[simp] lemma zero_apply {V W : SemiNormedGroup} (x : V) : (0 : V ⟶ W) x = 0 := rfl +lemma is_zero_of_subsingleton (V : SemiNormedGroup) [subsingleton V] : + limits.is_zero V := +begin + refine ⟨λ X, ⟨⟨⟨0⟩, λ f, _⟩⟩, λ X, ⟨⟨⟨0⟩, λ f, _⟩⟩⟩, + { ext, have : x = 0 := subsingleton.elim _ _, simp only [this, normed_group_hom.map_zero], }, + { ext, apply subsingleton.elim } +end + instance has_zero_object : limits.has_zero_object SemiNormedGroup.{u} := -{ zero := 0, - unique_to := λ X, - { default := 0, - uniq := λ a, by { ext ⟨⟩, exact a.map_zero, }, }, - unique_from := λ X, - { default := 0, - uniq := λ f, by ext } } +⟨⟨of punit, is_zero_of_subsingleton _⟩⟩ lemma iso_isometry_of_norm_noninc {V W : SemiNormedGroup} (i : V ≅ W) (h1 : i.hom.norm_noninc) (h2 : i.inv.norm_noninc) : @@ -132,8 +136,10 @@ rfl @[simp] lemma coe_comp' {M N K : SemiNormedGroup₁} (f : M ⟶ N) (g : N ⟶ K) : ((f ≫ g) : normed_group_hom M K) = (↑g : normed_group_hom N K).comp ↑f := rfl -instance : has_zero SemiNormedGroup₁ := ⟨of punit⟩ -instance : inhabited SemiNormedGroup₁ := ⟨0⟩ +instance : inhabited SemiNormedGroup₁ := ⟨of punit⟩ + +instance of_unique (V : Type u) [semi_normed_group V] [i : unique V] : + unique (SemiNormedGroup₁.of V) := i instance : limits.has_zero_morphisms.{u (u+1)} SemiNormedGroup₁ := { has_zero := λ X Y, { zero := ⟨0, normed_group_hom.norm_noninc.zero⟩, }, @@ -142,14 +148,17 @@ instance : limits.has_zero_morphisms.{u (u+1)} SemiNormedGroup₁ := @[simp] lemma zero_apply {V W : SemiNormedGroup₁} (x : V) : (0 : V ⟶ W) x = 0 := rfl +lemma is_zero_of_subsingleton (V : SemiNormedGroup₁) [subsingleton V] : + limits.is_zero V := +begin + refine ⟨λ X, ⟨⟨⟨0⟩, λ f, _⟩⟩, λ X, ⟨⟨⟨0⟩, λ f, _⟩⟩⟩, + { ext, have : x = 0 := subsingleton.elim _ _, simp only [this, normed_group_hom.map_zero], + apply f.1.map_zero, }, + { ext, apply subsingleton.elim } +end + instance has_zero_object : limits.has_zero_object SemiNormedGroup₁.{u} := -{ zero := 0, - unique_to := λ X, - { default := 0, - uniq := λ a, by { ext ⟨⟩, exact a.1.map_zero, }, }, - unique_from := λ X, - { default := 0, - uniq := λ f, by ext } } +⟨⟨of punit, is_zero_of_subsingleton _⟩⟩ lemma iso_isometry {V W : SemiNormedGroup₁} (i : V ≅ W) : isometry i.hom := diff --git a/src/category_theory/abelian/basic.lean b/src/category_theory/abelian/basic.lean index ad4d7f56e058e..3e9216d0c35ea 100644 --- a/src/category_theory/abelian/basic.lean +++ b/src/category_theory/abelian/basic.lean @@ -190,7 +190,7 @@ def normal_mono_category : normal_mono_category C := is_limit := begin haveI : limits.has_images C := has_images, haveI : has_equalizers C := preadditive.has_equalizers_of_has_kernels, - letI : has_zero_object C := has_zero_object_of_has_finite_biproducts _, + haveI : has_zero_object C := limits.has_zero_object_of_has_finite_biproducts _, have aux : _ := _, refine is_limit_aux _ (λ A, limit.lift _ _ ≫ inv (image_mono_factorisation f).e) aux _, { intros A g hg, @@ -215,7 +215,7 @@ def normal_epi_category : normal_epi_category C := is_colimit := begin haveI : limits.has_images C := has_images, haveI : has_equalizers C := preadditive.has_equalizers_of_has_kernels, - letI : has_zero_object C := has_zero_object_of_has_finite_biproducts _, + haveI : has_zero_object C := limits.has_zero_object_of_has_finite_biproducts _, have aux : _ := _, refine is_colimit_aux _ (λ A, inv (image_mono_factorisation f).m ≫ diff --git a/src/category_theory/abelian/right_derived.lean b/src/category_theory/abelian/right_derived.lean index 24c18cbc7d49a..40e2d7a4ce326 100644 --- a/src/category_theory/abelian/right_derived.lean +++ b/src/category_theory/abelian/right_derived.lean @@ -89,7 +89,8 @@ def functor.right_derived_obj_injective_succ (F : C ⥤ D) [F.additive] (n : ℕ (F.right_derived (n+1)).obj X ≅ 0 := F.right_derived_obj_iso (n+1) (InjectiveResolution.self X) ≪≫ (homology_functor _ _ _).map_iso ((cochain_complex.single₀_map_homological_complex F).app X) ≪≫ - (cochain_complex.homology_functor_succ_single₀ D n).app (F.obj X) + (cochain_complex.homology_functor_succ_single₀ D n).app (F.obj X) ≪≫ + (functor.zero_obj _).iso_zero /-- We can compute a right derived functor on a morphism using a descent of that morphism to a cochain map between chosen injective resolutions. diff --git a/src/category_theory/differential_object.lean b/src/category_theory/differential_object.lean index 51fd5fe0428d8..3ea1d59ac7a49 100644 --- a/src/category_theory/differential_object.lean +++ b/src/category_theory/differential_object.lean @@ -184,11 +184,7 @@ variables [has_zero_object C] [has_zero_morphisms C] [has_shift C ℤ] open_locale zero_object instance has_zero_object : has_zero_object (differential_object C) := -{ zero := - { X := (0 : C), - d := 0, }, - unique_to := λ X, ⟨⟨{ f := 0 }⟩, λ f, (by ext)⟩, - unique_from := λ X, ⟨⟨{ f := 0 }⟩, λ f, (by ext)⟩, } +by { refine ⟨⟨⟨0, 0⟩, λ X, ⟨⟨⟨⟨0⟩⟩, λ f, _⟩⟩, λ X, ⟨⟨⟨⟨0⟩⟩, λ f, _⟩⟩⟩⟩; ext, } end differential_object diff --git a/src/category_theory/functor/left_derived.lean b/src/category_theory/functor/left_derived.lean index 993ad9472f831..26a2216d37c93 100644 --- a/src/category_theory/functor/left_derived.lean +++ b/src/category_theory/functor/left_derived.lean @@ -90,7 +90,8 @@ def functor.left_derived_obj_projective_succ (F : C ⥤ D) [F.additive] (n : ℕ (F.left_derived (n+1)).obj X ≅ 0 := F.left_derived_obj_iso (n+1) (ProjectiveResolution.self X) ≪≫ (homology_functor _ _ _).map_iso ((chain_complex.single₀_map_homological_complex F).app X) ≪≫ - (chain_complex.homology_functor_succ_single₀ D n).app (F.obj X) + (chain_complex.homology_functor_succ_single₀ D n).app (F.obj X) ≪≫ + (functor.zero_obj _).iso_zero /-- We can compute a left derived functor on a morphism using a lift of that morphism diff --git a/src/category_theory/graded_object.lean b/src/category_theory/graded_object.lean index f6cd0e02615f7..394d339fe27a8 100644 --- a/src/category_theory/graded_object.lean +++ b/src/category_theory/graded_object.lean @@ -137,9 +137,7 @@ open_locale zero_object instance has_zero_object [has_zero_object C] [has_zero_morphisms C] (β : Type w) : has_zero_object.{(max w v)} (graded_object β C) := -{ zero := λ b, (0 : C), - unique_to := λ X, ⟨⟨λ b, 0⟩, λ f, (by ext)⟩, - unique_from := λ X, ⟨⟨λ b, 0⟩, λ f, (by ext)⟩, } +by { refine ⟨⟨λ b, 0, λ X, ⟨⟨⟨λ b, 0⟩, λ f, _⟩⟩, λ X, ⟨⟨⟨λ b, 0⟩, λ f, _⟩⟩⟩⟩; ext, } end end graded_object diff --git a/src/category_theory/limits/shapes/biproducts.lean b/src/category_theory/limits/shapes/biproducts.lean index deba88d9fedfe..7a7350aa82694 100644 --- a/src/category_theory/limits/shapes/biproducts.lean +++ b/src/category_theory/limits/shapes/biproducts.lean @@ -594,10 +594,9 @@ section variables (C) /-- A category with finite biproducts has a zero object. -/ -def has_zero_object_of_has_finite_biproducts [has_finite_biproducts C] : has_zero_object C := -{ zero := biproduct pempty.elim, - unique_to := λ X, ⟨⟨0⟩, by tidy⟩, - unique_from := λ X, ⟨⟨0⟩, by tidy⟩, } +@[priority 100] -- see Note [lower instance priority] +instance has_zero_object_of_has_finite_biproducts [has_finite_biproducts C] : has_zero_object C := +by { refine ⟨⟨biproduct pempty.elim, λ X, ⟨⟨⟨0⟩, _⟩⟩, λ X, ⟨⟨⟨0⟩, _⟩⟩⟩⟩, tidy, } end diff --git a/src/category_theory/limits/shapes/zero_morphisms.lean b/src/category_theory/limits/shapes/zero_morphisms.lean index d2c95656aef36..a3d1ac5a5a589 100644 --- a/src/category_theory/limits/shapes/zero_morphisms.lean +++ b/src/category_theory/limits/shapes/zero_morphisms.lean @@ -27,6 +27,7 @@ zero object provides zero morphisms, as the unique morphisms factoring through t noncomputable theory universes v u +universes v' u' open category_theory open category_theory.category @@ -34,6 +35,7 @@ open category_theory.category namespace category_theory.limits variables (C : Type u) [category.{v} C] +variables (D : Type u') [category.{v'} D] /-- A category "has zero morphisms" if there is a designated "zero morphism" in each morphism space, and compositions of zero morphisms with anything give the zero morphism. -/ @@ -120,8 +122,6 @@ lemma nonzero_image_of_nonzero {X Y : C} {f : X ⟶ Y} [has_image f] (w : f ≠ end section -universes v' u' -variables (D : Type u') [category.{v'} D] variables [has_zero_morphisms D] @@ -200,18 +200,27 @@ end has_zero_morphisms open_locale zero_object -instance {B : Type*} [category B] [has_zero_morphisms C] : has_zero_object (B ⥤ C) := -{ zero := { obj := λ X, 0, map := λ X Y f, 0, }, - unique_to := λ F, ⟨⟨{ app := λ X, 0, }⟩, by tidy⟩, - unique_from := λ F, ⟨⟨{ app := λ X, 0, }⟩, by tidy⟩ } - -@[simp] lemma functor.zero_obj {B : Type*} [category B] [has_zero_morphisms C] (X : B) : - (0 : B ⥤ C).obj X = 0 := rfl -@[simp] lemma functor.zero_map {B : Type*} [category B] [has_zero_morphisms C] - {X Y : B} (f : X ⟶ Y) : (0 : B ⥤ C).map f = 0 := rfl +instance {B : Type*} [category B] : has_zero_object (B ⥤ C) := +(((category_theory.functor.const B).obj (0 : C)).is_zero $ λ X, is_zero_zero _).has_zero_object end has_zero_object +open_locale zero_object + +variables {D} + +@[simp] lemma is_zero.map [has_zero_object D] [has_zero_morphisms D] {F : C ⥤ D} (hF : is_zero F) + {X Y : C} (f : X ⟶ Y) : F.map f = 0 := +(hF.obj _).eq_of_src _ _ + +@[simp] lemma _root_.category_theory.functor.zero_obj [has_zero_object D] + (X : C) : is_zero ((0 : C ⥤ D).obj X) := +(is_zero_zero _).obj _ + +@[simp] lemma _root_.category_theory.zero_map [has_zero_object D] [has_zero_morphisms D] + {X Y : C} (f : X ⟶ Y) : (0 : C ⥤ D).map f = 0 := +(is_zero_zero _).map _ + section variables [has_zero_object C] [has_zero_morphisms C] open_locale zero_object @@ -362,28 +371,26 @@ def is_iso_zero_self_equiv_iso_zero (X : C) : is_iso (0 : X ⟶ X) ≃ (X ≅ 0) end is_iso /-- If there are zero morphisms, any initial object is a zero object. -/ -def has_zero_object_of_has_initial_object +lemma has_zero_object_of_has_initial_object [has_zero_morphisms C] [has_initial C] : has_zero_object C := -{ zero := ⊥_ C, - unique_to := λ X, ⟨⟨0⟩, by tidy⟩, - unique_from := λ X, ⟨⟨0⟩, λ f, +begin + refine ⟨⟨⊥_ C, λ X, ⟨⟨⟨0⟩, by tidy⟩⟩, λ X, ⟨⟨⟨0⟩, λ f, _⟩⟩⟩⟩, calc f = f ≫ 𝟙 _ : (category.comp_id _).symm ... = f ≫ 0 : by congr ... = 0 : has_zero_morphisms.comp_zero _ _ - ⟩ } +end /-- If there are zero morphisms, any terminal object is a zero object. -/ -def has_zero_object_of_has_terminal_object +lemma has_zero_object_of_has_terminal_object [has_zero_morphisms C] [has_terminal C] : has_zero_object C := -{ zero := ⊤_ C, - unique_from := λ X, ⟨⟨0⟩, by tidy⟩, - unique_to := λ X, ⟨⟨0⟩, λ f, +begin + refine ⟨⟨⊤_ C, λ X, ⟨⟨⟨0⟩, λ f, _⟩⟩, λ X, ⟨⟨⟨0⟩, by tidy⟩⟩⟩⟩, calc f = 𝟙 _ ≫ f : (category.id_comp _).symm ... = 0 ≫ f : by congr ... = 0 : zero_comp - ⟩ } +end section image diff --git a/src/category_theory/limits/shapes/zero_objects.lean b/src/category_theory/limits/shapes/zero_objects.lean index 0e6096842ebc9..a7ab330b88932 100644 --- a/src/category_theory/limits/shapes/zero_objects.lean +++ b/src/category_theory/limits/shapes/zero_objects.lean @@ -26,11 +26,13 @@ universes v u v' u' open category_theory open category_theory.category -namespace category_theory.limits - variables {C : Type u} [category.{v} C] variables {D : Type u'} [category.{v'} D] +namespace category_theory + +namespace limits + /-- An object `X` in a category is a *zero object* if for every object `Y` there is a unique morphism `to : X → Y` and a unique morphism `from : Y → X`. @@ -101,25 +103,38 @@ end end is_zero +end limits + +open category_theory.limits + lemma iso.is_zero_iff {X Y : C} (e : X ≅ Y) : is_zero X ↔ is_zero Y := ⟨λ h, h.of_iso e.symm, λ h, h.of_iso e⟩ +lemma functor.is_zero (F : C ⥤ D) (hF : ∀ X, is_zero (F.obj X)) : + is_zero F := +begin + split; intros G; refine ⟨⟨⟨_⟩, _⟩⟩, + { refine { app := λ X, (hF _).to _, naturality' := _ }, + intros, exact (hF _).eq_of_src _ _ }, + { intro f, ext, apply (hF _).eq_of_src _ _ }, + { refine { app := λ X, (hF _).from _, naturality' := _ }, + intros, exact (hF _).eq_of_tgt _ _ }, + { intro f, ext, apply (hF _).eq_of_tgt _ _ }, +end + +namespace limits + variables (C) /-- A category "has a zero object" if it has an object which is both initial and terminal. -/ -class has_zero_object := -(zero : C) -(unique_to : Π X : C, unique (zero ⟶ X)) -(unique_from : Π X : C, unique (X ⟶ zero)) +class has_zero_object : Prop := +(zero : ∃ X : C, is_zero X) instance has_zero_object_punit : has_zero_object (discrete punit) := -{ zero := punit.star, - unique_to := by tidy, - unique_from := by tidy, } +{ zero := ⟨punit.star, by tidy, by tidy⟩, } - -namespace has_zero_object +section variables [has_zero_object C] @@ -127,22 +142,48 @@ variables [has_zero_object C] Construct a `has_zero C` for a category with a zero object. This can not be a global instance as it will trigger for every `has_zero C` typeclass search. -/ -protected def has_zero : has_zero C := -{ zero := has_zero_object.zero } +protected def has_zero_object.has_zero : has_zero C := +{ zero := has_zero_object.zero.some } localized "attribute [instance] category_theory.limits.has_zero_object.has_zero" in zero_object -localized "attribute [instance] category_theory.limits.has_zero_object.unique_to" in zero_object -localized "attribute [instance] category_theory.limits.has_zero_object.unique_from" in zero_object lemma is_zero_zero : is_zero (0 : C) := -{ unique_to := λ Y, ⟨has_zero_object.unique_to Y⟩, - unique_from := λ Y, ⟨has_zero_object.unique_from Y⟩ } +has_zero_object.zero.some_spec + +end + +open_locale zero_object + +variables {C} + +lemma is_zero.has_zero_object {X : C} (hX : is_zero X) : has_zero_object C := ⟨⟨X, hX⟩⟩ /-- Every zero object is isomorphic to *the* zero object. -/ -def is_zero.iso_zero {X : C} (hX : is_zero X) : X ≅ 0 := +def is_zero.iso_zero [has_zero_object C] {X : C} (hX : is_zero X) : X ≅ 0 := hX.iso (is_zero_zero C) -variables {C} +lemma is_zero.obj [has_zero_object D] {F : C ⥤ D} (hF : is_zero F) (X : C) : + is_zero (F.obj X) := +begin + let G : C ⥤ D := (category_theory.functor.const C).obj 0, + have hG : is_zero G := functor.is_zero _ (λ X, is_zero_zero _), + let e : F ≅ G := hF.iso hG, + exact (is_zero_zero _).of_iso (e.app X), +end + +namespace has_zero_object +variables [has_zero_object C] + +/-- There is a unique morphism from the zero object to any object `X`. -/ +protected def unique_to (X : C) : unique (0 ⟶ X) := +((is_zero_zero C).unique_to X).some + +/-- There is a unique morphism from any object `X` to the zero object. -/ +protected def unique_from (X : C) : unique (X ⟶ 0) := +((is_zero_zero C).unique_from X).some + +localized "attribute [instance] category_theory.limits.has_zero_object.unique_to" in zero_object +localized "attribute [instance] category_theory.limits.has_zero_object.unique_from" in zero_object @[ext] lemma to_zero_ext {X : C} (f g : X ⟶ 0) : f = g := @@ -162,11 +203,11 @@ instance {X : C} (f : X ⟶ 0) : epi f := /-- A zero object is in particular initial. -/ def zero_is_initial : is_initial (0 : C) := -is_initial.of_unique 0 +(is_zero_zero C).is_initial /-- A zero object is in particular terminal. -/ def zero_is_terminal : is_terminal (0 : C) := -is_terminal.of_unique 0 +(is_zero_zero C).is_terminal /-- A zero object is in particular initial. -/ @[priority 10] @@ -198,8 +239,15 @@ zero_is_terminal.unique_up_to_iso terminal_is_terminal instance has_strict_initial : initial_mono_class C := initial_mono_class.of_is_initial zero_is_initial (λ X, category_theory.mono _) +end has_zero_object + +end limits + +open category_theory.limits open_locale zero_object -end has_zero_object +lemma functor.is_zero_iff [has_zero_object D] (F : C ⥤ D) : + is_zero F ↔ ∀ X, is_zero (F.obj X) := +⟨λ hF X, hF.obj X, functor.is_zero _⟩ -end category_theory.limits +end category_theory From 1da12b57494f434be3711d03e93064686ba0f59a Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Fri, 22 Apr 2022 01:34:17 +0000 Subject: [PATCH 160/373] fix(analysis/normed_space/basic): allow the zero ring to be a normed algebra (#13544) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This replaces `norm_algebra_map_eq : ∀ x : 𝕜, ∥algebra_map 𝕜 𝕜' x∥ = ∥x∥` with `norm_smul_le : ∀ (r : 𝕜) (x : 𝕜'), ∥r • x∥ ≤ ∥r∥ * ∥x∥` in `normed_algebra`. With this change, `normed_algebra` means nothing more than "a normed module that is also an algebra", which seems to be the only notion actually used in mathlib anyway. In practice, this change really just removes any constraints on `∥1∥`. The old meaning of `[normed_algebra R A]` is now achieved with `[normed_algebra R A] [norm_one_class A]`. As a result, lemmas like `normed_algebra.norm_one_class` and `normed_algebra.nontrivial` have been removed, as they no longer make sense now that the two typeclasses are entirely orthogonal. Notably this means that the following `normed_algebra` instances hold more generally than before: * `continuous_linear_map.to_normed_algebra` * `pi.normed_algebra` * `bounded_continuous_function.normed_algebra` * `continuous_map.normed_algebra` * Instances not yet in mathlib: * Matrices under the `L1-L_inf` norm are a normed algebra even if the matrix is empty * Matrices under the frobenius norm are a normed algebra (note `∥(1 : matrix n n 𝕜')∥ = \sqrt (fintype.card n)` with that norm) This last one is the original motivation for this PR; otherwise every lemma about a matrix exponential has to case on whether the matrices are empty. It is possible that some of the `[norm_one_class A]`s added in `spectrum.lean` are unnecessary; however, the assumptions are no stronger than they were before, and I'm not interested in trying to generalize them as part of this PR. [Zulip](https://leanprover.zulipchat.com/#narrow/stream/116395-maths/topic/Is.20the.20zero.20algebra.20normed.3F/near/279515954) --- src/analysis/complex/basic.lean | 12 +- src/analysis/normed/normed_field.lean | 6 +- src/analysis/normed_space/basic.lean | 118 ++++++++---------- src/analysis/normed_space/is_R_or_C.lean | 2 +- src/analysis/normed_space/operator_norm.lean | 64 +++++----- src/analysis/normed_space/spectrum.lean | 25 ++-- src/analysis/normed_space/star/spectrum.lean | 5 +- src/analysis/quaternion.lean | 4 +- .../cyclotomic/discriminant.lean | 2 +- .../cyclotomic/primitive_roots.lean | 10 +- src/ring_theory/norm.lean | 2 +- src/ring_theory/polynomial/eisenstein.lean | 7 +- src/topology/continuous_function/bounded.lean | 9 +- src/topology/continuous_function/compact.lean | 4 +- 14 files changed, 133 insertions(+), 137 deletions(-) diff --git a/src/analysis/complex/basic.lean b/src/analysis/complex/basic.lean index 98e96f07a2f78..378408840be86 100644 --- a/src/analysis/complex/basic.lean +++ b/src/analysis/complex/basic.lean @@ -37,6 +37,8 @@ open_locale complex_conjugate instance : has_norm ℂ := ⟨abs⟩ +@[simp] lemma norm_eq_abs (z : ℂ) : ∥z∥ = abs z := rfl + instance : normed_group ℂ := normed_group.of_core ℂ { norm_eq_zero_iff := λ z, abs_eq_zero, @@ -50,10 +52,14 @@ instance : normed_field ℂ := .. complex.field } instance : nondiscrete_normed_field ℂ := -{ non_trivial := ⟨2, by simp [norm]; norm_num⟩ } +{ non_trivial := ⟨2, by simp; norm_num⟩ } instance {R : Type*} [normed_field R] [normed_algebra R ℝ] : normed_algebra R ℂ := -{ norm_algebra_map_eq := λ x, (abs_of_real $ algebra_map R ℝ x).trans (norm_algebra_map_eq ℝ x), +{ norm_smul_le := λ r x, begin + rw [norm_eq_abs, norm_eq_abs, ←algebra_map_smul ℝ r x, algebra.smul_def, abs_mul, + ←norm_algebra_map' ℝ r, coe_algebra_map, abs_of_real], + refl, + end, to_algebra := complex.algebra } /-- The module structure from `module.complex_to_real` is a normed space. -/ @@ -62,8 +68,6 @@ instance _root_.normed_space.complex_to_real {E : Type*} [normed_group E] [norme normed_space ℝ E := normed_space.restrict_scalars ℝ ℂ E -@[simp] lemma norm_eq_abs (z : ℂ) : ∥z∥ = abs z := rfl - lemma dist_eq (z w : ℂ) : dist z w = abs (z - w) := rfl lemma dist_self_conj (z : ℂ) : dist z (conj z) = 2 * |z.im| := diff --git a/src/analysis/normed/normed_field.lean b/src/analysis/normed/normed_field.lean index 5b624a897991a..2247519ba7780 100644 --- a/src/analysis/normed/normed_field.lean +++ b/src/analysis/normed/normed_field.lean @@ -111,6 +111,10 @@ attribute [simp] norm_one @[simp] lemma nnnorm_one [semi_normed_group α] [has_one α] [norm_one_class α] : ∥(1 : α)∥₊ = 1 := nnreal.eq norm_one +lemma norm_one_class.nontrivial (α : Type*) [semi_normed_group α] [has_one α] [norm_one_class α] : + nontrivial α := +nontrivial_of_ne 0 1 $ ne_of_apply_ne norm $ by simp + @[priority 100] -- see Note [lower instance priority] instance semi_normed_comm_ring.to_comm_ring [β : semi_normed_comm_ring α] : comm_ring α := { ..β } @@ -331,7 +335,7 @@ variables [normed_ring α] lemma units.norm_pos [nontrivial α] (x : αˣ) : 0 < ∥(x:α)∥ := norm_pos_iff.mpr (units.ne_zero x) -lemma units.nnorm_pos [nontrivial α] (x : αˣ) : 0 < ∥(x:α)∥₊ := +lemma units.nnnorm_pos [nontrivial α] (x : αˣ) : 0 < ∥(x:α)∥₊ := x.norm_pos /-- Normed ring structure on the product of two normed rings, using the sup norm. -/ diff --git a/src/analysis/normed_space/basic.lean b/src/analysis/normed_space/basic.lean index 2c50fa293e94b..35fffc9a63514 100644 --- a/src/analysis/normed_space/basic.lean +++ b/src/analysis/normed_space/basic.lean @@ -338,52 +338,16 @@ end normed_space_nondiscrete section normed_algebra -/-- A normed algebra `𝕜'` over `𝕜` is an algebra endowed with a norm for which the -embedding of `𝕜` in `𝕜'` is an isometry. -/ +/-- A normed algebra `𝕜'` over `𝕜` is normed module that is also an algebra. -/ class normed_algebra (𝕜 : Type*) (𝕜' : Type*) [normed_field 𝕜] [semi_normed_ring 𝕜'] extends algebra 𝕜 𝕜' := -(norm_algebra_map_eq : ∀x:𝕜, ∥algebra_map 𝕜 𝕜' x∥ = ∥x∥) +(norm_smul_le : ∀ (r : 𝕜) (x : 𝕜'), ∥r • x∥ ≤ ∥r∥ * ∥x∥) -@[simp] lemma norm_algebra_map_eq {𝕜 : Type*} (𝕜' : Type*) [normed_field 𝕜] [semi_normed_ring 𝕜'] - [h : normed_algebra 𝕜 𝕜'] (x : 𝕜) : ∥algebra_map 𝕜 𝕜' x∥ = ∥x∥ := -normed_algebra.norm_algebra_map_eq _ - -@[simp] lemma nnorm_algebra_map_eq {𝕜 : Type*} (𝕜' : Type*) [normed_field 𝕜] [semi_normed_ring 𝕜'] - [h : normed_algebra 𝕜 𝕜'] (x : 𝕜) : ∥algebra_map 𝕜 𝕜' x∥₊ = ∥x∥₊ := -subtype.ext $ normed_algebra.norm_algebra_map_eq _ - -/-- In a normed algebra, the inclusion of the base field in the extended field is an isometry. -/ -lemma algebra_map_isometry (𝕜 : Type*) (𝕜' : Type*) [normed_field 𝕜] [semi_normed_ring 𝕜'] - [normed_algebra 𝕜 𝕜'] : isometry (algebra_map 𝕜 𝕜') := -begin - refine isometry_emetric_iff_metric.2 (λx y, _), - rw [dist_eq_norm, dist_eq_norm, ← ring_hom.map_sub, norm_algebra_map_eq], -end - -variables (𝕜 : Type*) (𝕜' : Type*) [normed_field 𝕜] - -/-- The inclusion of the base field in a normed algebra as a continuous linear map. -/ -@[simps] -def algebra_map_clm [semi_normed_ring 𝕜'] [normed_algebra 𝕜 𝕜'] : 𝕜 →L[𝕜] 𝕜' := -{ to_fun := algebra_map 𝕜 𝕜', - map_add' := (algebra_map 𝕜 𝕜').map_add, - map_smul' := λ r x, by rw [algebra.id.smul_eq_mul, map_mul, ring_hom.id_apply, algebra.smul_def], - cont := (algebra_map_isometry 𝕜 𝕜').continuous } - -lemma algebra_map_clm_coe [semi_normed_ring 𝕜'] [normed_algebra 𝕜 𝕜'] : - (algebra_map_clm 𝕜 𝕜' : 𝕜 → 𝕜') = (algebra_map 𝕜 𝕜' : 𝕜 → 𝕜') := rfl - -lemma algebra_map_clm_to_linear_map [semi_normed_ring 𝕜'] [normed_algebra 𝕜 𝕜'] : - (algebra_map_clm 𝕜 𝕜').to_linear_map = algebra.linear_map 𝕜 𝕜' := rfl +variables {𝕜 : Type*} (𝕜' : Type*) [normed_field 𝕜] [semi_normed_ring 𝕜'] [normed_algebra 𝕜 𝕜'] @[priority 100] -instance normed_algebra.to_normed_space [semi_normed_ring 𝕜'] [h : normed_algebra 𝕜 𝕜'] : - normed_space 𝕜 𝕜' := -{ norm_smul_le := λ s x, calc - ∥s • x∥ = ∥((algebra_map 𝕜 𝕜') s) * x∥ : by { rw h.smul_def', refl } - ... ≤ ∥algebra_map 𝕜 𝕜' s∥ * ∥x∥ : semi_normed_ring.norm_mul _ _ - ... = ∥s∥ * ∥x∥ : by rw norm_algebra_map_eq, - ..h } +instance normed_algebra.to_normed_space : normed_space 𝕜 𝕜' := +{ norm_smul_le := normed_algebra.norm_smul_le } /-- While this may appear identical to `normed_algebra.to_normed_space`, it contains an implicit argument involving `normed_ring.to_semi_normed_ring` that typeclass inference has trouble inferring. @@ -398,30 +362,55 @@ example See `normed_space.to_module'` for a similar situation. -/ @[priority 100] -instance normed_algebra.to_normed_space' [normed_ring 𝕜'] [normed_algebra 𝕜 𝕜'] : +instance normed_algebra.to_normed_space' {𝕜'} [normed_ring 𝕜'] [normed_algebra 𝕜 𝕜'] : normed_space 𝕜 𝕜' := by apply_instance -instance normed_algebra.id : normed_algebra 𝕜 𝕜 := -{ norm_algebra_map_eq := by simp, - .. algebra.id 𝕜} +lemma norm_algebra_map (x : 𝕜) : ∥algebra_map 𝕜 𝕜' x∥ = ∥x∥ * ∥(1 : 𝕜')∥ := +begin + rw algebra.algebra_map_eq_smul_one, + exact norm_smul _ _, +end -variables (𝕜') [semi_normed_ring 𝕜'] [normed_algebra 𝕜 𝕜'] -include 𝕜 +lemma nnnorm_algebra_map (x : 𝕜) : ∥algebra_map 𝕜 𝕜' x∥₊ = ∥x∥₊ * ∥(1 : 𝕜')∥₊ := +subtype.ext $ norm_algebra_map 𝕜' x -lemma normed_algebra.norm_one : ∥(1:𝕜')∥ = 1 := -by simpa using (norm_algebra_map_eq 𝕜' (1:𝕜)) +@[simp] lemma norm_algebra_map' [norm_one_class 𝕜'] (x : 𝕜) : ∥algebra_map 𝕜 𝕜' x∥ = ∥x∥ := +by rw [norm_algebra_map, norm_one, mul_one] -lemma normed_algebra.norm_one_class : norm_one_class 𝕜' := -⟨normed_algebra.norm_one 𝕜 𝕜'⟩ +@[simp] lemma nnnorm_algebra_map' [norm_one_class 𝕜'] (x : 𝕜) : ∥algebra_map 𝕜 𝕜' x∥₊ = ∥x∥₊ := +subtype.ext $ norm_algebra_map' _ _ -lemma normed_algebra.zero_ne_one : (0:𝕜') ≠ 1 := +variables (𝕜 𝕜') + +/-- In a normed algebra, the inclusion of the base field in the extended field is an isometry. -/ +lemma algebra_map_isometry [norm_one_class 𝕜'] : isometry (algebra_map 𝕜 𝕜') := begin - refine (ne_zero_of_norm_ne_zero _).symm, - rw normed_algebra.norm_one 𝕜 𝕜', norm_num, + refine isometry_emetric_iff_metric.2 (λx y, _), + rw [dist_eq_norm, dist_eq_norm, ← ring_hom.map_sub, norm_algebra_map'], end -lemma normed_algebra.nontrivial : nontrivial 𝕜' := -⟨⟨0, 1, normed_algebra.zero_ne_one 𝕜 𝕜'⟩⟩ +/-- The inclusion of the base field in a normed algebra as a continuous linear map. -/ +@[simps] +def algebra_map_clm : 𝕜 →L[𝕜] 𝕜' := +{ to_fun := algebra_map 𝕜 𝕜', + map_add' := (algebra_map 𝕜 𝕜').map_add, + map_smul' := λ r x, by rw [algebra.id.smul_eq_mul, map_mul, ring_hom.id_apply, algebra.smul_def], + cont := + have lipschitz_with ∥(1 : 𝕜')∥₊ (algebra_map 𝕜 𝕜') := λ x y, begin + rw [edist_eq_coe_nnnorm_sub, edist_eq_coe_nnnorm_sub, ←map_sub, ←ennreal.coe_mul, + ennreal.coe_le_coe, mul_comm], + exact (nnnorm_algebra_map _ _).le, + end, this.continuous } + +lemma algebra_map_clm_coe : + (algebra_map_clm 𝕜 𝕜' : 𝕜 → 𝕜') = (algebra_map 𝕜 𝕜' : 𝕜 → 𝕜') := rfl + +lemma algebra_map_clm_to_linear_map : + (algebra_map_clm 𝕜 𝕜').to_linear_map = algebra.linear_map 𝕜 𝕜' := rfl + +instance normed_algebra.id : normed_algebra 𝕜 𝕜 := +{ .. normed_field.to_normed_space, + .. algebra.id 𝕜} /-- Any normed characteristic-zero division ring that is a normed_algebra over the reals is also a normed algebra over the rationals. @@ -430,27 +419,20 @@ Phrased another way, if `𝕜` is a normed algebra over the reals, then `algebra norm. -/ instance normed_algebra_rat {𝕜} [normed_division_ring 𝕜] [char_zero 𝕜] [normed_algebra ℝ 𝕜] : normed_algebra ℚ 𝕜 := -{ norm_algebra_map_eq := λ q, - by simpa only [ring_hom.map_rat_algebra_map] using norm_algebra_map_eq 𝕜 (algebra_map _ ℝ q) } +{ norm_smul_le := λ q x, + by rw [←smul_one_smul ℝ q x, rat.smul_one_eq_coe, norm_smul, rat.norm_cast_real], } /-- The product of two normed algebras is a normed algebra, with the sup norm. -/ instance prod.normed_algebra {E F : Type*} [semi_normed_ring E] [semi_normed_ring F] [normed_algebra 𝕜 E] [normed_algebra 𝕜 F] : normed_algebra 𝕜 (E × F) := -{ norm_algebra_map_eq := λ x, begin - dsimp [prod.norm_def], - rw [norm_algebra_map_eq, norm_algebra_map_eq, max_self], - end } +{ ..prod.normed_space } /-- The product of finitely many normed algebras is a normed algebra, with the sup norm. -/ -instance pi.normed_algebra {E : ι → Type*} [fintype ι] [nonempty ι] +instance pi.normed_algebra {E : ι → Type*} [fintype ι] [Π i, semi_normed_ring (E i)] [Π i, normed_algebra 𝕜 (E i)] : normed_algebra 𝕜 (Π i, E i) := -{ norm_algebra_map_eq := λ x, begin - dsimp [has_norm.norm], - simp_rw [pi.algebra_map_apply ι E, nnorm_algebra_map_eq, ←coe_nnnorm], - rw finset.sup_const (@finset.univ_nonempty ι _ _) _, - end, +{ .. pi.normed_space, .. pi.algebra _ E } end normed_algebra diff --git a/src/analysis/normed_space/is_R_or_C.lean b/src/analysis/normed_space/is_R_or_C.lean index 5869ae7edd1c5..d0d42de322ac4 100644 --- a/src/analysis/normed_space/is_R_or_C.lean +++ b/src/analysis/normed_space/is_R_or_C.lean @@ -30,7 +30,7 @@ open metric @[simp, is_R_or_C_simps] lemma is_R_or_C.norm_coe_norm {𝕜 : Type*} [is_R_or_C 𝕜] {E : Type*} [normed_group E] {z : E} : ∥(∥z∥ : 𝕜)∥ = ∥z∥ := -by { unfold_coes, simp only [norm_algebra_map_eq, ring_hom.to_fun_eq_coe, norm_norm], } +by { unfold_coes, simp only [norm_algebra_map', ring_hom.to_fun_eq_coe, norm_norm], } variables {𝕜 : Type*} [is_R_or_C 𝕜] {E : Type*} [normed_group E] [normed_space 𝕜 E] diff --git a/src/analysis/normed_space/operator_norm.lean b/src/analysis/normed_space/operator_norm.lean index 8e8456d198aef..2cc99c0cc9cd5 100644 --- a/src/analysis/normed_space/operator_norm.lean +++ b/src/analysis/normed_space/operator_norm.lean @@ -422,6 +422,12 @@ instance to_semi_normed_ring : semi_normed_ring (E →L[𝕜] E) := { norm_mul := λ f g, op_norm_comp_le f g, .. continuous_linear_map.to_semi_normed_group } +/-- For a normed space `E`, continuous linear endomorphisms form a normed algebra with +respect to the operator norm. -/ +instance to_normed_algebra : normed_algebra 𝕜 (E →L[𝕜] E) := +{ .. continuous_linear_map.to_normed_space, + .. continuous_linear_map.algebra } + theorem le_op_nnnorm : ∥f x∥₊ ≤ ∥f∥₊ * ∥x∥₊ := f.le_op_norm x /-- continuous linear maps are Lipschitz continuous. -/ @@ -774,25 +780,27 @@ variables {𝕜 E Fₗ Gₗ} section multiplication_linear variables (𝕜) (𝕜' : Type*) [normed_ring 𝕜'] [normed_algebra 𝕜 𝕜'] -/-- Left multiplication in a normed algebra as a linear isometry to the space of -continuous linear maps. -/ -def lmulₗᵢ : 𝕜' →ₗᵢ[𝕜] 𝕜' →L[𝕜] 𝕜' := -{ to_linear_map := (algebra.lmul 𝕜 𝕜').to_linear_map.mk_continuous₂ 1 $ - λ x y, by simpa using norm_mul_le x y, - norm_map' := λ x, le_antisymm - (op_norm_le_bound _ (norm_nonneg x) (norm_mul_le x)) - (by { convert ratio_le_op_norm _ (1 : 𝕜'), simp [normed_algebra.norm_one 𝕜 𝕜'], - apply_instance }) } - /-- Left multiplication in a normed algebra as a continuous bilinear map. -/ def lmul : 𝕜' →L[𝕜] 𝕜' →L[𝕜] 𝕜' := -(lmulₗᵢ 𝕜 𝕜').to_continuous_linear_map +(algebra.lmul 𝕜 𝕜').to_linear_map.mk_continuous₂ 1 $ + λ x y, by simpa using norm_mul_le x y @[simp] lemma lmul_apply (x y : 𝕜') : lmul 𝕜 𝕜' x y = x * y := rfl -@[simp] lemma coe_lmulₗᵢ : ⇑(lmulₗᵢ 𝕜 𝕜') = lmul 𝕜 𝕜' := rfl +@[simp] lemma op_norm_lmul_apply_le (x : 𝕜') : ∥lmul 𝕜 𝕜' x∥ ≤ ∥x∥ := +(op_norm_le_bound _ (norm_nonneg x) (norm_mul_le x)) + +/-- Left multiplication in a normed algebra as a linear isometry to the space of +continuous linear maps. -/ +def lmulₗᵢ [norm_one_class 𝕜'] : 𝕜' →ₗᵢ[𝕜] 𝕜' →L[𝕜] 𝕜' := +{ to_linear_map := lmul 𝕜 𝕜', + norm_map' := λ x, le_antisymm (op_norm_lmul_apply_le _ _ _) + (by { convert ratio_le_op_norm _ (1 : 𝕜'), simp [norm_one], + apply_instance }) } + +@[simp] lemma coe_lmulₗᵢ [norm_one_class 𝕜'] : ⇑(lmulₗᵢ 𝕜 𝕜') = lmul 𝕜 𝕜' := rfl -@[simp] lemma op_norm_lmul_apply (x : 𝕜') : ∥lmul 𝕜 𝕜' x∥ = ∥x∥ := +@[simp] lemma op_norm_lmul_apply [norm_one_class 𝕜'] (x : 𝕜') : ∥lmul 𝕜 𝕜' x∥ = ∥x∥ := (lmulₗᵢ 𝕜 𝕜').norm_map x /-- Right-multiplication in a normed algebra, considered as a continuous linear map. -/ @@ -800,19 +808,22 @@ def lmul_right : 𝕜' →L[𝕜] 𝕜' →L[𝕜] 𝕜' := (lmul 𝕜 𝕜').fl @[simp] lemma lmul_right_apply (x y : 𝕜') : lmul_right 𝕜 𝕜' x y = y * x := rfl -@[simp] lemma op_norm_lmul_right_apply (x : 𝕜') : ∥lmul_right 𝕜 𝕜' x∥ = ∥x∥ := +@[simp] lemma op_norm_lmul_right_apply_le (x : 𝕜') : ∥lmul_right 𝕜 𝕜' x∥ ≤ ∥x∥ := +op_norm_le_bound _ (norm_nonneg x) (λ y, (norm_mul_le y x).trans_eq (mul_comm _ _)) + +@[simp] lemma op_norm_lmul_right_apply [norm_one_class 𝕜'] (x : 𝕜') : ∥lmul_right 𝕜 𝕜' x∥ = ∥x∥ := le_antisymm - (op_norm_le_bound _ (norm_nonneg x) (λ y, (norm_mul_le y x).trans_eq (mul_comm _ _))) - (by { convert ratio_le_op_norm _ (1 : 𝕜'), simp [normed_algebra.norm_one 𝕜 𝕜'], + (op_norm_lmul_right_apply_le _ _ _) + (by { convert ratio_le_op_norm _ (1 : 𝕜'), simp [norm_one], apply_instance }) /-- Right-multiplication in a normed algebra, considered as a linear isometry to the space of continuous linear maps. -/ -def lmul_rightₗᵢ : 𝕜' →ₗᵢ[𝕜] 𝕜' →L[𝕜] 𝕜' := +def lmul_rightₗᵢ [norm_one_class 𝕜'] : 𝕜' →ₗᵢ[𝕜] 𝕜' →L[𝕜] 𝕜' := { to_linear_map := lmul_right 𝕜 𝕜', norm_map' := op_norm_lmul_right_apply 𝕜 𝕜' } -@[simp] lemma coe_lmul_rightₗᵢ : ⇑(lmul_rightₗᵢ 𝕜 𝕜') = lmul_right 𝕜 𝕜' := rfl +@[simp] lemma coe_lmul_rightₗᵢ [norm_one_class 𝕜'] : ⇑(lmul_rightₗᵢ 𝕜 𝕜') = lmul_right 𝕜 𝕜' := rfl /-- Simultaneous left- and right-multiplication in a normed algebra, considered as a continuous trilinear map. -/ @@ -824,7 +835,9 @@ def lmul_left_right : 𝕜' →L[𝕜] 𝕜' →L[𝕜] 𝕜' →L[𝕜] 𝕜' : lemma op_norm_lmul_left_right_apply_apply_le (x y : 𝕜') : ∥lmul_left_right 𝕜 𝕜' x y∥ ≤ ∥x∥ * ∥y∥ := -(op_norm_comp_le _ _).trans_eq $ by simp [mul_comm] +(op_norm_comp_le _ _).trans $ (mul_comm _ _).trans_le $ + mul_le_mul (op_norm_lmul_apply_le _ _ _) (op_norm_lmul_right_apply_le _ _ _) + (norm_nonneg _) (norm_nonneg _) lemma op_norm_lmul_left_right_apply_le (x : 𝕜') : ∥lmul_left_right 𝕜 𝕜' x∥ ≤ ∥x∥ := @@ -1252,13 +1265,6 @@ instance to_normed_ring : normed_ring (E →L[𝕜] E) := { norm_mul := op_norm_comp_le, .. continuous_linear_map.to_normed_group } -/-- For a nonzero normed space `E`, continuous linear endomorphisms form a normed algebra with -respect to the operator norm. -/ -instance to_normed_algebra [nontrivial E] : normed_algebra 𝕜 (E →L[𝕜] E) := -{ norm_algebra_map_eq := λ c, show ∥c • id 𝕜 E∥ = ∥c∥, - by {rw [norm_smul, norm_id], simp}, - .. continuous_linear_map.algebra } - variable {f} lemma homothety_norm [ring_hom_isometric σ₁₂] [nontrivial E] (f : E →SL[σ₁₂] F) {a : ℝ} @@ -1591,10 +1597,10 @@ continuous_linear_map.homothety_norm _ c.norm_smul_right_apply variables (𝕜) (𝕜' : Type*) [normed_ring 𝕜'] [normed_algebra 𝕜 𝕜'] -@[simp] lemma op_norm_lmul : ∥lmul 𝕜 𝕜'∥ = 1 := -by haveI := normed_algebra.nontrivial 𝕜 𝕜'; exact (lmulₗᵢ 𝕜 𝕜').norm_to_continuous_linear_map +@[simp] lemma op_norm_lmul [norm_one_class 𝕜'] : ∥lmul 𝕜 𝕜'∥ = 1 := +by haveI := norm_one_class.nontrivial 𝕜'; exact (lmulₗᵢ 𝕜 𝕜').norm_to_continuous_linear_map -@[simp] lemma op_norm_lmul_right : ∥lmul_right 𝕜 𝕜'∥ = 1 := +@[simp] lemma op_norm_lmul_right [norm_one_class 𝕜'] : ∥lmul_right 𝕜 𝕜'∥ = 1 := (op_norm_flip (@lmul 𝕜 _ 𝕜' _ _)).trans (op_norm_lmul _ _) end continuous_linear_map diff --git a/src/analysis/normed_space/spectrum.lean b/src/analysis/normed_space/spectrum.lean index 36caf279fb412..6ae2ba0bc0099 100644 --- a/src/analysis/normed_space/spectrum.lean +++ b/src/analysis/normed_space/spectrum.lean @@ -70,12 +70,12 @@ not_not.mp $ λ hn, h.not_le $ le_supr₂ k hn variable [complete_space A] lemma is_open_resolvent_set (a : A) : is_open (ρ a) := -units.is_open.preimage ((algebra_map_isometry 𝕜 A).continuous.sub continuous_const) +units.is_open.preimage ((algebra_map_clm 𝕜 A).continuous.sub continuous_const) lemma is_closed (a : A) : is_closed (σ a) := (is_open_resolvent_set a).is_closed_compl -lemma mem_resolvent_of_norm_lt {a : A} {k : 𝕜} (h : ∥a∥ < ∥k∥) : +lemma mem_resolvent_of_norm_lt [norm_one_class A] {a : A} {k : 𝕜} (h : ∥a∥ < ∥k∥) : k ∈ ρ a := begin rw [resolvent_set, set.mem_set_of_eq, algebra.algebra_map_eq_smul_one], @@ -85,28 +85,28 @@ begin simpa [ku, sub_eq_add_neg, algebra.algebra_map_eq_smul_one] using (ku.add (-a) hku).is_unit, end -lemma norm_le_norm_of_mem {a : A} {k : 𝕜} (hk : k ∈ σ a) : +lemma norm_le_norm_of_mem [norm_one_class A] {a : A} {k : 𝕜} (hk : k ∈ σ a) : ∥k∥ ≤ ∥a∥ := le_of_not_lt $ mt mem_resolvent_of_norm_lt hk -lemma subset_closed_ball_norm (a : A) : +lemma subset_closed_ball_norm [norm_one_class A] (a : A) : σ a ⊆ metric.closed_ball (0 : 𝕜) (∥a∥) := λ k hk, by simp [norm_le_norm_of_mem hk] -lemma is_bounded (a : A) : metric.bounded (σ a) := +lemma is_bounded [norm_one_class A] (a : A) : metric.bounded (σ a) := (metric.bounded_iff_subset_ball 0).mpr ⟨∥a∥, subset_closed_ball_norm a⟩ -theorem is_compact [proper_space 𝕜] (a : A) : is_compact (σ a) := +theorem is_compact [norm_one_class A] [proper_space 𝕜] (a : A) : is_compact (σ a) := metric.is_compact_of_is_closed_bounded (is_closed a) (is_bounded a) -theorem spectral_radius_le_nnnorm (a : A) : +theorem spectral_radius_le_nnnorm [norm_one_class A] (a : A) : spectral_radius 𝕜 a ≤ ∥a∥₊ := by { refine supr₂_le (λ k hk, _), exact_mod_cast norm_le_norm_of_mem hk } open ennreal polynomial variable (𝕜) -theorem spectral_radius_le_pow_nnnorm_pow_one_div (a : A) (n : ℕ) : +theorem spectral_radius_le_pow_nnnorm_pow_one_div [norm_one_class A] (a : A) (n : ℕ) : spectral_radius 𝕜 a ≤ ∥a ^ (n + 1)∥₊ ^ (1 / (n + 1) : ℝ) := begin refine supr₂_le (λ k hk, _), @@ -282,7 +282,7 @@ end /-- **Gelfand's formula**: Given an element `a : A` of a complex Banach algebra, the `spectral_radius` of `a` is the limit of the sequence `∥a ^ n∥₊ ^ (1 / n)` -/ -theorem pow_nnnorm_pow_one_div_tendsto_nhds_spectral_radius (a : A) : +theorem pow_nnnorm_pow_one_div_tendsto_nhds_spectral_radius [norm_one_class A] (a : A) : tendsto (λ n : ℕ, ((∥a ^ n∥₊ ^ (1 / n : ℝ)) : ℝ≥0∞)) at_top (𝓝 (spectral_radius ℂ a)) := begin refine tendsto_of_le_liminf_of_limsup_le _ _ (by apply_auto_param) (by apply_auto_param), @@ -296,7 +296,7 @@ end instead of `nnnorm`. -/ /-- **Gelfand's formula**: Given an element `a : A` of a complex Banach algebra, the `spectral_radius` of `a` is the limit of the sequence `∥a ^ n∥₊ ^ (1 / n)` -/ -theorem pow_norm_pow_one_div_tendsto_nhds_spectral_radius (a : A) : +theorem pow_norm_pow_one_div_tendsto_nhds_spectral_radius [norm_one_class A] (a : A) : tendsto (λ n : ℕ, ennreal.of_real (∥a ^ n∥ ^ (1 / n : ℝ))) at_top (𝓝 (spectral_radius ℂ a)) := begin convert pow_nnnorm_pow_one_div_tendsto_nhds_spectral_radius a, @@ -414,11 +414,12 @@ local notation `↑ₐ` := algebra_map 𝕜 A /-- An algebra homomorphism into the base field, as a continuous linear map (since it is automatically bounded). -/ -@[simps] def to_continuous_linear_map (φ : A →ₐ[𝕜] 𝕜) : A →L[𝕜] 𝕜 := +@[simps] def to_continuous_linear_map [norm_one_class A] (φ : A →ₐ[𝕜] 𝕜) : A →L[𝕜] 𝕜 := φ.to_linear_map.mk_continuous_of_exists_bound $ ⟨1, λ a, (one_mul ∥a∥).symm ▸ spectrum.norm_le_norm_of_mem (φ.apply_mem_spectrum _)⟩ -lemma continuous (φ : A →ₐ[𝕜] 𝕜) : continuous φ := φ.to_continuous_linear_map.continuous +lemma continuous [norm_one_class A] (φ : A →ₐ[𝕜] 𝕜) : continuous φ := +φ.to_continuous_linear_map.continuous end normed_field diff --git a/src/analysis/normed_space/star/spectrum.lean b/src/analysis/normed_space/star/spectrum.lean index ca708c04d7fca..8110678ab8ca1 100644 --- a/src/analysis/normed_space/star/spectrum.lean +++ b/src/analysis/normed_space/star/spectrum.lean @@ -51,7 +51,8 @@ variables {A : Type*} local notation `↑ₐ` := algebra_map ℂ A -lemma spectral_radius_eq_nnnorm_of_self_adjoint {a : A} (ha : a ∈ self_adjoint A) : +lemma spectral_radius_eq_nnnorm_of_self_adjoint [norm_one_class A] {a : A} + (ha : a ∈ self_adjoint A) : spectral_radius ℂ a = ∥a∥₊ := begin have hconst : tendsto (λ n : ℕ, (∥a∥₊ : ℝ≥0∞)) at_top _ := tendsto_const_nhds, @@ -64,7 +65,7 @@ begin simp, end -lemma spectral_radius_eq_nnnorm_of_star_normal (a : A) [is_star_normal a] : +lemma spectral_radius_eq_nnnorm_of_star_normal [norm_one_class A] (a : A) [is_star_normal a] : spectral_radius ℂ a = ∥a∥₊ := begin refine (ennreal.pow_strict_mono (by linarith : 2 ≠ 0)).injective _, diff --git a/src/analysis/quaternion.lean b/src/analysis/quaternion.lean index c5fdbf03e0ca9..2b77f49fb5427 100644 --- a/src/analysis/quaternion.lean +++ b/src/analysis/quaternion.lean @@ -57,7 +57,7 @@ instance : norm_one_class ℍ := @[simp, norm_cast] lemma norm_coe (a : ℝ) : ∥(a : ℍ)∥ = ∥a∥ := by rw [norm_eq_sqrt_real_inner, inner_self, norm_sq_coe, real.sqrt_sq_eq_abs, real.norm_eq_abs] -@[simp, norm_cast] lemma nnorm_coe (a : ℝ) : ∥(a : ℍ)∥₊ = ∥a∥₊ := +@[simp, norm_cast] lemma nnnorm_coe (a : ℝ) : ∥(a : ℍ)∥₊ = ∥a∥₊ := subtype.ext $ norm_coe a noncomputable instance : normed_division_ring ℍ := @@ -66,7 +66,7 @@ noncomputable instance : normed_division_ring ℍ := exact real.sqrt_mul norm_sq_nonneg _ } } noncomputable instance : normed_algebra ℝ ℍ := -{ norm_algebra_map_eq := norm_coe, +{ norm_smul_le := λ a x, (norm_smul a x).le, to_algebra := quaternion.algebra } instance : has_coe ℂ ℍ := ⟨λ z, ⟨z.re, z.im, 0, 0⟩⟩ diff --git a/src/number_theory/cyclotomic/discriminant.lean b/src/number_theory/cyclotomic/discriminant.lean index 0357923fc6b19..1c8bb0fe92095 100644 --- a/src/number_theory/cyclotomic/discriminant.lean +++ b/src/number_theory/cyclotomic/discriminant.lean @@ -119,7 +119,7 @@ begin { exact hζ.pow_sub_one_norm_prime_pow_of_one_le hirr (by simpa using hirr₁) rfl.le (hp2 hp) }, { exact hζ.pow_sub_one_norm_prime_ne_two hirr (by simpa using hirr₁) rfl.le hp } }, rw [monoid_hom.map_mul, hnorm, monoid_hom.map_mul, ← map_nat_cast (algebra_map K L), - norm_algebra_map, finrank _ hirr, pnat.pow_coe, totient_prime_pow hp.out (succ_pos k), + algebra.norm_algebra_map, finrank _ hirr, pnat.pow_coe, totient_prime_pow hp.out (succ_pos k), nat.sub_one, nat.pred_succ, ← hζ.minpoly_eq_cyclotomic_of_irreducible hirr, map_pow, hζ.norm_eq_one hk hirr, one_pow, mul_one, cast_pow, ← coe_coe, ← pow_mul, ← mul_assoc, mul_comm (k + 1), mul_assoc] at H, diff --git a/src/number_theory/cyclotomic/primitive_roots.lean b/src/number_theory/cyclotomic/primitive_roots.lean index 29d8cd386519e..ce0960555630a 100644 --- a/src/number_theory/cyclotomic/primitive_roots.lean +++ b/src/number_theory/cyclotomic/primitive_roots.lean @@ -184,7 +184,8 @@ variables {K} [field K] [algebra K L] [ne_zero ((n : ℕ) : K)] /-- This mathematically trivial result is complementary to `norm_eq_one` below. -/ lemma norm_eq_neg_one_pow (hζ : is_primitive_root ζ 2) : norm K ζ = (-1) ^ finrank K L := -by rw [hζ.eq_neg_one_of_two_right , show -1 = algebra_map K L (-1), by simp, norm_algebra_map] +by rw [hζ.eq_neg_one_of_two_right , show -1 = algebra_map K L (-1), by simp, + algebra.norm_algebra_map] include hζ @@ -195,7 +196,7 @@ lemma norm_eq_one [is_cyclotomic_extension {n} K L] (hn : n ≠ 2) begin by_cases h1 : n = 1, { rw [h1, one_coe, one_right_iff] at hζ, - rw [hζ, show 1 = algebra_map K L 1, by simp, norm_algebra_map, one_pow] }, + rw [hζ, show 1 = algebra_map K L 1, by simp, algebra.norm_algebra_map, one_pow] }, { replace h1 : 2 ≤ n, { by_contra' h, exact h1 (pnat.eq_one_of_lt_two h) }, @@ -211,7 +212,7 @@ lemma norm_eq_one_of_linearly_ordered {K : Type*} [linear_ordered_field K] [alge begin haveI := ne_zero.of_no_zero_smul_divisors K L n, have hz := congr_arg (norm K) ((is_primitive_root.iff_def _ n).1 hζ).1, - rw [←(algebra_map K L).map_one , norm_algebra_map, one_pow, map_pow, ←one_pow ↑n] at hz, + rw [←(algebra_map K L).map_one , algebra.norm_algebra_map, one_pow, map_pow, ←one_pow ↑n] at hz, exact strict_mono.injective hodd.strict_mono_pow hz end @@ -412,7 +413,8 @@ begin { simp only [_root_.map_neg, map_bit0, _root_.map_one], ring }, replace hirr : irreducible (cyclotomic (2 ^ (k + 1) : ℕ+) K) := by simp [hirr], - rw [this.eq_neg_one_of_two_right, H, norm_algebra_map, is_cyclotomic_extension.finrank L hirr, + rw [this.eq_neg_one_of_two_right, H, algebra.norm_algebra_map, + is_cyclotomic_extension.finrank L hirr, pow_coe, pnat.coe_bit0, one_coe, totient_prime_pow nat.prime_two (zero_lt_succ k), succ_sub_succ_eq_sub, tsub_zero, mul_one] end diff --git a/src/ring_theory/norm.lean b/src/ring_theory/norm.lean index 298a66638e7ce..044e4098ad177 100644 --- a/src/ring_theory/norm.lean +++ b/src/ring_theory/norm.lean @@ -89,7 +89,7 @@ end (If `L` is not finite-dimensional over `K`, then `norm = 1 = x ^ 0 = x ^ (finrank L K)`.) -/ @[simp] -lemma norm_algebra_map (x : K) : norm K (algebra_map K L x) = x ^ finrank K L := +protected lemma norm_algebra_map (x : K) : norm K (algebra_map K L x) = x ^ finrank K L := begin by_cases H : ∃ (s : finset L), nonempty (basis s K L), { rw [norm_algebra_map_of_basis H.some_spec.some, finrank_eq_card_basis H.some_spec.some] }, diff --git a/src/ring_theory/polynomial/eisenstein.lean b/src/ring_theory/polynomial/eisenstein.lean index 13c457b336a18..9c7ab6a9d8edb 100644 --- a/src/ring_theory/polynomial/eisenstein.lean +++ b/src/ring_theory/polynomial/eisenstein.lean @@ -357,12 +357,12 @@ begin p • Q.coeff x • f (x + n)) : congr_arg (norm K) (eq_sub_of_add_eq _) ... = _ : _, - { simp only [algebra.smul_def, algebra_map_apply R K L, norm_algebra_map, _root_.map_mul, + { simp only [algebra.smul_def, algebra_map_apply R K L, algebra.norm_algebra_map, _root_.map_mul, _root_.map_pow, finrank_K_L, power_basis.norm_gen_eq_coeff_zero_minpoly, minpoly.gcd_domain_eq_field_fractions K hBint, coeff_map, ← hn], ring_exp }, swap, { simp_rw [← smul_sum, ← smul_sub, algebra.smul_def p, algebra_map_apply R K L, - _root_.map_mul, norm_algebra_map, finrank_K_L, hr, ← hn] }, + _root_.map_mul, algebra.norm_algebra_map, finrank_K_L, hr, ← hn] }, calc _ = (Q.coeff 0 • 1 + ∑ (x : ℕ) in (range (Q.nat_degree + 1)).erase 0, Q.coeff x • B.gen ^ x) * B.gen ^ n : _ @@ -529,7 +529,8 @@ begin simpa using hk } }, obtain ⟨r, hr⟩ := is_integral_iff.1 (is_integral_norm K hintsum), rw [algebra.smul_def, mul_assoc, ← mul_sub, _root_.map_mul, algebra_map_apply R K L, map_pow, - norm_algebra_map, _root_.map_mul, algebra_map_apply R K L, norm_algebra_map, finrank B, ← hr, + algebra.norm_algebra_map, _root_.map_mul, algebra_map_apply R K L, algebra.norm_algebra_map, + finrank B, ← hr, power_basis.norm_gen_eq_coeff_zero_minpoly, minpoly.gcd_domain_eq_field_fractions K hBint, coeff_map, show (-1 : K) = algebra_map R K (-1), by simp, ← map_pow, ← map_pow, ← _root_.map_mul, ← map_pow, ← _root_.map_mul, ← map_pow, ← _root_.map_mul] at hQ, diff --git a/src/topology/continuous_function/bounded.lean b/src/topology/continuous_function/bounded.lean index 13c2843ff26b2..3c92c051eed18 100644 --- a/src/topology/continuous_function/bounded.lean +++ b/src/topology/continuous_function/bounded.lean @@ -1119,13 +1119,8 @@ instance : algebra 𝕜 (α →ᵇ γ) := algebra_map 𝕜 (α →ᵇ γ) k a = k • 1 := by { rw algebra.algebra_map_eq_smul_one, refl, } -instance [nonempty α] : normed_algebra 𝕜 (α →ᵇ γ) := -{ norm_algebra_map_eq := λ c, begin - calc ∥ (algebra_map 𝕜 (α →ᵇ γ)).to_fun c∥ = ∥(algebra_map 𝕜 γ) c∥ : _ - ... = ∥c∥ : norm_algebra_map_eq _ _, - apply norm_const_eq ((algebra_map 𝕜 γ) c), assumption, - end, - ..bounded_continuous_function.algebra } +instance : normed_algebra 𝕜 (α →ᵇ γ) := +{ ..bounded_continuous_function.normed_space } /-! ### Structure as normed module over scalar functions diff --git a/src/topology/continuous_function/compact.lean b/src/topology/continuous_function/compact.lean index 88de16c29ca02..30844763f0d4d 100644 --- a/src/topology/continuous_function/compact.lean +++ b/src/topology/continuous_function/compact.lean @@ -258,8 +258,8 @@ end section variables {𝕜 : Type*} {γ : Type*} [normed_field 𝕜] [normed_ring γ] [normed_algebra 𝕜 γ] -instance [nonempty α] : normed_algebra 𝕜 C(α, γ) := -{ norm_algebra_map_eq := λ c, (norm_algebra_map_eq (α →ᵇ γ) c : _), } +instance : normed_algebra 𝕜 C(α, γ) := +{ ..continuous_map.normed_space } end From 7b92db75cbff19563fc3717930b2e91bf4050b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Fri, 22 Apr 2022 01:34:19 +0000 Subject: [PATCH 161/373] chore(set_theory/cardinal/basic): Fix spacing (#13562) --- src/set_theory/cardinal/basic.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/set_theory/cardinal/basic.lean b/src/set_theory/cardinal/basic.lean index 66496a4fa224c..056f6332a15e1 100644 --- a/src/set_theory/cardinal/basic.lean +++ b/src/set_theory/cardinal/basic.lean @@ -76,11 +76,11 @@ variables {α β : Type u} Quotienting by this equivalence relation gives the cardinal numbers. -/ instance cardinal.is_equivalent : setoid (Type u) := -{ r := λα β, nonempty (α ≃ β), - iseqv := ⟨λα, +{ r := λ α β, nonempty (α ≃ β), + iseqv := ⟨λ α, ⟨equiv.refl α⟩, - λα β ⟨e⟩, ⟨e.symm⟩, - λα β γ ⟨e₁⟩ ⟨e₂⟩, ⟨e₁.trans e₂⟩⟩ } + λ α β ⟨e⟩, ⟨e.symm⟩, + λ α β γ ⟨e₁⟩ ⟨e₂⟩, ⟨e₁.trans e₂⟩⟩ } /-- `cardinal.{u}` is the type of cardinal numbers in `Type u`, defined as the quotient of `Type u` by existence of an equivalence From 821e7c895e64cf70e6d58e947b369da4a8d530e7 Mon Sep 17 00:00:00 2001 From: Johan Commelin Date: Fri, 22 Apr 2022 01:34:20 +0000 Subject: [PATCH 162/373] doc(category_theory/limits/has_limits): fix two docstrings (#13581) --- src/category_theory/limits/has_limits.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/category_theory/limits/has_limits.lean b/src/category_theory/limits/has_limits.lean index a55d82a94b0b1..4ffdb7fb33952 100644 --- a/src/category_theory/limits/has_limits.lean +++ b/src/category_theory/limits/has_limits.lean @@ -500,7 +500,7 @@ by { constructor, intro F, apply has_limit_of_equivalence_comp e, apply_instance variable (C) /-- -`has_limits_of_size.{v u} C` tries to obtain `has_limits_of_size.{v u} C` +`has_limits_of_size_shrink.{v u} C` tries to obtain `has_limits_of_size.{v u} C` from some other `has_limits_of_size C`. -/ lemma has_limits_of_size_shrink [has_limits_of_size.{(max v₁ v₂) (max u₁ u₂)} C] : @@ -983,7 +983,7 @@ by { constructor, intro F, apply has_colimit_of_equivalence_comp e, apply_instan variable (C) /-- -`has_colimits_of_size.{v u} C` tries to obtain `has_colimits_of_size.{v u} C` +`has_colimits_of_size_shrink.{v u} C` tries to obtain `has_colimits_of_size.{v u} C` from some other `has_colimits_of_size C`. -/ lemma has_colimits_of_size_shrink [has_colimits_of_size.{(max v₁ v₂) (max u₁ u₂)} C] : From 40fc58cbc2ab5c91f4cd4a2ac0e85bad8fc6d62f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Fri, 22 Apr 2022 01:34:21 +0000 Subject: [PATCH 163/373] feat(data/quot): `quotient.out` is injective (#13584) --- src/data/quot.lean | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/data/quot.lean b/src/data/quot.lean index ac2b80352cdd0..b410f8cb7782b 100644 --- a/src/data/quot.lean +++ b/src/data/quot.lean @@ -255,9 +255,12 @@ end x.out ≈ y.out ↔ x = y := by rw [← quotient.eq_mk_iff_out, quotient.out_eq] +lemma quotient.out_injective {s : setoid α} : function.injective (@quotient.out α s) := +λ a b h, quotient.out_equiv_out.1 $ h ▸ setoid.refl _ + @[simp] lemma quotient.out_inj {s : setoid α} {x y : quotient s} : x.out = y.out ↔ x = y := -⟨λ h, quotient.out_equiv_out.1 $ h ▸ setoid.refl _, λ h, h ▸ rfl⟩ +⟨λ h, quotient.out_injective h, λ h, h ▸ rfl⟩ section pi From 17d24243497e7b1d112dc2ae8ead4dfbb7d49009 Mon Sep 17 00:00:00 2001 From: Eric Rodriguez Date: Fri, 22 Apr 2022 01:34:22 +0000 Subject: [PATCH 164/373] feat(polynomial/cyclotomic): `eval_apply` (#13586) Co-authored-by: Alex J Best --- src/ring_theory/polynomial/cyclotomic/basic.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ring_theory/polynomial/cyclotomic/basic.lean b/src/ring_theory/polynomial/cyclotomic/basic.lean index ce299655c8ae9..44945f4109db2 100644 --- a/src/ring_theory/polynomial/cyclotomic/basic.lean +++ b/src/ring_theory/polynomial/cyclotomic/basic.lean @@ -316,6 +316,10 @@ begin simp only [coeff_map, ring_hom.eq_int_cast, ring_hom.map_int_cast] end +lemma cyclotomic.eval_apply {R S : Type*} (q : R) (n : ℕ) [ring R] [ring S] (f : R →+* S) : + eval (f q) (cyclotomic n S) = f (eval q (cyclotomic n R)) := +by rw [← map_cyclotomic n f, eval_map, eval₂_at_apply] + /-- The zeroth cyclotomic polyomial is `1`. -/ @[simp] lemma cyclotomic_zero (R : Type*) [ring R] : cyclotomic 0 R = 1 := by simp only [cyclotomic, dif_pos] From 79bc6ad40a6b73456b065c286bbe66b43a001d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Sadofschi=20Costa?= Date: Fri, 22 Apr 2022 04:34:07 +0000 Subject: [PATCH 165/373] feat(data/mv_polynomial/equiv): API for `mv_polynomial.fin_succ_equiv` (#10812) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR provides API for `mv_polynomial.fin_succ_equiv`: coefficients, degree, coefficientes of coefficients, degree_of of coefficients, etc. To state and prove these lemmas I had to define `cons` and `tail` for maps `fin (n+1) →₀ M` and prove the usual properties for these. I'm not sure if this is necessary or the correct approach to do this. Co-authored-by: Iván Sadofschi Costa Co-authored-by: Eric Wieser --- src/data/finsupp/fin.lean | 113 +++++++++++++++++++ src/data/mv_polynomial/equiv.lean | 175 +++++++++++++++++++++++++++++- 2 files changed, 282 insertions(+), 6 deletions(-) create mode 100644 src/data/finsupp/fin.lean diff --git a/src/data/finsupp/fin.lean b/src/data/finsupp/fin.lean new file mode 100644 index 0000000000000..3c6e7b514ec68 --- /dev/null +++ b/src/data/finsupp/fin.lean @@ -0,0 +1,113 @@ +/- +Copyright (c) 2021 Ivan Sadofschi Costa. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Ivan Sadofschi Costa +-/ +import data.fin.tuple +import data.finsupp.basic +/-! +# `cons` and `tail` for maps `fin n →₀ M` + +We interpret maps `fin n →₀ M` as `n`-tuples of elements of `M`, +We define the following operations: +* `finsupp.tail` : the tail of a map `fin (n + 1) →₀ M`, i.e., its last `n` entries; +* `finsupp.cons` : adding an element at the beginning of an `n`-tuple, to get an `n + 1`-tuple; + +In this context, we prove some usual properties of `tail` and `cons`, analogous to those of +`data.fin.tuple.basic`. +-/ + +noncomputable theory + +namespace finsupp + +variables {n : ℕ} (i : fin n) {M : Type*} [has_zero M] (y : M) + (t : fin (n + 1) →₀ M) (s : fin n →₀ M) + + +/-- `tail` for maps `fin (n + 1) →₀ M`. See `fin.tail` for more details. -/ +def tail (s : fin (n + 1) →₀ M) : fin n →₀ M := +finsupp.equiv_fun_on_fintype.inv_fun (fin.tail s.to_fun) + +/-- `cons` for maps `fin n →₀ M`. See `fin.cons` for more details. -/ +def cons (y : M) (s : fin n →₀ M) : fin (n + 1) →₀ M := +finsupp.equiv_fun_on_fintype.inv_fun (fin.cons y s.to_fun) + +lemma tail_apply : tail t i = t i.succ := +begin + simp only [tail, equiv_fun_on_fintype_symm_apply_to_fun, equiv.inv_fun_as_coe], + congr, +end + +@[simp] lemma cons_zero : cons y s 0 = y := +by simp [cons, finsupp.equiv_fun_on_fintype] + +@[simp] lemma cons_succ : cons y s i.succ = s i := +begin + simp only [finsupp.cons, fin.cons, finsupp.equiv_fun_on_fintype, fin.cases_succ, finsupp.coe_mk], + refl, +end + +@[simp] lemma tail_cons : tail (cons y s) = s := +begin + simp only [finsupp.cons, fin.cons, finsupp.tail, fin.tail], + ext, + simp only [equiv_fun_on_fintype_symm_apply_to_fun, equiv.inv_fun_as_coe, + finsupp.coe_mk, fin.cases_succ, equiv_fun_on_fintype], + refl, +end + +@[simp] lemma cons_tail : cons (t 0) (tail t) = t := +begin + ext, + by_cases c_a : a = 0, + { rw [c_a, cons_zero] }, + { rw [←fin.succ_pred a c_a, cons_succ, ←tail_apply] }, +end + +@[simp] lemma cons_zero_zero : cons 0 (0 : fin n →₀ M) = 0 := +begin + ext, + by_cases c : a ≠ 0, + { rw [←fin.succ_pred a c, cons_succ], + simp }, + { simp only [not_not] at c, + simp [c] }, +end + +variables {s} {y} + +lemma cons_ne_zero_of_left (h : y ≠ 0) : cons y s ≠ 0 := +begin + by_contradiction c, + have h1 : cons y s 0 = 0 := by simp [c], + rw cons_zero at h1, + cc, +end + +lemma cons_ne_zero_of_right (h : s ≠ 0) : cons y s ≠ 0 := +begin + by_contradiction c, + have h' : s = 0, + { ext, + simp [ ← cons_succ a y s, c] }, + cc, +end + +lemma cons_ne_zero_iff : cons y s ≠ 0 ↔ y ≠ 0 ∨ s ≠ 0 := +begin + apply iff.intro, + { intro h, + apply or_iff_not_imp_left.2, + intro h', + simp only [not_not] at h', + by_contra c, + rw [h', c] at h, + simpa using h }, + { intro h, + cases h, + { exact cons_ne_zero_of_left h }, + { exact cons_ne_zero_of_right h } }, +end + +end finsupp diff --git a/src/data/mv_polynomial/equiv.lean b/src/data/mv_polynomial/equiv.lean index 5a2e31091de18..76e328ca13d5e 100644 --- a/src/data/mv_polynomial/equiv.lean +++ b/src/data/mv_polynomial/equiv.lean @@ -6,7 +6,12 @@ Authors: Johannes Hölzl, Johan Commelin, Mario Carneiro import data.mv_polynomial.rename import data.polynomial.algebra_map +import data.polynomial.lifts +import data.mv_polynomial.variables +import data.finsupp.fin import logic.equiv.fin +import algebra.big_operators.fin + /-! # Equivalences between polynomial rings @@ -47,7 +52,7 @@ universes u v w x variables {R : Type u} {S₁ : Type v} {S₂ : Type w} {S₃ : Type x} namespace mv_polynomial -variables {σ : Type*} {a a' a₁ a₂ : R} {e : ℕ} {n m : σ} {s : σ →₀ ℕ} +variables {σ : Type*} {a a' a₁ a₂ : R} {e : ℕ} {s : σ →₀ ℕ} section equiv @@ -274,19 +279,30 @@ def option_equiv_right : mv_polynomial (option S₁) R ≃ₐ[R] mv_polynomial S alg_equiv.of_alg_hom (mv_polynomial.aeval (λ o, o.elim (C polynomial.X) X)) (mv_polynomial.aeval_tower (polynomial.aeval (X none)) (λ i, X (option.some i))) - (by ext : 2; simp [mv_polynomial.algebra_map_eq]) - (by ext i : 2; cases i; simp) + begin + ext : 2; + simp only [mv_polynomial.algebra_map_eq, option.elim, alg_hom.coe_comp, alg_hom.id_comp, + is_scalar_tower.coe_to_alg_hom', comp_app, aeval_tower_C, polynomial.aeval_X, aeval_X, + option.elim, aeval_tower_X, alg_hom.coe_id, id.def, eq_self_iff_true, implies_true_iff], + end + begin + ext ⟨i⟩ : 2; + simp only [option.elim, alg_hom.coe_comp, comp_app, aeval_X, aeval_tower_C, + polynomial.aeval_X, alg_hom.coe_id, id.def, aeval_tower_X], + end + +variables (n : ℕ) /-- The algebra isomorphism between multivariable polynomials in `fin (n + 1)` and polynomials over multivariable polynomials in `fin n`. -/ -def fin_succ_equiv (n : ℕ) : +def fin_succ_equiv : mv_polynomial (fin (n + 1)) R ≃ₐ[R] polynomial (mv_polynomial (fin n) R) := (rename_equiv R (fin_succ_equiv n)).trans (option_equiv_left R (fin n)) -lemma fin_succ_equiv_eq (n : ℕ) : +lemma fin_succ_equiv_eq : (fin_succ_equiv R n : mv_polynomial (fin (n + 1)) R →+* polynomial (mv_polynomial (fin n) R)) = eval₂_hom (polynomial.C.comp (C : R →+* mv_polynomial (fin n) R)) (λ i : fin (n+1), fin.cases polynomial.X (λ k, polynomial.C (X k)) i) := @@ -301,7 +317,7 @@ begin simp [fin_succ_equiv] } end -@[simp] lemma fin_succ_equiv_apply (n : ℕ) (p : mv_polynomial (fin (n + 1)) R) : +@[simp] lemma fin_succ_equiv_apply (p : mv_polynomial (fin (n + 1)) R) : fin_succ_equiv R n p = eval₂_hom (polynomial.C.comp (C : R →+* mv_polynomial (fin n) R)) (λ i : fin (n+1), fin.cases polynomial.X (λ k, polynomial.C (X k)) i) p := @@ -319,6 +335,153 @@ begin simp only [mv_polynomial.fin_succ_equiv_apply, mv_polynomial.eval₂_hom_C], end +variables {n} {R} + +lemma fin_succ_equiv_X_zero : + fin_succ_equiv R n (X 0) = polynomial.X := by simp + +lemma fin_succ_equiv_X_succ {j : fin n} : + fin_succ_equiv R n (X j.succ) = polynomial.C (X j) := by simp + +/-- The coefficient of `m` in the `i`-th coefficient of `fin_succ_equiv R n f` equals the + coefficient of `finsupp.cons i m` in `f`. -/ +lemma fin_succ_equiv_coeff_coeff (m : fin n →₀ ℕ) + (f : mv_polynomial (fin (n + 1)) R) (i : ℕ) : + coeff m (polynomial.coeff (fin_succ_equiv R n f) i) = coeff (m.cons i) f := +begin + induction f using mv_polynomial.induction_on' with j r p q hp hq generalizing i m, + swap, + { simp only [(fin_succ_equiv R n).map_add, polynomial.coeff_add, coeff_add, hp, hq] }, + simp only [fin_succ_equiv_apply, coe_eval₂_hom, eval₂_monomial, ring_hom.coe_comp, prod_pow, + polynomial.coeff_C_mul, coeff_C_mul, coeff_monomial, + fin.prod_univ_succ, fin.cases_zero, fin.cases_succ, ← ring_hom.map_prod, ← ring_hom.map_pow], + rw [← mul_boole, mul_comm (polynomial.X ^ j 0), polynomial.coeff_C_mul_X_pow], congr' 1, + obtain rfl | hjmi := eq_or_ne j (m.cons i), + { simpa only [cons_zero, cons_succ, if_pos rfl, monomial_eq, C_1, one_mul, prod_pow] + using coeff_monomial m m (1:R), }, + { simp only [hjmi, if_false], + obtain hij | rfl := ne_or_eq i (j 0), + { simp only [hij, if_false, coeff_zero] }, + simp only [eq_self_iff_true, if_true], + have hmj : m ≠ j.tail, { rintro rfl, rw [cons_tail] at hjmi, contradiction }, + simpa only [monomial_eq, C_1, one_mul, prod_pow, finsupp.tail_apply, if_neg hmj.symm] + using coeff_monomial m j.tail (1:R), } +end + +lemma eval_eq_eval_mv_eval' (s : fin n → R) (y : R) (f : mv_polynomial (fin (n + 1)) R) : + eval (fin.cons y s : fin (n + 1) → R) f = + polynomial.eval y (polynomial.map (eval s) (fin_succ_equiv R n f)) := +begin + -- turn this into a def `polynomial.map_alg_hom` + let φ : (mv_polynomial (fin n) R)[X] →ₐ[R] R[X] := + { commutes' := λ r, by { convert polynomial.map_C _, exact (eval_C _).symm }, + .. polynomial.map_ring_hom (eval s) }, + show aeval (fin.cons y s : fin (n + 1) → R) f = + (polynomial.aeval y).comp (φ.comp (fin_succ_equiv R n).to_alg_hom) f, + congr' 2, + apply mv_polynomial.alg_hom_ext, + rw fin.forall_fin_succ, + simp only [aeval_X, fin.cons_zero, alg_equiv.to_alg_hom_eq_coe, alg_hom.coe_comp, + polynomial.coe_aeval_eq_eval, polynomial.map_C, alg_hom.coe_mk, ring_hom.to_fun_eq_coe, + polynomial.coe_map_ring_hom, alg_equiv.coe_alg_hom, comp_app, fin_succ_equiv_apply, + eval₂_hom_X', fin.cases_zero, polynomial.map_X, polynomial.eval_X, eq_self_iff_true, + fin.cons_succ, fin.cases_succ, eval_X, polynomial.eval_C, implies_true_iff, and_self], +end + +lemma coeff_eval_eq_eval_coeff (s' : fin n → R) (f : polynomial (mv_polynomial (fin n) R)) + (i : ℕ) : polynomial.coeff (polynomial.map (eval s') f) i = eval s' (polynomial.coeff f i) := +by simp only [polynomial.coeff_map] + +lemma support_coeff_fin_succ_equiv {f : mv_polynomial (fin (n + 1)) R} {i : ℕ} + {m : fin n →₀ ℕ } : m ∈ (polynomial.coeff ((fin_succ_equiv R n) f) i).support + ↔ (finsupp.cons i m) ∈ f.support := +begin + apply iff.intro, + { intro h, + simpa [←fin_succ_equiv_coeff_coeff] using h }, + { intro h, + simpa [mem_support_iff, ←fin_succ_equiv_coeff_coeff m f i] using h }, +end + +lemma fin_succ_equiv_support (f : mv_polynomial (fin (n + 1)) R) : + (fin_succ_equiv R n f).support = finset.image (λ m : fin (n + 1)→₀ ℕ, m 0) f.support := +begin + ext i, + rw [polynomial.mem_support_iff, finset.mem_image, nonzero_iff_exists], + split, + { rintro ⟨m, hm⟩, + refine ⟨cons i m, _, cons_zero _ _⟩, + rw ← support_coeff_fin_succ_equiv, + simpa using hm, }, + { rintro ⟨m, h, rfl⟩, + refine ⟨tail m, _⟩, + rwa [← coeff, ← mem_support_iff, support_coeff_fin_succ_equiv, cons_tail] }, +end + +lemma fin_succ_equiv_support' {f : mv_polynomial (fin (n + 1)) R} {i : ℕ} : + finset.image (finsupp.cons i) (polynomial.coeff ((fin_succ_equiv R n) f) i).support + = f.support.filter(λ m, m 0 = i) := +begin + ext m, + rw [finset.mem_filter, finset.mem_image, mem_support_iff], + conv_lhs + { congr, + funext, + rw [mem_support_iff, fin_succ_equiv_coeff_coeff, ne.def] }, + split, + { rintros ⟨m',⟨h, hm'⟩⟩, + simp only [←hm'], + exact ⟨h, by rw cons_zero⟩ }, + { intro h, + use tail m, + rw [← h.2, cons_tail], + simp [h.1] } +end + +lemma support_fin_succ_equiv_nonempty {f : mv_polynomial (fin (n + 1)) R} (h : f ≠ 0) : + (fin_succ_equiv R n f).support.nonempty := +begin + by_contradiction c, + simp only [finset.not_nonempty_iff_eq_empty, polynomial.support_eq_empty] at c, + have t'' : (fin_succ_equiv R n f) ≠ 0, + { let ii := (fin_succ_equiv R n).symm, + have h' : f = 0 := + calc f = ii (fin_succ_equiv R n f) : by simpa only [ii, ←alg_equiv.inv_fun_eq_symm] + using ((fin_succ_equiv R n).left_inv f).symm + ... = ii 0 : by rw c + ... = 0 : by simp, + simpa [h'] using h }, + simpa [c] using h, +end + +lemma degree_fin_succ_equiv {f : mv_polynomial (fin (n + 1)) R} (h : f ≠ 0) : + (fin_succ_equiv R n f).degree = degree_of 0 f := +begin + have h' : (fin_succ_equiv R n f).support.sup (λ x , x) = degree_of 0 f, + { rw [degree_of_eq_sup, fin_succ_equiv_support f, finset.sup_image] }, + rw [polynomial.degree, ← h', finset.coe_sup_of_nonempty (support_fin_succ_equiv_nonempty h)], + congr, +end + +lemma nat_degree_fin_succ_equiv (f : mv_polynomial (fin (n + 1)) R) : + (fin_succ_equiv R n f).nat_degree = degree_of 0 f := +begin + by_cases c : f = 0, + { rw [c, (fin_succ_equiv R n).map_zero, polynomial.nat_degree_zero, degree_of_zero] }, + { rw [polynomial.nat_degree, degree_fin_succ_equiv (by simpa only [ne.def]) ], + simp }, +end + +lemma degree_of_coeff_fin_succ_equiv (p : mv_polynomial (fin (n + 1)) R) (j : fin n) + (i : ℕ) : degree_of j (polynomial.coeff (fin_succ_equiv R n p) i) ≤ degree_of j.succ p := +begin + rw [degree_of_eq_sup, degree_of_eq_sup, finset.sup_le_iff], + intros m hm, + rw ← finsupp.cons_succ j i m, + convert finset.le_sup (support_coeff_fin_succ_equiv.1 hm), + refl, +end + end end equiv From 2b902eb3a13739fc6f060608f58fec5cfb48118f Mon Sep 17 00:00:00 2001 From: leanprover-community-bot Date: Fri, 22 Apr 2022 04:34:08 +0000 Subject: [PATCH 166/373] chore(scripts): update nolints.txt (#13597) I am happy to remove some nolints for you! --- scripts/nolints.txt | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/scripts/nolints.txt b/scripts/nolints.txt index 005c60d46d055..a0f3c4722dcf1 100644 --- a/scripts/nolints.txt +++ b/scripts/nolints.txt @@ -28,10 +28,7 @@ apply_nolint one_hom.comp_assoc to_additive_doc -- algebra/order/group.lean apply_nolint inv_le_of_inv_le' to_additive_doc -apply_nolint inv_le_one' to_additive_doc apply_nolint inv_lt_of_inv_lt' to_additive_doc -apply_nolint inv_lt_one' to_additive_doc -apply_nolint inv_lt_one_iff_one_lt to_additive_doc apply_nolint inv_mul_lt_of_lt_mul to_additive_doc apply_nolint inv_of_one_lt_inv to_additive_doc apply_nolint le_inv_mul_of_mul_le to_additive_doc @@ -44,27 +41,18 @@ apply_nolint left.one_lt_inv_iff to_additive_doc apply_nolint lt_inv_mul_of_mul_lt to_additive_doc apply_nolint lt_inv_of_lt_inv to_additive_doc apply_nolint lt_mul_of_inv_mul_lt to_additive_doc -apply_nolint lt_mul_of_inv_mul_lt_left to_additive_doc apply_nolint lt_of_inv_lt_inv to_additive_doc apply_nolint mul_le_of_le_inv_mul to_additive_doc apply_nolint mul_lt_of_lt_inv_mul to_additive_doc -apply_nolint one_le_inv' to_additive_doc apply_nolint one_le_of_inv_le_one to_additive_doc -apply_nolint one_lt_inv' to_additive_doc apply_nolint one_lt_inv_of_inv to_additive_doc apply_nolint one_lt_of_inv_lt_one to_additive_doc -apply_nolint ordered_comm_group.le_of_mul_le_mul_left to_additive_doc -apply_nolint ordered_comm_group.lt_of_mul_lt_mul_left to_additive_doc -apply_nolint ordered_comm_group.mul_lt_mul_left' to_additive_doc apply_nolint right.inv_le_one_iff to_additive_doc apply_nolint right.one_le_inv_iff to_additive_doc -- algebra/order/lattice_group.lean apply_nolint lattice_ordered_comm_group.mabs_mul_le to_additive_doc --- algebra/order/monoid_lemmas.lean -apply_nolint mul_le_one' to_additive_doc - -- category_theory/limits/filtered_colimit_commutes_finite_limit.lean apply_nolint category_theory.limits.colimit_limit_to_limit_colimit_is_iso fails_quickly @@ -492,7 +480,6 @@ apply_nolint submonoid.localization_map.lift_left_inverse to_additive_doc -- group_theory/order_of_element.lean apply_nolint image_range_order_of to_additive_doc -apply_nolint is_of_fin_order.quotient to_additive_doc apply_nolint is_of_fin_order_iff_coe to_additive_doc apply_nolint order_of_eq_of_pow_and_pow_div_prime to_additive_doc apply_nolint pow_gcd_card_eq_one_iff to_additive_doc @@ -606,9 +593,6 @@ apply_nolint tactic.coinductive_predicate doc_blame apply_nolint tactic.interactive.coinduction doc_blame apply_nolint tactic.mono doc_blame --- number_theory/dioph.lean -apply_nolint poly has_inhabited_instance - -- order/filter/at_top_bot.lean apply_nolint filter.map_at_top_finset_prod_le_of_prod_eq to_additive_doc @@ -621,10 +605,6 @@ apply_nolint witt_vector.comm_ring check_reducibility -- set_theory/lists.lean apply_nolint finsets doc_blame --- set_theory/pgame.lean -apply_nolint pgame.relabelling has_inhabited_instance -apply_nolint pgame.restricted has_inhabited_instance - -- set_theory/zfc.lean apply_nolint Set.map_definable_aux unused_arguments From 06a6044f9319693cc131da5ee2d577b7273a5360 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Fri, 22 Apr 2022 06:47:39 +0000 Subject: [PATCH 167/373] feat(analysis/normed_space/exponential): Weaken typeclass requirements (#13444) This allows the exponential to be defined independently of a choice of norm. --- src/analysis/analytic/basic.lean | 48 +++++---- .../calculus/formal_multilinear_series.lean | 100 +++++++++++------- src/analysis/normed_space/exponential.lean | 57 ++++++---- src/analysis/normed_space/multilinear.lean | 14 ++- 4 files changed, 143 insertions(+), 76 deletions(-) diff --git a/src/analysis/analytic/basic.lean b/src/analysis/analytic/basic.lean index 8a4244db130bc..02deec2c320b5 100644 --- a/src/analysis/analytic/basic.lean +++ b/src/analysis/analytic/basic.lean @@ -69,16 +69,42 @@ build the general theory. We do not define it here. noncomputable theory -variables {𝕜 : Type*} [nondiscrete_normed_field 𝕜] -{E : Type*} [normed_group E] [normed_space 𝕜 E] -{F : Type*} [normed_group F] [normed_space 𝕜 F] -{G : Type*} [normed_group G] [normed_space 𝕜 G] +variables {𝕜 E F G : Type*} open_locale topological_space classical big_operators nnreal filter ennreal open set filter asymptotics +namespace formal_multilinear_series + +variables [ring 𝕜] [add_comm_group E] [add_comm_group F] [module 𝕜 E] [module 𝕜 F] +variables [topological_space E] [topological_space F] +variables [topological_add_group E] [topological_add_group F] +variables [has_continuous_const_smul 𝕜 E] [has_continuous_const_smul 𝕜 F] + +/-- Given a formal multilinear series `p` and a vector `x`, then `p.sum x` is the sum `Σ pₙ xⁿ`. A +priori, it only behaves well when `∥x∥ < p.radius`. -/ +protected def sum (p : formal_multilinear_series 𝕜 E F) (x : E) : F := ∑' n : ℕ , p n (λ i, x) + +/-- Given a formal multilinear series `p` and a vector `x`, then `p.partial_sum n x` is the sum +`Σ pₖ xᵏ` for `k ∈ {0,..., n-1}`. -/ +def partial_sum (p : formal_multilinear_series 𝕜 E F) (n : ℕ) (x : E) : F := +∑ k in finset.range n, p k (λ(i : fin k), x) + +/-- The partial sums of a formal multilinear series are continuous. -/ +lemma partial_sum_continuous (p : formal_multilinear_series 𝕜 E F) (n : ℕ) : + continuous (p.partial_sum n) := +by continuity + +end formal_multilinear_series + /-! ### The radius of a formal multilinear series -/ + +variables [nondiscrete_normed_field 𝕜] +[normed_group E] [normed_space 𝕜 E] +[normed_group F] [normed_space 𝕜 F] +[normed_group G] [normed_space 𝕜 G] + namespace formal_multilinear_series variables (p : formal_multilinear_series 𝕜 E F) {r : ℝ≥0} @@ -281,25 +307,11 @@ end @[simp] lemma radius_neg (p : formal_multilinear_series 𝕜 E F) : (-p).radius = p.radius := by simp [radius] -/-- Given a formal multilinear series `p` and a vector `x`, then `p.sum x` is the sum `Σ pₙ xⁿ`. A -priori, it only behaves well when `∥x∥ < p.radius`. -/ -protected def sum (p : formal_multilinear_series 𝕜 E F) (x : E) : F := ∑' n : ℕ , p n (λ i, x) - protected lemma has_sum [complete_space F] (p : formal_multilinear_series 𝕜 E F) {x : E} (hx : x ∈ emetric.ball (0 : E) p.radius) : has_sum (λ n : ℕ, p n (λ _, x)) (p.sum x) := (p.summable hx).has_sum -/-- Given a formal multilinear series `p` and a vector `x`, then `p.partial_sum n x` is the sum -`Σ pₖ xᵏ` for `k ∈ {0,..., n-1}`. -/ -def partial_sum (p : formal_multilinear_series 𝕜 E F) (n : ℕ) (x : E) : F := -∑ k in finset.range n, p k (λ(i : fin k), x) - -/-- The partial sums of a formal multilinear series are continuous. -/ -lemma partial_sum_continuous (p : formal_multilinear_series 𝕜 E F) (n : ℕ) : - continuous (p.partial_sum n) := -by continuity - lemma radius_le_radius_continuous_linear_map_comp (p : formal_multilinear_series 𝕜 E F) (f : F →L[𝕜] G) : p.radius ≤ (f.comp_formal_multilinear_series p).radius := diff --git a/src/analysis/calculus/formal_multilinear_series.lean b/src/analysis/calculus/formal_multilinear_series.lean index 4d4ed45b4c165..08490045b8cb5 100644 --- a/src/analysis/calculus/formal_multilinear_series.lean +++ b/src/analysis/calculus/formal_multilinear_series.lean @@ -27,18 +27,27 @@ noncomputable theory open set fin open_locale topological_space -variables {𝕜 : Type*} [nondiscrete_normed_field 𝕜] -{E : Type*} [normed_group E] [normed_space 𝕜 E] -{F : Type*} [normed_group F] [normed_space 𝕜 F] -{G : Type*} [normed_group G] [normed_space 𝕜 G] +variables {𝕜 𝕜' E F G : Type*} + +section +variables [comm_ring 𝕜] + [add_comm_group E] [module 𝕜 E] [topological_space E] [topological_add_group E] + [has_continuous_const_smul 𝕜 E] + [add_comm_group F] [module 𝕜 F] [topological_space F] [topological_add_group F] + [has_continuous_const_smul 𝕜 F] + [add_comm_group G] [module 𝕜 G] [topological_space G] [topological_add_group G] + [has_continuous_const_smul 𝕜 G] + /-- A formal multilinear series over a field `𝕜`, from `E` to `F`, is given by a family of multilinear maps from `E^n` to `F` for all `n`. -/ -@[derive add_comm_group] -def formal_multilinear_series - (𝕜 : Type*) [nondiscrete_normed_field 𝕜] - (E : Type*) [normed_group E] [normed_space 𝕜 E] - (F : Type*) [normed_group F] [normed_space 𝕜 F] := +@[derive add_comm_group, nolint unused_arguments] +def formal_multilinear_series (𝕜 : Type*) (E : Type*) (F : Type*) + [ring 𝕜] + [add_comm_group E] [module 𝕜 E] [topological_space E] [topological_add_group E] + [has_continuous_const_smul 𝕜 E] + [add_comm_group F] [module 𝕜 F] [topological_space F] [topological_add_group F] + [has_continuous_const_smul 𝕜 F] := Π (n : ℕ), (E [×n]→L[𝕜] F) instance : inhabited (formal_multilinear_series 𝕜 E F) := ⟨0⟩ @@ -46,45 +55,31 @@ instance : inhabited (formal_multilinear_series 𝕜 E F) := ⟨0⟩ section module /- `derive` is not able to find the module structure, probably because Lean is confused by the dependent types. We register it explicitly. -/ -local attribute [reducible] formal_multilinear_series instance : module 𝕜 (formal_multilinear_series 𝕜 E F) := begin - letI : ∀ n, module 𝕜 (continuous_multilinear_map 𝕜 (λ (i : fin n), E) F) := + letI : Π n, module 𝕜 (continuous_multilinear_map 𝕜 (λ (i : fin n), E) F) := λ n, by apply_instance, - apply_instance + refine pi.module _ _ _, end end module namespace formal_multilinear_series -variables (p : formal_multilinear_series 𝕜 E F) - -/-- Forgetting the zeroth term in a formal multilinear series, and interpreting the following terms -as multilinear maps into `E →L[𝕜] F`. If `p` corresponds to the Taylor series of a function, then -`p.shift` is the Taylor series of the derivative of the function. -/ -def shift : formal_multilinear_series 𝕜 E (E →L[𝕜] F) := -λn, (p n.succ).curry_right - -/-- Adding a zeroth term to a formal multilinear series taking values in `E →L[𝕜] F`. This -corresponds to starting from a Taylor series for the derivative of a function, and building a Taylor -series for the function itself. -/ -def unshift (q : formal_multilinear_series 𝕜 E (E →L[𝕜] F)) (z : F) : - formal_multilinear_series 𝕜 E F -| 0 := (continuous_multilinear_curry_fin0 𝕜 E F).symm z -| (n + 1) := continuous_multilinear_curry_right_equiv' 𝕜 n E F (q n) - /-- Killing the zeroth coefficient in a formal multilinear series -/ def remove_zero (p : formal_multilinear_series 𝕜 E F) : formal_multilinear_series 𝕜 E F | 0 := 0 | (n + 1) := p (n + 1) -@[simp] lemma remove_zero_coeff_zero : p.remove_zero 0 = 0 := rfl +@[simp] lemma remove_zero_coeff_zero (p : formal_multilinear_series 𝕜 E F) : + p.remove_zero 0 = 0 := rfl -@[simp] lemma remove_zero_coeff_succ (n : ℕ) : p.remove_zero (n+1) = p (n+1) := rfl +@[simp] lemma remove_zero_coeff_succ (p : formal_multilinear_series 𝕜 E F) (n : ℕ) : + p.remove_zero (n+1) = p (n+1) := rfl -lemma remove_zero_of_pos {n : ℕ} (h : 0 < n) : p.remove_zero n = p n := +lemma remove_zero_of_pos (p : formal_multilinear_series 𝕜 E F) {n : ℕ} (h : 0 < n) : + p.remove_zero n = p n := by { rw ← nat.succ_pred_eq_of_pos h, refl } /-- Convenience congruence lemma stating in a dependent setting that, if the arguments to a formal @@ -104,19 +99,52 @@ def comp_continuous_linear_map (p : formal_multilinear_series 𝕜 F G) (u : E (p : formal_multilinear_series 𝕜 F G) (u : E →L[𝕜] F) (n : ℕ) (v : fin n → E) : (p.comp_continuous_linear_map u) n v = p n (u ∘ v) := rfl -variables (𝕜) {𝕜' : Type*} [nondiscrete_normed_field 𝕜'] [normed_algebra 𝕜 𝕜'] -variables [normed_space 𝕜' E] [is_scalar_tower 𝕜 𝕜' E] -variables [normed_space 𝕜' F] [is_scalar_tower 𝕜 𝕜' F] +variables (𝕜) [comm_ring 𝕜'] [has_scalar 𝕜 𝕜'] +variables [module 𝕜' E] [has_continuous_const_smul 𝕜' E] [is_scalar_tower 𝕜 𝕜' E] +variables [module 𝕜' F] [has_continuous_const_smul 𝕜' F] [is_scalar_tower 𝕜 𝕜' F] -/-- Reinterpret a formal `𝕜'`-multilinear series as a formal `𝕜`-multilinear series, where `𝕜'` is a -normed algebra over `𝕜`. -/ +/-- Reinterpret a formal `𝕜'`-multilinear series as a formal `𝕜`-multilinear series. -/ @[simp] protected def restrict_scalars (p : formal_multilinear_series 𝕜' E F) : formal_multilinear_series 𝕜 E F := λ n, (p n).restrict_scalars 𝕜 end formal_multilinear_series +end + +namespace formal_multilinear_series + +variables [nondiscrete_normed_field 𝕜] + [normed_group E] [normed_space 𝕜 E] + [normed_group F] [normed_space 𝕜 F] + [normed_group G] [normed_space 𝕜 G] + +variables (p : formal_multilinear_series 𝕜 E F) + +/-- Forgetting the zeroth term in a formal multilinear series, and interpreting the following terms +as multilinear maps into `E →L[𝕜] F`. If `p` corresponds to the Taylor series of a function, then +`p.shift` is the Taylor series of the derivative of the function. -/ +def shift : formal_multilinear_series 𝕜 E (E →L[𝕜] F) := +λn, (p n.succ).curry_right + +/-- Adding a zeroth term to a formal multilinear series taking values in `E →L[𝕜] F`. This +corresponds to starting from a Taylor series for the derivative of a function, and building a Taylor +series for the function itself. -/ +def unshift (q : formal_multilinear_series 𝕜 E (E →L[𝕜] F)) (z : F) : + formal_multilinear_series 𝕜 E F +| 0 := (continuous_multilinear_curry_fin0 𝕜 E F).symm z +| (n + 1) := continuous_multilinear_curry_right_equiv' 𝕜 n E F (q n) + +end formal_multilinear_series + namespace continuous_linear_map +variables [comm_ring 𝕜] + [add_comm_group E] [module 𝕜 E] [topological_space E] [topological_add_group E] + [has_continuous_const_smul 𝕜 E] + [add_comm_group F] [module 𝕜 F] [topological_space F] [topological_add_group F] + [has_continuous_const_smul 𝕜 F] + [add_comm_group G] [module 𝕜 G] [topological_space G] [topological_add_group G] + [has_continuous_const_smul 𝕜 G] /-- Composing each term `pₙ` in a formal multilinear series with a continuous linear map `f` on the left gives a new formal multilinear series `f.comp_formal_multilinear_series p` whose general term diff --git a/src/analysis/normed_space/exponential.lean b/src/analysis/normed_space/exponential.lean index 4a49a2709a88d..1c9c22d0732ef 100644 --- a/src/analysis/normed_space/exponential.lean +++ b/src/analysis/normed_space/exponential.lean @@ -12,9 +12,12 @@ import data.finset.noncomm_prod /-! # Exponential in a Banach algebra -In this file, we define `exp 𝕂 𝔸`, the exponential map in a normed algebra `𝔸` over a nondiscrete -normed field `𝕂`. Although the definition doesn't require `𝔸` to be complete, we need to assume it -for most results. +In this file, we define `exp 𝕂 𝔸`, the exponential map in a topological algebra `𝔸` over a field +`𝕂`. + +While for most interesting results we need `𝔸` to be normed algebra, we do not require this in the +definition in order to make `exp` independent of a particular choice of norm. The definition also +does not require that `𝔸` be complete, but we need to assume it for most results. We then prove some basic results, but we avoid importing derivatives here to minimize dependencies. Results involving derivatives and comparisons with `real.exp` and `complex.exp` can be found in @@ -60,23 +63,21 @@ We prove most result for an arbitrary field `𝕂`, and then specialize to `𝕂 open filter is_R_or_C continuous_multilinear_map normed_field asymptotics open_locale nat topological_space big_operators ennreal -section any_field_any_algebra +section topological_algebra -variables (𝕂 𝔸 𝔹 : Type*) [nondiscrete_normed_field 𝕂] -variables [normed_ring 𝔸] [normed_ring 𝔹] [normed_algebra 𝕂 𝔸] [normed_algebra 𝕂 𝔹] +variables (𝕂 𝔸 : Type*) [field 𝕂] [ring 𝔸] [algebra 𝕂 𝔸] [topological_space 𝔸] + [topological_ring 𝔸] [has_continuous_const_smul 𝕂 𝔸] -/-- In a Banach algebra `𝔸` over a normed field `𝕂`, `exp_series 𝕂 𝔸` is the -`formal_multilinear_series` whose `n`-th term is the map `(xᵢ) : 𝔸ⁿ ↦ (1/n! : 𝕂) • ∏ xᵢ`. -Its sum is the exponential map `exp 𝕂 𝔸 : 𝔸 → 𝔸`. -/ +/-- `exp_series 𝕂 𝔸` is the `formal_multilinear_series` whose `n`-th term is the map +`(xᵢ) : 𝔸ⁿ ↦ (1/n! : 𝕂) • ∏ xᵢ`. Its sum is the exponential map `exp 𝕂 𝔸 : 𝔸 → 𝔸`. -/ def exp_series : formal_multilinear_series 𝕂 𝔸 𝔸 := - λ n, (1/n! : 𝕂) • continuous_multilinear_map.mk_pi_algebra_fin 𝕂 n 𝔸 +λ n, (1/n! : 𝕂) • continuous_multilinear_map.mk_pi_algebra_fin 𝕂 n 𝔸 -/-- In a Banach algebra `𝔸` over a normed field `𝕂`, `exp 𝕂 𝔸 : 𝔸 → 𝔸` is the exponential map -determined by the action of `𝕂` on `𝔸`. +/-- `exp 𝕂 𝔸 : 𝔸 → 𝔸` is the exponential map determined by the action of `𝕂` on `𝔸`. It is defined as the sum of the `formal_multilinear_series` `exp_series 𝕂 𝔸`. -/ noncomputable def exp (x : 𝔸) : 𝔸 := (exp_series 𝕂 𝔸).sum x -variables {𝕂 𝔸 𝔹} +variables {𝕂 𝔸} lemma exp_series_apply_eq (x : 𝔸) (n : ℕ) : exp_series 𝕂 𝔸 n (λ _, x) = (1 / n! : 𝕂) • x^n := by simp [exp_series] @@ -85,28 +86,32 @@ lemma exp_series_apply_eq' (x : 𝔸) : (λ n, exp_series 𝕂 𝔸 n (λ _, x)) = (λ n, (1 / n! : 𝕂) • x^n) := funext (exp_series_apply_eq x) -lemma exp_series_apply_eq_field (x : 𝕂) (n : ℕ) : exp_series 𝕂 𝕂 n (λ _, x) = x^n / n! := +lemma exp_series_apply_eq_field [topological_space 𝕂] [topological_ring 𝕂] (x : 𝕂) (n : ℕ) : + exp_series 𝕂 𝕂 n (λ _, x) = x^n / n! := begin rw [div_eq_inv_mul, ←smul_eq_mul, inv_eq_one_div], exact exp_series_apply_eq x n, end -lemma exp_series_apply_eq_field' (x : 𝕂) : (λ n, exp_series 𝕂 𝕂 n (λ _, x)) = (λ n, x^n / n!) := +lemma exp_series_apply_eq_field' [topological_space 𝕂] [topological_ring 𝕂] (x : 𝕂) : + (λ n, exp_series 𝕂 𝕂 n (λ _, x)) = (λ n, x^n / n!) := funext (exp_series_apply_eq_field x) lemma exp_series_sum_eq (x : 𝔸) : (exp_series 𝕂 𝔸).sum x = ∑' (n : ℕ), (1 / n! : 𝕂) • x^n := tsum_congr (λ n, exp_series_apply_eq x n) -lemma exp_series_sum_eq_field (x : 𝕂) : (exp_series 𝕂 𝕂).sum x = ∑' (n : ℕ), x^n / n! := +lemma exp_series_sum_eq_field [topological_space 𝕂] [topological_ring 𝕂] (x : 𝕂) : + (exp_series 𝕂 𝕂).sum x = ∑' (n : ℕ), x^n / n! := tsum_congr (λ n, exp_series_apply_eq_field x n) lemma exp_eq_tsum : exp 𝕂 𝔸 = (λ x : 𝔸, ∑' (n : ℕ), (1 / n! : 𝕂) • x^n) := funext exp_series_sum_eq -lemma exp_eq_tsum_field : exp 𝕂 𝕂 = (λ x : 𝕂, ∑' (n : ℕ), x^n / n!) := +lemma exp_eq_tsum_field [topological_space 𝕂] [topological_ring 𝕂] : + exp 𝕂 𝕂 = (λ x : 𝕂, ∑' (n : ℕ), x^n / n!) := funext exp_series_sum_eq_field -@[simp] lemma exp_zero : exp 𝕂 𝔸 0 = 1 := +@[simp] lemma exp_zero [t2_space 𝔸] : exp 𝕂 𝔸 0 = 1 := begin suffices : (λ x : 𝔸, ∑' (n : ℕ), (1 / n! : 𝕂) • x^n) 0 = ∑' (n : ℕ), if n = 0 then 1 else 0, { have key : ∀ n ∉ ({0} : finset ℕ), (if n = 0 then (1 : 𝔸) else 0) = 0, @@ -118,6 +123,15 @@ begin simp [h] end +end topological_algebra + +section normed + +section any_field_any_algebra + +variables {𝕂 𝔸 𝔹 : Type*} [nondiscrete_normed_field 𝕂] +variables [normed_ring 𝔸] [normed_ring 𝔹] [normed_algebra 𝕂 𝔸] [normed_algebra 𝕂 𝔹] + lemma norm_exp_series_summable_of_mem_ball (x : 𝔸) (hx : x ∈ emetric.ball (0 : 𝔸) (exp_series 𝕂 𝔸).radius) : summable (λ n, ∥exp_series 𝕂 𝔸 n (λ _, x)∥) := @@ -520,10 +534,13 @@ end comm_algebra end is_R_or_C +end normed + section scalar_tower -variables (𝕂 𝕂' 𝔸 : Type*) [nondiscrete_normed_field 𝕂] [nondiscrete_normed_field 𝕂'] - [normed_ring 𝔸] [normed_algebra 𝕂 𝔸] [normed_algebra 𝕂' 𝔸] +variables (𝕂 𝕂' 𝔸 : Type*) [field 𝕂] [field 𝕂'] [ring 𝔸] [algebra 𝕂 𝔸] [algebra 𝕂' 𝔸] + [topological_space 𝔸] [topological_ring 𝔸] + [has_continuous_const_smul 𝕂 𝔸] [has_continuous_const_smul 𝕂' 𝔸] /-- If a normed ring `𝔸` is a normed algebra over two fields, then they define the same `exp_series` on `𝔸`. -/ diff --git a/src/analysis/normed_space/multilinear.lean b/src/analysis/normed_space/multilinear.lean index 18947e090488f..81479135ec78e 100644 --- a/src/analysis/normed_space/multilinear.lean +++ b/src/analysis/normed_space/multilinear.lean @@ -375,12 +375,22 @@ lemma op_norm_neg : ∥-f∥ = ∥f∥ := by { rw norm_def, apply congr_arg, ext /-- Continuous multilinear maps themselves form a normed space with respect to the operator norm. -/ -instance to_normed_group : normed_group (continuous_multilinear_map 𝕜 E G) := +instance normed_group : normed_group (continuous_multilinear_map 𝕜 E G) := normed_group.of_core _ ⟨op_norm_zero_iff, op_norm_add_le, op_norm_neg⟩ -instance to_normed_space : normed_space 𝕜' (continuous_multilinear_map 𝕜 E G) := +/-- An alias of `continuous_multilinear_map.normed_group` with non-dependent types to help typeclass +search. -/ +instance normed_group' : normed_group (continuous_multilinear_map 𝕜 (λ i : ι, G) G') := +continuous_multilinear_map.normed_group + +instance normed_space : normed_space 𝕜' (continuous_multilinear_map 𝕜 E G) := ⟨λ c f, f.op_norm_smul_le c⟩ +/-- An alias of `continuous_multilinear_map.normed_space` with non-dependent types to help typeclass +search. -/ +instance normed_space' : normed_space 𝕜' (continuous_multilinear_map 𝕜 (λ i : ι, G') G) := +continuous_multilinear_map.normed_space + theorem le_op_norm_mul_prod_of_le {b : ι → ℝ} (hm : ∀ i, ∥m i∥ ≤ b i) : ∥f m∥ ≤ ∥f∥ * ∏ i, b i := (f.le_op_norm m).trans $ mul_le_mul_of_nonneg_left (prod_le_prod (λ _ _, norm_nonneg _) (λ i _, hm i)) (norm_nonneg f) From 0d77f29f964ae1d828bc61945f92a65d5a7b01d8 Mon Sep 17 00:00:00 2001 From: Floris van Doorn Date: Fri, 22 Apr 2022 06:47:40 +0000 Subject: [PATCH 168/373] feat(analysis/calculus/specific_functions): define normed bump functions (#13463) * Normed bump functions have integral 1 w.r.t. the specified measure. * Also add a few more properties of bump functions, including its smoothness in all arguments (including midpoint and the two radii). * From the sphere eversion project * Required for convolutions --- src/analysis/calculus/specific_functions.lean | 138 +++++++++++++++--- src/analysis/normed/group/basic.lean | 6 + src/measure_theory/function/l1_space.lean | 4 + src/order/cover.lean | 12 ++ src/topology/algebra/order/basic.lean | 16 ++ 5 files changed, 159 insertions(+), 17 deletions(-) diff --git a/src/analysis/calculus/specific_functions.lean b/src/analysis/calculus/specific_functions.lean index 19527e8b03d77..8820b4018fe90 100644 --- a/src/analysis/calculus/specific_functions.lean +++ b/src/analysis/calculus/specific_functions.lean @@ -1,10 +1,12 @@ /- Copyright (c) 2020 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Sébastien Gouëzel +Authors: Sébastien Gouëzel, Floris van Doorn -/ import analysis.calculus.iterated_deriv import analysis.inner_product_space.euclidean_dist +import measure_theory.function.locally_integrable +import measure_theory.integral.set_integral /-! # Infinitely smooth bump function @@ -29,6 +31,9 @@ function cannot have: function: real numbers `r`, `R`, and proofs of `0 < r < R`. The function itself is available through `coe_fn`. +* If `f : cont_diff_bump_of_inner c` and `μ` is a measure on the domain of `f`, then `f.normed μ` + is a smooth bump function with integral `1` w.r.t. `μ`. + * `f : cont_diff_bump c`, where `c` is a point in a finite dimensional real vector space, is a bundled smooth function such that @@ -264,7 +269,7 @@ end smooth_transition end real -variable {E : Type*} +variables {E X : Type*} /-- `f : cont_diff_bump_of_inner c`, where `c` is a point in an inner product space, is a bundled smooth function such that @@ -287,7 +292,8 @@ lemma R_pos {c : E} (f : cont_diff_bump_of_inner c) : 0 < f.R := f.r_pos.trans f instance (c : E) : inhabited (cont_diff_bump_of_inner c) := ⟨⟨1, 2, zero_lt_one, one_lt_two⟩⟩ -variables [inner_product_space ℝ E] {c : E} (f : cont_diff_bump_of_inner c) {x : E} +variables [inner_product_space ℝ E] [normed_group X] [normed_space ℝ X] +variables {c : E} (f : cont_diff_bump_of_inner c) {x : E} {n : with_top ℕ} /-- The function defined by `f : cont_diff_bump_of_inner c`. Use automatic coercion to function instead. -/ @@ -296,6 +302,15 @@ def to_fun (f : cont_diff_bump_of_inner c) : E → ℝ := instance : has_coe_to_fun (cont_diff_bump_of_inner c) (λ _, E → ℝ) := ⟨to_fun⟩ +protected lemma «def» (x : E) : f x = real.smooth_transition ((f.R - dist x c) / (f.R - f.r)) := +rfl + +protected lemma sub (x : E) : f (c - x) = f (c + x) := +by simp_rw [f.def, dist_self_sub_left, dist_self_add_left] + +protected lemma neg (f : cont_diff_bump_of_inner (0 : E)) (x : E) : f (- x) = f x := +by simp_rw [← zero_sub, f.sub, zero_add] + open real (smooth_transition) real.smooth_transition metric lemma one_of_mem_closed_ball (hx : x ∈ closed_ball c f.r) : @@ -304,6 +319,10 @@ one_of_one_le $ (one_le_div (sub_pos.2 f.r_lt_R)).2 $ sub_le_sub_left hx _ lemma nonneg : 0 ≤ f x := nonneg _ +/-- A version of `cont_diff_bump_of_inner.nonneg` with `x` explicit -/ +lemma nonneg' (x : E) : 0 ≤ f x := +f.nonneg + lemma le_one : f x ≤ 1 := le_one _ lemma pos_of_mem_ball (hx : x ∈ ball c f.R) : 0 < f x := @@ -324,6 +343,12 @@ begin { simp [hx.not_lt, f.zero_of_le_dist hx] } end +lemma tsupport_eq : tsupport f = closed_ball c f.R := +by simp_rw [tsupport, f.support_eq, closure_ball _ f.R_pos.ne'] + +protected lemma has_compact_support [finite_dimensional ℝ E] : has_compact_support f := +by simp_rw [has_compact_support, f.tsupport_eq, is_compact_closed_ball] + lemma eventually_eq_one_of_mem_ball (h : x ∈ ball c f.r) : f =ᶠ[𝓝 x] 1 := ((is_open_lt (continuous_id.dist continuous_const) continuous_const).eventually_mem h).mono $ @@ -332,26 +357,105 @@ lemma eventually_eq_one_of_mem_ball (h : x ∈ ball c f.r) : lemma eventually_eq_one : f =ᶠ[𝓝 c] 1 := f.eventually_eq_one_of_mem_ball (mem_ball_self f.r_pos) -protected lemma cont_diff_at {n} : - cont_diff_at ℝ n f x := +/-- `cont_diff_bump` is `𝒞ⁿ` in all its arguments. -/ +protected lemma _root_.cont_diff_at.cont_diff_bump {c g : X → E} + {f : ∀ x, cont_diff_bump_of_inner (c x)} {x : X} + (hc : cont_diff_at ℝ n c x) (hr : cont_diff_at ℝ n (λ x, (f x).r) x) + (hR : cont_diff_at ℝ n (λ x, (f x).R) x) + (hg : cont_diff_at ℝ n g x) : cont_diff_at ℝ n (λ x, f x (g x)) x := begin - rcases em (x = c) with rfl|hx, - { refine cont_diff_at.congr_of_eventually_eq _ f.eventually_eq_one, - rw pi.one_def, - exact cont_diff_at_const }, - { exact real.smooth_transition.cont_diff_at.comp x - (cont_diff_at.div_const $ cont_diff_at_const.sub $ - cont_diff_at_id.dist cont_diff_at_const hx) } + rcases eq_or_ne (g x) (c x) with hx|hx, + { have : (λ x, f x (g x)) =ᶠ[𝓝 x] (λ x, 1), + { have : dist (g x) (c x) < (f x).r, { simp_rw [hx, dist_self, (f x).r_pos] }, + have := continuous_at.eventually_lt (hg.continuous_at.dist hc.continuous_at) hr.continuous_at + this, + exact eventually_of_mem this + (λ x hx, (f x).one_of_mem_closed_ball (mem_set_of_eq.mp hx).le) }, + exact cont_diff_at_const.congr_of_eventually_eq this }, + { refine real.smooth_transition.cont_diff_at.comp x _, + refine ((hR.sub $ hg.dist hc hx).div (hR.sub hr) (sub_pos.mpr (f x).r_lt_R).ne') } end -protected lemma cont_diff {n} : - cont_diff ℝ n f := -cont_diff_iff_cont_diff_at.2 $ λ y, f.cont_diff_at +lemma _root_.cont_diff.cont_diff_bump {c g : X → E} {f : ∀ x, cont_diff_bump_of_inner (c x)} + (hc : cont_diff ℝ n c) (hr : cont_diff ℝ n (λ x, (f x).r)) (hR : cont_diff ℝ n (λ x, (f x).R)) + (hg : cont_diff ℝ n g) : cont_diff ℝ n (λ x, f x (g x)) := +by { rw [cont_diff_iff_cont_diff_at] at *, exact λ x, (hc x).cont_diff_bump (hr x) (hR x) (hg x) } -protected lemma cont_diff_within_at {s n} : - cont_diff_within_at ℝ n f s x := +protected lemma cont_diff : cont_diff ℝ n f := +cont_diff_const.cont_diff_bump cont_diff_const cont_diff_const cont_diff_id + +protected lemma cont_diff_at : cont_diff_at ℝ n f x := +f.cont_diff.cont_diff_at + +protected lemma cont_diff_within_at {s : set E} : cont_diff_within_at ℝ n f s x := f.cont_diff_at.cont_diff_within_at +protected lemma continuous : continuous f := +cont_diff_zero.mp f.cont_diff + +open measure_theory +variables [measurable_space E] {μ : measure E} + +/-- A bump function normed so that `∫ x, f.normed μ x ∂μ = 1`. -/ +protected def normed (μ : measure E) : E → ℝ := +λ x, f x / ∫ x, f x ∂μ + +lemma normed_def {μ : measure E} (x : E) : f.normed μ x = f x / ∫ x, f x ∂μ := +rfl + +lemma nonneg_normed (x : E) : 0 ≤ f.normed μ x := +div_nonneg f.nonneg $ integral_nonneg f.nonneg' + +lemma cont_diff_normed {n : with_top ℕ} : cont_diff ℝ n (f.normed μ) := +f.cont_diff.div_const + +lemma continuous_normed : continuous (f.normed μ) := +f.continuous.div_const + +lemma normed_sub (x : E) : f.normed μ (c - x) = f.normed μ (c + x) := +by simp_rw [f.normed_def, f.sub] + +lemma normed_neg (f : cont_diff_bump_of_inner (0 : E)) (x : E) : f.normed μ (- x) = f.normed μ x := +by simp_rw [f.normed_def, f.neg] + +variables [borel_space E] [finite_dimensional ℝ E] [is_locally_finite_measure μ] + +protected lemma integrable : integrable f μ := +f.continuous.integrable_of_has_compact_support f.has_compact_support + +protected lemma integrable_normed : integrable (f.normed μ) μ := +f.integrable.div_const _ + +variables [μ .is_open_pos_measure] + +lemma integral_pos : 0 < ∫ x, f x ∂μ := +begin + refine (integral_pos_iff_support_of_nonneg f.nonneg' f.integrable).mpr _, + rw [f.support_eq], + refine is_open_ball.measure_pos _ (nonempty_ball.mpr f.R_pos) +end + +lemma integral_normed : ∫ x, f.normed μ x ∂μ = 1 := +begin + simp_rw [cont_diff_bump_of_inner.normed, div_eq_mul_inv, mul_comm (f _), ← smul_eq_mul, + integral_smul], + exact inv_mul_cancel (f.integral_pos.ne') +end + +lemma support_normed_eq : support (f.normed μ) = metric.ball c f.R := +by simp_rw [cont_diff_bump_of_inner.normed, support_div, f.support_eq, + support_const f.integral_pos.ne', inter_univ] + +lemma tsupport_normed_eq : tsupport (f.normed μ) = metric.closed_ball c f.R := +by simp_rw [tsupport, f.support_normed_eq, closure_ball _ f.R_pos.ne'] + +lemma has_compact_support_normed : has_compact_support (f.normed μ) := +by simp_rw [has_compact_support, f.tsupport_normed_eq, is_compact_closed_ball] + +variable (μ) +lemma integral_normed_smul (z : X) [complete_space X] : ∫ x, f.normed μ x • z ∂μ = z := +by simp_rw [integral_smul_const, f.integral_normed, one_smul] + end cont_diff_bump_of_inner /-- `f : cont_diff_bump c`, where `c` is a point in a finite dimensional real vector space, is diff --git a/src/analysis/normed/group/basic.lean b/src/analysis/normed/group/basic.lean index 53efaf81902df..9b53dece7ca9e 100644 --- a/src/analysis/normed/group/basic.lean +++ b/src/analysis/normed/group/basic.lean @@ -158,6 +158,12 @@ by rw [← dist_zero_left, ← dist_add_left g 0 h, add_zero] @[simp] theorem dist_self_add_left (g h : E) : dist (g + h) g = ∥h∥ := by rw [dist_comm, dist_self_add_right] +@[simp] theorem dist_self_sub_right (g h : E) : dist g (g - h) = ∥h∥ := +by rw [sub_eq_add_neg, dist_self_add_right, norm_neg] + +@[simp] theorem dist_self_sub_left (g h : E) : dist (g - h) g = ∥h∥ := +by rw [dist_comm, dist_self_sub_right] + /-- **Triangle inequality** for the norm. -/ lemma norm_add_le (g h : E) : ∥g + h∥ ≤ ∥g∥ + ∥h∥ := by simpa [dist_eq_norm] using dist_triangle g 0 (-h) diff --git a/src/measure_theory/function/l1_space.lean b/src/measure_theory/function/l1_space.lean index b848c816beda9..8bf4ee4b080ca 100644 --- a/src/measure_theory/function/l1_space.lean +++ b/src/measure_theory/function/l1_space.lean @@ -833,6 +833,10 @@ lemma integrable.mul_const {f : α → ℝ} (h : integrable f μ) (c : ℝ) : integrable (λ x, f x * c) μ := by simp_rw [mul_comm, h.const_mul _] +lemma integrable.div_const {f : α → ℝ} (h : integrable f μ) (c : ℝ) : + integrable (λ x, f x / c) μ := +by simp_rw [div_eq_mul_inv, h.mul_const] + end normed_space section normed_space_over_complete_field diff --git a/src/order/cover.lean b/src/order/cover.lean index 68f1e034d37a4..0fd3a7fa85f0b 100644 --- a/src/order/cover.lean +++ b/src/order/cover.lean @@ -224,6 +224,18 @@ h.wcovby.Icc_eq end partial_order +section linear_order + +variables [linear_order α] {a b : α} + +lemma covby.Ioi_eq (h : a ⋖ b) : Ioi a = Ici b := +by rw [← Ioo_union_Ici_eq_Ioi h.lt, h.Ioo_eq, empty_union] + +lemma covby.Iio_eq (h : a ⋖ b) : Iio b = Iic a := +by rw [← Iic_union_Ioo_eq_Iio h.lt, h.Ioo_eq, union_empty] + +end linear_order + namespace set lemma wcovby_insert (x : α) (s : set α) : s ⩿ insert x s := diff --git a/src/topology/algebra/order/basic.lean b/src/topology/algebra/order/basic.lean index 64608f0e67d8f..24a1fcb5a2ec2 100644 --- a/src/topology/algebra/order/basic.lean +++ b/src/topology/algebra/order/basic.lean @@ -559,6 +559,22 @@ lemma continuous.if_le [topological_space γ] [Π x, decidable (f x ≤ g x)] {f continuous (λ x, if f x ≤ g x then f' x else g' x) := continuous_if_le hf hg hf'.continuous_on hg'.continuous_on hfg +lemma tendsto.eventually_lt {l : filter γ} {f g : γ → α} {y z : α} + (hf : tendsto f l (𝓝 y)) (hg : tendsto g l (𝓝 z)) (hyz : y < z) : ∀ᶠ x in l, f x < g x := +begin + by_cases h : y ⋖ z, + { filter_upwards [hf (Iio_mem_nhds hyz), hg (Ioi_mem_nhds hyz)], + rw [h.Iio_eq], + exact λ x hfx hgx, lt_of_le_of_lt hfx hgx }, + { obtain ⟨w, hyw, hwz⟩ := (not_covby_iff hyz).mp h, + filter_upwards [hf (Iio_mem_nhds hyw), hg (Ioi_mem_nhds hwz)], + exact λ x, lt_trans }, +end + +lemma continuous_at.eventually_lt {x₀ : β} (hf : continuous_at f x₀) + (hg : continuous_at g x₀) (hfg : f x₀ < g x₀) : ∀ᶠ x in 𝓝 x₀, f x < g x := +tendsto.eventually_lt hf hg hfg + @[continuity] lemma continuous.min (hf : continuous f) (hg : continuous g) : continuous (λb, min (f b) (g b)) := by { simp only [min_def], exact hf.if_le hg hf hg (λ x, id) } From 9db591650f53d70a8fbd2f42fe2342f4ef128277 Mon Sep 17 00:00:00 2001 From: Stuart Presnell Date: Fri, 22 Apr 2022 06:47:41 +0000 Subject: [PATCH 169/373] fix(data/fintype/basic): fix `fintype_of_option_equiv` (#13466) A type is a `fintype` if its successor (using `option`) is a `fintype` This fixes an error introduced in #13086. --- src/data/fintype/basic.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/fintype/basic.lean b/src/data/fintype/basic.lean index e464fe054d09e..8b555777549d8 100644 --- a/src/data/fintype/basic.lean +++ b/src/data/fintype/basic.lean @@ -846,8 +846,8 @@ def fintype_of_option {α : Type*} [fintype (option α)] : fintype α := ⟨finset.erase_none (fintype.elems (option α)), λ x, mem_erase_none.mpr (fintype.complete (some x))⟩ /-- A type is a `fintype` if its successor (using `option`) is a `fintype`. -/ -def fintype_of_option_equiv [fintype α] (f : option α ≃ β) : fintype β := -by { haveI := fintype.of_equiv (option α) f, exact fintype_of_option } +def fintype_of_option_equiv [fintype α] (f : α ≃ option β) : fintype β := +by { haveI := fintype.of_equiv _ f, exact fintype_of_option } instance {α : Type*} (β : α → Type*) [fintype α] [∀ a, fintype (β a)] : fintype (sigma β) := From 394dec321c38f11a47817548f04ce20c096dca83 Mon Sep 17 00:00:00 2001 From: Floris van Doorn Date: Fri, 22 Apr 2022 06:47:42 +0000 Subject: [PATCH 170/373] feat(order/filter/small_sets): define the filter of small sets (#13467) * Main author is @PatrickMassot * From the sphere eversion project * Required for convolutions Co-authored by: Patrick Massot --- src/order/filter/small_sets.lean | 72 ++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/order/filter/small_sets.lean diff --git a/src/order/filter/small_sets.lean b/src/order/filter/small_sets.lean new file mode 100644 index 0000000000000..9e3de47b556c3 --- /dev/null +++ b/src/order/filter/small_sets.lean @@ -0,0 +1,72 @@ +/- +Copyright (c) 2022 Patrick Massot. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Patrick Massot, Floris van Doorn +-/ +import order.filter.bases + +/-! +# The filter of small sets + +This file defines the filter of small sets w.r.t. a filter `f`, which is the largest filter +containing all powersets of members of `f`. + +`g` converges to `f.small_sets` if for all `s ∈ f`, eventually we have `g x ⊆ s`. + +An example usage is that if `f : ι → ℝ` is a family of nonnegative functions with integral 1, then +saying that `f` tendsto `(𝓝 0).small_sets` is a way of saying that `f` tends to the Dirac delta +distribution. +-/ + +open_locale filter +open filter set + +variables {α β : Type*} {ι : Sort*} + +namespace filter + +/-- The filter `f.small_sets` is the largest filter containing all powersets of members of `f`. + Note: `𝓟` is the principal filter and `𝒫` is the powerset. -/ +def small_sets (f : filter α) : filter (set α) := +⨅ t ∈ f, 𝓟 (𝒫 t) + +lemma small_sets_eq_generate {f : filter α} : f.small_sets = generate (powerset '' f.sets) := +by simp_rw [generate_eq_binfi, small_sets, infi_image, filter.mem_sets] + +lemma has_basis_small_sets (f : filter α) : + has_basis f.small_sets (λ t : set α, t ∈ f) powerset := +begin + apply has_basis_binfi_principal _ _, + { rintros u (u_in : u ∈ f) v (v_in : v ∈ f), + use [u ∩ v, inter_mem u_in v_in], + split, + rintros w (w_sub : w ⊆ u ∩ v), + exact w_sub.trans (inter_subset_left u v), + rintros w (w_sub : w ⊆ u ∩ v), + exact w_sub.trans (inter_subset_right u v) }, + { use univ, + exact univ_mem }, +end + +lemma has_basis.small_sets {f : filter α} {p : ι → Prop} {s : ι → set α} + (h : has_basis f p s) : has_basis f.small_sets p (λ i, 𝒫 (s i)) := +⟨begin + intros t, + rw f.has_basis_small_sets.mem_iff, + split, + { rintro ⟨u, u_in, hu : {v : set α | v ⊆ u} ⊆ t⟩, + rcases h.mem_iff.mp u_in with ⟨i, hpi, hiu⟩, + use [i, hpi], + apply subset.trans _ hu, + intros v hv x hx, + exact hiu (hv hx) }, + { rintro ⟨i, hi, hui⟩, + exact ⟨s i, h.mem_of_mem hi, hui⟩ } +end⟩ + +/-- `g` converges to `f.small_sets` if for all `s ∈ f`, eventually we have `g x ⊆ s`. -/ +lemma tendsto_small_sets_iff {la : filter α} {lb : filter β} {f : α → set β} : + tendsto f la lb.small_sets ↔ ∀ t ∈ lb, ∀ᶠ x in la, f x ⊆ t := +(has_basis_small_sets lb).tendsto_right_iff + +end filter From 3d24b09321313b9195dcb8f54fb59bf01753075c Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Fri, 22 Apr 2022 08:34:36 +0000 Subject: [PATCH 171/373] feat(algebra/ring/basic): define non-unital ring homs (#13430) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This defines a new bundled hom type and associated class for non-unital (even non-associative) (semi)rings. The associated notation introduced for these homs is `α →ₙ+* β` to parallel the `ring_hom` notation `α →+* β`, where `ₙ` stands for "non-unital". --- src/algebra/ring/basic.lean | 204 +++++++++++++++++++++++++++++++++++- 1 file changed, 203 insertions(+), 1 deletion(-) diff --git a/src/algebra/ring/basic.lean b/src/algebra/ring/basic.lean index 500f6dd13176d..571575878e96f 100644 --- a/src/algebra/ring/basic.lean +++ b/src/algebra/ring/basic.lean @@ -6,6 +6,7 @@ Neil Strickland -/ import algebra.divisibility import algebra.regular.basic +import data.pi /-! # Properties and homomorphisms of semirings and rings @@ -23,7 +24,8 @@ ring_hom, nonzero, domain, is_domain ## Notations -→+* for bundled ring homs (also use for semiring homs) +* `→+*` for bundled ring homs (also use for semiring homs) +* `→ₙ+*` for bundled non-unital ring homs (also use for non-unital semiring homs) ## Implementation notes @@ -335,6 +337,202 @@ lemma mul_right_apply {R : Type*} [non_unital_non_assoc_semiring R] (a r : R) : end add_monoid_hom +/-- Bundled non-unital semiring homomorphisms `R →ₙ+* S`; use this for bundled non-unital ring +homomorphisms too. + +When possible, instead of parametrizing results over `(f : R →ₙ+* S)`, +you should parametrize over `(F : Type*) [non_unital_ring_hom_class F R S] (f : F)`. + +When you extend this structure, make sure to extend `non_unital_ring_hom_class`. -/ +structure non_unital_ring_hom (R : Type*) (S : Type*) [non_unital_non_assoc_semiring R] + [non_unital_non_assoc_semiring S] extends R →ₙ* S, R →+ S + +infixr ` →ₙ+* `:25 := non_unital_ring_hom + +/-- Reinterpret a non-unital ring homomorphism `f : R →ₙ+* S` as a semigroup +homomorphism `R →ₙ* S`. The `simp`-normal form is `(f : R →ₙ* S)`. -/ +add_decl_doc non_unital_ring_hom.to_mul_hom + +/-- Reinterpret a non-unital ring homomorphism `f : R →ₙ+* S` as an additive +monoid homomorphism `R →+ S`. The `simp`-normal form is `(f : R →+ S)`. -/ +add_decl_doc non_unital_ring_hom.to_add_monoid_hom + +section non_unital_ring_hom_class + +/-- `non_unital_ring_hom_class F R S` states that `F` is a type of non-unital (semi)ring +homomorphisms. You should extend this class when you extend `non_unital_ring_hom`. -/ +class non_unital_ring_hom_class (F : Type*) (R S : out_param Type*) + [non_unital_non_assoc_semiring R] [non_unital_non_assoc_semiring S] + extends mul_hom_class F R S, add_monoid_hom_class F R S + +variables {F : Type*} [non_unital_non_assoc_semiring α] [non_unital_non_assoc_semiring β] + [non_unital_ring_hom_class F α β] + +instance : has_coe_t F (α →ₙ+* β) := +⟨λ f, { to_fun := f, map_zero' := map_zero f, map_mul' := map_mul f, map_add' := map_add f }⟩ + +end non_unital_ring_hom_class + +namespace non_unital_ring_hom + +section coe + +/-! +Throughout this section, some `semiring` arguments are specified with `{}` instead of `[]`. +See note [implicit instance arguments]. +-/ +variables {rα : non_unital_non_assoc_semiring α} {rβ : non_unital_non_assoc_semiring β} + +include rα rβ + +instance : non_unital_ring_hom_class (α →ₙ+* β) α β := +{ coe := non_unital_ring_hom.to_fun, + coe_injective' := λ f g h, by cases f; cases g; congr', + map_add := non_unital_ring_hom.map_add', + map_zero := non_unital_ring_hom.map_zero', + map_mul := non_unital_ring_hom.map_mul' } + +/-- Helper instance for when there's too many metavariables to apply `fun_like.has_coe_to_fun` +directly. +-/ +instance : has_coe_to_fun (α →ₙ+* β) (λ _, α → β) := ⟨non_unital_ring_hom.to_fun⟩ + +@[simp] lemma to_fun_eq_coe (f : α →ₙ+* β) : f.to_fun = f := rfl + +@[simp] lemma coe_mk (f : α → β) (h₁ h₂ h₃) : ⇑(⟨f, h₁, h₂, h₃⟩ : α →ₙ+* β) = f := rfl + +@[simp] lemma coe_coe {F : Type*} [non_unital_ring_hom_class F α β] (f : F) : + ((f : α →ₙ+* β) : α → β) = f := rfl + +@[simp] lemma coe_to_mul_hom (f : α →ₙ+* β) : ⇑f.to_mul_hom = f := rfl + +@[simp] lemma coe_mul_hom_mk (f : α → β) (h₁ h₂ h₃) : + ((⟨f, h₁, h₂, h₃⟩ : α →ₙ+* β) : α →ₙ* β) = ⟨f, h₁⟩ := +rfl + +@[simp] lemma coe_to_add_monoid_hom (f : α →ₙ+* β) : ⇑f.to_add_monoid_hom = f := rfl + +@[simp] lemma coe_add_monoid_hom_mk (f : α → β) (h₁ h₂ h₃) : + ((⟨f, h₁, h₂, h₃⟩ : α →ₙ+* β) : α →+ β) = ⟨f, h₂, h₃⟩ := +rfl + +/-- Copy of a `ring_hom` with a new `to_fun` equal to the old one. Useful to fix definitional +equalities. -/ +protected def copy (f : α →ₙ+* β) (f' : α → β) (h : f' = f) : α →ₙ+* β := +{ ..f.to_mul_hom.copy f' h, ..f.to_add_monoid_hom.copy f' h } + +end coe + +variables [rα : non_unital_non_assoc_semiring α] [rβ : non_unital_non_assoc_semiring β] + +section +include rα rβ + +variables (f : α →ₙ+* β) {x y : α} {rα rβ} + +@[ext] theorem ext ⦃f g : α →ₙ+* β⦄ (h : ∀ x, f x = g x) : f = g := +fun_like.ext _ _ h + +theorem ext_iff {f g : α →ₙ+* β} : f = g ↔ ∀ x, f x = g x := +fun_like.ext_iff + +@[simp] lemma mk_coe (f : α →ₙ+* β) (h₁ h₂ h₃) : non_unital_ring_hom.mk f h₁ h₂ h₃ = f := +ext $ λ _, rfl + +theorem coe_add_monoid_hom_injective : function.injective (coe : (α →ₙ+* β) → (α →+ β)) := +λ f g h, ext (λ x, add_monoid_hom.congr_fun h x) + +theorem coe_mul_hom_injective : function.injective (coe : (α →ₙ+* β) → (α →ₙ* β)) := +λ f g h, ext (λ x, mul_hom.congr_fun h x) + +end + +/-- The identity non-unital ring homomorphism from a non-unital semiring to itself. -/ +protected def id (α : Type*) [non_unital_non_assoc_semiring α] : α →ₙ+* α := +by refine {to_fun := id, ..}; intros; refl + +include rα rβ + +instance : has_zero (α →ₙ+* β) := +has_zero.mk + { to_fun := 0, + map_mul' := λ x y, (mul_zero (0 : β)).symm, + map_zero' := rfl, + map_add' := λ x y, (add_zero (0 : β)).symm } + +instance : inhabited (α →ₙ+* β) := ⟨0⟩ + +@[simp] lemma coe_zero : ⇑(0 : α →ₙ+* β) = 0 := rfl +@[simp] lemma zero_apply (x : α) : (0 : α →ₙ+* β) x = 0 := rfl + +omit rβ + +@[simp] lemma id_apply (x : α) : non_unital_ring_hom.id α x = x := rfl +@[simp] lemma coe_add_monoid_hom_id : + (non_unital_ring_hom.id α : α →+ α) = add_monoid_hom.id α := rfl +@[simp] lemma coe_mul_hom_id : (non_unital_ring_hom.id α : α →ₙ* α) = mul_hom.id α := rfl + +variable {rγ : non_unital_non_assoc_semiring γ} +include rβ rγ + +/-- Composition of non-unital ring homomorphisms is a non-unital ring homomorphism. -/ +def comp (g : β →ₙ+* γ) (f : α →ₙ+* β) : α →ₙ+* γ := +{ ..g.to_mul_hom.comp f.to_mul_hom, ..g.to_add_monoid_hom.comp f.to_add_monoid_hom } + +/-- Composition of non-unital ring homomorphisms is associative. -/ +lemma comp_assoc {δ} {rδ : non_unital_non_assoc_semiring δ} (f : α →ₙ+* β) (g : β →ₙ+* γ) + (h : γ →ₙ+* δ) : (h.comp g).comp f = h.comp (g.comp f) := rfl + +@[simp] lemma coe_comp (g : β →ₙ+* γ) (f : α →ₙ+* β) : ⇑(g.comp f) = g ∘ f := rfl +@[simp] lemma comp_apply (g : β →ₙ+* γ) (f : α →ₙ+* β) (x : α) : g.comp f x = g (f x) := rfl + +@[simp] lemma coe_comp_add_monoid_hom (g : β →ₙ+* γ) (f : α →ₙ+* β) : + (g.comp f : α →+ γ) = (g : β →+ γ).comp f := rfl +@[simp] lemma coe_comp_mul_hom (g : β →ₙ+* γ) (f : α →ₙ+* β) : + (g.comp f : α →ₙ* γ) = (g : β →ₙ* γ).comp f := rfl + +@[simp] lemma comp_zero (g : β →ₙ+* γ) : g.comp (0 : α →ₙ+* β) = 0 := by { ext, simp } +@[simp] lemma zero_comp (f : α →ₙ+* β) : (0 : β →ₙ+* γ).comp f = 0 := by { ext, refl } + +omit rγ + +@[simp] lemma comp_id (f : α →ₙ+* β) : f.comp (non_unital_ring_hom.id α) = f := ext $ λ x, rfl +@[simp] lemma id_comp (f : α →ₙ+* β) : (non_unital_ring_hom.id β).comp f = f := ext $ λ x, rfl + +omit rβ + +instance : monoid_with_zero (α →ₙ+* α) := +{ one := non_unital_ring_hom.id α, + mul := comp, + mul_one := comp_id, + one_mul := id_comp, + mul_assoc := λ f g h, comp_assoc _ _ _, + zero := 0, + mul_zero := comp_zero, + zero_mul := zero_comp } + +lemma one_def : (1 : α →ₙ+* α) = non_unital_ring_hom.id α := rfl + +@[simp] lemma coe_one : ⇑(1 : α →ₙ+* α) = id := rfl + +lemma mul_def (f g : α →ₙ+* α) : f * g = f.comp g := rfl + +@[simp] lemma coe_mul (f g : α →ₙ+* α) : ⇑(f * g) = f ∘ g := rfl + +include rβ rγ + +lemma cancel_right {g₁ g₂ : β →ₙ+* γ} {f : α →ₙ+* β} (hf : surjective f) : + g₁.comp f = g₂.comp f ↔ g₁ = g₂ := +⟨λ h, ext $ hf.forall.2 (ext_iff.1 h), λ h, h ▸ rfl⟩ + +lemma cancel_left {g : β →ₙ+* γ} {f₁ f₂ : α →ₙ+* β} (hg : injective g) : + g.comp f₁ = g.comp f₂ ↔ f₁ = f₂ := +⟨λ h, ext $ λ x, hg $ by rw [← comp_apply, h, comp_apply], λ h, h ▸ rfl⟩ + +omit rα rβ rγ + +end non_unital_ring_hom + /-- Bundled semiring homomorphisms; use this for bundled ring homomorphisms too. This extends from both `monoid_hom` and `monoid_with_zero_hom` in order to put the fields in a @@ -382,6 +580,10 @@ instance : has_coe_t F (α →+* β) := ⟨λ f, { to_fun := f, map_zero' := map_zero f, map_one' := map_one f, map_mul' := map_mul f, map_add' := map_add f }⟩ +@[priority 100] +instance ring_hom_class.to_non_unital_ring_hom_class : non_unital_ring_hom_class F α β := +{ .. ‹ring_hom_class F α β› } + end ring_hom_class namespace ring_hom From 9abfff391ab56625d3a8a38cf5a93e0c190934f1 Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Fri, 22 Apr 2022 11:41:15 +0000 Subject: [PATCH 172/373] chore(analysis/inner_product_space/lax_milgram): tidy some proofs (#13604) --- .../inner_product_space/lax_milgram.lean | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/analysis/inner_product_space/lax_milgram.lean b/src/analysis/inner_product_space/lax_milgram.lean index 85a09de31cf85..15c7b647b2708 100644 --- a/src/analysis/inner_product_space/lax_milgram.lean +++ b/src/analysis/inner_product_space/lax_milgram.lean @@ -53,9 +53,9 @@ begin intro v, by_cases h : 0 < ∥v∥, { refine (mul_le_mul_right h).mp _, - exact calc C * ∥v∥ * ∥v∥ + calc C * ∥v∥ * ∥v∥ ≤ B v v : coercivity v - ... = ⟪B♯ v, v⟫_ℝ : by simp + ... = ⟪B♯ v, v⟫_ℝ : (continuous_linear_map_of_bilin_apply ℝ B v v).symm ... ≤ ∥B♯ v∥ * ∥v∥ : real_inner_le_norm (B♯ v) v, }, { have : v = 0 := by simpa using h, simp [this], } @@ -82,7 +82,7 @@ end lemma closed_range (coercive : is_coercive B) : is_closed (B♯.range : set V) := begin - rcases coercive.antilipschitz with ⟨_, _, antilipschitz⟩, + rcases coercive.antilipschitz with ⟨_, _, antilipschitz⟩, exact antilipschitz.is_closed_range B♯.uniform_continuous, end @@ -92,16 +92,16 @@ begin rw ← B♯.range.orthogonal_orthogonal, rw submodule.eq_top_iff', intros v w mem_w_orthogonal, - rcases coercive with ⟨C, C_ge_0, coercivity⟩, - have : C * ∥w∥ * ∥w∥ ≤ 0 := - calc C * ∥w∥ * ∥w∥ - ≤ B w w : coercivity w - ... = ⟪B♯ w, w⟫_ℝ : by simp - ... = 0 : mem_w_orthogonal _ ⟨w, rfl⟩, - have : ∥w∥ * ∥w∥ ≤ 0 := by nlinarith, - have h : ∥w∥ = 0 := by nlinarith [norm_nonneg w], - have w_eq_zero : w = 0 := by simpa using h, - simp [w_eq_zero], + rcases coercive with ⟨C, C_pos, coercivity⟩, + obtain rfl : w = 0, + { rw [←norm_eq_zero, ←mul_self_eq_zero, ←mul_right_inj' C_pos.ne', mul_zero, ←mul_assoc], + apply le_antisymm, + { calc C * ∥w∥ * ∥w∥ + ≤ B w w : coercivity w + ... = ⟪B♯ w, w⟫_ℝ : (continuous_linear_map_of_bilin_apply ℝ B w w).symm + ... = 0 : mem_w_orthogonal _ ⟨w, rfl⟩ }, + { exact mul_nonneg (mul_nonneg C_pos.le (norm_nonneg w)) (norm_nonneg w) } }, + exact inner_zero_left, end /-- From 62205c274d37071ff5d1e2b13dc0d9e1d0e86e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Fri, 22 Apr 2022 12:15:32 +0000 Subject: [PATCH 173/373] refactor(data/nat/factorization): Infer arguments (#13595) --- src/data/nat/factorization.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/data/nat/factorization.lean b/src/data/nat/factorization.lean index ea92303cd189c..b61a536d91e26 100644 --- a/src/data/nat/factorization.lean +++ b/src/data/nat/factorization.lean @@ -90,7 +90,7 @@ prime.pos (prime_of_mem_factorization hp) lemma le_of_mem_factorization {n p : ℕ} (h : p ∈ n.factorization.support) : p ≤ n := le_of_mem_factors (factor_iff_mem_factorization.mp h) -lemma factorization_eq_zero_of_non_prime (n p : ℕ) (hp : ¬p.prime) : n.factorization p = 0 := +lemma factorization_eq_zero_of_non_prime (n : ℕ) {p : ℕ} (hp : ¬p.prime) : n.factorization p = 0 := not_mem_support_iff.1 (mt prime_of_mem_factorization hp) lemma prime.factorization_pos_of_dvd {n p : ℕ} (hp : p.prime) (hn : n ≠ 0) (h : p ∣ n) : @@ -206,7 +206,7 @@ end lemma pow_factorization_dvd (n p : ℕ) : p ^ n.factorization p ∣ n := begin - by_cases hp : p.prime, swap, { simp [factorization_eq_zero_of_non_prime n p hp] }, + by_cases hp : p.prime, swap, { simp [factorization_eq_zero_of_non_prime n hp] }, rw ←factors_count_eq, apply dvd_of_factors_subperm (pow_ne_zero _ hp.ne_zero), rw [hp.factors_pow, list.subperm_ext_iff], @@ -276,7 +276,7 @@ begin nat.div_mul_cancel h], end -lemma dvd_iff_div_factorization_eq_tsub (d n : ℕ) (hd : d ≠ 0) (hdn : d ≤ n) : +lemma dvd_iff_div_factorization_eq_tsub {d n : ℕ} (hd : d ≠ 0) (hdn : d ≤ n) : d ∣ n ↔ (n / d).factorization = n.factorization - d.factorization := begin refine ⟨factorization_div, _⟩, @@ -301,7 +301,7 @@ begin refine ⟨λ h p k _ hpkd, dvd_trans hpkd h, _⟩, rw [←factorization_le_iff_dvd hd hn, finsupp.le_def], intros h p, - by_cases pp : prime p, swap, { simp [factorization_eq_zero_of_non_prime d p pp] }, + by_cases pp : prime p, swap, { simp [factorization_eq_zero_of_non_prime d pp] }, rw ←pp.pow_dvd_iff_le_factorization hn, exact h p _ pp (pow_factorization_dvd _ _) end From 6729cca2b8ac6723957708643ea5609bf70f6062 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Fri, 22 Apr 2022 12:15:34 +0000 Subject: [PATCH 174/373] feat(set_theory/game/pgame): simp + private (#13596) --- src/set_theory/game/pgame.lean | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/set_theory/game/pgame.lean b/src/set_theory/game/pgame.lean index 4926c1feea896..5d2c1a1b3ef12 100644 --- a/src/set_theory/game/pgame.lean +++ b/src/set_theory/game/pgame.lean @@ -347,7 +347,7 @@ theorem lt_mk_of_le {x : pgame} {yl yr : Type*} {yL : yl → pgame} {yR i} : (x ≤ yL i) → x < ⟨yl, yr, yL, yR⟩ := by { cases x, rw mk_lt_mk, exact λ h, or.inl ⟨_, h⟩ } -theorem not_le_lt {x y : pgame} : +private theorem not_le_lt {x y : pgame} : (¬ x ≤ y ↔ y < x) ∧ (¬ x < y ↔ y ≤ x) := begin induction x with xl xr xL xR IHxl IHxr generalizing y, @@ -358,8 +358,8 @@ begin and_comm, or_comm, IHxl, IHxr, IHyl, IHyr, iff_self, and_self] end -theorem not_le {x y : pgame} : ¬ x ≤ y ↔ y < x := not_le_lt.1 -theorem not_lt {x y : pgame} : ¬ x < y ↔ y ≤ x := not_le_lt.2 +@[simp] theorem not_le {x y : pgame} : ¬ x ≤ y ↔ y < x := not_le_lt.1 +@[simp] theorem not_lt {x y : pgame} : ¬ x < y ↔ y ≤ x := not_le_lt.2 @[refl] protected theorem le_refl : ∀ x : pgame, x ≤ x | ⟨l, r, L, R⟩ := by rw mk_le_mk; exact From f7dac5eae2e4f675f03302a2f3cd4f18a7bbe9e1 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 22 Apr 2022 12:15:35 +0000 Subject: [PATCH 175/373] feat(logic/basic): add `auto_param.out` and `opt_param.out` (#13599) --- src/logic/basic.lean | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/logic/basic.lean b/src/logic/basic.lean index 571a140f04b96..0dbc7530909b1 100644 --- a/src/logic/basic.lean +++ b/src/logic/basic.lean @@ -215,6 +215,16 @@ lemma fact_iff {p : Prop} : fact p ↔ p := ⟨λ h, h.1, λ h, ⟨h⟩⟩ Π i₂ j₂ i₁ j₁, φ i₁ j₁ i₂ j₂ := λ i₂ j₂ i₁ j₁, f i₁ j₁ i₂ j₂ +/-- If `x : α . tac_name` then `x.out : α`. These are definitionally equal, but this can +nevertheless be useful for various reasons, e.g. to apply further projection notation or in an +argument to `simp`. -/ +def auto_param.out {α : Sort*} {n : name} (x : auto_param α n) : α := x + +/-- If `x : α := d` then `x.out : α`. These are definitionally equal, but this can +nevertheless be useful for various reasons, e.g. to apply further projection notation or in an +argument to `simp`. -/ +def opt_param.out {α : Sort*} {d : α} (x : α := d) : α := x + end miscellany open function From 631890bf90e76818b80c57c00291380c0329143d Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Fri, 22 Apr 2022 12:15:36 +0000 Subject: [PATCH 176/373] chore(data/rat/basic): tidy some proofs (#13603) --- src/data/rat/basic.lean | 52 ++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/data/rat/basic.lean b/src/data/rat/basic.lean index 892223b9477fe..520e4e6214389 100644 --- a/src/data/rat/basic.lean +++ b/src/data/rat/basic.lean @@ -83,7 +83,7 @@ def mk_pnat (n : ℤ) : ℕ+ → ℚ | ⟨d, dpos⟩ := let n' := n.nat_abs, g := n'.gcd d in ⟨n / g, d / g, begin apply (nat.le_div_iff_mul_le _ _ (nat.gcd_pos_of_pos_right _ dpos)).2, - simp, exact nat.le_of_dvd dpos (nat.gcd_dvd_right _ _) + rw one_mul, exact nat.le_of_dvd dpos (nat.gcd_dvd_right _ _) end, begin have : int.nat_abs (n / ↑g) = n' / g, { cases int.nat_abs_eq n with e e; rw e, { refl }, @@ -113,7 +113,11 @@ theorem mk_nat_eq (n d) : mk_nat n d = n /. d := rfl @[simp] theorem mk_zero (n) : n /. 0 = 0 := rfl @[simp] theorem zero_mk_pnat (n) : mk_pnat 0 n = 0 := -by cases n; simp [mk_pnat]; change int.nat_abs 0 with 0; simp *; refl +begin + cases n with n npos, + simp only [mk_pnat, int.nat_abs_zero, nat.div_self npos, nat.gcd_zero_left, int.zero_div], + refl +end @[simp] theorem zero_mk_nat (n) : mk_nat 0 n = 0 := by by_cases n = 0; simp [*, mk_nat] @@ -137,6 +141,9 @@ begin { apply neg_injective, simp [this h] } end +theorem mk_ne_zero {a b : ℤ} (b0 : b ≠ 0) : a /. b ≠ 0 ↔ a ≠ 0 := +(mk_eq_zero b0).not + theorem mk_eq : ∀ {a b c d : ℤ} (hb : b ≠ 0) (hd : d ≠ 0), a /. b = c /. d ↔ a * d = c * b := suffices ∀ a b c d hb hd, mk_pnat a ⟨b, hb⟩ = mk_pnat c ⟨d, hd⟩ ↔ a * d = c * b, @@ -247,7 +254,7 @@ begin refine (int.nat_abs_dvd.1 $ int.dvd_nat_abs.1 $ int.coe_nat_dvd.2 $ c.dvd_of_dvd_mul_right _), have := congr_arg int.nat_abs e, - simp [int.nat_abs_mul, int.nat_abs_of_nat] at this, simp [this] + simp only [int.nat_abs_mul, int.nat_abs_of_nat] at this, simp [this] end theorem denom_dvd (a b : ℤ) : ((a /. b).denom : ℤ) ∣ b := @@ -351,9 +358,9 @@ begin unfold rat.inv, rw num_denom' }, { unfold rat.inv, rw num_denom', refl } }, have n0 : n ≠ 0, - { refine mt (λ (n0 : n = 0), _) a0, - subst n0, simp at ha, - exact (mk_eq_zero b0).1 ha }, + { rintro rfl, + rw [rat.zero_mk, mk_eq_zero b0] at ha, + exact a0 ha }, have d0 := ne_of_gt (int.coe_nat_lt.2 h), have ha := (mk_eq b0 d0).1 ha, apply (mk_eq n0 a0).2, @@ -425,8 +432,7 @@ protected theorem mul_add : a * (b + c) = a * b + a * c := by rw [rat.mul_comm, rat.add_mul, rat.mul_comm, rat.mul_comm c a] protected theorem zero_ne_one : 0 ≠ (1:ℚ) := -suffices (1:ℚ) = 0 → false, by cc, -by { rw [← mk_one_one, mk_eq_zero one_ne_zero], exact one_ne_zero } +by { rw [ne_comm, ← mk_one_one, mk_ne_zero one_ne_zero], exact one_ne_zero } protected theorem mul_inv_cancel : a ≠ 0 → a * a⁻¹ = 1 := num_denom_cases_on' a $ λ n d h a0, @@ -529,8 +535,7 @@ assume : d = 0, hq $ by simpa [this] using hqnd lemma mk_ne_zero_of_ne_zero {n d : ℤ} (h : n ≠ 0) (hd : d ≠ 0) : n /. d ≠ 0 := -assume : n /. d = 0, -h $ (mk_eq_zero hd).1 this +(mk_ne_zero hd).mpr h lemma mul_num_denom (q r : ℚ) : q * r = (q.num * r.num) /. ↑(q.denom * r.denom) := have hq' : (↑q.denom : ℤ) ≠ 0, by have := denom_ne_zero q; simpa, @@ -550,22 +555,21 @@ else ... = (q.num * r.denom) /. (q.denom * r.num) : mul_def (by simpa using denom_ne_zero q) hr lemma num_denom_mk {q : ℚ} {n d : ℤ} (hd : d ≠ 0) (qdf : q = n /. d) : - ∃ c : ℤ, n = c * q.num ∧ d = c * q.denom := -(eq_or_ne n 0).by_cases -(λ hn, by simp [*] at *) $ λ hn, -have hq : q ≠ 0, from - assume : q = 0, - hn $ (rat.mk_eq_zero hd).1 (by cc), -have q.num /. q.denom = n /. d, by rwa [num_denom], -have q.num * d = n * ↑(q.denom), from (rat.mk_eq (by simp [rat.denom_ne_zero]) hd).1 this, + ∃ c : ℤ, n = c * q.num ∧ d = c * q.denom := begin - existsi n / q.num, - have hqdn : q.num ∣ n, begin rw qdf, apply rat.num_dvd, assumption end, - split, + obtain rfl|hn := eq_or_ne n 0, + { simp [qdf] }, + have : q.num * d = n * ↑(q.denom), + { refine (rat.mk_eq _ hd).mp _, + { exact int.coe_nat_ne_zero.mpr (rat.denom_ne_zero _) }, + { rwa [num_denom] } }, + have hqdn : q.num ∣ n, + { rw qdf, exact rat.num_dvd _ hd }, + refine ⟨n / q.num, _, _⟩, { rw int.div_mul_cancel hqdn }, - { apply int.eq_mul_div_of_mul_eq_mul_of_dvd_left, - { apply rat.num_ne_zero_of_ne_zero hq }, - repeat { assumption } } + { refine int.eq_mul_div_of_mul_eq_mul_of_dvd_left _ hqdn this, + rw qdf, + exact rat.num_ne_zero_of_ne_zero ((mk_ne_zero hd).mpr hn) } end theorem mk_pnat_num (n : ℤ) (d : ℕ+) : From a74df9b5af0cd5adfbf16d512831d7d31b820721 Mon Sep 17 00:00:00 2001 From: MichaelStollBayreuth Date: Fri, 22 Apr 2022 15:16:42 +0000 Subject: [PATCH 177/373] feat(number_theory/legendre_symbol): add file quadratic_char.lean (#13503) This adds the file `quadratic_char.lean` in `number_theory/legendre_symbol/`. This file contains (apart from some more general stuff on finite fields that is useful for what is done in the file) the definition of the quadratic character on a finite field `F` (with values in the integers) and a number of statements of properties. It also defines quadratic characters on `zmod 4` and `zmod 8` that will be useful for the supplements to the law of quadratic reciprocity. --- src/algebra/parity.lean | 9 + .../legendre_symbol/quadratic_char.lean | 329 ++++++++++++++++++ 2 files changed, 338 insertions(+) create mode 100644 src/number_theory/legendre_symbol/quadratic_char.lean diff --git a/src/algebra/parity.lean b/src/algebra/parity.lean index 69f2c7620ec19..048cac9bdf775 100644 --- a/src/algebra/parity.lean +++ b/src/algebra/parity.lean @@ -69,6 +69,11 @@ lemma is_square.map [mul_one_class α] [mul_one_class β] [monoid_hom_class F α is_square m → is_square (f m) := by { rintro ⟨m, rfl⟩, exact ⟨f m, by simp⟩ } +/-- Create a decidability instance for `is_square` on `fintype`s. -/ +instance is_square_decidable [fintype α] [has_mul α] [decidable_eq α] : + decidable_pred (is_square : α → Prop) := +λ a, fintype.decidable_exists_fintype + section monoid variables [monoid α] @@ -82,6 +87,10 @@ by { rintro ⟨c, rfl⟩ a, simp_rw [←two_mul, pow_mul, neg_sq] } lemma even.neg_one_pow (h : even n) : (-1 : α) ^ n = 1 := by rw [h.neg_pow, one_pow] +/-- `0` is always a square (in a monoid with zero). -/ +lemma is_square_zero (M : Type*) [monoid_with_zero M] : is_square (0 : M) := +by { use 0, simp only [mul_zero] } + end monoid @[to_additive] diff --git a/src/number_theory/legendre_symbol/quadratic_char.lean b/src/number_theory/legendre_symbol/quadratic_char.lean new file mode 100644 index 0000000000000..c50770912b196 --- /dev/null +++ b/src/number_theory/legendre_symbol/quadratic_char.lean @@ -0,0 +1,329 @@ +/- +Copyright (c) 2022 Michael Stoll. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Michael Stoll +-/ +import tactic.basic +import field_theory.finite.basic + +/-! +# Quadratic characters of finite fields + +This file defines the quadratic character on a finite field `F` and proves +some basic statements about it. + +## Tags + +quadratic character +-/ + +/-! +### Some general results on finite fields +-/ + +section general + +/-- If `ring_char R = 2`, where `R` is a finite reduced commutative ring, +then every `a : R` is a square. -/ +lemma is_square_of_char_two' {R : Type*} [fintype R] [comm_ring R] [is_reduced R] [char_p R 2] + (a : R) : is_square a := +exists_imp_exists (λ b h, pow_two b ▸ eq.symm h) $ + ((fintype.bijective_iff_injective_and_card _).mpr ⟨frobenius_inj R 2, rfl⟩).surjective a + +namespace finite_field + +variables {F : Type*} [field F] [fintype F] + +/-- In a finite field of characteristic `2`, all elements are squares. -/ +lemma is_square_of_char_two (hF : ring_char F = 2) (a : F) : is_square a := +begin + haveI hF' : char_p F 2 := ring_char.of_eq hF, + exact is_square_of_char_two' a, +end + +/-- If the finite field `F` has characteristic `≠ 2`, then it has odd cardinatlity. -/ +lemma odd_card_of_char_ne_two (hF : ring_char F ≠ 2) : fintype.card F % 2 = 1 := +begin + rcases finite_field.card F (ring_char F) with ⟨ n, hp, h ⟩, + have h₁ : odd ((ring_char F) ^ (n : ℕ)) := + odd.pow ((or_iff_right hF).mp (nat.prime.eq_two_or_odd' hp)), + rwa [← h, nat.odd_iff] at h₁, +end + +/-- Characteristic `≠ 2` implies that `-1 ≠ 1`. -/ +lemma neg_one_ne_one_of_char_ne_two (hF : ring_char F ≠ 2) : (-1 : F) ≠ 1 := +begin + have hc := char_p.char_is_prime F (ring_char F), + haveI hF' : fact (2 < ring_char F) := ⟨ lt_of_le_of_ne (nat.prime.two_le hc) (ne.symm hF) ⟩, + exact char_p.neg_one_ne_one _ (ring_char F), +end + +/-- If `F` has odd characteristic, then for nonzero `a : F`, we have that `a ^ (#F / 2) = ±1`. -/ +lemma pow_dichotomy (hF : ring_char F ≠ 2) {a : F} (ha : a ≠ 0) : + a^(fintype.card F / 2) = 1 ∨ a^(fintype.card F / 2) = -1 := +begin + have h₁ := finite_field.pow_card_sub_one_eq_one a ha, + set q := fintype.card F with hq, + have hq : q % 2 = 1 := finite_field.odd_card_of_char_ne_two hF, + have h₂ := nat.two_mul_odd_div_two hq, + rw [← h₂, mul_comm, pow_mul, pow_two] at h₁, + exact mul_self_eq_one_iff.mp h₁, +end + +/-- A unit `a` of a finite field `F` of odd characteristic is a square +if and only if `a ^ (#F / 2) = 1`. -/ +lemma unit_is_sqare_iff (hF : ring_char F ≠ 2) (a : Fˣ) : + is_square a ↔ a ^ (fintype.card F / 2) = 1 := +begin + classical, + obtain ⟨g, hg⟩ := is_cyclic.exists_generator Fˣ, + obtain ⟨n, hn⟩ : a ∈ submonoid.powers g, { rw mem_powers_iff_mem_zpowers, apply hg }, + have hodd := nat.two_mul_odd_div_two (finite_field.odd_card_of_char_ne_two hF), + split, + { rintro ⟨y, rfl⟩, + rw [← pow_two, ← pow_mul, hodd], + apply_fun (@coe Fˣ F _), + { push_cast, + exact finite_field.pow_card_sub_one_eq_one (y : F) (units.ne_zero y), }, + { exact units.ext, }, }, + { subst a, assume h, + have key : 2 * (fintype.card F / 2) ∣ n * (fintype.card F / 2), + { rw [← pow_mul] at h, + rw [hodd, ← fintype.card_units, ← order_of_eq_card_of_forall_mem_zpowers hg], + apply order_of_dvd_of_pow_eq_one h }, + have : 0 < fintype.card F / 2 := nat.div_pos fintype.one_lt_card (by norm_num), + obtain ⟨m, rfl⟩ := nat.dvd_of_mul_dvd_mul_right this key, + refine ⟨g ^ m, _⟩, + rw [mul_comm, pow_mul, pow_two], }, +end + +/-- A non-zero `a : F` is a square if and only if `a ^ (#F / 2) = 1`. -/ +lemma is_square_iff (hF : ring_char F ≠ 2) {a : F} (ha : a ≠ 0) : + is_square a ↔ a ^ (fintype.card F / 2) = 1 := +begin + apply (iff_congr _ (by simp [units.ext_iff])).mp + (finite_field.unit_is_sqare_iff hF (units.mk0 a ha)), + simp only [is_square, units.ext_iff, units.coe_mk0, units.coe_mul], + split, { rintro ⟨y, hy⟩, exact ⟨y, hy⟩ }, + { rintro ⟨y, rfl⟩, + have hy : y ≠ 0, { rintro rfl, simpa [zero_pow] using ha, }, + refine ⟨units.mk0 y hy, _⟩, simp, } +end + +/-- In a finite field of odd characteristic, not every element is a square. -/ +lemma exists_nonsquare (hF : ring_char F ≠ 2) : ∃ (a : F), ¬ is_square a := +begin + -- idea: the squaring map on `F` is not injetive, hence not surjective + let sq : F → F := λ x, x^2, + have h : ¬ function.injective sq, + { simp only [function.injective, not_forall, exists_prop], + use [-1, 1], + split, + { simp only [sq, one_pow, neg_one_sq], }, + { exact finite_field.neg_one_ne_one_of_char_ne_two hF, }, }, + have h₁ := mt (fintype.injective_iff_surjective.mpr) h, -- sq not surjective + push_neg at h₁, + cases h₁ with a h₁, + use a, + simp only [is_square, sq, not_exists, ne.def] at h₁ ⊢, + intros b hb, + rw ← pow_two at hb, + exact (h₁ b hb.symm), +end + +end finite_field + +end general + +namespace char + +/-! +### Definition of the quadratic character + +We define the quadratic character of a finite field `F` with values in ℤ. +-/ + +section define + +/-- Define the quadratic character with values in ℤ on a monoid with zero `α`. +It takes the value zero at zero; for non-zero argument `a : α`, it is `1` +if `a` is a square, otherwise it is `-1`. + +This only deserves the name "character" when it is multiplicative, +e.g., when `α` is a finite field. See `quadratic_char_mul`. +-/ +def quadratic_char (α : Type*) [monoid_with_zero α] [decidable_eq α] + [decidable_pred (is_square : α → Prop)] (a : α) : ℤ := +if a = 0 then 0 else if is_square a then 1 else -1 + +end define + +/-! +### Basic properties of the quadratic character + +We prove some properties of the quadratic character. +We work with a finite field `F` here. +The interesting case is when the characteristic of `F` is odd. +-/ + +section quadratic_char + +variables {F : Type*} [field F] [fintype F] [decidable_eq F] + +/-- Some basic API lemmas -/ +lemma quadratic_char_eq_zero_iff (a : F) : quadratic_char F a = 0 ↔ a = 0 := +begin + simp only [quadratic_char], + by_cases ha : a = 0, + { simp only [ha, eq_self_iff_true, if_true], }, + { simp [ha], + split_ifs; simp only [neg_eq_zero, one_ne_zero, not_false_iff], }, +end + +@[simp] +lemma quadratic_char_zero : quadratic_char F 0 = 0 := +by simp only [quadratic_char, eq_self_iff_true, if_true, id.def] + +@[simp] +lemma quadratic_char_one : quadratic_char F 1 = 1 := +by simp only [quadratic_char, one_ne_zero, is_square_one, if_true, if_false, id.def] + +/-- For nonzero `a : F`, `quadratic_char F a = 1 ↔ is_square a`. -/ +lemma quadratic_char_one_iff_is_square {a : F} (ha : a ≠ 0) : + quadratic_char F a = 1 ↔ is_square a := +by { simp [quadratic_char, ha, (dec_trivial : (-1 : ℤ) ≠ 1)], tauto } + +/-- The quadratic character takes the value `1` on nonzero squares. -/ +lemma quadratic_char_sq_one' {a : F} (ha : a ≠ 0) : quadratic_char F (a ^ 2) = 1 := +by simp only [quadratic_char, ha, pow_eq_zero_iff, nat.succ_pos', is_square_sq, if_true, if_false] + +/-- If `ring_char F = 2`, then `quadratic_char F` takes the value `1` on nonzero elements. -/ +lemma quadratic_char_eq_one_of_char_two (hF : ring_char F = 2) {a : F} (ha : a ≠ 0) : + quadratic_char F a = 1 := +begin + simp only [quadratic_char, ha, if_false, ite_eq_left_iff], + intro h, + exfalso, + exact h (finite_field.is_square_of_char_two hF a), +end + +/-- If `ring_char F` is odd, then `quadratic_char F a` can be computed in +terms of `a ^ (fintype.card F / 2)`. -/ +lemma quadratic_char_eq_pow_of_char_ne_two (hF : ring_char F ≠ 2) {a : F} (ha : a ≠ 0) : + quadratic_char F a = if a ^ (fintype.card F / 2) = 1 then 1 else -1 := +begin + simp only [quadratic_char, ha, if_false], + simp_rw finite_field.is_square_iff hF ha, +end + +/-- The quadratic character is multiplicative. -/ +lemma quadratic_char_mul (a b : F) : + quadratic_char F (a * b) = quadratic_char F a * quadratic_char F b := +begin + by_cases ha : a = 0, + { rw [ha, zero_mul, quadratic_char_zero, zero_mul], }, + -- now `a ≠ 0` + by_cases hb : b = 0, + { rw [hb, mul_zero, quadratic_char_zero, mul_zero], }, + -- now `a ≠ 0` and `b ≠ 0` + have hab := mul_ne_zero ha hb, + by_cases hF : ring_char F = 2, + { -- case `ring_char F = 2` + rw [quadratic_char_eq_one_of_char_two hF ha, + quadratic_char_eq_one_of_char_two hF hb, + quadratic_char_eq_one_of_char_two hF hab, + mul_one], }, + { -- case of odd characteristic + rw [quadratic_char_eq_pow_of_char_ne_two hF ha, + quadratic_char_eq_pow_of_char_ne_two hF hb, + quadratic_char_eq_pow_of_char_ne_two hF hab, + mul_pow], + cases finite_field.pow_dichotomy hF hb with hb' hb', + { simp only [hb', mul_one, eq_self_iff_true, if_true], }, + { have h := finite_field.neg_one_ne_one_of_char_ne_two hF, -- `-1 ≠ 1` + simp only [hb', h, mul_neg, mul_one, if_false, ite_mul, neg_mul], + cases finite_field.pow_dichotomy hF ha with ha' ha'; + simp only [ha', h, neg_neg, eq_self_iff_true, if_true, if_false], }, }, +end + +/-- The quadratic character is a homomorphism of monoids with zero. -/ +@[simps] def quadratic_char_hom : F →*₀ ℤ := +{ to_fun := quadratic_char F, + map_zero' := quadratic_char_zero, + map_one' := quadratic_char_one, + map_mul' := quadratic_char_mul } + +/-- The square of the quadratic character on nonzero arguments is `1`. -/ +lemma quadratic_char_sq_one {a : F} (ha : a ≠ 0) : (quadratic_char F a)^2 = 1 := +by rwa [pow_two, ← quadratic_char_mul, ← pow_two, quadratic_char_sq_one'] + +/-- The quadratic character is `1` or `-1` on nonzero arguments. -/ +lemma quadratic_char_dichotomy {a : F} (ha : a ≠ 0) : + quadratic_char F a = 1 ∨ quadratic_char F a = -1 := +(sq_eq_one_iff (quadratic_char F a)).mp (quadratic_char_sq_one ha) + +/-- If `F` has odd characteristic, then `quadratic_char F` takes the value `-1`. -/ +lemma quadratic_char_exists_neg_one (hF : ring_char F ≠ 2) : ∃ a, quadratic_char F a = -1 := +begin + cases (finite_field.exists_nonsquare hF) with b h₁, + have hb : b ≠ 0 := by { intro hf, rw hf at h₁, exact h₁ (is_square_zero F), }, + use b, + simp only [quadratic_char, hb, if_false, ite_eq_right_iff], + tauto, +end + +open_locale big_operators + +/-- The sum over the values of the quadratic character is zero when the characteristic is odd. -/ +lemma quadratic_char_sum_zero (hF : ring_char F ≠ 2) : ∑ (a : F), quadratic_char F a = 0 := +begin + cases (quadratic_char_exists_neg_one hF) with b hb, + have h₀ : b ≠ 0 := by + { intro hf, + rw [hf, quadratic_char_zero, zero_eq_neg] at hb, + exact one_ne_zero hb, }, + let mul_b : F → F := λ x, b * x, + have h₁ : ∑ (a : F), quadratic_char F (b * a) = ∑ (a : F), quadratic_char F a := + by refine fintype.sum_bijective _ (mul_left_bijective₀ b h₀) _ _ (λ x, rfl), + simp only [quadratic_char_mul] at h₁, + rw [← finset.mul_sum, hb, neg_mul, one_mul] at h₁, + exact eq_zero_of_neg_eq h₁, +end + +end quadratic_char + +end char + +/-! +### Quadratic characters mod 4 and 8 + +We define the primitive quadratic characters `χ₄`on `zmod 4` +and `χ₈`, `χ₈'` on `zmod 8`. +-/ + +namespace zmod + +section quad_char_mod_p + +/-- Define the nontrivial quadratic character on `zmod 4`, `χ₄`. +It corresponds to the extension `ℚ(√-1)/ℚ`. -/ + +@[simps] def χ₄ : (zmod 4) →*₀ ℤ := +{ to_fun := (![0,1,0,-1] : (zmod 4 → ℤ)), + map_zero' := rfl, map_one' := rfl, map_mul' := by dec_trivial } + +/-- Define the first primitive quadratic character on `zmod 8`, `χ₈`. +It corresponds to the extension `ℚ(√2)/ℚ`. -/ +@[simps] def χ₈ : (zmod 8) →*₀ ℤ := +{ to_fun := (![0,1,0,-1,0,-1,0,1] : (zmod 8 → ℤ)), + map_zero' := rfl, map_one' := rfl, map_mul' := by dec_trivial } + +/-- Define the second primitive quadratic character on `zmod 8`, `χ₈'`. +It corresponds to the extension `ℚ(√-2)/ℚ`. -/ +@[simps] def χ₈' : (zmod 8) →*₀ ℤ := +{ to_fun := (![0,1,0,1,0,-1,0,-1] : (zmod 8 → ℤ)), + map_zero' := rfl, map_one' := rfl, map_mul' := by dec_trivial } + +end quad_char_mod_p + +end zmod From 79ac4c81ed507f2d6f148169b05cbd044c4aec55 Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Fri, 22 Apr 2022 15:16:44 +0000 Subject: [PATCH 178/373] chore(data/polynomial/degree/definitions): simplify sum_fin, degree_C_le (#13564) --- src/data/polynomial/degree/definitions.lean | 19 +++++++++++-------- src/order/bounded_order.lean | 11 +++++++++++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/data/polynomial/degree/definitions.lean b/src/data/polynomial/degree/definitions.lean index e646f136c8d5b..82eb9ffaf1c16 100644 --- a/src/data/polynomial/degree/definitions.lean +++ b/src/data/polynomial/degree/definitions.lean @@ -151,6 +151,10 @@ mt $ λ h, by rw [nat_degree, h, option.get_or_else_coe] theorem nat_degree_le_iff_degree_le {n : ℕ} : nat_degree p ≤ n ↔ degree p ≤ n := with_bot.get_or_else_bot_le_iff +lemma nat_degree_lt_iff_degree_lt (hp : p ≠ 0) : + p.nat_degree < n ↔ p.degree < ↑n := +with_bot.get_or_else_bot_lt_iff $ degree_eq_bot.not.mpr hp + alias polynomial.nat_degree_le_iff_degree_le ↔ . . lemma nat_degree_le_nat_degree [semiring S] {q : S[X]} (hpq : p.degree ≤ q.degree) : @@ -161,7 +165,11 @@ with_bot.gi_get_or_else_bot.gc.monotone_l hpq by { rw [degree, ← monomial_zero_left, support_monomial 0 _ ha, sup_singleton], refl } lemma degree_C_le : degree (C a) ≤ 0 := -by by_cases h : a = 0; [rw [h, C_0], rw [degree_C h]]; [exact bot_le, exact le_rfl] +begin + by_cases h : a = 0, + { rw [h, C_0], exact bot_le }, + { rw [degree_C h], exact le_rfl } +end lemma degree_C_lt : degree (C a) < 1 := degree_C_le.trans_lt $ with_bot.coe_lt_coe.mpr zero_lt_one @@ -274,13 +282,8 @@ lemma sum_fin [add_comm_monoid S] begin by_cases hp : p = 0, { rw [hp, sum_zero_index, finset.sum_eq_zero], intros i _, exact hf i }, - rw [degree_eq_nat_degree hp, with_bot.coe_lt_coe] at hn, - calc ∑ (i : fin n), f i (p.coeff i) - = ∑ i in finset.range n, f i (p.coeff i) : fin.sum_univ_eq_sum_range (λ i, f i (p.coeff i)) _ - ... = ∑ i in p.support, f i (p.coeff i) : (finset.sum_subset - (supp_subset_range_nat_degree_succ.trans (finset.range_subset.mpr hn)) - (λ i _ hi, show f i (p.coeff i) = 0, by rw [not_mem_support_iff.mp hi, hf])).symm - ... = p.sum f : p.sum_def _ + rw [sum_over_range' _ hf n ((nat_degree_lt_iff_degree_lt hp).mpr hn), + fin.sum_univ_eq_sum_range (λ i, f i (p.coeff i))], end lemma as_sum_range' (p : R[X]) (n : ℕ) (w : p.nat_degree < n) : diff --git a/src/order/bounded_order.lean b/src/order/bounded_order.lean index 020791e8681b7..dc463a734e37e 100644 --- a/src/order/bounded_order.lean +++ b/src/order/bounded_order.lean @@ -639,6 +639,17 @@ lemma get_or_else_bot_le_iff [has_le α] [order_bot α] {a : with_bot α} {b : a.get_or_else ⊥ ≤ b ↔ a ≤ b := by cases a; simp [none_eq_bot, some_eq_coe] +lemma get_or_else_bot_lt_iff [partial_order α] [order_bot α] {a : with_bot α} {b : α} + (ha : a ≠ ⊥) : + a.get_or_else ⊥ < b ↔ a < b := +begin + obtain ⟨a, rfl⟩ := ne_bot_iff_exists.mp ha, + simp only [lt_iff_le_and_ne, get_or_else_bot_le_iff, and.congr_right_iff], + intro h, + apply iff.not, + simp only [with_bot.coe_eq_coe, option.get_or_else_coe, iff_self], +end + instance [semilattice_sup α] : semilattice_sup (with_bot α) := { sup := option.lift_or_get (⊔), le_sup_left := λ o₁ o₂ a ha, From 355d68abdda3680e01337219f5b91fd5162b262c Mon Sep 17 00:00:00 2001 From: Eric Rodriguez Date: Fri, 22 Apr 2022 15:16:45 +0000 Subject: [PATCH 179/373] chore(ring_theory/roots_of_unity): primitive roots are not zero (#13587) Co-authored-by: Eric Rodriguez <37984851+ericrbg@users.noreply.github.com> --- src/ring_theory/roots_of_unity.lean | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ring_theory/roots_of_unity.lean b/src/ring_theory/roots_of_unity.lean index 2e53f390fe8f5..b1b717c3442d1 100644 --- a/src/ring_theory/roots_of_unity.lean +++ b/src/ring_theory/roots_of_unity.lean @@ -433,6 +433,9 @@ variables {M₀ : Type*} [comm_monoid_with_zero M₀] lemma zero [nontrivial M₀] : is_primitive_root (0 : M₀) 0 := ⟨pow_zero 0, λ l hl, by simpa [zero_pow_eq, show ∀ p, ¬p → false ↔ p, from @not_not] using hl⟩ +protected lemma ne_zero [nontrivial M₀] {ζ : M₀} (h : is_primitive_root ζ k) : k ≠ 0 → ζ ≠ 0 := +mt $ λ hn, h.unique (hn.symm ▸ is_primitive_root.zero) + end comm_monoid_with_zero section comm_group From 2e83d61757d49ec6a11f72c4d62bebc704f14760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Fri, 22 Apr 2022 18:15:48 +0000 Subject: [PATCH 180/373] feat(topology/metric_space/hausdorff_distance): Thickening the closure (#13515) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `thickening δ (closure s) = thickening δ s` and other simple lemmas. Also rename `inf_edist_le_inf_edist_of_subset` to `inf_edist_anti` and make arguments to `mem_thickening_iff` implicit. --- src/data/real/ennreal.lean | 2 + src/data/set/lattice.lean | 10 +++ .../metric_space/hausdorff_distance.lean | 84 +++++++++++++++---- 3 files changed, 78 insertions(+), 18 deletions(-) diff --git a/src/data/real/ennreal.lean b/src/data/real/ennreal.lean index 0738b25560f24..8109d6fd616ff 100644 --- a/src/data/real/ennreal.lean +++ b/src/data/real/ennreal.lean @@ -1559,6 +1559,8 @@ by simp [ennreal.of_real] @[simp] lemma zero_eq_of_real {p : ℝ} : 0 = ennreal.of_real p ↔ p ≤ 0 := eq_comm.trans of_real_eq_zero +alias ennreal.of_real_eq_zero ↔ _ ennreal.of_real_of_nonpos + lemma of_real_le_iff_le_to_real {a : ℝ} {b : ℝ≥0∞} (hb : b ≠ ∞) : ennreal.of_real a ≤ b ↔ a ≤ ennreal.to_real b := begin diff --git a/src/data/set/lattice.lean b/src/data/set/lattice.lean index a97b5621ddd5a..a623ef7a53a1e 100644 --- a/src/data/set/lattice.lean +++ b/src/data/set/lattice.lean @@ -1649,3 +1649,13 @@ noncomputable def Union_eq_sigma_of_disjoint {t : α → set β} (equiv.of_bijective _ $ sigma_to_Union_bijective t h).symm end set + +open set + +variables [complete_lattice β] + +lemma supr_Union (s : ι → set α) (f : α → β) : (⨆ a ∈ (⋃ i, s i), f a) = ⨆ i (a ∈ s i), f a := +by { rw supr_comm, simp_rw [mem_Union, supr_exists] } + +lemma infi_Union (s : ι → set α) (f : α → β) : (⨅ a ∈ (⋃ i, s i), f a) = ⨅ i (a ∈ s i), f a := +by { rw infi_comm, simp_rw [mem_Union, infi_exists] } diff --git a/src/topology/metric_space/hausdorff_distance.lean b/src/topology/metric_space/hausdorff_distance.lean index c667e7240e7ce..4c8671b8711e5 100644 --- a/src/topology/metric_space/hausdorff_distance.lean +++ b/src/topology/metric_space/hausdorff_distance.lean @@ -32,12 +32,13 @@ universes u v w open classical set function topological_space filter +variables {ι : Sort*} {α : Type u} {β : Type v} + namespace emetric section inf_edist -variables {α : Type u} {β : Type v} [pseudo_emetric_space α] [pseudo_emetric_space β] {x y : α} -{s t : set α} {Φ : α → β} +variables [pseudo_emetric_space α] [pseudo_emetric_space β] {x y : α} {s t : set α} {Φ : α → β} /-! ### Distance of a point to a set as a function into `ℝ≥0∞`. -/ @@ -53,6 +54,10 @@ by simp only [inf_edist, le_infi_iff] @[simp] lemma inf_edist_union : inf_edist x (s ∪ t) = inf_edist x s ⊓ inf_edist x t := infi_union +@[simp] lemma inf_edist_Union (f : ι → set α) (x : α) : + inf_edist x (⋃ i, f i) = ⨅ i, inf_edist x (f i) := +infi_Union f _ + /-- The edist to a singleton is the edistance to the single point of this singleton -/ @[simp] lemma inf_edist_singleton : inf_edist x {y} = edist x y := infi_singleton @@ -64,9 +69,8 @@ lemma inf_edist_le_edist_of_mem (h : y ∈ s) : inf_edist x s ≤ edist x y := i lemma inf_edist_zero_of_mem (h : x ∈ s) : inf_edist x s = 0 := nonpos_iff_eq_zero.1 $ @edist_self _ _ x ▸ inf_edist_le_edist_of_mem h -/-- The edist is monotonous with respect to inclusion -/ -lemma inf_edist_le_inf_edist_of_subset (h : s ⊆ t) : inf_edist x t ≤ inf_edist x s := -infi_le_infi_of_subset h +/-- The edist is antitone with respect to inclusion. -/ +lemma inf_edist_anti (h : s ⊆ t) : inf_edist x t ≤ inf_edist x s := infi_le_infi_of_subset h /-- The edist to a set is `< r` iff there exists a point in the set at edistance `< r` -/ lemma inf_edist_lt_iff {r : ℝ≥0∞} : inf_edist x s < r ↔ ∃ y ∈ s, edist x y < r := @@ -79,6 +83,9 @@ calc (⨅ z ∈ s, edist x z) ≤ ⨅ z ∈ s, edist y z + edist x y : infi₂_mono $ λ z hz, (edist_triangle _ _ _).trans_eq (add_comm _ _) ... = (⨅ z ∈ s, edist y z) + edist x y : by simp only [ennreal.infi_add] +lemma inf_edist_le_edist_add_inf_edist : inf_edist x s ≤ edist x y + inf_edist y s := +by { rw add_comm, exact inf_edist_le_inf_edist_add_edist } + /-- The edist to a set depends continuously on the point -/ @[continuity] lemma continuous_inf_edist : continuous (λx, inf_edist x s) := @@ -88,7 +95,7 @@ continuous_of_le_add_edist 1 (by simp) $ /-- The edist to a set and to its closure coincide -/ lemma inf_edist_closure : inf_edist x (closure s) = inf_edist x s := begin - refine le_antisymm (inf_edist_le_inf_edist_of_subset subset_closure) _, + refine le_antisymm (inf_edist_anti subset_closure) _, refine ennreal.le_of_forall_pos_le_add (λε εpos h, _), have ε0 : 0 < (ε / 2 : ℝ≥0∞) := by simpa [pos_iff_ne_zero] using εpos, have : inf_edist x (closure s) < inf_edist x (closure s) + ε/2, @@ -182,8 +189,7 @@ by rw Hausdorff_edist section Hausdorff_edist -variables {α : Type u} {β : Type v} [pseudo_emetric_space α] [pseudo_emetric_space β] - {x y : α} {s t u : set α} {Φ : α → β} +variables [pseudo_emetric_space α] [pseudo_emetric_space β] {x y : α} {s t u : set α} {Φ : α → β} /-- The Hausdorff edistance of a set to itself vanishes -/ @[simp] lemma Hausdorff_edist_self : Hausdorff_edist s s = 0 := @@ -370,8 +376,7 @@ modulo some tedious rewriting of inequalities from one to the other. -/ namespace metric section -variables {α : Type u} {β : Type v} [pseudo_metric_space α] [pseudo_metric_space β] - {s t u : set α} {x y : α} {Φ : α → β} +variables [pseudo_metric_space α] [pseudo_metric_space β] {s t u : set α} {x y : α} {Φ : α → β} open emetric /-! ### Distance of a point to a set as a function into `ℝ`. -/ @@ -418,7 +423,7 @@ lemma inf_dist_le_inf_dist_of_subset (h : s ⊆ t) (hs : s.nonempty) : begin have ht : t.nonempty := hs.mono h, rw [inf_dist, inf_dist, ennreal.to_real_le_to_real (inf_edist_ne_top ht) (inf_edist_ne_top hs)], - exact inf_edist_le_inf_edist_of_subset h + exact inf_edist_anti h end /-- The minimal distance to a set is `< r` iff there exists a point in this set at distance `< r` -/ @@ -787,7 +792,7 @@ end --section section thickening -variables {α : Type u} [pseudo_emetric_space α] +variables [pseudo_emetric_space α] {δ : ℝ} {s : set α} {x : α} open emetric @@ -795,6 +800,9 @@ open emetric of those points that are at distance less than `δ` from some point of `E`. -/ def thickening (δ : ℝ) (E : set α) : set α := {x : α | inf_edist x E < ennreal.of_real δ} +lemma mem_thickening_iff_inf_edist_lt : x ∈ thickening δ s ↔ inf_edist x s < ennreal.of_real δ := +iff.rfl + /-- The (open) thickening equals the preimage of an open interval under `inf_edist`. -/ lemma thickening_eq_preimage_inf_edist (δ : ℝ) (E : set α) : thickening δ E = (λ x, inf_edist x E) ⁻¹' (Iio (ennreal.of_real δ)) := rfl @@ -807,6 +815,9 @@ continuous.is_open_preimage continuous_inf_edist _ is_open_Iio @[simp] lemma thickening_empty (δ : ℝ) : thickening δ (∅ : set α) = ∅ := by simp only [thickening, set_of_false, inf_edist_empty, not_top_lt] +lemma thickening_of_nonpos (hδ : δ ≤ 0) (s : set α) : thickening δ s = ∅ := +eq_empty_of_forall_not_mem $ λ x, ((ennreal.of_real_of_nonpos hδ).trans_le bot_le).not_lt + /-- The (open) thickening `thickening δ E` of a fixed subset `E` is an increasing function of the thickening radius `δ`. -/ lemma thickening_mono {δ₁ δ₂ : ℝ} (hle : δ₁ ≤ δ₂) (E : set α) : @@ -817,7 +828,7 @@ preimage_mono (Iio_subset_Iio (ennreal.of_real_le_of_real hle)) an increasing function of the subset `E`. -/ lemma thickening_subset_of_subset (δ : ℝ) {E₁ E₂ : set α} (h : E₁ ⊆ E₂) : thickening δ E₁ ⊆ thickening δ E₂ := -λ _ hx, lt_of_le_of_lt (inf_edist_le_inf_edist_of_subset h) hx +λ _ hx, lt_of_le_of_lt (inf_edist_anti h) hx lemma mem_thickening_iff_exists_edist_lt {δ : ℝ} (E : set α) (x : α) : x ∈ thickening δ E ↔ ∃ z ∈ E, edist x z < ennreal.of_real δ := @@ -827,7 +838,7 @@ variables {X : Type u} [pseudo_metric_space X] /-- A point in a metric space belongs to the (open) `δ`-thickening of a subset `E` if and only if it is at distance less than `δ` from some point of `E`. -/ -lemma mem_thickening_iff {δ : ℝ} (E : set X) (x : X) : +lemma mem_thickening_iff {E : set X} {x : X} : x ∈ thickening δ E ↔ (∃ z ∈ E, dist x z < δ) := begin have key_iff : ∀ (z : X), edist x z < ennreal.of_real δ ↔ dist x z < δ, @@ -848,7 +859,7 @@ by { ext, simp [mem_thickening_iff] } union of balls of radius `δ` centered at points of `E`. -/ lemma thickening_eq_bUnion_ball {δ : ℝ} {E : set X} : thickening δ E = ⋃ x ∈ E, ball x δ := -by { ext x, rw mem_Union₂, exact mem_thickening_iff E x, } +by { ext x, rw mem_Union₂, exact mem_thickening_iff } lemma bounded.thickening {δ : ℝ} {E : set X} (h : bounded E) : bounded (thickening δ E) := @@ -857,7 +868,7 @@ begin rcases h.subset_ball x with ⟨R, hR⟩, refine (bounded_iff_subset_ball x).2 ⟨R + δ, _⟩, assume y hy, - rcases (mem_thickening_iff _ _).1 hy with ⟨z, zE, hz⟩, + rcases mem_thickening_iff.1 hy with ⟨z, zE, hz⟩, calc dist y x ≤ dist z x + dist y z : by { rw add_comm, exact dist_triangle _ _ _ } ... ≤ R + δ : add_le_add (hR zE) hz.le end @@ -866,7 +877,7 @@ end thickening --section section cthickening -variables {α : Type*} [pseudo_emetric_space α] +variables [pseudo_emetric_space α] {δ ε : ℝ} {s : set α} {x : α} open emetric @@ -874,6 +885,9 @@ open emetric of those points that are at infimum distance at most `δ` from `E`. -/ def cthickening (δ : ℝ) (E : set α) : set α := {x : α | inf_edist x E ≤ ennreal.of_real δ} +@[simp] lemma mem_cthickening_iff : x ∈ cthickening δ s ↔ inf_edist x s ≤ ennreal.of_real δ := +iff.rfl + lemma mem_cthickening_of_edist_le (x y : α) (δ : ℝ) (E : set α) (h : y ∈ E) (h' : edist x y ≤ ennreal.of_real δ) : x ∈ cthickening δ E := @@ -931,7 +945,7 @@ end an increasing function of the subset `E`. -/ lemma cthickening_subset_of_subset (δ : ℝ) {E₁ E₂ : set α} (h : E₁ ⊆ E₂) : cthickening δ E₁ ⊆ cthickening δ E₂ := -λ _ hx, le_trans (inf_edist_le_inf_edist_of_subset h) hx +λ _ hx, le_trans (inf_edist_anti h) hx lemma cthickening_subset_thickening {δ₁ : ℝ≥0} {δ₂ : ℝ} (hlt : (δ₁ : ℝ) < δ₂) (E : set α) : cthickening δ₁ E ⊆ thickening δ₂ E := @@ -991,6 +1005,24 @@ lemma self_subset_cthickening {δ : ℝ} (E : set α) : E ⊆ cthickening δ E := subset_closure.trans (closure_subset_cthickening δ E) +@[simp] lemma thickening_union (δ : ℝ) (s t : set α) : + thickening δ (s ∪ t) = thickening δ s ∪ thickening δ t := +by simp_rw [thickening, inf_edist_union, inf_eq_min, min_lt_iff, set_of_or] + +@[simp] lemma cthickening_union (δ : ℝ) (s t : set α) : + cthickening δ (s ∪ t) = cthickening δ s ∪ cthickening δ t := +by simp_rw [cthickening, inf_edist_union, inf_eq_min, min_le_iff, set_of_or] + +@[simp] lemma thickening_Union (δ : ℝ) (f : ι → set α) : + thickening δ (⋃ i, f i) = ⋃ i, thickening δ (f i) := +by simp_rw [thickening, inf_edist_Union, infi_lt_iff, set_of_exists] + +@[simp] lemma thickening_closure : thickening δ (closure s) = thickening δ s := +by simp_rw [thickening, inf_edist_closure] + +@[simp] lemma cthickening_closure : cthickening δ (closure s) = cthickening δ s := +by simp_rw [cthickening, inf_edist_closure] + lemma cthickening_eq_Inter_cthickening' {δ : ℝ} (s : set ℝ) (hsδ : s ⊆ Ioi δ) (hs : ∀ ε, δ < ε → (s ∩ (Ioc δ ε)).nonempty) (E : set α) : cthickening δ E = ⋂ ε ∈ s, cthickening ε E := @@ -1121,6 +1153,22 @@ begin exact mem_bUnion yE D2, end +lemma inf_edist_le_inf_edist_cthickening_add : + inf_edist x s ≤ inf_edist x (cthickening δ s) + ennreal.of_real δ := +begin + refine le_of_forall_lt' (λ r h, _), + simp_rw [←lt_tsub_iff_right, inf_edist_lt_iff, mem_cthickening_iff] at h, + obtain ⟨y, hy, hxy⟩ := h, + exact inf_edist_le_edist_add_inf_edist.trans_lt ((ennreal.add_lt_add_of_lt_of_le + (hy.trans_lt ennreal.of_real_lt_top).ne hxy hy).trans_le + (tsub_add_cancel_of_le $ le_self_add.trans (lt_tsub_iff_left.1 hxy).le).le), +end + +lemma inf_edist_le_inf_edist_thickening_add : + inf_edist x s ≤ inf_edist x (thickening δ s) + ennreal.of_real δ := +inf_edist_le_inf_edist_cthickening_add.trans $ + add_le_add_right (inf_edist_anti $ thickening_subset_cthickening _ _) _ + end cthickening --section end metric --namespace From 695e0b70e336cc1042100b29986334a148b248f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Fri, 22 Apr 2022 18:15:49 +0000 Subject: [PATCH 181/373] feat(analysis/convex/strict_convex_space): Verify strict convexity from fixed scalars (#13548) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prove that `∀ x y : E, ∥x∥ ≤ 1 → ∥y∥ ≤ 1 → x ≠ y → ∥a • x + b • y∥ < 1` for **fixed** `a` and `b` is enough for `E` to be a strictly convex space. --- src/analysis/convex/strict_convex_space.lean | 48 ++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/analysis/convex/strict_convex_space.lean b/src/analysis/convex/strict_convex_space.lean index 2f8524729458f..e34040c3aae52 100644 --- a/src/analysis/convex/strict_convex_space.lean +++ b/src/analysis/convex/strict_convex_space.lean @@ -106,6 +106,54 @@ begin smul_right_inj hb.ne'] using (h _ _ H).norm_smul_eq.symm end +lemma strict_convex_space.of_norm_add_lt_aux {a b c d : ℝ} (ha : 0 < a) (hab : a + b = 1) + (hc : 0 < c) (hd : 0 < d) (hcd : c + d = 1) (hca : c ≤ a) {x y : E} (hy : ∥y∥ ≤ 1) + (hxy : ∥a • x + b • y∥ < 1) : + ∥c • x + d • y∥ < 1 := +begin + have hbd : b ≤ d, + { refine le_of_add_le_add_left (hab.trans_le _), + rw ←hcd, + exact add_le_add_right hca _ }, + have h₁ : 0 < c / a := div_pos hc ha, + have h₂ : 0 ≤ d - c / a * b, + { rw [sub_nonneg, mul_comm_div', ←le_div_iff' hc], + exact div_le_div hd.le hbd hc hca }, + calc ∥c • x + d • y∥ = ∥(c / a) • (a • x + b • y) + (d - c / a * b) • y∥ + : by rw [smul_add, ←mul_smul, ←mul_smul, div_mul_cancel _ ha.ne', sub_smul, + add_add_sub_cancel] + ... ≤ ∥(c / a) • (a • x + b • y)∥ + ∥(d - c / a * b) • y∥ : norm_add_le _ _ + ... = c / a * ∥a • x + b • y∥ + (d - c / a * b) * ∥y∥ + : by rw [norm_smul_of_nonneg h₁.le, norm_smul_of_nonneg h₂] + ... < c / a * 1 + (d - c / a * b) * 1 + : add_lt_add_of_lt_of_le (mul_lt_mul_of_pos_left hxy h₁) (mul_le_mul_of_nonneg_left hy h₂) + ... = 1 : begin + nth_rewrite 0 ←hab, + rw [mul_add, div_mul_cancel _ ha.ne', mul_one, add_add_sub_cancel, hcd], + end, +end + +/-- Strict convexity is equivalent to `∥a • x + b • y∥ < 1` for all `x` and `y` of norm at most `1` +and all strictly positive `a` and `b` such that `a + b = 1`. This shows that we only need to check +it for fixed `a` and `b`. -/ +lemma strict_convex_space.of_norm_add_lt {a b : ℝ} (ha : 0 < a) (hb : 0 < b) (hab : a + b = 1) + (h : ∀ x y : E, ∥x∥ ≤ 1 → ∥y∥ ≤ 1 → x ≠ y → ∥a • x + b • y∥ < 1) : + strict_convex_space ℝ E := +begin + refine strict_convex_space.of_strict_convex_closed_unit_ball _ (λ x hx y hy hxy c d hc hd hcd, _), + rw [interior_closed_ball (0 : E) one_ne_zero, mem_ball_zero_iff], + rw mem_closed_ball_zero_iff at hx hy, + obtain hca | hac := le_total c a, + { exact strict_convex_space.of_norm_add_lt_aux ha hab hc hd hcd hca hy (h _ _ hx hy hxy) }, + rw add_comm at ⊢ hab hcd, + refine strict_convex_space.of_norm_add_lt_aux hb hab hd hc hcd _ hx _, + { refine le_of_add_le_add_right (hcd.trans_le _), + rw ←hab, + exact add_le_add_left hac _ }, + { rw add_comm, + exact h _ _ hx hy hxy } +end + variables [strict_convex_space ℝ E] {x y z : E} {a b r : ℝ} /-- If `x ≠ y` belong to the same closed ball, then a convex combination of `x` and `y` with From 9c3cb72cfb6d9c16e6539a94b6e22dd004e67efb Mon Sep 17 00:00:00 2001 From: tb65536 Date: Fri, 22 Apr 2022 18:15:50 +0000 Subject: [PATCH 182/373] feat(data/int/basic): Add unit lemmas (#13565) This PR adds a few more unit lemmas, and cleans up some of the proofs. --- src/algebra/group_power/lemmas.lean | 3 --- src/data/int/basic.lean | 15 ++++++++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/algebra/group_power/lemmas.lean b/src/algebra/group_power/lemmas.lean index 39df5aeb588a6..2410fcf2a94bc 100644 --- a/src/algebra/group_power/lemmas.lean +++ b/src/algebra/group_power/lemmas.lean @@ -520,9 +520,6 @@ theorem nat.cast_le_pow_div_sub {K : Type*} [linear_ordered_field K] {a : K} (H namespace int -lemma units_sq (u : ℤˣ) : u ^ 2 = 1 := -(sq u).symm ▸ units_mul_self u - alias int.units_sq ← int.units_pow_two lemma units_pow_eq_pow_mod_two (u : ℤˣ) (n : ℕ) : u ^ n = u ^ (n % 2) := diff --git a/src/data/int/basic.lean b/src/data/int/basic.lean index 6c0a073f65b8f..b0889489c4f38 100644 --- a/src/data/int/basic.lean +++ b/src/data/int/basic.lean @@ -1317,11 +1317,20 @@ by rw [is_unit_iff_nat_abs_eq, abs_eq_nat_abs, ←int.coe_nat_one, coe_nat_inj'] lemma of_nat_is_unit {n : ℕ} : is_unit (n : ℤ) ↔ is_unit n := by rw [nat.is_unit_iff, is_unit_iff_nat_abs_eq, nat_abs_of_nat] -lemma units_inv_eq_self (u : ℤˣ) : u⁻¹ = u := -(units_eq_one_or u).elim (λ h, h.symm ▸ rfl) (λ h, h.symm ▸ rfl) +lemma is_unit_mul_self {a : ℤ} (ha : is_unit a) : a * a = 1 := +(is_unit_eq_one_or ha).elim (λ h, h.symm ▸ rfl) (λ h, h.symm ▸ rfl) + +lemma is_unit_sq {a : ℤ} (ha : is_unit a) : a ^ 2 = 1 := +by rw [sq, is_unit_mul_self ha] + +@[simp] lemma units_sq (u : ℤˣ) : u ^ 2 = 1 := +by rw [units.ext_iff, units.coe_pow, units.coe_one, is_unit_sq u.is_unit] @[simp] lemma units_mul_self (u : ℤˣ) : u * u = 1 := -(units_eq_one_or u).elim (λ h, h.symm ▸ rfl) (λ h, h.symm ▸ rfl) +by rw [←sq, units_sq] + +@[simp] lemma units_inv_eq_self (u : ℤˣ) : u⁻¹ = u := +by rw [inv_eq_iff_mul_eq_one, units_mul_self] -- `units.coe_mul` is a "wrong turn" for the simplifier, this undoes it and simplifies further @[simp] lemma units_coe_mul_self (u : ℤˣ) : (u * u : ℤ) = 1 := From ad3e66728408691b74d4d1c44cac81c1c58dec2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Fri, 22 Apr 2022 20:06:16 +0000 Subject: [PATCH 183/373] feat(order/chain): Flags (#13089) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define the type of maximal chains, aka flags, of an order. Co-authored-by: Violeta Hernández <[vi.hdz.p@gmail.com](mailto:vi.hdz.p@gmail.com)> --- src/data/set/pairwise.lean | 9 ++++ src/order/chain.lean | 85 +++++++++++++++++++++++++++++++++++--- 2 files changed, 89 insertions(+), 5 deletions(-) diff --git a/src/data/set/pairwise.lean b/src/data/set/pairwise.lean index 9f129c8460bf8..9cf16e6d3bad8 100644 --- a/src/data/set/pairwise.lean +++ b/src/data/set/pairwise.lean @@ -100,6 +100,15 @@ subsingleton_empty.pairwise r @[simp] lemma pairwise_singleton (a : α) (r : α → α → Prop) : set.pairwise {a} r := subsingleton_singleton.pairwise r +lemma pairwise_iff_of_refl [is_refl α r] : s.pairwise r ↔ ∀ ⦃a⦄, a ∈ s → ∀ ⦃b⦄, b ∈ s → r a b := +forall₄_congr $ λ a _ b _, or_iff_not_imp_left.symm.trans $ or_iff_right_of_imp of_eq + +alias pairwise_iff_of_refl ↔ set.pairwise.of_refl _ + +lemma _root_.reflexive.set_pairwise_iff (hr : reflexive r) : + s.pairwise r ↔ ∀ ⦃a⦄, a ∈ s → ∀ ⦃b⦄, b ∈ s → r a b := +forall₄_congr $ λ a _ b _, or_iff_not_imp_left.symm.trans $ or_iff_right_of_imp $ eq.rec $ hr a + lemma nonempty.pairwise_iff_exists_forall [is_equiv α r] {s : set ι} (hs : s.nonempty) : (s.pairwise (r on f)) ↔ ∃ z, ∀ x ∈ s, r (f x) z := begin diff --git a/src/order/chain.lean b/src/order/chain.lean index 626ce0e35f20f..df3d51bae1d6e 100644 --- a/src/order/chain.lean +++ b/src/order/chain.lean @@ -4,16 +4,19 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl -/ import data.set.pairwise +import data.set_like.basic /-! -# Chains +# Chains and flags -This file defines chains for an arbitrary relation and proves Hausdorff's Maximality Principle. +This file defines chains for an arbitrary relation and flags for an order and proves Hausdorff's +Maximality Principle. ## Main declarations * `is_chain s`: A chain `s` is a set of comparable elements. * `max_chain_spec`: Hausdorff's Maximality Principle. +* `flag`: The type of flags, aka maximal chains, of an order. ## Notes @@ -24,12 +27,14 @@ Fleuriot, Tobias Nipkow, Christian Sternagel. open classical set -variables {α β : Type*} (r : α → α → Prop) +variables {α β : Type*} -local infix ` ≺ `:50 := r +/-! ### Chains -/ section chain -variables (r) +variables (r : α → α → Prop) + +local infix ` ≺ `:50 := r /-- A chain is a set `s` satisfying `x ≺ y ∨ x = y ∨ y ≺ x` for all `x y ∈ s`. -/ def is_chain (s : set α) : Prop := s.pairwise (λ x y, x ≺ y ∨ y ≺ x) @@ -93,6 +98,12 @@ lemma is_max_chain.is_chain (h : is_max_chain r s) : is_chain r s := h.1 lemma is_max_chain.not_super_chain (h : is_max_chain r s) : ¬super_chain r s t := λ ht, ht.2.ne $ h.2 ht.1 ht.2.1 +lemma is_max_chain.bot_mem [has_le α] [order_bot α] (h : is_max_chain (≤) s) : ⊥ ∈ s := +(h.2 (h.1.insert $ λ a _ _, or.inl bot_le) $ subset_insert _ _).symm ▸ mem_insert _ _ + +lemma is_max_chain.top_mem [has_le α] [order_top α] (h : is_max_chain (≤) s) : ⊤ ∈ s := +(h.2 (h.1.insert $ λ a _ _, or.inr le_top) $ subset_insert _ _).symm ▸ mem_insert _ _ + open_locale classical /-- Given a set `s`, if there exists a chain `t` strictly including `s`, then `succ_chain s` @@ -219,3 +230,67 @@ let ⟨h₁, H⟩ := chain_closure_max_chain.is_chain.super_chain_succ_chain h i H.ne (chain_closure_max_chain.succ_fixpoint_iff.mpr rfl).symm end chain + +/-! ### Flags -/ + +/-- The type of flags, aka maximal chains, of an order. -/ +structure flag (α : Type*) [has_le α] := +(carrier : set α) +(chain' : is_chain (≤) carrier) +(max_chain' : ∀ ⦃s⦄, is_chain (≤) s → carrier ⊆ s → carrier = s) + +namespace flag +section has_le +variables [has_le α] {s t : flag α} {a : α} + +instance : set_like (flag α) α := +{ coe := carrier, + coe_injective' := λ s t h, by { cases s, cases t, congr' } } + +@[ext] lemma ext : (s : set α) = t → s = t := set_like.ext' +@[simp] lemma mem_coe_iff : a ∈ (s : set α) ↔ a ∈ s := iff.rfl +@[simp] lemma coe_mk (s : set α) (h₁ h₂) : (mk s h₁ h₂ : set α) = s := rfl +@[simp] lemma mk_coe (s : flag α) : mk (s : set α) s.chain' s.max_chain' = s := ext rfl + +lemma chain_le (s : flag α) : is_chain (≤) (s : set α) := s.chain' +protected lemma max_chain (s : flag α) : is_max_chain (≤) (s : set α) := ⟨s.chain_le, s.max_chain'⟩ + +lemma top_mem [order_top α] (s : flag α) : (⊤ : α) ∈ s := s.max_chain.top_mem +lemma bot_mem [order_bot α] (s : flag α) : (⊥ : α) ∈ s := s.max_chain.bot_mem + +end has_le + +section preorder +variables [preorder α] {a b : α} + +protected lemma le_or_le (s : flag α) (ha : a ∈ s) (hb : b ∈ s) : a ≤ b ∨ b ≤ a := +s.chain_le.total ha hb + +instance [order_top α] (s : flag α) : order_top s := subtype.order_top s.top_mem +instance [order_bot α] (s : flag α) : order_bot s := subtype.order_bot s.bot_mem +instance [bounded_order α] (s : flag α) : bounded_order s := +subtype.bounded_order s.bot_mem s.top_mem + +end preorder + +section partial_order +variables [partial_order α] + +lemma chain_lt (s : flag α) : is_chain (<) (s : set α) := +λ a ha b hb h, (s.le_or_le ha hb).imp h.lt_of_le h.lt_of_le' + +instance [decidable_eq α] [@decidable_rel α (≤)] [@decidable_rel α (<)] (s : flag α) : + linear_order s := +{ le_total := λ a b, s.le_or_le a.2 b.2, + decidable_eq := subtype.decidable_eq, + decidable_le := subtype.decidable_le, + decidable_lt := subtype.decidable_lt, + ..subtype.partial_order _ } + +end partial_order + +instance [linear_order α] : unique (flag α) := +{ default := ⟨univ, is_chain_of_trichotomous _, λ s _, s.subset_univ.antisymm'⟩, + uniq := λ s, set_like.coe_injective $ s.3 (is_chain_of_trichotomous _) $ subset_univ _ } + +end flag From 7be21e09f18082f2b51f7ec051c29b8f6ea50628 Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Fri, 22 Apr 2022 20:06:18 +0000 Subject: [PATCH 184/373] feat(topology/algebra/group): quotient by a closed subgroup is regular (#13278) --- src/topology/algebra/group.lean | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/topology/algebra/group.lean b/src/topology/algebra/group.lean index 19136f4387c95..6321a138971f0 100644 --- a/src/topology/algebra/group.lean +++ b/src/topology/algebra/group.lean @@ -940,10 +940,21 @@ lemma topological_group.regular_space [t1_space G] : regular_space G := contradiction end⟩ -local attribute [instance] topological_group.regular_space +@[to_additive] +lemma topological_group.t2_space [t1_space G] : t2_space G := +@regular_space.t2_space G _ (topological_group.regular_space G) + +variables {G} (S : subgroup G) [subgroup.normal S] [is_closed (S : set G)] @[to_additive] -lemma topological_group.t2_space [t1_space G] : t2_space G := regular_space.t2_space G +instance subgroup.regular_quotient_of_is_closed + (S : subgroup G) [subgroup.normal S] [is_closed (S : set G)] : regular_space (G ⧸ S) := +begin + suffices : t1_space (G ⧸ S), { exact @topological_group.regular_space _ _ _ _ this, }, + have hS : is_closed (S : set G) := infer_instance, + rw ← quotient_group.ker_mk S at hS, + exact topological_group.t1_space (G ⧸ S) ((quotient_map_quotient_mk.is_closed_preimage).mp hS), +end end From 9eb3858a77cc48d1063337b6a7ca1a851d1b9c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Fri, 22 Apr 2022 20:06:19 +0000 Subject: [PATCH 185/373] feat(combinatorics/pigeonhole): Pigeons in linear commutative rings (#13308) Duplicate almost all the pigeonhole principle API to work in `linear_ordered_comm_ring`s. Co-authored-by: Bhavik Mehta --- src/algebra/module/basic.lean | 8 ++- src/combinatorics/pigeonhole.lean | 107 ++++++++++++++++++++++++++++-- 2 files changed, 107 insertions(+), 8 deletions(-) diff --git a/src/algebra/module/basic.lean b/src/algebra/module/basic.lean index d5a39b6689d19..4ced2e4b03436 100644 --- a/src/algebra/module/basic.lean +++ b/src/algebra/module/basic.lean @@ -39,9 +39,8 @@ semimodule, module, vector space open function open_locale big_operators -universes u u' v w x y z -variables {R : Type u} {k : Type u'} {S : Type v} {M : Type w} {M₂ : Type x} {M₃ : Type y} - {ι : Type z} +universes u v +variables {α R k S M M₂ M₃ ι : Type*} /-- A module is a generalization of vector spaces to a scalar semiring. It consists of a scalar semiring `R` and an additive monoid of "vectors" `M`, @@ -618,3 +617,6 @@ by rw [nsmul_eq_mul, mul_one] @[simp] lemma int.smul_one_eq_coe {R : Type*} [ring R] (m : ℤ) : m • (1 : R) = ↑m := by rw [zsmul_eq_mul, mul_one] + +lemma finset.cast_card [comm_semiring R] (s : finset α) : (s.card : R) = ∑ a in s, 1 := +by rw [finset.sum_const, nat.smul_one_eq_coe] diff --git a/src/combinatorics/pigeonhole.lean b/src/combinatorics/pigeonhole.lean index 73e806c28f105..4b1a755f04ea4 100644 --- a/src/combinatorics/pigeonhole.lean +++ b/src/combinatorics/pigeonhole.lean @@ -54,15 +54,22 @@ docstrings instead of the names. `measure_theory.exists_nonempty_inter_of_measure_univ_lt_sum_measure`: pigeonhole principle in a measure space. +## TODO + +The `_nsmul` lemmas could be generalized from `linear_ordered_comm_ring` to +`linear_ordered_comm_semiring` if the latter existed (or some combination of +`covariant`/`contravariant` classes once the refactor has gone deep enough). This would allow +deriving the `_mul` lemmas from the `_nsmul` ones. + ## Tags pigeonhole principle -/ universes u v w -variables {α : Type u} {β : Type v} {M : Type w} [linear_ordered_cancel_add_comm_monoid M] - [decidable_eq β] +variables {α : Type u} {β : Type v} {M : Type w} [decidable_eq β] +open nat open_locale big_operators namespace finset @@ -94,6 +101,9 @@ There are a few bits we can change in this theorem: We can do all these variations independently, so we have eight versions of the theorem. -/ +section +variables [linear_ordered_cancel_add_comm_monoid M] + /-! #### Strict inequality versions -/ @@ -186,6 +196,10 @@ lemma exists_sum_fiber_le_of_sum_fiber_nonneg_of_sum_le_nsmul ∃ y ∈ t, (∑ x in s.filter (λ x, f x = y), w x) ≤ b := @exists_le_sum_fiber_of_sum_fiber_nonpos_of_nsmul_le_sum α β (order_dual M) _ _ _ _ _ _ _ hf ht hb +end + +variables [linear_ordered_comm_ring M] + /-! ### The pigeonhole principles on `finset`s, pigeons counted by heads @@ -203,6 +217,16 @@ So, we prove four theorems: `finset.exists_lt_card_fiber_of_maps_to_of_mul_lt_ca `finset.exists_le_card_fiber_of_maps_to_of_mul_le_card`, `finset.exists_card_fiber_lt_of_card_lt_mul`, and `finset.exists_card_fiber_le_of_card_le_mul`. -/ +/-- The pigeonhole principle for finitely many pigeons counted by heads: there is a pigeonhole with +at least as many pigeons as the ceiling of the average number of pigeons across all pigeonholes. -/ +lemma exists_lt_card_fiber_of_nsmul_lt_card_of_maps_to (hf : ∀ a ∈ s, f a ∈ t) + (ht : t.card • b < s.card) : + ∃ y ∈ t, b < (s.filter $ λ x, f x = y).card := +begin + simp_rw cast_card at ⊢ ht, + exact exists_lt_sum_fiber_of_maps_to_of_nsmul_lt_sum hf ht, +end + /-- The pigeonhole principle for finitely many pigeons counted by heads: there is a pigeonhole with at least as many pigeons as the ceiling of the average number of pigeons across all pigeonholes. ("The maximum is at least the mean" specialized to integers.) @@ -219,6 +243,16 @@ begin simpa end +/-- The pigeonhole principle for finitely many pigeons counted by heads: there is a pigeonhole with +at most as many pigeons as the floor of the average number of pigeons across all pigeonholes. -/ +lemma exists_card_fiber_lt_of_card_lt_nsmul (ht : ↑(s.card) < t.card • b) : + ∃ y ∈ t, ↑((s.filter $ λ x, f x = y).card) < b := +begin + simp_rw cast_card at ⊢ ht, + exact exists_sum_fiber_lt_of_sum_fiber_nonneg_of_sum_lt_nsmul + (λ _ _, sum_nonneg $ λ _ _, zero_le_one) ht, +end + /-- The pigeonhole principle for finitely many pigeons counted by heads: there is a pigeonhole with at most as many pigeons as the floor of the average number of pigeons across all pigeonholes. ("The minimum is at most the mean" specialized to integers.) @@ -235,7 +269,19 @@ begin end /-- The pigeonhole principle for finitely many pigeons counted by heads: given a function between -finite sets `s` and `t` and a natural number `n` such that `card t * n ≤ card s`, there exists `y ∈ +finite sets `s` and `t` and a number `b` such that `card t • b ≤ card s`, there exists `y ∈ t` such +that its preimage in `s` has at least `b` elements. +See also `finset.exists_lt_card_fiber_of_nsmul_lt_card_of_maps_to` for a stronger statement. -/ +lemma exists_le_card_fiber_of_nsmul_le_card_of_maps_to (hf : ∀ a ∈ s, f a ∈ t) (ht : t.nonempty) + (hb : t.card • b ≤ s.card) : + ∃ y ∈ t, b ≤ (s.filter $ λ x, f x = y).card := +begin + simp_rw cast_card at ⊢ hb, + exact exists_le_sum_fiber_of_maps_to_of_nsmul_le_sum hf ht hb, +end + +/-- The pigeonhole principle for finitely many pigeons counted by heads: given a function between +finite sets `s` and `t` and a natural number `b` such that `card t * n ≤ card s`, there exists `y ∈ t` such that its preimage in `s` has at least `n` elements. See also `finset.exists_lt_card_fiber_of_mul_lt_card_of_maps_to` for a stronger statement. -/ lemma exists_le_card_fiber_of_mul_le_card_of_maps_to (hf : ∀ a ∈ s, f a ∈ t) (ht : t.nonempty) @@ -247,6 +293,18 @@ begin simpa end +/-- The pigeonhole principle for finitely many pigeons counted by heads: given a function `f`, a +finite sets `s` and `t`, and a number `b` such that `card s ≤ card t • b`, there exists `y ∈ t` such +that its preimage in `s` has no more than `b` elements. +See also `finset.exists_card_fiber_lt_of_card_lt_nsmul` for a stronger statement. -/ +lemma exists_card_fiber_le_of_card_le_nsmul (ht : t.nonempty) (hb : ↑(s.card) ≤ t.card • b) : + ∃ y ∈ t, ↑((s.filter $ λ x, f x = y).card) ≤ b := +begin + simp_rw cast_card at ⊢ hb, + refine exists_sum_fiber_le_of_sum_fiber_nonneg_of_sum_le_nsmul + (λ _ _, sum_nonneg $ λ _ _, zero_le_one) ht hb, +end + /-- The pigeonhole principle for finitely many pigeons counted by heads: given a function `f`, a finite sets `s` in its domain, a finite set `t` in its codomain, and a natural number `n` such that `card s ≤ card t * n`, there exists `y ∈ t` such that its preimage in `s` has no more than `n` @@ -266,6 +324,9 @@ open finset variables [fintype α] [fintype β] (f : α → β) {w : α → M} {b : M} {n : ℕ} +section +variables [linear_ordered_cancel_add_comm_monoid M] + /-! ### The pigeonhole principles on `fintypes`s, pigeons counted by weight @@ -295,7 +356,7 @@ version: there is a pigeonhole with the total weight of pigeons in it less than the total number of pigeonholes times `b` is greater than the total weight of all pigeons. -/ lemma exists_sum_fiber_lt_of_sum_lt_nsmul (hb : (∑ x, w x) < card β • b) : ∃ y, (∑ x in univ.filter (λ x, f x = y), w x) < b := -@exists_lt_sum_fiber_of_nsmul_lt_sum α β (order_dual M) _ _ _ _ _ w b hb +@exists_lt_sum_fiber_of_nsmul_lt_sum α β (order_dual M) _ _ _ _ _ _ _ hb /-- The pigeonhole principle for finitely many pigeons of different weights, non-strict inequality version: there is a pigeonhole with the total weight of pigeons in it less than or equal to `b` @@ -303,7 +364,19 @@ provided that the total number of pigeonholes times `b` is greater than or equal of all pigeons. -/ lemma exists_sum_fiber_le_of_sum_le_nsmul [nonempty β] (hb : (∑ x, w x) ≤ card β • b) : ∃ y, (∑ x in univ.filter (λ x, f x = y), w x) ≤ b := -@exists_le_sum_fiber_of_nsmul_le_sum α β (order_dual M) _ _ _ _ _ w b _ hb +@exists_le_sum_fiber_of_nsmul_le_sum α β (order_dual M) _ _ _ _ _ _ _ _ hb + +end + +variables [linear_ordered_comm_ring M] + +/-- +The strong pigeonhole principle for finitely many pigeons and pigeonholes. There is a pigeonhole +with at least as many pigeons as the ceiling of the average number of pigeons across all +pigeonholes. -/ +lemma exists_lt_card_fiber_of_nsmul_lt_card (hb : card β • b < card α) : + ∃ y : β, b < (univ.filter (λ x, f x = y)).card := +let ⟨y, _, h⟩ := exists_lt_card_fiber_of_nsmul_lt_card_of_maps_to (λ _ _, mem_univ _) hb in ⟨y, h⟩ /-- The strong pigeonhole principle for finitely many pigeons and pigeonholes. @@ -318,6 +391,13 @@ lemma exists_lt_card_fiber_of_mul_lt_card (hn : card β * n < card α) : ∃ y : β, n < (univ.filter (λ x, f x = y)).card := let ⟨y, _, h⟩ := exists_lt_card_fiber_of_mul_lt_card_of_maps_to (λ _ _, mem_univ _) hn in ⟨y, h⟩ +/-- The strong pigeonhole principle for finitely many pigeons and pigeonholes. There is a pigeonhole +with at most as many pigeons as the floor of the average number of pigeons across all pigeonholes. +-/ +lemma exists_card_fiber_lt_of_card_lt_nsmul (hb : ↑(card α) < card β • b) : + ∃ y : β, ↑((univ.filter $ λ x, f x = y).card) < b := +let ⟨y, _, h⟩ := exists_card_fiber_lt_of_card_lt_nsmul hb in ⟨y, h⟩ + /-- The strong pigeonhole principle for finitely many pigeons and pigeonholes. There is a pigeonhole with at most as many pigeons as @@ -331,6 +411,15 @@ lemma exists_card_fiber_lt_of_card_lt_mul (hn : card α < card β * n) : ∃ y : β, (univ.filter (λ x, f x = y)).card < n := let ⟨y, _, h⟩ := exists_card_fiber_lt_of_card_lt_mul hn in ⟨y, h⟩ +/-- The strong pigeonhole principle for finitely many pigeons and pigeonholes. Given a function `f` +between finite types `α` and `β` and a number `b` such that `card β • b ≤ card α`, there exists an +element `y : β` such that its preimage has at least `b` elements. +See also `fintype.exists_lt_card_fiber_of_nsmul_lt_card` for a stronger statement. -/ +lemma exists_le_card_fiber_of_nsmul_le_card [nonempty β] (hb : card β • b ≤ card α) : + ∃ y : β, b ≤ (univ.filter $ λ x, f x = y).card := +let ⟨y, _, h⟩ := exists_le_card_fiber_of_nsmul_le_card_of_maps_to (λ _ _, mem_univ _) univ_nonempty + hb in ⟨y, h⟩ + /-- The strong pigeonhole principle for finitely many pigeons and pigeonholes. Given a function `f` between finite types `α` and `β` and a number `n` such that `card β * n ≤ card α`, there exists an element `y : β` such that its preimage has at least `n` elements. See also @@ -340,6 +429,14 @@ lemma exists_le_card_fiber_of_mul_le_card [nonempty β] (hn : card β * n ≤ ca let ⟨y, _, h⟩ := exists_le_card_fiber_of_mul_le_card_of_maps_to (λ _ _, mem_univ _) univ_nonempty hn in ⟨y, h⟩ +/-- The strong pigeonhole principle for finitely many pigeons and pigeonholes. Given a function `f` +between finite types `α` and `β` and a number `b` such that `card α ≤ card β • b`, there exists an +element `y : β` such that its preimage has at most `b` elements. +See also `fintype.exists_card_fiber_lt_of_card_lt_nsmul` for a stronger statement. -/ +lemma exists_card_fiber_le_of_card_le_nsmul [nonempty β] (hb : ↑(card α) ≤ card β • b) : + ∃ y : β, ↑((univ.filter $ λ x, f x = y).card) ≤ b := +let ⟨y, _, h⟩ := exists_card_fiber_le_of_card_le_nsmul univ_nonempty hb in ⟨y, h⟩ + /-- The strong pigeonhole principle for finitely many pigeons and pigeonholes. Given a function `f` between finite types `α` and `β` and a number `n` such that `card α ≤ card β * n`, there exists an element `y : β` such that its preimage has at most `n` elements. See also From 45470769a21cac2f8a93b3ce55dfdba979a64a35 Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Fri, 22 Apr 2022 20:06:20 +0000 Subject: [PATCH 186/373] chore(*): use zero_lt_two/two_ne_zero lemmas more (#13609) Co-authored-by: Yury G. Kudryashov --- src/algebra/group_with_zero/basic.lean | 2 ++ src/analysis/normed_space/star/spectrum.lean | 2 +- src/data/nat/modeq.lean | 2 +- src/data/nat/sqrt.lean | 5 ++--- src/number_theory/fermat4.lean | 13 ++++++------- src/number_theory/lucas_lehmer.lean | 2 +- src/number_theory/pythagorean_triples.lean | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/algebra/group_with_zero/basic.lean b/src/algebra/group_with_zero/basic.lean index c838911267331..643cedd69c6e4 100644 --- a/src/algebra/group_with_zero/basic.lean +++ b/src/algebra/group_with_zero/basic.lean @@ -141,6 +141,8 @@ not_congr mul_eq_zero_comm lemma mul_self_eq_zero : a * a = 0 ↔ a = 0 := by simp lemma zero_eq_mul_self : 0 = a * a ↔ a = 0 := by simp +lemma mul_self_ne_zero : a * a ≠ 0 ↔ a ≠ 0 := not_congr mul_self_eq_zero +lemma zero_ne_mul_self : 0 ≠ a * a ↔ a ≠ 0 := not_congr zero_eq_mul_self end diff --git a/src/analysis/normed_space/star/spectrum.lean b/src/analysis/normed_space/star/spectrum.lean index 8110678ab8ca1..617e7f64c986e 100644 --- a/src/analysis/normed_space/star/spectrum.lean +++ b/src/analysis/normed_space/star/spectrum.lean @@ -68,7 +68,7 @@ end lemma spectral_radius_eq_nnnorm_of_star_normal [norm_one_class A] (a : A) [is_star_normal a] : spectral_radius ℂ a = ∥a∥₊ := begin - refine (ennreal.pow_strict_mono (by linarith : 2 ≠ 0)).injective _, + refine (ennreal.pow_strict_mono two_ne_zero).injective _, have ha : a⋆ * a ∈ self_adjoint A, from self_adjoint.mem_iff.mpr (by simpa only [star_star] using (star_mul a⋆ a)), have heq : (λ n : ℕ, ((∥(a⋆ * a) ^ n∥₊ ^ (1 / n : ℝ)) : ℝ≥0∞)) diff --git a/src/data/nat/modeq.lean b/src/data/nat/modeq.lean index 7e32fe298fed9..d77d291e3d6dd 100644 --- a/src/data/nat/modeq.lean +++ b/src/data/nat/modeq.lean @@ -405,7 +405,7 @@ lemma odd_mul_odd_div_two {m n : ℕ} (hm1 : m % 2 = 1) (hn1 : n % 2 = 1) : (m * n) / 2 = m * (n / 2) + m / 2 := have hm0 : 0 < m := nat.pos_of_ne_zero (λ h, by simp * at *), have hn0 : 0 < n := nat.pos_of_ne_zero (λ h, by simp * at *), -(nat.mul_right_inj (show 0 < 2, from dec_trivial)).1 $ +(nat.mul_right_inj zero_lt_two).1 $ by rw [mul_add, two_mul_odd_div_two hm1, mul_left_comm, two_mul_odd_div_two hn1, two_mul_odd_div_two (nat.odd_mul_odd hm1 hn1), mul_tsub, mul_one, ← add_tsub_assoc_of_le (succ_le_of_lt hm0), diff --git a/src/data/nat/sqrt.lean b/src/data/nat/sqrt.lean index 102f95d8bd823..3df252d2a0672 100644 --- a/src/data/nat/sqrt.lean +++ b/src/data/nat/sqrt.lean @@ -79,9 +79,8 @@ private lemma sqrt_aux_is_sqrt_lemma (m r n : ℕ) is_sqrt n (sqrt_aux m' ((r + 2^m) * 2^m) (n - (r + 2^m) * (r + 2^m)))) : is_sqrt n (sqrt_aux (2^m * 2^m) ((2*r)*2^m) (n - r*r)) := begin - have b0 := - have b0:_, from ne_of_gt (pow_pos (show 0 < 2, from dec_trivial) m), - nat.mul_ne_zero b0 b0, + have b0 : 2 ^ m * 2 ^ m ≠ 0, + from mul_self_ne_zero.2 (pow_ne_zero m two_ne_zero), have lb : n - r * r < 2 * r * 2^m + 2^m * 2^m ↔ n < (r+2^m)*(r+2^m), { rw [tsub_lt_iff_right h₁], diff --git a/src/number_theory/fermat4.lean b/src/number_theory/fermat4.lean index a8450b3f19f2a..5f3fe6387b5b3 100644 --- a/src/number_theory/fermat4.lean +++ b/src/number_theory/fermat4.lean @@ -46,7 +46,7 @@ end lemma ne_zero {a b c : ℤ} (h : fermat_42 a b c) : c ≠ 0 := begin - apply ne_zero_pow (dec_trivial : 2 ≠ 0), apply ne_of_gt, + apply ne_zero_pow two_ne_zero _, apply ne_of_gt, rw [← h.2.2, (by ring : a ^ 4 + b ^ 4 = (a ^ 2) ^ 2 + (b ^ 2) ^ 2)], exact add_pos (sq_pos_of_ne_zero _ (pow_ne_zero 2 h.1)) (sq_pos_of_ne_zero _ (pow_ne_zero 2 h.2.1)) @@ -85,15 +85,14 @@ begin obtain ⟨a1, rfl⟩ := (int.coe_nat_dvd_left.mpr hpa), obtain ⟨b1, rfl⟩ := (int.coe_nat_dvd_left.mpr hpb), have hpc : (p : ℤ) ^ 2 ∣ c, - { apply (int.pow_dvd_pow_iff (dec_trivial : 0 < 2)).mp, - rw ← h.1.2.2, + { rw [←int.pow_dvd_pow_iff zero_lt_two, ←h.1.2.2], apply dvd.intro (a1 ^ 4 + b1 ^ 4), ring }, obtain ⟨c1, rfl⟩ := hpc, have hf : fermat_42 a1 b1 c1, exact (fermat_42.mul (int.coe_nat_ne_zero.mpr (nat.prime.ne_zero hp))).mpr h.1, apply nat.le_lt_antisymm (h.2 _ _ _ hf), rw [int.nat_abs_mul, lt_mul_iff_one_lt_left, int.nat_abs_pow, int.nat_abs_of_nat], - { exact nat.one_lt_pow _ _ (show 0 < 2, from dec_trivial) (nat.prime.one_lt hp) }, + { exact nat.one_lt_pow _ _ zero_lt_two (nat.prime.one_lt hp) }, { exact (nat.pos_of_ne_zero (int.nat_abs_ne_zero_of_ne_zero (ne_zero hf))) }, end @@ -217,7 +216,7 @@ begin revert hb20, rw [ht2, htt2, mul_assoc, @mul_assoc _ _ _ r s, hrsz], simp }, have h2b0 : b' ≠ 0, - { apply ne_zero_pow (dec_trivial : 2 ≠ 0), + { apply ne_zero_pow two_ne_zero, rw hs, apply mul_ne_zero, { exact ne_of_gt h4}, { exact hrsz } }, obtain ⟨i, hi⟩ := int.sq_of_gcd_eq_one hcp hs.symm, -- use m is positive to exclude m = - i ^ 2 @@ -244,14 +243,14 @@ begin -- r = +/- j ^ 2 obtain ⟨j, hj⟩ := int.sq_of_gcd_eq_one htt4 hd, have hj0 : j ≠ 0, - { intro h0, rw [h0, zero_pow (dec_trivial : 0 < 2), neg_zero, or_self] at hj, + { intro h0, rw [h0, zero_pow zero_lt_two, neg_zero, or_self] at hj, apply left_ne_zero_of_mul hrsz hj }, rw mul_comm at hd, rw [int.gcd_comm] at htt4, -- s = +/- k ^ 2 obtain ⟨k, hk⟩ := int.sq_of_gcd_eq_one htt4 hd, have hk0 : k ≠ 0, - { intro h0, rw [h0, zero_pow (dec_trivial : 0 < 2), neg_zero, or_self] at hk, + { intro h0, rw [h0, zero_pow zero_lt_two, neg_zero, or_self] at hk, apply right_ne_zero_of_mul hrsz hk }, have hj2 : r ^ 2 = j ^ 4, { cases hj with hjp hjp; { rw hjp, ring } }, have hk2 : s ^ 2 = k ^ 4, { cases hk with hkp hkp; { rw hkp, ring } }, diff --git a/src/number_theory/lucas_lehmer.lean b/src/number_theory/lucas_lehmer.lean index 9b1a0fedb6813..cbef60a48fff0 100644 --- a/src/number_theory/lucas_lehmer.lean +++ b/src/number_theory/lucas_lehmer.lean @@ -510,7 +510,7 @@ begin conv in k { rw ← nat.div_add_mod k (2^n) }, refine nat.modeq.add_right _ _, conv { congr, skip, skip, rw ← one_mul (k/2^n) }, - exact (nat.modeq_sub $ pow_pos (by norm_num : 0 < 2) _).mul_right _, + exact (nat.modeq_sub $ nat.succ_le_of_lt $ pow_pos zero_lt_two _).mul_right _, end -- It's hard to know what the limiting factor for large Mersenne primes would be. diff --git a/src/number_theory/pythagorean_triples.lean b/src/number_theory/pythagorean_triples.lean index 43a8e1dd97c99..7af2d59a0aac5 100644 --- a/src/number_theory/pythagorean_triples.lean +++ b/src/number_theory/pythagorean_triples.lean @@ -153,7 +153,7 @@ begin ∃ (k : ℕ) x0 y0, 0 < k ∧ int.gcd x0 y0 = 1 ∧ x = x0 * k ∧ y = y0 * k := int.exists_gcd_one' (nat.pos_of_ne_zero h0), rw [int.gcd_mul_right, h2, int.nat_abs_of_nat, one_mul], - rw [← int.pow_dvd_pow_iff (dec_trivial : 0 < 2), sq z, ← h.eq], + rw [← int.pow_dvd_pow_iff zero_lt_two, sq z, ← h.eq], rw (by ring : x0 * k * (x0 * k) + y0 * k * (y0 * k) = k ^ 2 * (x0 * x0 + y0 * y0)), exact dvd_mul_right _ _ end From b98bd418672ae57c29d5abc44cb374d01bf4b3cb Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Fri, 22 Apr 2022 22:31:58 +0000 Subject: [PATCH 187/373] feat(topology/uniform_space/matrix): Add the uniform_space structure on matrices (#13534) Co-authored-by: Heather Macbeth <25316162+hrmacbeth@users.noreply.github.com> --- src/topology/uniform_space/matrix.lean | 40 ++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/topology/uniform_space/matrix.lean diff --git a/src/topology/uniform_space/matrix.lean b/src/topology/uniform_space/matrix.lean new file mode 100644 index 0000000000000..a39badbdaf63a --- /dev/null +++ b/src/topology/uniform_space/matrix.lean @@ -0,0 +1,40 @@ +/- +Copyright (c) 2022 Eric Wieser. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Eric Wieser, Heather Macbeth +-/ +import topology.uniform_space.pi +import data.matrix.basic + +/-! +# Uniform space structure on matrices +-/ + +open_locale uniformity topological_space + +variables (m n 𝕜 : Type*) [uniform_space 𝕜] + +namespace matrix + +instance : uniform_space (matrix m n 𝕜) := +(by apply_instance : uniform_space (m → n → 𝕜)) + +lemma uniformity : + 𝓤 (matrix m n 𝕜) = ⨅ (i : m) (j : n), (𝓤 𝕜).comap (λ a, (a.1 i j, a.2 i j)) := +begin + erw [Pi.uniformity, Pi.uniformity], + simp_rw [filter.comap_infi, filter.comap_comap], + refl, +end + +lemma uniform_continuous {β : Type*} [uniform_space β] {f : β → matrix m n 𝕜} : + uniform_continuous f ↔ ∀ i j, uniform_continuous (λ x, f x i j) := +by simp only [uniform_continuous, matrix.uniformity, filter.tendsto_infi, filter.tendsto_comap_iff] + +instance [complete_space 𝕜] : complete_space (matrix m n 𝕜) := +(by apply_instance : complete_space (m → n → 𝕜)) + +instance [separated_space 𝕜] : separated_space (matrix m n 𝕜) := +(by apply_instance : separated_space (m → n → 𝕜)) + +end matrix From 976c544cb0a0c1b1a21d2931a30d311ae2e0940e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Fri, 22 Apr 2022 22:31:59 +0000 Subject: [PATCH 188/373] feat(algebra/order/archimedean): Comparing with rationals determines the order (#13602) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In a linear ordered field, if `q < x → q ≤ y` for all `q : ℚ`, then `x ≤ y`, and similar results. --- src/algebra/order/archimedean.lean | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/algebra/order/archimedean.lean b/src/algebra/order/archimedean.lean index 5ca66b88e7cd6..1dfd6928e874a 100644 --- a/src/algebra/order/archimedean.lean +++ b/src/algebra/order/archimedean.lean @@ -284,7 +284,7 @@ archimedean_iff_rat_lt.trans λ H x, let ⟨n, h⟩ := H x in ⟨n+1, lt_of_le_of_lt h (rat.cast_lt.2 (lt_add_one _))⟩⟩ -variable [archimedean α] +variables [archimedean α] {x y : α} theorem exists_rat_lt (x : α) : ∃ q : ℚ, (q : α) < x := let ⟨n, h⟩ := exists_int_lt x in ⟨n, by rwa rat.cast_coe_int⟩ @@ -308,6 +308,20 @@ begin { rw [rat.coe_nat_denom, nat.cast_one], exact one_ne_zero } end +lemma le_of_forall_rat_lt_imp_le (h : ∀ q : ℚ, (q : α) < x → (q : α) ≤ y) : x ≤ y := +le_of_not_lt $ λ hyx, let ⟨q, hy, hx⟩ := exists_rat_btwn hyx in hy.not_le $ h _ hx + +lemma le_of_forall_lt_rat_imp_le (h : ∀ q : ℚ, y < q → x ≤ q) : x ≤ y := +le_of_not_lt $ λ hyx, let ⟨q, hy, hx⟩ := exists_rat_btwn hyx in hx.not_le $ h _ hy + +lemma eq_of_forall_rat_lt_iff_lt (h : ∀ q : ℚ, (q : α) < x ↔ (q : α) < y) : x = y := +(le_of_forall_rat_lt_imp_le $ λ q hq, ((h q).1 hq).le).antisymm $ le_of_forall_rat_lt_imp_le $ + λ q hq, ((h q).2 hq).le + +lemma eq_of_forall_lt_rat_iff_lt (h : ∀ q : ℚ, x < q ↔ y < q) : x = y := +(le_of_forall_lt_rat_imp_le $ λ q hq, ((h q).2 hq).le).antisymm $ le_of_forall_lt_rat_imp_le $ + λ q hq, ((h q).1 hq).le + theorem exists_nat_one_div_lt {ε : α} (hε : 0 < ε) : ∃ n : ℕ, 1 / (n + 1: α) < ε := begin cases exists_nat_gt (1/ε) with n hn, From 9923362cefa105341da924075d44ebf9f5b84130 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 22 Apr 2022 23:37:56 +0000 Subject: [PATCH 189/373] doc(measure_theory): add some missing `to_additive` docstrings (#13456) --- src/measure_theory/constructions/pi.lean | 8 ++- src/measure_theory/group/integration.lean | 29 +++++---- src/measure_theory/group/measure.lean | 72 +++++++++++++++-------- 3 files changed, 72 insertions(+), 37 deletions(-) diff --git a/src/measure_theory/constructions/pi.lean b/src/measure_theory/constructions/pi.lean index 1187a6f8411a1..f3e10833b467e 100644 --- a/src/measure_theory/constructions/pi.lean +++ b/src/measure_theory/constructions/pi.lean @@ -553,7 +553,9 @@ measure.pi_closed_ball _ _ hr open measure /-- We intentionally restrict this only to the nondependent function space, since type-class inference cannot find an instance for `ι → ℝ` when this is stated for dependent function spaces. -/ -@[to_additive] +@[to_additive "We intentionally restrict this only to the nondependent function space, since +type-class inference cannot find an instance for `ι → ℝ` when this is stated for dependent function +spaces."] instance pi.is_mul_left_invariant_volume {α} [group α] [measure_space α] [sigma_finite (volume : measure α)] [has_measurable_mul α] [is_mul_left_invariant (volume : measure α)] : @@ -562,7 +564,9 @@ pi.is_mul_left_invariant _ /-- We intentionally restrict this only to the nondependent function space, since type-class inference cannot find an instance for `ι → ℝ` when this is stated for dependent function spaces. -/ -@[to_additive] +@[to_additive "We intentionally restrict this only to the nondependent function space, since +type-class inference cannot find an instance for `ι → ℝ` when this is stated for dependent function +spaces."] instance pi.is_inv_invariant_volume {α} [group α] [measure_space α] [sigma_finite (volume : measure α)] [has_measurable_inv α] [is_inv_invariant (volume : measure α)] : diff --git a/src/measure_theory/group/integration.lean b/src/measure_theory/group/integration.lean index d9bd4db4dc5aa..8deb54b2fb5e0 100644 --- a/src/measure_theory/group/integration.lean +++ b/src/measure_theory/group/integration.lean @@ -46,9 +46,10 @@ section measurable_mul variables [group G] [has_measurable_mul G] -/-- Translating a function by left-multiplication does not change its `lintegral` with respect to -a left-invariant measure. -/ -@[to_additive] +/-- Translating a function by left-multiplication does not change its `measure_theory.lintegral` +with respect to a left-invariant measure. -/ +@[to_additive "Translating a function by left-addition does not change its +`measure_theory.lintegral` with respect to a left-invariant measure."] lemma lintegral_mul_left_eq_self [is_mul_left_invariant μ] (f : G → ℝ≥0∞) (g : G) : ∫⁻ x, f (g * x) ∂μ = ∫⁻ x, f x ∂μ := begin @@ -56,9 +57,10 @@ begin simp [map_mul_left_eq_self μ g] end -/-- Translating a function by right-multiplication does not change its `lintegral` with respect to -a right-invariant measure. -/ -@[to_additive] +/-- Translating a function by right-multiplication does not change its `measure_theory.lintegral` +with respect to a right-invariant measure. -/ +@[to_additive "Translating a function by right-addition does not change its +`measure_theory.lintegral` with respect to a right-invariant measure."] lemma lintegral_mul_right_eq_self [is_mul_right_invariant μ] (f : G → ℝ≥0∞) (g : G) : ∫⁻ x, f (x * g) ∂μ = ∫⁻ x, f x ∂μ := begin @@ -68,7 +70,8 @@ end /-- Translating a function by left-multiplication does not change its integral with respect to a left-invariant measure. -/ -@[to_additive] +@[to_additive "Translating a function by left-addition does not change its integral with respect to +a left-invariant measure."] lemma integral_mul_left_eq_self [is_mul_left_invariant μ] (f : G → E) (g : G) : ∫ x, f (g * x) ∂μ = ∫ x, f x ∂μ := begin @@ -79,7 +82,8 @@ end /-- Translating a function by right-multiplication does not change its integral with respect to a right-invariant measure. -/ -@[to_additive] +@[to_additive "Translating a function by right-addition does not change its integral with respect to +a right-invariant measure."] lemma integral_mul_right_eq_self [is_mul_right_invariant μ] (f : G → E) (g : G) : ∫ x, f (x * g) ∂μ = ∫ x, f x ∂μ := begin @@ -90,14 +94,16 @@ end /-- If some left-translate of a function negates it, then the integral of the function with respect to a left-invariant measure is 0. -/ -@[to_additive] +@[to_additive "If some left-translate of a function negates it, then the integral of the function +with respect to a left-invariant measure is 0."] lemma integral_eq_zero_of_mul_left_eq_neg [is_mul_left_invariant μ] (hf' : ∀ x, f (g * x) = - f x) : ∫ x, f x ∂μ = 0 := by simp_rw [← self_eq_neg ℝ E, ← integral_neg, ← hf', integral_mul_left_eq_self] /-- If some right-translate of a function negates it, then the integral of the function with respect to a right-invariant measure is 0. -/ -@[to_additive] +@[to_additive "If some right-translate of a function negates it, then the integral of the function +with respect to a right-invariant measure is 0."] lemma integral_eq_zero_of_mul_right_eq_neg [is_mul_right_invariant μ] (hf' : ∀ x, f (x * g) = - f x) : ∫ x, f x ∂μ = 0 := by simp_rw [← self_eq_neg ℝ E, ← integral_neg, ← hf', integral_mul_right_eq_self] @@ -149,7 +155,8 @@ variables [topological_space G] [group G] [topological_group G] [borel_space G] /-- For nonzero regular left invariant measures, the integral of a continuous nonnegative function `f` is 0 iff `f` is 0. -/ -@[to_additive] +@[to_additive "For nonzero regular left invariant measures, the integral of a continuous nonnegative +function `f` is 0 iff `f` is 0."] lemma lintegral_eq_zero_of_is_mul_left_invariant [regular μ] (hμ : μ ≠ 0) {f : G → ℝ≥0∞} (hf : continuous f) : ∫⁻ x, f x ∂μ = 0 ↔ f = 0 := diff --git a/src/measure_theory/group/measure.lean b/src/measure_theory/group/measure.lean index 4473afab832a5..e4655360e0380 100644 --- a/src/measure_theory/group/measure.lean +++ b/src/measure_theory/group/measure.lean @@ -67,7 +67,7 @@ lemma map_mul_right_eq_self (μ : measure G) [is_mul_right_invariant μ] (g : G) is_mul_right_invariant.map_mul_right_eq_self g /-- An alternative way to prove that `μ` is left invariant under multiplication. -/ -@[to_additive] +@[to_additive "An alternative way to prove that `μ` is left invariant under addition."] lemma forall_measure_preimage_mul_iff [has_measurable_mul G] (μ : measure G) : (∀ (g : G) (A : set G), measurable_set A → μ ((λ h, g * h) ⁻¹' A) = μ A) ↔ is_mul_left_invariant μ := @@ -80,7 +80,7 @@ begin end /-- An alternative way to prove that `μ` is left invariant under multiplication. -/ -@[to_additive] +@[to_additive "An alternative way to prove that `μ` is left invariant under addition."] lemma forall_measure_preimage_mul_right_iff [has_measurable_mul G] (μ : measure G) : (∀ (g : G) (A : set G), measurable_set A → μ ((λ h, h * g) ⁻¹' A) = μ A) ↔ is_mul_right_invariant μ := @@ -116,7 +116,8 @@ variables [has_measurable_mul G] /-- We shorten this from `measure_preimage_mul_left`, since left invariant is the preferred option for measures in this formalization. -/ -@[simp, to_additive] +@[simp, to_additive "We shorten this from `measure_preimage_add_left`, since left invariant is the +preferred option for measures in this formalization."] lemma measure_preimage_mul (μ : measure G) [is_mul_left_invariant μ] (g : G) (A : set G) : μ ((λ h, g * h) ⁻¹' A) = μ A := calc μ ((λ h, g * h) ⁻¹' A) = map (λ h, g * h) μ A : @@ -252,9 +253,11 @@ begin end variables [is_mul_left_invariant μ] -/-- If a left-invariant measure gives positive mass to a compact set, then -it gives positive mass to any open set. -/ -@[to_additive] + +/-- If a left-invariant measure gives positive mass to a compact set, then it gives positive mass to +any open set. -/ +@[to_additive "If a left-invariant measure gives positive mass to a compact set, then it gives +positive mass to any open set."] lemma is_open_pos_measure_of_mul_left_invariant_of_compact (K : set G) (hK : is_compact K) (h : μ K ≠ 0) : is_open_pos_measure μ := @@ -271,7 +274,7 @@ begin end /-- A nonzero left-invariant regular measure gives positive mass to any open set. -/ -@[to_additive] +@[to_additive "A nonzero left-invariant regular measure gives positive mass to any open set."] lemma is_open_pos_measure_of_mul_left_invariant_of_regular [regular μ] (h₀ : μ ≠ 0) : is_open_pos_measure μ := let ⟨K, hK, h2K⟩ := regular.exists_compact_not_null.mpr h₀ @@ -299,9 +302,10 @@ lemma measure_pos_iff_nonempty_of_is_mul_left_invariant [regular μ] 0 < μ s ↔ s.nonempty := pos_iff_ne_zero.trans $ measure_ne_zero_iff_nonempty_of_is_mul_left_invariant h3μ hs -/-- If a left-invariant measure gives finite mass to a nonempty open set, then -it gives finite mass to any compact set. -/ -@[to_additive] +/-- If a left-invariant measure gives finite mass to a nonempty open set, then it gives finite mass +to any compact set. -/ +@[to_additive "If a left-invariant measure gives finite mass to a nonempty open set, then it gives +finite mass to any compact set."] lemma measure_lt_top_of_is_compact_of_is_mul_left_invariant (U : set G) (hU : is_open U) (h'U : U.nonempty) (h : μ U ≠ ∞) {K : set G} (hK : is_compact K) : μ K < ∞ := @@ -317,7 +321,8 @@ end /-- If a left-invariant measure gives finite mass to a set with nonempty interior, then it gives finite mass to any compact set. -/ -@[to_additive] +@[to_additive "If a left-invariant measure gives finite mass to a set with nonempty interior, then +it gives finite mass to any compact set."] lemma measure_lt_top_of_is_compact_of_is_mul_left_invariant' {U : set G} (hU : (interior U).nonempty) (h : μ U ≠ ∞) {K : set G} (hK : is_compact K) : μ K < ∞ := @@ -333,7 +338,9 @@ variables [comm_group G] /-- In an abelian group every left invariant measure is also right-invariant. We don't declare the converse as an instance, since that would loop type-class inference, and we use `is_mul_left_invariant` as default hypotheses in abelian groups. -/ -@[priority 100, to_additive] +@[priority 100, to_additive "In an abelian additive group every left invariant measure is also +right-invariant. We don't declare the converse as an instance, since that would loop type-class +inference, and we use `is_add_left_invariant` as default hypotheses in abelian groups."] instance is_mul_left_invariant.is_mul_right_invariant {μ : measure G} [is_mul_left_invariant μ] : is_mul_right_invariant μ := ⟨λ g, by simp_rw [mul_comm, map_mul_left_eq_self]⟩ @@ -358,10 +365,17 @@ class is_haar_measure {G : Type*} [group G] [topological_space G] [measurable_sp (μ : measure G) extends is_finite_measure_on_compacts μ, is_mul_left_invariant μ, is_open_pos_measure μ : Prop -/- Record that a Haar measure on a locally compact space is locally finite. This is needed as the +/-- Record that a Haar measure on a locally compact space is locally finite. This is needed as the fact that a measure which is finite on compacts is locally finite is not registered as an instance, -to avoid an instance loop. -/ -@[priority 100, to_additive] -- see Note [lower instance priority] +to avoid an instance loop. + +See Note [lower instance priority]. -/ + +@[priority 100, to_additive "Record that an additive Haar measure on a locally compact space is +locally finite. This is needed as the fact that a measure which is finite on compacts is locally +finite is not registered as an instance, to avoid an instance loop. + +See Note [lower instance priority]"] instance is_locally_finite_measure_of_is_haar_measure {G : Type*} [group G] [measurable_space G] [topological_space G] [locally_compact_space G] (μ : measure G) [is_haar_measure μ] : @@ -387,8 +401,9 @@ lemma is_haar_measure.smul {c : ℝ≥0∞} (cpos : c ≠ 0) (ctop : c ≠ ∞) to_is_open_pos_measure := is_open_pos_measure_smul μ cpos } /-- If a left-invariant measure gives positive mass to some compact set with nonempty interior, then -it is a Haar measure -/ -@[to_additive] +it is a Haar measure. -/ +@[to_additive "If a left-invariant measure gives positive mass to some compact set with nonempty +interior, then it is an additive Haar measure."] lemma is_haar_measure_of_is_compact_nonempty_interior [topological_group G] [borel_space G] (μ : measure G) [is_mul_left_invariant μ] (K : set G) (hK : is_compact K) (h'K : (interior K).nonempty) (h : μ K ≠ 0) (h' : μ K ≠ ∞) : @@ -399,7 +414,8 @@ lemma is_haar_measure_of_is_compact_nonempty_interior [topological_group G] [bor /-- The image of a Haar measure under a group homomorphism which is also a homeomorphism is again a Haar measure. -/ -@[to_additive] +@[to_additive "The image of an additive Haar measure under an additive group homomorphism which is +also a homeomorphism is again an additive Haar measure."] lemma is_haar_measure_map [borel_space G] [topological_group G] {H : Type*} [group H] [topological_space H] [measurable_space H] [borel_space H] [t2_space H] [topological_group H] (f : G ≃* H) (hf : continuous f) (hfsymm : continuous f.symm) : @@ -423,8 +439,12 @@ lemma is_haar_measure_map [borel_space G] [topological_group G] {H : Type*} [gro end, to_is_open_pos_measure := hf.is_open_pos_measure_map f.surjective } -/-- A Haar measure on a sigma-compact space is sigma-finite. -/ -@[priority 100, to_additive] -- see Note [lower instance priority] +/-- A Haar measure on a σ-compact space is σ-finite. + +See Note [lower instance priority] -/ +@[priority 100, to_additive "A Haar measure on a σ-compact space is σ-finite. + +See Note [lower instance priority]"] instance is_haar_measure.sigma_finite [sigma_compact_space G] : sigma_finite μ := ⟨⟨{ set := compact_covering G, set_mem := λ n, mem_univ _, @@ -435,11 +455,15 @@ open_locale topological_space open filter /-- If the neutral element of a group is not isolated, then a Haar measure on this group has -no atom. +no atoms. -This applies in particular to show that an additive Haar measure on a nontrivial -finite-dimensional real vector space has no atom. -/ -@[priority 100, to_additive] +The additive version of this instance applies in particular to show that an additive Haar measure on +a nontrivial finite-dimensional real vector space has no atom. -/ +@[priority 100, to_additive "If the zero element of an additive group is not isolated, then an +additive Haar measure on this group has no atoms. + +This applies in particular to show that an additive Haar measure on a nontrivial finite-dimensional +real vector space has no atom."] instance is_haar_measure.has_no_atoms [topological_group G] [borel_space G] [t1_space G] [locally_compact_space G] [(𝓝[≠] (1 : G)).ne_bot] (μ : measure G) [μ.is_haar_measure] : From 79ea30ceb4db0240e8877cc42b5d2a4ef9be1a9f Mon Sep 17 00:00:00 2001 From: leanprover-community-bot Date: Sat, 23 Apr 2022 03:26:36 +0000 Subject: [PATCH 190/373] chore(scripts): update nolints.txt (#13637) I am happy to remove some nolints for you! --- scripts/nolints.txt | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/scripts/nolints.txt b/scripts/nolints.txt index a0f3c4722dcf1..a5246ea31ca11 100644 --- a/scripts/nolints.txt +++ b/scripts/nolints.txt @@ -519,33 +519,6 @@ apply_nolint relator.lift_fun doc_blame apply_nolint relator.right_total doc_blame apply_nolint relator.right_unique doc_blame --- measure_theory/constructions/pi.lean -apply_nolint measure_theory.pi.is_inv_invariant_volume to_additive_doc -apply_nolint measure_theory.pi.is_mul_left_invariant_volume to_additive_doc - --- measure_theory/group/integration.lean -apply_nolint measure_theory.integral_eq_zero_of_mul_left_eq_neg to_additive_doc -apply_nolint measure_theory.integral_eq_zero_of_mul_right_eq_neg to_additive_doc -apply_nolint measure_theory.integral_mul_left_eq_self to_additive_doc -apply_nolint measure_theory.integral_mul_right_eq_self to_additive_doc -apply_nolint measure_theory.lintegral_eq_zero_of_is_mul_left_invariant to_additive_doc -apply_nolint measure_theory.lintegral_mul_left_eq_self to_additive_doc -apply_nolint measure_theory.lintegral_mul_right_eq_self to_additive_doc - --- measure_theory/group/measure.lean -apply_nolint measure_theory.forall_measure_preimage_mul_iff to_additive_doc -apply_nolint measure_theory.forall_measure_preimage_mul_right_iff to_additive_doc -apply_nolint measure_theory.is_mul_left_invariant.is_mul_right_invariant to_additive_doc -apply_nolint measure_theory.is_open_pos_measure_of_mul_left_invariant_of_compact to_additive_doc -apply_nolint measure_theory.is_open_pos_measure_of_mul_left_invariant_of_regular to_additive_doc -apply_nolint measure_theory.measure.is_haar_measure.has_no_atoms to_additive_doc -apply_nolint measure_theory.measure.is_haar_measure.sigma_finite to_additive_doc -apply_nolint measure_theory.measure.is_haar_measure_map to_additive_doc -apply_nolint measure_theory.measure.is_haar_measure_of_is_compact_nonempty_interior to_additive_doc -apply_nolint measure_theory.measure_lt_top_of_is_compact_of_is_mul_left_invariant to_additive_doc -apply_nolint measure_theory.measure_lt_top_of_is_compact_of_is_mul_left_invariant' to_additive_doc -apply_nolint measure_theory.measure_preimage_mul to_additive_doc - -- measure_theory/group/prod.lean apply_nolint measure_theory.absolutely_continuous_of_is_mul_left_invariant to_additive_doc apply_nolint measure_theory.map_prod_inv_mul_eq to_additive_doc From b62b53141d4a29c766a045c2175af1df39e0b84b Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sat, 23 Apr 2022 04:08:26 +0000 Subject: [PATCH 191/373] doc(analysis/normed_space/basic): Explain how to use non-unital normed algebras (#13605) [Zulip](https://leanprover.zulipchat.com/#narrow/stream/116395-maths/topic/.E2.9C.94.20Is.20the.20zero.20algebra.20normed.3F/near/279555566) --- src/analysis/normed_space/basic.lean | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/analysis/normed_space/basic.lean b/src/analysis/normed_space/basic.lean index 35fffc9a63514..c27104cedd8bd 100644 --- a/src/analysis/normed_space/basic.lean +++ b/src/analysis/normed_space/basic.lean @@ -338,7 +338,15 @@ end normed_space_nondiscrete section normed_algebra -/-- A normed algebra `𝕜'` over `𝕜` is normed module that is also an algebra. -/ +/-- A normed algebra `𝕜'` over `𝕜` is normed module that is also an algebra. + +See the implementation notes for `algebra` for a discussion about non-unital algebras. Following +the strategy there, a non-unital *normed* algebra can be written as: +```lean +variables [normed_field 𝕜] [non_unital_semi_normed_ring 𝕜'] +variables [normed_module 𝕜 𝕜'] [smul_comm_class 𝕜 𝕜' 𝕜'] [is_scalar_tower 𝕜 𝕜' 𝕜'] +``` +-/ class normed_algebra (𝕜 : Type*) (𝕜' : Type*) [normed_field 𝕜] [semi_normed_ring 𝕜'] extends algebra 𝕜 𝕜' := (norm_smul_le : ∀ (r : 𝕜) (x : 𝕜'), ∥r • x∥ ≤ ∥r∥ * ∥x∥) From 94f970a61979b8efc9dce0f9b03fcbb96dd07a3a Mon Sep 17 00:00:00 2001 From: antoinelab01 Date: Sat, 23 Apr 2022 04:08:27 +0000 Subject: [PATCH 192/373] feat(linear_algebra/basic): add a simp lemma for comp_right (#13625) --- src/linear_algebra/basic.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/linear_algebra/basic.lean b/src/linear_algebra/basic.lean index 03ed05e23ccec..43fde04ad6c3d 100644 --- a/src/linear_algebra/basic.lean +++ b/src/linear_algebra/basic.lean @@ -394,6 +394,10 @@ def comp_right (f : M₂ →ₗ[R] M₃) : (M →ₗ[R] M₂) →ₗ[R] (M → map_add' := λ _ _, linear_map.ext $ λ _, f.map_add _ _, map_smul' := λ _ _, linear_map.ext $ λ _, f.map_smul _ _ } +@[simp] +lemma comp_right_apply (f : M₂ →ₗ[R] M₃) (g : M →ₗ[R] M₂) : + comp_right f g = f.comp g := rfl + /-- Applying a linear map at `v : M`, seen as a linear map from `M →ₗ[R] M₂` to `M₂`. See also `linear_map.applyₗ'` for a version that works with two different semirings. From 26b2d7278dd2b5d9cab7b08224983b28a39bffe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Sat, 23 Apr 2022 04:08:28 +0000 Subject: [PATCH 193/373] feat(set_theory/game/pgame): Empty instances (#13635) --- src/set_theory/game/pgame.lean | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/set_theory/game/pgame.lean b/src/set_theory/game/pgame.lean index 5d2c1a1b3ef12..f2754be43624b 100644 --- a/src/set_theory/game/pgame.lean +++ b/src/set_theory/game/pgame.lean @@ -193,6 +193,9 @@ instance : has_zero pgame := ⟨⟨pempty, pempty, pempty.elim, pempty.elim⟩ @[simp] lemma zero_left_moves : (0 : pgame).left_moves = pempty := rfl @[simp] lemma zero_right_moves : (0 : pgame).right_moves = pempty := rfl +instance is_empty_zero_left_moves : is_empty (0 : pgame).left_moves := pempty.is_empty +instance is_empty_zero_right_moves : is_empty (0 : pgame).right_moves := pempty.is_empty + instance : inhabited pgame := ⟨0⟩ /-- The pre-game `one` is defined by `1 = { 0 | }`. -/ @@ -202,6 +205,8 @@ instance : has_one pgame := ⟨⟨punit, pempty, λ _, 0, pempty.elim⟩⟩ @[simp] lemma one_move_left : (1 : pgame).move_left punit.star = 0 := rfl @[simp] lemma one_right_moves : (1 : pgame).right_moves = pempty := rfl +instance is_empty_one_right_moves : is_empty (1 : pgame).right_moves := pempty.is_empty + /-- Define simultaneously by mutual induction the `<=` and `<` relation on pre-games. The ZFC definition says that `x = {xL | xR}` is less or equal to `y = {yL | yR}` if `∀ x₁ ∈ xL, x₁ < y` From 0bea7a085af15797ce88742011124dd91a252585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Sat, 23 Apr 2022 05:39:45 +0000 Subject: [PATCH 194/373] feat(set_theory/pgame): Lemmas about order and left/right moves (#13590) --- src/set_theory/game/pgame.lean | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/set_theory/game/pgame.lean b/src/set_theory/game/pgame.lean index f2754be43624b..128ef1f7b146d 100644 --- a/src/set_theory/game/pgame.lean +++ b/src/set_theory/game/pgame.lean @@ -352,6 +352,22 @@ theorem lt_mk_of_le {x : pgame} {yl yr : Type*} {yL : yl → pgame} {yR i} : (x ≤ yL i) → x < ⟨yl, yr, yL, yR⟩ := by { cases x, rw mk_lt_mk, exact λ h, or.inl ⟨_, h⟩ } +theorem move_left_lt_of_le {x y : pgame} {i} : + x ≤ y → x.move_left i < y := +by { cases x, exact lt_of_le_mk } + +theorem lt_move_right_of_le {x y : pgame} {i} : + x ≤ y → x < y.move_right i := +by { cases y, exact lt_of_mk_le } + +theorem lt_of_move_right_le {x y : pgame} {i} : + x.move_right i ≤ y → x < y := +by { cases x, rw move_right_mk, exact mk_lt_of_le } + +theorem lt_of_le_move_left {x y : pgame} {i} : + x ≤ y.move_left i → x < y := +by { cases y, rw move_left_mk, exact lt_mk_of_le } + private theorem not_le_lt {x y : pgame} : (¬ x ≤ y ↔ y < x) ∧ (¬ x < y ↔ y ≤ x) := begin From fe435de8ca7dcdda44d4f3e7ca99e8fe188489d7 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sat, 23 Apr 2022 05:39:47 +0000 Subject: [PATCH 195/373] feat(algebra/algebra/basic,analysis/normed_space/basic): The zero ring is a (normed) algebra (#13618) This instance probably isn't very useful, but it's nice to have in the docs as an example of what `normed_algebra` permits. --- src/algebra/algebra/basic.lean | 15 +++++++++++++++ src/analysis/normed_space/basic.lean | 3 +++ 2 files changed, 18 insertions(+) diff --git a/src/algebra/algebra/basic.lean b/src/algebra/algebra/basic.lean index f2266e8f70a84..2564185cecd65 100644 --- a/src/algebra/algebra/basic.lean +++ b/src/algebra/algebra/basic.lean @@ -310,6 +310,21 @@ lemma map_eq_self (x : R) : algebra_map R R x = x := rfl end id +section punit + +instance _root_.punit.algebra : algebra R punit := +{ to_fun := λ x, punit.star, + map_one' := rfl, + map_mul' := λ _ _, rfl, + map_zero' := rfl, + map_add' := λ _ _, rfl, + commutes' := λ _ _, rfl, + smul_def' := λ _ _, rfl } + +@[simp] lemma algebra_map_punit (r : R) : algebra_map R punit r = punit.star := rfl + +end punit + section prod variables (R A B) diff --git a/src/analysis/normed_space/basic.lean b/src/analysis/normed_space/basic.lean index c27104cedd8bd..48674e5d1c3fb 100644 --- a/src/analysis/normed_space/basic.lean +++ b/src/analysis/normed_space/basic.lean @@ -430,6 +430,9 @@ instance normed_algebra_rat {𝕜} [normed_division_ring 𝕜] [char_zero 𝕜] { norm_smul_le := λ q x, by rw [←smul_one_smul ℝ q x, rat.smul_one_eq_coe, norm_smul, rat.norm_cast_real], } +instance punit.normed_algebra : normed_algebra 𝕜 punit := +{ norm_smul_le := λ q x, by simp only [punit.norm_eq_zero, mul_zero] } + /-- The product of two normed algebras is a normed algebra, with the sup norm. -/ instance prod.normed_algebra {E F : Type*} [semi_normed_ring E] [semi_normed_ring F] [normed_algebra 𝕜 E] [normed_algebra 𝕜 F] : From 4ad7dc9d14d728552aa6081ee35ca85d4caee1e3 Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Sat, 23 Apr 2022 05:39:48 +0000 Subject: [PATCH 196/373] chore(algebra/ring/equiv): protect ring equiv lemmas for big operators (#13624) --- src/algebra/ring/equiv.lean | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/algebra/ring/equiv.lean b/src/algebra/ring/equiv.lean index 0e60d7a43986a..7c0e8d355380d 100644 --- a/src/algebra/ring/equiv.lean +++ b/src/algebra/ring/equiv.lean @@ -430,30 +430,30 @@ end semiring_hom section big_operators -lemma map_list_prod [semiring R] [semiring S] (f : R ≃+* S) (l : list R) : - f l.prod = (l.map f).prod := f.to_ring_hom.map_list_prod l +protected lemma map_list_prod [semiring R] [semiring S] (f : R ≃+* S) (l : list R) : + f l.prod = (l.map f).prod := map_list_prod f l -lemma map_list_sum [non_assoc_semiring R] [non_assoc_semiring S] (f : R ≃+* S) (l : list R) : - f l.sum = (l.map f).sum := f.to_ring_hom.map_list_sum l +protected lemma map_list_sum [non_assoc_semiring R] [non_assoc_semiring S] (f : R ≃+* S) + (l : list R) : f l.sum = (l.map f).sum := map_list_sum f l /-- An isomorphism into the opposite ring acts on the product by acting on the reversed elements -/ -lemma unop_map_list_prod [semiring R] [semiring S] (f : R ≃+* Sᵐᵒᵖ) (l : list R) : +protected lemma unop_map_list_prod [semiring R] [semiring S] (f : R ≃+* Sᵐᵒᵖ) (l : list R) : mul_opposite.unop (f l.prod) = (l.map (mul_opposite.unop ∘ f)).reverse.prod := -f.to_ring_hom.unop_map_list_prod l +unop_map_list_prod f l -lemma map_multiset_prod [comm_semiring R] [comm_semiring S] (f : R ≃+* S) (s : multiset R) : - f s.prod = (s.map f).prod := f.to_ring_hom.map_multiset_prod s +protected lemma map_multiset_prod [comm_semiring R] [comm_semiring S] (f : R ≃+* S) + (s : multiset R) : f s.prod = (s.map f).prod := map_multiset_prod f s -lemma map_multiset_sum [non_assoc_semiring R] [non_assoc_semiring S] - (f : R ≃+* S) (s : multiset R) : f s.sum = (s.map f).sum := f.to_ring_hom.map_multiset_sum s +protected lemma map_multiset_sum [non_assoc_semiring R] [non_assoc_semiring S] + (f : R ≃+* S) (s : multiset R) : f s.sum = (s.map f).sum := map_multiset_sum f s -lemma map_prod {α : Type*} [comm_semiring R] [comm_semiring S] (g : R ≃+* S) (f : α → R) +protected lemma map_prod {α : Type*} [comm_semiring R] [comm_semiring S] (g : R ≃+* S) (f : α → R) (s : finset α) : g (∏ x in s, f x) = ∏ x in s, g (f x) := -g.to_ring_hom.map_prod f s +map_prod g f s -lemma map_sum {α : Type*} [non_assoc_semiring R] [non_assoc_semiring S] +protected lemma map_sum {α : Type*} [non_assoc_semiring R] [non_assoc_semiring S] (g : R ≃+* S) (f : α → R) (s : finset α) : g (∑ x in s, f x) = ∑ x in s, g (f x) := -g.to_ring_hom.map_sum f s +map_sum g f s end big_operators From 8c262dae1613346a015a166e64d1ead54e086185 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Sat, 23 Apr 2022 05:39:49 +0000 Subject: [PATCH 197/373] chore(analysis/normed_space/ray): golf (#13629) Golf 2 proofs --- src/analysis/normed_space/ray.lean | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/analysis/normed_space/ray.lean b/src/analysis/normed_space/ray.lean index d3f13bee8d676..a813093626bbe 100644 --- a/src/analysis/normed_space/ray.lean +++ b/src/analysis/normed_space/ray.lean @@ -58,15 +58,11 @@ variables {x y : F} lemma norm_inj_on_ray_left (hx : x ≠ 0) : {y | same_ray ℝ x y}.inj_on norm := begin rintro y hy z hz h, - obtain rfl | hz' := eq_or_ne z 0, - { rwa [norm_zero, norm_eq_zero] at h }, - have hy' : y ≠ 0, - { rwa [←norm_ne_zero_iff, ←h, norm_ne_zero_iff] at hz' }, - obtain ⟨r, hr, rfl⟩ := hy.exists_pos_left hx hy', - obtain ⟨s, hs, rfl⟩ := hz.exists_pos_left hx hz', - simp_rw [norm_smul, mul_left_inj' (norm_ne_zero_iff.2 hx), norm_of_nonneg hr.le, - norm_of_nonneg hs.le] at h, - rw h, + rcases hy.exists_nonneg_left hx with ⟨r, hr, rfl⟩, + rcases hz.exists_nonneg_left hx with ⟨s, hs, rfl⟩, + rw [norm_smul, norm_smul, mul_left_inj' (norm_ne_zero_iff.2 hx), norm_of_nonneg hr, + norm_of_nonneg hs] at h, + rw h end lemma norm_inj_on_ray_right (hy : y ≠ 0) : {x | same_ray ℝ x y}.inj_on norm := @@ -80,12 +76,8 @@ lemma same_ray_iff_norm_smul_eq : same_ray ℝ x y ↔ ∥x∥ • y = ∥y∥ vectors `∥x∥⁻¹ • x` and `∥y∥⁻¹ • y` are equal. -/ lemma same_ray_iff_inv_norm_smul_eq_of_ne (hx : x ≠ 0) (hy : y ≠ 0) : same_ray ℝ x y ↔ ∥x∥⁻¹ • x = ∥y∥⁻¹ • y := -begin - have : ∥x∥⁻¹ * ∥y∥⁻¹ ≠ 0, by simp *, - rw [same_ray_iff_norm_smul_eq, ← smul_right_inj this]; try { apply_instance }, - rw [smul_comm, mul_smul, mul_smul, smul_inv_smul₀, inv_smul_smul₀, eq_comm], - exacts [norm_ne_zero_iff.2 hy, norm_ne_zero_iff.2 hx] -end +by rw [inv_smul_eq_iff₀, smul_comm, eq_comm, inv_smul_eq_iff₀, same_ray_iff_norm_smul_eq]; + rwa norm_ne_zero_iff alias same_ray_iff_inv_norm_smul_eq_of_ne ↔ same_ray.inv_norm_smul_eq _ From afd8a525e0db02ff233c51c628b49a2a90b4a2be Mon Sep 17 00:00:00 2001 From: Oliver Nash Date: Sat, 23 Apr 2022 09:50:22 +0000 Subject: [PATCH 198/373] feat(order/hom/basic): add simp lemmas for `strict_mono.order_iso` and friends (#13606) Formalized as part of the Sphere Eversion project. --- src/order/hom/basic.lean | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/order/hom/basic.lean b/src/order/hom/basic.lean index 1fd59ccf52afc..d95dfac61d161 100644 --- a/src/order/hom/basic.lean +++ b/src/order/hom/basic.lean @@ -676,27 +676,44 @@ protected noncomputable def strict_mono_on.order_iso {α β} [linear_order α] [ { to_equiv := hf.inj_on.bij_on_image.equiv _, map_rel_iff' := λ x y, hf.le_iff_le x.2 y.2 } +namespace strict_mono + +variables {α β} [linear_order α] [preorder β] +variables (f : α → β) (h_mono : strict_mono f) (h_surj : function.surjective f) + /-- A strictly monotone function from a linear order is an order isomorphism between its domain and its range. -/ -protected noncomputable def strict_mono.order_iso {α β} [linear_order α] [preorder β] (f : α → β) - (h_mono : strict_mono f) : α ≃o set.range f := +@[simps apply] protected noncomputable def order_iso : α ≃o set.range f := { to_equiv := equiv.of_injective f h_mono.injective, map_rel_iff' := λ a b, h_mono.le_iff_le } /-- A strictly monotone surjective function from a linear order is an order isomorphism. -/ -noncomputable def strict_mono.order_iso_of_surjective {α β} [linear_order α] [preorder β] - (f : α → β) (h_mono : strict_mono f) (h_surj : function.surjective f) : α ≃o β := +noncomputable def order_iso_of_surjective : α ≃o β := (h_mono.order_iso f).trans $ (order_iso.set_congr _ _ h_surj.range_eq).trans order_iso.set.univ +@[simp] lemma coe_order_iso_of_surjective : + (order_iso_of_surjective f h_mono h_surj : α → β) = f := +rfl + +@[simp] lemma order_iso_of_surjective_symm_apply_self (a : α) : + (order_iso_of_surjective f h_mono h_surj).symm (f a) = a := +(order_iso_of_surjective f h_mono h_surj).symm_apply_apply _ + +lemma order_iso_of_surjective_self_symm_apply (b : β) : + f ((order_iso_of_surjective f h_mono h_surj).symm b) = b := +(order_iso_of_surjective f h_mono h_surj).apply_symm_apply _ + /-- A strictly monotone function with a right inverse is an order isomorphism. -/ -def strict_mono.order_iso_of_right_inverse {α β} [linear_order α] [preorder β] - (f : α → β) (h_mono : strict_mono f) (g : β → α) (hg : function.right_inverse g f) : α ≃o β := +@[simps {fully_applied := false}] def order_iso_of_right_inverse + (g : β → α) (hg : function.right_inverse g f) : α ≃o β := { to_fun := f, inv_fun := g, left_inv := λ x, h_mono.injective $ hg _, right_inv := hg, .. order_embedding.of_strict_mono f h_mono } +end strict_mono + /-- An order isomorphism is also an order isomorphism between dual orders. -/ protected def order_iso.dual [has_le α] [has_le β] (f : α ≃o β) : order_dual α ≃o order_dual β := ⟨f.to_equiv, λ _ _, f.map_rel_iff⟩ From 09eb35fd0e0d59c37ef95d1f243ef1c8a4f4b4a9 Mon Sep 17 00:00:00 2001 From: Bolton Bailey Date: Sat, 23 Apr 2022 21:10:27 +0000 Subject: [PATCH 199/373] feat(data/part): add get_or_else_of_dom (#13588) Adds a lemma --- src/data/part.lean | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/data/part.lean b/src/data/part.lean index f7c4cded0d5ed..b3c27269773cf 100644 --- a/src/data/part.lean +++ b/src/data/part.lean @@ -110,6 +110,8 @@ instance : inhabited (part α) := ⟨none⟩ function returns `a`. -/ def some (a : α) : part α := ⟨true, λ_, a⟩ +@[simp] lemma some_dom (a : α) : (some a).dom := trivial + theorem mem_unique : ∀ {a b : α} {o : part α}, a ∈ o → b ∈ o → a = b | _ _ ⟨p, f⟩ ⟨h₁, rfl⟩ ⟨h₂, rfl⟩ := rfl @@ -139,6 +141,8 @@ theorem eq_none_iff {o : part α} : o = none ↔ ∀ a, a ∉ o := theorem eq_none_iff' {o : part α} : o = none ↔ ¬ o.dom := ⟨λ e, e.symm ▸ id, λ h, eq_none_iff.2 (λ a h', h h'.fst)⟩ +@[simp] lemma not_none_dom : ¬ (none : part α).dom := id + @[simp] lemma some_ne_none (x : α) : some x ≠ none := by { intro h, change none.dom, rw [← h], trivial } @@ -193,12 +197,17 @@ otherwise. -/ def get_or_else (a : part α) [decidable a.dom] (d : α) := if ha : a.dom then a.get ha else d +lemma get_or_else_of_dom (a : part α) (h : a.dom) [decidable a.dom] (d : α) : + get_or_else a d = a.get h := dif_pos h + +lemma get_or_else_of_not_dom (a : part α) (h : ¬ a.dom) [decidable a.dom] (d : α) : + get_or_else a d = d := dif_neg h + @[simp] lemma get_or_else_none (d : α) [decidable (none : part α).dom] : get_or_else none d = d := -dif_neg id +none.get_or_else_of_not_dom not_none_dom d @[simp] lemma get_or_else_some (a : α) (d : α) [decidable (some a).dom] : - get_or_else (some a) d = a := -dif_pos trivial + get_or_else (some a) d = a := (some a).get_or_else_of_dom (some_dom a) d @[simp] theorem mem_to_option {o : part α} [decidable o.dom] {a : α} : a ∈ to_option o ↔ a ∈ o := From 44a05db5a73e352fbf68e3dc854ee7a2d31dc831 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sat, 23 Apr 2022 22:43:24 +0000 Subject: [PATCH 200/373] fix(topology/algebra/matrix): correct a lemma name (#13640) --- src/topology/algebra/matrix.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/topology/algebra/matrix.lean b/src/topology/algebra/matrix.lean index f099572743c6d..bd176eb590088 100644 --- a/src/topology/algebra/matrix.lean +++ b/src/topology/algebra/matrix.lean @@ -72,7 +72,7 @@ lemma continuous.matrix_row {A : X → n → R} (hA : continuous A) : continuous continuous_matrix $ λ i j, (continuous_apply _).comp hA @[continuity] -lemma continuous_matrix.diagonal [has_zero R] [decidable_eq n] {A : X → n → R} (hA : continuous A) : +lemma continuous.matrix_diagonal [has_zero R] [decidable_eq n] {A : X → n → R} (hA : continuous A) : continuous (λ x, diagonal (A x)) := continuous_matrix $ λ i j, ((continuous_apply i).comp hA).if_const _ continuous_zero From 34b1cfd80a1e199ff9dfa3eeab34721832fc87bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Sat, 23 Apr 2022 22:43:25 +0000 Subject: [PATCH 201/373] feat(set_theory/game/pgame): Strengthen `move_{left/right}_mk` (#13646) --- src/set_theory/game/pgame.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/set_theory/game/pgame.lean b/src/set_theory/game/pgame.lean index 128ef1f7b146d..8ab3ea303b33a 100644 --- a/src/set_theory/game/pgame.lean +++ b/src/set_theory/game/pgame.lean @@ -138,15 +138,15 @@ pgame.mk (fin L.length) (fin R.length) (λ i, L.nth_le i i.is_lt) (λ j, R.nth_l /-- The new game after Left makes an allowed move. -/ def move_left : Π (g : pgame), left_moves g → pgame -| (mk l _ L _) i := L i +| (mk l _ L _) := L /-- The new game after Right makes an allowed move. -/ def move_right : Π (g : pgame), right_moves g → pgame -| (mk _ r _ R) j := R j +| (mk _ r _ R) := R @[simp] lemma left_moves_mk {xl xr xL xR} : (⟨xl, xr, xL, xR⟩ : pgame).left_moves = xl := rfl -@[simp] lemma move_left_mk {xl xr xL xR i} : (⟨xl, xr, xL, xR⟩ : pgame).move_left i = xL i := rfl +@[simp] lemma move_left_mk {xl xr xL xR} : (⟨xl, xr, xL, xR⟩ : pgame).move_left = xL := rfl @[simp] lemma right_moves_mk {xl xr xL xR} : (⟨xl, xr, xL, xR⟩ : pgame).right_moves = xr := rfl -@[simp] lemma move_right_mk {xl xr xL xR j} : (⟨xl, xr, xL, xR⟩ : pgame).move_right j = xR j := rfl +@[simp] lemma move_right_mk {xl xr xL xR} : (⟨xl, xr, xL, xR⟩ : pgame).move_right = xR := rfl /-- `subsequent p q` says that `p` can be obtained by playing some nonempty sequence of moves from `q`. -/ From 1abfde6cba9794bad68e5d4ca0ff92cc2a0a6586 Mon Sep 17 00:00:00 2001 From: Eric Rodriguez Date: Sat, 23 Apr 2022 22:43:26 +0000 Subject: [PATCH 202/373] chore(group_theory/exponent): generalise (#13647) Generalises a few lemmas to not require cancellativity. --- src/group_theory/exponent.lean | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/group_theory/exponent.lean b/src/group_theory/exponent.lean index c2ab3e650f7e3..55a442fd94475 100644 --- a/src/group_theory/exponent.lean +++ b/src/group_theory/exponent.lean @@ -219,12 +219,6 @@ end have _ := exponent_ne_zero_iff_range_order_of_finite h, by rwa [ne.def, not_iff_comm, iff.comm] at this -end monoid - -section left_cancel_monoid - -variable [left_cancel_monoid G] - @[to_additive lcm_add_order_eq_exponent] lemma lcm_order_eq_exponent [fintype G] : (finset.univ : finset G).lcm order_of = exponent G := begin @@ -234,6 +228,12 @@ begin rw [hm, pow_mul, pow_order_of_eq_one, one_pow] end +end monoid + +section left_cancel_monoid + +variable [left_cancel_monoid G] + @[to_additive] lemma exponent_ne_zero_of_fintype [fintype G] : exponent G ≠ 0 := by simpa [←lcm_order_eq_exponent, finset.lcm_eq_zero_iff] using λ x, (order_of_pos x).ne' @@ -242,7 +242,7 @@ end left_cancel_monoid section comm_monoid -variable [cancel_comm_monoid G] +variable [comm_monoid G] @[to_additive] lemma exponent_eq_supr_order_of (h : ∀ g : G, 0 < order_of g) : exponent G = ⨆ g : G, order_of g := @@ -296,6 +296,12 @@ begin exact exponent_eq_supr_order_of (λ g, ne.bot_lt $ this g) } end +end comm_monoid + +section cancel_comm_monoid + +variables [cancel_comm_monoid G] + @[to_additive] lemma exponent_eq_max'_order_of [fintype G] : exponent G = ((@finset.univ G _).image order_of).max' ⟨1, by simp⟩ := begin @@ -303,6 +309,6 @@ begin exact exponent_eq_supr_order_of order_of_pos end -end comm_monoid +end cancel_comm_monoid end monoid From cc406db0c3751c7b6c0521991b837527cfe9ce83 Mon Sep 17 00:00:00 2001 From: Eric Rodriguez Date: Sat, 23 Apr 2022 22:43:27 +0000 Subject: [PATCH 203/373] feat(algebra/ring/basic): generalisation linter suggestions (#13649) --- src/algebra/ring/basic.lean | 96 +++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 40 deletions(-) diff --git a/src/algebra/ring/basic.lean b/src/algebra/ring/basic.lean index 571575878e96f..5d9b8db4d1854 100644 --- a/src/algebra/ring/basic.lean +++ b/src/algebra/ring/basic.lean @@ -222,6 +222,15 @@ protected def function.surjective.semiring end injective_surjective_maps +section has_one_has_add + +variables [has_one α] [has_add α] + +lemma one_add_one_eq_two : 1 + 1 = (2 : α) := +by unfold bit0 + +end has_one_has_add + section non_unital_semiring variables [non_unital_semiring α] @@ -245,6 +254,9 @@ by rw [mul_add, mul_one] theorem two_mul (n : α) : 2 * n = n + n := eq.trans (right_distrib 1 1 n) (by simp) +theorem bit0_eq_two_mul (n : α) : bit0 n = 2 * n := +(two_mul _).symm + theorem mul_two (n : α) : n * 2 = n + n := (left_distrib n 1 1).trans (by simp) @@ -253,12 +265,6 @@ end non_assoc_semiring section semiring variables [semiring α] -lemma one_add_one_eq_two : 1 + 1 = (2 : α) := -by unfold bit0 - -theorem bit0_eq_two_mul (n : α) : bit0 n = 2 * n := -(two_mul _).symm - @[to_additive] lemma mul_ite {α} [has_mul α] (P : Prop) [decidable P] (a b c : α) : a * (if P then b else c) = if P then a * b else a * c := by split_ifs; refl @@ -312,6 +318,16 @@ namespace add_hom end add_hom +section add_hom_class + +variables {F : Type*} [non_assoc_semiring α] [non_assoc_semiring β] [add_hom_class F α β] + +/-- Additive homomorphisms preserve `bit0`. -/ +@[simp] lemma map_bit0 (f : F) (a : α) : (f (bit0 a) : β) = bit0 (f a) := +map_add _ _ _ + +end add_hom_class + namespace add_monoid_hom /-- Left multiplication by an element of a (semi)ring is an `add_monoid_hom` -/ @@ -568,10 +584,6 @@ class ring_hom_class (F : Type*) (R S : out_param Type*) variables {F : Type*} [non_assoc_semiring α] [non_assoc_semiring β] [ring_hom_class F α β] -/-- Ring homomorphisms preserve `bit0`. -/ -@[simp] lemma map_bit0 (f : F) (a : α) : (f (bit0 a) : β) = bit0 (f a) := -map_add _ _ _ - /-- Ring homomorphisms preserve `bit1`. -/ @[simp] lemma map_bit1 (f : F) (a : α) : (f (bit1 a) : β) = bit1 (f a) := by simp [bit1] @@ -906,6 +918,34 @@ by rw [←zero_mul (0 : α), ←neg_mul, mul_zero, mul_zero] end mul_zero_class +section semigroup + +variables [semigroup α] [has_distrib_neg α] {a b c : α} + +theorem dvd_neg_of_dvd (h : a ∣ b) : (a ∣ -b) := +let ⟨c, hc⟩ := h in ⟨-c, by simp [hc]⟩ + +theorem dvd_of_dvd_neg (h : a ∣ -b) : (a ∣ b) := +let t := dvd_neg_of_dvd h in by rwa neg_neg at t + +/-- An element a of a semigroup with a distributive negation divides the negation of an element b +iff a divides b. -/ +@[simp] lemma dvd_neg (a b : α) : (a ∣ -b) ↔ (a ∣ b) := +⟨dvd_of_dvd_neg, dvd_neg_of_dvd⟩ + +theorem neg_dvd_of_dvd (h : a ∣ b) : -a ∣ b := +let ⟨c, hc⟩ := h in ⟨-c, by simp [hc]⟩ + +theorem dvd_of_neg_dvd (h : -a ∣ b) : a ∣ b := +let t := neg_dvd_of_dvd h in by rwa neg_neg at t + +/-- The negation of an element a of a semigroup with a distributive negation divides +another element b iff a divides b. -/ +@[simp] lemma neg_dvd (a b : α) : (-a ∣ b) ↔ (a ∣ b) := +⟨dvd_of_neg_dvd, neg_dvd_of_dvd⟩ + +end semigroup + section group variables [group α] [has_distrib_neg α] @@ -1207,30 +1247,6 @@ instance comm_ring.to_comm_semiring [s : comm_ring α] : comm_semiring α := section ring variables [ring α] {a b c : α} -theorem dvd_neg_of_dvd (h : a ∣ b) : (a ∣ -b) := -dvd.elim h - (assume c, assume : b = a * c, - dvd.intro (-c) (by simp [this])) - -theorem dvd_of_dvd_neg (h : a ∣ -b) : (a ∣ b) := -let t := dvd_neg_of_dvd h in by rwa neg_neg at t - -/-- An element a of a ring divides the additive inverse of an element b iff a divides b. -/ -@[simp] lemma dvd_neg (a b : α) : (a ∣ -b) ↔ (a ∣ b) := -⟨dvd_of_dvd_neg, dvd_neg_of_dvd⟩ - -theorem neg_dvd_of_dvd (h : a ∣ b) : -a ∣ b := -dvd.elim h - (assume c, assume : b = a * c, - dvd.intro (-c) (by simp [this])) - -theorem dvd_of_neg_dvd (h : -a ∣ b) : a ∣ b := -let t := neg_dvd_of_dvd h in by rwa neg_neg at t - -/-- The additive inverse of an element a of a ring divides another element b iff a divides b. -/ -@[simp] lemma neg_dvd (a b : α) : (-a ∣ b) ↔ (a ∣ b) := -⟨dvd_of_neg_dvd, neg_dvd_of_dvd⟩ - theorem dvd_sub (h₁ : a ∣ b) (h₂ : a ∣ c) : a ∣ b - c := by { rw sub_eq_add_neg, exact dvd_add h₁ (dvd_neg_of_dvd h₂) } @@ -1329,10 +1345,10 @@ end end comm_ring -lemma succ_ne_self [ring α] [nontrivial α] (a : α) : a + 1 ≠ a := +lemma succ_ne_self [non_assoc_ring α] [nontrivial α] (a : α) : a + 1 ≠ a := λ h, one_ne_zero ((add_right_inj a).mp (by simp [h])) -lemma pred_ne_self [ring α] [nontrivial α] (a : α) : a - 1 ≠ a := +lemma pred_ne_self [non_assoc_ring α] [nontrivial α] (a : α) : a - 1 ≠ a := λ h, one_ne_zero (neg_injective ((add_right_inj a).mp (by simpa [sub_eq_add_neg] using h))) /-- Left `mul` by a `k : α` over `[ring α]` is injective, if `k` is not a zero divisor. @@ -1353,8 +1369,8 @@ begin rw [sub_mul, sub_eq_zero, h'] end -lemma is_regular_of_ne_zero' [ring α] [no_zero_divisors α] {k : α} (hk : k ≠ 0) : - is_regular k := +lemma is_regular_of_ne_zero' [non_unital_non_assoc_ring α] [no_zero_divisors α] {k : α} + (hk : k ≠ 0) : is_regular k := ⟨is_left_regular_of_non_zero_divisor k (λ x h, (no_zero_divisors.eq_zero_or_eq_zero_of_mul_eq_zero h).resolve_left hk), is_right_regular_of_non_zero_divisor k @@ -1484,7 +1500,7 @@ variables [mul_one_class R] [has_distrib_neg R] {a x y : R} end section -variables [ring R] {a b x y x' y' : R} +variables [non_unital_non_assoc_ring R] {a b x y x' y' : R} @[simp] lemma sub_right (h : semiconj_by a x y) (h' : semiconj_by a x' y') : semiconj_by a (x - x') (y - y') := @@ -1554,7 +1570,7 @@ variables [mul_one_class R] [has_distrib_neg R] {a : R} end section -variables [ring R] {a b c : R} +variables [non_unital_non_assoc_ring R] {a b c : R} @[simp] theorem sub_right : commute a b → commute a c → commute a (b - c) := semiconj_by.sub_right @[simp] theorem sub_left : commute a c → commute b c → commute (a - b) c := semiconj_by.sub_left From 2d0ff32921bbe47e4829b3f69ab8184752a7f798 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sun, 24 Apr 2022 00:36:50 +0000 Subject: [PATCH 204/373] chore(algebra/*): move function instances (#13650) These should have been much earlier, but I put them in their current places to avoid large build times in what was an already large refactor. --- src/algebra/algebra/basic.lean | 6 ++++++ .../manifold/algebra/smooth_functions.lean | 6 ------ src/group_theory/group_action/pi.lean | 15 +++++++++++++++ src/linear_algebra/pi.lean | 15 --------------- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/algebra/algebra/basic.lean b/src/algebra/algebra/basic.lean index 2564185cecd65..6ec8e263ce9c2 100644 --- a/src/algebra/algebra/basic.lean +++ b/src/algebra/algebra/basic.lean @@ -1384,6 +1384,12 @@ rfl end pi +/-- A special case of `pi.algebra` for non-dependent types. Lean struggles to elaborate +definitions elsewhere in the library without this, -/ +instance function.algebra {R : Type*} (I : Type*) (A : Type*) [comm_semiring R] + [semiring A] [algebra R A] : algebra R (I → A) := +pi.algebra _ _ + namespace alg_equiv /-- A family of algebra equivalences `Π j, (A₁ j ≃ₐ A₂ j)` generates a diff --git a/src/geometry/manifold/algebra/smooth_functions.lean b/src/geometry/manifold/algebra/smooth_functions.lean index 1f1e47b815a37..e0b1ebd25623b 100644 --- a/src/geometry/manifold/algebra/smooth_functions.lean +++ b/src/geometry/manifold/algebra/smooth_functions.lean @@ -233,12 +233,6 @@ instance algebra : algebra 𝕜 C^∞⟮I, N; 𝓘(𝕜, A), A⟯ := smul_def' := λ c f, by ext x; exact algebra.smul_def' _ _, ..smooth_map.semiring } -/-- A special case of `pi.algebra` for non-dependent types. Lean get stuck on the definition -below without this. -/ -instance _root_.function.algebra (I : Type*) {R : Type*} (A : Type*) {r : comm_semiring R} - [semiring A] [algebra R A] : algebra R (I → A) := -pi.algebra _ _ - /-- Coercion to a function as an `alg_hom`. -/ @[simps] def coe_fn_alg_hom : C^∞⟮I, N; 𝓘(𝕜, A), A⟯ →ₐ[𝕜] (N → A) := diff --git a/src/group_theory/group_action/pi.lean b/src/group_theory/group_action/pi.lean index afae7ce4c1bc2..5c897d4f82343 100644 --- a/src/group_theory/group_action/pi.lean +++ b/src/group_theory/group_action/pi.lean @@ -154,6 +154,21 @@ end pi namespace function +/-- Non-dependent version of `pi.has_scalar`. Lean gets confused by the dependent instance if this +is not present. -/ +@[to_additive has_vadd] +instance has_scalar {ι R M : Type*} [has_scalar R M] : + has_scalar R (ι → M) := +pi.has_scalar + +/-- Non-dependent version of `pi.smul_comm_class`. Lean gets confused by the dependent instance if +this is not present. -/ +@[to_additive] +instance smul_comm_class {ι α β M : Type*} + [has_scalar α M] [has_scalar β M] [smul_comm_class α β M] : + smul_comm_class α β (ι → M) := +pi.smul_comm_class + @[to_additive] lemma update_smul {α : Type*} [Π i, has_scalar α (f i)] [decidable_eq I] (c : α) (f₁ : Π i, f i) (i : I) (x₁ : f i) : diff --git a/src/linear_algebra/pi.lean b/src/linear_algebra/pi.lean index 901a42a70d415..17521b57d695f 100644 --- a/src/linear_algebra/pi.lean +++ b/src/linear_algebra/pi.lean @@ -427,21 +427,6 @@ lemma linear_map.vec_cons_apply {n} (f : M →ₗ[R] M₂) (g : M →ₗ[R] (fin end semiring -/-- Non-dependent version of `pi.has_scalar`. Lean gets confused by the dependent instance if this -is not present. -/ -@[to_additive function.has_vadd] -instance function.has_scalar {ι R M : Type*} [has_scalar R M] : - has_scalar R (ι → M) := -pi.has_scalar - -/-- Non-dependent version of `pi.smul_comm_class`. Lean gets confused by the dependent instance if -this is not present. -/ -@[to_additive] -instance function.smul_comm_class {ι α β M : Type*} - [has_scalar α M] [has_scalar β M] [smul_comm_class α β M]: - smul_comm_class α β (ι → M) := -pi.smul_comm_class - section comm_semiring variables [comm_semiring R] [add_comm_monoid M] [add_comm_monoid M₂] [add_comm_monoid M₃] From b0552c157365575f43c4f077c34739c579ae476b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Sun, 24 Apr 2022 02:22:27 +0000 Subject: [PATCH 205/373] docs(tactic/lint/default): Module docstring (#13570) Write the module docstring. --- src/tactic/lint/default.lean | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/tactic/lint/default.lean b/src/tactic/lint/default.lean index 3f611d626bc54..b3a03b928d748 100644 --- a/src/tactic/lint/default.lean +++ b/src/tactic/lint/default.lean @@ -3,11 +3,19 @@ Copyright (c) 2020 Floris van Doorn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn, Robert Y. Lewis, Gabriel Ebner -/ +import algebra.group.to_additive import tactic.lint.frontend +import tactic.lint.misc import tactic.lint.simp import tactic.lint.type_classes -import tactic.lint.misc -import algebra.group.to_additive + +/-! +# Default linters + +This file defines the list of linters that are run in mathlib CI. Not all linters are considered +"default" and run that way. A `linter` is marked as default if it is tagged with the `linter` +attribute. +-/ open tactic From 946f253cc9b9ebf9515cba5bbca1cf5ffb61907e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Sun, 24 Apr 2022 02:22:28 +0000 Subject: [PATCH 206/373] chore(set_theory/game/pgame): Cleanup (#13612) We remove redundant parentheses, and make arguments explicit when they can't be inferred. --- src/set_theory/game/impartial.lean | 2 +- src/set_theory/game/pgame.lean | 39 ++++++++++++++---------------- src/set_theory/surreal/basic.lean | 6 ++--- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/set_theory/game/impartial.lean b/src/set_theory/game/impartial.lean index 7ca38792a2a04..dc978fcf3594c 100644 --- a/src/set_theory/game/impartial.lean +++ b/src/set_theory/game/impartial.lean @@ -129,7 +129,7 @@ iff.symm $ iff_not_comm.1 $ iff.symm $ not_first_wins G lemma add_self (G : pgame) [G.impartial] : (G + G).first_loses := first_loses_is_zero.2 $ equiv_trans (add_congr (neg_equiv_self G) G.equiv_refl) - add_left_neg_equiv + (add_left_neg_equiv G) lemma equiv_iff_sum_first_loses (G H : pgame) [G.impartial] [H.impartial] : G ≈ H ↔ (G + H).first_loses := diff --git a/src/set_theory/game/pgame.lean b/src/set_theory/game/pgame.lean index 8ab3ea303b33a..4016c21e1907e 100644 --- a/src/set_theory/game/pgame.lean +++ b/src/set_theory/game/pgame.lean @@ -899,7 +899,7 @@ using_well_founded { dec_tac := pgame_wf_tac } theorem add_assoc_equiv {x y z : pgame} : (x + y) + z ≈ x + (y + z) := (add_assoc_relabelling x y z).equiv -private lemma add_le_add_right : Π {x y z : pgame} (h : x ≤ y), x + z ≤ y + z +private lemma add_le_add_right : ∀ {x y z : pgame} (h : x ≤ y), x + z ≤ y + z | (mk xl xr xL xR) (mk yl yr yL yR) (mk zl zr zL zR) := begin intros h, @@ -965,7 +965,7 @@ theorem add_congr {w x y z : pgame} (h₁ : w ≈ x) (h₂ : y ≈ z) : w + y theorem sub_congr {w x y z : pgame} (h₁ : w ≈ x) (h₂ : y ≈ z) : w - y ≈ x - z := add_congr h₁ (neg_congr h₂) -theorem add_left_neg_le_zero : Π {x : pgame}, (-x) + x ≤ 0 +theorem add_left_neg_le_zero : ∀ (x : pgame), -x + x ≤ 0 | ⟨xl, xr, xL, xR⟩ := begin rw [le_def], @@ -988,35 +988,32 @@ begin end using_well_founded { dec_tac := pgame_wf_tac } -theorem zero_le_add_left_neg : Π {x : pgame}, 0 ≤ (-x) + x := +theorem zero_le_add_left_neg (x : pgame) : 0 ≤ -x + x := begin - intro x, rw [le_iff_neg_ge, pgame.neg_zero], - exact le_trans neg_add_le add_left_neg_le_zero + exact le_trans neg_add_le (add_left_neg_le_zero _) end -theorem add_left_neg_equiv {x : pgame} : (-x) + x ≈ 0 := -⟨add_left_neg_le_zero, zero_le_add_left_neg⟩ +theorem add_left_neg_equiv (x : pgame) : -x + x ≈ 0 := +⟨add_left_neg_le_zero x, zero_le_add_left_neg x⟩ -theorem add_right_neg_le_zero {x : pgame} : x + (-x) ≤ 0 := -calc x + (-x) ≤ (-x) + x : add_comm_le - ... ≤ 0 : add_left_neg_le_zero +theorem add_right_neg_le_zero (x : pgame) : x + -x ≤ 0 := +le_trans add_comm_le (add_left_neg_le_zero x) -theorem zero_le_add_right_neg {x : pgame} : 0 ≤ x + (-x) := -calc 0 ≤ (-x) + x : zero_le_add_left_neg - ... ≤ x + (-x) : add_comm_le +theorem zero_le_add_right_neg (x : pgame) : 0 ≤ x + -x := +le_trans (zero_le_add_left_neg x) add_comm_le -theorem add_right_neg_equiv {x : pgame} : x + (-x) ≈ 0 := -⟨add_right_neg_le_zero, zero_le_add_right_neg⟩ +theorem add_right_neg_equiv (x : pgame) : x + -x ≈ 0 := +⟨add_right_neg_le_zero x, zero_le_add_right_neg x⟩ instance covariant_class_swap_add_lt : covariant_class pgame pgame (swap (+)) (<) := ⟨λ x y z h, suffices z + x ≤ y + x → z ≤ y, by { rw ←not_le at ⊢ h, exact mt this h }, λ w, calc z ≤ z + 0 : (add_zero_relabelling _).symm.le - ... ≤ z + (x + -x) : add_le_add_left zero_le_add_right_neg _ + ... ≤ z + (x + -x) : add_le_add_left (zero_le_add_right_neg x) _ ... ≤ z + x + -x : (add_assoc_relabelling _ _ _).symm.le ... ≤ y + x + -x : add_le_add_right w _ ... ≤ y + (x + -x) : (add_assoc_relabelling _ _ _).le - ... ≤ y + 0 : add_le_add_left add_right_neg_le_zero _ + ... ≤ y + 0 : add_le_add_left (add_right_neg_le_zero x) _ ... ≤ y : (add_zero_relabelling _).le⟩ instance covariant_class_add_lt : covariant_class pgame pgame (+) (<) := @@ -1025,20 +1022,20 @@ instance covariant_class_add_lt : covariant_class pgame pgame (+) (<) := ... ≤ x + z : add_comm_le⟩ theorem le_iff_sub_nonneg {x y : pgame} : x ≤ y ↔ 0 ≤ y - x := -⟨λ h, le_trans zero_le_add_right_neg (add_le_add_right h _), +⟨λ h, le_trans (zero_le_add_right_neg x) (add_le_add_right h _), λ h, calc x ≤ 0 + x : (zero_add_relabelling x).symm.le ... ≤ y - x + x : add_le_add_right h _ ... ≤ y + (-x + x) : (add_assoc_relabelling _ _ _).le - ... ≤ y + 0 : add_le_add_left (add_left_neg_le_zero) _ + ... ≤ y + 0 : add_le_add_left (add_left_neg_le_zero x) _ ... ≤ y : (add_zero_relabelling y).le⟩ theorem lt_iff_sub_pos {x y : pgame} : x < y ↔ 0 < y - x := -⟨λ h, lt_of_le_of_lt zero_le_add_right_neg (add_lt_add_right h _), +⟨λ h, lt_of_le_of_lt (zero_le_add_right_neg x) (add_lt_add_right h _), λ h, calc x ≤ 0 + x : (zero_add_relabelling x).symm.le ... < y - x + x : add_lt_add_right h _ ... ≤ y + (-x + x) : (add_assoc_relabelling _ _ _).le - ... ≤ y + 0 : add_le_add_left (add_left_neg_le_zero) _ + ... ≤ y + 0 : add_le_add_left (add_left_neg_le_zero x) _ ... ≤ y : (add_zero_relabelling y).le⟩ /-- The pre-game `star`, which is fuzzy/confused with zero. -/ diff --git a/src/set_theory/surreal/basic.lean b/src/set_theory/surreal/basic.lean index 60ec8e90bb428..dd6158d57fcde 100644 --- a/src/set_theory/surreal/basic.lean +++ b/src/set_theory/surreal/basic.lean @@ -316,10 +316,10 @@ instance : ordered_add_comm_group surreal := { add := (+), add_assoc := by { rintros ⟨_⟩ ⟨_⟩ ⟨_⟩, exact quotient.sound add_assoc_equiv }, zero := 0, - zero_add := by { rintros ⟨_⟩, exact quotient.sound (pgame.zero_add_equiv _) }, - add_zero := by { rintros ⟨_⟩, exact quotient.sound (pgame.add_zero_equiv _) }, + zero_add := by { rintros ⟨_⟩, exact quotient.sound (pgame.zero_add_equiv a) }, + add_zero := by { rintros ⟨_⟩, exact quotient.sound (pgame.add_zero_equiv a) }, neg := has_neg.neg, - add_left_neg := by { rintros ⟨_⟩, exact quotient.sound pgame.add_left_neg_equiv }, + add_left_neg := by { rintros ⟨_⟩, exact quotient.sound (pgame.add_left_neg_equiv a) }, add_comm := by { rintros ⟨_⟩ ⟨_⟩, exact quotient.sound pgame.add_comm_equiv }, le := (≤), lt := (<), From 5998b497fd3223c4307f027d1a6a75f0b33af339 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Sun, 24 Apr 2022 02:22:30 +0000 Subject: [PATCH 207/373] chore(order/filter/basic): golf 2 proofs (#13614) --- src/order/filter/basic.lean | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/order/filter/basic.lean b/src/order/filter/basic.lean index be1a8c560c35d..0716d02eb10bc 100644 --- a/src/order/filter/basic.lean +++ b/src/order/filter/basic.lean @@ -2744,12 +2744,8 @@ coprod_ne_bot_iff.2 (or.inr ⟨‹_›, ‹_›⟩) lemma principal_coprod_principal (s : set α) (t : set β) : (𝓟 s).coprod (𝓟 t) = 𝓟 (sᶜ ×ˢ tᶜ)ᶜ := -begin - rw [filter.coprod, comap_principal, comap_principal, sup_principal], - congr, - ext x, - simp ; tauto, -end +by rw [filter.coprod, comap_principal, comap_principal, sup_principal, set.prod_eq, compl_inter, + preimage_compl, preimage_compl, compl_compl, compl_compl] -- this inequality can be strict; see `map_const_principal_coprod_map_id_principal` and -- `map_prod_map_const_id_principal_coprod_principal` below. @@ -2770,13 +2766,8 @@ example showing that the inequality in the lemma `map_prod_map_coprod_le` can be lemma map_const_principal_coprod_map_id_principal {α β ι : Type*} (a : α) (b : β) (i : ι) : (map (λ _ : α, b) (𝓟 {a})).coprod (map id (𝓟 {i})) = 𝓟 (({b} : set β) ×ˢ (univ : set ι) ∪ (univ : set β) ×ˢ ({i} : set ι)) := -begin - rw [map_principal, map_principal, principal_coprod_principal], - congr, - ext ⟨b', i'⟩, - simp, - tauto, -end +by simp only [map_principal, filter.coprod, comap_principal, sup_principal, image_singleton, + image_id, prod_univ, univ_prod] /-- Characterization of the `filter.map` of the coproduct of two principal filters `𝓟 {a}` and `𝓟 {i}`, under the `prod.map` of two functions, respectively the constant function `λ a, b` and the From 92ca1369638b203f8c48df4c72b53df68c93f33d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Sun, 24 Apr 2022 02:22:31 +0000 Subject: [PATCH 208/373] feat(set_theory/game/pgame): Birthdays of pre-games (#13636) --- src/set_theory/game/birthday.lean | 94 +++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 src/set_theory/game/birthday.lean diff --git a/src/set_theory/game/birthday.lean b/src/set_theory/game/birthday.lean new file mode 100644 index 0000000000000..7a5bf4b51819b --- /dev/null +++ b/src/set_theory/game/birthday.lean @@ -0,0 +1,94 @@ +/- +Copyright (c) 2022 Violeta Hernández Palacios. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Violeta Hernández Palacios +-/ + +import set_theory.ordinal.arithmetic +import set_theory.game.pgame + +/-! +# Birthdays of games + +The birthday of a game is an ordinal that represents at which "step" the game was constructed. We +define it recursively as the least ordinal larger than the birthdays of its left and right games. We +prove the basic properties about these. + +# Main declarations + +- `pgame.birthday`: The birthday of a pre-game. + +# Todo + +- Define the birthdays of `game`s and `surreal`s. +- Characterize the birthdays of basic arithmetical operations. +-/ + +universe u + +namespace pgame + +/-- The birthday of a pre-game is inductively defined as the least strict upper bound of the +birthdays of its left and right games. It may be thought as the "step" in which a certain game is +constructed. -/ +noncomputable def birthday : pgame.{u} → ordinal.{u} +| ⟨xl, xr, xL, xR⟩ := + max (ordinal.lsub.{u u} $ λ i, birthday (xL i)) (ordinal.lsub.{u u} $ λ i, birthday (xR i)) + +theorem birthday_def (x : pgame) : birthday x = max + (ordinal.lsub.{u u} (λ i, birthday (x.move_left i))) + (ordinal.lsub.{u u} (λ i, birthday (x.move_right i))) := +by { cases x, rw birthday, refl } + +theorem birthday_move_left_lt {x : pgame} (i : x.left_moves) : + (x.move_left i).birthday < x.birthday := +by { cases x, rw birthday, exact lt_max_of_lt_left (ordinal.lt_lsub _ i) } + +theorem birthday_move_right_lt {x : pgame} (i : x.right_moves) : + (x.move_right i).birthday < x.birthday := +by { cases x, rw birthday, exact lt_max_of_lt_right (ordinal.lt_lsub _ i) } + +theorem lt_birthday_iff {x : pgame} {o : ordinal} : o < x.birthday ↔ + (∃ i : x.left_moves, o ≤ (x.move_left i).birthday) ∨ + (∃ i : x.right_moves, o ≤ (x.move_right i).birthday) := +begin + split, + { rw birthday_def, + intro h, + cases lt_max_iff.1 h with h' h', + { left, + rwa ordinal.lt_lsub_iff at h' }, + { right, + rwa ordinal.lt_lsub_iff at h' } }, + { rintro (⟨i, hi⟩ | ⟨i, hi⟩), + { exact hi.trans_lt (birthday_move_left_lt i) }, + { exact hi.trans_lt (birthday_move_right_lt i) } } +end + +theorem relabelling.birthday_congr : ∀ {x y : pgame.{u}}, relabelling x y → birthday x = birthday y +| ⟨xl, xr, xL, xR⟩ ⟨yl, yr, yL, yR⟩ ⟨L, R, hL, hR⟩ := begin + rw [birthday, birthday], + congr' 1, + all_goals + { apply ordinal.lsub_eq_of_range_eq.{u u u}, + ext i, + split }, + { rintro ⟨j, rfl⟩, + exact ⟨L j, (relabelling.birthday_congr (hL j)).symm⟩ }, + { rintro ⟨j, rfl⟩, + refine ⟨L.symm j, relabelling.birthday_congr _⟩, + convert hL (L.symm j), + rw L.apply_symm_apply }, + { rintro ⟨j, rfl⟩, + refine ⟨R j, (relabelling.birthday_congr _).symm⟩, + convert hR (R j), + rw R.symm_apply_apply }, + { rintro ⟨j, rfl⟩, + exact ⟨R.symm j, relabelling.birthday_congr (hR j)⟩ } +end +using_well_founded { dec_tac := pgame_wf_tac } + +@[simp] theorem birthday_zero : birthday 0 = 0 := +by rw [birthday_def, ordinal.lsub_empty, ordinal.lsub_empty, max_self] + +end pgame From b8b8bf3ea0c625fa1f950034a184e07c67f7bcfe Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Sun, 24 Apr 2022 04:20:58 +0000 Subject: [PATCH 209/373] refactor(category_theory/monoidal): prove coherence lemmas by coherence (#13406) Now that we have a basic monoidal coherence tactic, we can replace some boring proofs of particular coherence lemmas with `by coherence`. I've also simply deleted a few lemmas which are not actually used elsewhere in mathlib, and can be proved `by coherence`. Co-authored-by: Scott Morrison --- src/category_theory/monoidal/Mon_.lean | 1 + src/category_theory/monoidal/braided.lean | 2 +- src/category_theory/monoidal/category.lean | 142 +++--------------- .../monoidal/coherence_lemmas.lean | 78 ++++++++++ src/category_theory/monoidal/rigid.lean | 4 +- 5 files changed, 105 insertions(+), 122 deletions(-) create mode 100644 src/category_theory/monoidal/coherence_lemmas.lean diff --git a/src/category_theory/monoidal/Mon_.lean b/src/category_theory/monoidal/Mon_.lean index 01661befeaad2..65a7a5c8cc3a6 100644 --- a/src/category_theory/monoidal/Mon_.lean +++ b/src/category_theory/monoidal/Mon_.lean @@ -5,6 +5,7 @@ Authors: Scott Morrison -/ import category_theory.monoidal.braided import category_theory.monoidal.discrete +import category_theory.monoidal.coherence_lemmas import category_theory.limits.shapes.terminal import algebra.punit_instances diff --git a/src/category_theory/monoidal/braided.lean b/src/category_theory/monoidal/braided.lean index fa2a6de44e94d..6652067774925 100644 --- a/src/category_theory/monoidal/braided.lean +++ b/src/category_theory/monoidal/braided.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Scott Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Scott Morrison -/ -import category_theory.monoidal.coherence +import category_theory.monoidal.coherence_lemmas import category_theory.monoidal.natural_transformation import category_theory.monoidal.discrete diff --git a/src/category_theory/monoidal/category.lean b/src/category_theory/monoidal/category.lean index ea8b2a640da51..044b2efecc52d 100644 --- a/src/category_theory/monoidal/category.lean +++ b/src/category_theory/monoidal/category.lean @@ -160,22 +160,6 @@ by { ext, simp [←tensor_comp], } variables {U V W X Y Z : C} --- When `rewrite_search` lands, add @[search] attributes to - --- monoidal_category.tensor_id monoidal_category.tensor_comp monoidal_category.associator_naturality --- monoidal_category.left_unitor_naturality monoidal_category.right_unitor_naturality --- monoidal_category.pentagon monoidal_category.triangle - --- tensor_comp_id tensor_id_comp comp_id_tensor_tensor_id --- triangle_assoc_comp_left triangle_assoc_comp_right --- triangle_assoc_comp_left_inv triangle_assoc_comp_right_inv --- left_unitor_tensor left_unitor_tensor_inv --- right_unitor_tensor right_unitor_tensor_inv --- pentagon_inv --- associator_inv_naturality --- left_unitor_inv_naturality --- right_unitor_inv_naturality - lemma tensor_dite {P : Prop} [decidable P] {W X Y Z : C} (f : W ⟶ X) (g : P → (Y ⟶ Z)) (g' : ¬P → (Y ⟶ Z)) : f ⊗ (if h : P then g h else g' h) = if h : P then f ⊗ g h else f ⊗ g' h := @@ -240,28 +224,15 @@ by { rw [←cancel_mono (λ_ Y).hom, left_unitor_naturality, left_unitor_natural (f ⊗ (𝟙 (𝟙_ C)) = g ⊗ (𝟙 (𝟙_ C))) ↔ (f = g) := by { rw [←cancel_mono (ρ_ Y).hom, right_unitor_naturality, right_unitor_naturality], simp } --- See Proposition 2.2.4 of -@[reassoc] -lemma left_unitor_tensor' (X Y : C) : - ((α_ (𝟙_ C) X Y).hom) ≫ ((λ_ (X ⊗ Y)).hom) = ((λ_ X).hom ⊗ (𝟙 Y)) := -by - rw [←tensor_left_iff, id_tensor_comp, ←cancel_epi (α_ (𝟙_ C) (𝟙_ C ⊗ X) Y).hom, - ←cancel_epi ((α_ (𝟙_ C) (𝟙_ C) X).hom ⊗ 𝟙 Y), pentagon_assoc, triangle, ←associator_naturality, - ←comp_tensor_id_assoc, triangle, associator_naturality, tensor_id] - -@[reassoc, simp] -lemma left_unitor_tensor (X Y : C) : - ((λ_ (X ⊗ Y)).hom) = ((α_ (𝟙_ C) X Y).inv) ≫ ((λ_ X).hom ⊗ (𝟙 Y)) := -by { rw [←left_unitor_tensor'], simp } - -lemma left_unitor_tensor_inv' (X Y : C) : - ((λ_ (X ⊗ Y)).inv) ≫ ((α_ (𝟙_ C) X Y).inv) = ((λ_ X).inv ⊗ (𝟙 Y)) := -eq_of_inv_eq_inv (by simp) +/-! The lemmas in the next section are true by coherence, +but we prove them directly as they are used in proving the coherence theorem. -/ +section -@[reassoc, simp] -lemma left_unitor_tensor_inv (X Y : C) : - (λ_ (X ⊗ Y)).inv = ((λ_ X).inv ⊗ (𝟙 Y)) ≫ (α_ (𝟙_ C) X Y).hom := -by { rw [←left_unitor_tensor_inv'], simp } +@[reassoc] +lemma pentagon_inv (W X Y Z : C) : + ((𝟙 W) ⊗ (α_ X Y Z).inv) ≫ (α_ W (X ⊗ Y) Z).inv ≫ ((α_ W X Y).inv ⊗ (𝟙 Z)) + = (α_ W X (Y ⊗ Z)).inv ≫ (α_ (W ⊗ X) Y Z).inv := +category_theory.eq_of_inv_eq_inv (by simp [pentagon]) @[reassoc, simp] lemma right_unitor_tensor (X Y : C) : @@ -276,13 +247,23 @@ lemma right_unitor_tensor_inv (X Y : C) : ((ρ_ (X ⊗ Y)).inv) = ((𝟙 X) ⊗ (ρ_ Y).inv) ≫ (α_ X Y (𝟙_ C)).inv := eq_of_inv_eq_inv (by simp) -@[reassoc] -lemma id_tensor_right_unitor_inv (X Y : C) : 𝟙 X ⊗ (ρ_ Y).inv = (ρ_ _).inv ≫ (α_ _ _ _).hom := -by simp only [right_unitor_tensor_inv, category.comp_id, iso.inv_hom_id, category.assoc] +lemma triangle_assoc_comp_left (X Y : C) : + (α_ X (𝟙_ C) Y).hom ≫ ((𝟙 X) ⊗ (λ_ Y).hom) = (ρ_ X).hom ⊗ 𝟙 Y := +monoidal_category.triangle X Y -@[reassoc] -lemma left_unitor_inv_tensor_id (X Y : C) : (λ_ X).inv ⊗ 𝟙 Y = (λ_ _).inv ≫ (α_ _ _ _).inv := -by simp only [left_unitor_tensor_inv, assoc, comp_id, hom_inv_id] +@[simp, reassoc] lemma triangle_assoc_comp_right (X Y : C) : + (α_ X (𝟙_ C) Y).inv ≫ ((ρ_ X).hom ⊗ 𝟙 Y) = ((𝟙 X) ⊗ (λ_ Y).hom) := +by rw [←triangle_assoc_comp_left, iso.inv_hom_id_assoc] + +@[simp, reassoc] lemma triangle_assoc_comp_left_inv (X Y : C) : + ((𝟙 X) ⊗ (λ_ Y).inv) ≫ (α_ X (𝟙_ C) Y).inv = ((ρ_ X).inv ⊗ 𝟙 Y) := +begin + apply (cancel_mono ((ρ_ X).hom ⊗ 𝟙 Y)).1, + simp only [triangle_assoc_comp_right, assoc], + rw [←id_tensor_comp, iso.inv_hom_id, ←comp_tensor_id, iso.inv_hom_id] +end + +end @[reassoc] lemma associator_inv_naturality {X Y Z X' Y' Z' : C} (f : X ⟶ X') (g : Y ⟶ Y') (h : Z ⟶ Z') : @@ -309,53 +290,6 @@ lemma associator_inv_conjugation {X X' Y Y' Z Z' : C} (f : X ⟶ X') (g : Y ⟶ (α_ X Y Z).inv ≫ ((f ⊗ g) ⊗ h) ≫ (α_ X' Y' Z').hom = f ⊗ g ⊗ h := by rw [associator_naturality, inv_hom_id_assoc] -@[reassoc] -lemma pentagon_inv (W X Y Z : C) : - ((𝟙 W) ⊗ (α_ X Y Z).inv) ≫ (α_ W (X ⊗ Y) Z).inv ≫ ((α_ W X Y).inv ⊗ (𝟙 Z)) - = (α_ W X (Y ⊗ Z)).inv ≫ (α_ (W ⊗ X) Y Z).inv := -category_theory.eq_of_inv_eq_inv (by simp [pentagon]) - -@[reassoc] -lemma pentagon_inv_inv_hom (W X Y Z : C) : - (α_ W (X ⊗ Y) Z).inv ≫ ((α_ W X Y).inv ⊗ (𝟙 Z)) ≫ (α_ (W ⊗ X) Y Z).hom - = ((𝟙 W) ⊗ (α_ X Y Z).hom) ≫ (α_ W X (Y ⊗ Z)).inv := -begin - rw ←((iso.eq_comp_inv _).mp (pentagon_inv W X Y Z)), - slice_rhs 1 2 { rw [←id_tensor_comp, iso.hom_inv_id] }, - simp only [tensor_id, assoc, id_comp] -end - -lemma triangle_assoc_comp_left (X Y : C) : - (α_ X (𝟙_ C) Y).hom ≫ ((𝟙 X) ⊗ (λ_ Y).hom) = (ρ_ X).hom ⊗ 𝟙 Y := -monoidal_category.triangle X Y - -@[simp, reassoc] lemma triangle_assoc_comp_right (X Y : C) : - (α_ X (𝟙_ C) Y).inv ≫ ((ρ_ X).hom ⊗ 𝟙 Y) = ((𝟙 X) ⊗ (λ_ Y).hom) := -by rw [←triangle_assoc_comp_left, iso.inv_hom_id_assoc] - -@[simp, reassoc] lemma triangle_assoc_comp_right_inv (X Y : C) : - ((ρ_ X).inv ⊗ 𝟙 Y) ≫ (α_ X (𝟙_ C) Y).hom = ((𝟙 X) ⊗ (λ_ Y).inv) := -begin - apply (cancel_mono (𝟙 X ⊗ (λ_ Y).hom)).1, - simp only [assoc, triangle_assoc_comp_left], - rw [←comp_tensor_id, iso.inv_hom_id, ←id_tensor_comp, iso.inv_hom_id] -end - -@[simp, reassoc] lemma triangle_assoc_comp_left_inv (X Y : C) : - ((𝟙 X) ⊗ (λ_ Y).inv) ≫ (α_ X (𝟙_ C) Y).inv = ((ρ_ X).inv ⊗ 𝟙 Y) := -begin - apply (cancel_mono ((ρ_ X).hom ⊗ 𝟙 Y)).1, - simp only [triangle_assoc_comp_right, assoc], - rw [←id_tensor_comp, iso.inv_hom_id, ←comp_tensor_id, iso.inv_hom_id] -end - -lemma unitors_equal : (λ_ (𝟙_ C)).hom = (ρ_ (𝟙_ C)).hom := -by rw [←tensor_left_iff, ←cancel_epi (α_ (𝟙_ C) (𝟙_ _) (𝟙_ _)).hom, ←cancel_mono (ρ_ (𝟙_ C)).hom, - triangle, ←right_unitor_tensor, right_unitor_naturality] - -lemma unitors_inv_equal : (λ_ (𝟙_ C)).inv = (ρ_ (𝟙_ C)).inv := -by { ext, simp [←unitors_equal] } - @[reassoc] lemma right_unitor_inv_comp_tensor (f : W ⟶ X) (g : 𝟙_ C ⟶ Z) : (ρ_ _).inv ≫ (f ⊗ g) = f ≫ (ρ_ _).inv ≫ (𝟙 _ ⊗ g) := @@ -386,34 +320,6 @@ lemma tensor_inv_hom_id {V W X Y Z : C} (f : V ≅ W) (g : X ⟶ Y) (h : Y ⟶ Z (g ⊗ f.inv) ≫ (h ⊗ f.hom) = (g ≫ h) ⊗ 𝟙 W := by rw [←tensor_comp, f.inv_hom_id] -@[reassoc] -lemma pentagon_hom_inv {W X Y Z : C} : - (α_ W X (Y ⊗ Z)).hom ≫ (𝟙 W ⊗ (α_ X Y Z).inv) - = (α_ (W ⊗ X) Y Z).inv ≫ ((α_ W X Y).hom ⊗ 𝟙 Z) ≫ (α_ W (X ⊗ Y) Z).hom := -begin - have pent := pentagon W X Y Z, - rw ←iso.comp_inv_eq at pent, - rw [iso.eq_inv_comp, ←pent], - simp only [tensor_hom_inv_id, iso.inv_hom_id_assoc, tensor_id, category.comp_id, category.assoc], -end - -@[reassoc] -lemma pentagon_inv_hom (W X Y Z : C) : - (α_ (W ⊗ X) Y Z).inv ≫ ((α_ W X Y).hom ⊗ 𝟙 Z) - = (α_ W X (Y ⊗ Z)).hom ≫ (𝟙 W ⊗ (α_ X Y Z).inv) ≫ (α_ W (X ⊗ Y) Z).inv := -begin - have pent := pentagon W X Y Z, - rw ←iso.inv_comp_eq at pent, - rw [←pent], - simp only [tensor_id, assoc, id_comp, comp_id, hom_inv_id, tensor_hom_inv_id_assoc], -end - -@[reassoc] -lemma pentagon_comp_id_tensor {W X Y Z : C} : - (α_ W (X ⊗ Y) Z).hom ≫ ((𝟙 W) ⊗ (α_ X Y Z).hom) - = ((α_ W X Y).inv ⊗ (𝟙 Z)) ≫ (α_ (W ⊗ X) Y Z).hom ≫ (α_ W X (Y ⊗ Z)).hom := -by { rw ←pentagon W X Y Z, simp } - end section diff --git a/src/category_theory/monoidal/coherence_lemmas.lean b/src/category_theory/monoidal/coherence_lemmas.lean new file mode 100644 index 0000000000000..8d8ff40a19d3c --- /dev/null +++ b/src/category_theory/monoidal/coherence_lemmas.lean @@ -0,0 +1,78 @@ +/- +Copyright (c) 2018 Michael Jendrusch. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Michael Jendrusch, Scott Morrison, Bhavik Mehta, Jakob von Raumer +-/ +import category_theory.monoidal.coherence + +/-! +# Lemmas which are consequences of monoidal coherence + +These lemmas are all proved `by coherence`. + +## Future work +Investigate whether these lemmas are really needed, +or if they can be replaced by use of the `coherence` tactic. +-/ + +open category_theory +open category_theory.category +open category_theory.iso + +namespace category_theory.monoidal_category + +variables {C : Type*} [category C] [monoidal_category C] + +-- See Proposition 2.2.4 of +@[reassoc] +lemma left_unitor_tensor' (X Y : C) : + ((α_ (𝟙_ C) X Y).hom) ≫ ((λ_ (X ⊗ Y)).hom) = ((λ_ X).hom ⊗ (𝟙 Y)) := +by coherence + +@[reassoc, simp] +lemma left_unitor_tensor (X Y : C) : + ((λ_ (X ⊗ Y)).hom) = ((α_ (𝟙_ C) X Y).inv) ≫ ((λ_ X).hom ⊗ (𝟙 Y)) := +by coherence + +@[reassoc] +lemma left_unitor_tensor_inv (X Y : C) : + (λ_ (X ⊗ Y)).inv = ((λ_ X).inv ⊗ (𝟙 Y)) ≫ (α_ (𝟙_ C) X Y).hom := +by coherence + +@[reassoc] +lemma id_tensor_right_unitor_inv (X Y : C) : 𝟙 X ⊗ (ρ_ Y).inv = (ρ_ _).inv ≫ (α_ _ _ _).hom := +by coherence + +@[reassoc] +lemma left_unitor_inv_tensor_id (X Y : C) : (λ_ X).inv ⊗ 𝟙 Y = (λ_ _).inv ≫ (α_ _ _ _).inv := +by coherence + +@[reassoc] +lemma pentagon_inv_inv_hom (W X Y Z : C) : + (α_ W (X ⊗ Y) Z).inv ≫ ((α_ W X Y).inv ⊗ (𝟙 Z)) ≫ (α_ (W ⊗ X) Y Z).hom + = ((𝟙 W) ⊗ (α_ X Y Z).hom) ≫ (α_ W X (Y ⊗ Z)).inv := +by coherence + +@[simp, reassoc] lemma triangle_assoc_comp_right_inv (X Y : C) : + ((ρ_ X).inv ⊗ 𝟙 Y) ≫ (α_ X (𝟙_ C) Y).hom = ((𝟙 X) ⊗ (λ_ Y).inv) := +by coherence + +lemma unitors_equal : (λ_ (𝟙_ C)).hom = (ρ_ (𝟙_ C)).hom := +by coherence + +lemma unitors_inv_equal : (λ_ (𝟙_ C)).inv = (ρ_ (𝟙_ C)).inv := +by coherence + +@[reassoc] +lemma pentagon_hom_inv {W X Y Z : C} : + (α_ W X (Y ⊗ Z)).hom ≫ (𝟙 W ⊗ (α_ X Y Z).inv) + = (α_ (W ⊗ X) Y Z).inv ≫ ((α_ W X Y).hom ⊗ 𝟙 Z) ≫ (α_ W (X ⊗ Y) Z).hom := +by coherence + +@[reassoc] +lemma pentagon_inv_hom (W X Y Z : C) : + (α_ (W ⊗ X) Y Z).inv ≫ ((α_ W X Y).hom ⊗ 𝟙 Z) + = (α_ W X (Y ⊗ Z)).hom ≫ (𝟙 W ⊗ (α_ X Y Z).inv) ≫ (α_ W (X ⊗ Y) Z).inv := +by coherence + +end category_theory.monoidal_category diff --git a/src/category_theory/monoidal/rigid.lean b/src/category_theory/monoidal/rigid.lean index 86e1604ab6905..8d4d32fcd4ac1 100644 --- a/src/category_theory/monoidal/rigid.lean +++ b/src/category_theory/monoidal/rigid.lean @@ -3,9 +3,7 @@ Copyright (c) 2021 Jakob von Raumer. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jakob von Raumer -/ - -import category_theory.monoidal.coherence - +import category_theory.monoidal.coherence_lemmas /-! # Rigid (autonomous) monoidal categories From e006f38ce18b92066e5ed09449e78d185910d78e Mon Sep 17 00:00:00 2001 From: tb65536 Date: Sun, 24 Apr 2022 06:52:55 +0000 Subject: [PATCH 210/373] feat(algebra/hom/iterate): Iterating an action (#13659) This PR adds `smul_iterate`, generalizing `mul_left_iterate` and `mul_right_iterate`. --- src/algebra/hom/iterate.lean | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/algebra/hom/iterate.lean b/src/algebra/hom/iterate.lean index f5bf0610a201e..63b253f5a01b2 100644 --- a/src/algebra/hom/iterate.lean +++ b/src/algebra/hom/iterate.lean @@ -7,6 +7,7 @@ Authors: Yury Kudryashov import algebra.group_power.basic import logic.function.iterate import group_theory.perm.basic +import group_theory.group_action.opposite /-! # Iterates of monoid and ring homomorphisms @@ -149,16 +150,16 @@ section monoid variables [monoid G] (a : G) (n : ℕ) +@[simp, to_additive] lemma smul_iterate [mul_action G H] : + ((•) a : H → H)^[n] = (•) (a^n) := +funext (λ b, nat.rec_on n (by rw [iterate_zero, id.def, pow_zero, one_smul]) + (λ n ih, by rw [iterate_succ', comp_app, ih, pow_succ, mul_smul])) + @[simp, to_additive] lemma mul_left_iterate : ((*) a)^[n] = (*) (a^n) := -nat.rec_on n (funext $ λ x, by simp) $ λ n ihn, -funext $ λ x, by simp [iterate_succ, ihn, pow_succ', mul_assoc] +smul_iterate a n @[simp, to_additive] lemma mul_right_iterate : (* a)^[n] = (* a ^ n) := -begin - induction n with d hd, - { simpa }, - { simp [← pow_succ, hd] } -end +smul_iterate (mul_opposite.op a) n @[to_additive] lemma mul_right_iterate_apply_one : (* a)^[n] 1 = a ^ n := From 812625597b89565712d7c597cad7faa0254bd673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Sun, 24 Apr 2022 08:21:40 +0000 Subject: [PATCH 211/373] feat(set_theory/surreal/basic): Definitional characterization of `numeric` (#13653) --- src/set_theory/surreal/basic.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/set_theory/surreal/basic.lean b/src/set_theory/surreal/basic.lean index dd6158d57fcde..53ea3a5cec371 100644 --- a/src/set_theory/surreal/basic.lean +++ b/src/set_theory/surreal/basic.lean @@ -52,6 +52,10 @@ def numeric : pgame → Prop | ⟨l, r, L, R⟩ := (∀ i j, L i < R j) ∧ (∀ i, numeric (L i)) ∧ (∀ i, numeric (R i)) +lemma numeric_def (x : pgame) : numeric x ↔ (∀ i j, x.move_left i < x.move_right j) ∧ + (∀ i, numeric (x.move_left i)) ∧ (∀ i, numeric (x.move_right i)) := +by { cases x, refl } + lemma numeric.move_left {x : pgame} (o : numeric x) (i : x.left_moves) : numeric (x.move_left i) := begin From 63da426d3cf9fb32bc2d5bcbd1a8a7565f63c0ef Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Sun, 24 Apr 2022 11:06:15 +0000 Subject: [PATCH 212/373] refactor(linear_algebra/dimension): further generalisations to division_ring (#13657) Co-authored-by: Scott Morrison --- .../affine_space/finite_dimensional.lean | 23 ++- src/linear_algebra/dimension.lean | 131 ++++++++++-------- 2 files changed, 95 insertions(+), 59 deletions(-) diff --git a/src/linear_algebra/affine_space/finite_dimensional.lean b/src/linear_algebra/affine_space/finite_dimensional.lean index ec1cc34dbe050..2f297c4804a24 100644 --- a/src/linear_algebra/affine_space/finite_dimensional.lean +++ b/src/linear_algebra/affine_space/finite_dimensional.lean @@ -24,13 +24,15 @@ open_locale big_operators classical affine section affine_space' -variables (k : Type*) {V : Type*} {P : Type*} [field k] [add_comm_group V] [module k V] - [affine_space V P] +variables (k : Type*) {V : Type*} {P : Type*} variables {ι : Type*} include V open affine_subspace finite_dimensional module +section +variables [division_ring k] [add_comm_group V] [module k V] [affine_space V P] + /-- The `vector_span` of a finite set is finite-dimensional. -/ lemma finite_dimensional_vector_span_of_finite {s : set P} (h : set.finite s) : finite_dimensional k (vector_span k s) := @@ -82,6 +84,11 @@ lemma finite_of_fin_dim_affine_independent [finite_dimensional k V] {s : set P} (hi : affine_independent k (coe : s → P)) : s.finite := ⟨fintype_of_fin_dim_affine_independent k hi⟩ +end + +section + +variables [field k] [add_comm_group V] [module k V] [affine_space V P] variables {k} /-- The `vector_span` of a finite subset of an affinely independent @@ -262,6 +269,11 @@ lemma finrank_vector_span_le_iff_not_affine_independent [fintype ι] (p : ι → finrank k (vector_span k (set.range p)) ≤ n ↔ ¬ affine_independent k p := (not_iff_comm.1 (affine_independent_iff_not_finrank_vector_span_le k p hc).symm).symm +end + +section division_ring +variables [division_ring k] [add_comm_group V] [module k V] [affine_space V P] + /-- A set of points is collinear if their `vector_span` has dimension at most `1`. -/ def collinear (s : set P) : Prop := module.rank k (vector_span k s) ≤ 1 @@ -364,6 +376,11 @@ begin simp [hp] } end +end division_ring + +section field +variables [field k] [add_comm_group V] [module k V] [affine_space V P] + /-- Three points are affinely independent if and only if they are not collinear. -/ lemma affine_independent_iff_not_collinear (p : fin 3 → P) : @@ -378,4 +395,6 @@ lemma collinear_iff_not_affine_independent (p : fin 3 → P) : by rw [collinear_iff_finrank_le_one, finrank_vector_span_le_iff_not_affine_independent k p (fintype.card_fin 3)] +end field + end affine_space' diff --git a/src/linear_algebra/dimension.lean b/src/linear_algebra/dimension.lean index 773ec53060c5c..0cbb22c2e9ce9 100644 --- a/src/linear_algebra/dimension.lean +++ b/src/linear_algebra/dimension.lean @@ -1035,7 +1035,6 @@ end division_ring section field variables [field K] [add_comm_group V] [module K V] [add_comm_group V₁] [module K V₁] variables [add_comm_group V'] [module K V'] -variables {K V} theorem dim_quotient_add_dim (p : submodule K V) : module.rank K (V ⧸ p) + module.rank K p = module.rank K V := @@ -1119,36 +1118,23 @@ lemma exists_mem_ne_zero_of_dim_pos {s : submodule K V} (h : 0 < module.rank K s ∃ b : V, b ∈ s ∧ b ≠ 0 := exists_mem_ne_zero_of_ne_bot $ assume eq, by rw [eq, dim_bot] at h; exact lt_irrefl _ h +end field + section rank --- TODO This definition, and some of the results about it, could be generalized to arbitrary rings. +section +variables [ring K] [add_comm_group V] [module K V] [add_comm_group V₁] [module K V₁] +variables [add_comm_group V'] [module K V'] + /-- `rank f` is the rank of a `linear_map f`, defined as the dimension of `f.range`. -/ def rank (f : V →ₗ[K] V') : cardinal := module.rank K f.range -lemma rank_le_domain (f : V →ₗ[K] V₁) : rank f ≤ module.rank K V := -by { rw [← dim_range_add_dim_ker f], exact self_le_add_right _ _ } - lemma rank_le_range (f : V →ₗ[K] V₁) : rank f ≤ module.rank K V₁ := dim_submodule_le _ -lemma rank_add_le (f g : V →ₗ[K] V') : rank (f + g) ≤ rank f + rank g := -calc rank (f + g) ≤ module.rank K (f.range ⊔ g.range : submodule K V') : - begin - refine dim_le_of_submodule _ _ _, - exact (linear_map.range_le_iff_comap.2 $ eq_top_iff'.2 $ - assume x, show f x + g x ∈ (f.range ⊔ g.range : submodule K V'), from - mem_sup.2 ⟨_, ⟨x, rfl⟩, _, ⟨x, rfl⟩, rfl⟩) - end - ... ≤ rank f + rank g : dim_add_le_dim_add_dim _ _ - -@[simp] lemma rank_zero : rank (0 : V →ₗ[K] V') = 0 := +@[simp] lemma rank_zero [nontrivial K] : rank (0 : V →ₗ[K] V') = 0 := by rw [rank, linear_map.range_zero, dim_bot] -lemma rank_finset_sum_le {η} (s : finset η) (f : η → V →ₗ[K] V') : - rank (∑ d in s, f d) ≤ ∑ d in s, rank (f d) := -@finset.sum_hom_rel _ _ _ _ _ (λa b, rank a ≤ b) f (λ d, rank (f d)) s (le_of_eq rank_zero) - (λ i g c h, le_trans (rank_add_le _ _) (add_le_add_left h _)) - variables [add_comm_group V''] [module K V''] lemma rank_comp_le1 (g : V →ₗ[K] V') (f : V' →ₗ[K] V'') : rank (f.comp g) ≤ rank f := @@ -1163,10 +1149,36 @@ variables [add_comm_group V'₁] [module K V'₁] lemma rank_comp_le2 (g : V →ₗ[K] V') (f : V' →ₗ[K] V'₁) : rank (f.comp g) ≤ rank g := by rw [rank, rank, linear_map.range_comp]; exact dim_map_le _ _ -end rank +end + +section field +variables [field K] [add_comm_group V] [module K V] [add_comm_group V₁] [module K V₁] +variables [add_comm_group V'] [module K V'] + +lemma rank_le_domain (f : V →ₗ[K] V₁) : rank f ≤ module.rank K V := +by { rw [← dim_range_add_dim_ker f], exact self_le_add_right _ _ } --- TODO The remainder of this file could be generalized to arbitrary rings. +lemma rank_add_le (f g : V →ₗ[K] V') : rank (f + g) ≤ rank f + rank g := +calc rank (f + g) ≤ module.rank K (f.range ⊔ g.range : submodule K V') : + begin + refine dim_le_of_submodule _ _ _, + exact (linear_map.range_le_iff_comap.2 $ eq_top_iff'.2 $ + assume x, show f x + g x ∈ (f.range ⊔ g.range : submodule K V'), from + mem_sup.2 ⟨_, ⟨x, rfl⟩, _, ⟨x, rfl⟩, rfl⟩) + end + ... ≤ rank f + rank g : dim_add_le_dim_add_dim _ _ +lemma rank_finset_sum_le {η} (s : finset η) (f : η → V →ₗ[K] V') : + rank (∑ d in s, f d) ≤ ∑ d in s, rank (f d) := +@finset.sum_hom_rel _ _ _ _ _ (λa b, rank a ≤ b) f (λ d, rank (f d)) s (le_of_eq rank_zero) + (λ i g c h, le_trans (rank_add_le _ _) (add_le_add_left h _)) + +end field + +end rank + +section division_ring +variables [division_ring K] [add_comm_group V] [module K V] [add_comm_group V'] [module K V'] /-- The `ι` indexed basis on `V`, where `ι` is an empty type and `V` is zero-dimensional. @@ -1209,40 +1221,6 @@ begin exact ⟨s, ⟨s, rfl, rfl⟩, si⟩ } end -lemma le_rank_iff_exists_linear_independent {c : cardinal} {f : V →ₗ[K] V'} : - c ≤ rank f ↔ - ∃ s : set V, cardinal.lift.{v'} (#s) = cardinal.lift.{v} c ∧ - linear_independent K (λ x : s, f x) := -begin - rcases f.range_restrict.exists_right_inverse_of_surjective f.range_range_restrict with ⟨g, hg⟩, - have fg : left_inverse f.range_restrict g, from linear_map.congr_fun hg, - refine ⟨λ h, _, _⟩, - { rcases le_dim_iff_exists_linear_independent.1 h with ⟨s, rfl, si⟩, - refine ⟨g '' s, cardinal.mk_image_eq_lift _ _ fg.injective, _⟩, - replace fg : ∀ x, f (g x) = x, by { intro x, convert congr_arg subtype.val (fg x) }, - replace si : linear_independent K (λ x : s, f (g x)), - by simpa only [fg] using si.map' _ (ker_subtype _), - exact si.image_of_comp s g f }, - { rintro ⟨s, hsc, si⟩, - have : linear_independent K (λ x : s, f.range_restrict x), - from linear_independent.of_comp (f.range.subtype) (by convert si), - convert cardinal_le_dim_of_linear_independent this.image, - rw [← cardinal.lift_inj, ← hsc, cardinal.mk_image_eq_of_inj_on_lift], - exact inj_on_iff_injective.2 this.injective } -end - -lemma le_rank_iff_exists_linear_independent_finset {n : ℕ} {f : V →ₗ[K] V'} : - ↑n ≤ rank f ↔ ∃ s : finset V, s.card = n ∧ linear_independent K (λ x : (s : set V), f x) := -begin - simp only [le_rank_iff_exists_linear_independent, cardinal.lift_nat_cast, - cardinal.lift_eq_nat_iff, cardinal.mk_eq_nat_iff_finset], - split, - { rintro ⟨s, ⟨t, rfl, rfl⟩, si⟩, - exact ⟨t, rfl, si⟩ }, - { rintro ⟨s, rfl, si⟩, - exact ⟨s, ⟨s, rfl, rfl⟩, si⟩ } -end - /-- A vector space has dimension at most `1` if and only if there is a single vector of which all vectors are multiples. -/ lemma dim_le_one_iff : module.rank K V ≤ 1 ↔ ∃ v₀ : V, ∀ v, ∃ r : K, r • v₀ = v := @@ -1315,6 +1293,45 @@ begin simp [hw] } } end +end division_ring + +section field +variables [field K] [add_comm_group V] [module K V] [add_comm_group V'] [module K V'] + +lemma le_rank_iff_exists_linear_independent {c : cardinal} {f : V →ₗ[K] V'} : + c ≤ rank f ↔ + ∃ s : set V, cardinal.lift.{v'} (#s) = cardinal.lift.{v} c ∧ + linear_independent K (λ x : s, f x) := +begin + rcases f.range_restrict.exists_right_inverse_of_surjective f.range_range_restrict with ⟨g, hg⟩, + have fg : left_inverse f.range_restrict g, from linear_map.congr_fun hg, + refine ⟨λ h, _, _⟩, + { rcases le_dim_iff_exists_linear_independent.1 h with ⟨s, rfl, si⟩, + refine ⟨g '' s, cardinal.mk_image_eq_lift _ _ fg.injective, _⟩, + replace fg : ∀ x, f (g x) = x, by { intro x, convert congr_arg subtype.val (fg x) }, + replace si : linear_independent K (λ x : s, f (g x)), + by simpa only [fg] using si.map' _ (ker_subtype _), + exact si.image_of_comp s g f }, + { rintro ⟨s, hsc, si⟩, + have : linear_independent K (λ x : s, f.range_restrict x), + from linear_independent.of_comp (f.range.subtype) (by convert si), + convert cardinal_le_dim_of_linear_independent this.image, + rw [← cardinal.lift_inj, ← hsc, cardinal.mk_image_eq_of_inj_on_lift], + exact inj_on_iff_injective.2 this.injective } +end + +lemma le_rank_iff_exists_linear_independent_finset {n : ℕ} {f : V →ₗ[K] V'} : + ↑n ≤ rank f ↔ ∃ s : finset V, s.card = n ∧ linear_independent K (λ x : (s : set V), f x) := +begin + simp only [le_rank_iff_exists_linear_independent, cardinal.lift_nat_cast, + cardinal.lift_eq_nat_iff, cardinal.mk_eq_nat_iff_finset], + split, + { rintro ⟨s, ⟨t, rfl, rfl⟩, si⟩, + exact ⟨t, rfl, si⟩ }, + { rintro ⟨s, rfl, si⟩, + exact ⟨s, ⟨s, rfl, rfl⟩, si⟩ } +end + end field end module From 42b9cdf8602151a514e3f2970799ff97ee18cd14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Sun, 24 Apr 2022 13:05:30 +0000 Subject: [PATCH 213/373] feat(data/quot): Decidability of `quotient.lift` and friends (#13589) and make `antisymmetrization.linear_order` computable. --- src/data/quot.lean | 74 ++++++++++++++++++++++++++++++- src/order/antisymmetrization.lean | 11 +++-- 2 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/data/quot.lean b/src/data/quot.lean index b410f8cb7782b..6f32e7c9e1e52 100644 --- a/src/data/quot.lean +++ b/src/data/quot.lean @@ -57,7 +57,7 @@ protected def map_right {ra' : α → α → Prop} (h : ∀a₁ a₂, ra a₁ a quot ra → quot ra' := quot.map id h -/-- weaken the relation of a quotient -/ +/-- Weaken the relation of a quotient. This is the same as `quot.map id`. -/ def factor {α : Type*} (r s : α → α → Prop) (h : ∀ x y, r x y → s x y) : quot r → quot s := quot.lift (quot.mk s) (λ x y rxy, quot.sound (h x y rxy)) @@ -121,6 +121,14 @@ lemma map₂_mk (f : α → β → γ) (hs : ∀ a₁ a₂ b, r a₁ a₂ → t (f a₁ b) (f a₂ b)) (a : α) (b : β) : quot.map₂ f hr hs (quot.mk r a) (quot.mk s b) = quot.mk t (f a b) := rfl +/-- A binary version of `quot.rec_on_subsingleton`. -/ +@[reducible, elab_as_eliminator] +protected def rec_on_subsingleton₂ {φ : quot r → quot s → Sort*} + [h : ∀ a b, subsingleton (φ ⟦a⟧ ⟦b⟧)] (q₁ : quot r) (q₂ : quot s) (f : Π a b, φ ⟦a⟧ ⟦b⟧) : + φ q₁ q₂ := +@quot.rec_on_subsingleton _ r (λ q, φ q q₂) (λ a, quot.ind (h a) q₂) q₁ $ + λ a, quot.rec_on_subsingleton q₂ $ λ b, f a b + attribute [elab_as_eliminator] protected lemma induction_on₂ {δ : quot r → quot s → Prop} (q₁ : quot r) (q₂ : quot s) @@ -133,6 +141,28 @@ protected lemma induction_on₃ (h : ∀ a b c, δ (quot.mk r a) (quot.mk s b) (quot.mk t c)) : δ q₁ q₂ q₃ := quot.ind (λ a₁, quot.ind (λ a₂, quot.ind (λ a₃, h a₁ a₂ a₃) q₃) q₂) q₁ +instance (r : α → α → Prop) (f : α → Prop) (h : ∀ a b, r a b → f a = f b) [hf : decidable_pred f] : + decidable_pred (quot.lift f h) := +λ q, quot.rec_on_subsingleton q hf + +/-- Note that this provides `decidable_rel (quot.lift₂ f ha hb)` when `α = β`. -/ +instance (r : α → α → Prop) (s : β → β → Prop) (f : α → β → Prop) + (ha : ∀ a b₁ b₂, s b₁ b₂ → f a b₁ = f a b₂) (hb : ∀ a₁ a₂ b, r a₁ a₂ → f a₁ b = f a₂ b) + [hf : Π a, decidable_pred (f a)] (q₁ : quot r) : + decidable_pred (quot.lift₂ f ha hb q₁) := +λ q₂, quot.rec_on_subsingleton₂ q₁ q₂ hf + +instance (r : α → α → Prop) (q : quot r) (f : α → Prop) (h : ∀ a b, r a b → f a = f b) + [decidable_pred f] : + decidable (quot.lift_on q f h) := +quot.lift.decidable_pred _ _ _ _ + +instance (r : α → α → Prop) (s : β → β → Prop) (q₁ : quot r) (q₂ : quot s) (f : α → β → Prop) + (ha : ∀ a b₁ b₂, s b₁ b₂ → f a b₁ = f a b₂) (hb : ∀ a₁ a₂ b, r a₁ a₂ → f a₁ b = f a₂ b) + [Π a, decidable_pred (f a)] : + decidable (quot.lift_on₂ q₁ q₂ f ha hb) := +quot.lift₂.decidable_pred _ _ _ _ _ _ _ + end quot namespace quotient @@ -172,6 +202,31 @@ quotient.lift₂ (λ x y, ⟦f x y⟧) (λ x₁ y₁ x₂ y₂ h₁ h₂, quot.s @[simp] lemma map₂_mk (f : α → β → γ) (h : ((≈) ⇒ (≈) ⇒ (≈)) f f) (x : α) (y : β) : quotient.map₂ f h (⟦x⟧ : quotient sa) (⟦y⟧ : quotient sb) = (⟦f x y⟧ : quotient sc) := rfl +include sa + +instance (f : α → Prop) (h : ∀ a b, a ≈ b → f a = f b) [decidable_pred f] : + decidable_pred (quotient.lift f h) := +quot.lift.decidable_pred _ _ _ + +include sb + +/-- Note that this provides `decidable_rel (quotient.lift₂ f h)` when `α = β`. -/ +instance (f : α → β → Prop) (h : ∀ a₁ b₁ a₂ b₂, a₁ ≈ a₂ → b₁ ≈ b₂ → f a₁ b₁ = f a₂ b₂) + [hf : Π a, decidable_pred (f a)] (q₁ : quotient sa) : + decidable_pred (quotient.lift₂ f h q₁) := +λ q₂, quotient.rec_on_subsingleton₂ q₁ q₂ hf + +omit sb + +instance (q : quotient sa) (f : α → Prop) (h : ∀ a b, a ≈ b → f a = f b) [decidable_pred f] : + decidable (quotient.lift_on q f h) := +quotient.lift.decidable_pred _ _ _ + +instance (q₁ : quotient sa) (q₂ : quotient sb) (f : α → β → Prop) + (h : ∀ a₁ b₁ a₂ b₂, a₁ ≈ a₂ → b₁ ≈ b₂ → f a₁ b₁ = f a₂ b₂) [Π a, decidable_pred (f a)] : + decidable (quotient.lift_on₂ q₁ q₂ f h) := +quotient.lift₂.decidable_pred _ _ _ _ + end quotient lemma quot.eq {α : Type*} {r : α → α → Prop} {x y : α} : @@ -245,7 +300,7 @@ begin end lemma quotient.eq_mk_iff_out [s : setoid α] {x : quotient s} {y : α} : - x = ⟦y⟧ ↔ quotient.out x ≈ y := + x = ⟦y⟧ ↔ quotient.out x ≈ y := begin refine iff.trans _ quotient.eq, rw quotient.out_eq x, @@ -295,6 +350,8 @@ end pi lemma nonempty_quotient_iff (s : setoid α) : nonempty (quotient s) ↔ nonempty α := ⟨assume ⟨a⟩, quotient.induction_on a nonempty.intro, assume ⟨a⟩, ⟨⟦a⟧⟩⟩ +/-! ### Truncation -/ + /-- `trunc α` is the quotient of `α` by the always-true relation. This is related to the propositional truncation in HoTT, and is similar in effect to `nonempty α`, but unlike `nonempty α`, `trunc α` is data, @@ -388,6 +445,8 @@ nonempty_of_exists q.exists_rep end trunc +/-! ### `quotient` with implicit `setoid` -/ + namespace quotient variables {γ : Sort*} {φ : Sort*} {s₁ : setoid α} {s₂ : setoid β} {s₃ : setoid γ} @@ -554,4 +613,15 @@ protected lemma mk'_eq_mk (x : α) : quotient.mk' x = ⟦x⟧ := rfl end +instance (q : quotient s₁) (f : α → Prop) (h : ∀ a b, @setoid.r α s₁ a b → f a = f b) + [decidable_pred f] : + decidable (quotient.lift_on' q f h) := +quotient.lift.decidable_pred _ _ q + +instance (q₁ : quotient s₁) (q₂ : quotient s₂) (f : α → β → Prop) + (h : ∀ a₁ b₁ a₂ b₂, @setoid.r α s₁ a₁ a₂ → @setoid.r β s₂ b₁ b₂ → f a₁ b₁ = f a₂ b₂) + [Π a, decidable_pred (f a)] : + decidable (quotient.lift_on₂' q₁ q₂ f h) := +quotient.lift₂.decidable_pred _ _ _ _ + end quotient diff --git a/src/order/antisymmetrization.lean b/src/order/antisymmetrization.lean index 261e96d94303b..c6ca0a435e52e 100644 --- a/src/order/antisymmetrization.lean +++ b/src/order/antisymmetrization.lean @@ -108,13 +108,12 @@ instance : partial_order (antisymmetrization α (≤)) := lt_iff_le_not_le := λ a b, quotient.induction_on₂' a b $ λ a b, lt_iff_le_not_le, le_antisymm := λ a b, quotient.induction_on₂' a b $ λ a b hab hba, quotient.sound' ⟨hab, hba⟩ } --- TODO@Yaël: Make computable by adding the missing decidability instances for `quotient.lift` and --- `quotient.lift₂` -noncomputable instance [is_total α (≤)] : linear_order (antisymmetrization α (≤)) := +instance [@decidable_rel α (≤)] [@decidable_rel α (<)] [is_total α (≤)] : + linear_order (antisymmetrization α (≤)) := { le_total := λ a b, quotient.induction_on₂' a b $ total_of (≤), - decidable_eq := classical.dec_rel _, - decidable_le := classical.dec_rel _, - decidable_lt := classical.dec_rel _, + decidable_eq := @quotient.decidable_eq _ (antisymm_rel.setoid _ (≤)) antisymm_rel.decidable_rel, + decidable_le := λ _ _, quotient.lift_on₂'.decidable _ _ _ _, + decidable_lt := λ _ _, quotient.lift_on₂'.decidable _ _ _ _, ..antisymmetrization.partial_order } @[simp] lemma to_antisymmetrization_le_to_antisymmetrization_iff : From 53a484e6936f2c10940131c89205fb5abd533678 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Sun, 24 Apr 2022 17:23:52 +0000 Subject: [PATCH 214/373] chore(order/filter/small_sets): redefine, golf (#13672) The new definition is defeq to the old one. --- src/order/filter/small_sets.lean | 43 +++++++------------------------- 1 file changed, 9 insertions(+), 34 deletions(-) diff --git a/src/order/filter/small_sets.lean b/src/order/filter/small_sets.lean index 9e3de47b556c3..c66aa21be8558 100644 --- a/src/order/filter/small_sets.lean +++ b/src/order/filter/small_sets.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Patrick Massot. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Patrick Massot, Floris van Doorn -/ -import order.filter.bases +import order.filter.lift /-! # The filter of small sets @@ -25,44 +25,19 @@ variables {α β : Type*} {ι : Sort*} namespace filter -/-- The filter `f.small_sets` is the largest filter containing all powersets of members of `f`. - Note: `𝓟` is the principal filter and `𝒫` is the powerset. -/ -def small_sets (f : filter α) : filter (set α) := -⨅ t ∈ f, 𝓟 (𝒫 t) +/-- The filter `f.small_sets` is the largest filter containing all powersets of members of `f`. -/ +def small_sets (f : filter α) : filter (set α) := f.lift' powerset lemma small_sets_eq_generate {f : filter α} : f.small_sets = generate (powerset '' f.sets) := -by simp_rw [generate_eq_binfi, small_sets, infi_image, filter.mem_sets] - -lemma has_basis_small_sets (f : filter α) : - has_basis f.small_sets (λ t : set α, t ∈ f) powerset := -begin - apply has_basis_binfi_principal _ _, - { rintros u (u_in : u ∈ f) v (v_in : v ∈ f), - use [u ∩ v, inter_mem u_in v_in], - split, - rintros w (w_sub : w ⊆ u ∩ v), - exact w_sub.trans (inter_subset_left u v), - rintros w (w_sub : w ⊆ u ∩ v), - exact w_sub.trans (inter_subset_right u v) }, - { use univ, - exact univ_mem }, -end +by { simp_rw [generate_eq_binfi, small_sets, infi_image], refl } lemma has_basis.small_sets {f : filter α} {p : ι → Prop} {s : ι → set α} (h : has_basis f p s) : has_basis f.small_sets p (λ i, 𝒫 (s i)) := -⟨begin - intros t, - rw f.has_basis_small_sets.mem_iff, - split, - { rintro ⟨u, u_in, hu : {v : set α | v ⊆ u} ⊆ t⟩, - rcases h.mem_iff.mp u_in with ⟨i, hpi, hiu⟩, - use [i, hpi], - apply subset.trans _ hu, - intros v hv x hx, - exact hiu (hv hx) }, - { rintro ⟨i, hi, hui⟩, - exact ⟨s i, h.mem_of_mem hi, hui⟩ } -end⟩ +h.lift' monotone_powerset + +lemma has_basis_small_sets (f : filter α) : + has_basis f.small_sets (λ t : set α, t ∈ f) powerset := +f.basis_sets.small_sets /-- `g` converges to `f.small_sets` if for all `s ∈ f`, eventually we have `g x ⊆ s`. -/ lemma tendsto_small_sets_iff {la : filter α} {lb : filter β} {f : α → set β} : From 0d16bb4dc9f0ec490a383204bba7fd71faa1d08a Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Sun, 24 Apr 2022 20:37:26 +0000 Subject: [PATCH 215/373] refactor(*): migrate from `filter.lift' _ powerset` to `filter.small_sets` (#13673) --- .../special_functions/non_integrable.lean | 2 +- .../integral/integrable_on.lean | 16 ++-- src/measure_theory/integral/set_integral.lean | 34 ++++---- src/measure_theory/measurable_space.lean | 6 +- src/measure_theory/measure/measure_space.lean | 6 +- src/order/filter/interval.lean | 45 ++++------ src/order/filter/lift.lean | 49 ----------- src/order/filter/small_sets.lean | 86 +++++++++++++++++-- src/topology/algebra/order/basic.lean | 5 +- .../metric_space/hausdorff_dimension.lean | 14 +-- 10 files changed, 136 insertions(+), 127 deletions(-) diff --git a/src/analysis/special_functions/non_integrable.lean b/src/analysis/special_functions/non_integrable.lean index 8b25dab35bb64..bdc86f7af1229 100644 --- a/src/analysis/special_functions/non_integrable.lean +++ b/src/analysis/special_functions/non_integrable.lean @@ -60,7 +60,7 @@ begin { rcases hfg.exists_nonneg with ⟨C, C₀, hC⟩, have h : ∀ᶠ x : ℝ × ℝ in l.prod l, ∀ y ∈ [x.1, x.2], (differentiable_at ℝ f y ∧ ∥deriv f y∥ ≤ C * ∥g y∥) ∧ y ∈ [a, b], - from (tendsto_fst.interval tendsto_snd).eventually ((hd.and hC.bound).and hl).lift'_powerset, + from (tendsto_fst.interval tendsto_snd).eventually ((hd.and hC.bound).and hl).small_sets, rcases mem_prod_self_iff.1 h with ⟨s, hsl, hs⟩, simp only [prod_subset_iff, mem_set_of_eq] at hs, exact ⟨C, C₀, s, hsl, λ x hx y hy z hz, (hs x hx y hy z hz).2, diff --git a/src/measure_theory/integral/integrable_on.lean b/src/measure_theory/integral/integrable_on.lean index c539897511bf3..a5248839a5e5c 100644 --- a/src/measure_theory/integral/integrable_on.lean +++ b/src/measure_theory/integral/integrable_on.lean @@ -38,8 +38,8 @@ def strongly_measurable_at_filter (f : α → β) (l : filter α) (μ : measure ⟨∅, mem_bot, by simp⟩ protected lemma strongly_measurable_at_filter.eventually (h : strongly_measurable_at_filter f l μ) : - ∀ᶠ s in l.lift' powerset, ae_strongly_measurable f (μ.restrict s) := -(eventually_lift'_powerset' $ λ s t, ae_strongly_measurable.mono_set).2 h + ∀ᶠ s in l.small_sets, ae_strongly_measurable f (μ.restrict s) := +(eventually_small_sets' $ λ s t, ae_strongly_measurable.mono_set).2 h protected lemma strongly_measurable_at_filter.filter_mono (h : strongly_measurable_at_filter f l μ) (h' : l' ≤ l) : @@ -246,15 +246,15 @@ begin end /-- We say that a function `f` is *integrable at filter* `l` if it is integrable on some -set `s ∈ l`. Equivalently, it is eventually integrable on `s` in `l.lift' powerset`. -/ +set `s ∈ l`. Equivalently, it is eventually integrable on `s` in `l.small_sets`. -/ def integrable_at_filter (f : α → E) (l : filter α) (μ : measure α . volume_tac) := ∃ s ∈ l, integrable_on f s μ variables {l l' : filter α} protected lemma integrable_at_filter.eventually (h : integrable_at_filter f l μ) : - ∀ᶠ s in l.lift' powerset, integrable_on f s μ := -by { refine (eventually_lift'_powerset' $ λ s t hst ht, _).2 h, exact ht.mono_set hst } + ∀ᶠ s in l.small_sets, integrable_on f s μ := +iff.mpr (eventually_small_sets' $ λ s t hst ht, ht.mono_set hst) h lemma integrable_at_filter.filter_mono (hl : l ≤ l') (hl' : integrable_at_filter f l' μ) : integrable_at_filter f l μ := @@ -289,9 +289,9 @@ lemma measure.finite_at_filter.integrable_at_filter {l : filter α} [is_measurab (hf : l.is_bounded_under (≤) (norm ∘ f)) : integrable_at_filter f l μ := begin - obtain ⟨C, hC⟩ : ∃ C, ∀ᶠ s in (l.lift' powerset), ∀ x ∈ s, ∥f x∥ ≤ C, - from hf.imp (λ C hC, eventually_lift'_powerset.2 ⟨_, hC, λ t, id⟩), - rcases (hfm.eventually.and (hμ.eventually.and hC)).exists_measurable_mem_of_lift' + obtain ⟨C, hC⟩ : ∃ C, ∀ᶠ s in l.small_sets, ∀ x ∈ s, ∥f x∥ ≤ C, + from hf.imp (λ C hC, eventually_small_sets.2 ⟨_, hC, λ t, id⟩), + rcases (hfm.eventually.and (hμ.eventually.and hC)).exists_measurable_mem_of_small_sets with ⟨s, hsl, hsm, hfm, hμ, hC⟩, refine ⟨s, hsl, ⟨hfm, has_finite_integral_restrict_of_bounded hμ _⟩⟩, exact C, diff --git a/src/measure_theory/integral/set_integral.lean b/src/measure_theory/integral/set_integral.lean index e897889b96040..22888a802521f 100644 --- a/src/measure_theory/integral/set_integral.lean +++ b/src/measure_theory/integral/set_integral.lean @@ -30,7 +30,7 @@ Finally, we prove a version of the for set integral, see `filter.tendsto.integral_sub_linear_is_o_ae` and its corollaries. Namely, consider a measurably generated filter `l`, a measure `μ` finite at this filter, and a function `f` that has a finite limit `c` at `l ⊓ μ.ae`. Then `∫ x in s, f x ∂μ = μ s • c + o(μ s)` -as `s` tends to `l.lift' powerset`, i.e. for any `ε>0` there exists `t ∈ l` such that +as `s` tends to `l.small_sets`, i.e. for any `ε>0` there exists `t ∈ l` such that `∥∫ x in s, f x ∂μ - μ s • c∥ ≤ ε * μ s` whenever `s ⊆ t`. We also formulate a version of this theorem for a locally finite measure `μ` and a function `f` continuous at a point `a`. @@ -600,9 +600,8 @@ variables {ι : Type*} [normed_group E] /-- Fundamental theorem of calculus for set integrals: if `μ` is a measure that is finite at a filter `l` and `f` is a measurable function that has a finite limit `b` at `l ⊓ μ.ae`, then `∫ x in -s i, f x ∂μ = μ (s i) • b + o(μ (s i))` at a filter `li` provided that `s i` tends to `l.lift' -powerset` along `li`. Since `μ (s i)` is an `ℝ≥0∞` number, we use `(μ (s i)).to_real` in the -actual statement. +s i, f x ∂μ = μ (s i) • b + o(μ (s i))` at a filter `li` provided that `s i` tends to `l.small_sets` +along `li`. Since `μ (s i)` is an `ℝ≥0∞` number, we use `(μ (s i)).to_real` in the actual statement. Often there is a good formula for `(μ (s i)).to_real`, so the formalization can take an optional argument `m` with this formula and a proof `of `(λ i, (μ (s i)).to_real) =ᶠ[li] m`. Without these @@ -612,17 +611,16 @@ lemma filter.tendsto.integral_sub_linear_is_o_ae {μ : measure α} {l : filter α} [l.is_measurably_generated] {f : α → E} {b : E} (h : tendsto f (l ⊓ μ.ae) (𝓝 b)) (hfm : strongly_measurable_at_filter f l μ) (hμ : μ.finite_at_filter l) - {s : ι → set α} {li : filter ι} (hs : tendsto s li (l.lift' powerset)) + {s : ι → set α} {li : filter ι} (hs : tendsto s li l.small_sets) (m : ι → ℝ := λ i, (μ (s i)).to_real) (hsμ : (λ i, (μ (s i)).to_real) =ᶠ[li] m . tactic.interactive.refl) : is_o (λ i, ∫ x in s i, f x ∂μ - m i • b) m li := begin - suffices : is_o (λ s, ∫ x in s, f x ∂μ - (μ s).to_real • b) (λ s, (μ s).to_real) - (l.lift' powerset), + suffices : is_o (λ s, ∫ x in s, f x ∂μ - (μ s).to_real • b) (λ s, (μ s).to_real) l.small_sets, from (this.comp_tendsto hs).congr' (hsμ.mono $ λ a ha, ha ▸ rfl) hsμ, refine is_o_iff.2 (λ ε ε₀, _), - have : ∀ᶠ s in l.lift' powerset, ∀ᶠ x in μ.ae, x ∈ s → f x ∈ closed_ball b ε := - eventually_lift'_powerset_eventually.2 (h.eventually $ closed_ball_mem_nhds _ ε₀), + have : ∀ᶠ s in l.small_sets, ∀ᶠ x in μ.ae, x ∈ s → f x ∈ closed_ball b ε := + eventually_small_sets_eventually.2 (h.eventually $ closed_ball_mem_nhds _ ε₀), filter_upwards [hμ.eventually, (hμ.integrable_at_filter_of_tendsto_ae hfm h).eventually, hfm.eventually, this], simp only [mem_closed_ball, dist_eq_norm], @@ -635,7 +633,7 @@ end /-- Fundamental theorem of calculus for set integrals, `nhds_within` version: if `μ` is a locally finite measure and `f` is an almost everywhere measurable function that is continuous at a point `a` within a measurable set `t`, then `∫ x in s i, f x ∂μ = μ (s i) • f a + o(μ (s i))` at a filter `li` -provided that `s i` tends to `(𝓝[t] a).lift' powerset` along `li`. Since `μ (s i)` is an `ℝ≥0∞` +provided that `s i` tends to `(𝓝[t] a).small_sets` along `li`. Since `μ (s i)` is an `ℝ≥0∞` number, we use `(μ (s i)).to_real` in the actual statement. Often there is a good formula for `(μ (s i)).to_real`, so the formalization can take an optional @@ -647,7 +645,7 @@ lemma continuous_within_at.integral_sub_linear_is_o_ae {μ : measure α} [is_locally_finite_measure μ] {a : α} {t : set α} {f : α → E} (ha : continuous_within_at f t a) (ht : measurable_set t) (hfm : strongly_measurable_at_filter f (𝓝[t] a) μ) - {s : ι → set α} {li : filter ι} (hs : tendsto s li ((𝓝[t] a).lift' powerset)) + {s : ι → set α} {li : filter ι} (hs : tendsto s li (𝓝[t] a).small_sets) (m : ι → ℝ := λ i, (μ (s i)).to_real) (hsμ : (λ i, (μ (s i)).to_real) =ᶠ[li] m . tactic.interactive.refl) : is_o (λ i, ∫ x in s i, f x ∂μ - m i • f a) m li := @@ -657,9 +655,9 @@ exact (ha.mono_left inf_le_left).integral_sub_linear_is_o_ae /-- Fundamental theorem of calculus for set integrals, `nhds` version: if `μ` is a locally finite measure and `f` is an almost everywhere measurable function that is continuous at a point `a`, then -`∫ x in s i, f x ∂μ = μ (s i) • f a + o(μ (s i))` at `li` provided that `s` tends to `(𝓝 a).lift' -powerset` along `li. Since `μ (s i)` is an `ℝ≥0∞` number, we use `(μ (s i)).to_real` in the -actual statement. +`∫ x in s i, f x ∂μ = μ (s i) • f a + o(μ (s i))` at `li` provided that `s` tends to +`(𝓝 a).small_sets` along `li. Since `μ (s i)` is an `ℝ≥0∞` number, we use `(μ (s i)).to_real` in +the actual statement. Often there is a good formula for `(μ (s i)).to_real`, so the formalization can take an optional argument `m` with this formula and a proof `of `(λ i, (μ (s i)).to_real) =ᶠ[li] m`. Without these @@ -669,7 +667,7 @@ lemma continuous_at.integral_sub_linear_is_o_ae [normed_space ℝ E] [complete_space E] {μ : measure α} [is_locally_finite_measure μ] {a : α} {f : α → E} (ha : continuous_at f a) (hfm : strongly_measurable_at_filter f (𝓝 a) μ) - {s : ι → set α} {li : filter ι} (hs : tendsto s li ((𝓝 a).lift' powerset)) + {s : ι → set α} {li : filter ι} (hs : tendsto s li (𝓝 a).small_sets) (m : ι → ℝ := λ i, (μ (s i)).to_real) (hsμ : (λ i, (μ (s i)).to_real) =ᶠ[li] m . tactic.interactive.refl) : is_o (λ i, ∫ x in s i, f x ∂μ - m i • f a) m li := @@ -677,8 +675,8 @@ lemma continuous_at.integral_sub_linear_is_o_ae /-- Fundamental theorem of calculus for set integrals, `nhds_within` version: if `μ` is a locally finite measure, `f` is continuous on a measurable set `t`, and `a ∈ t`, then `∫ x in (s i), f x ∂μ = -μ (s i) • f a + o(μ (s i))` at `li` provided that `s i` tends to `(𝓝[t] a).lift' powerset` along -`li`. Since `μ (s i)` is an `ℝ≥0∞` number, we use `(μ (s i)).to_real` in the actual statement. +μ (s i) • f a + o(μ (s i))` at `li` provided that `s i` tends to `(𝓝[t] a).small_sets` along `li`. +Since `μ (s i)` is an `ℝ≥0∞` number, we use `(μ (s i)).to_real` in the actual statement. Often there is a good formula for `(μ (s i)).to_real`, so the formalization can take an optional argument `m` with this formula and a proof `of `(λ i, (μ (s i)).to_real) =ᶠ[li] m`. Without these @@ -688,7 +686,7 @@ lemma continuous_on.integral_sub_linear_is_o_ae [normed_space ℝ E] [complete_space E] [second_countable_topology_either α E] {μ : measure α} [is_locally_finite_measure μ] {a : α} {t : set α} {f : α → E} (hft : continuous_on f t) (ha : a ∈ t) (ht : measurable_set t) - {s : ι → set α} {li : filter ι} (hs : tendsto s li ((𝓝[t] a).lift' powerset)) + {s : ι → set α} {li : filter ι} (hs : tendsto s li (𝓝[t] a).small_sets) (m : ι → ℝ := λ i, (μ (s i)).to_real) (hsμ : (λ i, (μ (s i)).to_real) =ᶠ[li] m . tactic.interactive.refl) : is_o (λ i, ∫ x in s i, f x ∂μ - m i • f a) m li := diff --git a/src/measure_theory/measurable_space.lean b/src/measure_theory/measurable_space.lean index c8d506b485f73..669c6da6ce487 100644 --- a/src/measure_theory/measurable_space.lean +++ b/src/measure_theory/measurable_space.lean @@ -1325,10 +1325,10 @@ lemma eventually.exists_measurable_mem {f : filter α} [is_measurably_generated ∃ s ∈ f, measurable_set s ∧ ∀ x ∈ s, p x := is_measurably_generated.exists_measurable_subset h -lemma eventually.exists_measurable_mem_of_lift' {f : filter α} [is_measurably_generated f] - {p : set α → Prop} (h : ∀ᶠ s in f.lift' powerset, p s) : +lemma eventually.exists_measurable_mem_of_small_sets {f : filter α} [is_measurably_generated f] + {p : set α → Prop} (h : ∀ᶠ s in f.small_sets, p s) : ∃ s ∈ f, measurable_set s ∧ p s := -let ⟨s, hsf, hs⟩ := eventually_lift'_powerset.1 h, +let ⟨s, hsf, hs⟩ := eventually_small_sets.1 h, ⟨t, htf, htm, hts⟩ := is_measurably_generated.exists_measurable_subset hsf in ⟨t, htf, htm, hs t hts⟩ diff --git a/src/measure_theory/measure/measure_space.lean b/src/measure_theory/measure/measure_space.lean index a955690b55450..09372f3c467b0 100644 --- a/src/measure_theory/measure/measure_space.lean +++ b/src/measure_theory/measure/measure_space.lean @@ -2357,7 +2357,7 @@ by { filter_upwards [hs_zero], intros, split_ifs, refl } namespace measure /-- A measure is called finite at filter `f` if it is finite at some set `s ∈ f`. -Equivalently, it is eventually finite at `s` in `f.lift' powerset`. -/ +Equivalently, it is eventually finite at `s` in `f.small_sets`. -/ def finite_at_filter {m0 : measurable_space α} (μ : measure α) (f : filter α) : Prop := ∃ s ∈ f, μ s < ∞ @@ -2908,8 +2908,8 @@ protected lemma measure_mono (h : μ ≤ ν) : ν.finite_at_filter f → μ.fini ν.finite_at_filter g → μ.finite_at_filter f := λ h, (h.filter_mono hf).measure_mono hμ -protected lemma eventually (h : μ.finite_at_filter f) : ∀ᶠ s in f.lift' powerset, μ s < ∞ := -(eventually_lift'_powerset' $ λ s t hst ht, (measure_mono hst).trans_lt ht).2 h +protected lemma eventually (h : μ.finite_at_filter f) : ∀ᶠ s in f.small_sets, μ s < ∞ := +(eventually_small_sets' $ λ s t hst ht, (measure_mono hst).trans_lt ht).2 h lemma filter_sup : μ.finite_at_filter f → μ.finite_at_filter g → μ.finite_at_filter (f ⊔ g) := λ ⟨s, hsf, hsμ⟩ ⟨t, htg, htμ⟩, diff --git a/src/order/filter/interval.lean b/src/order/filter/interval.lean index fd29a67556f54..605bfcd00266e 100644 --- a/src/order/filter/interval.lean +++ b/src/order/filter/interval.lean @@ -4,14 +4,14 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury G. Kudryashov -/ import data.set.intervals.ord_connected -import order.filter.lift +import order.filter.small_sets import order.filter.at_top_bot /-! # Convergence of intervals If both `a` and `b` tend to some filter `l₁`, sometimes this implies that `Ixx a b` tends to -`l₂.lift' powerset`, i.e., for any `s ∈ l₂` eventually `Ixx a b` becomes a subset of `s`. Here and +`l₂.small_sets`, i.e., for any `s ∈ l₂` eventually `Ixx a b` becomes a subset of `s`. Here and below `Ixx` is one of `Icc`, `Ico`, `Ioc`, and `Ioo`. We define `filter.tendsto_Ixx_class Ixx l₁ l₂` to be a typeclass representing this property. @@ -53,8 +53,8 @@ section preorder variables [preorder α] /-- A pair of filters `l₁`, `l₂` has `tendsto_Ixx_class Ixx` property if `Ixx a b` tends to -`l₂.lift' powerset` as `a` and `b` tend to `l₁`. In all instances `Ixx` is one of `Icc`, `Ico`, -`Ioc`, or `Ioo`. The instances provide the best `l₂` for a given `l₁`. In many cases `l₁ = l₂` but +`l₂.small_sets` as `a` and `b` tend to `l₁`. In all instances `Ixx` is one of `Icc`, `Ico`, `Ioc`, +or `Ioo`. The instances provide the best `l₂` for a given `l₁`. In many cases `l₁ = l₂` but sometimes we can drop an endpoint from an interval: e.g., we prove `tendsto_Ixx_class Ico (𝓟 $ Iic a) (𝓟 $ Iio a)`, i.e., if `u₁ n` and `u₂ n` belong eventually to `Iic a`, then the interval `Ico (u₁ n) (u₂ n)` is eventually included in `Iio a`. @@ -62,50 +62,48 @@ n) (u₂ n)` is eventually included in `Iio a`. We mark `l₂` as an `out_param` so that Lean can automatically find an appropriate `l₂` based on `Ixx` and `l₁`. This way, e.g., `tendsto.Ico h₁ h₂` works without specifying explicitly `l₂`. -/ class tendsto_Ixx_class (Ixx : α → α → set α) (l₁ : filter α) (l₂ : out_param $ filter α) : Prop := -(tendsto_Ixx : tendsto (λ p : α × α, Ixx p.1 p.2) (l₁ ×ᶠ l₁) (l₂.lift' powerset)) +(tendsto_Ixx : tendsto (λ p : α × α, Ixx p.1 p.2) (l₁ ×ᶠ l₁) l₂.small_sets) lemma tendsto.Icc {l₁ l₂ : filter α} [tendsto_Ixx_class Icc l₁ l₂] {lb : filter β} {u₁ u₂ : β → α} (h₁ : tendsto u₁ lb l₁) (h₂ : tendsto u₂ lb l₁) : - tendsto (λ x, Icc (u₁ x) (u₂ x)) lb (l₂.lift' powerset) := + tendsto (λ x, Icc (u₁ x) (u₂ x)) lb l₂.small_sets := tendsto_Ixx_class.tendsto_Ixx.comp $ h₁.prod_mk h₂ lemma tendsto.Ioc {l₁ l₂ : filter α} [tendsto_Ixx_class Ioc l₁ l₂] {lb : filter β} {u₁ u₂ : β → α} (h₁ : tendsto u₁ lb l₁) (h₂ : tendsto u₂ lb l₁) : - tendsto (λ x, Ioc (u₁ x) (u₂ x)) lb (l₂.lift' powerset) := + tendsto (λ x, Ioc (u₁ x) (u₂ x)) lb l₂.small_sets := tendsto_Ixx_class.tendsto_Ixx.comp $ h₁.prod_mk h₂ lemma tendsto.Ico {l₁ l₂ : filter α} [tendsto_Ixx_class Ico l₁ l₂] {lb : filter β} {u₁ u₂ : β → α} (h₁ : tendsto u₁ lb l₁) (h₂ : tendsto u₂ lb l₁) : - tendsto (λ x, Ico (u₁ x) (u₂ x)) lb (l₂.lift' powerset) := + tendsto (λ x, Ico (u₁ x) (u₂ x)) lb l₂.small_sets := tendsto_Ixx_class.tendsto_Ixx.comp $ h₁.prod_mk h₂ lemma tendsto.Ioo {l₁ l₂ : filter α} [tendsto_Ixx_class Ioo l₁ l₂] {lb : filter β} {u₁ u₂ : β → α} (h₁ : tendsto u₁ lb l₁) (h₂ : tendsto u₂ lb l₁) : - tendsto (λ x, Ioo (u₁ x) (u₂ x)) lb (l₂.lift' powerset) := + tendsto (λ x, Ioo (u₁ x) (u₂ x)) lb l₂.small_sets := tendsto_Ixx_class.tendsto_Ixx.comp $ h₁.prod_mk h₂ lemma tendsto_Ixx_class_principal {s t : set α} {Ixx : α → α → set α} : - tendsto_Ixx_class Ixx (𝓟 s) (𝓟 t) ↔ ∀ (x ∈ s) (y ∈ s), Ixx x y ⊆ t := -begin - refine iff.trans ⟨λ h, h.1, λ h, ⟨h⟩⟩ _, - simp [lift'_principal monotone_powerset, -mem_prod, -prod.forall, forall_prod_set] -end + tendsto_Ixx_class Ixx (𝓟 s) (𝓟 t) ↔ ∀ x y ∈ s, Ixx x y ⊆ t := +iff.trans ⟨λ h, h.1, λ h, ⟨h⟩⟩ $ by simp only [small_sets_principal, prod_principal_principal, + tendsto_principal_principal, forall_prod_set, mem_powerset_iff, mem_principal] lemma tendsto_Ixx_class_inf {l₁ l₁' l₂ l₂' : filter α} {Ixx} [h : tendsto_Ixx_class Ixx l₁ l₂] [h' : tendsto_Ixx_class Ixx l₁' l₂'] : tendsto_Ixx_class Ixx (l₁ ⊓ l₁') (l₂ ⊓ l₂') := -⟨by simpa only [prod_inf_prod, lift'_inf_powerset] using h.1.inf h'.1⟩ +⟨by simpa only [prod_inf_prod, small_sets_inf] using h.1.inf h'.1⟩ lemma tendsto_Ixx_class_of_subset {l₁ l₂ : filter α} {Ixx Ixx' : α → α → set α} (h : ∀ a b, Ixx a b ⊆ Ixx' a b) [h' : tendsto_Ixx_class Ixx' l₁ l₂] : tendsto_Ixx_class Ixx l₁ l₂ := -⟨tendsto_lift'_powerset_mono h'.1 $ eventually_of_forall $ prod.forall.2 h⟩ +⟨h'.1.small_sets_mono $ eventually_of_forall $ prod.forall.2 h⟩ lemma has_basis.tendsto_Ixx_class {ι : Type*} {p : ι → Prop} {s} {l : filter α} (hl : l.has_basis p s) {Ixx : α → α → set α} (H : ∀ i, p i → ∀ (x ∈ s i) (y ∈ s i), Ixx x y ⊆ s i) : tendsto_Ixx_class Ixx l l := -⟨(hl.prod_self.tendsto_iff (hl.lift' monotone_powerset)).2 $ λ i hi, +⟨(hl.prod_self.tendsto_iff hl.small_sets).2 $ λ i hi, ⟨i, hi, λ x hx, H i hi _ hx.1 _ hx.2⟩⟩ instance tendsto_Icc_at_top_at_top : tendsto_Ixx_class Icc (at_top : filter α) at_top := @@ -190,14 +188,9 @@ variable [partial_order α] instance tendsto_Icc_pure_pure {a : α} : tendsto_Ixx_class Icc (pure a) (pure a : filter α) := by { rw ← principal_singleton, exact tendsto_Ixx_class_principal.2 ord_connected_singleton.out } -instance tendsto_Ico_pure_bot {a : α} : tendsto_Ixx_class Ico (pure a) ⊥ := -⟨by simp [lift'_bot monotone_powerset]⟩ - -instance tendsto_Ioc_pure_bot {a : α} : tendsto_Ixx_class Ioc (pure a) ⊥ := -⟨by simp [lift'_bot monotone_powerset]⟩ - -instance tendsto_Ioo_pure_bot {a : α} : tendsto_Ixx_class Ioo (pure a) ⊥ := -tendsto_Ixx_class_of_subset (λ _ _, Ioo_subset_Ioc_self) +instance tendsto_Ico_pure_bot {a : α} : tendsto_Ixx_class Ico (pure a) ⊥ := ⟨by simp⟩ +instance tendsto_Ioc_pure_bot {a : α} : tendsto_Ixx_class Ioc (pure a) ⊥ := ⟨by simp⟩ +instance tendsto_Ioo_pure_bot {a : α} : tendsto_Ixx_class Ioo (pure a) ⊥ := ⟨by simp⟩ end partial_order @@ -225,7 +218,7 @@ end lemma tendsto.interval {l : filter α} [tendsto_Ixx_class Icc l l] {f g : β → α} {lb : filter β} (hf : tendsto f lb l) (hg : tendsto g lb l) : - tendsto (λ x, [f x, g x]) lb (l.lift' powerset) := + tendsto (λ x, [f x, g x]) lb l.small_sets := tendsto_Ixx_class.tendsto_Ixx.comp $ hf.prod_mk hg end linear_order diff --git a/src/order/filter/lift.lean b/src/order/filter/lift.lean index 4f880005becad..81c48e3e98b27 100644 --- a/src/order/filter/lift.lean +++ b/src/order/filter/lift.lean @@ -368,55 +368,6 @@ theorem comap_eq_lift' {f : filter β} {m : α → β} : comap m f = f.lift' (preimage m) := filter.ext $ λ s, (mem_lift'_sets monotone_preimage).symm -lemma lift'_infi_powerset {f : ι → filter α} : - (infi f).lift' powerset = (⨅i, (f i).lift' powerset) := -begin - casesI is_empty_or_nonempty ι, - { rw [infi_of_empty f, infi_of_empty, lift'_top, powerset_univ, principal_univ] }, - { exact (lift'_infi $ λ _ _, (powerset_inter _ _).symm) }, -end - -lemma lift'_inf_powerset (f g : filter α) : - (f ⊓ g).lift' powerset = f.lift' powerset ⊓ g.lift' powerset := -lift'_inf f g $ λ _ _, (powerset_inter _ _).symm - -lemma eventually_lift'_powerset {f : filter α} {p : set α → Prop} : - (∀ᶠ s in f.lift' powerset, p s) ↔ ∃ s ∈ f, ∀ t ⊆ s, p t := -eventually_lift'_iff monotone_powerset - -lemma eventually_lift'_powerset' {f : filter α} {p : set α → Prop} - (hp : ∀ ⦃s t⦄, s ⊆ t → p t → p s) : - (∀ᶠ s in f.lift' powerset, p s) ↔ ∃ s ∈ f, p s := -eventually_lift'_powerset.trans $ exists₂_congr $ λ s hsf, - ⟨λ H, H s (subset.refl s), λ hs t ht, hp ht hs⟩ - -instance lift'_powerset_ne_bot (f : filter α) : ne_bot (f.lift' powerset) := -(lift'_ne_bot_iff monotone_powerset).2 $ λ _ _, powerset_nonempty - -lemma tendsto_lift'_powerset_mono {la : filter α} {lb : filter β} {s t : α → set β} - (ht : tendsto t la (lb.lift' powerset)) (hst : ∀ᶠ x in la, s x ⊆ t x) : - tendsto s la (lb.lift' powerset) := -begin - simp only [filter.lift', filter.lift, (∘), tendsto_infi, tendsto_principal] at ht ⊢, - exact λ u hu, (ht u hu).mp (hst.mono $ λ a hst ht, subset.trans hst ht) -end - -@[simp] lemma eventually_lift'_powerset_forall {f : filter α} {p : α → Prop} : - (∀ᶠ s in f.lift' powerset, ∀ x ∈ s, p x) ↔ ∀ᶠ x in f, p x := -iff.trans (eventually_lift'_powerset' $ λ s t hst ht x hx, ht x (hst hx)) - exists_mem_subset_iff - -alias eventually_lift'_powerset_forall ↔ - filter.eventually.of_lift'_powerset filter.eventually.lift'_powerset - -@[simp] lemma eventually_lift'_powerset_eventually {f g : filter α} {p : α → Prop} : - (∀ᶠ s in f.lift' powerset, ∀ᶠ x in g, x ∈ s → p x) ↔ ∀ᶠ x in f ⊓ g, p x := -calc _ ↔ ∃ s ∈ f, ∀ᶠ x in g, x ∈ s → p x : - eventually_lift'_powerset' $ λ s t hst ht, ht.mono $ λ x hx hs, hx (hst hs) -... ↔ ∃ (s ∈ f) (t ∈ g), ∀ x, x ∈ t → x ∈ s → p x : - by simp only [eventually_iff_exists_mem] -... ↔ ∀ᶠ x in f ⊓ g, p x : by simp only [eventually_inf, and_comm, mem_inter_iff, ←and_imp] - end lift' section prod diff --git a/src/order/filter/small_sets.lean b/src/order/filter/small_sets.lean index c66aa21be8558..a9b0446e840de 100644 --- a/src/order/filter/small_sets.lean +++ b/src/order/filter/small_sets.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2022 Patrick Massot. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Patrick Massot, Floris van Doorn +Authors: Patrick Massot, Floris van Doorn, Yury Kudryashov -/ import order.filter.lift @@ -25,23 +25,91 @@ variables {α β : Type*} {ι : Sort*} namespace filter -/-- The filter `f.small_sets` is the largest filter containing all powersets of members of `f`. -/ -def small_sets (f : filter α) : filter (set α) := f.lift' powerset +variables {l l' la : filter α} {lb : filter β} + +/-- The filter `l.small_sets` is the largest filter containing all powersets of members of `l`. -/ +def small_sets (l : filter α) : filter (set α) := l.lift' powerset lemma small_sets_eq_generate {f : filter α} : f.small_sets = generate (powerset '' f.sets) := by { simp_rw [generate_eq_binfi, small_sets, infi_image], refl } -lemma has_basis.small_sets {f : filter α} {p : ι → Prop} {s : ι → set α} - (h : has_basis f p s) : has_basis f.small_sets p (λ i, 𝒫 (s i)) := +lemma has_basis.small_sets {p : ι → Prop} {s : ι → set α} + (h : has_basis l p s) : has_basis l.small_sets p (λ i, 𝒫 (s i)) := h.lift' monotone_powerset -lemma has_basis_small_sets (f : filter α) : - has_basis f.small_sets (λ t : set α, t ∈ f) powerset := -f.basis_sets.small_sets +lemma has_basis_small_sets (l : filter α) : + has_basis l.small_sets (λ t : set α, t ∈ l) powerset := +l.basis_sets.small_sets /-- `g` converges to `f.small_sets` if for all `s ∈ f`, eventually we have `g x ⊆ s`. -/ -lemma tendsto_small_sets_iff {la : filter α} {lb : filter β} {f : α → set β} : +lemma tendsto_small_sets_iff {f : α → set β} : tendsto f la lb.small_sets ↔ ∀ t ∈ lb, ∀ᶠ x in la, f x ⊆ t := (has_basis_small_sets lb).tendsto_right_iff +lemma eventually_small_sets {p : set α → Prop} : + (∀ᶠ s in l.lift' powerset, p s) ↔ ∃ s ∈ l, ∀ t ⊆ s, p t := +eventually_lift'_iff monotone_powerset + +lemma eventually_small_sets' {p : set α → Prop} (hp : ∀ ⦃s t⦄, s ⊆ t → p t → p s) : + (∀ᶠ s in l.lift' powerset, p s) ↔ ∃ s ∈ l, p s := +eventually_small_sets.trans $ exists₂_congr $ λ s hsf, + ⟨λ H, H s (subset.refl s), λ hs t ht, hp ht hs⟩ + +@[mono] lemma monotone_small_sets : monotone (@small_sets α) := +monotone_lift' monotone_id monotone_const + +@[simp] lemma small_sets_bot : (⊥ : filter α).small_sets = pure ∅ := +by rw [small_sets, lift'_bot monotone_powerset, powerset_empty, principal_singleton] + +@[simp] lemma small_sets_top : (⊤ : filter α).small_sets = ⊤ := +by rw [small_sets, lift'_top, powerset_univ, principal_univ] + +@[simp] lemma small_sets_principal (s : set α) : (𝓟 s).small_sets = 𝓟(𝒫 s) := +lift'_principal monotone_powerset + +lemma small_sets_comap (l : filter β) (f : α → β) : + (comap f l).small_sets = l.lift' (powerset ∘ preimage f) := +comap_lift'_eq2 monotone_powerset + +lemma comap_small_sets (l : filter β) (f : α → set β) : + comap f l.small_sets = l.lift' (preimage f ∘ powerset) := +comap_lift'_eq monotone_powerset + +lemma small_sets_infi {f : ι → filter α} : + (infi f).small_sets = (⨅ i, (f i).small_sets) := +begin + casesI is_empty_or_nonempty ι, + { rw [infi_of_empty f, infi_of_empty, small_sets_top] }, + { exact (lift'_infi $ λ _ _, (powerset_inter _ _).symm) }, +end + +lemma small_sets_inf (l₁ l₂ : filter α) : + (l₁ ⊓ l₂).small_sets = l₁.small_sets ⊓ l₂.small_sets := +lift'_inf _ _ $ λ _ _, (powerset_inter _ _).symm + +instance small_sets_ne_bot (l : filter α) : ne_bot l.small_sets := +(lift'_ne_bot_iff monotone_powerset).2 $ λ _ _, powerset_nonempty + +lemma tendsto.small_sets_mono {s t : α → set β} + (ht : tendsto t la lb.small_sets) (hst : ∀ᶠ x in la, s x ⊆ t x) : + tendsto s la lb.small_sets := +begin + rw [tendsto_small_sets_iff] at ht ⊢, + exact λ u hu, (ht u hu).mp (hst.mono $ λ a hst ht, subset.trans hst ht) +end + +@[simp] lemma eventually_small_sets_eventually {p : α → Prop} : + (∀ᶠ s in l.small_sets, ∀ᶠ x in l', x ∈ s → p x) ↔ ∀ᶠ x in l ⊓ l', p x := +calc _ ↔ ∃ s ∈ l, ∀ᶠ x in l', x ∈ s → p x : + eventually_small_sets' $ λ s t hst ht, ht.mono $ λ x hx hs, hx (hst hs) +... ↔ ∃ (s ∈ l) (t ∈ l'), ∀ x, x ∈ t → x ∈ s → p x : + by simp only [eventually_iff_exists_mem] +... ↔ ∀ᶠ x in l ⊓ l', p x : by simp only [eventually_inf, and_comm, mem_inter_iff, ← and_imp] + +@[simp] lemma eventually_small_sets_forall {p : α → Prop} : + (∀ᶠ s in l.small_sets, ∀ x ∈ s, p x) ↔ ∀ᶠ x in l, p x := +by simpa only [inf_top_eq, eventually_top] using @eventually_small_sets_eventually α l ⊤ p + +alias eventually_small_sets_forall ↔ filter.eventually.of_small_sets filter.eventually.small_sets + end filter diff --git a/src/topology/algebra/order/basic.lean b/src/topology/algebra/order/basic.lean index 24a1fcb5a2ec2..df9d85550cfca 100644 --- a/src/topology/algebra/order/basic.lean +++ b/src/topology/algebra/order/basic.lean @@ -782,9 +782,8 @@ instance tendsto_Icc_class_nhds_pi {ι : Type*} {α : ι → Type*} tendsto_Ixx_class Icc (𝓝 f) (𝓝 f) := begin constructor, - conv in ((𝓝 f).lift' powerset) { rw [nhds_pi, filter.pi] }, - simp only [lift'_infi_powerset, comap_lift'_eq2 monotone_powerset, tendsto_infi, tendsto_lift', - mem_powerset_iff, subset_def, mem_preimage], + conv in ((𝓝 f).small_sets) { rw [nhds_pi, filter.pi] }, + simp only [small_sets_infi, small_sets_comap, tendsto_infi, tendsto_lift', (∘), mem_powerset_iff], intros i s hs, have : tendsto (λ g : Π i, α i, g i) (𝓝 f) (𝓝 (f i)) := ((continuous_apply i).tendsto f), refine (tendsto_lift'.1 ((this.comp tendsto_fst).Icc (this.comp tendsto_snd)) s hs).mono _, diff --git a/src/topology/metric_space/hausdorff_dimension.lean b/src/topology/metric_space/hausdorff_dimension.lean index 6d8c812e3c5c3..59f7d7ff3dadf 100644 --- a/src/topology/metric_space/hausdorff_dimension.lean +++ b/src/topology/metric_space/hausdorff_dimension.lean @@ -225,27 +225,27 @@ end /-- In an (extended) metric space with second countable topology, the Hausdorff dimension of a set `s` is the supremum over `x ∈ s` of the limit superiors of `dimH t` along -`(𝓝[s] x).lift' powerset`. -/ -lemma bsupr_limsup_dimH (s : set X) : (⨆ x ∈ s, limsup ((𝓝[s] x).lift' powerset) dimH) = dimH s := +`(𝓝[s] x).small_sets`. -/ +lemma bsupr_limsup_dimH (s : set X) : (⨆ x ∈ s, limsup (𝓝[s] x).small_sets dimH) = dimH s := begin refine le_antisymm (supr₂_le $ λ x hx, _) _, { refine Limsup_le_of_le (by apply_auto_param) (eventually_map.2 _), - exact eventually_lift'_powerset.2 ⟨s, self_mem_nhds_within, λ t, dimH_mono⟩ }, + exact eventually_small_sets.2 ⟨s, self_mem_nhds_within, λ t, dimH_mono⟩ }, { refine le_of_forall_ge_of_dense (λ r hr, _), rcases exists_mem_nhds_within_lt_dimH_of_lt_dimH hr with ⟨x, hxs, hxr⟩, refine le_supr₂_of_le x hxs _, rw limsup_eq, refine le_Inf (λ b hb, _), - rcases eventually_lift'_powerset.1 hb with ⟨t, htx, ht⟩, + rcases eventually_small_sets.1 hb with ⟨t, htx, ht⟩, exact (hxr t htx).le.trans (ht t subset.rfl) } end /-- In an (extended) metric space with second countable topology, the Hausdorff dimension of a set `s` is the supremum over all `x` of the limit superiors of `dimH t` along -`(𝓝[s] x).lift' powerset`. -/ -lemma supr_limsup_dimH (s : set X) : (⨆ x, limsup ((𝓝[s] x).lift' powerset) dimH) = dimH s := +`(𝓝[s] x).small_sets`. -/ +lemma supr_limsup_dimH (s : set X) : (⨆ x, limsup (𝓝[s] x).small_sets dimH) = dimH s := begin refine le_antisymm (supr_le $ λ x, _) _, { refine Limsup_le_of_le (by apply_auto_param) (eventually_map.2 _), - exact eventually_lift'_powerset.2 ⟨s, self_mem_nhds_within, λ t, dimH_mono⟩ }, + exact eventually_small_sets.2 ⟨s, self_mem_nhds_within, λ t, dimH_mono⟩ }, { rw ← bsupr_limsup_dimH, exact supr₂_le_supr _ _ } end From 54d1ddd2f1f08e4d0f1066bc681bc428afeba03a Mon Sep 17 00:00:00 2001 From: negiizhao Date: Mon, 25 Apr 2022 00:39:20 +0000 Subject: [PATCH 216/373] feat(algebra/polynomial/big_operators): add a lemma, reduce assumptions, golf (#13264) --- src/algebra/polynomial/big_operators.lean | 32 +++++++++++++++------ src/data/polynomial/degree/definitions.lean | 2 +- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/algebra/polynomial/big_operators.lean b/src/algebra/polynomial/big_operators.lean index a0a3f285921e0..9f48a03f1f5af 100644 --- a/src/algebra/polynomial/big_operators.lean +++ b/src/algebra/polynomial/big_operators.lean @@ -277,7 +277,23 @@ by simpa using multiset_prod_X_sub_C_coeff_card_pred (s.1.map f) (by simpa using end comm_ring section no_zero_divisors -variables [comm_ring R] [no_zero_divisors R] (f : ι → R[X]) (t : multiset R[X]) + +section semiring +variables [semiring R] [no_zero_divisors R] + +/-- +The degree of a product of polynomials is equal to +the sum of the degrees, where the degree of the zero polynomial is ⊥. +`[nontrivial R]` is needed, otherwise for `l = []` we have `⊥` in the LHS and `0` in the RHS. +-/ +lemma degree_list_prod [nontrivial R] (l : list R[X]) : + l.prod.degree = (l.map degree).sum := +map_list_prod (@degree_monoid_hom R _ _ _) l + +end semiring + +section comm_semiring +variables [comm_semiring R] [no_zero_divisors R] (f : ι → R[X]) (t : multiset R[X]) /-- The degree of a product of polynomials is equal to @@ -295,9 +311,8 @@ begin intros x hx, simp [h x hx] end -lemma nat_degree_multiset_prod (s : multiset R[X]) - (h : (0 : R[X]) ∉ s) : - nat_degree s.prod = (s.map nat_degree).sum := +lemma nat_degree_multiset_prod (h : (0 : R[X]) ∉ t) : + nat_degree t.prod = (t.map nat_degree).sum := begin nontriviality R, rw nat_degree_multiset_prod', @@ -312,17 +327,14 @@ the sum of the degrees, where the degree of the zero polynomial is ⊥. -/ lemma degree_multiset_prod [nontrivial R] : t.prod.degree = (t.map (λ f, degree f)).sum := -begin - refine multiset.induction_on t _ (λ a t ht, _), { simp }, - { rw [multiset.prod_cons, degree_mul, ht, map_cons, multiset.sum_cons] } -end +map_multiset_prod (@degree_monoid_hom R _ _ _) _ /-- The degree of a product of polynomials is equal to the sum of the degrees, where the degree of the zero polynomial is ⊥. -/ lemma degree_prod [nontrivial R] : (∏ i in s, f i).degree = ∑ i in s, (f i).degree := -by simpa using degree_multiset_prod (s.1.map f) +map_prod (@degree_monoid_hom R _ _ _) _ _ /-- The leading coefficient of a product of polynomials is equal to @@ -346,5 +358,7 @@ lemma leading_coeff_prod : (∏ i in s, f i).leading_coeff = ∏ i in s, (f i).leading_coeff := by simpa using leading_coeff_multiset_prod (s.1.map f) +end comm_semiring + end no_zero_divisors end polynomial diff --git a/src/data/polynomial/degree/definitions.lean b/src/data/polynomial/degree/definitions.lean index 82eb9ffaf1c16..7fdca44f69ed9 100644 --- a/src/data/polynomial/degree/definitions.lean +++ b/src/data/polynomial/degree/definitions.lean @@ -1189,7 +1189,7 @@ def degree_monoid_hom [nontrivial R] : R[X] →* multiplicative (with_bot ℕ) : @[simp] lemma degree_pow [nontrivial R] (p : R[X]) (n : ℕ) : degree (p ^ n) = n • (degree p) := -map_pow (degree_monoid_hom : R[X] →* _) _ _ +map_pow (@degree_monoid_hom R _ _ _) _ _ @[simp] lemma leading_coeff_mul (p q : R[X]) : leading_coeff (p * q) = leading_coeff p * leading_coeff q := From 045fc4438e2f3b0c35283d3e937eb465d5b31ec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Mon, 25 Apr 2022 01:54:41 +0000 Subject: [PATCH 217/373] docs(tactic/algebra): Module docstring (#13571) Write the module docstring. --- src/tactic/algebra.lean | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/tactic/algebra.lean b/src/tactic/algebra.lean index 6f4c97dbfb258..93082151ca201 100644 --- a/src/tactic/algebra.lean +++ b/src/tactic/algebra.lean @@ -5,6 +5,14 @@ Authors: Simon Hudon -/ import tactic.core +/-! +# Recording typeclass ancestors + +The "old" structure command currently does not record the parent typeclasses. This file defines the +`ancestor` attribute to remedy this. This information is notably used by `to_additive` to map +structure fields and constructors of a multiplicative structure to its additive counterpart. +-/ + open lean.parser namespace tactic From 9101c48bb8cbb6a683d0afd58f8d521a16bd6eea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Mon, 25 Apr 2022 01:54:42 +0000 Subject: [PATCH 218/373] docs(number_theory/sum_two_squares): Update docs (#13593) We add a remark for an alternate name for the theorem, and a todo note for a generalization of it. --- src/number_theory/sum_two_squares.lean | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/number_theory/sum_two_squares.lean b/src/number_theory/sum_two_squares.lean index 462ffe861141b..098a5058731c6 100644 --- a/src/number_theory/sum_two_squares.lean +++ b/src/number_theory/sum_two_squares.lean @@ -3,28 +3,29 @@ Copyright (c) 2019 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ + import number_theory.zsqrtd.gaussian_int + /-! # Sums of two squares Proof of Fermat's theorem on the sum of two squares. Every prime congruent to 1 mod 4 is the sum -of two squares --/ +of two squares. -open gaussian_int principal_ideal_ring +# Todo -namespace nat -namespace prime +Fully characterize the natural numbers that are the sum of two squares: those such that for every +prime p congruent to 3 mod 4, the largest power of p dividing them is even. +-/ + +open gaussian_int /-- **Fermat's theorem on the sum of two squares**. Every prime congruent to 1 mod 4 is the sum -of two squares. -/ -lemma sq_add_sq (p : ℕ) [hp : _root_.fact p.prime] (hp1 : p % 4 = 1) : +of two squares. Also known as **Fermat's Christmas theorem**. -/ +lemma nat.prime.sq_add_sq {p : ℕ} [fact p.prime] (hp : p % 4 = 1) : ∃ a b : ℕ, a ^ 2 + b ^ 2 = p := begin apply sq_add_sq_of_nat_prime_of_not_irreducible p, - rw [principal_ideal_ring.irreducible_iff_prime, prime_iff_mod_four_eq_three_of_nat_prime p, hp1], + rw [principal_ideal_ring.irreducible_iff_prime, prime_iff_mod_four_eq_three_of_nat_prime p, hp], norm_num end - -end prime -end nat From 454b8848d4d525fbafb41ccec05108bd2053cfde Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Mon, 25 Apr 2022 01:54:43 +0000 Subject: [PATCH 219/373] chore(topology/metric_space/basic): golf an instance (#13664) Golf the proof of `prod.pseudo_metric_space_max` using `pseudo_emetric_space.to_pseudo_metric_space_of_dist`. --- src/topology/metric_space/basic.lean | 40 +++++++--------------------- 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/src/topology/metric_space/basic.lean b/src/topology/metric_space/basic.lean index fd876bd513ba6..f3e3fe9effdd4 100644 --- a/src/topology/metric_space/basic.lean +++ b/src/topology/metric_space/basic.lean @@ -1395,25 +1395,11 @@ variables [pseudo_metric_space β] noncomputable instance prod.pseudo_metric_space_max : pseudo_metric_space (α × β) := -{ dist := λ x y, max (dist x.1 y.1) (dist x.2 y.2), - dist_self := λ x, by simp, - dist_comm := λ x y, by simp [dist_comm], - dist_triangle := λ x y z, max_le - (le_trans (dist_triangle _ _ _) (add_le_add (le_max_left _ _) (le_max_left _ _))) - (le_trans (dist_triangle _ _ _) (add_le_add (le_max_right _ _) (le_max_right _ _))), - edist := λ x y, max (edist x.1 y.1) (edist x.2 y.2), - edist_dist := assume x y, begin - have : monotone ennreal.of_real := assume x y h, ennreal.of_real_le_of_real h, - rw [edist_dist, edist_dist, ← this.map_max] - end, - uniformity_dist := begin - refine uniformity_prod.trans _, - simp only [uniformity_basis_dist.eq_binfi, comap_infi], - rw ← infi_inf_eq, congr, funext, - rw ← infi_inf_eq, congr, funext, - simp [inf_principal, ext_iff, max_lt_iff] - end, - to_uniform_space := prod.uniform_space } +pseudo_emetric_space.to_pseudo_metric_space_of_dist + (λ x y : α × β, max (dist x.1 y.1) (dist x.2 y.2)) + (λ x y, (max_lt (edist_lt_top _ _) (edist_lt_top _ _)).ne) $ + λ x y, by rw [dist_edist, dist_edist, prod.edist_eq, + ← ennreal.to_real_max (edist_ne_top _ _) (edist_ne_top _ _)] lemma prod.dist_eq {x y : α × β} : dist x y = max (dist x.1 y.1) (dist x.2 y.2) := rfl @@ -1650,17 +1636,11 @@ begin the uniformity is the same as the product uniformity, but we register nevertheless a nice formula for the distance -/ refine pseudo_emetric_space.to_pseudo_metric_space_of_dist - (λf g, ((sup univ (λb, nndist (f b) (g b)) : ℝ≥0) : ℝ)) _ _, - show ∀ (x y : Π (b : β), π b), edist x y ≠ ⊤, - { assume x y, - rw ← lt_top_iff_ne_top, - have : (⊥ : ℝ≥0∞) < ⊤ := ennreal.coe_lt_top, - simp [edist_pi_def, finset.sup_lt_iff this, edist_lt_top] }, - show ∀ (x y : Π (b : β), π b), ↑(sup univ (λ (b : β), nndist (x b) (y b))) = - ennreal.to_real (sup univ (λ (b : β), edist (x b) (y b))), - { assume x y, - simp only [edist_nndist], - norm_cast } + (λf g, ((sup univ (λb, nndist (f b) (g b)) : ℝ≥0) : ℝ)) (λ f g, _) (λ f g, _), + show edist f g ≠ ⊤, + from ne_of_lt ((finset.sup_lt_iff bot_lt_top).2 $ λ b hb, edist_lt_top _ _), + show ↑(sup univ (λ b, nndist (f b) (g b))) = (sup univ (λ b, edist (f b) (g b))).to_real, + by simp only [edist_nndist, ← ennreal.coe_finset_sup, ennreal.coe_to_real] end lemma nndist_pi_def (f g : Πb, π b) : nndist f g = sup univ (λb, nndist (f b) (g b)) := From 65edf2556ea53e43bce4e3ab3240bd102e778614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Mon, 25 Apr 2022 03:54:18 +0000 Subject: [PATCH 220/373] feat(set_theory/game/pgame): `x.move_left i < x` and variants (#13654) --- src/set_theory/game/pgame.lean | 23 +++++++++++++++++++ src/set_theory/surreal/basic.lean | 36 +++++++----------------------- src/set_theory/surreal/dyadic.lean | 4 ++-- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/set_theory/game/pgame.lean b/src/set_theory/game/pgame.lean index 4016c21e1907e..1efa0539c3346 100644 --- a/src/set_theory/game/pgame.lean +++ b/src/set_theory/game/pgame.lean @@ -386,12 +386,35 @@ end | ⟨l, r, L, R⟩ := by rw mk_le_mk; exact ⟨λ i, lt_mk_of_le (le_refl _), λ i, mk_lt_of_le (le_refl _)⟩ +protected theorem le_rfl {x : pgame} : x ≤ x := +pgame.le_refl x + protected theorem lt_irrefl (x : pgame) : ¬ x < x := not_lt.2 (pgame.le_refl _) protected theorem ne_of_lt : ∀ {x y : pgame}, x < y → x ≠ y | x _ h rfl := pgame.lt_irrefl x h +/-- In general, `xL i ≤ x` isn't true. It is true however for `numeric` games, see +`numeric.move_left_le`. -/ +theorem lt_mk {xl xr : Type u} {xL : xl → pgame} {xR : xr → pgame} (i) : xL i < mk xl xr xL xR := +lt_mk_of_le pgame.le_rfl + +/-- In general, `x ≤ xR i` isn't true. It is true however for `numeric` games, see +`numeric.move_right_le`. -/ +theorem mk_lt {xl xr : Type u} {xL : xl → pgame} {xR : xr → pgame} (i) : mk xl xr xL xR < xR i := +mk_lt_of_le pgame.le_rfl + +/-- In general, `x.move_left i ≤ x` isn't true. It is true however for `numeric` games, see +`numeric.move_left_le`. -/ +theorem move_left_lt {x : pgame} (i) : x.move_left i < x := +move_left_lt_of_le pgame.le_rfl + +/-- In general, `x ≤ x.move_right i` isn't true. It is true however for `numeric` games, see +`numeric.move_right_le`. -/ +theorem lt_move_right {x : pgame} (i) : x < x.move_right i := +lt_move_right_of_le pgame.le_rfl + theorem le_trans_aux {xl xr} {xL : xl → pgame} {xR : xr → pgame} {yl yr} {yL : yl → pgame} {yR : yr → pgame} diff --git a/src/set_theory/surreal/basic.lean b/src/set_theory/surreal/basic.lean index 53ea3a5cec371..3747ee534742f 100644 --- a/src/set_theory/surreal/basic.lean +++ b/src/set_theory/surreal/basic.lean @@ -108,35 +108,15 @@ theorem numeric_neg : Π {x : pgame} (o : numeric x), numeric (-x) ⟨λ j i, lt_iff_neg_gt.1 (o.1 i j), ⟨λ j, numeric_neg (o.2.2 j), λ i, numeric_neg (o.2.1 i)⟩⟩ --- We provide this as an analogue for `numeric.move_left_le`, --- even though it does not need the `numeric` hypothesis. -@[nolint unused_arguments] -theorem numeric.move_left_lt {x : pgame.{u}} (o : numeric x) (i : x.left_moves) : - x.move_left i < x := -begin - rw lt_def_le, - left, - use i, -end - +/-- For the `<` version, see `pgame.move_left_lt`. -/ theorem numeric.move_left_le {x : pgame} (o : numeric x) (i : x.left_moves) : x.move_left i ≤ x := -le_of_lt (o.move_left i) o (o.move_left_lt i) - --- We provide this as an analogue for `numeric.le_move_right`, --- even though it does not need the `numeric` hypothesis. -@[nolint unused_arguments] -theorem numeric.lt_move_right {x : pgame} (o : numeric x) (j : x.right_moves) : - x < x.move_right j := -begin - rw lt_def_le, - right, - use j, -end +le_of_lt (o.move_left i) o (pgame.move_left_lt i) +/-- For the `<` version, see `pgame.lt_move_right`. -/ theorem numeric.le_move_right {x : pgame} (o : numeric x) (j : x.right_moves) : x ≤ x.move_right j := -le_of_lt o (o.move_right j) (o.lt_move_right j) +le_of_lt o (o.move_right j) (pgame.lt_move_right j) theorem add_lt_add {w x y z : pgame.{u}} (oy : numeric y) (oz : numeric z) @@ -178,10 +158,10 @@ theorem numeric_add : Π {x y : pgame} (ox : numeric x) (oy : numeric y), numeri { show xL ix + ⟨yl, yr, yL, yR⟩ < xR jx + ⟨yl, yr, yL, yR⟩, exact add_lt_add_right (ox.1 ix jx) _ }, { show xL ix + ⟨yl, yr, yL, yR⟩ < ⟨xl, xr, xL, xR⟩ + yR jy, - exact add_lt_add oy (oy.move_right jy) (ox.move_left_lt _) (oy.lt_move_right _), }, - { -- show ⟨xl, xr, xL, xR⟩ + yL iy < xR jx + ⟨yl, yr, yL, yR⟩, -- fails? - exact add_lt_add (oy.move_left iy) oy (ox.lt_move_right _) (oy.move_left_lt _), }, - { -- show ⟨xl, xr, xL, xR⟩ + yL iy < ⟨xl, xr, xL, xR⟩ + yR jy, -- fails? + exact add_lt_add oy (oy.move_right jy) (pgame.lt_mk ix) (pgame.mk_lt jy), }, + { -- show ⟨xl, xr, xL, xR⟩ + yL iy < xR jx + ⟨yl, yr, yL, yR⟩, -- fails? + exact add_lt_add (oy.move_left iy) oy (pgame.mk_lt jx) (pgame.lt_mk iy), }, + { -- show ⟨xl, xr, xL, xR⟩ + yL iy < ⟨xl, xr, xL, xR⟩ + yR jy, -- fails? exact @add_lt_add_left pgame _ _ _ _ _ (oy.1 iy jy) ⟨xl, xr, xL, xR⟩ } end, begin diff --git a/src/set_theory/surreal/dyadic.lean b/src/set_theory/surreal/dyadic.lean index b57c4e895e5ea..d41f8e1dbc31a 100644 --- a/src/set_theory/surreal/dyadic.lean +++ b/src/set_theory/surreal/dyadic.lean @@ -66,12 +66,12 @@ begin { rintro ⟨ ⟩ ⟨ ⟩, dsimp only [pi.zero_apply], rw ← pow_half_move_left' n, - apply hn.move_left_lt }, + apply pgame.move_left_lt }, { exact ⟨λ _, numeric_zero, λ _, hn⟩ } } end theorem pow_half_succ_lt_pow_half {n : ℕ} : pow_half (n + 1) < pow_half n := -(@numeric_pow_half (n + 1)).lt_move_right punit.star +pgame.lt_move_right punit.star theorem pow_half_succ_le_pow_half {n : ℕ} : pow_half (n + 1) ≤ pow_half n := le_of_lt numeric_pow_half numeric_pow_half pow_half_succ_lt_pow_half From d4d5b6d26ac55183211a27655a55ad481dc9cb9d Mon Sep 17 00:00:00 2001 From: leanprover-community-bot Date: Mon, 25 Apr 2022 03:54:20 +0000 Subject: [PATCH 221/373] chore(scripts): update nolints.txt (#13679) I am happy to remove some nolints for you! --- scripts/nolints.txt | 16 +++++++--------- scripts/style-exceptions.txt | 1 - 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/scripts/nolints.txt b/scripts/nolints.txt index a5246ea31ca11..92b91ae7a4822 100644 --- a/scripts/nolints.txt +++ b/scripts/nolints.txt @@ -121,7 +121,7 @@ apply_nolint traversable.mfoldr doc_blame -- control/monad/cont.lean apply_nolint cont doc_blame -apply_nolint cont_t doc_blame has_inhabited_instance +apply_nolint cont_t has_inhabited_instance doc_blame apply_nolint cont_t.map doc_blame apply_nolint cont_t.monad_lift doc_blame apply_nolint cont_t.run doc_blame @@ -131,7 +131,7 @@ apply_nolint except_t.mk_label doc_blame apply_nolint is_lawful_monad_cont doc_blame apply_nolint monad_cont doc_blame apply_nolint monad_cont.goto doc_blame -apply_nolint monad_cont.label doc_blame has_inhabited_instance +apply_nolint monad_cont.label has_inhabited_instance doc_blame apply_nolint option_t.call_cc doc_blame apply_nolint option_t.mk_label doc_blame apply_nolint reader_t.call_cc doc_blame @@ -147,7 +147,7 @@ apply_nolint except_t.pass_aux doc_blame apply_nolint option_t.pass_aux doc_blame apply_nolint swap_right doc_blame apply_nolint writer doc_blame -apply_nolint writer_t doc_blame has_inhabited_instance +apply_nolint writer_t has_inhabited_instance doc_blame apply_nolint writer_t.adapt doc_blame apply_nolint writer_t.bind doc_blame apply_nolint writer_t.ext unused_arguments @@ -191,7 +191,7 @@ apply_nolint filter.realizer has_inhabited_instance apply_nolint filter.realizer.of_eq doc_blame -- data/analysis/topology.lean -apply_nolint compact.realizer doc_blame unused_arguments has_inhabited_instance +apply_nolint compact.realizer has_inhabited_instance doc_blame unused_arguments apply_nolint ctop has_inhabited_instance apply_nolint ctop.realizer has_inhabited_instance apply_nolint ctop.realizer.id doc_blame @@ -200,7 +200,7 @@ apply_nolint ctop.realizer.nhds_F unused_arguments apply_nolint ctop.realizer.nhds_σ unused_arguments apply_nolint ctop.realizer.of_equiv doc_blame apply_nolint ctop.to_realizer doc_blame -apply_nolint locally_finite.realizer doc_blame has_inhabited_instance +apply_nolint locally_finite.realizer has_inhabited_instance doc_blame -- data/finset/noncomm_prod.lean apply_nolint finset.noncomm_prod_union_of_disjoint to_additive_doc @@ -470,6 +470,8 @@ apply_nolint left_cancel_monoid.to_has_faithful_opposite_scalar to_additive_doc apply_nolint monoid.to_opposite_mul_action to_additive_doc -- group_theory/group_action/pi.lean +apply_nolint function.has_scalar to_additive_doc +apply_nolint function.smul_comm_class to_additive_doc apply_nolint pi.has_faithful_scalar_at to_additive_doc -- group_theory/group_action/sub_mul_action.lean @@ -506,10 +508,6 @@ apply_nolint sylow.fixed_points_mul_left_cosets_equiv_quotient doc_blame apply_nolint affine_span.nonempty fails_quickly apply_nolint affine_subspace.to_add_torsor fails_quickly --- linear_algebra/pi.lean -apply_nolint function.has_scalar to_additive_doc -apply_nolint function.smul_comm_class to_additive_doc - -- logic/relator.lean apply_nolint relator.bi_total doc_blame apply_nolint relator.bi_unique doc_blame diff --git a/scripts/style-exceptions.txt b/scripts/style-exceptions.txt index 13ef38ddb31a7..9c6dfcda33adb 100644 --- a/scripts/style-exceptions.txt +++ b/scripts/style-exceptions.txt @@ -45,7 +45,6 @@ src/tactic/ext.lean : line 9 : ERR_MOD : Module docstring missing, or too late src/tactic/find.lean : line 8 : ERR_MOD : Module docstring missing, or too late src/tactic/hint.lean : line 9 : ERR_MOD : Module docstring missing, or too late src/tactic/interactive.lean : line 10 : ERR_MOD : Module docstring missing, or too late -src/tactic/lint/default.lean : line 12 : ERR_MOD : Module docstring missing, or too late src/tactic/local_cache.lean : line 8 : ERR_MOD : Module docstring missing, or too late src/tactic/monotonicity/basic.lean : line 8 : ERR_MOD : Module docstring missing, or too late src/tactic/monotonicity/interactive.lean : line 11 : ERR_MOD : Module docstring missing, or too late From df4066cf59a287ee05b2a06236c37c6ff1ef1a18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Mon, 25 Apr 2022 04:29:05 +0000 Subject: [PATCH 222/373] refactor(order/ideal): Make `order.ideal` extend `lower_set` (#13070) * Redefine `order.ideal` to extend `lower_set`. * `set_like` instance * Get rid of `order.ideal.ideal_Inter_nonempty` in favor of `order_bot` * Make arguments to `order.ideal.sup_mem` semi-implicit * Reorder sections according to typeclass assumptions (some were outdated since Yakov's `order_bot`/`order_top` refactor) --- src/order/ideal.lean | 361 ++++++++++++++----------------------- src/order/pfilter.lean | 16 +- src/order/prime_ideal.lean | 13 +- 3 files changed, 151 insertions(+), 239 deletions(-) diff --git a/src/order/ideal.lean b/src/order/ideal.lean index c1c0384ec814d..de3958a8d8b57 100644 --- a/src/order/ideal.lean +++ b/src/order/ideal.lean @@ -5,6 +5,7 @@ Authors: David Wärn -/ import logic.encodable.basic import order.atoms +import order.upper_lower /-! # Order ideals, cofinal sets, and the Rasiowa–Sikorski lemma @@ -21,8 +22,6 @@ structure, such as a bottom element, a top element, or a join-semilattice struct Dual to the notion of a proper filter. - `order.ideal.is_maximal`: a predicate for maximal ideals. Dual to the notion of an ultrafilter. -- `ideal_Inter_nonempty P`: a predicate for when the intersection of all ideals of - `P` is nonempty. - `order.cofinal P`: the type of subsets of `P` containing arbitrarily large elements. Dual to the notion of 'dense set' used in forcing. - `order.ideal_of_cofinals p 𝒟`, where `p : P`, and `𝒟` is a countable family of cofinal @@ -38,19 +37,13 @@ structure, such as a bottom element, a top element, or a join-semilattice struct Note that for the Rasiowa–Sikorski lemma, Wikipedia uses the opposite ordering on `P`, in line with most presentations of forcing. -## TODO - -`order.ideal.ideal_Inter_nonempty` is a complicated way to say that `P` has a bottom element. It -should be replaced by this clearer condition, which could be called strong directedness and which -is a Prop version of `order_bot`. - ## Tags ideal, cofinal, dense, countable, generic -/ -open function +open function set namespace order @@ -60,67 +53,68 @@ variables {P : Type*} - nonempty - upward directed (any pair of elements in the ideal has an upper bound in the ideal) - downward closed (any element less than an element of the ideal is in the ideal). -/ -structure ideal (P) [has_le P] := -(carrier : set P) -(nonempty : carrier.nonempty) -(directed : directed_on (≤) carrier) -(mem_of_le : ∀ {x y : P}, x ≤ y → y ∈ carrier → x ∈ carrier) +structure ideal (P) [has_le P] extends lower_set P := +(nonempty' : carrier.nonempty) +(directed' : directed_on (≤) carrier) /-- A subset of a preorder `P` is an ideal if it is - nonempty - upward directed (any pair of elements in the ideal has an upper bound in the ideal) - downward closed (any element less than an element of the ideal is in the ideal). -/ @[mk_iff] structure is_ideal {P} [has_le P] (I : set P) : Prop := +(is_lower_set : is_lower_set I) (nonempty : I.nonempty) (directed : directed_on (≤) I) -(mem_of_le : ∀ {x y : P}, x ≤ y → y ∈ I → x ∈ I) - -attribute [protected] ideal.nonempty ideal.directed is_ideal.nonempty is_ideal.directed /-- Create an element of type `order.ideal` from a set satisfying the predicate `order.is_ideal`. -/ def is_ideal.to_ideal [has_le P] {I : set P} (h : is_ideal I) : ideal P := -⟨I, h.1, h.2, h.3⟩ +⟨⟨I, h.is_lower_set⟩, h.nonempty, h.directed⟩ namespace ideal section has_le -variables [has_le P] {I J : ideal P} {x y : P} - -/-- An ideal of `P` can be viewed as a subset of `P`. -/ -instance : has_coe (ideal P) (set P) := ⟨carrier⟩ +variables [has_le P] -/-- For the notation `x ∈ I`. -/ -instance : has_mem P (ideal P) := ⟨λ x I, x ∈ (I : set P)⟩ +section +variables {I J s t : ideal P} {x y : P} -@[simp] lemma mem_coe : x ∈ (I : set P) ↔ x ∈ I := iff_of_eq rfl +lemma to_lower_set_injective : injective (to_lower_set : ideal P → lower_set P) := +λ s t h, by { cases s, cases t, congr' } -/-- Two ideals are equal when their underlying sets are equal. -/ -@[ext] lemma ext : ∀ {I J : ideal P}, (I : set P) = J → I = J -| ⟨_, _, _, _⟩ ⟨_, _, _, _⟩ rfl := rfl +instance : set_like (ideal P) P := +{ coe := λ s, s.carrier, + coe_injective' := λ s t h, to_lower_set_injective $ set_like.coe_injective h } -lemma coe_injective : injective (coe : ideal P → set P) := λ _ _, ext +@[ext] lemma ext {s t : ideal P} : (s : set P) = t → s = t := set_like.ext' -@[simp, norm_cast] lemma coe_inj : (I : set P) = J ↔ I = J := ⟨by ext, congr_arg _⟩ +@[simp] lemma carrier_eq_coe (s : ideal P) : s.carrier = s := rfl +@[simp] lemma coe_to_lower_set (s : ideal P) : (s.to_lower_set : set P) = s := rfl -lemma ext_iff : I = J ↔ (I : set P) = J := coe_inj.symm +protected lemma lower (s : ideal P) : is_lower_set (s : set P) := s.lower' +protected lemma nonempty (s : ideal P) : (s : set P).nonempty := s.nonempty' +protected lemma directed (s : ideal P) : directed_on (≤) (s : set P) := s.directed' +protected lemma is_ideal (s : ideal P) : is_ideal (s : set P) := ⟨s.lower, s.nonempty, s.directed⟩ -protected lemma is_ideal (I : ideal P) : is_ideal (I : set P) := ⟨I.2, I.3, I.4⟩ +lemma mem_compl_of_ge {x y : P} : x ≤ y → x ∈ (I : set P)ᶜ → y ∈ (I : set P)ᶜ := λ h, mt $ I.lower h /-- The partial ordering by subset inclusion, inherited from `set P`. -/ -instance : partial_order (ideal P) := partial_order.lift coe coe_injective +instance : partial_order (ideal P) := partial_order.lift coe set_like.coe_injective + +@[simp] lemma coe_subset_coe : (s : set P) ⊆ t ↔ s ≤ t := iff.rfl +@[simp] lemma coe_ssubset_coe : (s : set P) ⊂ t ↔ s < t := iff.rfl @[trans] lemma mem_of_mem_of_le {x : P} {I J : ideal P} : x ∈ I → I ≤ J → x ∈ J := @set.mem_of_mem_of_subset P x I J /-- A proper ideal is one that is not the whole set. Note that the whole set might not be an ideal. -/ -@[mk_iff] class is_proper (I : ideal P) : Prop := (ne_univ : (I : set P) ≠ set.univ) +@[mk_iff] class is_proper (I : ideal P) : Prop := (ne_univ : (I : set P) ≠ univ) lemma is_proper_of_not_mem {I : ideal P} {p : P} (nmem : p ∉ I) : is_proper I := ⟨λ hp, begin change p ∉ ↑I at nmem, rw hp at nmem, - exact nmem (set.mem_univ p), + exact nmem (mem_univ p), end⟩ /-- An ideal is maximal if it is maximal in the collection of proper ideals. @@ -128,123 +122,39 @@ end⟩ Note that `is_coatom` is less general because ideals only have a top element when `P` is directed and nonempty. -/ @[mk_iff] class is_maximal (I : ideal P) extends is_proper I : Prop := -(maximal_proper : ∀ ⦃J : ideal P⦄, I < J → (J : set P) = set.univ) - -variable (P) - -/-- An order `P` has the `ideal_Inter_nonempty` property if the intersection of all ideals is -nonempty. Most importantly, the ideals of a `semilattice_sup` with this property form a complete -lattice. - -TODO: This is equivalent to the existence of a bottom element and shouldn't be specialized to -ideals. -/ -class ideal_Inter_nonempty : Prop := -(Inter_nonempty : (⋂ (I : ideal P), (I : set P)).nonempty) - -variable {P} - -lemma Inter_nonempty [ideal_Inter_nonempty P] : - (⋂ (I : ideal P), (I : set P)).nonempty := -ideal_Inter_nonempty.Inter_nonempty - -lemma ideal_Inter_nonempty.exists_all_mem [ideal_Inter_nonempty P] : - ∃ a : P, ∀ I : ideal P, a ∈ I := -begin - change ∃ (a : P), ∀ (I : ideal P), a ∈ (I : set P), - rw ← set.nonempty_Inter, - exact Inter_nonempty, -end - -lemma ideal_Inter_nonempty_of_exists_all_mem (h : ∃ a : P, ∀ I : ideal P, a ∈ I) : - ideal_Inter_nonempty P := -{ Inter_nonempty := by rwa set.nonempty_Inter } - -lemma ideal_Inter_nonempty_iff : - ideal_Inter_nonempty P ↔ ∃ a : P, ∀ I : ideal P, a ∈ I := -⟨λ _, by exactI ideal_Inter_nonempty.exists_all_mem, ideal_Inter_nonempty_of_exists_all_mem⟩ +(maximal_proper : ∀ ⦃J : ideal P⦄, I < J → (J : set P) = univ) lemma inter_nonempty [is_directed P (swap (≤))] (I J : ideal P) : (I ∩ J : set P).nonempty := begin obtain ⟨a, ha⟩ := I.nonempty, obtain ⟨b, hb⟩ := J.nonempty, obtain ⟨c, hac, hbc⟩ := directed_of (swap (≤)) a b, - exact ⟨c, I.mem_of_le hac ha, J.mem_of_le hbc hb⟩, + exact ⟨c, I.lower hac ha, J.lower hbc hb⟩, end -end has_le - -section preorder -variables [preorder P] {I J : ideal P} {x y : P} - -/-- The smallest ideal containing a given element. -/ -def principal (p : P) : ideal P := -{ carrier := { x | x ≤ p }, - nonempty := ⟨p, le_rfl⟩, - directed := λ x hx y hy, ⟨p, le_rfl, hx, hy⟩, - mem_of_le := λ x y hxy hy, le_trans hxy hy, } - -instance [inhabited P] : inhabited (ideal P) := ⟨ideal.principal default⟩ - -@[simp] lemma principal_le_iff : principal x ≤ I ↔ x ∈ I := -⟨λ (h : ∀ {y}, y ≤ x → y ∈ I), h (le_refl x), - λ h_mem y (h_le : y ≤ x), I.mem_of_le h_le h_mem⟩ - -@[simp] lemma mem_principal : x ∈ principal y ↔ x ≤ y := iff.rfl - -lemma mem_compl_of_ge {x y : P} : x ≤ y → x ∈ (I : set P)ᶜ → y ∈ (I : set P)ᶜ := -λ h, mt (I.mem_of_le h) - -end preorder - -section order_bot - -/-- A specific witness of `I.nonempty` when `P` has a bottom element. -/ -@[simp] lemma bot_mem [has_le P] [order_bot P] {I : ideal P} : ⊥ ∈ I := -I.mem_of_le bot_le I.nonempty.some_mem - -variables [preorder P] [order_bot P] {I : ideal P} - -/-- There is a bottom ideal when `P` has a bottom element. -/ -instance : order_bot (ideal P) := -{ bot := principal ⊥, - bot_le := by simp } - -@[priority 100] -instance order_bot.ideal_Inter_nonempty : ideal_Inter_nonempty P := -by { rw ideal_Inter_nonempty_iff, exact ⟨⊥, λ I, bot_mem⟩ } - -end order_bot +end section directed -variables [has_le P] [is_directed P (≤)] [nonempty P] {I : ideal P} +variables [is_directed P (≤)] [nonempty P] {I : ideal P} -/-- In a directed and nonempty order, the top ideal of a is `set.univ`. -/ +/-- In a directed and nonempty order, the top ideal of a is `univ`. -/ instance : order_top (ideal P) := -{ top := { carrier := set.univ, - nonempty := set.univ_nonempty, - directed := directed_on_univ, - mem_of_le := λ _ _ _ _, trivial }, +{ top := ⟨⊤, univ_nonempty, directed_on_univ⟩, le_top := λ I, le_top } -@[simp] lemma coe_top : ((⊤ : ideal P) : set P) = set.univ := rfl +@[simp] lemma top_to_lower_set : (⊤ : ideal P).to_lower_set = ⊤ := rfl +@[simp] lemma coe_top : ((⊤ : ideal P) : set P) = univ := rfl lemma is_proper_of_ne_top (ne_top : I ≠ ⊤) : is_proper I := ⟨λ h, ne_top $ ext h⟩ -lemma is_proper.ne_top (hI : is_proper I) : I ≠ ⊤ := -begin - intro h, - rw [ext_iff, coe_top] at h, - apply hI.ne_univ, - assumption, -end +lemma is_proper.ne_top (hI : is_proper I) : I ≠ ⊤ := λ h, is_proper.ne_univ $ congr_arg coe h lemma _root_.is_coatom.is_proper (hI : is_coatom I) : is_proper I := is_proper_of_ne_top hI.1 lemma is_proper_iff_ne_top : is_proper I ↔ I ≠ ⊤ := ⟨λ h, h.ne_top, λ h, is_proper_of_ne_top h⟩ lemma is_maximal.is_coatom (h : is_maximal I) : is_coatom I := -⟨is_maximal.to_is_proper.ne_top, - λ _ _, by { rw [ext_iff, coe_top], exact is_maximal.maximal_proper ‹_› }⟩ +⟨is_maximal.to_is_proper.ne_top, λ J h, ext $ is_maximal.maximal_proper h⟩ lemma is_maximal.is_coatom' [is_maximal I] : is_coatom I := is_maximal.is_coatom ‹_› @@ -256,69 +166,116 @@ lemma is_maximal_iff_is_coatom : is_maximal I ↔ is_coatom I := ⟨λ h, h.is_c end directed +section order_bot +variables [order_bot P] + +@[simp] lemma bot_mem (s : ideal P) : ⊥ ∈ s := s.lower bot_le s.nonempty.some_mem + +end order_bot + section order_top -variables [has_le P] [order_top P] {I : ideal P} +variables [order_top P] {I : ideal P} -lemma top_of_top_mem (hI : ⊤ ∈ I) : I = ⊤ := -by { ext, exact iff_of_true (I.mem_of_le le_top hI) trivial } +lemma top_of_top_mem (h : ⊤ ∈ I) : I = ⊤ := by { ext, exact iff_of_true (I.lower le_top h) trivial } lemma is_proper.top_not_mem (hI : is_proper I) : ⊤ ∉ I := λ h, hI.ne_top $ top_of_top_mem h end order_top +end has_le + +section preorder +variables [preorder P] + +section +variables {I J : ideal P} {x y : P} + +/-- The smallest ideal containing a given element. -/ +@[simps] def principal (p : P) : ideal P := +{ to_lower_set := lower_set.Iic p, + nonempty' := nonempty_Iic, + directed' := λ x hx y hy, ⟨p, le_rfl, hx, hy⟩ } + +instance [inhabited P] : inhabited (ideal P) := ⟨ideal.principal default⟩ + +@[simp] lemma principal_le_iff : principal x ≤ I ↔ x ∈ I := +⟨λ h, h le_rfl, λ hx y hy, I.lower hy hx⟩ + +@[simp] lemma mem_principal : x ∈ principal y ↔ x ≤ y := iff.rfl + +end + +section order_bot +variables [order_bot P] + +/-- There is a bottom ideal when `P` has a bottom element. -/ +instance : order_bot (ideal P) := +{ bot := principal ⊥, + bot_le := by simp } + +@[simp] lemma principal_bot : principal (⊥ : P) = ⊥ := rfl + +end order_bot + +section order_top +variables [order_top P] + +@[simp] lemma principal_top : principal (⊤ : P) = ⊤ := to_lower_set_injective $ lower_set.Iic_top + +end order_top +end preorder section semilattice_sup -variables [semilattice_sup P] {x y : P} {I : ideal P} +variables [semilattice_sup P] {x y : P} {I s : ideal P} /-- A specific witness of `I.directed` when `P` has joins. -/ -lemma sup_mem (x y ∈ I) : x ⊔ y ∈ I := -let ⟨z, h_mem, hx, hy⟩ := I.directed x ‹_› y ‹_› in -I.mem_of_le (sup_le hx hy) h_mem +lemma sup_mem (hx : x ∈ s) (hy : y ∈ s) : x ⊔ y ∈ s := +let ⟨z, hz, hx, hy⟩ := s.directed x hx y hy in s.lower (sup_le hx hy) hz @[simp] lemma sup_mem_iff : x ⊔ y ∈ I ↔ x ∈ I ∧ y ∈ I := -⟨λ h, ⟨I.mem_of_le le_sup_left h, I.mem_of_le le_sup_right h⟩, - λ h, sup_mem x h.left y h.right⟩ +⟨λ h, ⟨I.lower le_sup_left h, I.lower le_sup_right h⟩, λ h, sup_mem h.1 h.2⟩ end semilattice_sup section semilattice_sup_directed -variables [semilattice_sup P] [is_directed P (swap (≤))] {x : P} {I J K : ideal P} +variables [semilattice_sup P] [is_directed P (swap (≤))] {x : P} {I J K s t : ideal P} /-- The infimum of two ideals of a co-directed order is their intersection. -/ instance : has_inf (ideal P) := -⟨λ I J, { carrier := I ∩ J, - nonempty := inter_nonempty I J, - directed := λ x ⟨_, _⟩ y ⟨_, _⟩, ⟨x ⊔ y, ⟨sup_mem x ‹_› y ‹_›, sup_mem x ‹_› y ‹_›⟩, by simp⟩, - mem_of_le := λ x y h ⟨_, _⟩, ⟨mem_of_le I h ‹_›, mem_of_le J h ‹_›⟩ }⟩ +⟨λ I J, { to_lower_set := I.to_lower_set ⊓ J.to_lower_set, + nonempty' := inter_nonempty I J, + directed' := λ x hx y hy, ⟨x ⊔ y, ⟨sup_mem hx.1 hy.1, sup_mem hx.2 hy.2⟩, by simp⟩ }⟩ /-- The supremum of two ideals of a co-directed order is the union of the down sets of the pointwise supremum of `I` and `J`. -/ instance : has_sup (ideal P) := ⟨λ I J, { carrier := {x | ∃ (i ∈ I) (j ∈ J), x ≤ i ⊔ j}, - nonempty := by { cases inter_nonempty I J, exact ⟨w, w, h.1, w, h.2, le_sup_left⟩ }, - directed := λ x ⟨xi, _, xj, _, _⟩ y ⟨yi, _, yj, _, _⟩, + nonempty' := by { cases inter_nonempty I J, exact ⟨w, w, h.1, w, h.2, le_sup_left⟩ }, + directed' := λ x ⟨xi, _, xj, _, _⟩ y ⟨yi, _, yj, _, _⟩, ⟨x ⊔ y, - ⟨xi ⊔ yi, sup_mem xi ‹_› yi ‹_›, - xj ⊔ yj, sup_mem xj ‹_› yj ‹_›, + ⟨xi ⊔ yi, sup_mem ‹_› ‹_›, + xj ⊔ yj, sup_mem ‹_› ‹_›, sup_le (calc x ≤ xi ⊔ xj : ‹_› ... ≤ (xi ⊔ yi) ⊔ (xj ⊔ yj) : sup_le_sup le_sup_left le_sup_left) (calc y ≤ yi ⊔ yj : ‹_› ... ≤ (xi ⊔ yi) ⊔ (xj ⊔ yj) : sup_le_sup le_sup_right le_sup_right)⟩, le_sup_left, le_sup_right⟩, - mem_of_le := λ x y _ ⟨yi, _, yj, _, _⟩, ⟨yi, ‹_›, yj, ‹_›, le_trans ‹x ≤ y› ‹_›⟩ }⟩ + lower' := λ x y h ⟨yi, _, yj, _, _⟩, ⟨yi, ‹_›, yj, ‹_›, h.trans ‹_›⟩ }⟩ instance : lattice (ideal P) := { sup := (⊔), le_sup_left := λ I J (i ∈ I), by { cases J.nonempty, exact ⟨i, ‹_›, w, ‹_›, le_sup_left⟩ }, le_sup_right := λ I J (j ∈ J), by { cases I.nonempty, exact ⟨w, ‹_›, j, ‹_›, le_sup_right⟩ }, sup_le := λ I J K hIK hJK a ⟨i, hi, j, hj, ha⟩, - K.mem_of_le ha $ sup_mem i (mem_of_mem_of_le hi hIK) j (mem_of_mem_of_le hj hJK), + K.lower ha $ sup_mem (mem_of_mem_of_le hi hIK) (mem_of_mem_of_le hj hJK), inf := (⊓), - inf_le_left := λ I J, set.inter_subset_left I J, - inf_le_right := λ I J, set.inter_subset_right I J, - le_inf := λ I J K, set.subset_inter, + inf_le_left := λ I J, inter_subset_left I J, + inf_le_right := λ I J, inter_subset_right I J, + le_inf := λ I J K, subset_inter, .. ideal.partial_order } +@[simp] lemma coe_sup : ↑(s ⊔ t) = {x | ∃ (a ∈ s) (b ∈ t), x ≤ a ⊔ b} := rfl +@[simp] lemma coe_inf : (↑(s ⊓ t) : set P) = s ∩ t := rfl @[simp] lemma mem_inf : x ∈ I ⊓ J ↔ x ∈ I ∧ x ∈ J := iff.rfl @[simp] lemma mem_sup : x ∈ I ⊔ J ↔ ∃ (i ∈ I) (j ∈ J), x ≤ i ⊔ j := iff.rfl @@ -327,76 +284,38 @@ le_sup_left.lt_of_ne $ λ h, hx $ by simpa only [left_eq_sup, principal_le_iff] end semilattice_sup_directed -section ideal_Inter_nonempty - -variables [preorder P] [ideal_Inter_nonempty P] - -@[priority 100] -instance ideal_Inter_nonempty.to_directed_ge : is_directed P (swap (≤)) := -⟨λ a b, begin - obtain ⟨c, hc⟩ : ∃ a, ∀ I : ideal P, a ∈ I := ideal_Inter_nonempty.exists_all_mem, - exact ⟨c, hc (principal a), hc (principal b)⟩, - end⟩ - -variables {α β γ : Type*} {ι : Sort*} - -lemma ideal_Inter_nonempty.all_Inter_nonempty {f : ι → ideal P} : - (⋂ x, (f x : set P)).nonempty := -begin - obtain ⟨a, ha⟩ : ∃ a : P, ∀ I : ideal P, a ∈ I := ideal_Inter_nonempty.exists_all_mem, - exact ⟨a, by simp [ha]⟩ -end - -lemma ideal_Inter_nonempty.all_bInter_nonempty {f : α → ideal P} {s : set α} : - (⋂ x ∈ s, (f x : set P)).nonempty := -begin - obtain ⟨a, ha⟩ : ∃ a : P, ∀ I : ideal P, a ∈ I := ideal_Inter_nonempty.exists_all_mem, - exact ⟨a, by simp [ha]⟩ -end - -end ideal_Inter_nonempty - -section semilattice_sup_ideal_Inter_nonempty - -variables [semilattice_sup P] [ideal_Inter_nonempty P] {x : P} {I J K : ideal P} +section semilattice_sup_order_bot +variables [semilattice_sup P] [order_bot P] {x : P} {I J K : ideal P} instance : has_Inf (ideal P) := -{ Inf := λ s, { carrier := ⋂ (I ∈ s), (I : set P), - nonempty := ideal_Inter_nonempty.all_bInter_nonempty, - directed := λ x hx y hy, ⟨x ⊔ y, ⟨λ S ⟨I, hS⟩, +⟨λ S, { to_lower_set := ⨅ s ∈ S, to_lower_set s, + nonempty' := ⟨⊥, begin + rw [lower_set.carrier_eq_coe, lower_set.coe_infi₂, set.mem_Inter₂], + exact λ s _, s.bot_mem, + end⟩, + directed' := λ a ha b hb, ⟨a ⊔ b, ⟨ begin - simp only [←hS, sup_mem_iff, mem_coe, set.mem_Inter], - intro hI, - rw set.mem_Inter₂ at *, - exact ⟨hx _ hI, hy _ hI⟩ + rw [lower_set.carrier_eq_coe, lower_set.coe_infi₂, set.mem_Inter₂] at ⊢ ha hb, + exact λ s hs, sup_mem (ha _ hs) (hb _ hs), end, - le_sup_left, le_sup_right⟩⟩, - mem_of_le := λ x y hxy hy, - begin - rw set.mem_Inter₂ at *, - exact λ I hI, mem_of_le I ‹_› (hy I hI) - end } } - -variables {s : set (ideal P)} - -@[simp] lemma mem_Inf : x ∈ Inf s ↔ ∀ I ∈ s, x ∈ I := -by { change x ∈ (⋂ (I ∈ s), (I : set P)) ↔ ∀ I ∈ s, x ∈ I, simp } + le_sup_left, le_sup_right⟩⟩ }⟩ -@[simp] lemma coe_Inf : ↑(Inf s) = ⋂ (I ∈ s), (I : set P) := rfl +variables {S : set (ideal P)} -lemma Inf_le (hI : I ∈ s) : Inf s ≤ I := -λ _ hx, hx I ⟨I, by simp [hI]⟩ +@[simp] lemma coe_Inf : (↑(Inf S) : set P) = ⋂ s ∈ S, ↑s := lower_set.coe_infi₂ _ -lemma le_Inf (h : ∀ J ∈ s, I ≤ J) : I ≤ Inf s := -λ _ _, by { simp only [mem_coe, coe_Inf, set.mem_Inter], tauto } - -lemma is_glb_Inf : is_glb s (Inf s) := ⟨λ _, Inf_le, λ _, le_Inf⟩ +@[simp] lemma mem_Inf : x ∈ Inf S ↔ ∀ s ∈ S, x ∈ s := +by simp_rw [←set_like.mem_coe, coe_Inf, mem_Inter₂] instance : complete_lattice (ideal P) := { ..ideal.lattice, - ..complete_lattice_of_Inf (ideal P) (λ _, @is_glb_Inf _ _ _ _) } + ..complete_lattice_of_Inf (ideal P) (λ S, begin + refine ⟨λ s hs, _, λ s hs, by rwa [←coe_subset_coe, coe_Inf, subset_Inter₂_iff]⟩, + rw [←coe_subset_coe, coe_Inf], + exact bInter_subset_of_mem hs, + end) } -end semilattice_sup_ideal_Inter_nonempty +end semilattice_sup_order_bot section distrib_lattice @@ -406,19 +325,15 @@ variables {I J : ideal P} lemma eq_sup_of_le_sup {x i j: P} (hi : i ∈ I) (hj : j ∈ J) (hx : x ≤ i ⊔ j) : ∃ (i' ∈ I) (j' ∈ J), x = i' ⊔ j' := begin - refine ⟨x ⊓ i, I.mem_of_le inf_le_right hi, x ⊓ j, J.mem_of_le inf_le_right hj, _⟩, + refine ⟨x ⊓ i, I.lower inf_le_right hi, x ⊓ j, J.lower inf_le_right hj, _⟩, calc x = x ⊓ (i ⊔ j) : left_eq_inf.mpr hx ... = (x ⊓ i) ⊔ (x ⊓ j) : inf_sup_left, end lemma coe_sup_eq : ↑(I ⊔ J) = {x | ∃ i ∈ I, ∃ j ∈ J, x = i ⊔ j} := -begin - ext, - rw [mem_coe, mem_sup], - exact ⟨λ ⟨_, _, _, _, _⟩, eq_sup_of_le_sup ‹_› ‹_› ‹_›, +set.ext $ λ _, ⟨λ ⟨_, _, _, _, _⟩, eq_sup_of_le_sup ‹_› ‹_› ‹_›, λ ⟨i, _, j, _, _⟩, ⟨i, ‹_›, j, ‹_›, le_of_eq ‹_›⟩⟩ -end end distrib_lattice @@ -430,7 +345,7 @@ lemma is_proper.not_mem_of_compl_mem (hI : is_proper I) (hxc : xᶜ ∈ I) : x begin intro hx, apply hI.top_not_mem, - have ht : x ⊔ xᶜ ∈ I := sup_mem _ ‹_› _ ‹_›, + have ht : x ⊔ xᶜ ∈ I := sup_mem ‹_› ‹_›, rwa sup_compl_eq_top at ht, end @@ -453,7 +368,7 @@ namespace cofinal variables [preorder P] instance : inhabited (cofinal P) := -⟨{ carrier := set.univ, mem_gt := λ x, ⟨x, trivial, le_rfl⟩ }⟩ +⟨{ carrier := univ, mem_gt := λ x, ⟨x, trivial, le_rfl⟩ }⟩ instance : has_mem P (cofinal P) := ⟨λ x D, x ∈ D.carrier⟩ @@ -498,12 +413,12 @@ by { dunfold sequence_of_cofinals, rw encodable.encodek, apply cofinal.above_mem This proves the Rasiowa–Sikorski lemma. -/ def ideal_of_cofinals : ideal P := { carrier := { x : P | ∃ n, x ≤ sequence_of_cofinals p 𝒟 n }, - nonempty := ⟨p, 0, le_rfl⟩, - directed := λ x ⟨n, hn⟩ y ⟨m, hm⟩, + lower' := λ x y hxy ⟨n, hn⟩, ⟨n, le_trans hxy hn⟩, + nonempty' := ⟨p, 0, le_rfl⟩, + directed' := λ x ⟨n, hn⟩ y ⟨m, hm⟩, ⟨_, ⟨max n m, le_rfl⟩, le_trans hn $ sequence_of_cofinals.monotone p 𝒟 (le_max_left _ _), - le_trans hm $ sequence_of_cofinals.monotone p 𝒟 (le_max_right _ _) ⟩, - mem_of_le := λ x y hxy ⟨n, hn⟩, ⟨n, le_trans hxy hn⟩, } + le_trans hm $ sequence_of_cofinals.monotone p 𝒟 (le_max_right _ _) ⟩ } lemma mem_ideal_of_cofinals : p ∈ ideal_of_cofinals p 𝒟 := ⟨0, le_rfl⟩ diff --git a/src/order/pfilter.lean b/src/order/pfilter.lean index 86c8f2b33d42f..43b49eb367283 100644 --- a/src/order/pfilter.lean +++ b/src/order/pfilter.lean @@ -51,7 +51,7 @@ def is_pfilter [preorder P] (F : set P) : Prop := lemma is_pfilter.of_def [preorder P] {F : set P} (nonempty : F.nonempty) (directed : directed_on (≥) F) (mem_of_le : ∀ {x y : P}, x ≤ y → x ∈ F → y ∈ F) : is_pfilter F := -by { use [nonempty, directed], exact λ _ _ _ _, mem_of_le ‹_› ‹_› } +⟨λ _ _ _ _, mem_of_le ‹_› ‹_›, nonempty, directed⟩ /-- Create an element of type `order.pfilter` from a set satisfying the predicate `order.is_pfilter`. -/ @@ -61,7 +61,7 @@ def is_pfilter.to_pfilter [preorder P] {F : set P} (h : is_pfilter F) : pfilter namespace pfilter section preorder -variables [preorder P] {x y : P} (F : pfilter P) +variables [preorder P] {x y : P} (F s t : pfilter P) /-- A filter on `P` is a subset of `P`. -/ instance : has_coe (pfilter P) (set P) := ⟨λ F, F.dual.carrier⟩ @@ -78,7 +78,7 @@ lemma nonempty : (F : set P).nonempty := F.dual.nonempty lemma directed : directed_on (≥) (F : set P) := F.dual.directed -lemma mem_of_le {F : pfilter P} : x ≤ y → x ∈ F → y ∈ F := λ h, F.dual.mem_of_le h +lemma mem_of_le {F : pfilter P} : x ≤ y → x ∈ F → y ∈ F := λ h, F.dual.lower h /-- The smallest filter containing a given element. -/ def principal (p : P) : pfilter P := ⟨ideal.principal p⟩ @@ -86,8 +86,8 @@ def principal (p : P) : pfilter P := ⟨ideal.principal p⟩ instance [inhabited P] : inhabited (pfilter P) := ⟨⟨default⟩⟩ /-- Two filters are equal when their underlying sets are equal. -/ -@[ext] lemma ext : ∀ (F G : pfilter P), (F : set P) = G → F = G -| ⟨⟨_, _, _, _⟩⟩ ⟨⟨_, _, _, _⟩⟩ rfl := rfl +@[ext] lemma ext (h : (s : set P) = t) : s = t := +by { cases s, cases t, exact congr_arg _ (ideal.ext h) } /-- The partial ordering by subset inclusion, inherited from `set P`. -/ instance : partial_order (pfilter P) := partial_order.lift coe ext @@ -104,8 +104,7 @@ section order_top variables [preorder P] [order_top P] {F : pfilter P} /-- A specific witness of `pfilter.nonempty` when `P` has a top element. -/ -@[simp] lemma top_mem : ⊤ ∈ F := -ideal.bot_mem +@[simp] lemma top_mem : ⊤ ∈ F := ideal.bot_mem _ /-- There is a bottom filter when `P` has a top element. -/ instance : order_bot (pfilter P) := @@ -123,8 +122,7 @@ section semilattice_inf variables [semilattice_inf P] {x y : P} {F : pfilter P} /-- A specific witness of `pfilter.directed` when `P` has meets. -/ -lemma inf_mem (x y ∈ F) : x ⊓ y ∈ F := -ideal.sup_mem x ‹x ∈ F› y ‹y ∈ F› +lemma inf_mem (hx : x ∈ F) (hy : y ∈ F) : x ⊓ y ∈ F := ideal.sup_mem hx hy @[simp] lemma inf_mem_iff : x ⊓ y ∈ F ↔ x ∈ F ∧ y ∈ F := ideal.sup_mem_iff diff --git a/src/order/prime_ideal.lean b/src/order/prime_ideal.lean index 9757bbb43ad66..09e5457b2ea80 100644 --- a/src/order/prime_ideal.lean +++ b/src/order/prime_ideal.lean @@ -98,7 +98,7 @@ begin contrapose!, let F := hI.compl_filter.to_pfilter, show x ∈ F ∧ y ∈ F → x ⊓ y ∈ F, - exact λ h, inf_mem _ h.1 _ h.2, + exact λ h, inf_mem h.1 h.2, end lemma is_prime.of_mem_or_mem [is_proper I] (hI : ∀ {x y : P}, x ⊓ y ∈ I → x ∈ I ∨ y ∈ I) : @@ -139,8 +139,7 @@ begin rw coe_sup_eq at hyJ, rcases hyJ with ⟨a, ha, b, hb, hy⟩, rw hy, - apply sup_mem _ ha _, - refine I.mem_of_le (le_inf hb _) hxy, + refine sup_mem ha (I.lower (le_inf hb _) hxy), rw hy, exact le_sup_right end @@ -155,7 +154,7 @@ lemma is_prime.mem_or_compl_mem (hI : is_prime I) : x ∈ I ∨ xᶜ ∈ I := begin apply hI.mem_or_mem, rw inf_compl_eq_bot, - exact bot_mem, + exact I.bot_mem, end lemma is_prime.mem_compl_of_not_mem (hI : is_prime I) (hxnI : x ∉ I) : xᶜ ∈ I := @@ -166,7 +165,7 @@ begin simp only [is_prime_iff_mem_or_mem, or_iff_not_imp_left], intros x y hxy hxI, have hxcI : xᶜ ∈ I := h.resolve_left hxI, - have ass : (x ⊓ y) ⊔ (y ⊓ xᶜ) ∈ I := sup_mem _ hxy _ (mem_of_le I inf_le_right hxcI), + have ass : (x ⊓ y) ⊔ (y ⊓ xᶜ) ∈ I := sup_mem hxy (I.lower inf_le_right hxcI), rwa [inf_comm, sup_inf_inf_compl] at ass end @@ -181,8 +180,8 @@ begin rcases set.exists_of_ssubset hIJ with ⟨y, hyJ, hyI⟩, suffices ass : (x ⊓ y) ⊔ (x ⊓ yᶜ) ∈ J, { rwa sup_inf_inf_compl at ass }, - exact sup_mem _ (J.mem_of_le inf_le_right hyJ) _ - (hIJ.le $ I.mem_of_le inf_le_right $ is_prime.mem_compl_of_not_mem ‹_› hyI), + exact sup_mem (J.lower inf_le_right hyJ) + (hIJ.le $ I.lower inf_le_right $ is_prime.mem_compl_of_not_mem ‹_› hyI), end end boolean_algebra From 070c21b6b705d908cc9203fa0b93865563f16bb4 Mon Sep 17 00:00:00 2001 From: Eric Rodriguez Date: Mon, 25 Apr 2022 05:10:33 +0000 Subject: [PATCH 223/373] chore(data/matrix): generalisation linter (#13655) --- src/data/matrix/basic.lean | 147 ++++++++++++++++++++----------------- 1 file changed, 79 insertions(+), 68 deletions(-) diff --git a/src/data/matrix/basic.lean b/src/data/matrix/basic.lean index c272c62249e75..283fe8f91ec52 100644 --- a/src/data/matrix/basic.lean +++ b/src/data/matrix/basic.lean @@ -261,7 +261,7 @@ variables {n α R} (diagonal d).map f = diagonal (λ m, f (d m)) := by { ext, simp only [diagonal, map_apply], split_ifs; simp [h], } -@[simp] lemma diagonal_conj_transpose [semiring α] [star_ring α] (v : n → α) : +@[simp] lemma diagonal_conj_transpose [add_monoid α] [star_add_monoid α] (v : n → α) : (diagonal v)ᴴ = diagonal (star v) := begin rw [conj_transpose, diagonal_transpose, diagonal_map (star_zero _)], @@ -300,7 +300,7 @@ section numeral @[simp] lemma bit0_apply [has_add α] (M : matrix m m α) (i : m) (j : m) : (bit0 M) i j = bit0 (M i j) := rfl -variables [add_monoid α] [has_one α] +variables [add_zero_class α] [has_one α] lemma bit1_apply (M : matrix n n α) (i : n) (j : n) : (bit1 M) i j = if i = j then bit1 (M i j) else bit0 (M i j) := @@ -337,7 +337,7 @@ lemma dot_product_assoc [fintype n] [non_unital_semiring α] (u : m → α) (w : (λ j, u ⬝ᵥ (λ i, v i j)) ⬝ᵥ w = u ⬝ᵥ (λ i, (v i) ⬝ᵥ w) := by simpa [dot_product, finset.mul_sum, finset.sum_mul, mul_assoc] using finset.sum_comm -lemma dot_product_comm [comm_semiring α] (v w : m → α) : +lemma dot_product_comm [add_comm_monoid α] [comm_semigroup α] (v w : m → α) : v ⬝ᵥ w = w ⬝ᵥ v := by simp_rw [dot_product, mul_comm] @@ -465,6 +465,21 @@ lemma sum_apply [add_comm_monoid α] (i : m) (j : n) (∑ c in s, g c) i j = ∑ c in s, g c i j := (congr_fun (s.sum_apply i g) j).trans (s.sum_apply j _) +section add_comm_monoid + +variables [add_comm_monoid α] [has_mul α] + +@[simp] lemma smul_mul [fintype n] [monoid R] [distrib_mul_action R α] [is_scalar_tower R α α] + (a : R) (M : matrix m n α) (N : matrix n l α) : + (a • M) ⬝ N = a • M ⬝ N := +by { ext, apply smul_dot_product } + +@[simp] lemma mul_smul [fintype n] [monoid R] [distrib_mul_action R α] [smul_comm_class R α α] + (M : matrix m n α) (a : R) (N : matrix n l α) : M ⬝ (a • N) = a • M ⬝ N := +by { ext, apply dot_product_smul } + +end add_comm_monoid + section non_unital_non_assoc_semiring variables [non_unital_non_assoc_semiring α] @@ -506,6 +521,10 @@ theorem diagonal_mul_diagonal' [fintype n] [decidable_eq n] (d₁ d₂ : n → diagonal d₁ * diagonal d₂ = diagonal (λ i, d₁ i * d₂ i) := diagonal_mul_diagonal _ _ +lemma smul_eq_diagonal_mul [fintype m] [decidable_eq m] (M : matrix m n α) (a : α) : + a • M = diagonal (λ _, a) ⬝ M := +by { ext, simp } + /-- Left multiplication by a matrix, as an `add_monoid_hom` from matrices to matrices. -/ @[simps] def add_monoid_hom_mul_left [fintype m] (M : matrix l m α) : matrix m n α →+ matrix l n α := @@ -528,6 +547,16 @@ protected lemma mul_sum [fintype m] (s : finset β) (f : β → matrix m n α) (M : matrix l m α) : M ⬝ ∑ a in s, f a = ∑ a in s, M ⬝ f a := (add_monoid_hom_mul_left M : matrix m n α →+ _).map_sum f s +/-- This instance enables use with `smul_mul_assoc`. -/ +instance semiring.is_scalar_tower [fintype n] [monoid R] [distrib_mul_action R α] + [is_scalar_tower R α α] : is_scalar_tower R (matrix n n α) (matrix n n α) := +⟨λ r m n, matrix.smul_mul r m n⟩ + +/-- This instance enables use with `mul_smul_comm`. -/ +instance semiring.smul_comm_class [fintype n] [monoid R] [distrib_mul_action R α] + [smul_comm_class R α α] : smul_comm_class R (matrix n n α) (matrix n n α) := +⟨λ r m n, (matrix.mul_smul m r n).symm⟩ + end non_unital_non_assoc_semiring section non_assoc_semiring @@ -620,29 +649,6 @@ instance [fintype n] [decidable_eq n] [ring α] : ring (matrix n n α) := section semiring variables [semiring α] -lemma smul_eq_diagonal_mul [fintype m] [decidable_eq m] (M : matrix m n α) (a : α) : - a • M = diagonal (λ _, a) ⬝ M := -by { ext, simp } - -@[simp] lemma smul_mul [fintype n] [monoid R] [distrib_mul_action R α] [is_scalar_tower R α α] - (a : R) (M : matrix m n α) (N : matrix n l α) : - (a • M) ⬝ N = a • M ⬝ N := -by { ext, apply smul_dot_product } - -/-- This instance enables use with `smul_mul_assoc`. -/ -instance semiring.is_scalar_tower [fintype n] [monoid R] [distrib_mul_action R α] - [is_scalar_tower R α α] : is_scalar_tower R (matrix n n α) (matrix n n α) := -⟨λ r m n, matrix.smul_mul r m n⟩ - -@[simp] lemma mul_smul [fintype n] [monoid R] [distrib_mul_action R α] [smul_comm_class R α α] - (M : matrix m n α) (a : R) (N : matrix n l α) : M ⬝ (a • N) = a • M ⬝ N := -by { ext, apply dot_product_smul } - -/-- This instance enables use with `mul_smul_comm`. -/ -instance semiring.smul_comm_class [fintype n] [monoid R] [distrib_mul_action R α] - [smul_comm_class R α α] : smul_comm_class R (matrix n n α) (matrix n n α) := -⟨λ r m n, (matrix.mul_smul m r n).symm⟩ - @[simp] lemma mul_mul_left [fintype n] (M : matrix m n α) (N : matrix n o α) (a : α) : (λ i j, a * M i j) ⬝ N = a • (M ⬝ N) := smul_mul a M N @@ -979,6 +985,10 @@ namespace matrix def vec_mul_vec [has_mul α] (w : m → α) (v : n → α) : matrix m n α | x y := w x * v y +lemma vec_mul_vec_eq [has_mul α] [add_comm_monoid α] (w : m → α) (v : n → α) : + vec_mul_vec w v = (col w) ⬝ (row v) := +by { ext i j, simp only [vec_mul_vec, mul_apply, fintype.univ_punit, finset.sum_singleton], refl } + section non_unital_non_assoc_semiring variables [non_unital_non_assoc_semiring α] @@ -1027,10 +1037,6 @@ by { ext, simp [mul_vec] } @[simp] lemma vec_mul_zero [fintype m] (v : m → α) : vec_mul v (0 : matrix m n α) = 0 := by { ext, simp [vec_mul] } -lemma vec_mul_vec_eq (w : m → α) (v : n → α) : - vec_mul_vec w v = (col w) ⬝ (row v) := -by { ext i j, simp [vec_mul_vec, mul_apply], refl } - lemma smul_mul_vec_assoc [fintype n] [monoid R] [distrib_mul_action R α] [is_scalar_tower R α α] (a : R) (A : matrix m n α) (b : n → α) : (a • A).mul_vec b = a • (A.mul_vec b) := @@ -1052,13 +1058,13 @@ lemma add_vec_mul [fintype m] (A : matrix m n α) (x y : m → α) : vec_mul (x + y) A = vec_mul x A + vec_mul y A := by { ext, apply add_dot_product } -lemma vec_mul_smul [fintype m] [comm_semiring R] [semiring S] [algebra R S] - (M : matrix m n S) (b : R) (v : m → S) : +lemma vec_mul_smul [fintype n] [monoid R] [non_unital_non_assoc_semiring S] [distrib_mul_action R S] + [is_scalar_tower R S S] (M : matrix n m S) (b : R) (v : n → S) : M.vec_mul (b • v) = b • M.vec_mul v := by { ext i, simp only [vec_mul, dot_product, finset.smul_sum, pi.smul_apply, smul_mul_assoc] } -lemma mul_vec_smul [fintype n] [comm_semiring R] [semiring S] [algebra R S] - (M : matrix m n S) (b : R) (v : n → S) : +lemma mul_vec_smul [fintype n] [monoid R] [non_unital_non_assoc_semiring S] [distrib_mul_action R S] + [smul_comm_class R S S] (M : matrix m n S) (b : R) (v : n → S) : M.mul_vec (b • v) = b • M.mul_vec v := by { ext i, simp only [mul_vec, dot_product, finset.smul_sum, pi.smul_apply, mul_smul_comm] } @@ -1158,8 +1164,8 @@ by { ext i j, simp } (M - N)ᵀ = Mᵀ - Nᵀ := by { ext i j, simp } -@[simp] lemma transpose_mul [comm_semiring α] [fintype n] (M : matrix m n α) (N : matrix n l α) : - (M ⬝ N)ᵀ = Nᵀ ⬝ Mᵀ := +@[simp] lemma transpose_mul [add_comm_monoid α] [comm_semigroup α] [fintype n] + (M : matrix m n α) (N : matrix n l α) : (M ⬝ N)ᵀ = Nᵀ ⬝ Mᵀ := begin ext i j, apply dot_product_comm @@ -1202,7 +1208,8 @@ lemma transpose_sum [add_comm_monoid α] {ι : Type*} (s : finset ι) (M : ι /-- `matrix.transpose` as a `ring_equiv` to the opposite ring -/ @[simps] -def transpose_ring_equiv [comm_semiring α] [fintype m] : matrix m m α ≃+* (matrix m m α)ᵐᵒᵖ := +def transpose_ring_equiv [add_comm_monoid α] [comm_semigroup α] [fintype m] : + matrix m m α ≃+* (matrix m m α)ᵐᵒᵖ := { to_fun := λ M, mul_opposite.op (Mᵀ), inv_fun := λ M, M.unopᵀ, map_mul' := λ M N, (congr_arg mul_opposite.op (transpose_mul M N)).trans @@ -1229,30 +1236,34 @@ open_locale matrix @[simp] lemma conj_transpose_conj_transpose [has_involutive_star α] (M : matrix m n α) : Mᴴᴴ = M := -by ext; simp +matrix.ext $ by simp -@[simp] lemma conj_transpose_zero [semiring α] [star_ring α] : (0 : matrix m n α)ᴴ = 0 := -by ext i j; simp +@[simp] lemma conj_transpose_zero [add_monoid α] [star_add_monoid α] : (0 : matrix m n α)ᴴ = 0 := +matrix.ext $ by simp @[simp] lemma conj_transpose_one [decidable_eq n] [semiring α] [star_ring α]: (1 : matrix n n α)ᴴ = 1 := by simp [conj_transpose] @[simp] lemma conj_transpose_add [add_monoid α] [star_add_monoid α] (M N : matrix m n α) : - (M + N)ᴴ = Mᴴ + Nᴴ := by ext i j; simp + (M + N)ᴴ = Mᴴ + Nᴴ := +matrix.ext $ by simp @[simp] lemma conj_transpose_sub [add_group α] [star_add_monoid α] (M N : matrix m n α) : - (M - N)ᴴ = Mᴴ - Nᴴ := by ext i j; simp + (M - N)ᴴ = Mᴴ - Nᴴ := +matrix.ext $ by simp -@[simp] lemma conj_transpose_smul [comm_monoid α] [star_semigroup α] (c : α) (M : matrix m n α) : +@[simp] lemma conj_transpose_smul [comm_semigroup α] [star_semigroup α] (c : α) (M : matrix m n α) : (c • M)ᴴ = (star c) • Mᴴ := -by ext i j; simp [mul_comm] +matrix.ext $ by simp -@[simp] lemma conj_transpose_mul [fintype n] [semiring α] [star_ring α] - (M : matrix m n α) (N : matrix n l α) : (M ⬝ N)ᴴ = Nᴴ ⬝ Mᴴ := by ext i j; simp [mul_apply] +@[simp] lemma conj_transpose_mul [fintype n] [non_unital_semiring α] [star_ring α] + (M : matrix m n α) (N : matrix n l α) : (M ⬝ N)ᴴ = Nᴴ ⬝ Mᴴ := +matrix.ext $ by simp [mul_apply] -@[simp] lemma conj_transpose_neg [non_unital_ring α] [star_ring α] (M : matrix m n α) : - (- M)ᴴ = - Mᴴ := by ext i j; simp +@[simp] lemma conj_transpose_neg [add_group α] [star_add_monoid α] (M : matrix m n α) : + (- M)ᴴ = - Mᴴ := +matrix.ext $ by simp /-- `matrix.conj_transpose` as an `add_equiv` -/ @[simps apply] @@ -1321,7 +1332,7 @@ instance [fintype n] [semiring α] [star_ring α] : star_ring (matrix n n α) := star_mul := conj_transpose_mul, } /-- A version of `star_mul` for `⬝` instead of `*`. -/ -lemma star_mul [fintype n] [semiring α] [star_ring α] (M N : matrix n n α) : +lemma star_mul [fintype n] [non_unital_semiring α] [star_ring α] (M N : matrix n n α) : star (M ⬝ N) = star N ⬝ star M := conj_transpose_mul _ _ end star @@ -1363,12 +1374,10 @@ lemma minor_neg [has_neg α] (A : matrix m n α) : lemma minor_sub [has_sub α] (A B : matrix m n α) : ((A - B).minor : (l → m) → (o → n) → matrix l o α) = A.minor - B.minor := rfl -@[simp] -lemma minor_zero [has_zero α] : +@[simp] lemma minor_zero [has_zero α] : ((0 : matrix m n α).minor : (l → m) → (o → n) → matrix l o α) = 0 := rfl -lemma minor_smul {R : Type*} [semiring R] [add_comm_monoid α] [module R α] (r : R) - (A : matrix m n α) : +lemma minor_smul {R : Type*} [has_scalar R α] (r : R) (A : matrix m n α) : ((r • A : matrix m n α).minor : (l → m) → (o → n) → matrix l o α) = r • A.minor := rfl lemma minor_map (f : α → β) (e₁ : l → m) (e₂ : o → n) (A : matrix m n α) : @@ -1391,7 +1400,7 @@ lemma minor_one [has_zero α] [has_one α] [decidable_eq m] [decidable_eq l] (e (1 : matrix m m α).minor e e = 1 := minor_diagonal _ e he -lemma minor_mul [fintype n] [fintype o] [semiring α] {p q : Type*} +lemma minor_mul [fintype n] [fintype o] [has_mul α] [add_comm_monoid α] {p q : Type*} (M : matrix m n α) (N : matrix n p α) (e₁ : l → m) (e₂ : o → n) (e₃ : q → p) (he₂ : function.bijective e₂) : (M ⬝ N).minor e₁ e₃ = (M.minor e₁ e₂) ⬝ (N.minor e₂ e₃) := @@ -1424,13 +1433,14 @@ lemma minor_one_equiv [has_zero α] [has_one α] [decidable_eq m] [decidable_eq minor_one e e.injective @[simp] -lemma minor_mul_equiv [fintype n] [fintype o] [semiring α] {p q : Type*} +lemma minor_mul_equiv [fintype n] [fintype o] [add_comm_monoid α] [has_mul α] {p q : Type*} (M : matrix m n α) (N : matrix n p α) (e₁ : l → m) (e₂ : o ≃ n) (e₃ : q → p) : (M.minor e₁ e₂) ⬝ (N.minor e₂ e₃) = (M ⬝ N).minor e₁ e₃ := (minor_mul M N e₁ e₂ e₃ e₂.bijective).symm -lemma mul_minor_one [fintype n] [fintype o] [semiring α] [decidable_eq o] (e₁ : n ≃ o) (e₂ : l → o) - (M : matrix m n α) : M ⬝ (1 : matrix o o α).minor e₁ e₂ = minor M id (e₁.symm ∘ e₂) := +lemma mul_minor_one [fintype n] [fintype o] [non_assoc_semiring α] [decidable_eq o] (e₁ : n ≃ o) + (e₂ : l → o) (M : matrix m n α) : + M ⬝ (1 : matrix o o α).minor e₁ e₂ = minor M id (e₁.symm ∘ e₂) := begin let A := M.minor id e₁.symm, have : M = A.minor id e₁, @@ -1440,8 +1450,9 @@ begin equiv.symm_comp_self], end -lemma one_minor_mul [fintype m] [fintype o] [semiring α] [decidable_eq o] (e₁ : l → o) (e₂ : m ≃ o) - (M : matrix m n α) : ((1 : matrix o o α).minor e₁ e₂).mul M = minor M (e₂.symm ∘ e₁) id := +lemma one_minor_mul [fintype m] [fintype o] [non_assoc_semiring α] [decidable_eq o] (e₁ : l → o) + (e₂ : m ≃ o) (M : matrix m n α) : + ((1 : matrix o o α).minor e₁ e₂).mul M = minor M (e₂.symm ∘ e₁) id := begin let A := M.minor e₂.symm id, have : M = A.minor e₂ id, @@ -1485,7 +1496,7 @@ lemma conj_transpose_reindex [has_star α] (eₘ : m ≃ l) (eₙ : n ≃ o) (M rfl @[simp] -lemma minor_mul_transpose_minor [fintype m] [fintype n] [semiring α] +lemma minor_mul_transpose_minor [fintype m] [fintype n] [add_comm_monoid α] [has_mul α] (e : m ≃ n) (M : matrix m n α) : (M.minor id e) ⬝ (Mᵀ).minor e id = M ⬝ Mᵀ := by rw [minor_mul_equiv, minor_id_id] @@ -1562,13 +1573,13 @@ lemma conj_transpose_col [has_star α] (v : m → α) : (col v)ᴴ = row (star v @[simp] lemma conj_transpose_row [has_star α] (v : m → α) : (row v)ᴴ = col (star v) := by { ext, refl } -lemma row_vec_mul [fintype m] [semiring α] (M : matrix m n α) (v : m → α) : +lemma row_vec_mul [fintype m] [non_unital_non_assoc_semiring α] (M : matrix m n α) (v : m → α) : matrix.row (matrix.vec_mul v M) = matrix.row v ⬝ M := by {ext, refl} -lemma col_vec_mul [fintype m] [semiring α] (M : matrix m n α) (v : m → α) : +lemma col_vec_mul [fintype m] [non_unital_non_assoc_semiring α] (M : matrix m n α) (v : m → α) : matrix.col (matrix.vec_mul v M) = (matrix.row v ⬝ M)ᵀ := by {ext, refl} -lemma col_mul_vec [fintype n] [semiring α] (M : matrix m n α) (v : n → α) : +lemma col_mul_vec [fintype n] [non_unital_non_assoc_semiring α] (M : matrix m n α) (v : n → α) : matrix.col (matrix.mul_vec M v) = M ⬝ matrix.col v := by {ext, refl} -lemma row_mul_vec [fintype n] [semiring α] (M : matrix m n α) (v : n → α) : +lemma row_mul_vec [fintype n] [non_unital_non_assoc_semiring α] (M : matrix m n α) (v : n → α) : matrix.row (matrix.mul_vec M v) = (M ⬝ matrix.col v)ᵀ := by {ext, refl} @[simp] @@ -1695,22 +1706,22 @@ end update end matrix namespace ring_hom -variables [fintype n] [semiring α] [semiring β] +variables [fintype n] [non_assoc_semiring α] [non_assoc_semiring β] lemma map_matrix_mul (M : matrix m n α) (N : matrix n o α) (i : m) (j : o) (f : α →+* β) : f (matrix.mul M N i j) = matrix.mul (λ i j, f (M i j)) (λ i j, f (N i j)) i j := by simp [matrix.mul_apply, ring_hom.map_sum] -lemma map_dot_product [semiring R] [semiring S] (f : R →+* S) (v w : n → R) : +lemma map_dot_product [non_assoc_semiring R] [non_assoc_semiring S] (f : R →+* S) (v w : n → R) : f (v ⬝ᵥ w) = (f ∘ v) ⬝ᵥ (f ∘ w) := by simp only [matrix.dot_product, f.map_sum, f.map_mul] -lemma map_vec_mul [semiring R] [semiring S] +lemma map_vec_mul [non_assoc_semiring R] [non_assoc_semiring S] (f : R →+* S) (M : matrix n m R) (v : n → R) (i : m) : f (M.vec_mul v i) = ((M.map f).vec_mul (f ∘ v) i) := by simp only [matrix.vec_mul, matrix.map_apply, ring_hom.map_dot_product] -lemma map_mul_vec [semiring R] [semiring S] +lemma map_mul_vec [non_assoc_semiring R] [non_assoc_semiring S] (f : R →+* S) (M : matrix m n R) (v : n → R) (i : m) : f (M.mul_vec v i) = ((M.map f).mul_vec (f ∘ v) i) := by simp only [matrix.mul_vec, matrix.map_apply, ring_hom.map_dot_product] From 91b8084223bbe94b73903ef9a039e3cc1e19ce25 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 25 Apr 2022 06:23:55 +0000 Subject: [PATCH 224/373] chore(analysis/normed_space/finite_dimension): extract some lemmas from existentials (#13600) A few proofs in this file prove an existential where a stronger statement in terms of the witness exists. This: * Removes `basis.sup_norm_le_norm` and replaces it with the more general statement `pi.sum_norm_apply_le_norm` * Renames `basis.op_norm_le` to `basis.exists_op_norm_le` * Creates a new `basis.op_norm_le` stated without the existential * Adds the `nnnorm` version of some `norm` lemmas. In some cases it's easier to prove these first, and derive the `norm` versions from them. --- src/analysis/normed/group/basic.lean | 13 ++++ .../normed_space/finite_dimension.lean | 67 ++++++++++--------- src/analysis/normed_space/operator_norm.lean | 17 +++++ 3 files changed, 64 insertions(+), 33 deletions(-) diff --git a/src/analysis/normed/group/basic.lean b/src/analysis/normed/group/basic.lean index 9b53dece7ca9e..00a094416dda8 100644 --- a/src/analysis/normed/group/basic.lean +++ b/src/analysis/normed/group/basic.lean @@ -812,6 +812,19 @@ by simpa only [← dist_zero_right] using dist_pi_const a 0 ∥(λ i : ι, a)∥₊ = ∥a∥₊ := nnreal.eq $ pi_norm_const a +/-- The $L^1$ norm is less than the $L^\infty$ norm scaled by the cardinality. -/ +lemma pi.sum_norm_apply_le_norm {π : ι → Type*} [fintype ι] [∀i, semi_normed_group (π i)] + (x : Π i, π i) : + ∑ i, ∥x i∥ ≤ fintype.card ι • ∥x∥ := +calc ∑ i, ∥x i∥ ≤ ∑ i : ι, ∥x∥ : finset.sum_le_sum $ λ i hi, norm_le_pi_norm x i + ... = fintype.card ι • ∥x∥ : finset.sum_const _ + +/-- The $L^1$ norm is less than the $L^\infty$ norm scaled by the cardinality. -/ +lemma pi.sum_nnnorm_apply_le_nnnorm {π : ι → Type*} [fintype ι] [∀i, semi_normed_group (π i)] + (x : Π i, π i) : + ∑ i, ∥x i∥₊ ≤ fintype.card ι • ∥x∥₊ := +nnreal.coe_sum.trans_le $ pi.sum_norm_apply_le_norm x + lemma tendsto_iff_norm_tendsto_zero {f : α → E} {a : filter α} {b : E} : tendsto f a (𝓝 b) ↔ tendsto (λ e, ∥f e - b∥) a (𝓝 0) := by { convert tendsto_iff_dist_tendsto_zero, simp [dist_eq_norm] } diff --git a/src/analysis/normed_space/finite_dimension.lean b/src/analysis/normed_space/finite_dimension.lean index 129d90e397e82..7b5bb0b2f5906 100644 --- a/src/analysis/normed_space/finite_dimension.lean +++ b/src/analysis/normed_space/finite_dimension.lean @@ -506,42 +506,43 @@ v.constr_apply_fintype 𝕜 _ _ (v.constrL f) (v i) = f i := v.constr_basis 𝕜 _ _ -lemma basis.sup_norm_le_norm (v : basis ι 𝕜 E) : - ∃ C > (0 : ℝ), ∀ e : E, ∑ i, ∥v.equiv_fun e i∥ ≤ C * ∥e∥ := -begin +lemma basis.op_nnnorm_le {ι : Type*} [fintype ι] (v : basis ι 𝕜 E) {u : E →L[𝕜] F} (M : ℝ≥0) + (hu : ∀ i, ∥u (v i)∥₊ ≤ M) : + ∥u∥₊ ≤ fintype.card ι • ∥v.equiv_funL.to_continuous_linear_map∥₊ * M := +u.op_nnnorm_le_bound _ $ λ e, begin set φ := v.equiv_funL.to_continuous_linear_map, - set C := ∥φ∥ * (fintype.card ι), - use [max C 1, lt_of_lt_of_le (zero_lt_one) (le_max_right C 1)], - intros e, - calc ∑ i, ∥φ e i∥ ≤ ∑ i : ι, ∥φ e∥ : by { apply finset.sum_le_sum, - exact λ i hi, norm_le_pi_norm (φ e) i } - ... = ∥φ e∥*(fintype.card ι) : by simpa only [mul_comm, finset.sum_const, nsmul_eq_mul] - ... ≤ ∥φ∥ * ∥e∥ * (fintype.card ι) : mul_le_mul_of_nonneg_right (φ.le_op_norm e) - (fintype.card ι).cast_nonneg - ... = ∥φ∥ * (fintype.card ι) * ∥e∥ : by ring - ... ≤ max C 1 * ∥e∥ : mul_le_mul_of_nonneg_right (le_max_left _ _) (norm_nonneg _) + calc + ∥u e∥₊ = ∥u (∑ i, v.equiv_fun e i • v i)∥₊ : by rw [v.sum_equiv_fun] + ... = ∥∑ i, (v.equiv_fun e i) • (u $ v i)∥₊ : by simp [u.map_sum, linear_map.map_smul] + ... ≤ ∑ i, ∥(v.equiv_fun e i) • (u $ v i)∥₊ : nnnorm_sum_le _ _ + ... = ∑ i, ∥v.equiv_fun e i∥₊ * ∥u (v i)∥₊ : by simp only [nnnorm_smul] + ... ≤ ∑ i, ∥v.equiv_fun e i∥₊ * M : finset.sum_le_sum (λ i hi, + mul_le_mul_of_nonneg_left (hu i) (zero_le _)) + ... = (∑ i, ∥v.equiv_fun e i∥₊) * M : finset.sum_mul.symm + ... ≤ fintype.card ι • (∥φ∥₊ * ∥e∥₊) * M : + (suffices _, from mul_le_mul_of_nonneg_right this (zero_le M), + calc ∑ i, ∥v.equiv_fun e i∥₊ + ≤ fintype.card ι • ∥φ e∥₊ : pi.sum_nnnorm_apply_le_nnnorm _ + ... ≤ fintype.card ι • (∥φ∥₊ * ∥e∥₊) : nsmul_le_nsmul_of_le_right (φ.le_op_nnnorm e) _) + ... = fintype.card ι • ∥φ∥₊ * M * ∥e∥₊ : by simp only [smul_mul_assoc, mul_right_comm], end -lemma basis.op_norm_le {ι : Type*} [fintype ι] (v : basis ι 𝕜 E) : +lemma basis.op_norm_le {ι : Type*} [fintype ι] (v : basis ι 𝕜 E) {u : E →L[𝕜] F} {M : ℝ} + (hM : 0 ≤ M) (hu : ∀ i, ∥u (v i)∥ ≤ M) : + ∥u∥ ≤ fintype.card ι • ∥v.equiv_funL.to_continuous_linear_map∥ * M := +by simpa using nnreal.coe_le_coe.mpr (v.op_nnnorm_le ⟨M, hM⟩ hu) + +/-- A weaker version of `basis.op_nnnorm_le` that abstracts away the value of `C`. -/ +lemma basis.exists_op_nnnorm_le {ι : Type*} [fintype ι] (v : basis ι 𝕜 E) : + ∃ C > (0 : ℝ≥0), ∀ {u : E →L[𝕜] F} (M : ℝ≥0), (∀ i, ∥u (v i)∥₊ ≤ M) → ∥u∥₊ ≤ C*M := +⟨ max (fintype.card ι • ∥v.equiv_funL.to_continuous_linear_map∥₊) 1, + zero_lt_one.trans_le (le_max_right _ _), + λ u M hu, (v.op_nnnorm_le M hu).trans $ mul_le_mul_of_nonneg_right (le_max_left _ _) (zero_le M)⟩ + +/-- A weaker version of `basis.op_norm_le` that abstracts away the value of `C`. -/ +lemma basis.exists_op_norm_le {ι : Type*} [fintype ι] (v : basis ι 𝕜 E) : ∃ C > (0 : ℝ), ∀ {u : E →L[𝕜] F} {M : ℝ}, 0 ≤ M → (∀ i, ∥u (v i)∥ ≤ M) → ∥u∥ ≤ C*M := -begin - obtain ⟨C, C_pos, hC⟩ : ∃ C > (0 : ℝ), ∀ (e : E), ∑ i, ∥v.equiv_fun e i∥ ≤ C * ∥e∥, - from v.sup_norm_le_norm, - use [C, C_pos], - intros u M hM hu, - apply u.op_norm_le_bound (mul_nonneg (le_of_lt C_pos) hM), - intros e, - calc - ∥u e∥ = ∥u (∑ i, v.equiv_fun e i • v i)∥ : by rw [v.sum_equiv_fun] - ... = ∥∑ i, (v.equiv_fun e i) • (u $ v i)∥ : by simp [u.map_sum, linear_map.map_smul] - ... ≤ ∑ i, ∥(v.equiv_fun e i) • (u $ v i)∥ : norm_sum_le _ _ - ... = ∑ i, ∥v.equiv_fun e i∥ * ∥u (v i)∥ : by simp only [norm_smul] - ... ≤ ∑ i, ∥v.equiv_fun e i∥ * M : finset.sum_le_sum (λ i hi, - mul_le_mul_of_nonneg_left (hu i) (norm_nonneg _)) - ... = (∑ i, ∥v.equiv_fun e i∥) * M : finset.sum_mul.symm - ... ≤ C * ∥e∥ * M : mul_le_mul_of_nonneg_right (hC e) hM - ... = C * M * ∥e∥ : by ring -end +let ⟨C, hC, h⟩ := v.exists_op_nnnorm_le in ⟨C, hC, λ u, subtype.forall'.mpr h⟩ instance [finite_dimensional 𝕜 E] [second_countable_topology F] : second_countable_topology (E →L[𝕜] F) := @@ -556,7 +557,7 @@ begin let v := finite_dimensional.fin_basis 𝕜 E, obtain ⟨C : ℝ, C_pos : 0 < C, hC : ∀ {φ : E →L[𝕜] F} {M : ℝ}, 0 ≤ M → (∀ i, ∥φ (v i)∥ ≤ M) → ∥φ∥ ≤ C * M⟩ := - v.op_norm_le, + v.exists_op_norm_le, have h_2C : 0 < 2*C := mul_pos zero_lt_two C_pos, have hε2C : 0 < ε/(2*C) := div_pos ε_pos h_2C, have : ∀ φ : E →L[𝕜] F, ∃ n : fin d → ℕ, ∥φ - (v.constrL $ u ∘ n)∥ ≤ ε/2, diff --git a/src/analysis/normed_space/operator_norm.lean b/src/analysis/normed_space/operator_norm.lean index 2cc99c0cc9cd5..032ef50f35ea3 100644 --- a/src/analysis/normed_space/operator_norm.lean +++ b/src/analysis/normed_space/operator_norm.lean @@ -402,6 +402,20 @@ begin exists_prop], end +/-- If one controls the norm of every `A x`, then one controls the norm of `A`. -/ +lemma op_nnnorm_le_bound (f : E →SL[σ₁₂] F) (M : ℝ≥0) (hM : ∀ x, ∥f x∥₊ ≤ M * ∥x∥₊) : + ∥f∥₊ ≤ M := +op_norm_le_bound f (zero_le M) hM + +theorem op_nnnorm_le_of_lipschitz {f : E →SL[σ₁₂] F} {K : ℝ≥0} (hf : lipschitz_with K f) : + ∥f∥₊ ≤ K := +op_norm_le_of_lipschitz hf + +lemma op_nnnorm_eq_of_bounds {φ : E →SL[σ₁₂] F} (M : ℝ≥0) + (h_above : ∀ x, ∥φ x∥ ≤ M*∥x∥) (h_below : ∀ N, (∀ x, ∥φ x∥₊ ≤ N*∥x∥₊) → M ≤ N) : + ∥φ∥₊ = M := +subtype.ext $ op_norm_eq_of_bounds (zero_le M) h_above $ subtype.forall'.mpr h_below + instance to_normed_space {𝕜' : Type*} [normed_field 𝕜'] [normed_space 𝕜' F] [smul_comm_class 𝕜₂ 𝕜' F] : normed_space 𝕜' (E →SL[σ₁₂] F) := ⟨op_norm_smul_le⟩ @@ -470,6 +484,9 @@ le_antisymm (op_norm_le_bound _ (norm_nonneg _) $ λ x, (le_max_left _ _).trans ((f.prod g).le_op_norm x)) (op_norm_le_bound _ (norm_nonneg _) $ λ x, (le_max_right _ _).trans ((f.prod g).le_op_norm x)) +@[simp] lemma op_nnnorm_prod (f : E →L[𝕜] Fₗ) (g : E →L[𝕜] Gₗ) : ∥f.prod g∥₊ = ∥(f, g)∥₊ := +subtype.ext $ op_norm_prod f g + /-- `continuous_linear_map.prod` as a `linear_isometry_equiv`. -/ def prodₗᵢ (R : Type*) [semiring R] [module R Fₗ] [module R Gₗ] [has_continuous_const_smul R Fₗ] [has_continuous_const_smul R Gₗ] From b6c8c0d4fe150505510fc20bd5a18e1bed1da487 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 25 Apr 2022 06:23:56 +0000 Subject: [PATCH 225/373] refactor(linear_algebra/quotient): Use the same quotient relation as add_subgroup (#13620) This means that the quotient by `p` and `p.to_add_subgroup` are defeq as types, and the instances defined on them are defeq too. This removes a TODO comment by Mario; I can only assume it resolves it in the right direction --- src/algebra/char_p/quotient.lean | 2 +- src/algebra/lie/quotient.lean | 1 + src/algebra/module/torsion.lean | 3 +- src/algebra/ring_quot.lean | 2 +- .../invariant_basis_number.lean | 1 + src/linear_algebra/quotient.lean | 65 +++++-------------- src/ring_theory/ideal/operations.lean | 2 +- src/ring_theory/ideal/quotient.lean | 14 ++-- src/ring_theory/valuation/basic.lean | 11 +--- src/topology/algebra/uniform_ring.lean | 6 +- 10 files changed, 38 insertions(+), 69 deletions(-) diff --git a/src/algebra/char_p/quotient.lean b/src/algebra/char_p/quotient.lean index 286bada40ccd0..12b4c9e2c689b 100644 --- a/src/algebra/char_p/quotient.lean +++ b/src/algebra/char_p/quotient.lean @@ -31,7 +31,7 @@ lemma quotient' {R : Type*} [comm_ring R] (p : ℕ) [char_p R p] (I : ideal R) char_p (R ⧸ I) p := ⟨λ x, begin rw [←cast_eq_zero_iff R p x, ←map_nat_cast (ideal.quotient.mk I)], - refine quotient.eq'.trans (_ : ↑x - 0 ∈ I ↔ _), + refine ideal.quotient.eq.trans (_ : ↑x - 0 ∈ I ↔ _), rw sub_zero, exact ⟨h x, λ h', h'.symm ▸ I.zero_mem⟩, end⟩ diff --git a/src/algebra/lie/quotient.lean b/src/algebra/lie/quotient.lean index 92feb25377bfb..fd47a97283820 100644 --- a/src/algebra/lie/quotient.lean +++ b/src/algebra/lie/quotient.lean @@ -102,6 +102,7 @@ instance lie_quotient_has_bracket : has_bracket (L ⧸ I) (L ⧸ I) := apply quotient.lift_on₂' x y (λ x' y', mk ⁅x', y'⁆), intros x₁ x₂ y₁ y₂ h₁ h₂, apply (submodule.quotient.eq I.to_submodule).2, + rw submodule.quotient_rel_r_def at h₁ h₂, have h : ⁅x₁, x₂⁆ - ⁅y₁, y₂⁆ = ⁅x₁, x₂ - y₂⁆ + ⁅x₁ - y₁, y₂⁆, by simp [-lie_skew, sub_eq_add_neg, add_assoc], rw h, diff --git a/src/algebra/module/torsion.lean b/src/algebra/module/torsion.lean index 7be257d703460..e3883d9291d2c 100644 --- a/src/algebra/module/torsion.lean +++ b/src/algebra/module/torsion.lean @@ -124,7 +124,8 @@ section quotient variables [comm_ring R] [add_comm_group M] [module R M] (a : R) instance : has_scalar (R ⧸ R ∙ a) (torsion_by R M a) := -{ smul := λ b x, quotient.lift_on' b (• x) $ λ b₁ b₂ (h : b₁ - b₂ ∈ _), begin +{ smul := λ b x, quotient.lift_on' b (• x) $ λ b₁ b₂ h, begin + rw submodule.quotient_rel_r_def at h, show b₁ • x = b₂ • x, obtain ⟨c, h⟩ := ideal.mem_span_singleton'.mp h, rw [← sub_eq_zero, ← sub_smul, ← h, mul_smul, smul_torsion_by, smul_zero], diff --git a/src/algebra/ring_quot.lean b/src/algebra/ring_quot.lean index acbeb6722c3ee..707b36502dd67 100644 --- a/src/algebra/ring_quot.lean +++ b/src/algebra/ring_quot.lean @@ -232,7 +232,7 @@ def ring_quot_to_ideal_quotient (r : B → B → Prop) : ring_quot r →+* B ⧸ ideal.of_rel r := lift ⟨ideal.quotient.mk (ideal.of_rel r), - λ x y h, quot.sound (submodule.mem_Inf.mpr (λ p w, w ⟨x, y, h, sub_add_cancel x y⟩))⟩ + λ x y h, ideal.quotient.eq.2 $ submodule.mem_Inf.mpr (λ p w, w ⟨x, y, h, sub_add_cancel x y⟩)⟩ @[simp] lemma ring_quot_to_ideal_quotient_apply (r : B → B → Prop) (x : B) : ring_quot_to_ideal_quotient r (mk_ring_hom r x) = ideal.quotient.mk _ x := rfl diff --git a/src/linear_algebra/invariant_basis_number.lean b/src/linear_algebra/invariant_basis_number.lean index d92e838b12857..8662cb7fb0912 100644 --- a/src/linear_algebra/invariant_basis_number.lean +++ b/src/linear_algebra/invariant_basis_number.lean @@ -240,6 +240,7 @@ private def induced_map (I : ideal R) (e : (ι → R) →ₗ[R] (ι' → R)) : λ x, quotient.lift_on' x (λ y, ideal.quotient.mk _ (e y)) begin refine λ a b hab, ideal.quotient.eq.2 (λ h, _), + rw submodule.quotient_rel_r_def at hab, rw ←linear_map.map_sub, exact ideal.map_pi _ _ hab e h, end diff --git a/src/linear_algebra/quotient.lean b/src/linear_algebra/quotient.lean index feaeb98a38221..2cc88bc86ad98 100644 --- a/src/linear_algebra/quotient.lean +++ b/src/linear_algebra/quotient.lean @@ -23,12 +23,15 @@ variables (p p' : submodule R M) open linear_map --- TODO(Mario): Factor through add_subgroup -/-- The equivalence relation associated to a submodule `p`, defined by `x ≈ y` iff `y - x ∈ p`. -/ +/-- The equivalence relation associated to a submodule `p`, defined by `x ≈ y` iff `-x + y ∈ p`. + +Note this is equivalent to `y - x ∈ p`, but defined this way to be be defeq to the `add_subgroup` +version, where commutativity can't be assumed. -/ def quotient_rel : setoid M := -⟨λ x y, x - y ∈ p, λ x, by simp, - λ x y h, by simpa using neg_mem h, - λ x y z h₁ h₂, by simpa [sub_eq_add_neg, add_left_comm, add_assoc] using add_mem h₁ h₂⟩ +quotient_add_group.left_rel p.to_add_subgroup + +lemma quotient_rel_r_def {x y : M} : @setoid.r _ (p.quotient_rel) x y ↔ x - y ∈ p := +iff.trans (by { rw [sub_eq_add_neg, neg_add, neg_neg], refl }) neg_mem_iff /-- The quotient of a module `M` by a submodule `p ⊆ M`. -/ instance has_quotient : has_quotient M (submodule R M) := ⟨λ p, quotient (quotient_rel p)⟩ @@ -44,7 +47,10 @@ def mk {p : submodule R M} : M → M ⧸ p := quotient.mk' @[simp] theorem mk'_eq_mk {p : submodule R M} (x : M) : (quotient.mk' x : M ⧸ p) = mk x := rfl @[simp] theorem quot_mk_eq_mk {p : submodule R M} (x : M) : (quot.mk _ x : M ⧸ p) = mk x := rfl -protected theorem eq {x y : M} : (mk x : M ⧸ p) = mk y ↔ x - y ∈ p := quotient.eq' +protected theorem eq' {x y : M} : (mk x : M ⧸ p) = mk y ↔ -x + y ∈ p := quotient.eq' + +protected theorem eq {x y : M} : (mk x : M ⧸ p) = mk y ↔ x - y ∈ p := +(p^.quotient.eq').trans p.quotient_rel_r_def instance : has_zero (M ⧸ p) := ⟨mk 0⟩ instance : inhabited (M ⧸ p) := ⟨0⟩ @@ -54,52 +60,15 @@ instance : inhabited (M ⧸ p) := ⟨0⟩ @[simp] theorem mk_eq_zero : (mk x : M ⧸ p) = 0 ↔ x ∈ p := by simpa using (quotient.eq p : mk x = 0 ↔ _) -instance : has_add (M ⧸ p) := -⟨λ a b, quotient.lift_on₂' a b (λ a b, mk (a + b)) $ - λ a₁ a₂ b₁ b₂ h₁ h₂, (quotient.eq p).2 $ - by simpa [sub_eq_add_neg, add_left_comm, add_comm] using add_mem h₁ h₂⟩ +instance add_comm_group : add_comm_group (M ⧸ p) := +quotient_add_group.add_comm_group p.to_add_subgroup @[simp] theorem mk_add : (mk (x + y) : M ⧸ p) = mk x + mk y := rfl -instance : has_neg (M ⧸ p) := -⟨λ a, quotient.lift_on' a (λ a, mk (-a)) $ - λ a b h, (quotient.eq p).2 $ by simpa using neg_mem h⟩ - @[simp] theorem mk_neg : (mk (-x) : M ⧸ p) = -mk x := rfl -instance : has_sub (M ⧸ p) := -⟨λ a b, quotient.lift_on₂' a b (λ a b, mk (a - b)) $ - λ a₁ a₂ b₁ b₂ h₁ h₂, (quotient.eq p).2 $ - by simpa [sub_eq_add_neg, add_left_comm, add_comm] using add_mem h₁ (neg_mem h₂)⟩ - @[simp] theorem mk_sub : (mk (x - y) : M ⧸ p) = mk x - mk y := rfl -instance add_comm_group : add_comm_group (M ⧸ p) := -{ zero := (0 : M ⧸ p), - add := (+), - neg := has_neg.neg, - sub := has_sub.sub, - add_assoc := by { rintros ⟨x⟩ ⟨y⟩ ⟨z⟩, simp only [←mk_add p, quot_mk_eq_mk, add_assoc] }, - zero_add := by { rintro ⟨x⟩, simp only [←mk_zero p, ←mk_add p, quot_mk_eq_mk, zero_add] }, - add_zero := by { rintro ⟨x⟩, simp only [←mk_zero p, ←mk_add p, add_zero, quot_mk_eq_mk] }, - add_comm := by { rintros ⟨x⟩ ⟨y⟩, simp only [←mk_add p, quot_mk_eq_mk, add_comm] }, - add_left_neg := by { rintro ⟨x⟩, - simp only [←mk_zero p, ←mk_add p, ←mk_neg p, quot_mk_eq_mk, add_left_neg] }, - sub_eq_add_neg := by { rintros ⟨x⟩ ⟨y⟩, - simp only [←mk_add p, ←mk_neg p, ←mk_sub p, sub_eq_add_neg, quot_mk_eq_mk] }, - nsmul := λ n x, quotient.lift_on' x (λ x, mk (n • x)) $ - λ x y h, (quotient.eq p).2 $ by simpa [smul_sub] using smul_of_tower_mem p n h, - nsmul_zero' := by { rintros ⟨⟩, simp only [mk_zero, quot_mk_eq_mk, zero_smul], refl }, - nsmul_succ' := by { rintros n ⟨⟩, - simp only [nat.succ_eq_one_add, add_nsmul, mk_add, quot_mk_eq_mk, one_nsmul], refl }, - zsmul := λ n x, quotient.lift_on' x (λ x, mk (n • x)) $ - λ x y h, (quotient.eq p).2 $ by simpa [smul_sub] using smul_of_tower_mem p n h, - zsmul_zero' := by { rintros ⟨⟩, simp only [mk_zero, quot_mk_eq_mk, zero_smul], refl }, - zsmul_succ' := by { rintros n ⟨⟩, - simp [nat.succ_eq_add_one, add_nsmul, mk_add, quot_mk_eq_mk, one_nsmul, add_smul, add_comm], - refl }, - zsmul_neg' := by { rintros n ⟨x⟩, simp_rw [zsmul_neg_succ_of_nat, coe_nat_zsmul], refl }, } - section has_scalar variables {S : Type*} [has_scalar S R] [has_scalar S M] [is_scalar_tower S R M] (P : submodule R M) @@ -221,10 +190,8 @@ linear_map.ext $ λ x, quotient.induction_on' x $ (linear_map.congr_fun h : _) /-- The map from the quotient of `M` by a submodule `p` to `M₂` induced by a linear map `f : M → M₂` vanishing on `p`, as a linear map. -/ def liftq (f : M →ₛₗ[τ₁₂] M₂) (h : p ≤ f.ker) : M ⧸ p →ₛₗ[τ₁₂] M₂ := -{ to_fun := λ x, _root_.quotient.lift_on' x f $ - λ a b (ab : a - b ∈ p), eq_of_sub_eq_zero $ by simpa using h ab, - map_add' := by rintro ⟨x⟩ ⟨y⟩; exact f.map_add x y, - map_smul' := by rintro a ⟨x⟩; exact f.map_smulₛₗ a x } +{ map_smul' := by rintro a ⟨x⟩; exact f.map_smulₛₗ a x, + ..quotient_add_group.lift p.to_add_subgroup f.to_add_monoid_hom h } @[simp] theorem liftq_apply (f : M →ₛₗ[τ₁₂] M₂) {h} (x : M) : p.liftq f h (quotient.mk x) = f x := rfl diff --git a/src/ring_theory/ideal/operations.lean b/src/ring_theory/ideal/operations.lean index ceb0517b0c1b5..54a445ca08fa1 100644 --- a/src/ring_theory/ideal/operations.lean +++ b/src/ring_theory/ideal/operations.lean @@ -1391,7 +1391,7 @@ ideal.quotient.lift_mk _ _ _ /-- The induced map from the quotient by the kernel is injective. -/ lemma ker_lift_injective (f : R →+* S) : function.injective (ker_lift f) := assume a b, quotient.induction_on₂' a b $ - assume a b (h : f a = f b), quotient.sound' $ + assume a b (h : f a = f b), ideal.quotient.eq.2 $ show a - b ∈ ker f, by rw [mem_ker, map_sub, h, sub_self] variable {f} diff --git a/src/ring_theory/ideal/quotient.lean b/src/ring_theory/ideal/quotient.lean index 77ba2c15429e9..f2e732ba00571 100644 --- a/src/ring_theory/ideal/quotient.lean +++ b/src/ring_theory/ideal/quotient.lean @@ -52,6 +52,7 @@ instance has_one (I : ideal R) : has_one (R ⧸ I) := ⟨submodule.quotient.mk 1 instance has_mul (I : ideal R) : has_mul (R ⧸ I) := ⟨λ a b, quotient.lift_on₂' a b (λ a b, submodule.quotient.mk (a * b)) $ λ a₁ a₂ b₁ b₂ h₁ h₂, quot.sound $ begin + rw submodule.quotient_rel_r_def at h₁ h₂ ⊢, have F := I.add_mem (I.mul_mem_left a₂ h₁) (I.mul_mem_right b₁ h₂), have : a₁ * a₂ - b₁ * b₂ = a₂ * (a₁ - b₁) + (a₂ - b₂) * b₁, { rw [mul_sub, sub_mul, sub_add_sub_cancel, mul_comm, mul_comm b₁] }, @@ -96,7 +97,7 @@ protected theorem eq : mk I x = mk I y ↔ x - y ∈ I := submodule.quotient.eq @[simp] theorem mk_eq_mk (x : R) : (submodule.quotient.mk x : R ⧸ I) = mk I x := rfl lemma eq_zero_iff_mem {I : ideal R} : mk I a = 0 ↔ a ∈ I := -by conv {to_rhs, rw ← sub_zero a }; exact quotient.eq' +submodule.quotient.mk_eq_zero _ theorem zero_eq_one_iff {I : ideal R} : (0 : R ⧸ I) = 1 ↔ I = ⊤ := eq_comm.trans $ eq_zero_iff_mem.trans (eq_top_iff_one _).symm @@ -151,6 +152,7 @@ begin refine ⟨mk _ b, quot.sound _⟩, --quot.sound hb rw ← eq_sub_iff_add_eq' at abc, rw [abc, ← neg_mem_iff, neg_sub] at hc, + rw submodule.quotient_rel_r_def, convert hc, end @@ -196,12 +198,11 @@ variable [comm_ring S] lift it to the quotient by this ideal. -/ def lift (I : ideal R) (f : R →+* S) (H : ∀ (a : R), a ∈ I → f a = 0) : R ⧸ I →+* S := -{ to_fun := λ x, quotient.lift_on' x f $ λ (a b) (h : _ ∈ _), - eq_of_sub_eq_zero $ by rw [← f.map_sub, H _ h], - map_one' := f.map_one, +{ map_one' := f.map_one, map_zero' := f.map_zero, map_add' := λ a₁ a₂, quotient.induction_on₂' a₁ a₂ f.map_add, - map_mul' := λ a₁ a₂, quotient.induction_on₂' a₁ a₂ f.map_mul } + map_mul' := λ a₁ a₂, quotient.induction_on₂' a₁ a₂ f.map_mul, + .. quotient_add_group.lift I.to_add_subgroup f.to_add_monoid_hom H } @[simp] lemma lift_mk (I : ideal R) (f : R →+* S) (H : ∀ (a : R), a ∈ I → f a = 0) : lift I f H (mk I a) = f a := rfl @@ -242,6 +243,7 @@ instance module_pi : module (R ⧸ I) ((ι → R) ⧸ I.pi ι) := { smul := λ c m, quotient.lift_on₂' c m (λ r m, submodule.quotient.mk $ r • m) begin intros c₁ m₁ c₂ m₂ hc hm, apply ideal.quotient.eq.2, + rw submodule.quotient_rel_r_def at hc hm, intro i, exact I.mul_sub_mul_mem hc (hm i), end, @@ -280,7 +282,7 @@ instance module_pi : module (R ⧸ I) ((ι → R) ⧸ I.pi ι) := /-- `R^n/I^n` is isomorphic to `(R/I)^n` as an `R/I`-module. -/ noncomputable def pi_quot_equiv : ((ι → R) ⧸ I.pi ι) ≃ₗ[(R ⧸ I)] (ι → (R ⧸ I)) := { to_fun := λ x, quotient.lift_on' x (λ f i, ideal.quotient.mk I (f i)) $ - λ a b hab, funext (λ i, ideal.quotient.eq.2 (hab i)), + λ a b hab, funext (λ i, (submodule.quotient.eq' _).2 (hab i)), map_add' := by { rintros ⟨_⟩ ⟨_⟩, refl }, map_smul' := by { rintros ⟨_⟩ ⟨_⟩, refl }, inv_fun := λ x, ideal.quotient.mk (I.pi ι) $ λ i, quotient.out' (x i), diff --git a/src/ring_theory/valuation/basic.lean b/src/ring_theory/valuation/basic.lean index 337e8ce5db624..db6116e59e3ad 100644 --- a/src/ring_theory/valuation/basic.lean +++ b/src/ring_theory/valuation/basic.lean @@ -391,8 +391,8 @@ Note: it's just the function; the valuation is `on_quot hJ`. -/ def on_quot_val {J : ideal R} (hJ : J ≤ supp v) : R ⧸ J → Γ₀ := λ q, quotient.lift_on' q v $ λ a b h, -calc v a = v (b + (a - b)) : by simp - ... = v b : v.map_add_supp b (hJ h) +calc v a = v (b + -(-a + b)) : by simp + ... = v b : v.map_add_supp b ((ideal.neg_mem_iff _).2 $ hJ h) /-- The extension of valuation v on R to valuation on R/J if J ⊆ supp v -/ def on_quot {J : ideal R} (hJ : J ≤ supp v) : @@ -405,12 +405,7 @@ def on_quot {J : ideal R} (hJ : J ≤ supp v) : @[simp] lemma on_quot_comap_eq {J : ideal R} (hJ : J ≤ supp v) : (v.on_quot hJ).comap (ideal.quotient.mk J) = v := -ext $ λ r, -begin - refine @quotient.lift_on_mk _ _ (J.quotient_rel) v (λ a b h, _) _, - calc v a = v (b + (a - b)) : by simp - ... = v b : v.map_add_supp b (hJ h) -end +ext $ λ r, rfl lemma comap_supp {S : Type*} [comm_ring S] (f : S →+* R) : supp (v.comap f) = ideal.comap f v.supp := diff --git a/src/topology/algebra/uniform_ring.lean b/src/topology/algebra/uniform_ring.lean index cf0cee58ac973..680104806aed5 100644 --- a/src/topology/algebra/uniform_ring.lean +++ b/src/topology/algebra/uniform_ring.lean @@ -157,7 +157,8 @@ namespace uniform_space variables {α : Type*} lemma ring_sep_rel (α) [comm_ring α] [uniform_space α] [uniform_add_group α] [topological_ring α] : separation_setoid α = submodule.quotient_rel (ideal.closure ⊥) := -setoid.ext $ assume x y, add_group_separation_rel x y +setoid.ext $ λ x y, (add_group_separation_rel x y).trans $ + iff.trans (by refl) (submodule.quotient_rel_r_def _).symm lemma ring_sep_quot (α : Type u) [r : comm_ring α] [uniform_space α] [uniform_add_group α] [topological_ring α] : @@ -170,7 +171,8 @@ corresponding to the closure of zero. -/ def sep_quot_equiv_ring_quot (α) [r : comm_ring α] [uniform_space α] [uniform_add_group α] [topological_ring α] : quotient (separation_setoid α) ≃ (α ⧸ (⊥ : ideal α).closure) := -quotient.congr_right $ assume x y, add_group_separation_rel x y +quotient.congr_right $ λ x y, (add_group_separation_rel x y).trans $ + iff.trans (by refl) (submodule.quotient_rel_r_def _).symm /- TODO: use a form of transport a.k.a. lift definition a.k.a. transfer -/ instance comm_ring [comm_ring α] [uniform_space α] [uniform_add_group α] [topological_ring α] : From 6cbf986ae623082ef27fb40106679fc6f68605d9 Mon Sep 17 00:00:00 2001 From: tb65536 Date: Mon, 25 Apr 2022 06:23:57 +0000 Subject: [PATCH 226/373] refactor(group_theory/schur_zassenhaus): Golf proof of abelian case (#13622) This PR golfs the proof of the abelian case of Schur-Zassenhaus by switching from a nonstandard definition of the difference of two left transversals to the definition used in `transfer.lean`. --- src/group_theory/schur_zassenhaus.lean | 143 ++++++++++--------------- 1 file changed, 56 insertions(+), 87 deletions(-) diff --git a/src/group_theory/schur_zassenhaus.lean b/src/group_theory/schur_zassenhaus.lean index 638fbc71d6a70..7810c3ef324b0 100644 --- a/src/group_theory/schur_zassenhaus.lean +++ b/src/group_theory/schur_zassenhaus.lean @@ -4,9 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Thomas Browning -/ -import group_theory.complement -import group_theory.group_action.basic import group_theory.sylow +import group_theory.transfer /-! # The Schur-Zassenhaus Theorem @@ -29,110 +28,80 @@ namespace subgroup section schur_zassenhaus_abelian -open mem_left_transversals +open mul_opposite mul_action subgroup.left_transversals mem_left_transversals -variables {G : Type*} [group G] {H : subgroup G} +variables {G : Type*} [group G] (H : subgroup G) [is_commutative H] [fintype (G ⧸ H)] + (α β : left_transversals (H : set G)) -variables [is_commutative H] [fintype (G ⧸ H)] +/-- The quotient of the transversals of an abelian normal `N` by the `diff` relation. -/ +def quotient_diff := +quotient (setoid.mk (λ α β, diff (monoid_hom.id H) α β = 1) ⟨λ α, diff_self (monoid_hom.id H) α, + λ α β h, by rw [←diff_inv, h, one_inv], λ α β γ h h', by rw [←diff_mul_diff, h, h', one_mul]⟩) -variables (α β γ : left_transversals (H : set G)) +instance : inhabited H.quotient_diff := quotient.inhabited _ -/-- The difference of two left transversals -/ -@[to_additive "The difference of two left transversals"] -noncomputable def diff [hH : normal H] : H := -∏ (q : G ⧸ H), ⟨(to_equiv α.2 q) * (to_equiv β.2 q)⁻¹, hH.mem_comm (quotient.exact' - (((to_equiv β.2).symm_apply_apply q).trans ((to_equiv α.2).symm_apply_apply q).symm))⟩ - -@[to_additive] lemma diff_mul_diff [normal H] : diff α β * diff β γ = diff α γ := -finset.prod_mul_distrib.symm.trans (finset.prod_congr rfl (λ x hx, subtype.ext - (by rw [coe_mul, coe_mk, coe_mk, coe_mk, mul_assoc, inv_mul_cancel_left]))) - -@[to_additive] lemma diff_self [normal H] : diff α α = 1 := -mul_right_eq_self.mp (diff_mul_diff α α α) - -@[to_additive] lemma diff_inv [normal H]: (diff α β)⁻¹ = diff β α := -inv_eq_of_mul_eq_one ((diff_mul_diff α β α).trans (diff_self α)) - -lemma smul_diff_smul [hH : normal H] (g : G) : - diff (g • α) (g • β) = ⟨g * diff α β * g⁻¹, hH.conj_mem (diff α β).1 (diff α β).2 g⟩ := +lemma smul_diff_smul' [hH : normal H] (g : Gᵐᵒᵖ) : + diff (monoid_hom.id H) (g • α) (g • β) = ⟨g.unop⁻¹ * (diff (monoid_hom.id H) α β : H) * g.unop, + hH.mem_comm ((congr_arg (∈ H) (mul_inv_cancel_left _ _)).mpr (set_like.coe_mem _))⟩ := begin let ϕ : H →* H := - { to_fun := λ h, ⟨g * h * g⁻¹, hH.conj_mem h.1 h.2 g⟩, - map_one' := subtype.ext (by rw [coe_mk, coe_one, mul_one, mul_inv_self]), - map_mul' := λ h₁ h₂, subtype.ext (by rw [coe_mk, coe_mul, coe_mul, coe_mk, coe_mk, mul_assoc, - mul_assoc, mul_assoc, mul_assoc, mul_assoc, inv_mul_cancel_left]) }, - refine eq.trans (finset.prod_bij' (λ q _, (↑g)⁻¹ * q) (λ _ _, finset.mem_univ _) - (λ q _, subtype.ext _) (λ q _, ↑g * q) (λ _ _, finset.mem_univ _) - (λ q _, mul_inv_cancel_left g q) (λ q _, inv_mul_cancel_left g q)) (ϕ.map_prod _ _).symm, - change _ * _ = g * (_ * _) * g⁻¹, - simp_rw [smul_apply_eq_smul_apply_inv_smul, smul_eq_mul, mul_inv_rev, mul_assoc], - refl, + { to_fun := λ h, ⟨g.unop⁻¹ * h * g.unop, + hH.mem_comm ((congr_arg (∈ H) (mul_inv_cancel_left _ _)).mpr (set_like.coe_mem _))⟩, + map_one' := by rw [subtype.ext_iff, coe_mk, coe_one, mul_one, inv_mul_self], + map_mul' := λ h₁ h₂, by rw [subtype.ext_iff, coe_mk, coe_mul, coe_mul, coe_mk, coe_mk, + mul_assoc, mul_assoc, mul_assoc, mul_assoc, mul_assoc, mul_inv_cancel_left] }, + refine eq.trans (finset.prod_bij' (λ q _, g⁻¹ • q) (λ q _, finset.mem_univ _) + (λ q _, subtype.ext _) (λ q _, g • q) (λ q _, finset.mem_univ _) (λ q _, smul_inv_smul g q) + (λ q _, inv_smul_smul g q)) (map_prod ϕ _ _).symm, + simp_rw [monoid_hom.id_apply, monoid_hom.coe_mk, coe_mk, smul_apply_eq_smul_apply_inv_smul, + smul_eq_mul_unop, mul_inv_rev, mul_assoc], end -lemma smul_diff [H.normal] (h : H) : - diff (h • α) β = h ^ H.index * diff α β := +variables {H} [normal H] + +instance : mul_action G H.quotient_diff := +{ smul := λ g, quotient.map' (λ α, op g⁻¹ • α) (λ α β h, subtype.ext (by rwa [smul_diff_smul', + coe_mk, coe_one, mul_eq_one_iff_eq_inv, mul_right_eq_self, ←coe_one, ←subtype.ext_iff])), + mul_smul := λ g₁ g₂ q, quotient.induction_on' q (λ T, congr_arg quotient.mk' + (by rw mul_inv_rev; exact mul_smul (op g₁⁻¹) (op g₂⁻¹) T)), + one_smul := λ q, quotient.induction_on' q (λ T, congr_arg quotient.mk' + (by rw one_inv; apply one_smul Gᵐᵒᵖ T)) } + +lemma smul_diff' (h : H) : + diff (monoid_hom.id H) α ((op (h : G)) • β) = diff (monoid_hom.id H) α β * h ^ H.index := begin rw [diff, diff, index_eq_card, ←finset.card_univ, ←finset.prod_const, ←finset.prod_mul_distrib], refine finset.prod_congr rfl (λ q _, _), - rw [subtype.ext_iff, coe_mul, coe_mk, coe_mk, ←mul_assoc, mul_right_cancel_iff], - rw [smul_def, smul_apply_eq_smul_apply_inv_smul, smul_eq_mul], - rw [mul_left_cancel_iff, ←subtype.ext_iff, equiv.apply_eq_iff_eq, inv_smul_eq_iff], - exact self_eq_mul_left.mpr ((quotient_group.eq_one_iff _).mpr h.2), + simp_rw [subtype.ext_iff, monoid_hom.id_apply, coe_mul, coe_mk, mul_assoc, mul_right_inj], + rw [smul_apply_eq_smul_apply_inv_smul, smul_eq_mul_unop, unop_op, + mul_left_inj, ←subtype.ext_iff, equiv.apply_eq_iff_eq, inv_smul_eq_iff], + exact self_eq_mul_right.mpr ((quotient_group.eq_one_iff _).mpr h.2), end -variables (H) - -instance setoid_diff [H.normal] : setoid (left_transversals (H : set G)) := -setoid.mk (λ α β, diff α β = 1) ⟨λ α, diff_self α, λ α β h₁, - by rw [←diff_inv, h₁, one_inv], λ α β γ h₁ h₂, by rw [←diff_mul_diff, h₁, h₂, one_mul]⟩ - -/-- The quotient of the transversals of an abelian normal `N` by the `diff` relation -/ -def quotient_diff [H.normal] := -quotient H.setoid_diff - -instance [H.normal] : inhabited H.quotient_diff := quotient.inhabited _ - -variables {H} - -instance [H.normal] : mul_action G H.quotient_diff := -{ smul := λ g, quotient.map (λ α, g • α) (λ α β h, (smul_diff_smul α β g).trans - (subtype.ext (mul_inv_eq_one.mpr (mul_right_eq_self.mpr (subtype.ext_iff.mp h))))), - mul_smul := λ g₁ g₂ q, quotient.induction_on q (λ α, congr_arg quotient.mk (mul_smul g₁ g₂ α)), - one_smul := λ q, quotient.induction_on q (λ α, congr_arg quotient.mk (one_smul G α)) } - variables [fintype H] -lemma exists_smul_eq [H.normal] (α β : H.quotient_diff) - (hH : nat.coprime (fintype.card H) H.index) : - ∃ h : H, h • α = β := -quotient.induction_on α (quotient.induction_on β - (λ β α, exists_imp_exists (λ n, quotient.sound) - ⟨(pow_coprime hH).symm (diff α β)⁻¹, by - { change diff ((_ : H) • _) _ = 1, - rw smul_diff, - change pow_coprime hH ((pow_coprime hH).symm (diff α β)⁻¹) * (diff α β) = 1, - rw [equiv.apply_symm_apply, inv_mul_self] }⟩)) - -lemma smul_left_injective [H.normal] (α : H.quotient_diff) - (hH : nat.coprime (fintype.card H) H.index) : - function.injective (λ h : H, h • α) := -λ h₁ h₂, begin - refine quotient.induction_on α (λ α hα, _), - replace hα : diff (h₁ • α) (h₂ • α) = 1 := quotient.exact hα, - rw [smul_diff, ←diff_inv, smul_diff, diff_self, mul_one, mul_inv_eq_one] at hα, - exact (pow_coprime hH).injective hα, -end +lemma eq_one_of_smul_eq_one (hH : nat.coprime (fintype.card H) H.index) + (α : H.quotient_diff) (h : H) : h • α = α → h = 1 := +quotient.induction_on' α $ λ α hα, (pow_coprime hH).injective $ + calc h ^ H.index = diff (monoid_hom.id H) ((op ((h⁻¹ : H) : G)) • α) α : + by rw [←diff_inv, smul_diff', diff_self, one_mul, inv_pow, inv_inv] + ... = 1 ^ H.index : (quotient.exact' hα).trans (one_pow H.index).symm + +lemma exists_smul_eq (hH : nat.coprime (fintype.card H) H.index) + (α β : H.quotient_diff) : ∃ h : H, h • α = β := +quotient.induction_on' α (quotient.induction_on' β (λ β α, exists_imp_exists (λ n, quotient.sound') + ⟨(pow_coprime hH).symm (diff (monoid_hom.id H) β α), (diff_inv _ _ _).symm.trans + (inv_eq_one.mpr ((smul_diff' β α ((pow_coprime hH).symm (diff (monoid_hom.id H) β α))⁻¹).trans + (by rw [inv_pow, ←pow_coprime_apply hH, equiv.apply_symm_apply, mul_inv_self])))⟩)) -lemma is_complement'_stabilizer_of_coprime [H.normal] {α : H.quotient_diff} - (hH : nat.coprime (fintype.card H) H.index) : is_complement' H (mul_action.stabilizer G α) := -is_complement'_stabilizer α (λ h hh, smul_left_injective α hH (hh.trans (one_smul H α).symm)) - (λ g, exists_smul_eq (g • α) α hH) +lemma is_complement'_stabilizer_of_coprime {α : H.quotient_diff} + (hH : nat.coprime (fintype.card H) H.index) : is_complement' H (stabilizer G α) := +is_complement'_stabilizer α (eq_one_of_smul_eq_one hH α) (λ g, exists_smul_eq hH (g • α) α) /-- Do not use this lemma: It is made obsolete by `exists_right_complement'_of_coprime` -/ -private lemma exists_right_complement'_of_coprime_aux [H.normal] +private lemma exists_right_complement'_of_coprime_aux (hH : nat.coprime (fintype.card H) H.index) : ∃ K : subgroup G, is_complement' H K := -nonempty_of_inhabited.elim - (λ α : H.quotient_diff, ⟨mul_action.stabilizer G α, is_complement'_stabilizer_of_coprime hH⟩) +nonempty_of_inhabited.elim (λ α, ⟨stabilizer G α, is_complement'_stabilizer_of_coprime hH⟩) end schur_zassenhaus_abelian From b1b2cab4a2c54d65ba9daa584e816676281c94bb Mon Sep 17 00:00:00 2001 From: tb65536 Date: Mon, 25 Apr 2022 06:23:58 +0000 Subject: [PATCH 227/373] =?UTF-8?q?feat(group=5Ftheory/complement):=20The?= =?UTF-8?q?=20range=20of=20a=20section=20`G=20=E2=A7=B8=20H=20=E2=86=92=20?= =?UTF-8?q?G`=20is=20a=20transversal=20(#13623)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds left and right versions of the statement that the range of a section `G ⧸ H → G` is a transversal. --- src/group_theory/complement.lean | 48 +++++++++++++++----------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/src/group_theory/complement.lean b/src/group_theory/complement.lean index cfbed9e1e8300..56ab33596f457 100644 --- a/src/group_theory/complement.lean +++ b/src/group_theory/complement.lean @@ -198,36 +198,36 @@ mem_left_transversals_iff_exists_unique_quotient_mk'_eq.trans mem_right_transversals_iff_exists_unique_quotient_mk'_eq.trans (function.bijective_iff_exists_unique (S.restrict quotient.mk')).symm +@[to_additive] lemma range_mem_left_transversals {f : G ⧸ H → G} (hf : ∀ q, ↑(f q) = q) : + set.range f ∈ left_transversals (H : set G) := +mem_left_transversals_iff_bijective.mpr ⟨by rintros ⟨-, q₁, rfl⟩ ⟨-, q₂, rfl⟩ h; + exact congr_arg _ (((hf q₁).symm.trans h).trans (hf q₂)), λ q, ⟨⟨f q, q, rfl⟩, hf q⟩⟩ + +@[to_additive] lemma range_mem_right_transversals {f : quotient (quotient_group.right_rel H) → G} + (hf : ∀ q, quotient.mk' (f q) = q) : set.range f ∈ right_transversals (H : set G) := +mem_right_transversals_iff_bijective.mpr ⟨by rintros ⟨-, q₁, rfl⟩ ⟨-, q₂, rfl⟩ h; + exact congr_arg _ (((hf q₁).symm.trans h).trans (hf q₂)), λ q, ⟨⟨f q, q, rfl⟩, hf q⟩⟩ + @[to_additive] lemma exists_left_transversal (g : G) : ∃ S ∈ left_transversals (H : set G), g ∈ S := begin classical, - let f : G ⧸ H → G := function.update quotient.out' g g, - have hf : ∀ q, ↑(f q) = q, - { intro q, - by_cases hq : q = g, - { exact hq.symm ▸ congr_arg _ (function.update_same g g quotient.out') }, - { exact eq.trans (congr_arg _ (function.update_noteq hq g quotient.out')) q.out_eq' } }, - refine ⟨set.range f, mem_left_transversals_iff_bijective.mpr ⟨_, λ q, ⟨⟨f q, q, rfl⟩, hf q⟩⟩, - ⟨g, function.update_same g g quotient.out'⟩⟩, - rintros ⟨-, q₁, rfl⟩ ⟨-, q₂, rfl⟩ hg, - exact congr_arg _ (((hf q₁).symm.trans hg).trans (hf q₂)), + refine ⟨set.range (function.update quotient.out' ↑g g), range_mem_left_transversals (λ q, _), + g, function.update_same g g quotient.out'⟩, + by_cases hq : q = g, + { exact hq.symm ▸ congr_arg _ (function.update_same g g quotient.out') }, + { exact eq.trans (congr_arg _ (function.update_noteq hq g quotient.out')) q.out_eq' }, end @[to_additive] lemma exists_right_transversal (g : G) : ∃ S ∈ right_transversals (H : set G), g ∈ S := begin classical, - let f : _ → G := function.update quotient.out' (quotient.mk' g) g, - have hf : ∀ q : quotient (quotient_group.right_rel H), quotient.mk' (f q) = q, - { intro q, - by_cases hq : q = quotient.mk' g, - { exact hq.symm ▸ congr_arg _ (function.update_same (quotient.mk' g) g quotient.out') }, - { exact eq.trans (congr_arg _ (function.update_noteq hq g quotient.out')) q.out_eq' } }, - refine ⟨set.range f, mem_right_transversals_iff_bijective.mpr ⟨_, λ q, ⟨⟨_, q, rfl⟩, hf q⟩⟩, - ⟨quotient.mk' g, function.update_same (quotient.mk' g) g quotient.out'⟩⟩, - rintros ⟨-, q₁, rfl⟩ ⟨-, q₂, rfl⟩ hg, - exact congr_arg _ (((hf q₁).symm.trans hg).trans (hf q₂)), + refine ⟨set.range (function.update quotient.out' _ g), range_mem_right_transversals (λ q, _), + quotient.mk' g, function.update_same (quotient.mk' g) g quotient.out'⟩, + by_cases hq : q = quotient.mk' g, + { exact hq.symm ▸ congr_arg _ (function.update_same (quotient.mk' g) g quotient.out') }, + { exact eq.trans (congr_arg _ (function.update_noteq hq g quotient.out')) q.out_eq' }, end namespace mem_left_transversals @@ -326,14 +326,10 @@ by rw [smul_to_equiv, smul_inv_smul] end action @[to_additive] instance : inhabited (left_transversals (H : set G)) := -⟨⟨set.range quotient.out', mem_left_transversals_iff_bijective.mpr ⟨by -{ rintros ⟨_, q₁, rfl⟩ ⟨_, q₂, rfl⟩ hg, - rw (q₁.out_eq'.symm.trans hg).trans q₂.out_eq' }, λ q, ⟨⟨q.out', q, rfl⟩, quotient.out_eq' q⟩⟩⟩⟩ +⟨⟨set.range quotient.out', range_mem_left_transversals quotient.out_eq'⟩⟩ @[to_additive] instance : inhabited (right_transversals (H : set G)) := -⟨⟨set.range quotient.out', mem_right_transversals_iff_bijective.mpr ⟨by -{ rintros ⟨_, q₁, rfl⟩ ⟨_, q₂, rfl⟩ hg, - rw (q₁.out_eq'.symm.trans hg).trans q₂.out_eq' }, λ q, ⟨⟨q.out', q, rfl⟩, quotient.out_eq' q⟩⟩⟩⟩ +⟨⟨set.range quotient.out', range_mem_right_transversals quotient.out_eq'⟩⟩ lemma is_complement'.is_compl (h : is_complement' H K) : is_compl H K := begin From 9c861e32fa7e3d0609a8975a4e7671f671f9efdb Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 25 Apr 2022 06:23:59 +0000 Subject: [PATCH 228/373] feat(topology/algebra/matrix): `matrix.block_diagonal` is continuous (#13641) `continuous.if_const` isn't suitable for the primed `matrix.block_diagonal'` case, as the `if` is dependent. --- src/topology/algebra/matrix.lean | 35 +++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/topology/algebra/matrix.lean b/src/topology/algebra/matrix.lean index bd176eb590088..89157a0a77a69 100644 --- a/src/topology/algebra/matrix.lean +++ b/src/topology/algebra/matrix.lean @@ -21,7 +21,8 @@ This file is a place to collect topological results about matrices. open matrix open_locale matrix -variables {X α l m n p S R : Type*} [topological_space X] [topological_space R] +variables {X α l m n p S R : Type*} {m' n' : l → Type*} +variables [topological_space X] [topological_space R] instance : topological_space (matrix m n R) := Pi.topological_space @@ -188,3 +189,35 @@ lemma continuous_at_matrix_inv [fintype n] [decidable_eq n] [comm_ring R] [topol (A : matrix n n R) (h : continuous_at ring.inverse A.det) : continuous_at has_inv.inv A := (h.comp continuous_id.matrix_det.continuous_at).smul continuous_id.matrix_adjugate.continuous_at + +-- lemmas about functions in `data/matrix/block.lean` +section block_matrices + +@[continuity] +lemma continuous.matrix_from_blocks + {A : X → matrix n l R} {B : X → matrix n m R} {C : X → matrix p l R} {D : X → matrix p m R} + (hA : continuous A) (hB : continuous B) (hC : continuous C) (hD : continuous D) : + continuous (λ x, matrix.from_blocks (A x) (B x) (C x) (D x)) := +continuous_matrix $ λ i j, + by cases i; cases j; refine continuous.matrix_elem _ i j; assumption + +@[continuity] +lemma continuous.matrix_block_diagonal [has_zero R] [decidable_eq p] {A : X → p → matrix m n R} + (hA : continuous A) : + continuous (λ x, block_diagonal (A x)) := +continuous_matrix $ λ ⟨i₁, i₂⟩ ⟨j₁, j₂⟩, + (((continuous_apply i₂).comp hA).matrix_elem i₁ j₁).if_const _ continuous_zero + +@[continuity] +lemma continuous.matrix_block_diagonal' [has_zero R] [decidable_eq l] + {A : X → Π i, matrix (m' i) (n' i) R} (hA : continuous A) : + continuous (λ x, block_diagonal' (A x)) := +continuous_matrix $ λ ⟨i₁, i₂⟩ ⟨j₁, j₂⟩, begin + dsimp only [block_diagonal'], + split_ifs, + { subst h, + exact ((continuous_apply i₁).comp hA).matrix_elem i₂ j₂ }, + { exact continuous_const }, +end + +end block_matrices From b6a4be447801918487ea47883e6b4b372aa2ccf5 Mon Sep 17 00:00:00 2001 From: Yuma Mizuno Date: Mon, 25 Apr 2022 06:24:00 +0000 Subject: [PATCH 229/373] chore(ring_theory/witt_vector/isocrystal): speed up the proof (#13644) to remove a timeout in #13459 --- src/ring_theory/witt_vector/isocrystal.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ring_theory/witt_vector/isocrystal.lean b/src/ring_theory/witt_vector/isocrystal.lean index 722a6bc7357b0..937c49f8a1f3f 100644 --- a/src/ring_theory/witt_vector/isocrystal.lean +++ b/src/ring_theory/witt_vector/isocrystal.lean @@ -176,8 +176,8 @@ begin intros ha', apply this, simp only [←ha, ha', zero_smul] }, - obtain ⟨b, hb, m, (hmb : φ(p, k) b * a = p ^ m * b)⟩ := - witt_vector.exists_frobenius_solution_fraction_ring p ha, + obtain ⟨b, hb, m, hmb⟩ := witt_vector.exists_frobenius_solution_fraction_ring p ha, + replace hmb : φ(p, k) b * a = p ^ m * b := by convert hmb, use m, let F₀ : standard_one_dim_isocrystal p k m →ₗ[K(p,k)] V := linear_map.to_span_singleton K(p, k) V x, From 962bfcdb9adbc484fc78db5bd5bf1d17ca1102ba Mon Sep 17 00:00:00 2001 From: Eric Rodriguez Date: Mon, 25 Apr 2022 06:24:00 +0000 Subject: [PATCH 230/373] chore(field_theory/finite/polynomial): tidy + remove nolints (#13645) Some of these definitions only make full sense over a field (for example the indicator function can be nonsensical in non-field rings) but there's also no reason not to define them more generally. This removes all `nolint`s related to this file, and all of the generalisation linter suggestions too. --- src/field_theory/finite/polynomial.lean | 116 ++++++++++++++---------- 1 file changed, 66 insertions(+), 50 deletions(-) diff --git a/src/field_theory/finite/polynomial.lean b/src/field_theory/finite/polynomial.lean index 8f37c388a6b25..ab9d717b709f4 100644 --- a/src/field_theory/finite/polynomial.lean +++ b/src/field_theory/finite/polynomial.lean @@ -27,8 +27,7 @@ section frobenius variables {p : ℕ} [fact p.prime] -lemma frobenius_zmod (f : mv_polynomial σ (zmod p)) : - frobenius _ p f = expand p f := +lemma frobenius_zmod (f : mv_polynomial σ (zmod p)) : frobenius _ p f = expand p f := begin apply induction_on f, { intro a, rw [expand_C, frobenius_def, ← C_pow, zmod.pow_card], }, @@ -37,8 +36,7 @@ begin intros _ _ hf, rw [hf, frobenius_def], }, end -lemma expand_zmod (f : mv_polynomial σ (zmod p)) : - expand p f = f ^ p := +lemma expand_zmod (f : mv_polynomial σ (zmod p)) : expand p f = f ^ p := (frobenius_zmod _).symm end frobenius @@ -52,33 +50,26 @@ open_locale big_operators classical open set linear_map submodule variables {K : Type*} {σ : Type*} -variables [field K] [fintype K] [fintype σ] -def indicator (a : σ → K) : mv_polynomial σ K := -∏ n, (1 - (X n - C (a n))^(fintype.card K - 1)) +section indicator + +variables [fintype K] [fintype σ] + +/-- Over a field, this is the indicator function as an `mv_polynomial`. -/ +def indicator [comm_ring K] (a : σ → K) : mv_polynomial σ K := +∏ n, (1 - (X n - C (a n)) ^ (fintype.card K - 1)) + +section comm_ring + +variables [comm_ring K] lemma eval_indicator_apply_eq_one (a : σ → K) : eval a (indicator a) = 1 := -have 0 < fintype.card K - 1, -begin - rw [← fintype.card_units, fintype.card_pos_iff], - exact ⟨1⟩ -end, -by { simp only [indicator, (eval a).map_prod, ring_hom.map_sub, - (eval a).map_one, (eval a).map_pow, eval_X, eval_C, - sub_self, zero_pow this, sub_zero, finset.prod_const_one] } - -lemma eval_indicator_apply_eq_zero (a b : σ → K) (h : a ≠ b) : - eval a (indicator b) = 0 := -have ∃i, a i ≠ b i, by rwa [(≠), function.funext_iff, not_forall] at h, begin - rcases this with ⟨i, hi⟩, - simp only [indicator, (eval a).map_prod, ring_hom.map_sub, - (eval a).map_one, (eval a).map_pow, eval_X, eval_C, - sub_self, finset.prod_eq_zero_iff], - refine ⟨i, finset.mem_univ _, _⟩, - rw [finite_field.pow_card_sub_one_eq_one, sub_self], - rwa [(≠), sub_eq_zero], + nontriviality, + have : 0 < fintype.card K - 1 := tsub_pos_of_lt fintype.one_lt_card, + simp only [indicator, map_prod, map_sub, map_one, map_pow, eval_X, eval_C, + sub_self, zero_pow this, sub_zero, finset.prod_const_one] end lemma degrees_indicator (c : σ → K) : @@ -109,16 +100,34 @@ begin { rw [multiset.count_singleton_self, mul_one] } end +end comm_ring + +variables [field K] + +lemma eval_indicator_apply_eq_zero (a b : σ → K) (h : a ≠ b) : + eval a (indicator b) = 0 := +begin + obtain ⟨i, hi⟩ : ∃ i, a i ≠ b i := by rwa [(≠), function.funext_iff, not_forall] at h, + simp only [indicator, map_prod, map_sub, map_one, map_pow, eval_X, eval_C, + sub_self, finset.prod_eq_zero_iff], + refine ⟨i, finset.mem_univ _, _⟩, + rw [finite_field.pow_card_sub_one_eq_one, sub_self], + rwa [(≠), sub_eq_zero], +end + +end indicator + section variables (K σ) -def evalₗ : mv_polynomial σ K →ₗ[K] (σ → K) → K := + +/-- `mv_polynomial.eval` as a `K`-linear map. -/ +@[simps] def evalₗ [comm_semiring K] : mv_polynomial σ K →ₗ[K] (σ → K) → K := { to_fun := λ p e, eval e p, map_add' := λ p q, by { ext x, rw ring_hom.map_add, refl, }, map_smul' := λ a p, by { ext e, rw [smul_eq_C_mul, ring_hom.map_mul, eval_C], refl } } end -lemma evalₗ_apply (p : mv_polynomial σ K) (e : σ → K) : evalₗ K σ p e = eval e p := -rfl +variables [field K] [fintype K] [fintype σ] lemma map_restrict_dom_evalₗ : (restrict_degree σ K (fintype.card K - 1)).map (evalₗ K σ) = ⊤ := begin @@ -130,12 +139,12 @@ begin pi.smul_apply, linear_map.map_smul], simp only [evalₗ_apply], transitivity, - refine finset.sum_eq_single n _ _, - { assume b _ h, - rw [eval_indicator_apply_eq_zero _ _ h.symm, smul_zero] }, - { assume h, exact (h $ finset.mem_univ n).elim }, + refine finset.sum_eq_single n (λ b _ h, _) _, + { rw [eval_indicator_apply_eq_zero _ _ h.symm, smul_zero] }, + { exact λ h, (h $ finset.mem_univ n).elim }, { rw [eval_indicator_apply_eq_one, smul_eq_mul, mul_one] } } end + end mv_polynomial namespace mv_polynomial @@ -144,16 +153,30 @@ open_locale classical cardinal open linear_map submodule universe u -variables (σ : Type u) (K : Type u) [fintype σ] [field K] [fintype K] +variables (σ : Type u) (K : Type u) [fintype K] +/-- The submodule of multivariate polynomials whose degree of each variable is strictly less +than the cardinality of K. -/ @[derive [add_comm_group, module K, inhabited]] -def R : Type u := restrict_degree σ K (fintype.card K - 1) +def R [comm_ring K] : Type u := restrict_degree σ K (fintype.card K - 1) + +/-- Evaluation in the `mv_polynomial.R` subtype. -/ +def evalᵢ [comm_ring K] : R σ K →ₗ[K] (σ → K) → K := +((evalₗ K σ).comp (restrict_degree σ K (fintype.card K - 1)).subtype) + +section comm_ring + +variables [comm_ring K] noncomputable instance decidable_restrict_degree (m : ℕ) : decidable_pred (∈ {n : σ →₀ ℕ | ∀i, n i ≤ m }) := by simp only [set.mem_set_of_eq]; apply_instance -lemma dim_R : module.rank K (R σ K) = fintype.card (σ → K) := +end comm_ring + +variables [field K] + +lemma dim_R [fintype σ] : module.rank K (R σ K) = fintype.card (σ → K) := calc module.rank K (R σ K) = module.rank K (↥{s : σ →₀ ℕ | ∀ (n : σ), s n ≤ fintype.card K - 1} →₀ K) : linear_equiv.dim_eq @@ -174,37 +197,30 @@ calc module.rank K (R σ K) = (equiv.arrow_congr (equiv.refl σ) (fintype.equiv_fin K).symm).cardinal_eq ... = fintype.card (σ → K) : cardinal.mk_fintype _ -instance : finite_dimensional K (R σ K) := +instance [fintype σ] : finite_dimensional K (R σ K) := is_noetherian.iff_fg.1 $ is_noetherian.iff_dim_lt_omega.mpr (by simpa only [dim_R] using cardinal.nat_lt_omega (fintype.card (σ → K))) -lemma finrank_R : finite_dimensional.finrank K (R σ K) = fintype.card (σ → K) := +lemma finrank_R [fintype σ] : finite_dimensional.finrank K (R σ K) = fintype.card (σ → K) := finite_dimensional.finrank_eq_of_dim_eq (dim_R σ K) -def evalᵢ : R σ K →ₗ[K] (σ → K) → K := -((evalₗ K σ).comp (restrict_degree σ K (fintype.card K - 1)).subtype) - -lemma range_evalᵢ : (evalᵢ σ K).range = ⊤ := +lemma range_evalᵢ [fintype σ] : (evalᵢ σ K).range = ⊤ := begin rw [evalᵢ, linear_map.range_comp, range_subtype], exact map_restrict_dom_evalₗ end -lemma ker_evalₗ : (evalᵢ σ K).ker = ⊥ := +lemma ker_evalₗ [fintype σ] : (evalᵢ σ K).ker = ⊥ := begin refine (ker_eq_bot_iff_range_eq_top_of_finrank_eq_finrank _).mpr (range_evalᵢ _ _), rw [finite_dimensional.finrank_fintype_fun_eq_card, finrank_R] end -lemma eq_zero_of_eval_eq_zero (p : mv_polynomial σ K) +lemma eq_zero_of_eval_eq_zero [fintype σ] (p : mv_polynomial σ K) (h : ∀v:σ → K, eval v p = 0) (hp : p ∈ restrict_degree σ K (fintype.card K - 1)) : p = 0 := let p' : R σ K := ⟨p, hp⟩ in -have p' ∈ (evalᵢ σ K).ker := by { rw [mem_ker], ext v, exact h v }, -show p'.1 = (0 : R σ K).1, -begin - rw [ker_evalₗ, mem_bot] at this, - rw [this] -end +have p' ∈ (evalᵢ σ K).ker := funext h, +show p'.1 = (0 : R σ K).1, from congr_arg _ $ by rwa [ker_evalₗ, mem_bot] at this end mv_polynomial From c24f1f2b1ca4a93d74550f1179cb46c7378be53f Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Mon, 25 Apr 2022 06:24:04 +0000 Subject: [PATCH 231/373] chore(number_theory/padics/*): tidy some proofs (#13652) --- src/number_theory/padics/padic_norm.lean | 51 +++++++-------------- src/number_theory/padics/padic_numbers.lean | 20 +++----- 2 files changed, 24 insertions(+), 47 deletions(-) diff --git a/src/number_theory/padics/padic_norm.lean b/src/number_theory/padics/padic_norm.lean index 2f2e56389113a..872f7a03a1734 100644 --- a/src/number_theory/padics/padic_norm.lean +++ b/src/number_theory/padics/padic_norm.lean @@ -110,11 +110,9 @@ variables {p : ℕ} lemma of_ne_one_ne_zero {z : ℤ} (hp : p ≠ 1) (hz : z ≠ 0) : padic_val_int p z = (multiplicity (p : ℤ) z).get (by {apply multiplicity.finite_int_iff.2, simp [hp, hz]}) := begin - rw [padic_val_int, padic_val_nat, dif_pos], + rw [padic_val_int, padic_val_nat, dif_pos (and.intro hp (int.nat_abs_pos_of_ne_zero hz))], simp_rw multiplicity.int.nat_abs p z, refl, - simp [hp, hz], - exact int.nat_abs_pos_of_ne_zero hz, end /-- `padic_val_int p 0` is 0 for any `p`. -/ @@ -184,10 +182,9 @@ lemma multiplicity_sub_multiplicity {q : ℚ} (hp : p ≠ 1) (hq : q ≠ 0) : (by { rw [←finite_iff_dom, finite_nat_iff, and_iff_right hp], exact q.pos }) := begin rw [padic_val_rat, padic_val_int.of_ne_one_ne_zero hp, padic_val_nat, dif_pos], - refl, - simp only [hp, ne.def, not_false_iff, true_and], - exact q.pos, - exact rat.num_ne_zero_of_ne_zero hq, + { refl }, + { exact ⟨hp, q.pos⟩ }, + { exact rat.num_ne_zero_of_ne_zero hq }, end /-- The p-adic value of an integer `z ≠ 0` is its p-adic_value as a rational -/ @@ -482,21 +479,15 @@ lemma padic_val_nat_dvd_iff (p : ℕ) [hp :fact p.prime] (n : ℕ) (a : ℕ) : p^n ∣ a ↔ a = 0 ∨ n ≤ padic_val_nat p a := begin split, - { rw pow_dvd_iff_le_multiplicity, - rw padic_val_nat, + { rw [pow_dvd_iff_le_multiplicity, padic_val_nat], split_ifs, - rw enat.coe_le_iff, - intro hn, - right, - apply hn, - simp [hp.out.ne_one] at h, - rw h, - simp, }, - { intro h, - cases h, - rw h, - exact dvd_zero (p ^ n), - exact dvd_trans (pow_dvd_pow p h) pow_padic_val_nat_dvd, }, + { rw enat.coe_le_iff, + exact λ hn, or.inr (hn _) }, + { simp only [true_and, not_lt, ne.def, not_false_iff, nat.le_zero_iff, hp.out.ne_one] at h, + exact λ hn, or.inl h } }, + { rintro (rfl|h), + { exact dvd_zero (p ^ n) }, + { exact dvd_trans (pow_dvd_pow p h) pow_padic_val_nat_dvd } }, end lemma padic_val_nat_primes {p q : ℕ} [p_prime : fact p.prime] [q_prime : fact q.prime] @@ -589,33 +580,25 @@ by rw [padic_val_int, ←int.nat_abs_eq_zero, ←padic_val_nat_dvd_iff, ←int.c lemma padic_val_int_dvd (p : ℕ) [fact p.prime] (a : ℤ) : ↑p^(padic_val_int p a) ∣ a := begin rw padic_val_int_dvd_iff, - simp only [le_refl, or_true], + exact or.inr le_rfl, end lemma padic_val_int_self (p : ℕ) [pp : fact p.prime] : padic_val_int p p = 1 := -begin - apply padic_val_int.self, - exact pp.out.one_lt, -end +padic_val_int.self pp.out.one_lt lemma padic_val_int.mul (p : ℕ) [fact p.prime] {a b : ℤ} (ha : a ≠ 0) (hb : b ≠ 0) : padic_val_int p (a*b) = padic_val_int p a + padic_val_int p b := begin simp_rw padic_val_int, - rw int.nat_abs_mul, - rw padic_val_nat.mul; + rw [int.nat_abs_mul, padic_val_nat.mul]; rwa int.nat_abs_ne_zero, end lemma padic_val_int_mul_eq_succ (p : ℕ) [pp : fact p.prime] (a : ℤ) (ha : a ≠ 0) : padic_val_int p (a * p) = (padic_val_int p a) + 1 := begin - rw padic_val_int.mul, - congr, + rw padic_val_int.mul p ha (int.coe_nat_ne_zero.mpr (pp.out).ne_zero), simp only [eq_self_iff_true, padic_val_int.of_nat, padic_val_nat_self], - assumption, - simp only [int.coe_nat_eq_zero, ne.def], - exact (pp.out).ne_zero, end end padic_val_int @@ -661,7 +644,7 @@ The p-adic norm of `p` is `1/p` if `p > 1`. See also `padic_norm.padic_norm_p_of_prime` for a version that assumes `p` is prime. -/ lemma padic_norm_p {p : ℕ} (hp : 1 < p) : padic_norm p p = 1 / p := -by simp [padic_norm, (show p ≠ 0, by linarith), padic_val_nat.self hp] +by simp [padic_norm, (pos_of_gt hp).ne', padic_val_nat.self hp] /-- The p-adic norm of `p` is `1/p` if `p` is prime. diff --git a/src/number_theory/padics/padic_numbers.lean b/src/number_theory/padics/padic_numbers.lean index 2cc7a6357e7b7..d48b61bcbc334 100644 --- a/src/number_theory/padics/padic_numbers.lean +++ b/src/number_theory/padics/padic_numbers.lean @@ -543,21 +543,18 @@ lemma defn (f : padic_seq p) {ε : ℚ} (hε : 0 < ε) : ∃ N, ∀ i ≥ N, pad begin simp only [padic.cast_eq_of_rat], change ∃ N, ∀ i ≥ N, (f - const _ (f i)).norm < ε, - by_contradiction h, + by_contra' h, cases cauchy₂ f hε with N hN, - have : ∀ N, ∃ i ≥ N, ε ≤ (f - const _ (f i)).norm, - by simpa only [not_forall, not_exists, not_lt] using h, - rcases this N with ⟨i, hi, hge⟩, + rcases h N with ⟨i, hi, hge⟩, have hne : ¬ (f - const (padic_norm p) (f i)) ≈ 0, { intro h, unfold padic_seq.norm at hge; split_ifs at hge, exact not_lt_of_ge hge hε }, unfold padic_seq.norm at hge; split_ifs at hge, apply not_le_of_gt _ hge, - cases decidable.em (N ≤ stationary_point hne) with hgen hngen, - { apply hN; assumption }, + cases em (N ≤ stationary_point hne) with hgen hngen, + { apply hN _ hgen _ hi }, { have := stationary_point_spec hne le_rfl (le_of_not_le hngen), rw ←this, - apply hN, - exact le_rfl, assumption }, + exact hN _ le_rfl _ hi }, end protected lemma nonneg (q : ℚ_[p]) : 0 ≤ padic_norm_e q := @@ -651,8 +648,7 @@ quotient.induction_on q $ λ q', { have := eq.symm (this le_rfl hle), simp only [const_apply, sub_apply, padic_norm.zero, sub_self] at this, simpa only [this] }, - { apply hN, - apply le_of_lt, apply lt_of_not_ge, apply hle, exact le_rfl }} + { exact hN _ (lt_of_not_ge hle).le _ le_rfl } } end⟩ variables {p : ℕ} [fact p.prime] (f : cau_seq _ (@padic_norm_e p _)) @@ -705,9 +701,7 @@ begin { rw [padic_norm_e.sub_rev], apply_mod_cast hN, exact le_of_max_le_left hj }, - { apply hN2, - exact le_of_max_le_right hj, - apply le_max_right }}}, + { exact hN2 _ (le_of_max_le_right hj) _ (le_max_right _ _) } } }, { apply_mod_cast hN, apply le_max_left }}} end From 7d64215f7d4e2f28a1260266351a60db91312692 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Mon, 25 Apr 2022 06:24:07 +0000 Subject: [PATCH 232/373] chore(analysis/convex/topology): generalize a few lemmas (#13656) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way they work for `𝕜 = ℚ` too. --- src/analysis/convex/topology.lean | 64 +++++++++++++++---------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/analysis/convex/topology.lean b/src/analysis/convex/topology.lean index 6fd114592ff55..d7df224384345 100644 --- a/src/analysis/convex/topology.lean +++ b/src/analysis/convex/topology.lean @@ -77,12 +77,12 @@ end std_simplex section has_continuous_const_smul -variables [add_comm_group E] [module ℝ E] [topological_space E] - [topological_add_group E] [has_continuous_const_smul ℝ E] +variables {𝕜 : Type*} [linear_ordered_field 𝕜] [add_comm_group E] [module 𝕜 E] [topological_space E] + [topological_add_group E] [has_continuous_const_smul 𝕜 E] /-- If `s` is a convex set, then `a • interior s + b • closure s ⊆ interior s` for all `0 < a`, `0 ≤ b`, `a + b = 1`. See also `convex.combo_interior_self_subset_interior` for a weaker version. -/ -lemma convex.combo_interior_closure_subset_interior {s : set E} (hs : convex ℝ s) {a b : ℝ} +lemma convex.combo_interior_closure_subset_interior {s : set E} (hs : convex 𝕜 s) {a b : 𝕜} (ha : 0 < a) (hb : 0 ≤ b) (hab : a + b = 1) : a • interior s + b • closure s ⊆ interior s := interior_smul₀ ha.ne' s ▸ @@ -94,7 +94,7 @@ interior_smul₀ ha.ne' s ▸ /-- If `s` is a convex set, then `a • interior s + b • s ⊆ interior s` for all `0 < a`, `0 ≤ b`, `a + b = 1`. See also `convex.combo_interior_closure_subset_interior` for a stronger version. -/ -lemma convex.combo_interior_self_subset_interior {s : set E} (hs : convex ℝ s) {a b : ℝ} +lemma convex.combo_interior_self_subset_interior {s : set E} (hs : convex 𝕜 s) {a b : 𝕜} (ha : 0 < a) (hb : 0 ≤ b) (hab : a + b = 1) : a • interior s + b • s ⊆ interior s := calc a • interior s + b • s ⊆ a • interior s + b • closure s : @@ -103,96 +103,96 @@ calc a • interior s + b • s ⊆ a • interior s + b • closure s : /-- If `s` is a convex set, then `a • closure s + b • interior s ⊆ interior s` for all `0 ≤ a`, `0 < b`, `a + b = 1`. See also `convex.combo_self_interior_subset_interior` for a weaker version. -/ -lemma convex.combo_closure_interior_subset_interior {s : set E} (hs : convex ℝ s) {a b : ℝ} +lemma convex.combo_closure_interior_subset_interior {s : set E} (hs : convex 𝕜 s) {a b : 𝕜} (ha : 0 ≤ a) (hb : 0 < b) (hab : a + b = 1) : a • closure s + b • interior s ⊆ interior s := by { rw add_comm, exact hs.combo_interior_closure_subset_interior hb ha (add_comm a b ▸ hab) } /-- If `s` is a convex set, then `a • s + b • interior s ⊆ interior s` for all `0 ≤ a`, `0 < b`, `a + b = 1`. See also `convex.combo_closure_interior_subset_interior` for a stronger version. -/ -lemma convex.combo_self_interior_subset_interior {s : set E} (hs : convex ℝ s) {a b : ℝ} +lemma convex.combo_self_interior_subset_interior {s : set E} (hs : convex 𝕜 s) {a b : 𝕜} (ha : 0 ≤ a) (hb : 0 < b) (hab : a + b = 1) : a • s + b • interior s ⊆ interior s := by { rw add_comm, exact hs.combo_interior_self_subset_interior hb ha (add_comm a b ▸ hab) } -lemma convex.combo_interior_closure_mem_interior {s : set E} (hs : convex ℝ s) {x y : E} - (hx : x ∈ interior s) (hy : y ∈ closure s) {a b : ℝ} (ha : 0 < a) (hb : 0 ≤ b) (hab : a + b = 1) : +lemma convex.combo_interior_closure_mem_interior {s : set E} (hs : convex 𝕜 s) {x y : E} + (hx : x ∈ interior s) (hy : y ∈ closure s) {a b : 𝕜} (ha : 0 < a) (hb : 0 ≤ b) (hab : a + b = 1) : a • x + b • y ∈ interior s := hs.combo_interior_closure_subset_interior ha hb hab $ add_mem_add (smul_mem_smul_set hx) (smul_mem_smul_set hy) -lemma convex.combo_interior_self_mem_interior {s : set E} (hs : convex ℝ s) {x y : E} - (hx : x ∈ interior s) (hy : y ∈ s) {a b : ℝ} (ha : 0 < a) (hb : 0 ≤ b) (hab : a + b = 1) : +lemma convex.combo_interior_self_mem_interior {s : set E} (hs : convex 𝕜 s) {x y : E} + (hx : x ∈ interior s) (hy : y ∈ s) {a b : 𝕜} (ha : 0 < a) (hb : 0 ≤ b) (hab : a + b = 1) : a • x + b • y ∈ interior s := hs.combo_interior_closure_mem_interior hx (subset_closure hy) ha hb hab -lemma convex.combo_closure_interior_mem_interior {s : set E} (hs : convex ℝ s) {x y : E} - (hx : x ∈ closure s) (hy : y ∈ interior s) {a b : ℝ} (ha : 0 ≤ a) (hb : 0 < b) (hab : a + b = 1) : +lemma convex.combo_closure_interior_mem_interior {s : set E} (hs : convex 𝕜 s) {x y : E} + (hx : x ∈ closure s) (hy : y ∈ interior s) {a b : 𝕜} (ha : 0 ≤ a) (hb : 0 < b) (hab : a + b = 1) : a • x + b • y ∈ interior s := hs.combo_closure_interior_subset_interior ha hb hab $ add_mem_add (smul_mem_smul_set hx) (smul_mem_smul_set hy) -lemma convex.combo_self_interior_mem_interior {s : set E} (hs : convex ℝ s) {x y : E} - (hx : x ∈ s) (hy : y ∈ interior s) {a b : ℝ} (ha : 0 ≤ a) (hb : 0 < b) (hab : a + b = 1) : +lemma convex.combo_self_interior_mem_interior {s : set E} (hs : convex 𝕜 s) {x y : E} + (hx : x ∈ s) (hy : y ∈ interior s) {a b : 𝕜} (ha : 0 ≤ a) (hb : 0 < b) (hab : a + b = 1) : a • x + b • y ∈ interior s := hs.combo_closure_interior_mem_interior (subset_closure hx) hy ha hb hab -lemma convex.open_segment_interior_closure_subset_interior {s : set E} (hs : convex ℝ s) {x y : E} - (hx : x ∈ interior s) (hy : y ∈ closure s) : open_segment ℝ x y ⊆ interior s := +lemma convex.open_segment_interior_closure_subset_interior {s : set E} (hs : convex 𝕜 s) {x y : E} + (hx : x ∈ interior s) (hy : y ∈ closure s) : open_segment 𝕜 x y ⊆ interior s := begin rintro _ ⟨a, b, ha, hb, hab, rfl⟩, exact hs.combo_interior_closure_mem_interior hx hy ha hb.le hab end -lemma convex.open_segment_interior_self_subset_interior {s : set E} (hs : convex ℝ s) {x y : E} - (hx : x ∈ interior s) (hy : y ∈ s) : open_segment ℝ x y ⊆ interior s := +lemma convex.open_segment_interior_self_subset_interior {s : set E} (hs : convex 𝕜 s) {x y : E} + (hx : x ∈ interior s) (hy : y ∈ s) : open_segment 𝕜 x y ⊆ interior s := hs.open_segment_interior_closure_subset_interior hx (subset_closure hy) -lemma convex.open_segment_closure_interior_subset_interior {s : set E} (hs : convex ℝ s) {x y : E} - (hx : x ∈ closure s) (hy : y ∈ interior s) : open_segment ℝ x y ⊆ interior s := +lemma convex.open_segment_closure_interior_subset_interior {s : set E} (hs : convex 𝕜 s) {x y : E} + (hx : x ∈ closure s) (hy : y ∈ interior s) : open_segment 𝕜 x y ⊆ interior s := begin rintro _ ⟨a, b, ha, hb, hab, rfl⟩, exact hs.combo_closure_interior_mem_interior hx hy ha.le hb hab end -lemma convex.open_segment_self_interior_subset_interior {s : set E} (hs : convex ℝ s) {x y : E} - (hx : x ∈ s) (hy : y ∈ interior s) : open_segment ℝ x y ⊆ interior s := +lemma convex.open_segment_self_interior_subset_interior {s : set E} (hs : convex 𝕜 s) {x y : E} + (hx : x ∈ s) (hy : y ∈ interior s) : open_segment 𝕜 x y ⊆ interior s := hs.open_segment_closure_interior_subset_interior (subset_closure hx) hy /-- If `x ∈ closure s` and `y ∈ interior s`, then the segment `(x, y]` is included in `interior s`. -/ -lemma convex.add_smul_sub_mem_interior' {s : set E} (hs : convex ℝ s) - {x y : E} (hx : x ∈ closure s) (hy : y ∈ interior s) {t : ℝ} (ht : t ∈ Ioc (0 : ℝ) 1) : +lemma convex.add_smul_sub_mem_interior' {s : set E} (hs : convex 𝕜 s) + {x y : E} (hx : x ∈ closure s) (hy : y ∈ interior s) {t : 𝕜} (ht : t ∈ Ioc (0 : 𝕜) 1) : x + t • (y - x) ∈ interior s := by simpa only [sub_smul, smul_sub, one_smul, add_sub, add_comm] using hs.combo_interior_closure_mem_interior hy hx ht.1 (sub_nonneg.mpr ht.2) (add_sub_cancel'_right _ _) /-- If `x ∈ s` and `y ∈ interior s`, then the segment `(x, y]` is included in `interior s`. -/ -lemma convex.add_smul_sub_mem_interior {s : set E} (hs : convex ℝ s) - {x y : E} (hx : x ∈ s) (hy : y ∈ interior s) {t : ℝ} (ht : t ∈ Ioc (0 : ℝ) 1) : +lemma convex.add_smul_sub_mem_interior {s : set E} (hs : convex 𝕜 s) + {x y : E} (hx : x ∈ s) (hy : y ∈ interior s) {t : 𝕜} (ht : t ∈ Ioc (0 : 𝕜) 1) : x + t • (y - x) ∈ interior s := hs.add_smul_sub_mem_interior' (subset_closure hx) hy ht /-- If `x ∈ closure s` and `x + y ∈ interior s`, then `x + t y ∈ interior s` for `t ∈ (0, 1]`. -/ -lemma convex.add_smul_mem_interior' {s : set E} (hs : convex ℝ s) - {x y : E} (hx : x ∈ closure s) (hy : x + y ∈ interior s) {t : ℝ} (ht : t ∈ Ioc (0 : ℝ) 1) : +lemma convex.add_smul_mem_interior' {s : set E} (hs : convex 𝕜 s) + {x y : E} (hx : x ∈ closure s) (hy : x + y ∈ interior s) {t : 𝕜} (ht : t ∈ Ioc (0 : 𝕜) 1) : x + t • y ∈ interior s := by simpa only [add_sub_cancel'] using hs.add_smul_sub_mem_interior' hx hy ht /-- If `x ∈ s` and `x + y ∈ interior s`, then `x + t y ∈ interior s` for `t ∈ (0, 1]`. -/ -lemma convex.add_smul_mem_interior {s : set E} (hs : convex ℝ s) - {x y : E} (hx : x ∈ s) (hy : x + y ∈ interior s) {t : ℝ} (ht : t ∈ Ioc (0 : ℝ) 1) : +lemma convex.add_smul_mem_interior {s : set E} (hs : convex 𝕜 s) + {x y : E} (hx : x ∈ s) (hy : x + y ∈ interior s) {t : 𝕜} (ht : t ∈ Ioc (0 : 𝕜) 1) : x + t • y ∈ interior s := hs.add_smul_mem_interior' (subset_closure hx) hy ht /-- In a topological vector space, the interior of a convex set is convex. -/ -protected lemma convex.interior {s : set E} (hs : convex ℝ s) : convex ℝ (interior s) := +protected lemma convex.interior {s : set E} (hs : convex 𝕜 s) : convex 𝕜 (interior s) := convex_iff_open_segment_subset.mpr $ λ x y hx hy, hs.open_segment_closure_interior_subset_interior (interior_subset_closure hx) hy /-- In a topological vector space, the closure of a convex set is convex. -/ -protected lemma convex.closure {s : set E} (hs : convex ℝ s) : convex ℝ (closure s) := +protected lemma convex.closure {s : set E} (hs : convex 𝕜 s) : convex 𝕜 (closure s) := λ x y hx hy a b ha hb hab, let f : E → E → E := λ x' y', a • x' + b • y' in have hf : continuous (λ p : E × E, f p.1 p.2), from From 46563c5c2671172990076960d2f3374290815831 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Mon, 25 Apr 2022 06:24:09 +0000 Subject: [PATCH 233/373] refactor(analysis/convex/basic): rewrite a few proofs (#13658) * prove that a closed segment is the union of the corresponding open segment and the endpoints; * use this lemma to golf some proofs; * make the "field" argument of `mem_open_segment_of_ne_left_right` implicit. * use section variables. --- src/analysis/convex/basic.lean | 55 ++++++++++++++++---------------- src/analysis/convex/extreme.lean | 18 ++++------- 2 files changed, 34 insertions(+), 39 deletions(-) diff --git a/src/analysis/convex/basic.lean b/src/analysis/convex/basic.lean index 9ff7d4cbc233f..c3b4b10c672a0 100644 --- a/src/analysis/convex/basic.lean +++ b/src/analysis/convex/basic.lean @@ -109,42 +109,42 @@ segment_symm 𝕜 y x ▸ left_mem_segment 𝕜 y x end mul_action_with_zero section module -variables (𝕜) [module 𝕜 E] +variables (𝕜) [module 𝕜 E] {x y z : E} {s : set E} @[simp] lemma segment_same (x : E) : [x -[𝕜] x] = {x} := set.ext $ λ z, ⟨λ ⟨a, b, ha, hb, hab, hz⟩, by simpa only [(add_smul _ _ _).symm, mem_singleton_iff, hab, one_smul, eq_comm] using hz, λ h, mem_singleton_iff.1 h ▸ left_mem_segment 𝕜 z z⟩ -lemma mem_open_segment_of_ne_left_right {x y z : E} (hx : x ≠ z) (hy : y ≠ z) - (hz : z ∈ [x -[𝕜] y]) : - z ∈ open_segment 𝕜 x y := +lemma insert_endpoints_open_segment (x y : E) : + insert x (insert y (open_segment 𝕜 x y)) = [x -[𝕜] y] := begin - obtain ⟨a, b, ha, hb, hab, hz⟩ := hz, - by_cases ha' : a = 0, - { rw [ha', zero_add] at hab, - rw [ha', hab, zero_smul, one_smul, zero_add] at hz, - exact (hy hz).elim }, - by_cases hb' : b = 0, - { rw [hb', add_zero] at hab, - rw [hb', hab, zero_smul, one_smul, add_zero] at hz, - exact (hx hz).elim }, - exact ⟨a, b, ha.lt_of_ne (ne.symm ha'), hb.lt_of_ne (ne.symm hb'), hab, hz⟩, + simp only [subset_antisymm_iff, insert_subset, left_mem_segment, right_mem_segment, + open_segment_subset_segment, true_and], + rintro z ⟨a, b, ha, hb, hab, rfl⟩, + refine hb.eq_or_gt.imp _ (λ hb', ha.eq_or_gt.imp _ _), + { rintro rfl, + rw add_zero at hab, + rw [hab, one_smul, zero_smul, add_zero] }, + { rintro rfl, + rw zero_add at hab, + rw [hab, one_smul, zero_smul, zero_add] }, + { exact λ ha', ⟨a, b, ha', hb', hab, rfl⟩ } end variables {𝕜} -lemma open_segment_subset_iff_segment_subset {x y : E} {s : set E} (hx : x ∈ s) (hy : y ∈ s) : - open_segment 𝕜 x y ⊆ s ↔ [x -[𝕜] y] ⊆ s := +lemma mem_open_segment_of_ne_left_right (hx : x ≠ z) (hy : y ≠ z) (hz : z ∈ [x -[𝕜] y]) : + z ∈ open_segment 𝕜 x y := begin - refine ⟨λ h z hz, _, (open_segment_subset_segment 𝕜 x y).trans⟩, - obtain rfl | hxz := eq_or_ne x z, - { exact hx }, - obtain rfl | hyz := eq_or_ne y z, - { exact hy }, - exact h (mem_open_segment_of_ne_left_right 𝕜 hxz hyz hz), + rw [← insert_endpoints_open_segment] at hz, + exact ((hz.resolve_left hx.symm).resolve_left hy.symm) end +lemma open_segment_subset_iff_segment_subset (hx : x ∈ s) (hy : y ∈ s) : + open_segment 𝕜 x y ⊆ s ↔ [x -[𝕜] y] ⊆ s := +by simp only [← insert_endpoints_open_segment, insert_subset, *, true_and] + end module end ordered_semiring @@ -299,10 +299,9 @@ section linear_ordered_field variables [linear_ordered_field 𝕜] section add_comm_group -variables [add_comm_group E] [add_comm_group F] [module 𝕜 E] [module 𝕜 F] +variables [add_comm_group E] [add_comm_group F] [module 𝕜 E] [module 𝕜 F] {x y z : E} -lemma mem_segment_iff_same_ray {x y z : E} : - x ∈ [y -[𝕜] z] ↔ same_ray 𝕜 (x - y) (z - x) := +lemma mem_segment_iff_same_ray : x ∈ [y -[𝕜] z] ↔ same_ray 𝕜 (x - y) (z - x) := begin refine ⟨same_ray_of_mem_segment, λ h, _⟩, rcases h.exists_eq_smul_add with ⟨a, b, ha, hb, hab, hxy, hzx⟩, @@ -312,7 +311,7 @@ begin rw [← sub_eq_neg_add, ← neg_sub, hxy, ← sub_eq_neg_add, hzx, smul_neg, smul_comm, neg_add_self] end -lemma mem_segment_iff_div {x y z : E} : x ∈ [y -[𝕜] z] ↔ +lemma mem_segment_iff_div : x ∈ [y -[𝕜] z] ↔ ∃ a b : 𝕜, 0 ≤ a ∧ 0 ≤ b ∧ 0 < a + b ∧ (a / (a + b)) • y + (b / (a + b)) • z = x := begin split, @@ -324,7 +323,7 @@ begin rw [← add_div, div_self hab.ne'] } end -lemma mem_open_segment_iff_div {x y z : E} : x ∈ open_segment 𝕜 y z ↔ +lemma mem_open_segment_iff_div : x ∈ open_segment 𝕜 y z ↔ ∃ a b : 𝕜, 0 < a ∧ 0 < b ∧ (a / (a + b)) • y + (b / (a + b)) • z = x := begin split, @@ -427,7 +426,7 @@ end (segment_subset_Icc h).antisymm Icc_subset_segment lemma Ioo_subset_open_segment {x y : 𝕜} : Ioo x y ⊆ open_segment 𝕜 x y := -λ z hz, mem_open_segment_of_ne_left_right _ hz.1.ne hz.2.ne' +λ z hz, mem_open_segment_of_ne_left_right hz.1.ne hz.2.ne' (Icc_subset_segment $ Ioo_subset_Icc_self hz) @[simp] lemma open_segment_eq_Ioo {x y : 𝕜} (h : x < y) : open_segment 𝕜 x y = Ioo x y := diff --git a/src/analysis/convex/extreme.lean b/src/analysis/convex/extreme.lean index 8d2ad46d0e88a..cde58f3eb43ff 100644 --- a/src/analysis/convex/extreme.lean +++ b/src/analysis/convex/extreme.lean @@ -194,18 +194,14 @@ that contain it are those with `x` as one of their endpoints. -/ lemma mem_extreme_points_iff_forall_segment : x ∈ A.extreme_points 𝕜 ↔ x ∈ A ∧ ∀ (x₁ x₂ ∈ A), x ∈ segment 𝕜 x₁ x₂ → x₁ = x ∨ x₂ = x := begin + refine and_congr_right (λ hxA, forall₄_congr $ λ x₁ h₁ x₂ h₂, _), split, - { rintro ⟨hxA, hAx⟩, - use hxA, - rintro x₁ hx₁ x₂ hx₂ hx, - by_contra' h, - exact h.1 (hAx _ hx₁ _ hx₂ (mem_open_segment_of_ne_left_right 𝕜 h.1 h.2 hx)).1 }, - rintro ⟨hxA, hAx⟩, - use hxA, - rintro x₁ x₂ hx₁ hx₂ hx, - obtain rfl | rfl := hAx x₁ x₂ hx₁ hx₂ (open_segment_subset_segment 𝕜 _ _ hx), - { exact ⟨rfl, (left_mem_open_segment_iff.1 hx).symm⟩ }, - exact ⟨right_mem_open_segment_iff.1 hx, rfl⟩, + { rw ← insert_endpoints_open_segment, + rintro H (rfl|rfl|hx), + exacts [or.inl rfl, or.inr rfl, or.inl $ (H hx).1] }, + { intros H hx, + rcases H (open_segment_subset_segment _ _ _ hx) with rfl | rfl, + exacts [⟨rfl, (left_mem_open_segment_iff.1 hx).symm⟩, ⟨right_mem_open_segment_iff.1 hx, rfl⟩] } end lemma convex.mem_extreme_points_iff_convex_diff (hA : convex 𝕜 A) : From feb9aed43e1e971fbf49f970afcefeae2875d1e6 Mon Sep 17 00:00:00 2001 From: tb65536 Date: Mon, 25 Apr 2022 06:24:10 +0000 Subject: [PATCH 234/373] feat(group_theory/group_action/basic): More API for `quotient_action` (#13661) This PR adds a couple more API lemmas for `quotient_action`. --- src/group_theory/group_action/basic.lean | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/group_theory/group_action/basic.lean b/src/group_theory/group_action/basic.lean index 9fe4dd48e4658..c95c5a19ebfb7 100644 --- a/src/group_theory/group_action/basic.lean +++ b/src/group_theory/group_action/basic.lean @@ -342,11 +342,19 @@ attribute [to_additive add_action.quotient_action] mul_action.quotient_action variables {β} -@[simp, to_additive] lemma quotient.smul_mk [quotient_action β H] (a : β) (x : α) : - (a • quotient_group.mk x : α ⧸ H) = quotient_group.mk (a • x) := rfl +@[simp, to_additive] lemma quotient.smul_mk [quotient_action β H] (b : β) (a : α) : + (b • quotient_group.mk a : α ⧸ H) = quotient_group.mk (b • a) := rfl -@[simp, to_additive] lemma quotient.smul_coe [quotient_action β H] (a : β) (x : α) : - (a • x : α ⧸ H) = ↑(a • x) := rfl +@[simp, to_additive] lemma quotient.smul_coe [quotient_action β H] (b : β) (a : α) : + (b • a : α ⧸ H) = ↑(b • a) := rfl + +@[simp, to_additive] lemma quotient.mk_smul_out' [quotient_action β H] (b : β) (q : α ⧸ H) : + quotient_group.mk (b • q.out') = b • q := +by rw [←quotient.smul_mk, quotient_group.out_eq'] + +@[simp, to_additive] lemma quotient.coe_smul_out' [quotient_action β H] (b : β) (q : α ⧸ H) : + ↑(b • q.out') = b • q := +quotient.mk_smul_out' H b q end quotient_action From b0fe3cd219318ec22f24510332104e29eca8bfc5 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Mon, 25 Apr 2022 06:24:11 +0000 Subject: [PATCH 235/373] feat(order/filter): add `filter.coprod_bot` etc (#13662) --- src/order/filter/basic.lean | 8 ++++++++ src/order/filter/pi.lean | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/order/filter/basic.lean b/src/order/filter/basic.lean index 0716d02eb10bc..6c7da4b3ae4f0 100644 --- a/src/order/filter/basic.lean +++ b/src/order/filter/basic.lean @@ -2729,6 +2729,14 @@ lemma mem_coprod_iff {s : set (α×β)} {f : filter α} {g : filter β} : s ∈ f.coprod g ↔ ((∃ t₁ ∈ f, prod.fst ⁻¹' t₁ ⊆ s) ∧ (∃ t₂ ∈ g, prod.snd ⁻¹' t₂ ⊆ s)) := by simp [filter.coprod] +@[simp] lemma bot_coprod (l : filter β) : (⊥ : filter α).coprod l = comap prod.snd l := +by simp [filter.coprod] + +@[simp] lemma coprod_bot (l : filter α) : l.coprod (⊥ : filter β) = comap prod.fst l := +by simp [filter.coprod] + +lemma bot_coprod_bot : (⊥ : filter α).coprod (⊥ : filter β) = ⊥ := by simp + @[mono] lemma coprod_mono {f₁ f₂ : filter α} {g₁ g₂ : filter β} (hf : f₁ ≤ f₂) (hg : g₁ ≤ g₂) : f₁.coprod g₁ ≤ f₂.coprod g₂ := sup_le_sup (comap_mono hf) (comap_mono hg) diff --git a/src/order/filter/pi.lean b/src/order/filter/pi.lean index 2db1f99282954..b95e4576f5da8 100644 --- a/src/order/filter/pi.lean +++ b/src/order/filter/pi.lean @@ -169,6 +169,17 @@ by simp only [filter.Coprod, supr_ne_bot, ← exists_and_distrib_left, ← comap ne_bot (filter.Coprod f) ↔ ∃ d, ne_bot (f d) := by simp [Coprod_ne_bot_iff', *] +lemma Coprod_eq_bot_iff' : filter.Coprod f = ⊥ ↔ (∃ i, is_empty (α i)) ∨ f = ⊥ := +by simpa [not_and_distrib, funext_iff] using not_congr Coprod_ne_bot_iff' + +@[simp] lemma Coprod_eq_bot_iff [∀ i, nonempty (α i)] : filter.Coprod f = ⊥ ↔ f = ⊥ := +by simpa [funext_iff] using not_congr Coprod_ne_bot_iff + +@[simp] lemma Coprod_bot' : filter.Coprod (⊥ : Π i, filter (α i)) = ⊥ := +Coprod_eq_bot_iff'.2 (or.inr rfl) + +@[simp] lemma Coprod_bot : filter.Coprod (λ _, ⊥ : Π i, filter (α i)) = ⊥ := Coprod_bot' + lemma ne_bot.Coprod [∀ i, nonempty (α i)] {i : ι} (h : ne_bot (f i)) : ne_bot (filter.Coprod f) := Coprod_ne_bot_iff.2 ⟨i, h⟩ From ef3769db865bc1ca19d4886a51553928c23193ac Mon Sep 17 00:00:00 2001 From: tb65536 Date: Mon, 25 Apr 2022 06:24:12 +0000 Subject: [PATCH 236/373] feat(group_theory/subgroup/basic): Cyclic subgroups are commutative (#13663) This PR adds an instance stating that the cyclic subgroups `zpowers g` are commutative. --- src/group_theory/subgroup/basic.lean | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/group_theory/subgroup/basic.lean b/src/group_theory/subgroup/basic.lean index 2582b885efd70..ffaa9db910d7d 100644 --- a/src/group_theory/subgroup/basic.lean +++ b/src/group_theory/subgroup/basic.lean @@ -2648,6 +2648,14 @@ begin exact of_mul_image_zpowers_eq_zmultiples_of_mul, end +namespace subgroup + +@[to_additive] instance zpowers_is_commutative (g : G) : (zpowers g).is_commutative := +⟨⟨λ ⟨_, _, h₁⟩ ⟨_, _, h₂⟩, by rw [subtype.ext_iff, coe_mul, coe_mul, + subtype.coe_mk, subtype.coe_mk, ←h₁, ←h₂, zpow_mul_comm]⟩⟩ + +end subgroup + namespace monoid_hom variables {G' : Type*} [group G'] From f02c78444da3ce58a92e8ac79e6cec48e8b0f9c7 Mon Sep 17 00:00:00 2001 From: loefflerd Date: Mon, 25 Apr 2022 08:04:54 +0000 Subject: [PATCH 237/373] feat(special_functions/gamma): recurrence relation for Gamma function (#13156) Co-authored-by: Yury G. Kudryashov --- src/analysis/special_functions/gamma.lean | 230 +++++++++++++++++++++- 1 file changed, 220 insertions(+), 10 deletions(-) diff --git a/src/analysis/special_functions/gamma.lean b/src/analysis/special_functions/gamma.lean index e3156f7f087c2..f94a333f6ad96 100644 --- a/src/analysis/special_functions/gamma.lean +++ b/src/analysis/special_functions/gamma.lean @@ -8,15 +8,17 @@ import measure_theory.integral.exp_decay /-! # The Gamma function -This file treats Euler's integral for the `Γ` function, `∫ x in Ioi 0, exp (-x) * x ^ (s - 1)`, for -`s` a real or complex variable. +This file defines the `Γ` function (of a real or complex variable `s`). We define this by Euler's +integral `Γ(s) = ∫ x in Ioi 0, exp (-x) * x ^ (s - 1)` in a range where we can prove this is +convergent: presently `1 ≤ s` in the real case, and `1 ≤ re s` in the complex case (which is +non-optimal, but the optimal bound of `0 < s`, resp `0 < re s`, is harder to prove using the +methods in the library). -We prove convergence of the integral for `1 ≤ s` in the real case, and `1 ≤ re s` in the complex -case (which is non-optimal, but the optimal bound of `0 < s`, resp `0 < re s`, is harder to prove -using the methods in the library). We also show `Γ(1) = 1`. +We show that this integral satisfies `Γ(1) = 1` and `Γ(s + 1) = s * Γ(s)`; hence we can define +`Γ(s)` for all `s` as the unique function satisfying this recurrence and agreeing with Euler's +integral in the convergence range. -The recurrence `Γ(s + 1) = s * Γ(s)`, holomorphy in `s`, and extension to the whole complex plane -will be added in future pull requests. +TODO: Holomorpy in `s` (away from the poles at `-n : n ∈ ℕ`) will be added in a future PR. ## Tags @@ -75,13 +77,17 @@ by simpa only [Gamma_integral, sub_self, rpow_zero, mul_one] using integral_exp_ end real namespace complex +/- Technical note: In defining the Gamma integrand exp (-x) * x ^ (s - 1) for s complex, we have to +make a choice between ↑(real.exp (-x)), complex.exp (↑(-x)), and complex.exp (-↑x), all of which are +equal but not definitionally so. We use the first of these throughout. -/ + /-- The integral defining the Γ function converges for complex `s` with `1 ≤ re s`. This is proved by reduction to the real case. The bound is not optimal, but the optimal bound (convergence for `0 < re s`) is hard to establish with the results currently in the library. -/ lemma Gamma_integral_convergent {s : ℂ} (hs : 1 ≤ s.re) : - integrable_on (λ x:ℝ, real.exp (-x) * x ^ (s - 1) : ℝ → ℂ) (Ioi 0) := + integrable_on (λ x, (-x).exp * x ^ (s - 1) : ℝ → ℂ) (Ioi 0) := begin -- This is slightly subtle if `s` is non-real but `s.re = 1`, as the integrand is not continuous -- at the lower endpoint. However, it is continuous on the interior, and its norm is continuous @@ -98,7 +104,7 @@ begin refine has_finite_integral.congr (real.Gamma_integral_convergent hs).2 _, refine (ae_restrict_iff' measurable_set_Ioi).mpr (ae_of_all _ (λ x hx, _)), dsimp only, - rw [complex.norm_eq_abs, complex.abs_mul, complex.abs_of_nonneg $ le_of_lt $ exp_pos $ -x, + rw [norm_eq_abs, abs_mul, abs_of_nonneg $ le_of_lt $ exp_pos $ -x, abs_cpow_eq_rpow_re_of_pos hx _], simp } end @@ -108,7 +114,7 @@ end See `complex.Gamma_integral_convergent` for a proof of the convergence of the integral for `1 ≤ re s`. -/ -def Gamma_integral (s : ℂ) : ℂ := ∫ x in Ioi (0:ℝ), ↑(real.exp (-x)) * ↑x ^ (s - 1) +def Gamma_integral (s : ℂ) : ℂ := ∫ x in Ioi (0:ℝ), ↑(-x).exp * ↑x ^ (s - 1) lemma Gamma_integral_of_real (s : ℝ) : Gamma_integral ↑s = ↑(s.Gamma_integral) := @@ -127,3 +133,207 @@ begin end end complex + +/-! Now we establish the recurrence relation `Γ(s + 1) = s * Γ(s)` using integration by parts. -/ + +namespace complex + +section Gamma_recurrence + +/-- The indefinite version of the Γ function, Γ(s, X) = ∫ x ∈ 0..X, exp(-x) x ^ (s - 1). -/ +def partial_Gamma (s : ℂ) (X : ℝ) : ℂ := ∫ x in 0..X, (-x).exp * x ^ (s - 1) + +lemma tendsto_partial_Gamma {s : ℂ} (hs: 1 ≤ s.re) : + tendsto (λ X:ℝ, partial_Gamma s X) at_top (𝓝 $ Gamma_integral s) := +interval_integral_tendsto_integral_Ioi 0 (Gamma_integral_convergent hs) tendsto_id + +private lemma Gamma_integrand_interval_integrable (s : ℂ) {X : ℝ} (hs : 1 ≤ s.re) (hX : 0 ≤ X): + interval_integrable (λ x, (-x).exp * x ^ (s - 1) : ℝ → ℂ) volume 0 X := +begin + rw interval_integrable_iff_integrable_Ioc_of_le hX, + exact integrable_on.mono_set (Gamma_integral_convergent hs) Ioc_subset_Ioi_self +end + +private lemma Gamma_integrand_deriv_integrable_A {s : ℂ} (hs: 1 ≤ s.re) {X : ℝ} (hX : 0 ≤ X): + interval_integrable (λ x, -((-x).exp * x ^ s) : ℝ → ℂ) volume 0 X := +begin + have t := (Gamma_integrand_interval_integrable (s+1) _ hX).neg, + { simpa using t }, + { simp only [add_re, one_re], linarith,}, +end + +private lemma Gamma_integrand_deriv_integrable_B {s : ℂ} (hs: 1 ≤ s.re) {Y : ℝ} (hY : 0 ≤ Y) : + interval_integrable (λ (x : ℝ), (-x).exp * (s * x ^ (s - 1)) : ℝ → ℂ) volume 0 Y := +begin + have: (λ x, (-x).exp * (s * x ^ (s - 1)) : ℝ → ℂ) = + (λ x, s * ((-x).exp * x ^ (s - 1)) : ℝ → ℂ) := by { ext1, ring, }, + rw [this, interval_integrable_iff_integrable_Ioc_of_le hY], + split, + { refine (continuous_on_const.mul _).ae_strongly_measurable measurable_set_Ioc, + apply (continuous_of_real.comp continuous_neg.exp).continuous_on.mul, + apply continuous_at.continuous_on, + intros x hx, + refine (_ : continuous_at (λ x:ℂ, x ^ (s - 1)) _).comp continuous_of_real.continuous_at, + apply continuous_at_cpow_const, rw of_real_re, exact or.inl hx.1, }, + apply has_finite_integral_of_bounded, swap, exact s.abs * Y ^ (s.re - 1), + refine (ae_restrict_iff' measurable_set_Ioc).mpr (ae_of_all _ (λ x hx, _)), + rw [norm_eq_abs, abs_mul,abs_mul, abs_of_nonneg (exp_pos(-x)).le], + refine mul_le_mul_of_nonneg_left _ (abs_nonneg s), + have i1: (-x).exp ≤ 1 := by { simpa using hx.1.le, }, + have i2: abs (↑x ^ (s - 1)) ≤ Y ^ (s.re - 1), + { rw [abs_cpow_eq_rpow_re_of_pos hx.1 _, sub_re, one_re], + apply rpow_le_rpow hx.1.le hx.2, linarith, }, + simpa using mul_le_mul i1 i2 (abs_nonneg (↑x ^ (s - 1))) zero_le_one, +end + +/-- The recurrence relation for the indefinite version of the Γ function. -/ +lemma partial_Gamma_add_one {s : ℂ} (hs: 1 ≤ s.re) {X : ℝ} (hX : 0 ≤ X) : + partial_Gamma (s + 1) X = s * partial_Gamma s X - (-X).exp * X ^ s := +begin + rw [partial_Gamma, partial_Gamma, add_sub_cancel], + have F_der_I: (∀ (x:ℝ), (x ∈ Ioo 0 X) → has_deriv_at (λ x, (-x).exp * x ^ s : ℝ → ℂ) + ( -((-x).exp * x ^ s) + (-x).exp * (s * x ^ (s - 1))) x), + { intros x hx, + have d1 : has_deriv_at (λ (y: ℝ), (-y).exp) (-(-x).exp) x, + { simpa using (has_deriv_at_neg x).exp }, + have d1b : has_deriv_at (λ y, ↑(-y).exp : ℝ → ℂ) (↑-(-x).exp) x, + { convert has_deriv_at.scomp x of_real_clm.has_deriv_at d1, simp, }, + have d2: has_deriv_at (λ (y : ℝ), ↑y ^ s) (s * x ^ (s - 1)) x, + { have t := @has_deriv_at.cpow_const _ _ _ s (has_deriv_at_id ↑x), + simp only [id.def, of_real_re, of_real_im, + ne.def, eq_self_iff_true, not_true, or_false, mul_one] at t, + simpa using has_deriv_at.comp x (t hx.left) of_real_clm.has_deriv_at, }, + simpa only [of_real_neg, neg_mul] using d1b.mul d2 }, + have cont := (continuous_of_real.comp continuous_neg.exp).mul + (continuous_of_real_cpow_const $ lt_of_lt_of_le zero_lt_one hs), + have der_ible := (Gamma_integrand_deriv_integrable_A hs hX).add + (Gamma_integrand_deriv_integrable_B hs hX), + have int_eval := integral_eq_sub_of_has_deriv_at_of_le hX cont.continuous_on F_der_I der_ible, + -- We are basically done here but manipulating the output into the right form is fiddly. + apply_fun (λ x:ℂ, -x) at int_eval, + rw [interval_integral.integral_add (Gamma_integrand_deriv_integrable_A hs hX) + (Gamma_integrand_deriv_integrable_B hs hX), interval_integral.integral_neg, neg_add, neg_neg] + at int_eval, + replace int_eval := eq_sub_of_add_eq int_eval, + rw [int_eval, sub_neg_eq_add, neg_sub, add_comm, add_sub], + simp only [sub_left_inj, add_left_inj], + have : (λ x, (-x).exp * (s * x ^ (s - 1)) : ℝ → ℂ) = (λ x, s * (-x).exp * x ^ (s - 1) : ℝ → ℂ), + { ext1, ring,}, + rw this, + have t := @integral_const_mul (0:ℝ) X volume _ _ s (λ x:ℝ, (-x).exp * x ^ (s - 1)), + dsimp at t, rw [←t, of_real_zero, zero_cpow], + { rw [mul_zero, add_zero], congr', ext1, ring }, + { contrapose! hs, rw [hs, zero_re], exact zero_lt_one,} +end + +/-- The recurrence relation for the Γ integral. -/ +theorem Gamma_integral_add_one {s : ℂ} (hs: 1 ≤ s.re) : + Gamma_integral (s + 1) = s * Gamma_integral s := +begin + suffices : tendsto (s+1).partial_Gamma at_top (𝓝 $ s * Gamma_integral s), + { refine tendsto_nhds_unique _ this, + apply tendsto_partial_Gamma, rw [add_re, one_re], linarith, }, + have : (λ X:ℝ, s * partial_Gamma s X - X ^ s * (-X).exp) =ᶠ[at_top] (s+1).partial_Gamma, + { apply eventually_eq_of_mem (Ici_mem_at_top (0:ℝ)), + intros X hX, + rw partial_Gamma_add_one hs (mem_Ici.mp hX), + ring_nf, }, + refine tendsto.congr' this _, + suffices : tendsto (λ X, -X ^ s * (-X).exp : ℝ → ℂ) at_top (𝓝 0), + { simpa using tendsto.add (tendsto.const_mul s (tendsto_partial_Gamma hs)) this }, + rw tendsto_zero_iff_norm_tendsto_zero, + have : (λ (e : ℝ), ∥-(e:ℂ) ^ s * (-e).exp∥ ) =ᶠ[at_top] (λ (e : ℝ), e ^ s.re * (-1 * e).exp ), + { refine eventually_eq_of_mem (Ioi_mem_at_top 0) _, + intros x hx, dsimp only, + rw [norm_eq_abs, abs_mul, abs_neg, abs_cpow_eq_rpow_re_of_pos hx, + abs_of_nonneg (exp_pos(-x)).le, neg_mul, one_mul],}, + exact (tendsto_congr' this).mpr (tendsto_rpow_mul_exp_neg_mul_at_top_nhds_0 _ _ zero_lt_one), +end + +end Gamma_recurrence + +/-! Now we define `Γ(s)` on the whole complex plane, by recursion. -/ + +section Gamma_def + +/-- Th `n`th function in this family is `Γ(s)` if `1-n ≤ s.re`, and junk otherwise. -/ +noncomputable def Gamma_aux : ℕ → (ℂ → ℂ) +| 0 := Gamma_integral +| (n+1) := λ s:ℂ, (Gamma_aux n (s+1)) / s + +lemma Gamma_aux_recurrence1 (s : ℂ) (n : ℕ) (h1 : 1 - s.re ≤ ↑n) : + Gamma_aux n s = Gamma_aux n (s+1) / s := +begin + induction n with n hn generalizing s, + { simp only [nat.cast_zero, sub_nonpos] at h1, + dsimp only [Gamma_aux], rw Gamma_integral_add_one h1, + rw [mul_comm, mul_div_cancel], contrapose! h1, rw h1, + simp }, + { dsimp only [Gamma_aux], + have hh1 : 1 - (s+1).re ≤ n, + { rw [nat.succ_eq_add_one, nat.cast_add, nat.cast_one] at h1, + rw [add_re, one_re], linarith, }, + rw ←(hn (s+1) hh1) } +end + +lemma Gamma_aux_recurrence2 (s : ℂ) (n : ℕ) (h1 : 1 - s.re ≤ ↑n) : + Gamma_aux n s = Gamma_aux (n+1) s := +begin + cases n, + { simp only [nat.cast_zero, sub_nonpos] at h1, + dsimp only [Gamma_aux], rw Gamma_integral_add_one h1, + have : s ≠ 0 := by { contrapose! h1, rw h1, simp, }, + field_simp, ring }, + { dsimp only [Gamma_aux], + have : (Gamma_aux n (s + 1 + 1)) / (s+1) = Gamma_aux n (s + 1), + { have hh1 : 1 - (s+1).re ≤ n, + { rw [nat.succ_eq_add_one, nat.cast_add, nat.cast_one] at h1, + rw [add_re, one_re], linarith, }, + rw Gamma_aux_recurrence1 (s+1) n hh1, }, + rw this }, +end + +/-- The `Γ` function (of a complex variable `s`). -/ +def Gamma (s : ℂ) : ℂ := Gamma_aux ⌈ 1 - s.re ⌉₊ s + +lemma Gamma_eq_Gamma_aux (s : ℂ) (n : ℕ) (h1 : 1 - s.re ≤ ↑n) : Gamma s = Gamma_aux n s := +begin + have u : ∀ (k : ℕ), Gamma_aux (⌈ 1 - s.re ⌉₊ + k) s = Gamma s, + { intro k, induction k with k hk, + { simp [Gamma],}, + { rw [←hk, nat.succ_eq_add_one, ←add_assoc], + refine (Gamma_aux_recurrence2 s (⌈ 1 - s.re ⌉₊ + k) _).symm, + rw nat.cast_add, + have i1 := nat.le_ceil (1 - s.re), + refine le_add_of_le_of_nonneg i1 _, + rw [←nat.cast_zero, nat.cast_le], exact nat.zero_le k, } }, + rw [←nat.add_sub_of_le (nat.ceil_le.mpr h1), u (n - ⌈ 1 - s.re ⌉₊)], +end + +/-- The recurrence relation for the Γ function. -/ +theorem Gamma_add_one (s : ℂ) (h2 : s ≠ 0) : Gamma (s+1) = s * Gamma s := +begin + let n := ⌈ 1 - s.re ⌉₊, + have t1 : 1 - s.re ≤ n := nat.le_ceil (1 - s.re), + have t2 : 1 - (s+1).re ≤ n := by { rw [add_re, one_re], linarith, }, + rw [Gamma_eq_Gamma_aux s n t1, Gamma_eq_Gamma_aux (s+1) n t2, Gamma_aux_recurrence1 s n t1], + field_simp, ring +end + +theorem Gamma_eq_integral (s : ℂ) (hs : 1 ≤ s.re) : Gamma s = Gamma_integral s := +begin + refine Gamma_eq_Gamma_aux s 0 (_ : _ ≤ 0), linarith +end + +theorem Gamma_nat_eq_factorial (n : ℕ) : Gamma (n+1) = nat.factorial n := +begin + induction n with n hn, + { rw [nat.cast_zero, zero_add], rw Gamma_eq_integral, + simpa using Gamma_integral_one, simp,}, + rw (Gamma_add_one n.succ $ nat.cast_ne_zero.mpr $ nat.succ_ne_zero n), + { simp only [nat.cast_succ, nat.factorial_succ, nat.cast_mul], congr, exact hn }, +end + +end Gamma_def + +end complex From e059fdf93769567f8645ad9bb04679e4cdcf1ef8 Mon Sep 17 00:00:00 2001 From: Eric Rodriguez Date: Mon, 25 Apr 2022 08:04:55 +0000 Subject: [PATCH 238/373] feat(algebra/big_operators/basic): mk0_prod (#13582) Co-authored-by: Alex J Best --- src/algebra/big_operators/basic.lean | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/algebra/big_operators/basic.lean b/src/algebra/big_operators/basic.lean index 6aa45a6135c7f..fda86da3426e1 100644 --- a/src/algebra/big_operators/basic.lean +++ b/src/algebra/big_operators/basic.lean @@ -1673,6 +1673,11 @@ end multiset (s : finset α) : (↑∏ i in s, f i : M) = ∏ i in s, f i := (units.coe_hom M).map_prod _ _ +lemma units.mk0_prod [comm_group_with_zero β] (s : finset α) (f : α → β) (h) : + units.mk0 (∏ b in s, f b) h = + ∏ b in s.attach, units.mk0 (f b) (λ hh, h (finset.prod_eq_zero b.2 hh)) := +by { classical, induction s using finset.induction_on; simp* } + lemma nat_abs_sum_le {ι : Type*} (s : finset ι) (f : ι → ℤ) : (∑ i in s, f i).nat_abs ≤ ∑ i in s, (f i).nat_abs := begin From e251ef778688feb93fdcda1d84a9508acb6511b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Mon, 25 Apr 2022 08:04:56 +0000 Subject: [PATCH 239/373] feat(logic/basic): `congr_fun` for heterogeneous equality (#13591) Co-authored-by: Bhavik Mehta <@b-mehta> --- src/logic/basic.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/logic/basic.lean b/src/logic/basic.lean index 0dbc7530909b1..fd821f5aee3ce 100644 --- a/src/logic/basic.lean +++ b/src/logic/basic.lean @@ -885,6 +885,10 @@ lemma heq_of_cast_eq : ∀ {α β : Sort*} {a : α} {a' : β} (e : α = β) (h₂ : cast e a = a'), a == a' | α ._ a a' rfl h := eq.rec_on h (heq.refl _) +lemma congr_fun_heq {α β γ : Sort*} {f : α → γ} {g : β → γ} (h₁ : β = α) (h₂ : f == g) (x : β) : + f (cast h₁ x) = g x := +by { subst h₁, rw [eq_of_heq h₂, cast_eq] } + lemma cast_eq_iff_heq {α β : Sort*} {a : α} {a' : β} {e : α = β} : cast e a = a' ↔ a == a' := ⟨heq_of_cast_eq _, λ h, by cases h; refl⟩ From d795ea4b354c9d6f8f152259f5957ef6562d9c01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Mon, 25 Apr 2022 08:04:57 +0000 Subject: [PATCH 240/373] feat(number_theory/legendre_symbol/quadratic_reciprocity): Alternate forms of `exists_sq_eq_neg_one` (#13594) Also, renamed `exists_sq_eq_neg_one_iff_mod_four_ne_three` to `exists_sq_eq_neg_one` for consistency with `exists_sq_eq_two` and for convenience. --- archive/imo/imo2008_q3.lean | 2 +- .../quadratic_reciprocity.lean | 22 +++++++++++++++++-- src/number_theory/zsqrtd/gaussian_int.lean | 2 +- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/archive/imo/imo2008_q3.lean b/archive/imo/imo2008_q3.lean index fe9e04c0d0ffc..5c929bf992742 100644 --- a/archive/imo/imo2008_q3.lean +++ b/archive/imo/imo2008_q3.lean @@ -33,7 +33,7 @@ lemma p_lemma (p : ℕ) (hpp : nat.prime p) (hp_mod_4_eq_1 : p ≡ 1 [MOD 4]) (h begin haveI := fact.mk hpp, have hp_mod_4_ne_3 : p % 4 ≠ 3, { linarith [(show p % 4 = 1, by exact hp_mod_4_eq_1)] }, - obtain ⟨y, hy⟩ := (zmod.exists_sq_eq_neg_one_iff_mod_four_ne_three p).mpr hp_mod_4_ne_3, + obtain ⟨y, hy⟩ := (zmod.exists_sq_eq_neg_one_iff p).mpr hp_mod_4_ne_3, let m := zmod.val_min_abs y, let n := int.nat_abs m, diff --git a/src/number_theory/legendre_symbol/quadratic_reciprocity.lean b/src/number_theory/legendre_symbol/quadratic_reciprocity.lean index 6466075dc6dba..8b85e7576175a 100644 --- a/src/number_theory/legendre_symbol/quadratic_reciprocity.lean +++ b/src/number_theory/legendre_symbol/quadratic_reciprocity.lean @@ -24,7 +24,7 @@ interpretations in terms of existence of square roots depending on the congruenc `exists_sq_eq_prime_iff_of_mod_four_eq_three`. Also proven are conditions for `-1` and `2` to be a square modulo a prime, -`exists_sq_eq_neg_one_iff_mod_four_ne_three` and +`exists_sq_eq_neg_one_iff` and `exists_sq_eq_two_iff` ## Implementation notes @@ -72,7 +72,7 @@ begin refine ⟨units.mk0 y hy, _⟩, simp, } end -lemma exists_sq_eq_neg_one_iff_mod_four_ne_three : +lemma exists_sq_eq_neg_one_iff : (∃ y : zmod p, y ^ 2 = -1) ↔ p % 4 ≠ 3 := begin cases nat.prime.eq_two_or_odd (fact.out p.prime) with hp2 hp_odd, @@ -94,6 +94,24 @@ begin generalize : p % 4 = k, dec_trivial! } end +lemma mod_four_ne_three_of_sq_eq_neg_one {y : zmod p} (hy : y ^ 2 = -1) : p % 4 ≠ 3 := +(exists_sq_eq_neg_one_iff p).1 ⟨y, hy⟩ + +lemma mod_four_ne_three_of_sq_eq_neg_sq' {x y : zmod p} (hy : y ≠ 0) (hxy : x ^ 2 = - y ^ 2) : + p % 4 ≠ 3 := +@mod_four_ne_three_of_sq_eq_neg_one p _ (x / y) begin + apply_fun (λ z, z / y ^ 2) at hxy, + rwa [neg_div, ←div_pow, ←div_pow, div_self hy, one_pow] at hxy +end + +lemma mod_four_ne_three_of_sq_eq_neg_sq {x y : zmod p} (hx : x ≠ 0) (hxy : x ^ 2 = - y ^ 2) : + p % 4 ≠ 3 := +begin + apply_fun (λ x, -x) at hxy, + rw neg_neg at hxy, + exact mod_four_ne_three_of_sq_eq_neg_sq' p hx hxy.symm +end + lemma pow_div_two_eq_neg_one_or_one {a : zmod p} (ha : a ≠ 0) : a ^ (p / 2) = 1 ∨ a ^ (p / 2) = -1 := begin diff --git a/src/number_theory/zsqrtd/gaussian_int.lean b/src/number_theory/zsqrtd/gaussian_int.lean index b9a527cb7f8a4..e0d1bffc7230c 100644 --- a/src/number_theory/zsqrtd/gaussian_int.lean +++ b/src/number_theory/zsqrtd/gaussian_int.lean @@ -205,7 +205,7 @@ hp.1.eq_two_or_odd.elim revert this hp3 hp1, generalize : p % 4 = m, dec_trivial!, end, - let ⟨k, hk⟩ := (zmod.exists_sq_eq_neg_one_iff_mod_four_ne_three p).2 $ + let ⟨k, hk⟩ := (zmod.exists_sq_eq_neg_one_iff p).2 $ by rw hp41; exact dec_trivial in begin obtain ⟨k, k_lt_p, rfl⟩ : ∃ (k' : ℕ) (h : k' < p), (k' : zmod p) = k, From b35ed4006c2c88fea4c272a6380bafcfd6d2e3b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Mon, 25 Apr 2022 08:04:59 +0000 Subject: [PATCH 241/373] feat(algebra/order/hom/ring): There's at most one hom between linear ordered fields (#13601) There is at most one ring homomorphism from a linear ordered field to an archimedean linear ordered field. Also generalize `map_rat_cast` to take in `ring_hom_class`. Co-authored-by: Alex J. Best --- src/algebra/order/hom/ring.lean | 54 +++++++++++++++++++++++++++++++++ src/algebra/star/basic.lean | 2 +- src/data/complex/basic.lean | 3 +- src/data/complex/is_R_or_C.lean | 2 +- src/data/rat/cast.lean | 12 ++++---- src/ring_theory/algebraic.lean | 2 +- 6 files changed, 64 insertions(+), 11 deletions(-) diff --git a/src/algebra/order/hom/ring.lean b/src/algebra/order/hom/ring.lean index 43a12081fed8d..7fbd7a488e2c5 100644 --- a/src/algebra/order/hom/ring.lean +++ b/src/algebra/order/hom/ring.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Alex J. Best, Yaël Dillies. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Alex J. Best, Yaël Dillies -/ +import algebra.order.archimedean import algebra.order.hom.monoid import algebra.order.ring import algebra.ring.equiv @@ -277,6 +278,10 @@ ext e.left_inv @[simp] lemma symm_trans_self (e : α ≃+*o β) : e.symm.trans e = order_ring_iso.refl β := ext e.right_inv +lemma symm_bijective : bijective (order_ring_iso.symm : (α ≃+*o β) → β ≃+*o α) := +⟨λ f g h, f.symm_symm.symm.trans $ (congr_arg order_ring_iso.symm h).trans g.symm_symm, + λ f, ⟨f.symm, f.symm_symm⟩⟩ + end has_le section non_assoc_semiring @@ -294,5 +299,54 @@ def to_order_ring_hom (f : α ≃+*o β) : α →+*o β := @[simp] lemma coe_to_order_ring_hom_refl : (order_ring_iso.refl α : α →+*o α) = order_ring_hom.id α := rfl +lemma to_order_ring_hom_injective : injective (to_order_ring_hom : (α ≃+*o β) → α →+*o β) := +λ f g h, fun_like.coe_injective $ by convert fun_like.ext'_iff.1 h + end non_assoc_semiring end order_ring_iso + +/-! +### Uniqueness + +There is at most one ordered ring homomorphism from a linear ordered field to an archimedean linear +ordered field. Reciprocally, such an ordered ring homomorphism exists when the codomain is further +conditionally complete. +-/ + +/-- There is at most one ordered ring homomorphism from a linear ordered field to an archimedean +linear ordered field. -/ +-- TODO[gh-6025]: make this an instance once safe to do so +lemma order_ring_hom.subsingleton [linear_ordered_field α] [linear_ordered_field β] + [archimedean β] : + subsingleton (α →+*o β) := +⟨λ f g, begin + ext x, + by_contra' h, + wlog h : f x < g x using [f g, g f], + { exact ne.lt_or_lt h }, + obtain ⟨q, hf, hg⟩ := exists_rat_btwn h, + rw ←map_rat_cast f at hf, + rw ←map_rat_cast g at hg, + exact (lt_asymm ((order_hom_class.mono g).reflect_lt hg) $ + (order_hom_class.mono f).reflect_lt hf).elim, +end⟩ + +local attribute [instance] order_ring_hom.subsingleton + +/-- There is at most one ordered ring isomorphism between a linear ordered field and an archimedean +linear ordered field. -/ +-- TODO[gh-6025]: make this an instance once safe to do so +lemma order_ring_iso.subsingleton_right [linear_ordered_field α] [linear_ordered_field β] + [archimedean β] : + subsingleton (α ≃+*o β) := +order_ring_iso.to_order_ring_hom_injective.subsingleton + +local attribute [instance] order_ring_iso.subsingleton_right + +/-- There is at most one ordered ring isomorphism between an archimedean linear ordered field and a +linear ordered field. -/ +-- TODO[gh-6025]: make this an instance once safe to do so +lemma order_ring_iso.subsingleton_left [linear_ordered_field α] [archimedean α] + [linear_ordered_field β] : + subsingleton (α ≃+*o β) := +order_ring_iso.symm_bijective.injective.subsingleton diff --git a/src/algebra/star/basic.lean b/src/algebra/star/basic.lean index c2438f516341c..f4e19a3065b54 100644 --- a/src/algebra/star/basic.lean +++ b/src/algebra/star/basic.lean @@ -264,7 +264,7 @@ def star_ring_equiv [non_unital_semiring R] [star_ring R] : R ≃+* Rᵐᵒᵖ : @[simp, norm_cast] lemma star_rat_cast [division_ring R] [char_zero R] [star_ring R] (r : ℚ) : star (r : R) = r := -(congr_arg unop ((star_ring_equiv : R ≃+* Rᵐᵒᵖ).to_ring_hom.map_rat_cast r)).trans (unop_rat_cast _) +(congr_arg unop $ map_rat_cast (star_ring_equiv : R ≃+* Rᵐᵒᵖ) r).trans (unop_rat_cast _) /-- `star` as a ring automorphism, for commutative `R`. -/ @[simps apply] diff --git a/src/data/complex/basic.lean b/src/data/complex/basic.lean index abc0a81f71de2..7baeb45472365 100644 --- a/src/data/complex/basic.lean +++ b/src/data/complex/basic.lean @@ -400,8 +400,7 @@ by rw [← of_real_int_cast, of_real_re] @[simp, norm_cast] lemma int_cast_im (n : ℤ) : (n : ℂ).im = 0 := by rw [← of_real_int_cast, of_real_im] -@[simp, norm_cast] theorem of_real_rat_cast (n : ℚ) : ((n : ℝ) : ℂ) = n := -of_real.map_rat_cast n +@[simp, norm_cast] theorem of_real_rat_cast (n : ℚ) : ((n : ℝ) : ℂ) = n := map_rat_cast of_real n @[simp, norm_cast] lemma rat_cast_re (q : ℚ) : (q : ℂ).re = q := by rw [← of_real_rat_cast, of_real_re] diff --git a/src/data/complex/is_R_or_C.lean b/src/data/complex/is_R_or_C.lean index f3f745ec9da35..657f93b727416 100644 --- a/src/data/complex/is_R_or_C.lean +++ b/src/data/complex/is_R_or_C.lean @@ -442,7 +442,7 @@ by rw [← of_real_int_cast, of_real_im] @[simp, is_R_or_C_simps, norm_cast, priority 900] theorem of_real_rat_cast (n : ℚ) : ((n : ℝ) : K) = n := -(@is_R_or_C.of_real_hom K _).map_rat_cast n +map_rat_cast (@is_R_or_C.of_real_hom K _) n @[simp, is_R_or_C_simps, norm_cast] lemma rat_cast_re (q : ℚ) : re (q : K) = q := by rw [← of_real_rat_cast, of_real_re] diff --git a/src/data/rat/cast.lean b/src/data/rat/cast.lean index 4cf0c6ab01636..b189dcb98467d 100644 --- a/src/data/rat/cast.lean +++ b/src/data/rat/cast.lean @@ -24,8 +24,9 @@ casting lemmas showing the well-behavedness of this injection. rat, rationals, field, ℚ, numerator, denominator, num, denom, cast, coercion, casting -/ +variables {F α β : Type*} + namespace rat -variable {α : Type*} open_locale rat section with_div_ring @@ -271,10 +272,9 @@ calc f r = f (r.1 / r.2) : by rw [← int.cast_coe_nat, ← mk_eq_div, num_denom -- This seems to be true for a `[char_p k]` too because `k'` must have the same characteristic -- but the proof would be much longer -lemma ring_hom.map_rat_cast {k k'} [division_ring k] [char_zero k] [division_ring k'] - (f : k →+* k') (r : ℚ) : - f r = r := -(f.comp (cast_hom k)).eq_rat_cast r +@[simp] lemma map_rat_cast [division_ring α] [division_ring β] [char_zero α] [ring_hom_class F α β] + (f : F) (q : ℚ) : f q = q := +((f : α →+* β).comp $ cast_hom α).eq_rat_cast q lemma ring_hom.ext_rat {R : Type*} [semiring R] (f g : ℚ →+* R) : f = g := begin @@ -325,7 +325,7 @@ end monoid_with_zero_hom namespace mul_opposite -variables {α : Type*} [division_ring α] +variables [division_ring α] @[simp, norm_cast] lemma op_rat_cast (r : ℚ) : op (r : α) = (↑r : αᵐᵒᵖ) := by rw [cast_def, div_eq_mul_inv, op_mul, op_inv, op_nat_cast, op_int_cast, diff --git a/src/ring_theory/algebraic.lean b/src/ring_theory/algebraic.lean index 4563dcd834d70..fb1e19c6d3816 100644 --- a/src/ring_theory/algebraic.lean +++ b/src/ring_theory/algebraic.lean @@ -101,7 +101,7 @@ by { rw ←ring_hom.map_int_cast (algebra_map R A), exact is_algebraic_algebra_m lemma is_algebraic_rat (R : Type u) {A : Type v} [division_ring A] [field R] [char_zero R] [algebra R A] (n : ℚ) : is_algebraic R (n : A) := -by { rw ←ring_hom.map_rat_cast (algebra_map R A), exact is_algebraic_algebra_map n } +by { rw ←map_rat_cast (algebra_map R A), exact is_algebraic_algebra_map n } lemma is_algebraic_algebra_map_of_is_algebraic {a : S} : is_algebraic R a → is_algebraic R (algebra_map S A a) := From 6710d655487dbfac4a3c6fb00d5a0bd5062e3f0d Mon Sep 17 00:00:00 2001 From: Eric Rodriguez Date: Mon, 25 Apr 2022 10:43:44 +0000 Subject: [PATCH 242/373] feat(analysis/complex/roots_of_unity): arg of a primitive root (#13583) --- src/analysis/complex/roots_of_unity.lean | 57 ++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/analysis/complex/roots_of_unity.lean b/src/analysis/complex/roots_of_unity.lean index 12a43533616f4..69b5a6ed11723 100644 --- a/src/analysis/complex/roots_of_unity.lean +++ b/src/analysis/complex/roots_of_unity.lean @@ -114,3 +114,60 @@ lemma is_primitive_root.arg_eq_pi_iff {n : ℕ} {ζ : ℂ} (hζ : is_primitive_r (hn : n ≠ 0) : ζ.arg = real.pi ↔ ζ = -1 := ⟨λ h, hζ.arg_ext (is_primitive_root.neg_one 0 two_ne_zero.symm) hn two_ne_zero (h.trans complex.arg_neg_one.symm), λ h, h.symm ▸ complex.arg_neg_one⟩ + +lemma is_primitive_root.arg {n : ℕ} {ζ : ℂ} (h : is_primitive_root ζ n) (hn : n ≠ 0) : + ∃ i : ℤ, ζ.arg = i / n * (2 * real.pi) ∧ is_coprime i n ∧ i.nat_abs < n := +begin + rw complex.is_primitive_root_iff _ _ hn at h, + obtain ⟨i, h, hin, rfl⟩ := h, + rw [mul_comm, ←mul_assoc, complex.exp_mul_I], + refine ⟨if i * 2 ≤ n then i else i - n, _, _, _⟩, + work_on_goal 2 + { replace hin := nat.is_coprime_iff_coprime.mpr hin, + split_ifs with _, + { exact hin }, + { convert hin.add_mul_left_left (-1), + rw [mul_neg_one, sub_eq_add_neg] } }, + work_on_goal 2 + { split_ifs with h₂, + { exact_mod_cast h }, + suffices : (i - n : ℤ).nat_abs = n - i, + { rw this, + apply tsub_lt_self hn.bot_lt, + contrapose! h₂, + rw [nat.eq_zero_of_le_zero h₂, zero_mul], + exact zero_le _ }, + rw [←int.nat_abs_neg, neg_sub, int.nat_abs_eq_iff], + exact or.inl (int.coe_nat_sub h.le).symm }, + split_ifs with h₂, + { convert complex.arg_cos_add_sin_mul_I _, + { push_cast }, + { push_cast }, + field_simp [hn], + refine ⟨(neg_lt_neg real.pi_pos).trans_le _, _⟩, + { rw neg_zero, + exact mul_nonneg (mul_nonneg i.cast_nonneg $ by simp [real.pi_pos.le]) (by simp) }, + rw [←mul_rotate', mul_div_assoc], + rw ←mul_one n at h₂, + exact mul_le_of_le_one_right real.pi_pos.le + ((div_le_iff' $ by exact_mod_cast (pos_of_gt h)).mpr $ by exact_mod_cast h₂) }, + rw [←complex.cos_sub_two_pi, ←complex.sin_sub_two_pi], + convert complex.arg_cos_add_sin_mul_I _, + { push_cast, + rw [←sub_one_mul, sub_div, div_self], + exact_mod_cast hn }, + { push_cast, + rw [←sub_one_mul, sub_div, div_self], + exact_mod_cast hn }, + field_simp [hn], + refine ⟨_, le_trans _ real.pi_pos.le⟩, + work_on_goal 2 + { rw [mul_div_assoc], + exact mul_nonpos_of_nonpos_of_nonneg (sub_nonpos.mpr $ by exact_mod_cast h.le) + (div_nonneg (by simp [real.pi_pos.le]) $ by simp) }, + rw [←mul_rotate', mul_div_assoc, neg_lt, ←mul_neg, mul_lt_iff_lt_one_right real.pi_pos, + ←neg_div, ←neg_mul, neg_sub, div_lt_iff, one_mul, sub_mul, sub_lt, ←mul_sub_one], + norm_num, + exact_mod_cast not_le.mp h₂, + { exact (nat.cast_pos.mpr hn.bot_lt) } +end From ad0a3e66eb1677b0c613837cf8f1e0c44d6073f6 Mon Sep 17 00:00:00 2001 From: tb65536 Date: Mon, 25 Apr 2022 11:19:19 +0000 Subject: [PATCH 243/373] feat(dynamics/periodic_pts): Iteration is injective below the period (#13660) This PR adds `iterate_injective_of_lt_minimal_period`, generalizing `pow_injective_of_lt_order_of`. --- src/dynamics/periodic_pts.lean | 13 +++++++++++++ src/group_theory/order_of_element.lean | 17 +---------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/dynamics/periodic_pts.lean b/src/dynamics/periodic_pts.lean index a968566bd3c16..57b561ff6ce97 100644 --- a/src/dynamics/periodic_pts.lean +++ b/src/dynamics/periodic_pts.lean @@ -237,6 +237,9 @@ begin { exact is_periodic_pt_zero f x } end +lemma iterate_minimal_period (f : α → α) (x : α) : f^[minimal_period f x] x = x := +is_periodic_pt_minimal_period f x + lemma iterate_eq_mod_minimal_period : f^[n] x = (f^[n % minimal_period f x] x) := ((is_periodic_pt_minimal_period f x).iterate_mod_apply n).symm @@ -261,6 +264,16 @@ begin exact nat.find_min' (mk_mem_periodic_pts hn hx) ⟨hn, hx⟩ end +lemma iterate_injective_of_lt_minimal_period (hm : m < minimal_period f x) + (hn : n < minimal_period f x) (hf : (f^[m] x) = (f^[n] x)) : m = n := +begin + wlog h_le : n ≤ m, + rw [←h_le.le_iff_eq, ←tsub_le_tsub_iff_left hm.le, tsub_le_iff_right], + apply is_periodic_pt.minimal_period_le (nat.add_pos_left (tsub_pos_of_lt hm) n), + rw [is_periodic_pt, is_fixed_pt, iterate_add_apply, ←hf, ←iterate_add_apply, + nat.sub_add_cancel hm.le, iterate_minimal_period], +end + lemma minimal_period_id : minimal_period id x = 1 := ((is_periodic_id _ _ ).minimal_period_le nat.one_pos).antisymm (nat.succ_le_of_lt ((is_periodic_id _ _ ).minimal_period_pos nat.one_pos)) diff --git a/src/group_theory/order_of_element.lean b/src/group_theory/order_of_element.lean index 06ba702839e36..3727877d18e75 100644 --- a/src/group_theory/order_of_element.lean +++ b/src/group_theory/order_of_element.lean @@ -317,25 +317,10 @@ end monoid_add_monoid section cancel_monoid variables [left_cancel_monoid G] (x y) -@[to_additive] -lemma pow_injective_aux (h : n ≤ m) - (hm : m < order_of x) (eq : x ^ n = x ^ m) : n = m := -by_contradiction $ assume ne : n ≠ m, - have h₁ : m - n > 0, from nat.pos_of_ne_zero (by simp [tsub_eq_iff_eq_add_of_le h, ne.symm]), - have h₂ : m = n + (m - n) := (add_tsub_cancel_of_le h).symm, - have h₃ : x ^ (m - n) = 1, - by { rw [h₂, pow_add] at eq, apply mul_left_cancel, convert eq.symm, exact mul_one (x ^ n) }, - have le : order_of x ≤ m - n, from order_of_le_of_pow_eq_one h₁ h₃, - have lt : m - n < order_of x, - from (tsub_lt_iff_left h).mpr $ nat.lt_add_left _ _ _ hm, - lt_irrefl _ (le.trans_lt lt) - @[to_additive nsmul_injective_of_lt_add_order_of] lemma pow_injective_of_lt_order_of (hn : n < order_of x) (hm : m < order_of x) (eq : x ^ n = x ^ m) : n = m := -(le_total n m).elim - (assume h, pow_injective_aux x h hm eq) - (assume h, (pow_injective_aux x h hn eq.symm).symm) +iterate_injective_of_lt_minimal_period hn hm (by simpa only [mul_left_iterate, mul_one]) @[to_additive mem_multiples_iff_mem_range_add_order_of'] lemma mem_powers_iff_mem_range_order_of' [decidable_eq G] (hx : 0 < order_of x) : From 6d3ca07ac8cf33b913db5fca95d246689ebbac13 Mon Sep 17 00:00:00 2001 From: tb65536 Date: Mon, 25 Apr 2022 11:19:20 +0000 Subject: [PATCH 244/373] feat(data/zmod/basic): `-1 : zmod n` lifts to `n - 1` (#13665) This PR adds a lemma stating that `-1 : zmod n` lifts to `n - 1 : R` for any ring `R`. The proof is surprisingly painful, but maybe someone can find a nicer way? --- src/data/zmod/basic.lean | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/data/zmod/basic.lean b/src/data/zmod/basic.lean index 4c5cbe8b11e2b..03cfd650ba189 100644 --- a/src/data/zmod/basic.lean +++ b/src/data/zmod/basic.lean @@ -443,6 +443,22 @@ begin rw [←zmod.int_coe_eq_int_coe_iff', int.cast_coe_nat, zmod.nat_cast_val, zmod.cast_id], end +@[simp] lemma val_neg_one (n : ℕ) : (-1 : zmod n.succ).val = n := +begin + rw [val, fin.coe_neg], + cases n, + { rw [nat.mod_one] }, + { rw [fin.coe_one, nat.succ_add_sub_one, nat.mod_eq_of_lt (nat.lt.base _)] }, +end + +/-- `-1 : zmod n` lifts to `n - 1 : R`. This avoids the characteristic assumption in `cast_neg`. -/ +lemma cast_neg_one {R : Type*} [ring R] (n : ℕ) : ↑(-1 : zmod n) = (n - 1 : R) := +begin + cases n, + { rw [int.cast_neg, int.cast_one, nat.cast_zero, zero_sub] }, + { rw [←nat_cast_val, val_neg_one, nat.cast_succ, add_sub_cancel] }, +end + lemma nat_coe_zmod_eq_iff (p : ℕ) (n : ℕ) (z : zmod p) [fact (0 < p)] : ↑n = z ↔ ∃ k, n = z.val + p * k := begin From ed10ba23b2186a65864c6b6e83edbb231d02519c Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 25 Apr 2022 11:19:21 +0000 Subject: [PATCH 245/373] feat(ring_theory/witt_vector/frobenius): add `witt_vector.frobenius_equiv` (#13666) This promotes the bijection to an equivalence with an explicit inverse --- src/ring_theory/witt_vector/frobenius.lean | 15 ++++++++++----- .../witt_vector/frobenius_fraction_field.lean | 5 ++--- src/ring_theory/witt_vector/isocrystal.lean | 4 ++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/ring_theory/witt_vector/frobenius.lean b/src/ring_theory/witt_vector/frobenius.lean index c82d9e76a9d64..a0d22a0ece08a 100644 --- a/src/ring_theory/witt_vector/frobenius.lean +++ b/src/ring_theory/witt_vector/frobenius.lean @@ -318,13 +318,18 @@ lemma frobenius_zmodp (x : 𝕎 (zmod p)) : by simp only [ext_iff, coeff_frobenius_char_p, zmod.pow_card, eq_self_iff_true, forall_const] variables (p R) +/-- `witt_vector.frobenius` as an equiv. -/ +@[simps {fully_applied := ff}] +def frobenius_equiv [perfect_ring R p] : witt_vector p R ≃+* witt_vector p R := +{ to_fun := witt_vector.frobenius, + inv_fun := map (pth_root R p), + left_inv := λ f, ext $ λ n, by { rw frobenius_eq_map_frobenius, exact pth_root_frobenius _ }, + right_inv := λ f, ext $ λ n, by { rw frobenius_eq_map_frobenius, exact frobenius_pth_root _ }, + ..(witt_vector.frobenius : witt_vector p R →+* witt_vector p R) } + lemma frobenius_bijective [perfect_ring R p] : function.bijective (@witt_vector.frobenius p R _ _) := -begin - rw witt_vector.frobenius_eq_map_frobenius, - exact ⟨witt_vector.map_injective _ (frobenius_equiv R p).injective, - witt_vector.map_surjective _ (frobenius_equiv R p).surjective⟩, -end +(frobenius_equiv p R).bijective end char_p diff --git a/src/ring_theory/witt_vector/frobenius_fraction_field.lean b/src/ring_theory/witt_vector/frobenius_fraction_field.lean index 4b2806e3c7572..b8df1f484e2a9 100644 --- a/src/ring_theory/witt_vector/frobenius_fraction_field.lean +++ b/src/ring_theory/witt_vector/frobenius_fraction_field.lean @@ -219,8 +219,7 @@ begin refl } end -local notation `φ` := is_fraction_ring.field_equiv_of_ring_equiv - (ring_equiv.of_bijective _ (frobenius_bijective p k)) +local notation `φ` := is_fraction_ring.field_equiv_of_ring_equiv (frobenius_equiv p k) lemma exists_frobenius_solution_fraction_ring {a : fraction_ring (𝕎 k)} (ha : a ≠ 0) : ∃ (b : fraction_ring (𝕎 k)) (hb : b ≠ 0) (m : ℤ), φ b * a = p ^ m * b := @@ -250,7 +249,7 @@ begin simp only [is_fraction_ring.field_equiv_of_ring_equiv, is_localization.ring_equiv_of_ring_equiv_eq, ring_equiv.coe_of_bijective], convert congr_arg (λ x, algebra_map (𝕎 k) (fraction_ring (𝕎 k)) x) key using 1, - { simp only [ring_hom.map_mul, ring_hom.map_pow, map_nat_cast], + { simp only [ring_hom.map_mul, ring_hom.map_pow, map_nat_cast, frobenius_equiv_apply], ring }, { simp only [ring_hom.map_mul, ring_hom.map_pow, map_nat_cast] } end diff --git a/src/ring_theory/witt_vector/isocrystal.lean b/src/ring_theory/witt_vector/isocrystal.lean index 937c49f8a1f3f..1dce9a1916f94 100644 --- a/src/ring_theory/witt_vector/isocrystal.lean +++ b/src/ring_theory/witt_vector/isocrystal.lean @@ -66,8 +66,8 @@ variables [is_domain k] [char_p k p] [perfect_ring k p] /-! ### Frobenius-linear maps -/ /-- The Frobenius automorphism of `k` induces an automorphism of `K`. -/ -def fraction_ring.frobenius : K(p, k) ≃+* K(p, k) := is_fraction_ring.field_equiv_of_ring_equiv - (ring_equiv.of_bijective _ (witt_vector.frobenius_bijective p k)) +def fraction_ring.frobenius : K(p, k) ≃+* K(p, k) := +is_fraction_ring.field_equiv_of_ring_equiv (frobenius_equiv p k) /-- The Frobenius automorphism of `k` induces an endomorphism of `K`. For notation purposes. -/ def fraction_ring.frobenius_ring_hom : K(p, k) →+* K(p, k) := fraction_ring.frobenius p k From 7231172eaa3b3436657ad3b58f6cf0af606b20d2 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 25 Apr 2022 11:19:22 +0000 Subject: [PATCH 246/373] feat(topology/algebra): actions on the opposite type are continuous (#13671) This also adds the missing `t2_space` instance. --- src/topology/algebra/const_mul_action.lean | 5 +++++ src/topology/algebra/constructions.lean | 3 +++ src/topology/algebra/mul_action.lean | 4 ++++ src/topology/algebra/uniform_mul_action.lean | 8 +++++++- 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/topology/algebra/const_mul_action.lean b/src/topology/algebra/const_mul_action.lean index ce5ad16bd580a..04fb4e45d85d8 100644 --- a/src/topology/algebra/const_mul_action.lean +++ b/src/topology/algebra/const_mul_action.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Alex Kontorovich, Heather Macbeth. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Alex Kontorovich, Heather Macbeth -/ +import topology.algebra.constructions import topology.homeomorph import group_theory.group_action.basic /-! @@ -99,6 +100,10 @@ instance has_continuous_const_smul.op [has_scalar Mᵐᵒᵖ α] [is_central_sca has_continuous_const_smul Mᵐᵒᵖ α := ⟨ mul_opposite.rec $ λ c, by simpa only [op_smul_eq_smul] using continuous_const_smul c ⟩ +@[to_additive] instance mul_opposite.has_continuous_const_smul : + has_continuous_const_smul M αᵐᵒᵖ := +⟨λ c, mul_opposite.continuous_op.comp $ mul_opposite.continuous_unop.const_smul c⟩ + @[to_additive] instance [has_scalar M β] [has_continuous_const_smul M β] : has_continuous_const_smul M (α × β) := diff --git a/src/topology/algebra/constructions.lean b/src/topology/algebra/constructions.lean index 5492a346352d1..d41da27532151 100644 --- a/src/topology/algebra/constructions.lean +++ b/src/topology/algebra/constructions.lean @@ -36,6 +36,9 @@ continuous_induced_dom @[continuity, to_additive] lemma continuous_op : continuous (op : M → Mᵐᵒᵖ) := continuous_induced_rng continuous_id +@[to_additive] instance [t2_space M] : t2_space Mᵐᵒᵖ := +⟨λ x y h, separated_by_continuous mul_opposite.continuous_unop $ unop_injective.ne h⟩ + /-- `mul_opposite.op` as a homeomorphism. -/ @[to_additive "`add_opposite.op` as a homeomorphism."] def op_homeomorph : M ≃ₜ Mᵐᵒᵖ := diff --git a/src/topology/algebra/mul_action.lean b/src/topology/algebra/mul_action.lean index abbcdb4eca379..4f250aa67ba1a 100644 --- a/src/topology/algebra/mul_action.lean +++ b/src/topology/algebra/mul_action.lean @@ -110,6 +110,10 @@ instance has_continuous_smul.op [has_scalar Mᵐᵒᵖ X] [is_central_scalar M X from this.comp (mul_opposite.continuous_unop.prod_map continuous_id), by simpa only [op_smul_eq_smul] using (continuous_smul : continuous (λ p : M × X, _)) ⟩ +@[to_additive] instance mul_opposite.has_continuous_smul : has_continuous_smul M Xᵐᵒᵖ := +⟨mul_opposite.continuous_op.comp $ continuous_smul.comp $ + continuous_id.prod_map mul_opposite.continuous_unop⟩ + end has_scalar section monoid diff --git a/src/topology/algebra/uniform_mul_action.lean b/src/topology/algebra/uniform_mul_action.lean index 3079e25a568a8..6ea1087b57641 100644 --- a/src/topology/algebra/uniform_mul_action.lean +++ b/src/topology/algebra/uniform_mul_action.lean @@ -42,7 +42,9 @@ instance has_uniform_continuous_const_smul.to_has_continuous_const_smul [has_uniform_continuous_const_smul M X] : has_continuous_const_smul M X := ⟨λ c, (uniform_continuous_const_smul c).continuous⟩ -lemma uniform_continuous.const_smul [has_uniform_continuous_const_smul M X] +variables {M X Y} + +@[to_additive] lemma uniform_continuous.const_smul [has_uniform_continuous_const_smul M X] {f : Y → X} (hf : uniform_continuous f) (c : M) : uniform_continuous (c • f) := (uniform_continuous_const_smul c).comp hf @@ -57,6 +59,10 @@ instance has_uniform_continuous_const_smul.op [has_scalar Mᵐᵒᵖ X] [is_cent exact uniform_continuous_const_smul c, end⟩ +@[to_additive] instance mul_opposite.has_uniform_continuous_const_smul + [has_uniform_continuous_const_smul M X] : has_uniform_continuous_const_smul M Xᵐᵒᵖ := +⟨λ c, mul_opposite.uniform_continuous_op.comp $ mul_opposite.uniform_continuous_unop.const_smul c⟩ + end has_scalar @[to_additive] instance uniform_group.to_has_uniform_continuous_const_smul From 9e8d1075434eb7813e89d3b5a8bc9ea5c38b560f Mon Sep 17 00:00:00 2001 From: tb65536 Date: Mon, 25 Apr 2022 11:19:24 +0000 Subject: [PATCH 247/373] feat(dynamics/periodic_pts): `pow_smul_eq_iff_minimal_period_dvd` (#13676) This PR adds a lemma `pow_smul_eq_iff_minimal_period_dvd`, along with additive and integer versions. --- src/dynamics/periodic_pts.lean | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/dynamics/periodic_pts.lean b/src/dynamics/periodic_pts.lean index 57b561ff6ce97..004ee9f03663a 100644 --- a/src/dynamics/periodic_pts.lean +++ b/src/dynamics/periodic_pts.lean @@ -3,6 +3,7 @@ Copyright (c) 2020 Yury G. Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury G. Kudryashov -/ +import algebra.hom.iterate import data.nat.prime import dynamics.fixed_points.basic import data.pnat.basic @@ -382,3 +383,24 @@ minimal_period_iterate_eq_div_gcd_aux $ gcd_pos_of_pos_left n (minimal_period_pos_iff_mem_periodic_pts.mpr h) end function + +namespace mul_action + +open function + +variables {α β : Type*} [group α] [mul_action α β] {a : α} {b : β} + +@[to_additive] lemma pow_smul_eq_iff_minimal_period_dvd {n : ℕ} : + a ^ n • b = b ↔ function.minimal_period ((•) a) b ∣ n := +by rw [←is_periodic_pt_iff_minimal_period_dvd, is_periodic_pt, is_fixed_pt, smul_iterate] + +@[to_additive] lemma zpow_smul_eq_iff_minimal_period_dvd {n : ℤ} : + a ^ n • b = b ↔ (function.minimal_period ((•) a) b : ℤ) ∣ n := +begin + cases n, + { rw [int.of_nat_eq_coe, zpow_coe_nat, int.coe_nat_dvd, pow_smul_eq_iff_minimal_period_dvd] }, + { rw [int.neg_succ_of_nat_coe, zpow_neg, zpow_coe_nat, inv_smul_eq_iff, eq_comm, + dvd_neg, int.coe_nat_dvd, pow_smul_eq_iff_minimal_period_dvd] }, +end + +end mul_action From 4bfae3d821bb4cedf6b3dec0e0da0ee0b75f1490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Mon, 25 Apr 2022 11:19:25 +0000 Subject: [PATCH 248/373] feat(set_theory/game/pgame): remove nolint (#13680) We remove `@[nolint has_inhabited_instance]` from `left_moves` and `right_moves` by providing the appropriate instances for `star`. --- src/set_theory/game/pgame.lean | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/set_theory/game/pgame.lean b/src/set_theory/game/pgame.lean index 1efa0539c3346..516348ec8fd73 100644 --- a/src/set_theory/game/pgame.lean +++ b/src/set_theory/game/pgame.lean @@ -130,10 +130,10 @@ def of_lists (L R : list pgame.{0}) : pgame.{0} := pgame.mk (fin L.length) (fin R.length) (λ i, L.nth_le i i.is_lt) (λ j, R.nth_le j.val j.is_lt) /-- The indexing type for allowable moves by Left. -/ -@[nolint has_inhabited_instance] def left_moves : pgame → Type u +def left_moves : pgame → Type u | (mk l _ _ _) := l /-- The indexing type for allowable moves by Right. -/ -@[nolint has_inhabited_instance] def right_moves : pgame → Type u +def right_moves : pgame → Type u | (mk _ r _ _) := r /-- The new game after Left makes an allowed move. -/ @@ -1064,6 +1064,12 @@ theorem lt_iff_sub_pos {x y : pgame} : x < y ↔ 0 < y - x := /-- The pre-game `star`, which is fuzzy/confused with zero. -/ def star : pgame := pgame.of_lists [0] [0] +instance inhabited_star_left_moves : inhabited star.left_moves := +show (inhabited (fin 1)), by apply_instance + +instance inhabited_star_right_moves : inhabited star.right_moves := +show (inhabited (fin 1)), by apply_instance + theorem star_lt_zero : star < 0 := by rw lt_def; exact or.inr ⟨⟨0, zero_lt_one⟩, (by split; rintros ⟨⟩)⟩ From b7538a30c0c99748febfc2fa78d3b2f719e89b20 Mon Sep 17 00:00:00 2001 From: Oliver Nash Date: Mon, 25 Apr 2022 13:21:31 +0000 Subject: [PATCH 249/373] feat(algebra/periodic): add lemmas `periodic.prod`, `periodic.smul`, `antiperiodic.smul` (#13496) Formalized as part of the Sphere Eversion project. --- src/algebra/periodic.lean | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/algebra/periodic.lean b/src/algebra/periodic.lean index 8509217b9b751..987bef4bdd16b 100644 --- a/src/algebra/periodic.lean +++ b/src/algebra/periodic.lean @@ -31,6 +31,8 @@ period, periodic, periodicity, antiperiodic variables {α β γ : Type*} {f g : α → β} {c c₁ c₂ x : α} +open_locale big_operators + namespace function /-! ### Periodicity -/ @@ -66,6 +68,36 @@ lemma periodic.div [has_add α] [has_div β] periodic (f / g) c := by simp * at * +@[to_additive] +lemma _root_.list.periodic_prod [has_add α] [comm_monoid β] + (l : list (α → β)) (hl : ∀ f ∈ l, periodic f c) : + periodic l.prod c := +begin + induction l with g l ih hl, + { simp, }, + { simp only [list.mem_cons_iff, forall_eq_or_imp] at hl, + obtain ⟨hg, hl⟩ := hl, + simp only [list.prod_cons], + exact hg.mul (ih hl), }, +end + +@[to_additive] +lemma _root_.multiset.periodic_prod [has_add α] [comm_monoid β] + (s : multiset (α → β)) (hs : ∀ f ∈ s, periodic f c) : + periodic s.prod c := +s.prod_to_list ▸ s.to_list.periodic_prod $ λ f hf, hs f $ (multiset.mem_to_list f s).mp hf + +@[to_additive] +lemma _root_.finset.periodic_prod [has_add α] [comm_monoid β] + {ι : Type*} {f : ι → α → β} (s : finset ι) (hs : ∀ i ∈ s, periodic (f i) c) : + periodic (∏ i in s, f i) c := +s.prod_to_list f ▸ (s.to_list.map f).periodic_prod (by simpa [-periodic]) + +@[to_additive] +lemma periodic.smul [has_add α] [has_scalar γ β] (h : periodic f c) (a : γ) : + periodic (a • f) c := +by simp * at * + lemma periodic.const_smul [add_monoid α] [group γ] [distrib_mul_action γ α] (h : periodic f c) (a : γ) : periodic (λ x, f (a • x)) (a⁻¹ • c) := @@ -391,6 +423,11 @@ lemma antiperiodic.neg_eq [add_group α] [add_group β] f (-c) = -f 0 := by simpa only [zero_add] using h.neg 0 +lemma antiperiodic.smul [has_add α] [monoid γ] [add_group β] [distrib_mul_action γ β] + (h : antiperiodic f c) (a : γ) : + antiperiodic (a • f) c := +by simp * at * + lemma antiperiodic.const_smul [add_monoid α] [has_neg β] [group γ] [distrib_mul_action γ α] (h : antiperiodic f c) (a : γ) : antiperiodic (λ x, f (a • x)) (a⁻¹ • c) := From 14b0e32bb98611a1878742902a797d2b42be08f2 Mon Sep 17 00:00:00 2001 From: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> Date: Mon, 25 Apr 2022 13:21:32 +0000 Subject: [PATCH 250/373] chore(data/finsupp/fin): golf some proofs (#13607) --- src/data/finsupp/fin.lean | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/src/data/finsupp/fin.lean b/src/data/finsupp/fin.lean index 3c6e7b514ec68..e8ab345a5d6c9 100644 --- a/src/data/finsupp/fin.lean +++ b/src/data/finsupp/fin.lean @@ -36,7 +36,7 @@ finsupp.equiv_fun_on_fintype.inv_fun (fin.cons y s.to_fun) lemma tail_apply : tail t i = t i.succ := begin simp only [tail, equiv_fun_on_fintype_symm_apply_to_fun, equiv.inv_fun_as_coe], - congr, + refl, end @[simp] lemma cons_zero : cons y s 0 = y := @@ -53,7 +53,7 @@ begin simp only [finsupp.cons, fin.cons, finsupp.tail, fin.tail], ext, simp only [equiv_fun_on_fintype_symm_apply_to_fun, equiv.inv_fun_as_coe, - finsupp.coe_mk, fin.cases_succ, equiv_fun_on_fintype], + finsupp.coe_mk, fin.cases_succ, equiv_fun_on_fintype], refl, end @@ -68,46 +68,32 @@ end @[simp] lemma cons_zero_zero : cons 0 (0 : fin n →₀ M) = 0 := begin ext, - by_cases c : a ≠ 0, + by_cases c : a = 0, + { simp [c] }, { rw [←fin.succ_pred a c, cons_succ], simp }, - { simp only [not_not] at c, - simp [c] }, end variables {s} {y} lemma cons_ne_zero_of_left (h : y ≠ 0) : cons y s ≠ 0 := begin - by_contradiction c, - have h1 : cons y s 0 = 0 := by simp [c], - rw cons_zero at h1, - cc, + contrapose! h with c, + rw [←cons_zero y s, c, finsupp.coe_zero, pi.zero_apply], end lemma cons_ne_zero_of_right (h : s ≠ 0) : cons y s ≠ 0 := begin - by_contradiction c, - have h' : s = 0, - { ext, - simp [ ← cons_succ a y s, c] }, - cc, + contrapose! h with c, + ext, + simp [ ← cons_succ a y s, c], end lemma cons_ne_zero_iff : cons y s ≠ 0 ↔ y ≠ 0 ∨ s ≠ 0 := begin - apply iff.intro, - { intro h, - apply or_iff_not_imp_left.2, - intro h', - simp only [not_not] at h', - by_contra c, - rw [h', c] at h, - simpa using h }, - { intro h, - cases h, - { exact cons_ne_zero_of_left h }, - { exact cons_ne_zero_of_right h } }, + refine ⟨λ h, _, λ h, h.cases_on cons_ne_zero_of_left cons_ne_zero_of_right⟩, + refine imp_iff_not_or.1 (λ h' c, h _), + rw [h', c, finsupp.cons_zero_zero], end end finsupp From 2825f3534bbf0a65886edc0502cef42b83cdba4b Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Mon, 25 Apr 2022 13:21:34 +0000 Subject: [PATCH 251/373] feat(data/set/prod): add `set.eval_image_pi_subset` (#13613) Also reorder lemmas like `fst_image_prod_subset` so that simpler lemmas go first. --- src/data/set/prod.lean | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/data/set/prod.lean b/src/data/set/prod.lean index 6175c014cbcf1..4084dc924d300 100644 --- a/src/data/set/prod.lean +++ b/src/data/set/prod.lean @@ -193,20 +193,20 @@ by { rintro _ ⟨a, ha, rfl⟩, exact ⟨ha, hb⟩ } lemma image_prod_mk_subset_prod_right (ha : a ∈ s) : prod.mk a '' t ⊆ s ×ˢ t := by { rintro _ ⟨b, hb, rfl⟩, exact ⟨ha, hb⟩ } -lemma fst_image_prod_subset (s : set α) (t : set β) : prod.fst '' s ×ˢ t ⊆ s := -λ _ h, let ⟨_, ⟨h₂, _⟩, h₁⟩ := (set.mem_image _ _ _).1 h in h₁ ▸ h₂ - lemma prod_subset_preimage_fst (s : set α) (t : set β) : s ×ˢ t ⊆ prod.fst ⁻¹' s := -image_subset_iff.1 (fst_image_prod_subset s t) +inter_subset_left _ _ + +lemma fst_image_prod_subset (s : set α) (t : set β) : prod.fst '' s ×ˢ t ⊆ s := +image_subset_iff.2 $ prod_subset_preimage_fst s t lemma fst_image_prod (s : set β) {t : set α} (ht : t.nonempty) : prod.fst '' s ×ˢ t = s := (fst_image_prod_subset _ _).antisymm $ λ y hy, let ⟨x, hx⟩ := ht in ⟨(y, x), ⟨hy, hx⟩, rfl⟩ -lemma snd_image_prod_subset (s : set α) (t : set β) : prod.snd '' s ×ˢ t ⊆ t := -λ _ h, let ⟨_, ⟨_, h₂⟩, h₁⟩ := (set.mem_image _ _ _).1 h in h₁ ▸ h₂ - lemma prod_subset_preimage_snd (s : set α) (t : set β) : s ×ˢ t ⊆ prod.snd ⁻¹' t := -image_subset_iff.1 (snd_image_prod_subset s t) +inter_subset_right _ _ + +lemma snd_image_prod_subset (s : set α) (t : set β) : prod.snd '' s ×ˢ t ⊆ t := +image_subset_iff.2 $ prod_subset_preimage_snd s t lemma snd_image_prod {s : set α} (hs : s.nonempty) (t : set β) : prod.snd '' s ×ˢ t = t := (snd_image_prod_subset _ _).antisymm $ λ y y_in, let ⟨x, x_in⟩ := hs in ⟨(x, y), ⟨x_in, y_in⟩, rfl⟩ @@ -382,17 +382,19 @@ lemma univ_pi_update_univ [decidable_eq ι] (i : ι) (s : set (α i)) : pi univ (update (λ j : ι, (univ : set (α j))) i s) = eval i ⁻¹' s := by rw [univ_pi_update i (λ j, (univ : set (α j))) s (λ j t, t), pi_univ, inter_univ, preimage] +lemma eval_image_pi_subset (hs : i ∈ s) : eval i '' s.pi t ⊆ t i := +image_subset_iff.2 $ λ f hf, hf i hs + +lemma eval_image_univ_pi_subset : eval i '' pi univ t ⊆ t i := +eval_image_pi_subset (mem_univ i) + lemma eval_image_pi (hs : i ∈ s) (ht : (s.pi t).nonempty) : eval i '' s.pi t = t i := begin + refine (eval_image_pi_subset hs).antisymm _, classical, - ext x, obtain ⟨f, hf⟩ := ht, - refine ⟨_, λ hg, ⟨update f i x, λ j hj, _, by simp⟩⟩, - { rintro ⟨g, hg, rfl⟩, - exact hg i hs }, - { obtain rfl | hji := eq_or_ne j i, - { simp [hg] }, - { rw [mem_pi] at hf, simp [hji, hf _ hj] } } + refine λ y hy, ⟨update f i y, λ j hj, _, update_same _ _ _⟩, + obtain rfl | hji := eq_or_ne j i; simp [*, hf _ hj] end @[simp] lemma eval_image_univ_pi (ht : (pi univ t).nonempty) : From 2c15ce1454b837880c5444de85a2333da9caa5e7 Mon Sep 17 00:00:00 2001 From: Patrick Stevens Date: Mon, 25 Apr 2022 15:23:27 +0000 Subject: [PATCH 252/373] feat(data/nat/choose): add facts about the multiplicity of primes in the factorisation of central binomial coefficients (#9925) A number of bounds on the multiplicity of primes in the factorisation of central binomial coefficients. These are of interest because they form part of the proof of Bertrand's postulate. Co-authored-by: Johan Commelin --- src/data/nat/choose/central.lean | 106 +++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/src/data/nat/choose/central.lean b/src/data/nat/choose/central.lean index 36fa04c9d5c6e..47f7a5d197654 100644 --- a/src/data/nat/choose/central.lean +++ b/src/data/nat/choose/central.lean @@ -4,7 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Patrick Stevens, Thomas Browning -/ +import data.nat.prime import data.nat.choose.basic +import data.nat.choose.sum +import data.nat.multiplicity +import number_theory.padics.padic_norm import tactic.norm_num import tactic.linarith @@ -20,6 +24,12 @@ This file proves properties of the central binomial coefficients (that is, `nat. coefficients. * `nat.four_pow_lt_mul_central_binom`: an exponential lower bound on the central binomial coefficient. +* `nat.multiplicity_central_binom_le`: a logarithmic upper bound on the multiplicity of a prime in + the central binomial coefficient. +* `nat.multiplicity_central_binom_of_large_le_one`: sufficiently large primes appear at most once + in the factorisation of the central binomial coefficient. +* `nat.multiplicity_central_binom_of_large_eq_zero`: sufficiently large primes less than n do not + appear in the factorisation of the central binomial coefficient. -/ namespace nat @@ -98,4 +108,100 @@ lemma four_pow_le_two_mul_self_mul_central_binom : ∀ (n : ℕ) (n_pos : 0 < n) calc 4 ^ n ≤ n * central_binom n : (four_pow_lt_mul_central_binom _ le_add_self).le ... ≤ 2 * n * central_binom n : by { rw [mul_assoc], refine le_mul_of_pos_left zero_lt_two } +variables {p n : ℕ} + +/-- +A logarithmic upper bound on the multiplicity of a prime in the central binomial coefficient. +-/ +lemma padic_val_nat_central_binom_le (hp : p.prime) : + padic_val_nat p (central_binom n) ≤ log p (2 * n) := +begin + rw @padic_val_nat_def _ ⟨hp⟩ _ (central_binom_pos n), + unfold central_binom, + have two_n_sub : 2 * n - n = n, by rw [two_mul n, nat.add_sub_cancel n n], + simp only [nat.prime.multiplicity_choose hp (le_mul_of_pos_left zero_lt_two) (lt_add_one _), + two_n_sub, ←two_mul, enat.get_coe', finset.filter_congr_decidable], + calc _ ≤ (finset.Ico 1 (log p (2 * n) + 1)).card : finset.card_filter_le _ _ + ... = (log p (2 * n) + 1) - 1 : nat.card_Ico _ _, +end + +/-- +Sufficiently large primes appear only to multiplicity 0 or 1 in the central binomial coefficient. +-/ +lemma padic_val_nat_central_binom_of_large_le_one (hp : p.prime) (p_large : 2 * n < p ^ 2) : + (padic_val_nat p (central_binom n)) ≤ 1 := +begin + have log_weak_bound : log p (2 * n) ≤ 2, + { calc log p (2 * n) ≤ log p (p ^ 2) : log_le_log_of_le (le_of_lt p_large) + ... = 2 : log_pow hp.one_lt 2, }, + + have log_bound : log p (2 * n) ≤ 1, + { cases le_or_lt (log p (2 * n)) 1 with log_le lt_log, + { exact log_le, }, + { have v : log p (2 * n) = 2 := by linarith, + cases le_or_lt p (2 * n) with h h, + { exfalso, + rw [log_of_one_lt_of_le hp.one_lt h, succ_inj', log_eq_one_iff] at v, + have bad : p ^ 2 ≤ 2 * n, + { rw pow_two, + exact (nat.le_div_iff_mul_le _ _ (prime.pos hp)).1 v.2.2, }, + exact lt_irrefl _ (lt_of_le_of_lt bad p_large), }, + { rw log_eq_zero (or.inl h), + exact zero_le 1, }, }, }, + + exact le_trans (padic_val_nat_central_binom_le hp) log_bound, +end + +/-- +Sufficiently large primes less than `n` do not appear in the factorisation of `central_binom n`. +-/ +lemma padic_val_nat_central_binom_of_large_eq_zero + (hp : p.prime) (n_big : 2 < n) (p_le_n : p ≤ n) (big : 2 * n < 3 * p) : + padic_val_nat p (central_binom n) = 0 := +begin + rw @padic_val_nat_def _ ⟨hp⟩ _ (central_binom_pos n), + unfold central_binom, + have two_n_sub : 2 * n - n = n, by rw [two_mul n, nat.add_sub_cancel n n], + simp only [nat.prime.multiplicity_choose hp (le_mul_of_pos_left zero_lt_two) (lt_add_one _), + two_n_sub, ←two_mul, finset.card_eq_zero, enat.get_coe', finset.filter_congr_decidable], + clear two_n_sub, + + have three_lt_p : 3 ≤ p := by linarith, + have p_pos : 0 < p := nat.prime.pos hp, + + apply finset.filter_false_of_mem, + intros i i_in_interval, + rw finset.mem_Ico at i_in_interval, + refine not_le.mpr _, + + rcases lt_trichotomy 1 i with H|rfl|H, + { have two_le_i : 2 ≤ i := nat.succ_le_of_lt H, + have two_n_lt_pow_p_i : 2 * n < p ^ i, + { calc 2 * n < 3 * p : big + ... ≤ p * p : (mul_le_mul_right p_pos).2 three_lt_p + ... = p ^ 2 : (sq _).symm + ... ≤ p ^ i : nat.pow_le_pow_of_le_right p_pos two_le_i, }, + have n_mod : n % p ^ i = n, + { apply nat.mod_eq_of_lt, + calc n ≤ n + n : nat.le.intro rfl + ... = 2 * n : (two_mul n).symm + ... < p ^ i : two_n_lt_pow_p_i, }, + rw n_mod, + exact two_n_lt_pow_p_i, }, + + { rw [pow_one], + suffices h23 : 2 * (p * (n / p)) + 2 * (n % p) < 2 * (p * (n / p)) + p, + { exact (add_lt_add_iff_left (2 * (p * (n / p)))).mp h23, }, + have n_big : 1 ≤ (n / p) := (nat.le_div_iff_mul_le' p_pos).2 (trans (one_mul _).le p_le_n), + rw [←mul_add, nat.div_add_mod], + calc 2 * n < 3 * p : big + ... = 2 * p + p : nat.succ_mul _ _ + ... ≤ 2 * (p * (n / p)) + p : add_le_add_right ((mul_le_mul_left zero_lt_two).mpr + $ ((le_mul_iff_one_le_right p_pos).mpr n_big)) _ }, + + { have i_zero: i = 0 := nat.le_zero_iff.mp (nat.le_of_lt_succ H), + rw [i_zero, pow_zero, nat.mod_one, mul_zero], + exact zero_lt_one, }, +end + end nat From 9f75d75a0a66de0477a05279a7a55f63d4fcbc59 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Mon, 25 Apr 2022 15:23:28 +0000 Subject: [PATCH 253/373] feat(analysis/convex/measure): a convex set is null-measurable (#13138) --- src/analysis/convex/measure.lean | 83 +++++++++++++++++++++++++++++++ src/analysis/convex/topology.lean | 34 +++++++------ src/data/set/basic.lean | 10 ++-- src/topology/continuous_on.lean | 6 +++ 4 files changed, 114 insertions(+), 19 deletions(-) create mode 100644 src/analysis/convex/measure.lean diff --git a/src/analysis/convex/measure.lean b/src/analysis/convex/measure.lean new file mode 100644 index 0000000000000..cf1486d21fdaa --- /dev/null +++ b/src/analysis/convex/measure.lean @@ -0,0 +1,83 @@ +/- +Copyright (c) 2022 Yury Kudryashov. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yury Kudryashov +-/ +import analysis.convex.topology +import analysis.normed_space.add_torsor_bases +import measure_theory.measure.haar_lebesgue + +/-! +# Convex sets are null-measurable + +Let `E` be a finite dimensional real vector space, let `μ` be a Haar measure on `E`, let `s` be a +convex set in `E`. Then the frontier of `s` has measure zero (see `convex.add_haar_frontier`), hence +`s` is a `measure_theory.null_measurable_set` (see `convex.null_measurable_set`). +-/ + +open measure_theory measure_theory.measure set metric filter finite_dimensional (finrank) +open_locale topological_space nnreal ennreal + +variables {E : Type*} [normed_group E] [normed_space ℝ E] [measurable_space E] [borel_space E] + [finite_dimensional ℝ E] (μ : measure E) [is_add_haar_measure μ] {s : set E} + +namespace convex + +/-- Haar measure of the frontier of a convex set is zero. -/ +lemma add_haar_frontier (hs : convex ℝ s) : μ (frontier s) = 0 := +begin + /- If `s` is included in a hyperplane, then `frontier s ⊆ closure s` is included in the same + hyperplane, hence it has measure zero. -/ + cases ne_or_eq (affine_span ℝ s) ⊤ with hspan hspan, + { refine measure_mono_null _ (add_haar_affine_subspace _ _ hspan), + exact frontier_subset_closure.trans (closure_minimal (subset_affine_span _ _) + (affine_span ℝ s).closed_of_finite_dimensional) }, + rw ← hs.interior_nonempty_iff_affine_span_eq_top at hspan, + rcases hspan with ⟨x, hx⟩, + /- Without loss of generality, `s` is bounded. Indeed, `∂s ⊆ ⋃ n, ∂(s ∩ ball x (n + 1))`, hence it + suffices to prove that `∀ n, μ (s ∩ ball x (n + 1)) = 0`; the latter set is bounded. + -/ + suffices H : ∀ t : set E, convex ℝ t → x ∈ interior t → bounded t → μ (frontier t) = 0, + { set B : ℕ → set E := λ n, ball x (n + 1), + have : μ (⋃ n : ℕ, frontier (s ∩ B n)) = 0, + { refine measure_Union_null (λ n, H _ (hs.inter (convex_ball _ _)) _ + (bounded_ball.mono (inter_subset_right _ _))), + rw [interior_inter, is_open_ball.interior_eq], + exact ⟨hx, mem_ball_self (add_pos_of_nonneg_of_pos n.cast_nonneg zero_lt_one)⟩ }, + refine measure_mono_null (λ y hy, _) this, clear this, + set N : ℕ := ⌊dist y x⌋₊, + refine mem_Union.2 ⟨N, _⟩, + have hN : y ∈ B N, by { simp only [B, N], simp [nat.lt_floor_add_one] }, + suffices : y ∈ frontier (s ∩ B N) ∩ B N, from this.1, + rw [frontier_inter_open_inter is_open_ball], + exact ⟨hy, hN⟩ }, + clear hx hs s, intros s hs hx hb, + /- Since `s` is bounded, we have `μ (interior s) ≠ ∞`, hence it suffices to prove + `μ (closure s) ≤ μ (interior s)`. -/ + replace hb : μ (interior s) ≠ ∞, from (hb.mono interior_subset).measure_lt_top.ne, + suffices : μ (closure s) ≤ μ (interior s), + { rwa [frontier, measure_diff interior_subset_closure is_open_interior.measurable_set hb, + tsub_eq_zero_iff_le] }, + /- Due to `convex.closure_subset_image_homothety_interior_of_one_lt`, for any `r > 1` we have + `closure s ⊆ homothety x r '' interior s`, hence `μ (closure s) ≤ r ^ d * μ (interior s)`, + where `d = finrank ℝ E`. -/ + set d : ℕ := finite_dimensional.finrank ℝ E, + have : ∀ r : ℝ≥0, 1 < r → μ (closure s) ≤ ↑(r ^ d) * μ (interior s), + { intros r hr, + refine (measure_mono $ hs.closure_subset_image_homothety_interior_of_one_lt hx r hr).trans_eq _, + rw [add_haar_image_homothety, ← nnreal.coe_pow, nnreal.abs_eq, ennreal.of_real_coe_nnreal] }, + have : ∀ᶠ r in 𝓝[>] (1 : ℝ≥0), μ (closure s) ≤ ↑(r ^ d) * μ (interior s), + from mem_of_superset self_mem_nhds_within this, + /- Taking the limit as `r → 1`, we get `μ (closure s) ≤ μ (interior s)`. -/ + refine ge_of_tendsto _ this, + refine (((ennreal.continuous_mul_const hb).comp + (ennreal.continuous_coe.comp (continuous_pow d))).tendsto' _ _ _).mono_left nhds_within_le_nhds, + simp +end + +/-- A convex set in a finite dimensional real vector space is null measurable with respect to an +additive Haar measure on this space. -/ +protected lemma null_measurable_set (hs : convex ℝ s) : null_measurable_set s μ := +null_measurable_set_of_null_frontier (hs.add_haar_frontier μ) + +end convex diff --git a/src/analysis/convex/topology.lean b/src/analysis/convex/topology.lean index d7df224384345..33a69f779603a 100644 --- a/src/analysis/convex/topology.lean +++ b/src/analysis/convex/topology.lean @@ -225,29 +225,35 @@ hs.compact_convex_hull.is_closed open affine_map -/-- If we dilate a convex set about a point in its interior by a scale `t > 1`, the interior of -the result contains the closure of the original set. +/-- If we dilate the interior of a convex set about a point in its interior by a scale `t > 1`, +the result includes the closure of the original set. TODO Generalise this from convex sets to sets that are balanced / star-shaped about `x`. -/ -lemma convex.closure_subset_interior_image_homothety_of_one_lt {s : set E} (hs : convex ℝ s) +lemma convex.closure_subset_image_homothety_interior_of_one_lt {s : set E} (hs : convex ℝ s) {x : E} (hx : x ∈ interior s) (t : ℝ) (ht : 1 < t) : - closure s ⊆ interior (homothety x t '' s) := + closure s ⊆ homothety x t '' interior s := begin intros y hy, - have ht' : 0 < t, from one_pos.trans ht, - obtain ⟨z, rfl⟩ : ∃ z, homothety x t z = y, - from (affine_equiv.homothety_units_mul_hom x (units.mk0 t ht'.ne')).surjective y, - suffices : z ∈ interior s, - from (homothety_is_open_map x t ht'.ne').image_interior_subset _ (mem_image_of_mem _ this), - refine hs.open_segment_interior_closure_subset_interior hx hy _, + have hne : t ≠ 0, from (one_pos.trans ht).ne', + refine ⟨homothety x t⁻¹ y, hs.open_segment_interior_closure_subset_interior hx hy _, + (affine_equiv.homothety_units_mul_hom x (units.mk0 t hne)).apply_symm_apply y⟩, rw [open_segment_eq_image_line_map, ← inv_one, ← inv_Ioi (@one_pos ℝ _ _), ← image_inv, - image_image], - use [t, ht], - simp [← homothety_eq_line_map, ← homothety_mul_apply, ht'.ne'] + image_image, homothety_eq_line_map], + exact mem_image_of_mem _ ht end /-- If we dilate a convex set about a point in its interior by a scale `t > 1`, the interior of -the result contains the closure of the original set. +the result includes the closure of the original set. + +TODO Generalise this from convex sets to sets that are balanced / star-shaped about `x`. -/ +lemma convex.closure_subset_interior_image_homothety_of_one_lt {s : set E} (hs : convex ℝ s) + {x : E} (hx : x ∈ interior s) (t : ℝ) (ht : 1 < t) : + closure s ⊆ interior (homothety x t '' s) := +(hs.closure_subset_image_homothety_interior_of_one_lt hx t ht).trans $ + (homothety_is_open_map x t (one_pos.trans ht).ne').image_interior_subset _ + +/-- If we dilate a convex set about a point in its interior by a scale `t > 1`, the interior of +the result includes the closure of the original set. TODO Generalise this from convex sets to sets that are balanced / star-shaped about `x`. -/ lemma convex.subset_interior_image_homothety_of_one_lt {s : set E} (hs : convex ℝ s) diff --git a/src/data/set/basic.lean b/src/data/set/basic.lean index 66661fff7682b..e5cd3e4477914 100644 --- a/src/data/set/basic.lean +++ b/src/data/set/basic.lean @@ -2186,11 +2186,11 @@ image_preimage_coe s t theorem preimage_coe_eq_preimage_coe_iff {s t u : set α} : ((coe : s → α) ⁻¹' t = coe ⁻¹' u) ↔ t ∩ s = u ∩ s := -begin - rw [←image_preimage_coe, ←image_preimage_coe], - split, { intro h, rw h }, - intro h, exact coe_injective.image_injective h -end +by rw [← image_preimage_coe, ← image_preimage_coe, coe_injective.image_injective.eq_iff] + +@[simp] theorem preimage_coe_inter_self (s t : set α) : + (coe : s → α) ⁻¹' (t ∩ s) = coe ⁻¹' t := +by rw [preimage_coe_eq_preimage_coe_iff, inter_assoc, inter_self] theorem preimage_val_eq_preimage_val_iff (s t u : set α) : ((subtype.val : s → α) ⁻¹' t = subtype.val ⁻¹' u) ↔ (t ∩ s = u ∩ s) := diff --git a/src/topology/continuous_on.lean b/src/topology/continuous_on.lean index a1c563bd7ad26..4439b2fe39c4d 100644 --- a/src/topology/continuous_on.lean +++ b/src/topology/continuous_on.lean @@ -1086,6 +1086,12 @@ lemma continuous_on_piecewise_ite {s s' t : set α} {f f' : α → β} [∀ x, d continuous_on_piecewise_ite' (h.mono (inter_subset_left _ _)) (h'.mono (inter_subset_left _ _)) H Heq +lemma frontier_inter_open_inter {s t : set α} (ht : is_open t) : + frontier (s ∩ t) ∩ t = frontier s ∩ t := +by simp only [← subtype.preimage_coe_eq_preimage_coe_iff, + ht.is_open_map_subtype_coe.preimage_frontier_eq_frontier_preimage continuous_subtype_coe, + subtype.preimage_coe_inter_self] + lemma continuous_on_fst {s : set (α × β)} : continuous_on prod.fst s := continuous_fst.continuous_on From 85075bccb68ab7fa49fb05db816233fb790e4fe9 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Mon, 25 Apr 2022 15:23:29 +0000 Subject: [PATCH 254/373] refactor(category_theory/monoidal): rearrange simp lemmas to work better with coherence (#13409) Change the direction of some simp lemma for monoidal categories, and remove some unused lemmas. This PR is effectively a "no-op": no substantial changes to proofs. However, it should enable making `coherence` more powerful soon (following suggestions of @yuma-mizuno)! Co-authored-by: Scott Morrison --- src/category_theory/monoidal/End.lean | 4 +- src/category_theory/monoidal/Mon_.lean | 5 +- src/category_theory/monoidal/braided.lean | 12 +-- src/category_theory/monoidal/category.lean | 92 ++++++++----------- src/category_theory/monoidal/center.lean | 10 +- .../monoidal/free/coherence.lean | 5 +- src/category_theory/monoidal/opposite.lean | 76 +++------------ src/category_theory/monoidal/transport.lean | 10 +- 8 files changed, 70 insertions(+), 144 deletions(-) diff --git a/src/category_theory/monoidal/End.lean b/src/category_theory/monoidal/End.lean index 7a37d952ac68f..f12b646e85e4c 100644 --- a/src/category_theory/monoidal/End.lean +++ b/src/category_theory/monoidal/End.lean @@ -50,7 +50,9 @@ def tensoring_right_monoidal [monoidal_category.{v} C] : monoidal_functor C (C μ := λ X Y, { app := λ Z, (α_ Z X Y).hom, naturality' := λ Z Z' f, by { dsimp, rw associator_naturality, simp, } }, - μ_natural' := λ X Y X' Y' f g, by { ext Z, dsimp, simp [associator_naturality], }, + μ_natural' := λ X Y X' Y' f g, by { ext Z, dsimp, + simp only [←id_tensor_comp_tensor_id g f, id_tensor_comp, ←tensor_id, category.assoc, + associator_naturality, associator_naturality_assoc], }, associativity' := λ X Y Z, by { ext W, dsimp, simp [pentagon], }, left_unitality' := λ X, by { ext Y, dsimp, rw [category.id_comp, triangle, ←tensor_comp], simp, }, right_unitality' := λ X, diff --git a/src/category_theory/monoidal/Mon_.lean b/src/category_theory/monoidal/Mon_.lean index 65a7a5c8cc3a6..c25d0535bdc4f 100644 --- a/src/category_theory/monoidal/Mon_.lean +++ b/src/category_theory/monoidal/Mon_.lean @@ -58,9 +58,8 @@ def trivial : Mon_ C := { X := 𝟙_ C, one := 𝟙 _, mul := (λ_ _).hom, - mul_assoc' := - by simp_rw [triangle_assoc, iso.cancel_iso_hom_right, tensor_right_iff, unitors_equal], - mul_one' := by simp [unitors_equal] } + mul_assoc' := by coherence, + mul_one' := by coherence } instance : inhabited (Mon_ C) := ⟨trivial C⟩ diff --git a/src/category_theory/monoidal/braided.lean b/src/category_theory/monoidal/braided.lean index 6652067774925..f9e0c6d9f857a 100644 --- a/src/category_theory/monoidal/braided.lean +++ b/src/category_theory/monoidal/braided.lean @@ -81,8 +81,8 @@ I couldn't find a detailed proof in print, but this is discussed in: variables (C : Type u₁) [category.{v₁} C] [monoidal_category C] [braided_category C] lemma braiding_left_unitor_aux₁ (X : C) : - (α_ (𝟙_ C) (𝟙_ C) X).hom ≫ (𝟙 _ ⊗ (β_ X (𝟙_ C)).inv) ≫ (α_ _ X _).inv ≫ ((λ_ X).hom ⊗ 𝟙 _) = - ((λ_ _).hom ⊗ 𝟙 X) ≫ (β_ X _).inv := + (α_ (𝟙_ C) (𝟙_ C) X).hom ≫ (𝟙 (𝟙_ C) ⊗ (β_ X (𝟙_ C)).inv) ≫ (α_ _ X _).inv ≫ ((λ_ X).hom ⊗ 𝟙 _) = + ((λ_ _).hom ⊗ 𝟙 X) ≫ (β_ X (𝟙_ C)).inv := by { rw [←left_unitor_tensor, left_unitor_naturality], simp, } lemma braiding_left_unitor_aux₂ (X : C) : @@ -90,7 +90,7 @@ lemma braiding_left_unitor_aux₂ (X : C) : calc ((β_ X (𝟙_ C)).hom ⊗ (𝟙 (𝟙_ C))) ≫ ((λ_ X).hom ⊗ (𝟙 (𝟙_ C))) = ((β_ X (𝟙_ C)).hom ⊗ (𝟙 (𝟙_ C))) ≫ (α_ _ _ _).hom ≫ (α_ _ _ _).inv ≫ ((λ_ X).hom ⊗ (𝟙 (𝟙_ C))) - : by simp + : by coherence ... = ((β_ X (𝟙_ C)).hom ⊗ (𝟙 (𝟙_ C))) ≫ (α_ _ _ _).hom ≫ (𝟙 _ ⊗ (β_ X _).hom) ≫ (𝟙 _ ⊗ (β_ X _).inv) ≫ (α_ _ _ _).inv ≫ ((λ_ X).hom ⊗ (𝟙 (𝟙_ C))) : by { slice_rhs 3 4 { rw [←id_tensor_comp, iso.hom_inv_id, tensor_id], }, rw [id_comp], } @@ -111,8 +111,8 @@ lemma braiding_left_unitor (X : C) : (β_ X (𝟙_ C)).hom ≫ (λ_ X).hom = (ρ by rw [←tensor_right_iff, comp_tensor_id, braiding_left_unitor_aux₂] lemma braiding_right_unitor_aux₁ (X : C) : - (α_ X (𝟙_ C) (𝟙_ C)).inv ≫ ((β_ (𝟙_ C) X).inv ⊗ 𝟙 _) ≫ (α_ _ X _).hom ≫ (𝟙 _ ⊗ (ρ_ X).hom) = - (𝟙 X ⊗ (ρ_ _).hom) ≫ (β_ _ X).inv := + (α_ X (𝟙_ C) (𝟙_ C)).inv ≫ ((β_ (𝟙_ C) X).inv ⊗ 𝟙 (𝟙_ C)) ≫ (α_ _ X _).hom ≫ (𝟙 _ ⊗ (ρ_ X).hom) = + (𝟙 X ⊗ (ρ_ _).hom) ≫ (β_ (𝟙_ C) X).inv := by { rw [←right_unitor_tensor, right_unitor_naturality], simp, } lemma braiding_right_unitor_aux₂ (X : C) : @@ -120,7 +120,7 @@ lemma braiding_right_unitor_aux₂ (X : C) : calc ((𝟙 (𝟙_ C)) ⊗ (β_ (𝟙_ C) X).hom) ≫ ((𝟙 (𝟙_ C)) ⊗ (ρ_ X).hom) = ((𝟙 (𝟙_ C)) ⊗ (β_ (𝟙_ C) X).hom) ≫ (α_ _ _ _).inv ≫ (α_ _ _ _).hom ≫ ((𝟙 (𝟙_ C)) ⊗ (ρ_ X).hom) - : by simp + : by coherence ... = ((𝟙 (𝟙_ C)) ⊗ (β_ (𝟙_ C) X).hom) ≫ (α_ _ _ _).inv ≫ ((β_ _ X).hom ⊗ 𝟙 _) ≫ ((β_ _ X).inv ⊗ 𝟙 _) ≫ (α_ _ _ _).hom ≫ ((𝟙 (𝟙_ C)) ⊗ (ρ_ X).hom) : by { slice_rhs 3 4 { rw [←comp_tensor_id, iso.hom_inv_id, tensor_id], }, rw [id_comp], } diff --git a/src/category_theory/monoidal/category.lean b/src/category_theory/monoidal/category.lean index 044b2efecc52d..2c0b9f1f9f5c7 100644 --- a/src/category_theory/monoidal/category.lean +++ b/src/category_theory/monoidal/category.lean @@ -186,43 +186,35 @@ by { rw [←tensor_comp], simp } (g ⊗ (𝟙 W)) ≫ ((𝟙 Z) ⊗ f) = g ⊗ f := by { rw [←tensor_comp], simp } +@[simp] +lemma right_unitor_conjugation {X Y : C} (f : X ⟶ Y) : + (f ⊗ (𝟙 (𝟙_ C))) = (ρ_ X).hom ≫ f ≫ (ρ_ Y).inv := +by rw [←right_unitor_naturality_assoc, iso.hom_inv_id, category.comp_id] + +@[simp] +lemma left_unitor_conjugation {X Y : C} (f : X ⟶ Y) : + ((𝟙 (𝟙_ C)) ⊗ f) = (λ_ X).hom ≫ f ≫ (λ_ Y).inv := +by rw [←left_unitor_naturality_assoc, iso.hom_inv_id, category.comp_id] + @[reassoc] lemma left_unitor_inv_naturality {X X' : C} (f : X ⟶ X') : f ≫ (λ_ X').inv = (λ_ X).inv ≫ (𝟙 _ ⊗ f) := -begin - apply (cancel_mono (λ_ X').hom).1, - simp only [assoc, comp_id, iso.inv_hom_id], - rw [left_unitor_naturality, ←category.assoc, iso.inv_hom_id, category.id_comp] -end +by simp @[reassoc] lemma right_unitor_inv_naturality {X X' : C} (f : X ⟶ X') : f ≫ (ρ_ X').inv = (ρ_ X).inv ≫ (f ⊗ 𝟙 _) := -begin - apply (cancel_mono (ρ_ X').hom).1, - simp only [assoc, comp_id, iso.inv_hom_id], - rw [right_unitor_naturality, ←category.assoc, iso.inv_hom_id, category.id_comp] -end +by simp -@[simp] -lemma right_unitor_conjugation {X Y : C} (f : X ⟶ Y) : - (ρ_ X).inv ≫ (f ⊗ (𝟙 (𝟙_ C))) ≫ (ρ_ Y).hom = f := -by rw [right_unitor_naturality, ←category.assoc, iso.inv_hom_id, category.id_comp] - -@[simp] -lemma left_unitor_conjugation {X Y : C} (f : X ⟶ Y) : - (λ_ X).inv ≫ ((𝟙 (𝟙_ C)) ⊗ f) ≫ (λ_ Y).hom = f := -by rw [left_unitor_naturality, ←category.assoc, iso.inv_hom_id, category.id_comp] - -@[simp] lemma tensor_left_iff +lemma tensor_left_iff {X Y : C} (f g : X ⟶ Y) : ((𝟙 (𝟙_ C)) ⊗ f = (𝟙 (𝟙_ C)) ⊗ g) ↔ (f = g) := -by { rw [←cancel_mono (λ_ Y).hom, left_unitor_naturality, left_unitor_naturality], simp } +by simp -@[simp] lemma tensor_right_iff +lemma tensor_right_iff {X Y : C} (f g : X ⟶ Y) : (f ⊗ (𝟙 (𝟙_ C)) = g ⊗ (𝟙 (𝟙_ C))) ↔ (f = g) := -by { rw [←cancel_mono (ρ_ Y).hom, right_unitor_naturality, right_unitor_naturality], simp } +by simp /-! The lemmas in the next section are true by coherence, but we prove them directly as they are used in proving the coherence theorem. -/ @@ -247,13 +239,9 @@ lemma right_unitor_tensor_inv (X Y : C) : ((ρ_ (X ⊗ Y)).inv) = ((𝟙 X) ⊗ (ρ_ Y).inv) ≫ (α_ X Y (𝟙_ C)).inv := eq_of_inv_eq_inv (by simp) -lemma triangle_assoc_comp_left (X Y : C) : - (α_ X (𝟙_ C) Y).hom ≫ ((𝟙 X) ⊗ (λ_ Y).hom) = (ρ_ X).hom ⊗ 𝟙 Y := -monoidal_category.triangle X Y - @[simp, reassoc] lemma triangle_assoc_comp_right (X Y : C) : (α_ X (𝟙_ C) Y).inv ≫ ((ρ_ X).hom ⊗ 𝟙 Y) = ((𝟙 X) ⊗ (λ_ Y).hom) := -by rw [←triangle_assoc_comp_left, iso.inv_hom_id_assoc] +by rw [←triangle, iso.inv_hom_id_assoc] @[simp, reassoc] lemma triangle_assoc_comp_left_inv (X Y : C) : ((𝟙 X) ⊗ (λ_ Y).inv) ≫ (α_ X (𝟙_ C) Y).inv = ((ρ_ X).inv ⊗ 𝟙 Y) := @@ -270,55 +258,47 @@ lemma associator_inv_naturality {X Y Z X' Y' Z' : C} (f : X ⟶ X') (g : Y ⟶ Y (f ⊗ (g ⊗ h)) ≫ (α_ X' Y' Z').inv = (α_ X Y Z).inv ≫ ((f ⊗ g) ⊗ h) := by { rw [comp_inv_eq, assoc, associator_naturality], simp } -@[reassoc] -lemma id_tensor_associator_naturality {X Y Z Z' : C} (h : Z ⟶ Z') : - (𝟙 (X ⊗ Y) ⊗ h) ≫ (α_ X Y Z').hom = (α_ X Y Z).hom ≫ (𝟙 X ⊗ (𝟙 Y ⊗ h)) := -by { rw [←tensor_id, associator_naturality], } - -@[reassoc] -lemma id_tensor_associator_inv_naturality {X Y Z X' : C} (f : X ⟶ X') : - (f ⊗ 𝟙 (Y ⊗ Z)) ≫ (α_ X' Y Z).inv = (α_ X Y Z).inv ≫ ((f ⊗ 𝟙 Y) ⊗ 𝟙 Z) := -by { rw [←tensor_id, associator_inv_naturality] } - -@[reassoc] +@[reassoc, simp] lemma associator_conjugation {X X' Y Y' Z Z' : C} (f : X ⟶ X') (g : Y ⟶ Y') (h : Z ⟶ Z') : - (α_ X Y Z).hom ≫ (f ⊗ (g ⊗ h)) ≫ (α_ X' Y' Z').inv = (f ⊗ g) ⊗ h := + (f ⊗ g) ⊗ h = (α_ X Y Z).hom ≫ (f ⊗ (g ⊗ h)) ≫ (α_ X' Y' Z').inv := by rw [associator_inv_naturality, hom_inv_id_assoc] @[reassoc] lemma associator_inv_conjugation {X X' Y Y' Z Z' : C} (f : X ⟶ X') (g : Y ⟶ Y') (h : Z ⟶ Z') : - (α_ X Y Z).inv ≫ ((f ⊗ g) ⊗ h) ≫ (α_ X' Y' Z').hom = f ⊗ g ⊗ h := + f ⊗ g ⊗ h = (α_ X Y Z).inv ≫ ((f ⊗ g) ⊗ h) ≫ (α_ X' Y' Z').hom := by rw [associator_naturality, inv_hom_id_assoc] +-- TODO these next two lemmas aren't so fundamental, and perhaps could be removed +-- (replacing their usages by their proofs). @[reassoc] -lemma right_unitor_inv_comp_tensor (f : W ⟶ X) (g : 𝟙_ C ⟶ Z) : - (ρ_ _).inv ≫ (f ⊗ g) = f ≫ (ρ_ _).inv ≫ (𝟙 _ ⊗ g) := -by { slice_rhs 1 2 { rw right_unitor_inv_naturality }, simp } +lemma id_tensor_associator_naturality {X Y Z Z' : C} (h : Z ⟶ Z') : + (𝟙 (X ⊗ Y) ⊗ h) ≫ (α_ X Y Z').hom = (α_ X Y Z).hom ≫ (𝟙 X ⊗ (𝟙 Y ⊗ h)) := +by { rw [←tensor_id, associator_naturality], } @[reassoc] -lemma left_unitor_inv_comp_tensor (f : W ⟶ X) (g : 𝟙_ C ⟶ Z) : - (λ_ _).inv ≫ (g ⊗ f) = f ≫ (λ_ _).inv ≫ (g ⊗ 𝟙 _) := -by { slice_rhs 1 2 { rw left_unitor_inv_naturality }, simp } +lemma id_tensor_associator_inv_naturality {X Y Z X' : C} (f : X ⟶ X') : + (f ⊗ 𝟙 (Y ⊗ Z)) ≫ (α_ X' Y Z).inv = (α_ X Y Z).inv ≫ ((f ⊗ 𝟙 Y) ⊗ 𝟙 Z) := +by { rw [←tensor_id, associator_inv_naturality] } @[simp, reassoc] lemma hom_inv_id_tensor {V W X Y Z : C} (f : V ≅ W) (g : X ⟶ Y) (h : Y ⟶ Z) : - (f.hom ⊗ g) ≫ (f.inv ⊗ h) = 𝟙 V ⊗ (g ≫ h) := -by rw [←tensor_comp, f.hom_inv_id] + (f.hom ⊗ g) ≫ (f.inv ⊗ h) = (𝟙 V ⊗ g) ≫ (𝟙 V ⊗ h) := +by rw [←tensor_comp, f.hom_inv_id, id_tensor_comp] @[simp, reassoc] lemma inv_hom_id_tensor {V W X Y Z : C} (f : V ≅ W) (g : X ⟶ Y) (h : Y ⟶ Z) : - (f.inv ⊗ g) ≫ (f.hom ⊗ h) = 𝟙 W ⊗ (g ≫ h) := -by rw [←tensor_comp, f.inv_hom_id] + (f.inv ⊗ g) ≫ (f.hom ⊗ h) = (𝟙 W ⊗ g) ≫ (𝟙 W ⊗ h) := +by rw [←tensor_comp, f.inv_hom_id, id_tensor_comp] @[simp, reassoc] lemma tensor_hom_inv_id {V W X Y Z : C} (f : V ≅ W) (g : X ⟶ Y) (h : Y ⟶ Z) : - (g ⊗ f.hom) ≫ (h ⊗ f.inv) = (g ≫ h) ⊗ 𝟙 V := -by rw [←tensor_comp, f.hom_inv_id] + (g ⊗ f.hom) ≫ (h ⊗ f.inv) = (g ⊗ 𝟙 V) ≫ (h ⊗ 𝟙 V) := +by rw [←tensor_comp, f.hom_inv_id, comp_tensor_id] @[simp, reassoc] lemma tensor_inv_hom_id {V W X Y Z : C} (f : V ≅ W) (g : X ⟶ Y) (h : Y ⟶ Z) : - (g ⊗ f.inv) ≫ (h ⊗ f.hom) = (g ≫ h) ⊗ 𝟙 W := -by rw [←tensor_comp, f.inv_hom_id] + (g ⊗ f.inv) ≫ (h ⊗ f.hom) = (g ⊗ 𝟙 W) ≫ (h ⊗ 𝟙 W) := +by rw [←tensor_comp, f.inv_hom_id, comp_tensor_id] end diff --git a/src/category_theory/monoidal/center.lean b/src/category_theory/monoidal/center.lean index 9bb9e45d2ef1c..4ffea5d7850a4 100644 --- a/src/category_theory/monoidal/center.lean +++ b/src/category_theory/monoidal/center.lean @@ -127,10 +127,10 @@ def tensor_obj (X Y : center C) : center C := slice_rhs 6 7 { rw [tensor_id, tensor_id, tensor_id_comp_id_tensor, ←id_tensor_comp_tensor_id, ←tensor_id, ←tensor_id], }, -- Now insert associators as needed to make the four half-braidings look identical - slice_rhs 10 10 { rw ←associator_inv_conjugation, }, - slice_rhs 7 7 { rw ←associator_inv_conjugation, }, - slice_rhs 6 6 { rw ←associator_conjugation, }, - slice_rhs 3 3 { rw ←associator_conjugation, }, + slice_rhs 10 10 { rw associator_inv_conjugation, }, + slice_rhs 7 7 { rw associator_inv_conjugation, }, + slice_rhs 6 6 { rw associator_conjugation, }, + slice_rhs 3 3 { rw associator_conjugation, }, -- Finish with an application of the coherence theorem. coherence, end, @@ -175,7 +175,7 @@ def tensor_unit : center C := def associator (X Y Z : center C) : tensor_obj (tensor_obj X Y) Z ≅ tensor_obj X (tensor_obj Y Z) := iso_mk ⟨(α_ X.1 Y.1 Z.1).hom, λ U, begin dsimp, - simp only [comp_tensor_id, id_tensor_comp, ←tensor_id, ←associator_conjugation], + simp only [comp_tensor_id, id_tensor_comp, ←tensor_id, associator_conjugation], coherence, end⟩ diff --git a/src/category_theory/monoidal/free/coherence.lean b/src/category_theory/monoidal/free/coherence.lean index c634a27b2bbff..8304f1320f38a 100644 --- a/src/category_theory/monoidal/free/coherence.lean +++ b/src/category_theory/monoidal/free/coherence.lean @@ -195,8 +195,9 @@ begin simp only [discrete.functor_map_id, iso.cancel_iso_inv_left, category.assoc], dsimp, simp only [category.comp_id] }, { dsimp, - simp only [←(iso.eq_comp_inv _).1 (right_unitor_tensor_inv _ _), iso.hom_inv_id_assoc, - right_unitor_conjugation, discrete.functor_map_id, category.assoc], + simp only [←(iso.eq_comp_inv _).1 (right_unitor_tensor_inv _ _), right_unitor_conjugation, + discrete.functor_map_id, category.assoc, + iso.hom_inv_id, iso.hom_inv_id_assoc, iso.inv_hom_id, iso.inv_hom_id_assoc], dsimp, simp only [category.comp_id], }, { dsimp at *, rw [id_tensor_comp, category.assoc, f_ih_g ⟦f_g⟧, ←category.assoc, f_ih_f ⟦f_f⟧, category.assoc, diff --git a/src/category_theory/monoidal/opposite.lean b/src/category_theory/monoidal/opposite.lean index 39b647f351726..28f98b1404a0d 100644 --- a/src/category_theory/monoidal/opposite.lean +++ b/src/category_theory/monoidal/opposite.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Scott Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Scott Morrison -/ -import category_theory.monoidal.category +import category_theory.monoidal.coherence /-! # Monoidal opposites @@ -115,38 +115,11 @@ instance monoidal_category_op : monoidal_category Cᵒᵖ := associator := λ X Y Z, (α_ (unop X) (unop Y) (unop Z)).symm.op, left_unitor := λ X, (λ_ (unop X)).symm.op, right_unitor := λ X, (ρ_ (unop X)).symm.op, - associator_naturality' := - begin - intros, - apply quiver.hom.unop_inj, - simp [associator_inv_naturality], - end, - left_unitor_naturality' := - begin - intros, - apply quiver.hom.unop_inj, - simp [left_unitor_inv_naturality], - end, - right_unitor_naturality' := - begin - intros, - apply quiver.hom.unop_inj, - simp [right_unitor_inv_naturality], - end, - triangle' := - begin - intros, - apply quiver.hom.unop_inj, - dsimp, - simp, - end, - pentagon' := - begin - intros, - apply quiver.hom.unop_inj, - dsimp, - simp [pentagon_inv], - end } + associator_naturality' := by { intros, apply quiver.hom.unop_inj, simp, }, + left_unitor_naturality' := by { intros, apply quiver.hom.unop_inj, simp, }, + right_unitor_naturality' := by { intros, apply quiver.hom.unop_inj, simp, }, + triangle' := by { intros, apply quiver.hom.unop_inj, coherence, }, + pentagon' := by { intros, apply quiver.hom.unop_inj, coherence, }, } lemma op_tensor_obj (X Y : Cᵒᵖ) : X ⊗ Y = op (unop X ⊗ unop Y) := rfl lemma op_tensor_unit : (𝟙_ Cᵒᵖ) = op (𝟙_ C) := rfl @@ -158,38 +131,11 @@ instance monoidal_category_mop : monoidal_category Cᴹᵒᵖ := associator := λ X Y Z, (α_ (unmop Z) (unmop Y) (unmop X)).symm.mop, left_unitor := λ X, (ρ_ (unmop X)).mop, right_unitor := λ X, (λ_ (unmop X)).mop, - associator_naturality' := - begin - intros, - apply unmop_inj, - simp [associator_inv_naturality], - end, - left_unitor_naturality' := - begin - intros, - apply unmop_inj, - simp [right_unitor_naturality], - end, - right_unitor_naturality' := - begin - intros, - apply unmop_inj, - simp [left_unitor_naturality], - end, - triangle' := - begin - intros, - apply unmop_inj, - dsimp, - simp, - end, - pentagon' := - begin - intros, - apply unmop_inj, - dsimp, - simp [pentagon_inv], - end } + associator_naturality' := by { intros, apply unmop_inj, simp, }, + left_unitor_naturality' := by { intros, apply unmop_inj, simp, }, + right_unitor_naturality' := by { intros, apply unmop_inj, simp, }, + triangle' := by { intros, apply unmop_inj, coherence, }, + pentagon' := by { intros, apply unmop_inj, coherence, }, } lemma mop_tensor_obj (X Y : Cᴹᵒᵖ) : X ⊗ Y = mop (unmop Y ⊗ unmop X) := rfl lemma mop_tensor_unit : (𝟙_ Cᴹᵒᵖ) = mop (𝟙_ C) := rfl diff --git a/src/category_theory/monoidal/transport.lean b/src/category_theory/monoidal/transport.lean index 61950c2e88c3a..0f56702cb230f 100644 --- a/src/category_theory/monoidal/transport.lean +++ b/src/category_theory/monoidal/transport.lean @@ -170,8 +170,8 @@ def lax_to_transported (e : C ≌ D) : lax_monoidal_functor C (transported e) := conv_rhs { rw [←id_tensor_comp_tensor_id _ (e.unit_inv.app X)], }, dsimp only [functor.comp_obj], slice_rhs 3 4 { rw [←id_tensor_comp, iso.hom_inv_id_app], dsimp, rw [tensor_id] }, - simp only [id_comp], - simp [associator_naturality], + simp only [associator_conjugation, ←tensor_id, ←tensor_comp, iso.inv_hom_id, + iso.inv_hom_id_assoc, category.assoc, category.id_comp, category.comp_id], end, left_unitality' := λ X, begin @@ -180,8 +180,7 @@ def lax_to_transported (e : C ≌ D) : lax_monoidal_functor C (transported e) := rw equivalence.counit_app_functor, simp only [←e.functor.map_comp], congr' 1, - rw [←left_unitor_naturality], - simp, + simp only [←left_unitor_naturality, id_comp, ←tensor_comp_assoc, comp_id], end, right_unitality' := λ X, begin @@ -190,8 +189,7 @@ def lax_to_transported (e : C ≌ D) : lax_monoidal_functor C (transported e) := rw equivalence.counit_app_functor, simp only [←e.functor.map_comp], congr' 1, - rw [←right_unitor_naturality], - simp, + simp only [←right_unitor_naturality, id_comp, ←tensor_comp_assoc, comp_id], end, }. /-- From e2f56961d96f5ad2f61b798cb41184fb702aad5c Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 25 Apr 2022 15:23:30 +0000 Subject: [PATCH 255/373] feat(analysis/normed_space/exponential): add `pi.exp_apply` (#13488) The statement is a bit weird, but this structure is useful because it allows us to push `exp` through `matrix.diagonal` and into its elements. --- src/analysis/normed_space/exponential.lean | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/analysis/normed_space/exponential.lean b/src/analysis/normed_space/exponential.lean index 1c9c22d0732ef..4a4a6d56b139d 100644 --- a/src/analysis/normed_space/exponential.lean +++ b/src/analysis/normed_space/exponential.lean @@ -478,6 +478,32 @@ map_exp _ (ring_hom.fst 𝔸 𝔹) continuous_fst x @[simp] lemma prod.snd_exp [complete_space 𝔹] (x : 𝔸 × 𝔹) : (exp 𝕂 (𝔸 × 𝔹) x).snd = exp 𝕂 𝔹 x.snd := map_exp _ (ring_hom.snd 𝔸 𝔹) continuous_snd x +@[simp] lemma pi.exp_apply {ι : Type*} {𝔸 : ι → Type*} [fintype ι] + [Π i, normed_ring (𝔸 i)] [Π i, normed_algebra 𝕂 (𝔸 i)] [Π i, complete_space (𝔸 i)] + (x : Π i, 𝔸 i) (i : ι) : + exp 𝕂 (Π i, 𝔸 i) x i = exp 𝕂 (𝔸 i) (x i) := +begin + -- Lean struggles to infer this instance due to it wanting `[Π i, semi_normed_ring (𝔸 i)]` + letI : normed_algebra 𝕂 (Π i, 𝔸 i) := pi.normed_algebra _, + exact map_exp _ (pi.eval_ring_hom 𝔸 i) (continuous_apply _) x +end + +lemma pi.exp_def {ι : Type*} {𝔸 : ι → Type*} [fintype ι] + [Π i, normed_ring (𝔸 i)] [Π i, normed_algebra 𝕂 (𝔸 i)] [Π i, complete_space (𝔸 i)] + (x : Π i, 𝔸 i) : + exp 𝕂 (Π i, 𝔸 i) x = λ i, exp 𝕂 (𝔸 i) (x i) := +funext $ pi.exp_apply 𝕂 x + +lemma function.update_exp {ι : Type*} {𝔸 : ι → Type*} [fintype ι] [decidable_eq ι] + [Π i, normed_ring (𝔸 i)] [Π i, normed_algebra 𝕂 (𝔸 i)] [Π i, complete_space (𝔸 i)] + (x : Π i, 𝔸 i) (j : ι) (xj : 𝔸 j) : + function.update (exp 𝕂 (Π i, 𝔸 i) x) j (exp 𝕂 (𝔸 j) xj) = exp 𝕂 _ (function.update x j xj) := +begin + ext i, + simp_rw [pi.exp_def], + exact (function.apply_update (λ i, exp 𝕂 (𝔸 i)) x j xj i).symm, +end + end complete_algebra lemma algebra_map_exp_comm (x : 𝕂) : From 4481a561375b4302ce6fcb1fd1380ba89d0d02cc Mon Sep 17 00:00:00 2001 From: Patrick Stevens Date: Mon, 25 Apr 2022 15:23:31 +0000 Subject: [PATCH 256/373] feat(algebra/group_power/order): Add sq_zero_iff (#13670) Tiny lemma that seems to be missing. Should this be a simp lemma? Co-authored-by: Yury G. Kudryashov --- src/algebra/group_power/basic.lean | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/algebra/group_power/basic.lean b/src/algebra/group_power/basic.lean index ce8b27f87e5de..d1367eef908e2 100644 --- a/src/algebra/group_power/basic.lean +++ b/src/algebra/group_power/basic.lean @@ -330,6 +330,9 @@ lemma pow_ne_zero_iff [monoid_with_zero R] [no_zero_divisors R] {a : R} {n : ℕ {a : R} (n : ℕ) (h : a ≠ 0) : a ^ n ≠ 0 := mt pow_eq_zero h +theorem sq_eq_zero_iff [monoid_with_zero R] [no_zero_divisors R] {a : R} : a ^ 2 = 0 ↔ a = 0 := +pow_eq_zero_iff two_pos + lemma pow_dvd_pow_iff [cancel_comm_monoid_with_zero R] {x : R} {n m : ℕ} (h0 : x ≠ 0) (h1 : ¬ is_unit x) : x ^ n ∣ x ^ m ↔ n ≤ m := From 43e84cdd13ed91ee3c91022c0a6d6144d2960537 Mon Sep 17 00:00:00 2001 From: Eric Rodriguez Date: Mon, 25 Apr 2022 17:22:44 +0000 Subject: [PATCH 257/373] feat(data/fin/succ_pred): `fin` is an archimedean succ/pred order (#12792) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Eric Rodriguez <37984851+ericrbg@users.noreply.github.com> Co-authored-by: Yaël Dillies --- src/algebra/big_operators/fin.lean | 6 +-- src/data/fin/basic.lean | 48 +++++++++++++++++++++++ src/data/fin/succ_pred.lean | 61 ++++++++++++++++++++++++++++++ src/data/fintype/basic.lean | 13 +++++-- src/order/rel_classes.lean | 3 ++ src/order/succ_pred/basic.lean | 48 +++++++++++++++++++++++ src/set_theory/ordinal/basic.lean | 2 +- 7 files changed, 172 insertions(+), 9 deletions(-) create mode 100644 src/data/fin/succ_pred.lean diff --git a/src/algebra/big_operators/fin.lean b/src/algebra/big_operators/fin.lean index 58d446967966e..42a469db0776c 100644 --- a/src/algebra/big_operators/fin.lean +++ b/src/algebra/big_operators/fin.lean @@ -181,11 +181,7 @@ end lemma alternating_sum_eq_finset_sum {G : Type*} [add_comm_group G] : ∀ (L : list G), alternating_sum L = ∑ i : fin L.length, (-1 : ℤ) ^ (i : ℕ) • L.nth_le i i.is_lt | [] := by { rw [alternating_sum, finset.sum_eq_zero], rintro ⟨i, ⟨⟩⟩ } -| (g :: []) := -begin - show g = ∑ i : fin 1, (-1 : ℤ) ^ (i : ℕ) • [g].nth_le i i.2, - rw [fin.sum_univ_succ], simp, -end +| (g :: []) := by simp | (g :: h :: L) := calc g + -h + L.alternating_sum = g + -h + ∑ i : fin L.length, (-1 : ℤ) ^ (i : ℕ) • L.nth_le i i.2 : diff --git a/src/data/fin/basic.lean b/src/data/fin/basic.lean index e319ac332600b..ec6e542f08e0b 100644 --- a/src/data/fin/basic.lean +++ b/src/data/fin/basic.lean @@ -1169,6 +1169,54 @@ protected lemma coe_neg (a : fin n) : ((-a : fin n) : ℕ) = (n - a) % n := rfl protected lemma coe_sub (a b : fin n) : ((a - b : fin n) : ℕ) = (a + (n - b)) % n := by cases a; cases b; refl +@[simp] lemma coe_fin_one (a : fin 1) : ↑a = 0 := +by rw [subsingleton.elim a 0, fin.coe_zero] + +@[simp] lemma coe_neg_one : ↑(-1 : fin (n + 1)) = n := +begin + cases n, + { simp }, + rw [fin.coe_neg, fin.coe_one, nat.succ_sub_one, nat.mod_eq_of_lt], + constructor +end + +lemma coe_sub_one {n} (a : fin (n + 1)) : ↑(a - 1) = if a = 0 then n else a - 1 := +begin + cases n, + { simp }, + split_ifs, + { simp [h] }, + rw [sub_eq_add_neg, coe_add_eq_ite, coe_neg_one, if_pos, add_comm, add_tsub_add_eq_tsub_left], + rw [add_comm ↑a, add_le_add_iff_left, nat.one_le_iff_ne_zero], + rwa subtype.ext_iff at h +end + +/-- By sending `x` to `last n - x`, `fin n` is order-equivalent to its `order_dual`. -/ +def _root_.order_iso.fin_equiv : ∀ {n}, order_dual (fin n) ≃o fin n +| 0 := ⟨⟨elim0, elim0, elim0, elim0⟩, elim0⟩ +| (n+1) := order_iso.symm $ +{ to_fun := λ x, last n - x, + inv_fun := λ x, last n - x, + left_inv := sub_sub_cancel _, + right_inv := sub_sub_cancel _, + map_rel_iff' := λ a b, + begin + rw [order_dual.has_le], + simp only [equiv.coe_fn_mk], + rw [le_iff_coe_le_coe, fin.coe_sub, fin.coe_sub, coe_last], + have : (n - ↑b) % (n + 1) ≤ (n - ↑a) % (n + 1) ↔ a ≤ b, + { rw [nat.mod_eq_of_lt, nat.mod_eq_of_lt, tsub_le_tsub_iff_left a.is_le, + le_iff_coe_le_coe]; exact tsub_le_self.trans_lt n.lt_succ_self }, + suffices key : ∀ {x : fin (n + 1)}, (n + (n + 1 - x)) % (n + 1) = (n - x) % (n + 1), + { convert this using 2; exact key }, + intro x, + rw [add_comm, tsub_add_eq_add_tsub x.is_lt.le, add_tsub_assoc_of_le x.is_le, nat.add_mod_left] + end } + +lemma _root_.order_iso.fin_equiv_apply (a) : order_iso.fin_equiv a = last n - a.of_dual := rfl +lemma _root_.order_iso.fin_equiv_symm_apply (a) : + order_iso.fin_equiv.symm a = order_dual.to_dual (last n - a) := rfl + end add_group section succ_above diff --git a/src/data/fin/succ_pred.lean b/src/data/fin/succ_pred.lean new file mode 100644 index 0000000000000..85b2168310baa --- /dev/null +++ b/src/data/fin/succ_pred.lean @@ -0,0 +1,61 @@ +/- +Copyright (c) 2022 Eric Rodriguez. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Eric Rodriguez +-/ +import order.succ_pred.basic + +/-! +# Successors and predecessors of `fin n` + +In this file, we show that `fin n` is both a `succ_order` and a `pred_order`. Note that they are +also archimedean, but this is derived from the general instance for well-orderings as opposed +to a specific `fin` instance. + +-/ + +namespace fin + +instance : ∀ {n : ℕ}, succ_order (fin n) +| 0 := by constructor; exact elim0 +| (n+1) := +_root_.succ_order.of_core (λ i, if i < fin.last n then i + 1 else i) +begin + intros a ha b, + rw [is_max_iff_eq_top, eq_top_iff, not_le, top_eq_last] at ha, + rw [if_pos ha, lt_iff_coe_lt_coe, le_iff_coe_le_coe, coe_add_one_of_lt ha], + exact nat.lt_iff_add_one_le +end +begin + intros a ha, + rw [is_max_iff_eq_top, top_eq_last] at ha, + rw [if_neg ha.not_lt], +end + +@[simp] lemma succ_eq {n : ℕ} : succ_order.succ = λ a, if a < fin.last n then a + 1 else a := rfl +@[simp] lemma succ_apply {n : ℕ} (a) : + succ_order.succ a = if a < fin.last n then a + 1 else a := rfl + +instance : ∀ {n : ℕ}, pred_order (fin n) +| 0 := by constructor; exact elim0 +| (n+1) := +_root_.pred_order.of_core (λ x, if x = 0 then 0 else x - 1) +begin + intros a ha b, + rw [is_min_iff_eq_bot, eq_bot_iff, not_le, bot_eq_zero] at ha, + rw [if_neg ha.ne', lt_iff_coe_lt_coe, le_iff_coe_le_coe, coe_sub_one, + if_neg ha.ne', le_tsub_iff_right, iff.comm], + exact nat.lt_iff_add_one_le, + exact ha +end +begin + intros a ha, + rw [is_min_iff_eq_bot, bot_eq_zero] at ha, + rwa [if_pos ha, eq_comm], +end + +@[simp] lemma pred_eq {n} : pred_order.pred = λ a : fin (n + 1), if a = 0 then 0 else a - 1 := rfl +@[simp] lemma pred_apply {n : ℕ} (a : fin (n + 1)) : + pred_order.pred a = if a = 0 then 0 else a - 1 := rfl + +end fin diff --git a/src/data/fintype/basic.lean b/src/data/fintype/basic.lean index 8b555777549d8..6a0ad4418444b 100644 --- a/src/data/fintype/basic.lean +++ b/src/data/fintype/basic.lean @@ -1727,12 +1727,19 @@ have ∀ x y, r x y → (univ.filter (λ z, r z x)).card < (univ.filter (λ z, r exact ⟨λ z hzx, trans hzx hxy, not_forall_of_exists_not ⟨x, not_imp.2 ⟨hxy, irrefl x⟩⟩⟩, subrelation.wf this (measure_wf _) -lemma preorder.well_founded [fintype α] [preorder α] : well_founded ((<) : α → α → Prop) := +lemma preorder.well_founded_lt [fintype α] [preorder α] : well_founded ((<) : α → α → Prop) := well_founded_of_trans_of_irrefl _ -@[instance, priority 10] lemma linear_order.is_well_order [fintype α] [linear_order α] : +lemma preorder.well_founded_gt [fintype α] [preorder α] : well_founded ((>) : α → α → Prop) := +well_founded_of_trans_of_irrefl _ + +@[instance, priority 10] lemma linear_order.is_well_order_lt [fintype α] [linear_order α] : is_well_order α (<) := -{ wf := preorder.well_founded } +{ wf := preorder.well_founded_lt } + +@[instance, priority 10] lemma linear_order.is_well_order_gt [fintype α] [linear_order α] : + is_well_order α (>) := +{ wf := preorder.well_founded_gt } end fintype diff --git a/src/order/rel_classes.lean b/src/order/rel_classes.lean index c2cead66cf327..8db3f3846d5bf 100644 --- a/src/order/rel_classes.lean +++ b/src/order/rel_classes.lean @@ -462,3 +462,6 @@ instance order_dual.is_total_le [has_le α] [is_total α (≤)] : is_total (orde @is_total.swap α _ _ instance nat.lt.is_well_order : is_well_order ℕ (<) := ⟨nat.lt_wf⟩ + +instance [linear_order α] [h : is_well_order α (<)] : is_well_order (order_dual α) (>) := h +instance [linear_order α] [h : is_well_order α (>)] : is_well_order (order_dual α) (<) := h diff --git a/src/order/succ_pred/basic.lean b/src/order/succ_pred/basic.lean index 4b6e6416bd93a..49640974bca81 100644 --- a/src/order/succ_pred/basic.lean +++ b/src/order/succ_pred/basic.lean @@ -114,6 +114,29 @@ end preorder section linear_order variables [linear_order α] +/-- A constructor for `succ_order α` for `α` a linear order. -/ +@[simps] def succ_order.of_core (succ : α → α) (hn : ∀ {a}, ¬ is_max a → ∀ b, a < b ↔ succ a ≤ b) + (hm : ∀ a, is_max a → succ a = a) : succ_order α := +{ succ := succ, + succ_le_of_lt := λ a b, classical.by_cases (λ h hab, (hm a h).symm ▸ hab.le) (λ h, (hn h b).mp), + le_succ := λ a, classical.by_cases (λ h, (hm a h).symm.le) + (λ h, le_of_lt $ by simpa using (hn h a).not), + le_of_lt_succ := λ a b hab, classical.by_cases (λ h, hm b h ▸ hab.le) + (λ h, by simpa [hab] using (hn h a).not), + max_of_succ_le := λ a, not_imp_not.mp $ λ h, by simpa using (hn h a).not } + +/-- A constructor for `pred_order α` for `α` a linear order. -/ +@[simps] def pred_order.of_core {α} [linear_order α] (pred : α → α) + (hn : ∀ {a}, ¬ is_min a → ∀ b, b ≤ pred a ↔ b < a) (hm : ∀ a, is_min a → pred a = a) : + pred_order α := +{ pred := pred, + le_pred_of_lt := λ a b, classical.by_cases (λ h hab, (hm b h).symm ▸ hab.le) (λ h, (hn h a).mpr), + pred_le := λ a, classical.by_cases (λ h, (hm a h).le) + (λ h, le_of_lt $ by simpa using (hn h a).not), + le_of_pred_lt := λ a b hab, classical.by_cases (λ h, hm a h ▸ hab.le) + (λ h, by simpa [hab] using (hn h b).not), + min_of_le_pred := λ a, not_imp_not.mp $ λ h, by simpa using (hn h a).not } + /-- A constructor for `succ_order α` usable when `α` is a linear order with no maximal element. -/ def succ_order.of_succ_le_iff (succ : α → α) (hsucc_le_iff : ∀ {a b}, succ a ≤ b ↔ a < b) : succ_order α := @@ -939,6 +962,31 @@ lemma pred.rec_linear {p : α → Prop} (hsucc : ∀ a, p a ↔ p (pred a)) (a b end pred_order end linear_order +section is_well_order +variables [linear_order α] + +@[priority 100] +instance is_well_order.to_is_pred_archimedean [h : is_well_order α (<)] [pred_order α] : + is_pred_archimedean α := +⟨λ a, begin + refine well_founded.fix h.wf (λ b ih hab, _), + replace hab := hab.eq_or_lt, + rcases hab with rfl | hab, + { exact ⟨0, rfl⟩ }, + cases le_or_lt b (pred b) with hb hb, + { cases (min_of_le_pred hb).not_lt hab }, + obtain ⟨k, hk⟩ := ih (pred b) hb (le_pred_of_lt hab), + refine ⟨k + 1, _⟩, + rw [iterate_add_apply, iterate_one, hk], +end⟩ + +@[priority 100] +instance is_well_order.to_is_succ_archimedean [h : is_well_order α (>)] [succ_order α] : + is_succ_archimedean α := +by convert @order_dual.is_succ_archimedean (order_dual α) _ _ _ + +end is_well_order + section order_bot variables [preorder α] [order_bot α] [succ_order α] [is_succ_archimedean α] diff --git a/src/set_theory/ordinal/basic.lean b/src/set_theory/ordinal/basic.lean index b5eed328bf5b4..1ba23524f9173 100644 --- a/src/set_theory/ordinal/basic.lean +++ b/src/set_theory/ordinal/basic.lean @@ -479,7 +479,7 @@ instance (o : ordinal) : has_well_founded o.out.α := ⟨o.out.r, o.out.wo.wf⟩ instance (o : ordinal) : linear_order o.out.α := is_well_order.linear_order o.out.r -instance (o : ordinal) : is_well_order o.out.α (<) := +instance ordinal.is_well_order_lt (o : ordinal) : is_well_order o.out.α (<) := o.out.wo namespace ordinal From 4e50b688d7914d0d0b3a92027eab20af6f76d71a Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Mon, 25 Apr 2022 17:22:45 +0000 Subject: [PATCH 258/373] =?UTF-8?q?feat(category=5Ftheory/abelian):=20if?= =?UTF-8?q?=20D=20is=20abelian=20so=20is=20C=20=E2=A5=A4=20D=20(#13686)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed for LTE, and also useful to show `Rep k G` is abelian. Co-authored-by: Scott Morrison --- .../abelian/functor_category.lean | 92 +++++++++++++++++++ .../limits/preserves/shapes/kernels.lean | 4 +- .../limits/shapes/functor_category.lean | 31 +++++++ .../limits/shapes/kernels.lean | 14 +++ 4 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 src/category_theory/abelian/functor_category.lean create mode 100644 src/category_theory/limits/shapes/functor_category.lean diff --git a/src/category_theory/abelian/functor_category.lean b/src/category_theory/abelian/functor_category.lean new file mode 100644 index 0000000000000..5ec19afb4b070 --- /dev/null +++ b/src/category_theory/abelian/functor_category.lean @@ -0,0 +1,92 @@ +/- +Copyright (c) 2022 Scott Morrison. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Scott Morrison +-/ +import category_theory.abelian.basic +import category_theory.preadditive.functor_category +import category_theory.limits.shapes.functor_category +import category_theory.limits.preserves.shapes.kernels + +/-! +# If `D` is abelian, then the functor category `C ⥤ D` is also abelian. + +-/ + +noncomputable theory + +namespace category_theory +open category_theory.limits + +universes w v u +variables {C : Type (max v u)} [category.{v} C] +variables {D : Type w} [category.{max v u} D] [abelian D] + +namespace abelian + +namespace functor_category +variables {F G : C ⥤ D} (α : F ⟶ G) (X : C) + +/-- The evaluation of the abelian coimage in a functor category is +the abelian coimage of the corresponding component. -/ +@[simps] +def coimage_obj_iso : (abelian.coimage α).obj X ≅ abelian.coimage (α.app X) := +preserves_cokernel.iso ((evaluation C D).obj X) _ ≪≫ + cokernel.map_iso _ _ (preserves_kernel.iso ((evaluation C D).obj X) _) (iso.refl _) + begin + dsimp, + simp only [category.comp_id], + exact (kernel_comparison_comp_ι _ ((evaluation C D).obj X)).symm, + end + +/-- The evaluation of the abelian image in a functor category is +the abelian image of the corresponding component. -/ +@[simps] +def image_obj_iso : (abelian.image α).obj X ≅ abelian.image (α.app X) := +preserves_kernel.iso ((evaluation C D).obj X) _ ≪≫ + kernel.map_iso _ _ (iso.refl _) (preserves_cokernel.iso ((evaluation C D).obj X) _) + begin + apply (cancel_mono (preserves_cokernel.iso ((evaluation C D).obj X) α).inv).1, + simp only [category.assoc, iso.hom_inv_id], + dsimp, + simp only [category.id_comp, category.comp_id], + exact (π_comp_cokernel_comparison _ ((evaluation C D).obj X)).symm, + end + +lemma coimage_image_comparison_app : + coimage_image_comparison (α.app X) = + (coimage_obj_iso α X).inv ≫ (coimage_image_comparison α).app X ≫ (image_obj_iso α X).hom := +begin + ext, + dsimp, + simp only [category.comp_id, category.id_comp, category.assoc, + coimage_image_factorisation, limits.cokernel.π_desc_assoc, limits.kernel.lift_ι], + simp only [←evaluation_obj_map C D X], + erw kernel_comparison_comp_ι _ ((evaluation C D).obj X), + erw π_comp_cokernel_comparison_assoc _ ((evaluation C D).obj X), + simp only [←functor.map_comp], + simp only [coimage_image_factorisation, evaluation_obj_map], +end + +lemma coimage_image_comparison_app' : + (coimage_image_comparison α).app X = + (coimage_obj_iso α X).hom ≫ coimage_image_comparison (α.app X) ≫ (image_obj_iso α X).inv := +by simp only [coimage_image_comparison_app, iso.hom_inv_id_assoc, iso.hom_inv_id, category.assoc, + category.comp_id] + +instance functor_category_is_iso_coimage_image_comparison : + is_iso (abelian.coimage_image_comparison α) := +begin + haveI : ∀ X : C, is_iso ((abelian.coimage_image_comparison α).app X), + { intros, rw coimage_image_comparison_app', apply_instance, }, + apply nat_iso.is_iso_of_is_iso_app, +end + +end functor_category + +noncomputable instance : abelian (C ⥤ D) := +abelian.of_coimage_image_comparison_is_iso + +end abelian + +end category_theory diff --git a/src/category_theory/limits/preserves/shapes/kernels.lean b/src/category_theory/limits/preserves/shapes/kernels.lean index 21448cec3dca3..0662414ba6c4e 100644 --- a/src/category_theory/limits/preserves/shapes/kernels.lean +++ b/src/category_theory/limits/preserves/shapes/kernels.lean @@ -197,13 +197,13 @@ is_colimit.cocone_point_unique_up_to_iso (colimit.is_colimit _) @[simp] -lemma preserves_cokernel.iso_hom : +lemma preserves_cokernel.iso_inv : (preserves_cokernel.iso G f).inv = cokernel_comparison f G := rfl instance : is_iso (cokernel_comparison f G) := begin - rw ← preserves_cokernel.iso_hom, + rw ← preserves_cokernel.iso_inv, apply_instance end diff --git a/src/category_theory/limits/shapes/functor_category.lean b/src/category_theory/limits/shapes/functor_category.lean new file mode 100644 index 0000000000000..46fcedd223700 --- /dev/null +++ b/src/category_theory/limits/shapes/functor_category.lean @@ -0,0 +1,31 @@ +/- +Copyright (c) 2022 Scott Morrison. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Scott Morrison +-/ +import category_theory.limits.shapes.finite_limits +import category_theory.limits.functor_category + +/-! +# If `D` has finite (co)limits, so do the functor categories `C ⥤ D`. + +These are boiler-plate instances, in their own file as neither import otherwise needs the other. +-/ + +open category_theory + +namespace category_theory.limits + +universes w v u +variables {C : Type (max v u)} [category.{v} C] +variables {D : Type w} [category.{max v u} D] + +instance functor_category_has_finite_limits [has_finite_limits D] : + has_finite_limits (C ⥤ D) := +{ out := λ J _ _, by exactI infer_instance, } + +instance functor_category_has_finite_colimits [has_finite_colimits D] : + has_finite_colimits (C ⥤ D) := +{ out := λ J _ _, by exactI infer_instance, } + +end category_theory.limits diff --git a/src/category_theory/limits/shapes/kernels.lean b/src/category_theory/limits/shapes/kernels.lean index bddff1b2357ec..3a244f923f03c 100644 --- a/src/category_theory/limits/shapes/kernels.lean +++ b/src/category_theory/limits/shapes/kernels.lean @@ -225,6 +225,13 @@ lemma kernel.lift_map {X Y Z X' Y' Z' : C} kernel.lift g f w ≫ kernel.map g g' q r h₂ = p ≫ kernel.lift g' f' w' := by { ext, simp [h₁], } +/-- A commuting square of isomorphisms induces an isomorphism of kernels. -/ +@[simps] +def kernel.map_iso {X' Y' : C} (f' : X' ⟶ Y') [has_kernel f'] + (p : X ≅ X') (q : Y ≅ Y') (w : f ≫ q.hom = p.hom ≫ f') : kernel f ≅ kernel f' := +{ hom := kernel.map f f' p.hom q.hom w, + inv := kernel.map f' f p.inv q.inv (by { refine (cancel_mono q.hom).1 _, simp [w], }), } + /-- Every kernel of the zero morphism is an isomorphism -/ instance kernel.ι_zero_is_iso : is_iso (kernel.ι (0 : X ⟶ Y)) := equalizer.ι_of_self _ @@ -553,6 +560,13 @@ lemma cokernel.map_desc {X Y Z X' Y' Z' : C} cokernel.map f f' p q h₁ ≫ cokernel.desc f' g' w' = cokernel.desc f g w ≫ r := by { ext, simp [h₂], } +/-- A commuting square of isomorphisms induces an isomorphism of cokernels. -/ +@[simps] +def cokernel.map_iso {X' Y' : C} (f' : X' ⟶ Y') [has_cokernel f'] + (p : X ≅ X') (q : Y ≅ Y') (w : f ≫ q.hom = p.hom ≫ f') : cokernel f ≅ cokernel f' := +{ hom := cokernel.map f f' p.hom q.hom w, + inv := cokernel.map f' f p.inv q.inv (by { refine (cancel_mono q.hom).1 _, simp [w], }), } + /-- The cokernel of the zero morphism is an isomorphism -/ instance cokernel.π_zero_is_iso : is_iso (cokernel.π (0 : X ⟶ Y)) := From 8f604aa32be6acbbc0f28e24a47dfacf1da834f6 Mon Sep 17 00:00:00 2001 From: Eric Rodriguez Date: Mon, 25 Apr 2022 19:25:37 +0000 Subject: [PATCH 259/373] feat(data/nat/totient): totient equals one iff (#13688) --- src/data/nat/totient.lean | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/data/nat/totient.lean b/src/data/nat/totient.lean index ae3b19ef606fe..df2269212bea7 100644 --- a/src/data/nat/totient.lean +++ b/src/data/nat/totient.lean @@ -286,7 +286,18 @@ begin end @[simp] lemma totient_two : φ 2 = 1 := -(totient_prime prime_two).trans (by norm_num) +(totient_prime prime_two).trans rfl + +lemma totient_eq_one_iff : ∀ {n : ℕ}, n.totient = 1 ↔ n = 1 ∨ n = 2 +| 0 := by simp +| 1 := by simp +| 2 := by simp +| (n+3) := +begin + have : 3 ≤ n + 3 := le_add_self, + simp only [succ_succ_ne_one, false_or], + exact ⟨λ h, not_even_one.elim $ h ▸ totient_even this, by rintro ⟨⟩⟩, +end /-! ### Euler's product formula for the totient function From 438b39a7284cc701cf1ff8b12ae335fd7bac836e Mon Sep 17 00:00:00 2001 From: Aaron Anderson Date: Mon, 25 Apr 2022 23:11:10 +0000 Subject: [PATCH 260/373] feat(set_theory/cardinal/basic): Distributivity of `cardinal.sum` and + (#13643) `cardinal.sum_add_distrib` shows that `cardinal.sum` distributes over +. Co-authored-by: Aaron Anderson <65780815+awainverse@users.noreply.github.com> --- src/logic/equiv/basic.lean | 8 ++++++++ src/set_theory/cardinal/basic.lean | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/src/logic/equiv/basic.lean b/src/logic/equiv/basic.lean index a7a7ece125395..0f144bf0a4210 100644 --- a/src/logic/equiv/basic.lean +++ b/src/logic/equiv/basic.lean @@ -1214,6 +1214,14 @@ calc α × (β ⊕ γ) ≃ (β ⊕ γ) × α : prod_comm _ _ @[simp] theorem prod_sum_distrib_apply_right {α β γ} (a : α) (c : γ) : prod_sum_distrib α β γ (a, sum.inr c) = sum.inr (a, c) := rfl +/-- An indexed sum of disjoint sums of types is equivalent to the sum of the indexed sums. -/ +@[simps] def sigma_sum_distrib {ι : Type*} (α β : ι → Type*) : + (Σ i, α i ⊕ β i) ≃ (Σ i, α i) ⊕ Σ i, β i := +⟨λ p, sum.cases_on p.2 (λ x, sum.inl ⟨_, x⟩) (λ x, sum.inr ⟨_, x⟩), + sum.elim (sigma.map id (λ _, sum.inl)) (sigma.map id (λ _, sum.inr)), + λ p, by { rcases p with ⟨i, (a | b)⟩; refl }, + λ p, by { rcases p with (⟨i, a⟩ | ⟨i, b⟩); refl }⟩ + /-- The product of an indexed sum of types (formally, a `sigma`-type `Σ i, α i`) by a type `β` is equivalent to the sum of products `Σ i, (α i × β)`. -/ def sigma_prod_distrib {ι : Type*} (α : ι → Type*) (β : Type*) : diff --git a/src/set_theory/cardinal/basic.lean b/src/set_theory/cardinal/basic.lean index 056f6332a15e1..40b65a2edd1df 100644 --- a/src/set_theory/cardinal/basic.lean +++ b/src/set_theory/cardinal/basic.lean @@ -612,6 +612,11 @@ induction_on a $ λ α, mk_congr $ theorem sum_const' (ι : Type u) (a : cardinal.{u}) : sum (λ _:ι, a) = #ι * a := by simp +@[simp] theorem sum_add_distrib {ι} (f g : ι → cardinal) : + sum (f + g) = sum f + sum g := +by simpa only [mk_sigma, mk_sum, mk_out, lift_id] using + mk_congr (equiv.sigma_sum_distrib (quotient.out ∘ f) (quotient.out ∘ g)) + theorem sum_le_sum {ι} (f g : ι → cardinal) (H : ∀ i, f i ≤ g i) : sum f ≤ sum g := ⟨(embedding.refl _).sigma_map $ λ i, classical.choice $ by have := H i; rwa [← quot.out_eq (f i), ← quot.out_eq (g i)] at this⟩ From 24a8bb93a6ba81e3656ee2bc02cdec0186082614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Tue, 26 Apr 2022 01:09:50 +0000 Subject: [PATCH 261/373] feat(order/well-founded): Remove redundant arguments (#13702) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All of these are inferred as `{α : Type*}` (as opposed to `{α : Sort*}`), and there is already a `variables {α : Type*}` at the top of the file. --- src/order/well_founded.lean | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/order/well_founded.lean b/src/order/well_founded.lean index b06790d1fc0fd..347857614d4ad 100644 --- a/src/order/well_founded.lean +++ b/src/order/well_founded.lean @@ -28,19 +28,19 @@ theorem has_min {α} {r : α → α → Prop} (H : well_founded r) ⟨x, hx, λ y hy hyx, hne $ IH y hyx hy⟩) ha /-- A minimal element of a nonempty set in a well-founded order -/ -noncomputable def min {α} {r : α → α → Prop} (H : well_founded r) +noncomputable def min {r : α → α → Prop} (H : well_founded r) (p : set α) (h : p.nonempty) : α := classical.some (H.has_min p h) -theorem min_mem {α} {r : α → α → Prop} (H : well_founded r) +theorem min_mem {r : α → α → Prop} (H : well_founded r) (p : set α) (h : p.nonempty) : H.min p h ∈ p := let ⟨h, _⟩ := classical.some_spec (H.has_min p h) in h -theorem not_lt_min {α} {r : α → α → Prop} (H : well_founded r) +theorem not_lt_min {r : α → α → Prop} (H : well_founded r) (p : set α) (h : p.nonempty) {x} (xp : x ∈ p) : ¬ r x (H.min p h) := let ⟨_, h'⟩ := classical.some_spec (H.has_min p h) in h' _ xp -theorem well_founded_iff_has_min {α} {r : α → α → Prop} : (well_founded r) ↔ +theorem well_founded_iff_has_min {r : α → α → Prop} : (well_founded r) ↔ ∀ (p : set α), p.nonempty → ∃ m ∈ p, ∀ x ∈ p, ¬ r x m := begin classical, @@ -79,11 +79,11 @@ theorem well_founded_iff_has_min' [partial_order α] : (well_founded (has_lt.lt open set /-- The supremum of a bounded, well-founded order -/ -protected noncomputable def sup {α} {r : α → α → Prop} (wf : well_founded r) (s : set α) +protected noncomputable def sup {r : α → α → Prop} (wf : well_founded r) (s : set α) (h : bounded r s) : α := wf.min { x | ∀a ∈ s, r a x } h -protected lemma lt_sup {α} {r : α → α → Prop} (wf : well_founded r) {s : set α} (h : bounded r s) +protected lemma lt_sup {r : α → α → Prop} (wf : well_founded r) {s : set α} (h : bounded r s) {x} (hx : x ∈ s) : r x (wf.sup s h) := min_mem wf { x | ∀a ∈ s, r a x } h x hx @@ -91,15 +91,15 @@ section open_locale classical /-- A successor of an element `x` in a well-founded order is a minimal element `y` such that `x < y` if one exists. Otherwise it is `x` itself. -/ -protected noncomputable def succ {α} {r : α → α → Prop} (wf : well_founded r) (x : α) : α := +protected noncomputable def succ {r : α → α → Prop} (wf : well_founded r) (x : α) : α := if h : ∃y, r x y then wf.min { y | r x y } h else x -protected lemma lt_succ {α} {r : α → α → Prop} (wf : well_founded r) {x : α} (h : ∃y, r x y) : +protected lemma lt_succ {r : α → α → Prop} (wf : well_founded r) {x : α} (h : ∃y, r x y) : r x (wf.succ x) := by { rw [well_founded.succ, dif_pos h], apply min_mem } end -protected lemma lt_succ_iff {α} {r : α → α → Prop} [wo : is_well_order α r] {x : α} (h : ∃y, r x y) +protected lemma lt_succ_iff {r : α → α → Prop} [wo : is_well_order α r] {x : α} (h : ∃y, r x y) (y : α) : r y (wo.wf.succ x) ↔ r y x ∨ y = x := begin split, From 4de6527854ef9868a2309b0c7e30885f4d9704e4 Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Tue, 26 Apr 2022 02:57:32 +0000 Subject: [PATCH 262/373] feat(algebra/ring/basic): define non-unital commutative (semi)rings (#13476) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the classes of non-unital commutative (semi)rings. These are necessary to talk about, for example, non-unital commutative C∗-algebras such as `C₀(X, ℂ)` which are vital for the continuous functional calculus. In addition, we weaken many type class assumptions in `algebra/ring/basic` to `non_unital_non_assoc_ring`. --- src/algebra/monoid_algebra/basic.lean | 31 +++- src/algebra/order/ring.lean | 2 + src/algebra/ring/basic.lean | 159 ++++++++++++++---- src/algebra/ring/boolean_ring.lean | 17 +- src/algebra/ring/equiv.lean | 8 +- src/algebra/ring/opposite.lean | 12 ++ src/algebra/ring/pi.lean | 11 ++ src/algebra/ring/prod.lean | 9 + src/algebra/ring/ulift.lean | 10 ++ src/data/finsupp/pointwise.lean | 7 + src/data/set/pointwise.lean | 4 + src/logic/equiv/transfer_instance.lean | 11 ++ src/ring_theory/hahn_series.lean | 10 +- .../continuous_function/zero_at_infty.lean | 9 + src/topology/locally_constant/algebra.lean | 6 + 15 files changed, 250 insertions(+), 56 deletions(-) diff --git a/src/algebra/monoid_algebra/basic.lean b/src/algebra/monoid_algebra/basic.lean index c16ba8b5eca88..f66f0c170473e 100644 --- a/src/algebra/monoid_algebra/basic.lean +++ b/src/algebra/monoid_algebra/basic.lean @@ -207,14 +207,14 @@ def lift_nc_ring_hom (f : k →+* R) (g : G →* R) (h_comm : ∀ x y, commute ( end semiring -instance [comm_semiring k] [comm_monoid G] : comm_semiring (monoid_algebra k G) := +instance [comm_semiring k] [comm_semigroup G] : non_unital_comm_semiring (monoid_algebra k G) := { mul_comm := assume f g, begin simp only [mul_def, finsupp.sum, mul_comm], rw [finset.sum_comm], simp only [mul_comm] end, - .. monoid_algebra.semiring } + .. monoid_algebra.non_unital_semiring } instance [semiring k] [nontrivial k] [nonempty G]: nontrivial (monoid_algebra k G) := finsupp.nontrivial @@ -222,6 +222,10 @@ finsupp.nontrivial /-! #### Derived instances -/ section derived_instances +instance [comm_semiring k] [comm_monoid G] : comm_semiring (monoid_algebra k G) := +{ .. monoid_algebra.non_unital_comm_semiring, + .. monoid_algebra.semiring } + instance [semiring k] [subsingleton k] : unique (monoid_algebra k G) := finsupp.unique_of_right @@ -244,8 +248,13 @@ instance [ring k] [monoid G] : ring (monoid_algebra k G) := { .. monoid_algebra.non_unital_non_assoc_ring, .. monoid_algebra.semiring } +instance [comm_ring k] [comm_semigroup G] : non_unital_comm_ring (monoid_algebra k G) := +{ .. monoid_algebra.non_unital_comm_semiring, + .. monoid_algebra.non_unital_ring } + instance [comm_ring k] [comm_monoid G] : comm_ring (monoid_algebra k G) := -{ mul_comm := mul_comm, .. monoid_algebra.ring} +{ .. monoid_algebra.non_unital_comm_ring, + .. monoid_algebra.ring } variables {S : Type*} @@ -1041,9 +1050,10 @@ def lift_nc_ring_hom (f : k →+* R) (g : multiplicative G →* R) end semiring -instance [comm_semiring k] [add_comm_monoid G] : comm_semiring (add_monoid_algebra k G) := +instance [comm_semiring k] [add_comm_semigroup G] : + non_unital_comm_semiring (add_monoid_algebra k G) := { mul_comm := @mul_comm (monoid_algebra k $ multiplicative G) _, - .. add_monoid_algebra.semiring } + .. add_monoid_algebra.non_unital_semiring } instance [semiring k] [nontrivial k] [nonempty G] : nontrivial (add_monoid_algebra k G) := finsupp.nontrivial @@ -1051,6 +1061,10 @@ finsupp.nontrivial /-! #### Derived instances -/ section derived_instances +instance [comm_semiring k] [add_comm_monoid G] : comm_semiring (add_monoid_algebra k G) := +{ .. add_monoid_algebra.non_unital_comm_semiring, + .. add_monoid_algebra.semiring } + instance [semiring k] [subsingleton k] : unique (add_monoid_algebra k G) := finsupp.unique_of_right @@ -1073,8 +1087,13 @@ instance [ring k] [add_monoid G] : ring (add_monoid_algebra k G) := { .. add_monoid_algebra.non_unital_non_assoc_ring, .. add_monoid_algebra.semiring } +instance [comm_ring k] [add_comm_semigroup G] : non_unital_comm_ring (add_monoid_algebra k G) := +{ .. add_monoid_algebra.non_unital_comm_semiring, + .. add_monoid_algebra.non_unital_ring } + instance [comm_ring k] [add_comm_monoid G] : comm_ring (add_monoid_algebra k G) := -{ mul_comm := mul_comm, .. add_monoid_algebra.ring} +{ .. add_monoid_algebra.non_unital_comm_ring, + .. add_monoid_algebra.ring } variables {S : Type*} diff --git a/src/algebra/order/ring.lean b/src/algebra/order/ring.lean index 29c0e3ca1fe2c..fef4937123adf 100644 --- a/src/algebra/order/ring.lean +++ b/src/algebra/order/ring.lean @@ -101,11 +101,13 @@ instance [h : non_unital_non_assoc_semiring α] : non_unital_non_assoc_semiring instance [h : non_unital_semiring α] : non_unital_semiring (order_dual α) := h instance [h : non_assoc_semiring α] : non_assoc_semiring (order_dual α) := h instance [h : semiring α] : semiring (order_dual α) := h +instance [h : non_unital_comm_semiring α] : non_unital_comm_semiring (order_dual α) := h instance [h : comm_semiring α] : comm_semiring (order_dual α) := h instance [h : non_unital_non_assoc_ring α] : non_unital_non_assoc_ring (order_dual α) := h instance [h : non_unital_ring α] : non_unital_ring (order_dual α) := h instance [h : non_assoc_ring α] : non_assoc_ring (order_dual α) := h instance [h : ring α] : ring (order_dual α) := h +instance [h : non_unital_comm_ring α] : non_unital_comm_ring (order_dual α) := h instance [h : comm_ring α] : comm_ring (order_dual α) := h end order_dual diff --git a/src/algebra/ring/basic.lean b/src/algebra/ring/basic.lean index 5d9b8db4d1854..efefecdf77c51 100644 --- a/src/algebra/ring/basic.lean +++ b/src/algebra/ring/basic.lean @@ -817,6 +817,42 @@ lemma ring_hom.map_dvd [semiring β] (f : α →+* β) {a b : α} : a ∣ b → end semiring +/-- A non-unital commutative semiring is a `non_unital_semiring` with commutative multiplication. +In other words, it is a type with the following structures: additive commutative monoid +(`add_comm_monoid`), commutative semigroup (`comm_semigroup`), distributive laws (`distrib`), and +multiplication by zero law (`mul_zero_class`). -/ +@[protect_proj, ancestor non_unital_semiring comm_semigroup] +class non_unital_comm_semiring (α : Type u) extends non_unital_semiring α, comm_semigroup α + +section non_unital_comm_semiring +variables [non_unital_comm_semiring α] [non_unital_comm_semiring β] {a b c : α} + +/-- Pullback a `non_unital_semiring` instance along an injective function. +See note [reducible non-instances]. -/ +@[reducible] +protected def function.injective.non_unital_comm_semiring [has_zero γ] [has_add γ] [has_mul γ] + [has_scalar ℕ γ] (f : γ → α) (hf : injective f) (zero : f 0 = 0) + (add : ∀ x y, f (x + y) = f x + f y) (mul : ∀ x y, f (x * y) = f x * f y) + (nsmul : ∀ x (n : ℕ), f (n • x) = n • f x) : + non_unital_comm_semiring γ := +{ .. hf.non_unital_semiring f zero add mul nsmul, .. hf.comm_semigroup f mul } + +/-- Pushforward a `non_unital_semiring` instance along a surjective function. +See note [reducible non-instances]. -/ +@[reducible] +protected def function.surjective.non_unital_comm_semiring [has_zero γ] [has_add γ] [has_mul γ] + [has_scalar ℕ γ] (f : α → γ) (hf : surjective f) (zero : f 0 = 0) + (add : ∀ x y, f (x + y) = f x + f y) (mul : ∀ x y, f (x * y) = f x * f y) + (nsmul : ∀ x (n : ℕ), f (n • x) = n • f x) : + non_unital_comm_semiring γ := +{ .. hf.non_unital_semiring f zero add mul nsmul, .. hf.comm_semigroup f mul } + +lemma has_dvd.dvd.linear_comb {d x y : α} (hdx : d ∣ x) (hdy : d ∣ y) (a b : α) : + d ∣ (a * x + b * y) := +dvd_add (hdx.mul_left a) (hdy.mul_left b) + +end non_unital_comm_semiring + /-- A commutative semiring is a `semiring` with commutative multiplication. In other words, it is a type with the following structures: additive commutative monoid (`add_comm_monoid`), multiplicative commutative monoid (`comm_monoid`), distributive laws (`distrib`), and multiplication by zero law @@ -824,6 +860,10 @@ commutative monoid (`comm_monoid`), distributive laws (`distrib`), and multiplic @[protect_proj, ancestor semiring comm_monoid] class comm_semiring (α : Type u) extends semiring α, comm_monoid α +@[priority 100] -- see Note [lower instance priority] +instance comm_semiring.to_non_unital_comm_semiring [comm_semiring α] : non_unital_comm_semiring α := +{ .. comm_semiring.to_comm_monoid α, .. comm_semiring.to_semiring α } + @[priority 100] -- see Note [lower instance priority] instance comm_semiring.to_comm_monoid_with_zero [comm_semiring α] : comm_monoid_with_zero α := { .. comm_semiring.to_comm_monoid α, .. comm_semiring.to_semiring α } @@ -854,10 +894,6 @@ protected def function.surjective.comm_semiring [has_zero γ] [has_one γ] [has_ lemma add_mul_self_eq (a b : α) : (a + b) * (a + b) = a*a + 2*a*b + b*b := by simp only [two_mul, add_mul, mul_add, add_assoc, mul_comm b] -lemma has_dvd.dvd.linear_comb {d x y : α} (hdx : d ∣ x) (hdy : d ∣ y) (a b : α) : - d ∣ (a * x + b * y) := -dvd_add (hdx.mul_left a) (hdy.mul_left b) - end comm_semiring section has_distrib_neg @@ -1236,6 +1272,15 @@ def mk' {γ} [non_assoc_semiring α] [non_assoc_ring γ] (f : α →* γ) end ring_hom +/-- A non-unital commutative ring is a `non_unital_ring` with commutative multiplication. -/ +@[protect_proj, ancestor non_unital_ring comm_semigroup] +class non_unital_comm_ring (α : Type u) extends non_unital_ring α, comm_semigroup α + +@[priority 100] -- see Note [lower instance priority] +instance non_unital_comm_ring.to_non_unital_comm_semiring [s : non_unital_comm_ring α] : + non_unital_comm_semiring α := +{ ..s } + /-- A commutative ring is a `ring` with commutative multiplication. -/ @[protect_proj, ancestor ring comm_semigroup] class comm_ring (α : Type u) extends ring α, comm_monoid α @@ -1244,8 +1289,12 @@ class comm_ring (α : Type u) extends ring α, comm_monoid α instance comm_ring.to_comm_semiring [s : comm_ring α] : comm_semiring α := { mul_zero := mul_zero, zero_mul := zero_mul, ..s } -section ring -variables [ring α] {a b c : α} +@[priority 100] -- see Note [lower instance priority] +instance comm_ring.to_non_unital_comm_ring [s : comm_ring α] : non_unital_comm_ring α := +{ mul_zero := mul_zero, zero_mul := zero_mul, ..s } + +section non_unital_ring +variables [non_unital_ring α] {a b c : α} theorem dvd_sub (h₁ : a ∣ b) (h₂ : a ∣ c) : a ∣ b - c := by { rw sub_eq_add_neg, exact dvd_add h₁ (dvd_neg_of_dvd h₂) } @@ -1256,8 +1305,6 @@ theorem dvd_add_iff_left (h : a ∣ c) : a ∣ b ↔ a ∣ b + c := theorem dvd_add_iff_right (h : a ∣ b) : a ∣ c ↔ a ∣ b + c := by rw add_comm; exact dvd_add_iff_left h -theorem two_dvd_bit1 : 2 ∣ bit1 a ↔ (2 : α) ∣ 1 := (dvd_add_iff_right (@two_dvd_bit0 _ _ a)).symm - /-- If an element a divides another element c in a commutative ring, a divides the sum of another element b with c iff a divides b. -/ theorem dvd_add_left (h : a ∣ c) : a ∣ b + c ↔ a ∣ b := @@ -1268,14 +1315,6 @@ theorem dvd_add_left (h : a ∣ c) : a ∣ b + c ↔ a ∣ b := theorem dvd_add_right (h : a ∣ b) : a ∣ b + c ↔ a ∣ c := (dvd_add_iff_right h).symm -/-- An element a divides the sum a + b if and only if a divides b.-/ -@[simp] lemma dvd_add_self_left {a b : α} : a ∣ a + b ↔ a ∣ b := -dvd_add_right (dvd_refl a) - -/-- An element a divides the sum b + a if and only if a divides b.-/ -@[simp] lemma dvd_add_self_right {a b : α} : a ∣ b + a ↔ a ∣ b := -dvd_add_left (dvd_refl a) - lemma dvd_iff_dvd_of_dvd_sub {a b c : α} (h : a ∣ (b - c)) : (a ∣ b ↔ a ∣ c) := begin split, @@ -1287,38 +1326,51 @@ begin exact eq_add_of_sub_eq rfl } end +end non_unital_ring + +section ring +variables [ring α] {a b c : α} + +theorem two_dvd_bit1 : 2 ∣ bit1 a ↔ (2 : α) ∣ 1 := (dvd_add_iff_right (@two_dvd_bit0 _ _ a)).symm + +/-- An element a divides the sum a + b if and only if a divides b.-/ +@[simp] lemma dvd_add_self_left {a b : α} : a ∣ a + b ↔ a ∣ b := +dvd_add_right (dvd_refl a) + +/-- An element a divides the sum b + a if and only if a divides b.-/ +@[simp] lemma dvd_add_self_right {a b : α} : a ∣ b + a ↔ a ∣ b := +dvd_add_left (dvd_refl a) + end ring -section comm_ring -variables [comm_ring α] {a b c : α} +section non_unital_comm_ring +variables [non_unital_comm_ring α] {a b c : α} /-- Pullback a `comm_ring` instance along an injective function. See note [reducible non-instances]. -/ @[reducible] -protected def function.injective.comm_ring - [has_zero β] [has_one β] [has_add β] [has_mul β] [has_neg β] [has_sub β] - [has_scalar ℕ β] [has_scalar ℤ β] [has_pow β ℕ] - (f : β → α) (hf : injective f) (zero : f 0 = 0) (one : f 1 = 1) +protected def function.injective.non_unital_comm_ring + [has_zero β] [has_add β] [has_mul β] [has_neg β] [has_sub β] + [has_scalar ℕ β] [has_scalar ℤ β] + (f : β → α) (hf : injective f) (zero : f 0 = 0) (add : ∀ x y, f (x + y) = f x + f y) (mul : ∀ x y, f (x * y) = f x * f y) (neg : ∀ x, f (-x) = -f x) (sub : ∀ x y, f (x - y) = f x - f y) - (nsmul : ∀ x (n : ℕ), f (n • x) = n • f x) (zsmul : ∀ x (n : ℤ), f (n • x) = n • f x) - (npow : ∀ x (n : ℕ), f (x ^ n) = f x ^ n) : - comm_ring β := -{ .. hf.ring f zero one add mul neg sub nsmul zsmul npow, .. hf.comm_semigroup f mul } + (nsmul : ∀ x (n : ℕ), f (n • x) = n • f x) (zsmul : ∀ x (n : ℤ), f (n • x) = n • f x) : + non_unital_comm_ring β := +{ .. hf.non_unital_ring f zero add mul neg sub nsmul zsmul, .. hf.comm_semigroup f mul } -/-- Pushforward a `comm_ring` instance along a surjective function. +/-- Pushforward a `non_unital_comm_ring` instance along a surjective function. See note [reducible non-instances]. -/ @[reducible] -protected def function.surjective.comm_ring - [has_zero β] [has_one β] [has_add β] [has_mul β] [has_neg β] [has_sub β] - [has_scalar ℕ β] [has_scalar ℤ β] [has_pow β ℕ] - (f : α → β) (hf : surjective f) (zero : f 0 = 0) (one : f 1 = 1) +protected def function.surjective.non_unital_comm_ring + [has_zero β] [has_add β] [has_mul β] [has_neg β] [has_sub β] + [has_scalar ℕ β] [has_scalar ℤ β] + (f : α → β) (hf : surjective f) (zero : f 0 = 0) (add : ∀ x y, f (x + y) = f x + f y) (mul : ∀ x y, f (x * y) = f x * f y) (neg : ∀ x, f (-x) = -f x) (sub : ∀ x y, f (x - y) = f x - f y) - (nsmul : ∀ x (n : ℕ), f (n • x) = n • f x) (zsmul : ∀ x (n : ℤ), f (n • x) = n • f x) - (npow : ∀ x (n : ℕ), f (x ^ n) = f x ^ n) : - comm_ring β := -{ .. hf.ring f zero one add mul neg sub nsmul zsmul npow, .. hf.comm_semigroup f mul } + (nsmul : ∀ x (n : ℕ), f (n • x) = n • f x) (zsmul : ∀ x (n : ℤ), f (n • x) = n • f x) : + non_unital_comm_ring β := +{ .. hf.non_unital_ring f zero add mul neg sub nsmul zsmul, .. hf.comm_semigroup f mul } local attribute [simp] add_assoc add_comm add_left_comm mul_comm @@ -1343,6 +1395,39 @@ begin simp only [sub_eq_add_neg, add_assoc, neg_add_cancel_left], end +end non_unital_comm_ring + +section comm_ring +variables [comm_ring α] {a b c : α} + +/-- Pullback a `comm_ring` instance along an injective function. +See note [reducible non-instances]. -/ +@[reducible] +protected def function.injective.comm_ring + [has_zero β] [has_one β] [has_add β] [has_mul β] [has_neg β] [has_sub β] + [has_scalar ℕ β] [has_scalar ℤ β] [has_pow β ℕ] + (f : β → α) (hf : injective f) (zero : f 0 = 0) (one : f 1 = 1) + (add : ∀ x y, f (x + y) = f x + f y) (mul : ∀ x y, f (x * y) = f x * f y) + (neg : ∀ x, f (-x) = -f x) (sub : ∀ x y, f (x - y) = f x - f y) + (nsmul : ∀ x (n : ℕ), f (n • x) = n • f x) (zsmul : ∀ x (n : ℤ), f (n • x) = n • f x) + (npow : ∀ x (n : ℕ), f (x ^ n) = f x ^ n) : + comm_ring β := +{ .. hf.ring f zero one add mul neg sub nsmul zsmul npow, .. hf.comm_semigroup f mul } + +/-- Pushforward a `comm_ring` instance along a surjective function. +See note [reducible non-instances]. -/ +@[reducible] +protected def function.surjective.comm_ring + [has_zero β] [has_one β] [has_add β] [has_mul β] [has_neg β] [has_sub β] + [has_scalar ℕ β] [has_scalar ℤ β] [has_pow β ℕ] + (f : α → β) (hf : surjective f) (zero : f 0 = 0) (one : f 1 = 1) + (add : ∀ x y, f (x + y) = f x + f y) (mul : ∀ x y, f (x * y) = f x * f y) + (neg : ∀ x, f (-x) = -f x) (sub : ∀ x y, f (x - y) = f x - f y) + (nsmul : ∀ x (n : ℕ), f (n • x) = n • f x) (zsmul : ∀ x (n : ℤ), f (n • x) = n • f x) + (npow : ∀ x (n : ℕ), f (x ^ n) = f x ^ n) : + comm_ring β := +{ .. hf.ring f zero one add mul neg sub nsmul zsmul npow, .. hf.comm_semigroup f mul } + end comm_ring lemma succ_ne_self [non_assoc_ring α] [nontrivial α] (a : α) : a + 1 ≠ a := @@ -1376,8 +1461,8 @@ lemma is_regular_of_ne_zero' [non_unital_non_assoc_ring α] [no_zero_divisors α is_right_regular_of_non_zero_divisor k (λ x h, (no_zero_divisors.eq_zero_or_eq_zero_of_mul_eq_zero h).resolve_right hk)⟩ -lemma is_regular_iff_ne_zero' [nontrivial α] [ring α] [no_zero_divisors α] {k : α} : - is_regular k ↔ k ≠ 0 := +lemma is_regular_iff_ne_zero' [nontrivial α] [non_unital_non_assoc_ring α] [no_zero_divisors α] + {k : α} : is_regular k ↔ k ≠ 0 := ⟨λ h, by { rintro rfl, exact not_not.mpr h.left not_is_left_regular_zero }, is_regular_of_ne_zero'⟩ /-- A ring with no zero divisors is a cancel_monoid_with_zero. diff --git a/src/algebra/ring/boolean_ring.lean b/src/algebra/ring/boolean_ring.lean index 6f9b16445b0ca..3851071263fab 100644 --- a/src/algebra/ring/boolean_ring.lean +++ b/src/algebra/ring/boolean_ring.lean @@ -270,8 +270,8 @@ iff.rfl instance [inhabited α] : inhabited (as_boolring α) := ‹inhabited α› -/-- Every generalized Boolean algebra has the structure of a non unital ring with the following -data: +/-- Every generalized Boolean algebra has the structure of a non unital commutative ring with the +following data: * `a + b` unfolds to `a ∆ b` (symmetric difference) * `a * b` unfolds to `a ⊓ b` @@ -279,8 +279,8 @@ data: * `0` unfolds to `⊥` -/ @[reducible] -- See note [reducible non-instances] -def generalized_boolean_algebra.to_non_unital_ring [generalized_boolean_algebra α] : - non_unital_ring α := +def generalized_boolean_algebra.to_non_unital_comm_ring [generalized_boolean_algebra α] : + non_unital_comm_ring α := { add := (∆), add_assoc := symm_diff_assoc, zero := ⊥, @@ -293,11 +293,12 @@ def generalized_boolean_algebra.to_non_unital_ring [generalized_boolean_algebra add_comm := symm_diff_comm, mul := (⊓), mul_assoc := λ _ _ _, inf_assoc, + mul_comm := λ _ _, inf_comm, left_distrib := inf_symm_diff_distrib_left, right_distrib := inf_symm_diff_distrib_right } -instance [generalized_boolean_algebra α] : non_unital_ring (as_boolring α) := -@generalized_boolean_algebra.to_non_unital_ring α _ +instance [generalized_boolean_algebra α] : non_unital_comm_ring (as_boolring α) := +@generalized_boolean_algebra.to_non_unital_comm_ring α _ variables [boolean_algebra α] [boolean_algebra β] [boolean_algebra γ] @@ -315,9 +316,9 @@ def boolean_algebra.to_boolean_ring : boolean_ring α := one_mul := λ _, top_inf_eq, mul_one := λ _, inf_top_eq, mul_self := λ b, inf_idem, - ..generalized_boolean_algebra.to_non_unital_ring } + ..generalized_boolean_algebra.to_non_unital_comm_ring } -localized "attribute [instance, priority 100] generalized_boolean_algebra.to_non_unital_ring +localized "attribute [instance, priority 100] generalized_boolean_algebra.to_non_unital_comm_ring boolean_algebra.to_boolean_ring" in boolean_ring_of_boolean_algebra instance : boolean_ring (as_boolring α) := @boolean_algebra.to_boolean_ring α _ diff --git a/src/algebra/ring/equiv.lean b/src/algebra/ring/equiv.lean index 7c0e8d355380d..ab12a7833c75f 100644 --- a/src/algebra/ring/equiv.lean +++ b/src/algebra/ring/equiv.lean @@ -228,11 +228,11 @@ protected def op {α β} [has_add α] [has_mul α] [has_add β] [has_mul β] : @[simp] protected def unop {α β} [has_add α] [has_mul α] [has_add β] [has_mul β] : (αᵐᵒᵖ ≃+* βᵐᵒᵖ) ≃ (α ≃+* β) := ring_equiv.op.symm -section comm_semiring +section non_unital_comm_semiring -variables (R) [comm_semiring R] +variables (R) [non_unital_comm_semiring R] -/-- A commutative ring is isomorphic to its opposite. -/ +/-- A non-unital commutative ring is isomorphic to its opposite. -/ def to_opposite : R ≃+* Rᵐᵒᵖ := { map_add' := λ x y, rfl, map_mul' := λ x y, mul_comm (op y) (op x), @@ -244,7 +244,7 @@ lemma to_opposite_apply (r : R) : to_opposite R r = op r := rfl @[simp] lemma to_opposite_symm_apply (r : Rᵐᵒᵖ) : (to_opposite R).symm r = unop r := rfl -end comm_semiring +end non_unital_comm_semiring end opposite diff --git a/src/algebra/ring/opposite.lean b/src/algebra/ring/opposite.lean index 05e9e683397ac..8497108915589 100644 --- a/src/algebra/ring/opposite.lean +++ b/src/algebra/ring/opposite.lean @@ -47,6 +47,9 @@ instance [semiring α] : semiring αᵐᵒᵖ := { .. mul_opposite.non_unital_semiring α, .. mul_opposite.non_assoc_semiring α, .. mul_opposite.monoid_with_zero α } +instance [non_unital_comm_semiring α] : non_unital_comm_semiring αᵐᵒᵖ := +{ .. mul_opposite.non_unital_semiring α, .. mul_opposite.comm_semigroup α } + instance [comm_semiring α] : comm_semiring αᵐᵒᵖ := { .. mul_opposite.semiring α, .. mul_opposite.comm_semigroup α } @@ -63,6 +66,9 @@ instance [non_assoc_ring α] : non_assoc_ring αᵐᵒᵖ := instance [ring α] : ring αᵐᵒᵖ := { .. mul_opposite.add_comm_group α, .. mul_opposite.monoid α, .. mul_opposite.semiring α } +instance [non_unital_comm_ring α] : non_unital_comm_ring αᵐᵒᵖ := +{ .. mul_opposite.non_unital_ring α, .. mul_opposite.non_unital_comm_semiring α } + instance [comm_ring α] : comm_ring αᵐᵒᵖ := { .. mul_opposite.ring α, .. mul_opposite.comm_semiring α } @@ -117,6 +123,9 @@ instance [semiring α] : semiring αᵃᵒᵖ := { .. add_opposite.non_unital_semiring α, .. add_opposite.non_assoc_semiring α, .. add_opposite.monoid_with_zero α } +instance [non_unital_comm_semiring α] : non_unital_comm_semiring αᵃᵒᵖ := +{ .. add_opposite.non_unital_semiring α, .. add_opposite.comm_semigroup α } + instance [comm_semiring α] : comm_semiring αᵃᵒᵖ := { .. add_opposite.semiring α, .. add_opposite.comm_semigroup α } @@ -133,6 +142,9 @@ instance [non_assoc_ring α] : non_assoc_ring αᵃᵒᵖ := instance [ring α] : ring αᵃᵒᵖ := { .. add_opposite.add_comm_group α, .. add_opposite.monoid α, .. add_opposite.semiring α } +instance [non_unital_comm_ring α] : non_unital_comm_ring αᵃᵒᵖ := +{ .. add_opposite.non_unital_ring α, .. add_opposite.non_unital_comm_semiring α } + instance [comm_ring α] : comm_ring αᵃᵒᵖ := { .. add_opposite.ring α, .. add_opposite.comm_semiring α } diff --git a/src/algebra/ring/pi.lean b/src/algebra/ring/pi.lean index 33af3ec66d4b0..7b0ff31115171 100644 --- a/src/algebra/ring/pi.lean +++ b/src/algebra/ring/pi.lean @@ -42,6 +42,11 @@ by refine_struct { zero := (0 : Π i, f i), one := 1, add := (+), mul := (*), nsmul := add_monoid.nsmul, npow := monoid.npow }; tactic.pi_instance_derive_field +instance non_unital_comm_semiring [∀ i, non_unital_comm_semiring $ f i] : + non_unital_comm_semiring (Π i : I, f i) := +by refine_struct { zero := (0 : Π i, f i), add := (+), mul := (*), nsmul := add_monoid.nsmul }; +tactic.pi_instance_derive_field + instance comm_semiring [∀ i, comm_semiring $ f i] : comm_semiring (Π i : I, f i) := by refine_struct { zero := (0 : Π i, f i), one := 1, add := (+), mul := (*), nsmul := add_monoid.nsmul, npow := monoid.npow }; @@ -71,6 +76,12 @@ by refine_struct { zero := (0 : Π i, f i), one := 1, add := (+), mul := (*), npow := monoid.npow }; tactic.pi_instance_derive_field +instance non_unital_comm_ring [∀ i, non_unital_comm_ring $ f i] : + non_unital_comm_ring (Π i : I, f i) := +by refine_struct { zero := (0 : Π i, f i), add := (+), mul := (*), neg := has_neg.neg, + nsmul := add_monoid.nsmul, zsmul := sub_neg_monoid.zsmul }; +tactic.pi_instance_derive_field + instance comm_ring [∀ i, comm_ring $ f i] : comm_ring (Π i : I, f i) := by refine_struct { zero := (0 : Π i, f i), one := 1, add := (+), mul := (*), neg := has_neg.neg, nsmul := add_monoid.nsmul, zsmul := sub_neg_monoid.zsmul, diff --git a/src/algebra/ring/prod.lean b/src/algebra/ring/prod.lean index 472ecee75591b..e3b5c9b826518 100644 --- a/src/algebra/ring/prod.lean +++ b/src/algebra/ring/prod.lean @@ -49,6 +49,11 @@ instance [non_assoc_semiring R] [non_assoc_semiring S] : instance [semiring R] [semiring S] : semiring (R × S) := { .. prod.add_comm_monoid, .. prod.monoid_with_zero, .. prod.distrib } +/-- Product of two `non_unital_comm_semiring`s is a `non_unital_comm_semiring`. -/ +instance [non_unital_comm_semiring R] [non_unital_comm_semiring S] : + non_unital_comm_semiring (R × S) := +{ .. prod.non_unital_semiring, .. prod.comm_semigroup } + /-- Product of two commutative semirings is a commutative semiring. -/ instance [comm_semiring R] [comm_semiring S] : comm_semiring (R × S) := { .. prod.semiring, .. prod.comm_monoid } @@ -69,6 +74,10 @@ instance [non_assoc_ring R] [non_assoc_ring S] : instance [ring R] [ring S] : ring (R × S) := { .. prod.add_comm_group, .. prod.semiring } +/-- Product of two `non_unital_comm_ring`s is a `non_unital_comm_ring`. -/ +instance [non_unital_comm_ring R] [non_unital_comm_ring S] : non_unital_comm_ring (R × S) := +{ .. prod.non_unital_ring, .. prod.comm_semigroup } + /-- Product of two commutative rings is a commutative ring. -/ instance [comm_ring R] [comm_ring S] : comm_ring (R × S) := { .. prod.ring, .. prod.comm_monoid } diff --git a/src/algebra/ring/ulift.lean b/src/algebra/ring/ulift.lean index 7037131e5a7ce..d09849d02ccc1 100644 --- a/src/algebra/ring/ulift.lean +++ b/src/algebra/ring/ulift.lean @@ -59,6 +59,11 @@ def ring_equiv [non_unital_non_assoc_semiring α] : ulift α ≃+* α := left_inv := by tidy, right_inv := by tidy, } +instance non_unital_comm_semiring [non_unital_comm_semiring α] : + non_unital_comm_semiring (ulift α) := +by refine_struct { zero := (0 : ulift α), add := (+), mul := (*), nsmul := add_monoid.nsmul }; +tactic.pi_instance_derive_field + instance comm_semiring [comm_semiring α] : comm_semiring (ulift α) := by refine_struct { zero := (0 : ulift α), one := 1, add := (+), mul := (*), nsmul := add_monoid.nsmul, npow := monoid.npow }; @@ -88,6 +93,11 @@ by refine_struct { zero := (0 : ulift α), one := 1, add := (+), mul := (*), sub zsmul := sub_neg_monoid.zsmul }; tactic.pi_instance_derive_field +instance non_unital_comm_ring [non_unital_comm_ring α] : non_unital_comm_ring (ulift α) := +by refine_struct { zero := (0 : ulift α), add := (+), mul := (*), sub := has_sub.sub, + neg := has_neg.neg, nsmul := add_monoid.nsmul, zsmul := sub_neg_monoid.zsmul }; +tactic.pi_instance_derive_field + instance comm_ring [comm_ring α] : comm_ring (ulift α) := by refine_struct { zero := (0 : ulift α), one := 1, add := (+), mul := (*), sub := has_sub.sub, neg := has_neg.neg, nsmul := add_monoid.nsmul, npow := monoid.npow, diff --git a/src/data/finsupp/pointwise.lean b/src/data/finsupp/pointwise.lean index ac57f2d91ff7f..17a4c91e3e405 100644 --- a/src/data/finsupp/pointwise.lean +++ b/src/data/finsupp/pointwise.lean @@ -62,6 +62,9 @@ finsupp.coe_fn_injective.non_unital_non_assoc_semiring _ coe_zero coe_add coe_mu instance [non_unital_semiring β] : non_unital_semiring (α →₀ β) := finsupp.coe_fn_injective.non_unital_semiring _ coe_zero coe_add coe_mul (λ _ _, rfl) +instance [non_unital_comm_semiring β] : non_unital_comm_semiring (α →₀ β) := +finsupp.coe_fn_injective.non_unital_comm_semiring _ coe_zero coe_add coe_mul (λ _ _, rfl) + instance [non_unital_non_assoc_ring β] : non_unital_non_assoc_ring (α →₀ β) := finsupp.coe_fn_injective.non_unital_non_assoc_ring _ coe_zero coe_add coe_mul coe_neg coe_sub (λ _ _, rfl) (λ _ _, rfl) @@ -70,6 +73,10 @@ instance [non_unital_ring β] : non_unital_ring (α →₀ β) := finsupp.coe_fn_injective.non_unital_ring _ coe_zero coe_add coe_mul coe_neg coe_sub (λ _ _, rfl) (λ _ _, rfl) +instance [non_unital_comm_ring β] : non_unital_comm_ring (α →₀ β) := +finsupp.coe_fn_injective.non_unital_comm_ring _ + coe_zero coe_add coe_mul coe_neg coe_sub (λ _ _, rfl) (λ _ _, rfl) + -- TODO can this be generalized in the direction of `pi.has_scalar'` -- (i.e. dependent functions and finsupps) -- TODO in theory this could be generalised, we only really need `smul_zero` for the definition diff --git a/src/data/set/pointwise.lean b/src/data/set/pointwise.lean index 27cadc02865a8..da6cd0863be49 100644 --- a/src/data/set/pointwise.lean +++ b/src/data/set/pointwise.lean @@ -1042,6 +1042,10 @@ instance set_semiring.non_unital_semiring [semigroup α] : non_unital_semiring ( instance set_semiring.semiring [monoid α] : semiring (set_semiring α) := { ..set_semiring.non_assoc_semiring, ..set_semiring.non_unital_semiring } +instance set_semiring.non_unital_comm_semiring [comm_semigroup α] : + non_unital_comm_semiring (set_semiring α) := +{ ..set_semiring.non_unital_semiring, ..set.comm_semigroup } + instance set_semiring.comm_semiring [comm_monoid α] : comm_semiring (set_semiring α) := { ..set.comm_monoid, ..set_semiring.semiring } diff --git a/src/logic/equiv/transfer_instance.lean b/src/logic/equiv/transfer_instance.lean index 9063a16cb87bf..60ed443084927 100644 --- a/src/logic/equiv/transfer_instance.lean +++ b/src/logic/equiv/transfer_instance.lean @@ -206,6 +206,11 @@ let zero := e.has_zero, add := e.has_add, one := e.has_one, mul := e.has_mul, nsmul := e.has_scalar ℕ, npow := e.has_pow ℕ in by resetI; apply e.injective.semiring _; intros; exact e.apply_symm_apply _ +/-- Transfer `non_unital_comm_semiring` across an `equiv` -/ +protected def non_unital_comm_semiring [non_unital_comm_semiring β] : non_unital_comm_semiring α := +let zero := e.has_zero, add := e.has_add, mul := e.has_mul, nsmul := e.has_scalar ℕ in +by resetI; apply e.injective.non_unital_comm_semiring _; intros; exact e.apply_symm_apply _ + /-- Transfer `comm_semiring` across an `equiv` -/ protected def comm_semiring [comm_semiring β] : comm_semiring α := let zero := e.has_zero, add := e.has_add, one := e.has_one, mul := e.has_mul, @@ -239,6 +244,12 @@ let zero := e.has_zero, add := e.has_add, one := e.has_one, mul := e.has_mul, ne sub := e.has_sub, nsmul := e.has_scalar ℕ, zsmul := e.has_scalar ℤ, npow := e.has_pow ℕ in by resetI; apply e.injective.ring _; intros; exact e.apply_symm_apply _ +/-- Transfer `non_unital_comm_ring` across an `equiv` -/ +protected def non_unital_comm_ring [non_unital_comm_ring β] : non_unital_comm_ring α := +let zero := e.has_zero, add := e.has_add, mul := e.has_mul, neg := e.has_neg, + sub := e.has_sub, nsmul := e.has_scalar ℕ, zsmul := e.has_scalar ℤ in +by resetI; apply e.injective.non_unital_comm_ring _; intros; exact e.apply_symm_apply _ + /-- Transfer `comm_ring` across an `equiv` -/ protected def comm_ring [comm_ring β] : comm_ring α := let zero := e.has_zero, add := e.has_add, one := e.has_one, mul := e.has_mul, neg := e.has_neg, diff --git a/src/ring_theory/hahn_series.lean b/src/ring_theory/hahn_series.lean index 74db2ffa13ecc..37d7efe8c1191 100644 --- a/src/ring_theory/hahn_series.lean +++ b/src/ring_theory/hahn_series.lean @@ -732,7 +732,7 @@ instance [semiring R] : semiring (hahn_series Γ R) := .. hahn_series.non_assoc_semiring, .. hahn_series.non_unital_semiring } -instance [comm_semiring R] : comm_semiring (hahn_series Γ R) := +instance [non_unital_comm_semiring R] : non_unital_comm_semiring (hahn_series Γ R) := { mul_comm := λ x y, begin ext, simp_rw [mul_coeff, mul_comm], @@ -751,6 +751,10 @@ instance [comm_semiring R] : comm_semiring (hahn_series Γ R) := ne.def, set.mem_set_of_eq] at ha ⊢, exact ⟨(add_comm _ _).trans ha.1, ha.2.2, ha.2.1⟩ } end, + .. hahn_series.non_unital_semiring } + +instance [comm_semiring R] : comm_semiring (hahn_series Γ R) := +{ .. hahn_series.non_unital_comm_semiring, .. hahn_series.semiring } instance [non_unital_non_assoc_ring R] : non_unital_non_assoc_ring (hahn_series Γ R) := @@ -769,6 +773,10 @@ instance [ring R] : ring (hahn_series Γ R) := { .. hahn_series.semiring, .. hahn_series.add_comm_group } +instance [non_unital_comm_ring R] : non_unital_comm_ring (hahn_series Γ R) := +{ .. hahn_series.non_unital_comm_semiring, + .. hahn_series.non_unital_ring } + instance [comm_ring R] : comm_ring (hahn_series Γ R) := { .. hahn_series.comm_semiring, .. hahn_series.ring } diff --git a/src/topology/continuous_function/zero_at_infty.lean b/src/topology/continuous_function/zero_at_infty.lean index 22dd60256e6ea..38d780ee2f4b3 100644 --- a/src/topology/continuous_function/zero_at_infty.lean +++ b/src/topology/continuous_function/zero_at_infty.lean @@ -231,6 +231,10 @@ instance [non_unital_semiring β] [topological_semiring β] : non_unital_semiring C₀(α, β) := fun_like.coe_injective.non_unital_semiring _ coe_zero coe_add coe_mul (λ _ _, rfl) +instance [non_unital_comm_semiring β] [topological_semiring β] : + non_unital_comm_semiring C₀(α, β) := +fun_like.coe_injective.non_unital_comm_semiring _ coe_zero coe_add coe_mul (λ _ _, rfl) + instance [non_unital_non_assoc_ring β] [topological_ring β] : non_unital_non_assoc_ring C₀(α, β) := fun_like.coe_injective.non_unital_non_assoc_ring _ coe_zero coe_add coe_mul coe_neg coe_sub @@ -241,6 +245,11 @@ instance [non_unital_ring β] [topological_ring β] : fun_like.coe_injective.non_unital_ring _ coe_zero coe_add coe_mul coe_neg coe_sub (λ _ _, rfl) (λ _ _, rfl) +instance [non_unital_comm_ring β] [topological_ring β] : + non_unital_comm_ring C₀(α, β) := +fun_like.coe_injective.non_unital_comm_ring _ coe_zero coe_add coe_mul coe_neg coe_sub (λ _ _, rfl) + (λ _ _, rfl) + instance {R : Type*} [semiring R] [non_unital_non_assoc_semiring β] [topological_semiring β] [module R β] [has_continuous_const_smul R β] [is_scalar_tower R β β] : is_scalar_tower R C₀(α, β) C₀(α, β) := diff --git a/src/topology/locally_constant/algebra.lean b/src/topology/locally_constant/algebra.lean index 577481f4ec6cf..e811f342f3805 100644 --- a/src/topology/locally_constant/algebra.lean +++ b/src/topology/locally_constant/algebra.lean @@ -133,6 +133,9 @@ instance [semiring Y] : semiring (locally_constant X Y) := { .. locally_constant.add_comm_monoid, .. locally_constant.monoid, .. locally_constant.distrib, .. locally_constant.mul_zero_class } +instance [non_unital_comm_semiring Y] : non_unital_comm_semiring (locally_constant X Y) := +{ .. locally_constant.non_unital_semiring, .. locally_constant.comm_semigroup } + instance [comm_semiring Y] : comm_semiring (locally_constant X Y) := { .. locally_constant.semiring, .. locally_constant.comm_monoid } @@ -149,6 +152,9 @@ instance [non_assoc_ring Y] : non_assoc_ring (locally_constant X Y) := instance [ring Y] : ring (locally_constant X Y) := { .. locally_constant.semiring, .. locally_constant.add_comm_group } +instance [non_unital_comm_ring Y] : non_unital_comm_ring (locally_constant X Y) := +{ .. locally_constant.non_unital_comm_semiring, .. locally_constant.non_unital_ring } + instance [comm_ring Y] : comm_ring (locally_constant X Y) := { .. locally_constant.comm_semiring, .. locally_constant.ring } From 748ea79bf026554559d27fdb23ba7d74d4f8e22b Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Tue, 26 Apr 2022 04:54:37 +0000 Subject: [PATCH 263/373] feat(order/filter/basic): more lemmas about `filter.comap` (#13619) * add `set.compl_def`, `set.finite_image_fst_and_snd_iff`, and `set.forall_finite_image_eval_iff`; * add `filter.coext`, an extensionality lemma that is more useful for "cofilters"; * rename `filter.eventually_comap'` to `filter.eventually.comap`; * add `filter.mem_comap'`, `filter.mem_comap_iff_compl`, and `filter.compl_mem_comap`; * add `filter.compl_mem_coprod`, replace `filter.compl_mem_Coprod_iff` with a simpler `filter.compl_mem_Coprod`; * add `filter.map_top`; * use new lemmas to golf some proofs. Co-authored-by: Eric Wieser --- src/data/set/basic.lean | 2 + src/data/set/finite.lean | 9 +++ src/order/filter/basic.lean | 77 ++++++++++--------- src/order/filter/cofinite.lean | 17 +--- src/order/filter/pi.lean | 10 +-- .../algebra/order/intermediate_value.lean | 4 +- src/topology/subset_properties.lean | 20 +++-- 7 files changed, 69 insertions(+), 70 deletions(-) diff --git a/src/data/set/basic.lean b/src/data/set/basic.lean index e5cd3e4477914..570a443d8d70f 100644 --- a/src/data/set/basic.lean +++ b/src/data/set/basic.lean @@ -853,6 +853,8 @@ ssubset_singleton_iff.1 hs /-! ### Lemmas about complement -/ +lemma compl_def (s : set α) : sᶜ = {x | x ∉ s} := rfl + theorem mem_compl {s : set α} {x : α} (h : x ∉ s) : x ∈ sᶜ := h lemma compl_set_of {α} (p : α → Prop) : {a | p a}ᶜ = { a | ¬ p a } := rfl diff --git a/src/data/set/finite.lean b/src/data/set/finite.lean index 3a7af5e50e47d..01f7b87e09b23 100644 --- a/src/data/set/finite.lean +++ b/src/data/set/finite.lean @@ -493,6 +493,11 @@ fintype.of_finset (s.to_finset.product t.to_finset) $ by simp lemma finite.prod {s : set α} {t : set β} : finite s → finite t → finite (s ×ˢ t) | ⟨hs⟩ ⟨ht⟩ := by exactI ⟨set.fintype_prod s t⟩ +lemma finite_image_fst_and_snd_iff {s : set (α × β)} : + finite (prod.fst '' s) ∧ finite (prod.snd '' s) ↔ finite s := +⟨λ h, (h.1.prod h.2).subset $ λ x h, ⟨mem_image_of_mem _ h, mem_image_of_mem _ h⟩, + λ h, ⟨h.image _, h.image _⟩⟩ + /-- `image2 f s t` is finitype if `s` and `t` are. -/ instance fintype_image2 [decidable_eq γ] (f : α → β → γ) (s : set α) (t : set β) [hs : fintype s] [ht : fintype t] : fintype (image2 f s t : set γ) := @@ -593,6 +598,10 @@ begin exact (fintype.pi_finset t).finite_to_set, end +lemma forall_finite_image_eval_iff {δ : Type*} [fintype δ] {κ : δ → Type*} {s : set (Π d, κ d)} : + (∀ d, finite (eval d '' s)) ↔ finite s := +⟨λ h, (finite.pi h).subset $ subset_pi_eval_image _ _, λ h d, h.image _⟩ + /-- A finite union of finsets is finite. -/ lemma union_finset_finite_of_range_finite (f : α → finset β) (h : (range f).finite) : (⋃ a, (f a : set β)).finite := diff --git a/src/order/filter/basic.lean b/src/order/filter/basic.lean index 6c7da4b3ae4f0..68c9530e6aa07 100644 --- a/src/order/filter/basic.lean +++ b/src/order/filter/basic.lean @@ -119,6 +119,11 @@ by simp only [filter_eq_iff, ext_iff, filter.mem_sets] protected lemma ext : (∀ s, s ∈ f ↔ s ∈ g) → f = g := filter.ext_iff.2 +/-- An extensionality lemma that is useful for filters with good lemmas about `sᶜ ∈ f` (e.g., +`filter.comap`, `filter.coprod`, `filter.Coprod`, `filter.cofinite`). -/ +protected lemma coext (h : ∀ s, sᶜ ∈ f ↔ sᶜ ∈ g) : f = g := +filter.ext $ compl_surjective.forall.2 h + @[simp] lemma univ_mem : univ ∈ f := f.univ_sets @@ -1505,7 +1510,13 @@ end map section comap -/-- The inverse map of a filter -/ +/-- The inverse map of a filter. A set `s` belongs to `filter.comap f l` if either of the following +equivalent conditions hold. + +1. There exists a set `t ∈ l` such that `f ⁻¹' t ⊆ s`. This is used as a definition. +2. The set `{y | ∀ x, f x = y → x ∈ s}` belongs to `l`, see `filter.mem_comap'`. +3. The set `(f '' sᶜ)ᶜ` belongs to `l`, see `filter.mem_comap_iff_compl` and +`filter.compl_mem_comap`. -/ def comap (m : α → β) (f : filter β) : filter α := { sets := { s | ∃ t ∈ f, m ⁻¹' t ⊆ s }, univ_sets := ⟨univ, univ_mem, by simp only [subset_univ, preimage_univ]⟩, @@ -1513,25 +1524,24 @@ def comap (m : α → β) (f : filter β) : filter α := inter_sets := λ a b ⟨a', ha₁, ha₂⟩ ⟨b', hb₁, hb₂⟩, ⟨a' ∩ b', inter_mem ha₁ hb₁, inter_subset_inter ha₂ hb₂⟩ } -lemma eventually_comap' {f : filter β} {φ : α → β} {p : β → Prop} (hf : ∀ᶠ b in f, p b) : - ∀ᶠ a in comap φ f, p (φ a) := -⟨_, hf, (λ a h, h)⟩ +variables {f : α → β} {l : filter β} {p : α → Prop} {s : set α} -@[simp] lemma eventually_comap {f : filter β} {φ : α → β} {P : α → Prop} : - (∀ᶠ a in comap φ f, P a) ↔ ∀ᶠ b in f, ∀ a, φ a = b → P a := -begin - split ; intro h, - { rcases h with ⟨t, t_in, ht⟩, - apply mem_of_superset t_in, - rintro y y_in _ rfl, - apply ht y_in }, - { exact ⟨_, h, λ _ x_in, x_in _ rfl⟩ } -end +lemma mem_comap' : s ∈ comap f l ↔ {y | ∀ ⦃x⦄, f x = y → x ∈ s} ∈ l := +⟨λ ⟨t, ht, hts⟩, mem_of_superset ht $ λ y hy x hx, hts $ mem_preimage.2 $ by rwa hx, + λ h, ⟨_, h, λ x hx, hx rfl⟩⟩ -@[simp] lemma frequently_comap {f : filter β} {φ : α → β} {P : α → Prop} : - (∃ᶠ a in comap φ f, P a) ↔ ∃ᶠ b in f, ∃ a, φ a = b ∧ P a := +@[simp] lemma eventually_comap : (∀ᶠ a in comap f l, p a) ↔ ∀ᶠ b in l, ∀ a, f a = b → p a := +mem_comap' + +@[simp] lemma frequently_comap : (∃ᶠ a in comap f l, p a) ↔ ∃ᶠ b in l, ∃ a, f a = b ∧ p a := by simp only [filter.frequently, eventually_comap, not_exists, not_and] +lemma mem_comap_iff_compl : s ∈ comap f l ↔ (f '' sᶜ)ᶜ ∈ l := +by simp only [mem_comap', compl_def, mem_image, mem_set_of_eq, not_exists, not_and', not_not] + +lemma compl_mem_comap : sᶜ ∈ comap f l ↔ (f '' s)ᶜ ∈ l := +by rw [mem_comap_iff_compl, compl_compl] + end comap /-- The monadic bind operation on filter is defined the usual way in terms of `map` and `join`. @@ -1619,39 +1629,25 @@ variables {f f₁ f₂ : filter α} {g g₁ g₂ : filter β} {m : α → β} {m theorem preimage_mem_comap (ht : t ∈ g) : m ⁻¹' t ∈ comap m g := ⟨t, ht, subset.rfl⟩ +lemma eventually.comap {p : β → Prop} (hf : ∀ᶠ b in g, p b) (f : α → β) : + ∀ᶠ a in comap f g, p (f a) := +preimage_mem_comap hf + lemma comap_id : comap id f = f := le_antisymm (λ s, preimage_mem_comap) (λ s ⟨t, ht, hst⟩, mem_of_superset ht hst) lemma comap_const_of_not_mem {x : β} (ht : t ∈ g) (hx : x ∉ t) : comap (λ y : α, x) g = ⊥ := -begin - ext W, - suffices : ∃ t ∈ g, (λ (y : α), x) ⁻¹' t ⊆ W, by simpa, - use [t, ht], - simp [preimage_const_of_not_mem hx], -end +empty_mem_iff_bot.1 $ mem_comap'.2 $ mem_of_superset ht $ λ x' hx' y h, hx $ h.symm ▸ hx' lemma comap_const_of_mem {x : β} (h : ∀ t ∈ g, x ∈ t) : comap (λ y : α, x) g = ⊤ := -begin - ext W, - suffices : (∃ (t : set β), t ∈ g ∧ (λ (y : α), x) ⁻¹' t ⊆ W) ↔ W = univ, - by simpa, - split, - { rintro ⟨V, V_in, hW⟩, - simpa [preimage_const_of_mem (h V V_in), univ_subset_iff] using hW }, - { rintro rfl, - use univ, - simp [univ_mem] }, -end +top_unique $ λ s hs, univ_mem' $ λ y, h _ (mem_comap'.1 hs) rfl lemma map_const [ne_bot f] {c : β} : f.map (λ x, c) = pure c := by { ext s, by_cases h : c ∈ s; simp [h] } lemma comap_comap {m : γ → β} {n : β → α} : comap m (comap n f) = comap (n ∘ m) f := -le_antisymm - (λ c ⟨b, hb, (h : preimage (n ∘ m) b ⊆ c)⟩, ⟨preimage n b, preimage_mem_comap hb, h⟩) - (λ c ⟨b, ⟨a, ha, (h₁ : preimage n a ⊆ b)⟩, (h₂ : preimage m b ⊆ c)⟩, - ⟨a, ha, show preimage m (preimage n a) ⊆ c, from (preimage_mono h₁).trans h₂⟩) +filter.coext $ λ s, by simp only [compl_mem_comap, image_image] section comm variables {δ : Type*} @@ -1698,6 +1694,9 @@ lemma gc_map_comap (m : α → β) : galois_connection (map m) (comap m) := @[simp] lemma map_supr {f : ι → filter α} : map m (⨆ i, f i) = (⨆ i, map m (f i)) := (gc_map_comap m).l_supr +@[simp] lemma map_top (f : α → β) : map f ⊤ = 𝓟 (range f) := +by rw [← principal_univ, map_principal, image_univ] + @[simp] lemma comap_top : comap m ⊤ = ⊤ := (gc_map_comap m).u_top @[simp] lemma comap_inf : comap m (g₁ ⊓ g₂) = comap m g₁ ⊓ comap m g₂ := (gc_map_comap m).u_inf @[simp] lemma comap_infi {f : ι → filter β} : comap m (⨅ i, f i) = (⨅ i, comap m (f i)) := @@ -2737,6 +2736,10 @@ by simp [filter.coprod] lemma bot_coprod_bot : (⊥ : filter α).coprod (⊥ : filter β) = ⊥ := by simp +lemma compl_mem_coprod {s : set (α × β)} {la : filter α} {lb : filter β} : + sᶜ ∈ la.coprod lb ↔ (prod.fst '' s)ᶜ ∈ la ∧ (prod.snd '' s)ᶜ ∈ lb := +by simp only [filter.coprod, mem_sup, compl_mem_comap] + @[mono] lemma coprod_mono {f₁ f₂ : filter α} {g₁ g₂ : filter β} (hf : f₁ ≤ f₂) (hg : g₁ ≤ g₂) : f₁.coprod g₁ ≤ f₂.coprod g₂ := sup_le_sup (comap_mono hf) (comap_mono hg) diff --git a/src/order/filter/cofinite.lean b/src/order/filter/cofinite.lean index 53828577c53dc..33f72e0f88abd 100644 --- a/src/order/filter/cofinite.lean +++ b/src/order/filter/cofinite.lean @@ -91,23 +91,14 @@ le_cofinite_iff_eventually_ne.mpr $ λ x, /-- The coproduct of the cofinite filters on two types is the cofinite filter on their product. -/ lemma coprod_cofinite : (cofinite : filter α).coprod (cofinite : filter β) = cofinite := -begin - refine le_antisymm (sup_le (comap_cofinite_le _) (comap_cofinite_le _)) (λ S, _), - simp only [mem_coprod_iff, exists_prop, mem_comap, mem_cofinite], - rintro ⟨⟨A, hAf, hAS⟩, B, hBf, hBS⟩, - rw [← compl_subset_compl, ← preimage_compl] at hAS hBS, - exact (hAf.prod hBf).subset (subset_inter hAS hBS) -end +filter.coext $ λ s, by simp only [compl_mem_coprod, mem_cofinite, compl_compl, + finite_image_fst_and_snd_iff] /-- Finite product of finite sets is finite -/ lemma Coprod_cofinite {α : ι → Type*} [fintype ι] : filter.Coprod (λ i, (cofinite : filter (α i))) = cofinite := -begin - refine le_antisymm (supr_le $ λ i, comap_cofinite_le _) (compl_surjective.forall.2 $ λ S, _), - simp_rw [compl_mem_Coprod_iff, mem_cofinite, compl_compl], - rintro ⟨t, htf, hsub⟩, - exact (finite.pi htf).subset hsub -end +filter.coext $ λ s, by simp only [compl_mem_Coprod, mem_cofinite, compl_compl, + forall_finite_image_eval_iff] end filter diff --git a/src/order/filter/pi.lean b/src/order/filter/pi.lean index b95e4576f5da8..8ee93c4bcb42c 100644 --- a/src/order/filter/pi.lean +++ b/src/order/filter/pi.lean @@ -153,13 +153,9 @@ lemma mem_Coprod_iff {s : set (Π i, α i)} : (s ∈ filter.Coprod f) ↔ (∀ i : ι, (∃ t₁ ∈ f i, eval i ⁻¹' t₁ ⊆ s)) := by simp [filter.Coprod] -lemma compl_mem_Coprod_iff {s : set (Π i, α i)} : - sᶜ ∈ filter.Coprod f ↔ ∃ t : Π i, set (α i), (∀ i, (t i)ᶜ ∈ f i) ∧ s ⊆ set.pi univ (λ i, t i) := -begin - rw [(surjective_pi_map (λ i, @compl_surjective (set (α i)) _)).exists], - simp_rw [mem_Coprod_iff, classical.skolem, exists_prop, @subset_compl_comm _ _ s, - ← preimage_compl, ← subset_Inter_iff, ← univ_pi_eq_Inter, compl_compl] -end +lemma compl_mem_Coprod {s : set (Π i, α i)} : + sᶜ ∈ filter.Coprod f ↔ ∀ i, (eval i '' s)ᶜ ∈ f i := +by simp only [filter.Coprod, mem_supr, compl_mem_comap] lemma Coprod_ne_bot_iff' : ne_bot (filter.Coprod f) ↔ (∀ i, nonempty (α i)) ∧ ∃ d, ne_bot (f d) := diff --git a/src/topology/algebra/order/intermediate_value.lean b/src/topology/algebra/order/intermediate_value.lean index a9a30b53372cc..18bce4b1a6321 100644 --- a/src/topology/algebra/order/intermediate_value.lean +++ b/src/topology/algebra/order/intermediate_value.lean @@ -99,7 +99,7 @@ lemma is_preconnected.intermediate_value₂_eventually₁ {s : set X} (hs : is_p begin rw continuous_on_iff_continuous_restrict at hf hg, obtain ⟨b, h⟩ := @intermediate_value_univ₂_eventually₁ _ _ _ _ _ _ (subtype.preconnected_space hs) - ⟨a, ha⟩ _ (comap_coe_ne_bot_of_le_principal hl) _ _ hf hg ha' (eventually_comap' he), + ⟨a, ha⟩ _ (comap_coe_ne_bot_of_le_principal hl) _ _ hf hg ha' (he.comap _), exact ⟨b, b.prop, h⟩, end @@ -111,7 +111,7 @@ begin rw continuous_on_iff_continuous_restrict at hf hg, obtain ⟨b, h⟩ := @intermediate_value_univ₂_eventually₂ _ _ _ _ _ _ (subtype.preconnected_space hs) _ _ (comap_coe_ne_bot_of_le_principal hl₁) (comap_coe_ne_bot_of_le_principal hl₂) - _ _ hf hg (eventually_comap' he₁) (eventually_comap' he₂), + _ _ hf hg (he₁.comap _) (he₂.comap _), exact ⟨b, b.prop, h⟩, end diff --git a/src/topology/subset_properties.lean b/src/topology/subset_properties.lean index b9d4041a63d0c..e5dae21ad05c3 100644 --- a/src/topology/subset_properties.lean +++ b/src/topology/subset_properties.lean @@ -947,7 +947,7 @@ prod.noncompact_space_iff.2 (or.inr ⟨‹_›, ‹_›⟩) section tychonoff variables [Π i, topological_space (π i)] -/-- **Tychonoff's theorem** -/ +/-- **Tychonoff's theorem**: product of compact sets is compact. -/ lemma is_compact_pi_infinite {s : Π i, set (π i)} : (∀ i, is_compact (s i)) → is_compact {x : Π i, π i | ∀ i, x i ∈ s i} := begin @@ -961,7 +961,7 @@ begin exact ⟨a, assume i, (ha i).left, assume i, (ha i).right.le_comap⟩ end -/-- A version of Tychonoff's theorem that uses `set.pi`. -/ +/-- **Tychonoff's theorem** formulated using `set.pi`: product of compact sets is compact. -/ lemma is_compact_univ_pi {s : Π i, set (π i)} (h : ∀ i, is_compact (s i)) : is_compact (pi univ s) := by { convert is_compact_pi_infinite h, simp only [← mem_univ_pi, set_of_mem_eq] } @@ -969,18 +969,16 @@ by { convert is_compact_pi_infinite h, simp only [← mem_univ_pi, set_of_mem_eq instance pi.compact_space [∀ i, compact_space (π i)] : compact_space (Πi, π i) := ⟨by { rw [← pi_univ univ], exact is_compact_univ_pi (λ i, compact_univ) }⟩ -/-- Product of compact sets is compact -/ +/-- **Tychonoff's theorem** formulated in terms of filters: `filter.cocompact` on an indexed product +type `Π d, κ d` the `filter.Coprod` of filters `filter.cocompact` on `κ d`. -/ lemma filter.Coprod_cocompact {δ : Type*} {κ : δ → Type*} [Π d, topological_space (κ d)] : filter.Coprod (λ d, filter.cocompact (κ d)) = filter.cocompact (Π d, κ d) := begin - ext S, rcases compl_surjective S with ⟨S, rfl⟩, - simp_rw [compl_mem_Coprod_iff, filter.mem_cocompact, compl_subset_compl], - split, - { rintro ⟨t, H, hSt⟩, choose K hKc htK using H, - exact ⟨set.pi univ K, is_compact_univ_pi hKc, hSt.trans $ pi_mono $ λ i _, htK i⟩ }, - { rintro ⟨K, hKc, hSK⟩, - exact ⟨λ i, function.eval i '' K, λ i, ⟨_, hKc.image (continuous_apply i), subset.rfl⟩, - hSK.trans $ subset_pi_eval_image _ _⟩ } + refine le_antisymm (supr_le $ λ i, filter.comap_cocompact (continuous_apply i)) _, + refine compl_surjective.forall.2 (λ s H, _), + simp only [compl_mem_Coprod, filter.mem_cocompact, compl_subset_compl, image_subset_iff] at H ⊢, + choose K hKc htK using H, + exact ⟨set.pi univ K, is_compact_univ_pi hKc, λ f hf i hi, htK i hf⟩ end end tychonoff From bf67d4734fce7895731c1664bd1642b13485d222 Mon Sep 17 00:00:00 2001 From: leanprover-community-bot Date: Tue, 26 Apr 2022 04:54:38 +0000 Subject: [PATCH 264/373] chore(scripts): update nolints.txt (#13706) I am happy to remove some nolints for you! --- scripts/nolints.txt | 6 ------ scripts/style-exceptions.txt | 1 - 2 files changed, 7 deletions(-) diff --git a/scripts/nolints.txt b/scripts/nolints.txt index 92b91ae7a4822..1fee0899ec65c 100644 --- a/scripts/nolints.txt +++ b/scripts/nolints.txt @@ -442,12 +442,6 @@ apply_nolint is_subfield doc_blame -- deprecated/subring.lean apply_nolint ring.closure doc_blame --- field_theory/finite/polynomial.lean -apply_nolint mv_polynomial.R doc_blame unused_arguments -apply_nolint mv_polynomial.evalᵢ doc_blame -apply_nolint mv_polynomial.evalₗ doc_blame unused_arguments -apply_nolint mv_polynomial.indicator doc_blame - -- group_theory/coset.lean apply_nolint subgroup.card_subgroup_dvd_card to_additive_doc diff --git a/scripts/style-exceptions.txt b/scripts/style-exceptions.txt index 9c6dfcda33adb..bf4a542d5bb7f 100644 --- a/scripts/style-exceptions.txt +++ b/scripts/style-exceptions.txt @@ -31,7 +31,6 @@ src/deprecated/subfield.lean : line 8 : ERR_MOD : Module docstring missing, or t src/deprecated/subring.lean : line 10 : ERR_MOD : Module docstring missing, or too late src/logic/relator.lean : line 11 : ERR_MOD : Module docstring missing, or too late src/meta/coinductive_predicates.lean : line 8 : ERR_MOD : Module docstring missing, or too late -src/tactic/algebra.lean : line 8 : ERR_MOD : Module docstring missing, or too late src/tactic/apply_fun.lean : line 8 : ERR_MOD : Module docstring missing, or too late src/tactic/auto_cases.lean : line 8 : ERR_MOD : Module docstring missing, or too late src/tactic/chain.lean : line 8 : ERR_MOD : Module docstring missing, or too late From 093b583bcbf190399f27bb76a1b00432d3768651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Tue, 26 Apr 2022 07:21:28 +0000 Subject: [PATCH 265/373] feat(set_theory/game/pgame): `ordinal.to_pgame` (#13628) We define the canonical map from ordinals to pre-games and prove it's an order embedding. --- src/set_theory/game/ordinal.lean | 109 +++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/set_theory/game/ordinal.lean diff --git a/src/set_theory/game/ordinal.lean b/src/set_theory/game/ordinal.lean new file mode 100644 index 0000000000000..0fc3f79904c14 --- /dev/null +++ b/src/set_theory/game/ordinal.lean @@ -0,0 +1,109 @@ +/- +Copyright (c) 2022 Violeta Hernández Palacios. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Violeta Hernández Palacios +-/ + +import set_theory.game.pgame +import set_theory.ordinal.basic + +/-! +# Ordinals as games + +We define the canonical map `ordinal → pgame`, where every ordinal is mapped to the game whose left +set consists of all previous ordinals. + +# Main declarations + +- `ordinal.to_pgame`: The canonical map between ordinals and pre-games. +- `ordinal.to_pgame_embedding`: The order embedding version of the previous map. + +# Todo + +- Extend this map to `game` and `surreal`. +- Prove that `birthday o.to_pgame = o`. +-/ + +universe u + +namespace ordinal + +/-- Converts an ordinal into the corresponding pre-game. -/ +noncomputable! def to_pgame : Π o : ordinal.{u}, pgame.{u} +| o := ⟨o.out.α, pempty, λ x, let hwf := ordinal.typein_lt_self x in + (typein (<) x).to_pgame, pempty.elim⟩ +using_well_founded { dec_tac := tactic.assumption } + +theorem to_pgame_def (o : ordinal) : + o.to_pgame = ⟨o.out.α, pempty, λ x, (typein (<) x).to_pgame, pempty.elim⟩ := +by rw to_pgame + +@[simp] theorem to_pgame_left_moves (o : ordinal) : o.to_pgame.left_moves = o.out.α := +by rw [to_pgame, pgame.left_moves] + +@[simp] theorem to_pgame_right_moves (o : ordinal) : o.to_pgame.right_moves = pempty := +by rw [to_pgame, pgame.right_moves] + +instance : is_empty (0 : ordinal).to_pgame.left_moves := +by { rw to_pgame_left_moves, apply_instance } + +instance (o : ordinal) : is_empty o.to_pgame.right_moves := +by { rw to_pgame_right_moves, apply_instance } + +/-- Converts a member of `o.out.α` into a move for the `pgame` corresponding to `o`, and vice versa. + +Even though these types are the same (not definitionally so), this is the preferred way to convert +between them. -/ +def to_left_moves_to_pgame {o : ordinal} : o.out.α ≃ o.to_pgame.left_moves := +equiv.cast (to_pgame_left_moves o).symm + +theorem to_pgame_move_left_heq {o : ordinal} : + o.to_pgame.move_left == λ x : o.out.α, (typein (<) x).to_pgame := +by { rw to_pgame, refl } + +@[simp] theorem to_pgame_move_left {o : ordinal} (i : o.out.α) : + o.to_pgame.move_left (to_left_moves_to_pgame i) = (typein (<) i).to_pgame := +by { rw to_left_moves_to_pgame, exact congr_fun_heq _ to_pgame_move_left_heq i } + +theorem to_pgame_lt {a b : ordinal} (h : a < b) : a.to_pgame < b.to_pgame := +begin + convert pgame.move_left_lt (to_left_moves_to_pgame (enum (<) a _)), + { rw [to_pgame_move_left, typein_enum] }, + { rwa type_lt } +end + +theorem to_pgame_le {a b : ordinal} (h : a ≤ b) : a.to_pgame ≤ b.to_pgame := +begin + rw pgame.le_def, + refine ⟨λ i, or.inl ⟨to_left_moves_to_pgame + (enum (<) (typein (<) (to_left_moves_to_pgame.symm i)) _), _⟩, is_empty_elim⟩, + { rw type_lt, + apply lt_of_lt_of_le _ h, + simp_rw ←type_lt a, + apply typein_lt_type }, + { rw [←to_left_moves_to_pgame.apply_symm_apply i, to_pgame_move_left], + simp } +end + +@[simp] theorem to_pgame_lt_iff {a b : ordinal} : a.to_pgame < b.to_pgame ↔ a < b := +⟨by { contrapose, rw [not_lt, pgame.not_lt], exact to_pgame_le }, to_pgame_lt⟩ + +@[simp] theorem to_pgame_le_iff {a b : ordinal} : a.to_pgame ≤ b.to_pgame ↔ a ≤ b := +⟨by { contrapose, rw [not_le, pgame.not_le], exact to_pgame_lt }, to_pgame_le⟩ + +theorem to_pgame_injective : function.injective ordinal.to_pgame := +λ a b h, begin + by_contra hne, + cases lt_or_gt_of_ne hne with hlt hlt; + { have := to_pgame_lt hlt, + rw h at this, + exact pgame.lt_irrefl _ this } +end + +/-- The order embedding version of `to_pgame`. -/ +@[simps] noncomputable def to_pgame_embedding : ordinal.{u} ↪o pgame.{u} := +{ to_fun := ordinal.to_pgame, + inj' := to_pgame_injective, + map_rel_iff' := @to_pgame_le_iff } + +end ordinal From 1b1ae61f9c2bbbd1ec50a70dc92d90c965f8d886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 26 Apr 2022 07:55:32 +0000 Subject: [PATCH 266/373] feat(analysis/normed_space/pointwise): Thickening a thickening (#13380) In a real normed space, thickening twice is the same as thickening once. --- src/analysis/normed_space/pointwise.lean | 86 +++++++++++++++++++ src/data/real/ennreal.lean | 15 ++++ src/topology/metric_space/basic.lean | 7 ++ .../metric_space/hausdorff_distance.lean | 49 +++++++++++ 4 files changed, 157 insertions(+) diff --git a/src/analysis/normed_space/pointwise.lean b/src/analysis/normed_space/pointwise.lean index 9e31896888c1c..2b44a759d2d4e 100644 --- a/src/analysis/normed_space/pointwise.lean +++ b/src/analysis/normed_space/pointwise.lean @@ -193,6 +193,92 @@ begin exact h ⟨hxz, hzy⟩, end +open emetric ennreal + +@[simp] lemma inf_edist_thickening (hδ : 0 < δ) (s : set E) (x : E) : + inf_edist x (thickening δ s) = inf_edist x s - ennreal.of_real δ := +begin + obtain hs | hs := lt_or_le (inf_edist x s) (ennreal.of_real δ), + { rw [inf_edist_zero_of_mem, tsub_eq_zero_of_le hs.le], exact hs }, + refine (tsub_le_iff_right.2 inf_edist_le_inf_edist_thickening_add).antisymm' _, + refine le_sub_of_add_le_right of_real_ne_top _, + refine le_inf_edist.2 (λ z hz, le_of_forall_lt' $ λ r h, _), + cases r, + { exact add_lt_top.2 ⟨lt_top_iff_ne_top.2 $ inf_edist_ne_top ⟨z, self_subset_thickening hδ _ hz⟩, + of_real_lt_top⟩ }, + have hr : 0 < ↑r - δ, + { refine sub_pos_of_lt _, + have := hs.trans_lt ((inf_edist_le_edist_of_mem hz).trans_lt h), + rw [of_real_eq_coe_nnreal hδ.le, some_eq_coe] at this, + exact_mod_cast this }, + rw [some_eq_coe, edist_lt_coe, ←dist_lt_coe, ←add_sub_cancel'_right δ (↑r)] at h, + obtain ⟨y, hxy, hyz⟩ := exists_dist_lt_lt hr hδ h, + refine (ennreal.add_lt_add_right of_real_ne_top $ inf_edist_lt_iff.2 + ⟨_, mem_thickening_iff.2 ⟨_, hz, hyz⟩, edist_lt_of_real.2 hxy⟩).trans_le _, + rw [←of_real_add hr.le hδ.le, sub_add_cancel, of_real_coe_nnreal], + exact le_rfl, +end + +@[simp] lemma inf_edist_cthickening (δ : ℝ) (s : set E) (x : E) : + inf_edist x (cthickening δ s) = inf_edist x s - ennreal.of_real δ := +begin + obtain hδ | hδ := le_total δ 0, + { rw [cthickening_of_nonpos hδ, inf_edist_closure, of_real_of_nonpos hδ, tsub_zero] }, + obtain hs | hs := le_or_lt (inf_edist x s) (ennreal.of_real δ), + { rw [inf_edist_zero_of_mem (mem_cthickening_iff.2 hs), tsub_eq_zero_of_le hs] }, + refine (tsub_le_iff_right.2 inf_edist_le_inf_edist_cthickening_add).antisymm' _, + refine le_sub_of_add_le_right of_real_ne_top _, + refine le_inf_edist.2 (λ z hz, le_of_forall_lt' $ λ r h, _), + cases r, + { exact add_lt_top.2 ⟨lt_top_iff_ne_top.2 $ inf_edist_ne_top ⟨z, self_subset_cthickening _ hz⟩, + of_real_lt_top⟩ }, + have hr : 0 < ↑r - δ, + { refine sub_pos_of_lt _, + have := hs.trans ((inf_edist_le_edist_of_mem hz).trans_lt h), + rw [of_real_eq_coe_nnreal hδ, some_eq_coe] at this, + exact_mod_cast this }, + rw [some_eq_coe, edist_lt_coe, ←dist_lt_coe, ←add_sub_cancel'_right δ (↑r)] at h, + obtain ⟨y, hxy, hyz⟩ := exists_dist_lt_le hr hδ h, + refine (ennreal.add_lt_add_right of_real_ne_top $ inf_edist_lt_iff.2 + ⟨_, mem_cthickening_of_dist_le _ _ _ _ hz hyz, edist_lt_of_real.2 hxy⟩).trans_le _, + rw [←of_real_add hr.le hδ, sub_add_cancel, of_real_coe_nnreal], + exact le_rfl, +end + +@[simp] lemma thickening_thickening (hε : 0 < ε) (hδ : 0 < δ) (s : set E) : + thickening ε (thickening δ s) = thickening (ε + δ) s := +(thickening_thickening_subset _ _ _).antisymm $ λ x, begin + simp_rw mem_thickening_iff, + rintro ⟨z, hz, hxz⟩, + rw add_comm at hxz, + obtain ⟨y, hxy, hyz⟩ := exists_dist_lt_lt hε hδ hxz, + exact ⟨y, ⟨_, hz, hyz⟩, hxy⟩, +end + +@[simp] lemma thickening_cthickening (hε : 0 < ε) (hδ : 0 ≤ δ) (s : set E) : + thickening ε (cthickening δ s) = thickening (ε + δ) s := +(thickening_cthickening_subset _ hδ _).antisymm $ λ x, begin + simp_rw mem_thickening_iff, + rintro ⟨z, hz, hxz⟩, + rw add_comm at hxz, + obtain ⟨y, hxy, hyz⟩ := exists_dist_lt_le hε hδ hxz, + exact ⟨y, mem_cthickening_of_dist_le _ _ _ _ hz hyz, hxy⟩, +end + +@[simp] lemma cthickening_thickening (hε : 0 ≤ ε) (hδ : 0 < δ) (s : set E) : + cthickening ε (thickening δ s) = cthickening (ε + δ) s := +(cthickening_thickening_subset hε _ _).antisymm $ λ x, begin + simp_rw [mem_cthickening_iff, ennreal.of_real_add hε hδ.le, inf_edist_thickening hδ], + exact tsub_le_iff_right.2, +end + +@[simp] lemma cthickening_cthickening (hε : 0 ≤ ε) (hδ : 0 ≤ δ) (s : set E) : + cthickening ε (cthickening δ s) = cthickening (ε + δ) s := +(cthickening_cthickening_subset hε hδ _).antisymm $ λ x, begin + simp_rw [mem_cthickening_iff, ennreal.of_real_add hε hδ, inf_edist_cthickening], + exact tsub_le_iff_right.2, +end + end semi_normed_group section normed_group diff --git a/src/data/real/ennreal.lean b/src/data/real/ennreal.lean index 8109d6fd616ff..344c3bb088bc4 100644 --- a/src/data/real/ennreal.lean +++ b/src/data/real/ennreal.lean @@ -777,6 +777,12 @@ begin { exact (cancel_of_ne hc).lt_add_of_tsub_lt_right } end +lemma le_sub_of_add_le_left (ha : a ≠ ∞) : a + b ≤ c → b ≤ c - a := +(cancel_of_ne ha).le_tsub_of_add_le_left + +lemma le_sub_of_add_le_right (hb : b ≠ ∞) : a + b ≤ c → a ≤ c - b := +(cancel_of_ne hb).le_tsub_of_add_le_right + protected lemma sub_lt_of_lt_add (hac : c ≤ a) (h : a < b + c) : a - c < b := ((cancel_of_lt' $ hac.trans_lt h).tsub_lt_iff_right hac).mpr h @@ -1561,6 +1567,15 @@ eq_comm.trans of_real_eq_zero alias ennreal.of_real_eq_zero ↔ _ ennreal.of_real_of_nonpos +lemma of_real_sub (p : ℝ) (hq : 0 ≤ q) : + ennreal.of_real (p - q) = ennreal.of_real p - ennreal.of_real q := +begin + obtain h | h := le_total p q, + { rw [of_real_of_nonpos (sub_nonpos_of_le h), tsub_eq_zero_of_le (of_real_le_of_real h)] }, + refine ennreal.eq_sub_of_add_eq of_real_ne_top _, + rw [←of_real_add (sub_nonneg_of_le h) hq, sub_add_cancel], +end + lemma of_real_le_iff_le_to_real {a : ℝ} {b : ℝ≥0∞} (hb : b ≠ ∞) : ennreal.of_real a ≤ b ↔ a ≤ ennreal.to_real b := begin diff --git a/src/topology/metric_space/basic.lean b/src/topology/metric_space/basic.lean index f3e3fe9effdd4..61eea9f05b9bc 100644 --- a/src/topology/metric_space/basic.lean +++ b/src/topology/metric_space/basic.lean @@ -365,6 +365,13 @@ iff.rfl dist x y ≤ c ↔ nndist x y ≤ c := iff.rfl +@[simp] lemma edist_lt_of_real {x y : α} {r : ℝ} : edist x y < ennreal.of_real r ↔ dist x y < r := +by rw [edist_dist, ennreal.of_real_lt_of_real_iff_of_nonneg dist_nonneg] + +@[simp] lemma edist_le_of_real {x y : α} {r : ℝ} (hr : 0 ≤ r) : + edist x y ≤ ennreal.of_real r ↔ dist x y ≤ r := +by rw [edist_dist, ennreal.of_real_le_of_real_iff hr] + /--Express `nndist` in terms of `dist`-/ lemma nndist_dist (x y : α) : nndist x y = real.to_nnreal (dist x y) := by rw [dist_nndist, real.to_nnreal_coe] diff --git a/src/topology/metric_space/hausdorff_distance.lean b/src/topology/metric_space/hausdorff_distance.lean index 4c8671b8711e5..0dd2c8995a778 100644 --- a/src/topology/metric_space/hausdorff_distance.lean +++ b/src/topology/metric_space/hausdorff_distance.lean @@ -1153,6 +1153,7 @@ begin exact mem_bUnion yE D2, end +/-- For the equality, see `inf_edist_cthickening`. -/ lemma inf_edist_le_inf_edist_cthickening_add : inf_edist x s ≤ inf_edist x (cthickening δ s) + ennreal.of_real δ := begin @@ -1164,11 +1165,59 @@ begin (tsub_add_cancel_of_le $ le_self_add.trans (lt_tsub_iff_left.1 hxy).le).le), end +/-- For the equality, see `inf_edist_thickening`. -/ lemma inf_edist_le_inf_edist_thickening_add : inf_edist x s ≤ inf_edist x (thickening δ s) + ennreal.of_real δ := inf_edist_le_inf_edist_cthickening_add.trans $ add_le_add_right (inf_edist_anti $ thickening_subset_cthickening _ _) _ +/-- For the equality, see `thickening_thickening`. -/ +@[simp] lemma thickening_thickening_subset (ε δ : ℝ) (s : set α) : + thickening ε (thickening δ s) ⊆ thickening (ε + δ) s := +begin + obtain hε | hε := le_total ε 0, + { simp only [thickening_of_nonpos hε, empty_subset] }, + obtain hδ | hδ := le_total δ 0, + { simp only [thickening_of_nonpos hδ, thickening_empty, empty_subset] }, + intros x, + simp_rw [mem_thickening_iff_exists_edist_lt, ennreal.of_real_add hε hδ], + exact λ ⟨y, ⟨z, hz, hy⟩, hx⟩, ⟨z, hz, (edist_triangle _ _ _).trans_lt $ ennreal.add_lt_add hx hy⟩, +end + +/-- For the equality, see `thickening_cthickening`. -/ +@[simp] lemma thickening_cthickening_subset (ε : ℝ) (hδ : 0 ≤ δ) (s : set α) : + thickening ε (cthickening δ s) ⊆ thickening (ε + δ) s := +begin + obtain hε | hε := le_total ε 0, + { simp only [thickening_of_nonpos hε, empty_subset] }, + intro x, + simp_rw [mem_thickening_iff_exists_edist_lt, mem_cthickening_iff, ←inf_edist_lt_iff, + ennreal.of_real_add hε hδ], + rintro ⟨y, hy, hxy⟩, + exact inf_edist_le_edist_add_inf_edist.trans_lt + (ennreal.add_lt_add_of_lt_of_le (hy.trans_lt ennreal.of_real_lt_top).ne hxy hy), +end + +/-- For the equality, see `cthickening_thickening`. -/ +@[simp] lemma cthickening_thickening_subset (hε : 0 ≤ ε) (δ : ℝ) (s : set α) : + cthickening ε (thickening δ s) ⊆ cthickening (ε + δ) s := +begin + obtain hδ | hδ := le_total δ 0, + { simp only [thickening_of_nonpos hδ, cthickening_empty, empty_subset] }, + intro x, + simp_rw [mem_cthickening_iff, ennreal.of_real_add hε hδ], + exact λ hx, inf_edist_le_inf_edist_thickening_add.trans (add_le_add_right hx _), +end + +/-- For the equality, see `cthickening_cthickening`. -/ +@[simp] lemma cthickening_cthickening_subset (hε : 0 ≤ ε) (hδ : 0 ≤ δ) (s : set α) : + cthickening ε (cthickening δ s) ⊆ cthickening (ε + δ) s := +begin + intro x, + simp_rw [mem_cthickening_iff, ennreal.of_real_add hε hδ], + exact λ hx, inf_edist_le_inf_edist_cthickening_add.trans (add_le_add_right hx _), +end + end cthickening --section end metric --namespace From a02f11fa0d3c51298611e69991360861e3886298 Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Tue, 26 Apr 2022 07:55:33 +0000 Subject: [PATCH 267/373] feat(algebra/ring/equiv): generalize `ring_equiv` material to allow for non-unital rings (#13626) --- src/algebra/hom/equiv.lean | 20 +- src/algebra/ring/equiv.lean | 199 ++++++++++++++---- src/data/polynomial/eval.lean | 4 +- src/ring_theory/free_comm_ring.lean | 4 +- src/ring_theory/valuation/valuation_ring.lean | 5 +- 5 files changed, 169 insertions(+), 63 deletions(-) diff --git a/src/algebra/hom/equiv.lean b/src/algebra/hom/equiv.lean index 5f4e3db648b1a..48439c847ab42 100644 --- a/src/algebra/hom/equiv.lean +++ b/src/algebra/hom/equiv.lean @@ -350,11 +350,11 @@ lemma map_ne_one_iff {M N} [mul_one_class M] [mul_one_class N] (h : M ≃* N) {x h x ≠ 1 ↔ x ≠ 1 := mul_equiv_class.map_ne_one_iff h -/-- A bijective `monoid` homomorphism is an isomorphism -/ -@[to_additive "A bijective `add_monoid` homomorphism is an isomorphism"] -noncomputable def of_bijective {M N} [mul_one_class M] [mul_one_class N] (f : M →* N) +/-- A bijective `semigroup` homomorphism is an isomorphism -/ +@[to_additive "A bijective `add_semigroup` homomorphism is an isomorphism"] +noncomputable def of_bijective {M N F} [has_mul M] [has_mul N] [mul_hom_class F M N] (f : F) (hf : function.bijective f) : M ≃* N := -{ map_mul' := f.map_mul', +{ map_mul' := map_mul f, ..equiv.of_bijective f hf } /-- @@ -382,7 +382,7 @@ where the equivalence between the targets is multiplicative. -/ @[to_additive "An additive analogue of `equiv.arrow_congr`, where the equivalence between the targets is additive.", simps apply] -def arrow_congr {M N P Q : Type*} [mul_one_class P] [mul_one_class Q] +def arrow_congr {M N P Q : Type*} [has_mul P] [has_mul Q] (f : M ≃ N) (g : P ≃* Q) : (M → P) ≃* (N → Q) := { to_fun := λ h n, g (h (f.symm n)), inv_fun := λ k m, g.symm (k (f m)), @@ -418,7 +418,7 @@ generates an additive equivalence between `Π j, Ms j` and `Π j, Ns j`. This is the `add_equiv` version of `equiv.Pi_congr_right`, and the dependent version of `add_equiv.arrow_congr`.", simps apply] def Pi_congr_right {η : Type*} - {Ms Ns : η → Type*} [Π j, mul_one_class (Ms j)] [Π j, mul_one_class (Ns j)] + {Ms Ns : η → Type*} [Π j, has_mul (Ms j)] [Π j, has_mul (Ns j)] (es : ∀ j, Ms j ≃* Ns j) : (Π j, Ms j) ≃* (Π j, Ns j) := { to_fun := λ x j, es j (x j), inv_fun := λ x j, (es j).symm (x j), @@ -426,18 +426,18 @@ def Pi_congr_right {η : Type*} .. equiv.Pi_congr_right (λ j, (es j).to_equiv) } @[simp] -lemma Pi_congr_right_refl {η : Type*} {Ms : η → Type*} [Π j, mul_one_class (Ms j)] : +lemma Pi_congr_right_refl {η : Type*} {Ms : η → Type*} [Π j, has_mul (Ms j)] : Pi_congr_right (λ j, mul_equiv.refl (Ms j)) = mul_equiv.refl _ := rfl @[simp] lemma Pi_congr_right_symm {η : Type*} - {Ms Ns : η → Type*} [Π j, mul_one_class (Ms j)] [Π j, mul_one_class (Ns j)] + {Ms Ns : η → Type*} [Π j, has_mul (Ms j)] [Π j, has_mul (Ns j)] (es : ∀ j, Ms j ≃* Ns j) : (Pi_congr_right es).symm = (Pi_congr_right $ λ i, (es i).symm) := rfl @[simp] lemma Pi_congr_right_trans {η : Type*} - {Ms Ns Ps : η → Type*} [Π j, mul_one_class (Ms j)] [Π j, mul_one_class (Ns j)] - [Π j, mul_one_class (Ps j)] + {Ms Ns Ps : η → Type*} [Π j, has_mul (Ms j)] [Π j, has_mul (Ns j)] + [Π j, has_mul (Ps j)] (es : ∀ j, Ms j ≃* Ns j) (fs : ∀ j, Ns j ≃* Ps j) : (Pi_congr_right es).trans (Pi_congr_right fs) = (Pi_congr_right $ λ i, (es i).trans (fs i)) := rfl diff --git a/src/algebra/ring/equiv.lean b/src/algebra/ring/equiv.lean index ab12a7833c75f..c328a291092aa 100644 --- a/src/algebra/ring/equiv.lean +++ b/src/algebra/ring/equiv.lean @@ -42,7 +42,8 @@ variables {F α β R S S' : Type*} set_option old_structure_cmd true -/-- An equivalence between two (semi)rings that preserves the algebraic structure. -/ +/-- An equivalence between two (non-unital non-associative semi)rings that preserves the +algebraic structure. -/ structure ring_equiv (R S : Type*) [has_mul R] [has_add R] [has_mul S] [has_add S] extends R ≃ S, R ≃* S, R ≃+ S @@ -83,6 +84,15 @@ instance to_ring_hom_class (F R S : Type*) map_one := map_one, .. h } +@[priority 100] -- See note [lower instance priority] +instance to_non_unital_ring_hom_class (F R S : Type*) + [non_unital_non_assoc_semiring R] [non_unital_non_assoc_semiring S] [h : ring_equiv_class F R S] : + non_unital_ring_hom_class F R S := +{ coe := coe_fn, + coe_injective' := fun_like.coe_injective, + map_zero := map_zero, + .. h } + end ring_equiv_class instance [has_mul α] [has_add α] [has_mul β] [has_add β] [ring_equiv_class F α β] : @@ -262,30 +272,18 @@ protected lemma map_eq_zero_iff : f x = 0 ↔ x = 0 := add_equiv_class.map_eq_ze lemma map_ne_zero_iff : f x ≠ 0 ↔ x ≠ 0 := add_equiv_class.map_ne_zero_iff f -end non_unital_semiring - -section semiring - -variables [non_assoc_semiring R] [non_assoc_semiring S] (f : R ≃+* S) (x y : R) - -/-- A ring isomorphism sends one to one. -/ -protected lemma map_one : f 1 = 1 := map_one f - -variable {x} - -protected lemma map_eq_one_iff : f x = 1 ↔ x = 1 := mul_equiv_class.map_eq_one_iff f - -lemma map_ne_one_iff : f x ≠ 1 ↔ x ≠ 1 := mul_equiv_class.map_ne_one_iff f - /-- Produce a ring isomorphism from a bijective ring homomorphism. -/ -noncomputable def of_bijective (f : R →+* S) (hf : function.bijective f) : R ≃+* S := -{ .. equiv.of_bijective f hf, .. f } +noncomputable def of_bijective [non_unital_ring_hom_class F R S] (f : F) + (hf : function.bijective f) : R ≃+* S := +{ map_mul' := map_mul f, + map_add' := map_add f, + .. equiv.of_bijective f hf,} -@[simp] lemma coe_of_bijective (f : R →+* S) (hf : function.bijective f) : - (of_bijective f hf : R → S) = f := rfl +@[simp] lemma coe_of_bijective [non_unital_ring_hom_class F R S] (f : F) + (hf : function.bijective f) : (of_bijective f hf : R → S) = f := rfl -lemma of_bijective_apply (f : R →+* S) (hf : function.bijective f) (x : R) : - of_bijective f hf x = f x := rfl +lemma of_bijective_apply [non_unital_ring_hom_class F R S] (f : F) + (hf : function.bijective f) (x : R) : of_bijective f hf x = f x := rfl /-- A family of ring isomorphisms `Π j, (R j ≃+* S j)` generates a ring isomorphisms between `Π j, R j` and `Π j, S j`. @@ -295,7 +293,7 @@ This is the `ring_equiv` version of `equiv.Pi_congr_right`, and the dependent ve -/ @[simps apply] def Pi_congr_right {ι : Type*} {R S : ι → Type*} - [Π i, semiring (R i)] [Π i, semiring (S i)] + [Π i, non_unital_non_assoc_semiring (R i)] [Π i, non_unital_non_assoc_semiring (S i)] (e : Π i, R i ≃+* S i) : (Π i, R i) ≃+* Π i, S i := { to_fun := λ x j, e j (x j), inv_fun := λ x j, (e j).symm (x j), @@ -303,33 +301,114 @@ def Pi_congr_right {ι : Type*} {R S : ι → Type*} .. @add_equiv.Pi_congr_right ι R S _ _ (λ i, (e i).to_add_equiv) } @[simp] -lemma Pi_congr_right_refl {ι : Type*} {R : ι → Type*} [Π i, semiring (R i)] : +lemma Pi_congr_right_refl {ι : Type*} {R : ι → Type*} [Π i, non_unital_non_assoc_semiring (R i)] : Pi_congr_right (λ i, ring_equiv.refl (R i)) = ring_equiv.refl _ := rfl @[simp] lemma Pi_congr_right_symm {ι : Type*} {R S : ι → Type*} - [Π i, semiring (R i)] [Π i, semiring (S i)] + [Π i, non_unital_non_assoc_semiring (R i)] [Π i, non_unital_non_assoc_semiring (S i)] (e : Π i, R i ≃+* S i) : (Pi_congr_right e).symm = (Pi_congr_right $ λ i, (e i).symm) := rfl @[simp] lemma Pi_congr_right_trans {ι : Type*} {R S T : ι → Type*} - [Π i, semiring (R i)] [Π i, semiring (S i)] [Π i, semiring (T i)] + [Π i, non_unital_non_assoc_semiring (R i)] [Π i, non_unital_non_assoc_semiring (S i)] + [Π i, non_unital_non_assoc_semiring (T i)] (e : Π i, R i ≃+* S i) (f : Π i, S i ≃+* T i) : (Pi_congr_right e).trans (Pi_congr_right f) = (Pi_congr_right $ λ i, (e i).trans (f i)) := rfl +end non_unital_semiring + +section semiring + +variables [non_assoc_semiring R] [non_assoc_semiring S] (f : R ≃+* S) (x y : R) + +/-- A ring isomorphism sends one to one. -/ +protected lemma map_one : f 1 = 1 := map_one f + +variable {x} + +protected lemma map_eq_one_iff : f x = 1 ↔ x = 1 := mul_equiv_class.map_eq_one_iff f + +lemma map_ne_one_iff : f x ≠ 1 ↔ x ≠ 1 := mul_equiv_class.map_ne_one_iff f + end semiring -section +section non_unital_ring -variables [non_assoc_ring R] [non_assoc_ring S] (f : R ≃+* S) (x y : R) +variables [non_unital_non_assoc_ring R] [non_unital_non_assoc_ring S] (f : R ≃+* S) (x y : R) protected lemma map_neg : f (-x) = -f x := map_neg f x protected lemma map_sub : f (x - y) = f x - f y := map_sub f x y +end non_unital_ring + +section ring + +variables [non_assoc_ring R] [non_assoc_ring S] (f : R ≃+* S) (x y : R) + @[simp] lemma map_neg_one : f (-1) = -1 := f.map_one ▸ f.map_neg 1 -end +end ring + +section non_unital_semiring_hom + +variables [non_unital_non_assoc_semiring R] [non_unital_non_assoc_semiring S] + [non_unital_non_assoc_semiring S'] + +/-- Reinterpret a ring equivalence as a non-unital ring homomorphism. -/ +def to_non_unital_ring_hom (e : R ≃+* S) : R →ₙ+* S := +{ .. e.to_mul_equiv.to_mul_hom, .. e.to_add_equiv.to_add_monoid_hom } + +lemma to_non_unital_ring_hom_injective : + function.injective (to_non_unital_ring_hom : (R ≃+* S) → R →ₙ+* S) := +λ f g h, ring_equiv.ext (non_unital_ring_hom.ext_iff.1 h) + +/- The instance priority is lowered here so that in the case when `R` and `S` are both unital, Lean +will first find and use `ring_equiv.has_coe_to_ring_hom`. -/ +@[priority 900] +instance has_coe_to_non_unital_ring_hom : has_coe (R ≃+* S) (R →ₙ+* S) := +⟨ring_equiv.to_non_unital_ring_hom⟩ + +lemma to_non_unital_ring_hom_eq_coe (f : R ≃+* S) : f.to_non_unital_ring_hom = ↑f := rfl + +@[simp, norm_cast] lemma coe_to_non_unital_ring_hom (f : R ≃+* S) : ⇑(f : R →ₙ+* S) = f := rfl + +lemma coe_non_unital_ring_hom_inj_iff {R S : Type*} + [non_unital_non_assoc_semiring R] [non_unital_non_assoc_semiring S] + (f g : R ≃+* S) : + f = g ↔ (f : R →ₙ+* S) = g := +⟨congr_arg _, λ h, ext $ non_unital_ring_hom.ext_iff.mp h⟩ + +@[simp] +lemma to_non_unital_ring_hom_refl : + (ring_equiv.refl R).to_non_unital_ring_hom = non_unital_ring_hom.id R := rfl + +@[simp] +lemma to_non_unital_ring_hom_apply_symm_to_non_unital_ring_hom_apply (e : R ≃+* S) : + ∀ (y : S), e.to_non_unital_ring_hom (e.symm.to_non_unital_ring_hom y) = y := +e.to_equiv.apply_symm_apply + +@[simp] +lemma symm_to_non_unital_ring_hom_apply_to_non_unital_ring_hom_apply (e : R ≃+* S) : + ∀ (x : R), e.symm.to_non_unital_ring_hom (e.to_non_unital_ring_hom x) = x := +equiv.symm_apply_apply (e.to_equiv) + +@[simp] +lemma to_non_unital_ring_hom_trans (e₁ : R ≃+* S) (e₂ : S ≃+* S') : + (e₁.trans e₂).to_non_unital_ring_hom = e₂.to_non_unital_ring_hom.comp e₁.to_non_unital_ring_hom := +rfl + +@[simp] +lemma to_non_unital_ring_hom_comp_symm_to_non_unital_ring_hom (e : R ≃+* S) : + e.to_non_unital_ring_hom.comp e.symm.to_non_unital_ring_hom = non_unital_ring_hom.id _ := +by { ext, simp } + +@[simp] +lemma symm_to_non_unital_ring_hom_comp_to_non_unital_ring_hom (e : R ≃+* S) : + e.symm.to_non_unital_ring_hom.comp e.to_non_unital_ring_hom = non_unital_ring_hom.id _ := +by { ext, simp } +end non_unital_semiring_hom section semiring_hom @@ -353,6 +432,11 @@ lemma coe_ring_hom_inj_iff {R S : Type*} [non_assoc_semiring R] [non_assoc_semir f = g ↔ (f : R →+* S) = g := ⟨congr_arg _, λ h, ext $ ring_hom.ext_iff.mp h⟩ +/-- The two paths coercion can take to a `non_unital_ring_hom` are equivalent -/ +@[simp, norm_cast] lemma to_non_unital_ring_hom_commutes (f : R ≃+* S) : + ((f : R →+* S) : R →ₙ+* S) = (f : R →ₙ+* S) := +rfl + /-- Reinterpret a ring equivalence as a monoid homomorphism. -/ abbreviation to_monoid_hom (e : R ≃+* S) : R →* S := e.to_ring_hom.to_monoid_hom @@ -410,21 +494,35 @@ by { ext, simp } /-- Construct an equivalence of rings from homomorphisms in both directions, which are inverses. -/ -def of_hom_inv (hom : R →+* S) (inv : S →+* R) - (hom_inv_id : inv.comp hom = ring_hom.id R) (inv_hom_id : hom.comp inv = ring_hom.id S) : +@[simps] +def of_hom_inv' {R S F G : Type*} [non_unital_non_assoc_semiring R] + [non_unital_non_assoc_semiring S] [non_unital_ring_hom_class F R S] + [non_unital_ring_hom_class G S R] (hom : F) (inv : G) + (hom_inv_id : (inv : S →ₙ+* R).comp (hom : R →ₙ+* S) = non_unital_ring_hom.id R) + (inv_hom_id : (hom : R →ₙ+* S).comp (inv : S →ₙ+* R) = non_unital_ring_hom.id S) : R ≃+* S := -{ inv_fun := inv, - left_inv := λ x, ring_hom.congr_fun hom_inv_id x, - right_inv := λ x, ring_hom.congr_fun inv_hom_id x, - ..hom } +{ to_fun := hom, + inv_fun := inv, + left_inv := fun_like.congr_fun hom_inv_id, + right_inv := fun_like.congr_fun inv_hom_id, + map_mul' := map_mul hom, + map_add' := map_add hom, } -@[simp] -lemma of_hom_inv_apply (hom : R →+* S) (inv : S →+* R) (hom_inv_id inv_hom_id) (r : R) : - (of_hom_inv hom inv hom_inv_id inv_hom_id) r = hom r := rfl - -@[simp] -lemma of_hom_inv_symm_apply (hom : R →+* S) (inv : S →+* R) (hom_inv_id inv_hom_id) (s : S) : - (of_hom_inv hom inv hom_inv_id inv_hom_id).symm s = inv s := rfl +/-- +Construct an equivalence of rings from unital homomorphisms in both directions, which are inverses. +-/ +@[simps] +def of_hom_inv {R S F G : Type*} [non_assoc_semiring R] [non_assoc_semiring S] + [ring_hom_class F R S] [ring_hom_class G S R] (hom : F) (inv : G) + (hom_inv_id : (inv : S →+* R).comp (hom : R →+* S) = ring_hom.id R) + (inv_hom_id : (hom : R →+* S).comp (inv : S →+* R) = ring_hom.id S) : + R ≃+* S := +{ to_fun := hom, + inv_fun := inv, + left_inv := fun_like.congr_fun hom_inv_id, + right_inv := fun_like.congr_fun inv_hom_id, + map_mul' := map_mul hom, + map_add' := map_add hom, } end semiring_hom @@ -480,13 +578,22 @@ end ring_equiv namespace mul_equiv -/-- Gives a `ring_equiv` from a `mul_equiv` preserving addition.-/ -def to_ring_equiv {R : Type*} {S : Type*} [has_add R] [has_add S] [has_mul R] [has_mul S] - (h : R ≃* S) (H : ∀ x y : R, h (x + y) = h x + h y) : R ≃+* S := -{..h.to_equiv, ..h, ..add_equiv.mk' h.to_equiv H } +/-- Gives a `ring_equiv` from an element of a `mul_equiv_class` preserving addition.-/ +def to_ring_equiv {R S F : Type*} [has_add R] [has_add S] [has_mul R] [has_mul S] + [mul_equiv_class F R S] (f : F) (H : ∀ x y : R, f (x + y) = f x + f y) : R ≃+* S := +{ ..(f : R ≃* S).to_equiv, ..(f : R ≃* S), ..add_equiv.mk' (f : R ≃* S).to_equiv H } end mul_equiv +namespace add_equiv + +/-- Gives a `ring_equiv` from an element of an `add_equiv_class` preserving addition.-/ +def to_ring_equiv {R S F : Type*} [has_add R] [has_add S] [has_mul R] [has_mul S] + [add_equiv_class F R S] (f : F) (H : ∀ x y : R, f (x * y) = f x * f y) : R ≃+* S := +{ ..(f : R ≃+ S).to_equiv, ..(f : R ≃+ S), ..mul_equiv.mk' (f : R ≃+ S).to_equiv H } + +end add_equiv + namespace ring_equiv variables [has_add R] [has_add S] [has_mul R] [has_mul S] diff --git a/src/data/polynomial/eval.lean b/src/data/polynomial/eval.lean index 2aa0a6b0f6d3d..21ccdc0c6cbe9 100644 --- a/src/data/polynomial/eval.lean +++ b/src/data/polynomial/eval.lean @@ -560,8 +560,8 @@ end /-- If `R` and `S` are isomorphic, then so are their polynomial rings. -/ @[simps] def map_equiv (e : R ≃+* S) : R[X] ≃+* S[X] := ring_equiv.of_hom_inv - (map_ring_hom e) - (map_ring_hom e.symm) + (map_ring_hom (e : R →+* S)) + (map_ring_hom (e.symm : S →+* R)) (by ext; simp) (by ext; simp) diff --git a/src/ring_theory/free_comm_ring.lean b/src/ring_theory/free_comm_ring.lean index d902ef880cc50..214f602c4430a 100644 --- a/src/ring_theory/free_comm_ring.lean +++ b/src/ring_theory/free_comm_ring.lean @@ -317,10 +317,10 @@ end free_ring def free_comm_ring_equiv_mv_polynomial_int : free_comm_ring α ≃+* mv_polynomial α ℤ := ring_equiv.of_hom_inv - (free_comm_ring.lift $ λ a, mv_polynomial.X a) + (free_comm_ring.lift $ (λ a, mv_polynomial.X a : α → mv_polynomial α ℤ)) (mv_polynomial.eval₂_hom (int.cast_ring_hom (free_comm_ring α)) free_comm_ring.of) (by { ext, simp }) - (by ext; simp ) + (by ext; simp) /-- The free commutative ring on the empty type is isomorphic to `ℤ`. -/ def free_comm_ring_pempty_equiv_int : free_comm_ring pempty.{u+1} ≃+* ℤ := diff --git a/src/ring_theory/valuation/valuation_ring.lean b/src/ring_theory/valuation/valuation_ring.lean index bd5ee32a7514b..b3701d3342b6f 100644 --- a/src/ring_theory/valuation/valuation_ring.lean +++ b/src/ring_theory/valuation/valuation_ring.lean @@ -205,12 +205,11 @@ end /-- The valuation ring `A` is isomorphic to the ring of integers of its associated valuation. -/ noncomputable def equiv_integer : A ≃+* (valuation A K).integer := -ring_equiv.of_bijective +ring_equiv.of_bijective (show A →ₙ+* (valuation A K).integer, from { to_fun := λ a, ⟨algebra_map A K a, (mem_integer_iff _ _ _).mpr ⟨a,rfl⟩⟩, - map_one' := by { ext1, exact (algebra_map A K).map_one }, map_mul' := λ _ _, by { ext1, exact (algebra_map A K).map_mul _ _ }, map_zero' := by { ext1, exact (algebra_map A K).map_zero }, - map_add' := λ _ _, by { ext1, exact (algebra_map A K).map_add _ _ } } + map_add' := λ _ _, by { ext1, exact (algebra_map A K).map_add _ _ } }) begin split, { intros x y h, From 6ae00ad35437e38a2dc76f2328ff5a5c579aae0a Mon Sep 17 00:00:00 2001 From: sgouezel Date: Tue, 26 Apr 2022 07:55:34 +0000 Subject: [PATCH 268/373] chore(tactic/field_simp): fix docstring (#13695) --- src/tactic/field_simp.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/field_simp.lean b/src/tactic/field_simp.lean index bef9be5a60453..7255410dc0798 100644 --- a/src/tactic/field_simp.lean +++ b/src/tactic/field_simp.lean @@ -43,7 +43,7 @@ If the goal is an equality, this simpset will also clear the denominators, so th can normally be concluded by an application of `ring` or `ring_exp`. `field_simp [hx, hy]` is a short form for -`simp [-one_div, -mul_eq_zero, hx, hy] with field_simps {discharger := [field_simp.ne_zero]}` +`simp [-one_div, -mul_eq_zero, hx, hy] with field_simps {discharger := tactic.field_simp.ne_zero}` Note that this naive algorithm will not try to detect common factors in denominators to reduce the complexity of the resulting expression. Instead, it relies on the ability of `ring` to handle From b94ea159de7d40fcea1ee7a5debbfef3e8878ae8 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Tue, 26 Apr 2022 09:51:39 +0000 Subject: [PATCH 269/373] refactor(linear_algebra/matrix/trace): unbundle `matrix.diag` (#13687) The bundling makes it awkward to work with, as the base ring has to be specified even though it doesn't affect the computation. This brings it in line with `matrix.diagonal`. The bundled version is now available as `matrix.diag_linear_map`. This adds a handful of missing lemmas about `diag` inspired by those about `diagonal`; almost all of which are just `rfl`. --- .../83_friendship_graphs.lean | 2 +- src/analysis/matrix.lean | 2 +- src/data/matrix/basic.lean | 80 ++++++++++++++++--- src/data/matrix/basis.lean | 4 +- src/linear_algebra/matrix/is_diag.lean | 23 +++--- src/linear_algebra/matrix/trace.lean | 28 +------ src/topology/algebra/matrix.lean | 5 +- 7 files changed, 88 insertions(+), 56 deletions(-) diff --git a/archive/100-theorems-list/83_friendship_graphs.lean b/archive/100-theorems-list/83_friendship_graphs.lean index b5b7d6e263cf4..30ecea0fe0307 100644 --- a/archive/100-theorems-list/83_friendship_graphs.lean +++ b/archive/100-theorems-list/83_friendship_graphs.lean @@ -256,7 +256,7 @@ begin -- but the trace is 1 mod p when computed the other way rw adj_matrix_pow_mod_p_of_regular hG dmod hd hp2, dunfold fintype.card at Vmod, - simp only [matrix.trace, diag_apply, mul_one, nsmul_eq_mul, linear_map.coe_mk, sum_const], + simp only [matrix.trace, matrix.diag, mul_one, nsmul_eq_mul, linear_map.coe_mk, sum_const], rw [Vmod, ← nat.cast_one, zmod.nat_coe_zmod_eq_zero_iff_dvd, nat.dvd_one, nat.min_fac_eq_one_iff], linarith, diff --git a/src/analysis/matrix.lean b/src/analysis/matrix.lean index 2b688866e78ac..9b1898d5aa263 100644 --- a/src/analysis/matrix.lean +++ b/src/analysis/matrix.lean @@ -85,7 +85,7 @@ begin refine le_antisymm (finset.sup_le $ λ j hj, _) _, { obtain rfl | hij := eq_or_ne i j, { rw diagonal_apply_eq }, - { rw [diagonal_apply_ne hij, nnnorm_zero], + { rw [diagonal_apply_ne _ hij, nnnorm_zero], exact zero_le _ }, }, { refine eq.trans_le _ (finset.le_sup (finset.mem_univ i)), rw diagonal_apply_eq } diff --git a/src/data/matrix/basic.lean b/src/data/matrix/basic.lean index 283fe8f91ec52..f7b8a6cb3da67 100644 --- a/src/data/matrix/basic.lean +++ b/src/data/matrix/basic.lean @@ -204,14 +204,14 @@ Note that bundled versions exist as: def diagonal [has_zero α] (d : n → α) : matrix n n α | i j := if i = j then d i else 0 -@[simp] theorem diagonal_apply_eq [has_zero α] {d : n → α} (i : n) : (diagonal d) i i = d i := +@[simp] theorem diagonal_apply_eq [has_zero α] (d : n → α) (i : n) : (diagonal d) i i = d i := by simp [diagonal] -@[simp] theorem diagonal_apply_ne [has_zero α] {d : n → α} {i j : n} (h : i ≠ j) : +@[simp] theorem diagonal_apply_ne [has_zero α] (d : n → α) {i j : n} (h : i ≠ j) : (diagonal d) i j = 0 := by simp [diagonal, h] -theorem diagonal_apply_ne' [has_zero α] {d : n → α} {i j : n} (h : j ≠ i) : - (diagonal d) i j = 0 := diagonal_apply_ne h.symm +theorem diagonal_apply_ne' [has_zero α] (d : n → α) {i j : n} (h : j ≠ i) : + (diagonal d) i j = 0 := diagonal_apply_ne d h.symm lemma diagonal_injective [has_zero α] : function.injective (diagonal : (n → α) → matrix n n α) := λ d₁ d₂ h, funext $ λ i, by simpa using matrix.ext_iff.mpr h i i @@ -225,7 +225,7 @@ begin ext i j, by_cases h : i = j, { simp [h, transpose] }, - { simp [h, transpose, diagonal_apply_ne' h] } + { simp [h, transpose, diagonal_apply_ne' _ h] } end @[simp] theorem diagonal_add [add_zero_class α] (d₁ d₂ : n → α) : @@ -277,13 +277,13 @@ instance : has_one (matrix n n α) := ⟨diagonal (λ _, 1)⟩ theorem one_apply {i j} : (1 : matrix n n α) i j = if i = j then 1 else 0 := rfl -@[simp] theorem one_apply_eq (i) : (1 : matrix n n α) i i = 1 := diagonal_apply_eq i +@[simp] theorem one_apply_eq (i) : (1 : matrix n n α) i i = 1 := diagonal_apply_eq _ i @[simp] theorem one_apply_ne {i j} : i ≠ j → (1 : matrix n n α) i j = 0 := -diagonal_apply_ne +diagonal_apply_ne _ theorem one_apply_ne' {i j} : j ≠ i → (1 : matrix n n α) i j = 0 := -diagonal_apply_ne' +diagonal_apply_ne' _ @[simp] lemma map_one [has_zero β] [has_one β] (f : α → β) (h₀ : f 0 = 0) (h₁ : f 1 = 1) : @@ -320,6 +320,56 @@ end numeral end diagonal +section diag + +/-- The diagonal of a square matrix. -/ +@[simp] def diag (A : matrix n n α) (i : n) : α := A i i + +@[simp] lemma diag_diagonal [decidable_eq n] [has_zero α] (a : n → α) : diag (diagonal a) = a := +funext $ @diagonal_apply_eq _ _ _ _ a + +@[simp] lemma diag_transpose (A : matrix n n α) : diag Aᵀ = diag A := rfl + +@[simp] theorem diag_zero [has_zero α] : diag (0 : matrix n n α) = 0 := rfl + +@[simp] theorem diag_add [has_add α] (A B : matrix n n α) : diag (A + B) = diag A + diag B := rfl + +@[simp] theorem diag_sub [has_sub α] (A B : matrix n n α) : diag (A - B) = diag A - diag B := rfl + +@[simp] theorem diag_neg [has_neg α] (A : matrix n n α) : diag (-A) = -diag A := rfl + +@[simp] theorem diag_smul [has_scalar R α] (r : R) (A : matrix n n α) : diag (r • A) = r • diag A := +rfl + +@[simp] theorem diag_one [decidable_eq n] [has_zero α] [has_one α] : diag (1 : matrix n n α) = 1 := +diag_diagonal _ + +variables (n α) + +/-- `matrix.diag` as an `add_monoid_hom`. -/ +@[simps] +def diag_add_monoid_hom [add_zero_class α] : matrix n n α →+ (n → α) := +{ to_fun := diag, + map_zero' := diag_zero, + map_add' := diag_add,} + +variables (R) + +/-- `matrix.diag` as a `linear_map`. -/ +@[simps] +def diag_linear_map [semiring R] [add_comm_monoid α] [module R α] : matrix n n α →ₗ[R] (n → α) := +{ map_smul' := diag_smul, + .. diag_add_monoid_hom n α,} + +variables {n α R} + +lemma diag_map {f : α → β} {A : matrix n n α} : diag (A.map f) = f ∘ diag A := rfl + +@[simp] lemma diag_conj_transpose [add_monoid α] [star_add_monoid α] (A : matrix n n α) : + diag Aᴴ = star (diag A) := rfl + +end diag + section dot_product variable [fintype m] @@ -368,15 +418,15 @@ section non_unital_non_assoc_semiring_decidable variables [decidable_eq m] [non_unital_non_assoc_semiring α] (u v w : m → α) @[simp] lemma diagonal_dot_product (i : m) : diagonal v i ⬝ᵥ w = v i * w i := -have ∀ j ≠ i, diagonal v i j * w j = 0 := λ j hij, by simp [diagonal_apply_ne' hij], +have ∀ j ≠ i, diagonal v i j * w j = 0 := λ j hij, by simp [diagonal_apply_ne' _ hij], by convert finset.sum_eq_single i (λ j _, this j) _ using 1; simp @[simp] lemma dot_product_diagonal (i : m) : v ⬝ᵥ diagonal w i = v i * w i := -have ∀ j ≠ i, v j * diagonal w i j = 0 := λ j hij, by simp [diagonal_apply_ne' hij], +have ∀ j ≠ i, v j * diagonal w i j = 0 := λ j hij, by simp [diagonal_apply_ne' _ hij], by convert finset.sum_eq_single i (λ j _, this j) _ using 1; simp @[simp] lemma dot_product_diagonal' (i : m) : v ⬝ᵥ (λ j, diagonal w j i) = v i * w i := -have ∀ j ≠ i, v j * diagonal w j i = 0 := λ j hij, by simp [diagonal_apply_ne hij], +have ∀ j ≠ i, v j * diagonal w j i = 0 := λ j hij, by simp [diagonal_apply_ne _ hij], by convert finset.sum_eq_single i (λ j _, this j) _ using 1; simp @[simp] lemma single_dot_product (x : α) (i : m) : pi.single i x ⬝ᵥ v = x * v i := @@ -525,6 +575,9 @@ lemma smul_eq_diagonal_mul [fintype m] [decidable_eq m] (M : matrix m n α) (a : a • M = diagonal (λ _, a) ⬝ M := by { ext, simp } +@[simp] lemma diag_col_mul_row (a b : n → α) : diag (col a ⬝ row b) = a * b := +by { ext, simp [matrix.mul_apply, col, row] } + /-- Left multiplication by a matrix, as an `add_monoid_hom` from matrices to matrices. -/ @[simps] def add_monoid_hom_mul_left [fintype m] (M : matrix l m α) : matrix m n α →+ matrix l n α := @@ -1153,7 +1206,7 @@ begin unfold has_one.one transpose, by_cases i = j, { simp only [h, diagonal_apply_eq] }, - { simp only [diagonal_apply_ne h, diagonal_apply_ne (λ p, h (symm p))] } + { simp only [diagonal_apply_ne _ h, diagonal_apply_ne' _ h] } end @[simp] lemma transpose_add [has_add α] (M : matrix m n α) (N : matrix m n α) : @@ -1392,7 +1445,7 @@ ext $ λ i j, begin rw minor_apply, by_cases h : i = j, { rw [h, diagonal_apply_eq, diagonal_apply_eq], }, - { rw [diagonal_apply_ne h, diagonal_apply_ne (he.ne h)], }, + { rw [diagonal_apply_ne _ h, diagonal_apply_ne _ (he.ne h)], }, end lemma minor_one [has_zero α] [has_one α] [decidable_eq m] [decidable_eq l] (e : l → m) @@ -1406,6 +1459,7 @@ lemma minor_mul [fintype n] [fintype o] [has_mul α] [add_comm_monoid α] {p q : (M ⬝ N).minor e₁ e₃ = (M.minor e₁ e₂) ⬝ (N.minor e₂ e₃) := ext $ λ _ _, (he₂.sum_comp _).symm +lemma diag_minor (A : matrix m m α) (e : l → m) : diag (A.minor e e) = A.diag ∘ e := rfl /-! `simp` lemmas for `matrix.minor`s interaction with `matrix.diagonal`, `1`, and `matrix.mul` for when the mappings are bundled. -/ diff --git a/src/data/matrix/basis.lean b/src/data/matrix/basis.lean index b3a7610d779e9..f60a9942cd9b7 100644 --- a/src/data/matrix/basis.lean +++ b/src/data/matrix/basis.lean @@ -121,10 +121,10 @@ section variables (i j : n) (c : α) (i' j' : n) -@[simp] lemma diag_zero (h : j ≠ i) : diag n α α (std_basis_matrix i j c) = 0 := +@[simp] lemma diag_zero (h : j ≠ i) : diag (std_basis_matrix i j c) = 0 := funext $ λ k, if_neg $ λ ⟨e₁, e₂⟩, h (e₂.trans e₁.symm) -@[simp] lemma diag_same : diag n α α (std_basis_matrix i i c) = pi.single i c := +@[simp] lemma diag_same : diag (std_basis_matrix i i c) = pi.single i c := by { ext j, by_cases hij : i = j; try {rw hij}; simp [hij] } variable [fintype n] diff --git a/src/linear_algebra/matrix/is_diag.lean b/src/linear_algebra/matrix/is_diag.lean index 9cdc5645eede1..f4c75fe90ec93 100644 --- a/src/linear_algebra/matrix/is_diag.lean +++ b/src/linear_algebra/matrix/is_diag.lean @@ -33,22 +33,21 @@ def is_diag [has_zero α] (A : matrix n n α) : Prop := ∀ ⦃i j⦄, i ≠ j @[simp] lemma is_diag_diagonal [has_zero α] [decidable_eq n] (d : n → α) : (diagonal d).is_diag := -λ i j, matrix.diagonal_apply_ne +λ i j, matrix.diagonal_apply_ne _ -/-- Diagonal matrices are generated by `matrix.diagonal`. -/ -lemma is_diag.exists_diagonal [has_zero α] [decidable_eq n] {A : matrix n n α} (h : A.is_diag) : - ∃ d, diagonal d = A := -begin - refine ⟨λ i, A i i, ext $ λ i j, _⟩, +/-- Diagonal matrices are generated by the `matrix.diagonal` of their `matrix.diag`. -/ +lemma is_diag.diagonal_diag [has_zero α] [decidable_eq n] {A : matrix n n α} (h : A.is_diag) : + diagonal (diag A) = A := +ext $ λ i j, begin obtain rfl | hij := decidable.eq_or_ne i j, - { rw diagonal_apply_eq }, - { rw [diagonal_apply_ne hij, h hij] }, + { rw [diagonal_apply_eq, diag] }, + { rw [diagonal_apply_ne _ hij, h hij] }, end -/-- `matrix.is_diag.exists_diagonal` as an iff. -/ -lemma is_diag_iff_exists_diagonal [has_zero α] [decidable_eq n] (A : matrix n n α) : - A.is_diag ↔ (∃ d, diagonal d = A) := -⟨is_diag.exists_diagonal, λ ⟨d, hd⟩, hd ▸ is_diag_diagonal d⟩ +/-- `matrix.is_diag.diagonal_diag` as an iff. -/ +lemma is_diag_iff_diagonal_diag [has_zero α] [decidable_eq n] (A : matrix n n α) : + A.is_diag ↔ diagonal (diag A) = A := +⟨is_diag.diagonal_diag, λ hd, hd ▸ is_diag_diagonal (diag A)⟩ /-- Every matrix indexed by a subsingleton is diagonal. -/ lemma is_diag_of_subsingleton [has_zero α] [subsingleton n] (A : matrix n n α) : A.is_diag := diff --git a/src/linear_algebra/matrix/trace.lean b/src/linear_algebra/matrix/trace.lean index 072a4a21a9eea..5d8f912b3300f 100644 --- a/src/linear_algebra/matrix/trace.lean +++ b/src/linear_algebra/matrix/trace.lean @@ -31,46 +31,26 @@ universes u v w variables {m : Type*} (n : Type*) {p : Type*} variables (R : Type*) (M : Type*) [semiring R] [add_comm_monoid M] [module R M] -/-- -The diagonal of a square matrix. --/ -def diag : (matrix n n M) →ₗ[R] n → M := -{ to_fun := λ A i, A i i, - map_add' := by { intros, ext, refl, }, - map_smul' := by { intros, ext, refl, } } - -variables {n} {R} {M} - -@[simp] lemma diag_apply (A : matrix n n M) (i : n) : diag n R M A i = A i i := rfl - -@[simp] lemma diag_one [decidable_eq n] : - diag n R R 1 = λ i, 1 := by { dunfold diag, ext, simp [one_apply_eq] } - -@[simp] lemma diag_transpose (A : matrix n n M) : diag n R M Aᵀ = diag n R M A := rfl - -@[simp] lemma diag_col_mul_row (a b : n → R) : diag n R R (col a ⬝ row b) = a * b := -by { ext, simp [matrix.mul_apply] } - variables (n) (R) (M) /-- The trace of a square matrix. -/ def trace [fintype n] : (matrix n n M) →ₗ[R] M := -{ to_fun := λ A, ∑ i, diag n R M A i, +{ to_fun := λ A, ∑ i, diag A i, map_add' := by { intros, apply finset.sum_add_distrib, }, map_smul' := by { intros, simp [finset.smul_sum], } } variables {n} {R} {M} [fintype n] [fintype m] [fintype p] -@[simp] lemma trace_diag (A : matrix n n M) : trace n R M A = ∑ i, diag n R M A i := rfl +@[simp] lemma trace_diag (A : matrix n n M) : trace n R M A = ∑ i, diag A i := rfl lemma trace_apply (A : matrix n n M) : trace n R M A = ∑ i, A i i := rfl @[simp] lemma trace_one [decidable_eq n] : trace n R R 1 = fintype.card n := -have h : trace n R R 1 = ∑ i, diag n R R 1 i := rfl, -by simp_rw [h, diag_one, finset.sum_const, nsmul_one]; refl +have h : trace n R R 1 = ∑ i, diag 1 i := rfl, +by simp_rw [h, diag_one, pi.one_def, finset.sum_const, nsmul_one]; refl @[simp] lemma trace_transpose (A : matrix n n M) : trace n R M Aᵀ = trace n R M A := rfl diff --git a/src/topology/algebra/matrix.lean b/src/topology/algebra/matrix.lean index 89157a0a77a69..73278a09aeb42 100644 --- a/src/topology/algebra/matrix.lean +++ b/src/topology/algebra/matrix.lean @@ -137,9 +137,8 @@ lemma continuous.matrix_reindex {A : X → matrix l n R} hA.matrix_minor _ _ @[continuity] -lemma continuous.matrix_diag [semiring S] [add_comm_monoid R] [module S R] - {A : X → matrix n n R} (hA : continuous A) : - continuous (λ x, matrix.diag n S R (A x)) := +lemma continuous.matrix_diag {A : X → matrix n n R} (hA : continuous A) : + continuous (λ x, matrix.diag (A x)) := continuous_pi $ λ _, hA.matrix_elem _ _ @[continuity] From 4c6b373745305904361a287b17d440499e72a2fe Mon Sep 17 00:00:00 2001 From: tb65536 Date: Tue, 26 Apr 2022 09:51:40 +0000 Subject: [PATCH 270/373] feat(group_theory/subgroup/basic): `zpowers_le` (#13693) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds a lemma `zpowers_le : zpowers g ≤ H ↔ g ∈ H`. I also fixed the `to_additive` name of a lemma from a previous PR. --- src/group_theory/subgroup/basic.lean | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/group_theory/subgroup/basic.lean b/src/group_theory/subgroup/basic.lean index ffaa9db910d7d..d09154d73c2d1 100644 --- a/src/group_theory/subgroup/basic.lean +++ b/src/group_theory/subgroup/basic.lean @@ -2650,10 +2650,15 @@ end namespace subgroup -@[to_additive] instance zpowers_is_commutative (g : G) : (zpowers g).is_commutative := +@[to_additive zmultiples_is_commutative] +instance zpowers_is_commutative (g : G) : (zpowers g).is_commutative := ⟨⟨λ ⟨_, _, h₁⟩ ⟨_, _, h₂⟩, by rw [subtype.ext_iff, coe_mul, coe_mul, subtype.coe_mk, subtype.coe_mk, ←h₁, ←h₂, zpow_mul_comm]⟩⟩ +@[simp, to_additive zmultiples_le, simp] +lemma zpowers_le {g : G} {H : subgroup G} : zpowers g ≤ H ↔ g ∈ H := +by rw [zpowers_eq_closure, closure_le, set.singleton_subset_iff, set_like.mem_coe] + end subgroup namespace monoid_hom From 5172448ce8432766a61e883b261d10c489b2d6ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Tue, 26 Apr 2022 09:51:41 +0000 Subject: [PATCH 271/373] feat(set_theory/game/pgame): Conway induction on games (#13699) This is a more convenient restatement of the induction principle of the type. --- src/set_theory/game/pgame.lean | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/set_theory/game/pgame.lean b/src/set_theory/game/pgame.lean index 516348ec8fd73..aacf78cb5ec15 100644 --- a/src/set_theory/game/pgame.lean +++ b/src/set_theory/game/pgame.lean @@ -148,6 +148,13 @@ def move_right : Π (g : pgame), right_moves g → pgame @[simp] lemma right_moves_mk {xl xr xL xR} : (⟨xl, xr, xL, xR⟩ : pgame).right_moves = xr := rfl @[simp] lemma move_right_mk {xl xr xL xR} : (⟨xl, xr, xL, xR⟩ : pgame).move_right = xR := rfl +/-- A variant of `pgame.rec_on` expressed in terms of `pgame.move_left` and `pgame.move_right`. + +Both this and `pgame.rec_on` describe Conway induction on games. -/ +@[elab_as_eliminator] def move_rec_on {C : pgame → Sort*} (x : pgame) + (IH : ∀ (y : pgame), (∀ i, C (y.move_left i)) → (∀ j, C (y.move_right j)) → C y) : C x := +x.rec_on $ λ yl yr yL yR, IH (mk yl yr yL yR) + /-- `subsequent p q` says that `p` can be obtained by playing some nonempty sequence of moves from `q`. -/ inductive subsequent : pgame → pgame → Prop From b0efdbbd7555bbb1c4ad3f2c863902feccc2c972 Mon Sep 17 00:00:00 2001 From: antoinelab01 Date: Tue, 26 Apr 2022 09:51:42 +0000 Subject: [PATCH 272/373] feat(algebra/module/linear_map) : cancel_right and cancel_left for linear_maps (#13703) --- src/algebra/module/linear_map.lean | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/algebra/module/linear_map.lean b/src/algebra/module/linear_map.lean index 951b1949da06e..74d51e850b9d1 100644 --- a/src/algebra/module/linear_map.lean +++ b/src/algebra/module/linear_map.lean @@ -357,6 +357,18 @@ linear_map.ext $ λ x, rfl @[simp] theorem id_comp : id.comp f = f := linear_map.ext $ λ x, rfl +variables {f g} {f' : M₂ →ₛₗ[σ₂₃] M₃} {g' : M₁ →ₛₗ[σ₁₂] M₂} + +include σ₁₃ +theorem cancel_right (hg : function.surjective g) : + f.comp g = f'.comp g ↔ f = f' := +⟨λ h, ext $ hg.forall.2 (ext_iff.1 h), λ h, h ▸ rfl⟩ + +theorem cancel_left (hf : function.injective f) : + f.comp g = f.comp g' ↔ g = g' := +⟨λ h, ext $ λ x, hf $ by rw [← comp_apply, h, comp_apply], λ h, h ▸ rfl⟩ +omit σ₁₃ + end variables [add_comm_monoid M] [add_comm_monoid M₁] [add_comm_monoid M₂] [add_comm_monoid M₃] From c83488b91c7030484d3c2afbd3960de719db9369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 26 Apr 2022 11:29:38 +0000 Subject: [PATCH 273/373] feat(topology/order/priestley): Priestley spaces (#12044) Define `priestley_space`, a Prop-valued mixin for an ordered topological space to respect Priestley's separation axiom. --- src/order/basic.lean | 3 ++ src/topology/order/priestley.lean | 73 +++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 src/topology/order/priestley.lean diff --git a/src/order/basic.lean b/src/order/basic.lean index 4017d5159659e..48a73f4fa6044 100644 --- a/src/order/basic.lean +++ b/src/order/basic.lean @@ -244,6 +244,9 @@ alias eq_of_ge_of_not_gt ← has_le.le.eq_of_not_gt lemma ne.le_iff_lt [partial_order α] {a b : α} (h : a ≠ b) : a ≤ b ↔ a < b := ⟨λ h', lt_of_le_of_ne h' h, λ h, h.le⟩ +lemma ne.not_le_or_not_le [partial_order α] {a b : α} (h : a ≠ b) : ¬ a ≤ b ∨ ¬ b ≤ a := +not_and_distrib.1 $ le_antisymm_iff.not.1 h + -- See Note [decidable namespace] protected lemma decidable.ne_iff_lt_iff_le [partial_order α] [decidable_eq α] {a b : α} : (a ≠ b ↔ a < b) ↔ a ≤ b := diff --git a/src/topology/order/priestley.lean b/src/topology/order/priestley.lean new file mode 100644 index 0000000000000..ac900eb4b1d1b --- /dev/null +++ b/src/topology/order/priestley.lean @@ -0,0 +1,73 @@ +/- +Copyright (c) 2022 Yaël Dillies. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yaël Dillies +-/ +import order.upper_lower +import topology.separation + +/-! +# Priestley spaces + +This file defines Priestley spaces. A Priestley space is an ordered compact topological space such +that any two distinct points can be separated by a clopen upper set. + +## Main declarations + +* `priestley_space`: Prop-valued mixin stating the Priestley separation axiom: Any two distinct + points can be separated by a clopen upper set. + +## Implementation notes + +We do not include compactness in the definition, so a Priestley space is to be declared as follows: +`[preorder α] [topological_space α] [compact_space α] [priestley_space α]` + +## References + +* [Wikipedia, *Priestley space*](https://en.wikipedia.org/wiki/Priestley_space) +* [Davey, Priestley *Introduction to Lattices and Order*][davey_priestley] +-/ + +open set + +variables {α : Type*} + +/-- A Priestley space is an ordered topological space such that any two distinct points can be +separated by a clopen upper set. Compactness is often assumed, but we do not include it here. -/ +class priestley_space (α : Type*) [preorder α] [topological_space α] := +(priestley {x y : α} : ¬ x ≤ y → ∃ U : set α, is_clopen U ∧ is_upper_set U ∧ x ∈ U ∧ y ∉ U) + +variables [topological_space α] + +section preorder +variables [preorder α] [priestley_space α] {x y : α} + +lemma exists_clopen_upper_of_not_le : + ¬ x ≤ y → ∃ U : set α, is_clopen U ∧ is_upper_set U ∧ x ∈ U ∧ y ∉ U := +priestley_space.priestley + +lemma exists_clopen_lower_of_not_le (h : ¬ x ≤ y) : + ∃ U : set α, is_clopen U ∧ is_lower_set U ∧ x ∉ U ∧ y ∈ U := +let ⟨U, hU, hU', hx, hy⟩ := exists_clopen_upper_of_not_le h in + ⟨Uᶜ, hU.compl, hU'.compl, not_not.2 hx, hy⟩ + +end preorder + +section partial_order +variables [partial_order α] [priestley_space α] {x y : α} + +lemma exists_clopen_upper_or_lower_of_ne (h : x ≠ y) : + ∃ U : set α, is_clopen U ∧ (is_upper_set U ∨ is_lower_set U) ∧ x ∈ U ∧ y ∉ U := +begin + obtain (h | h) := h.not_le_or_not_le, + { exact (exists_clopen_upper_of_not_le h).imp (λ U, and.imp_right $ and.imp_left or.inl) }, + { obtain ⟨U, hU, hU', hy, hx⟩ := exists_clopen_lower_of_not_le h, + exact ⟨U, hU, or.inr hU', hx, hy⟩ } +end + +@[priority 100] -- See note [lower instance priority] +instance priestley_space.to_t2_space : t2_space α := +⟨λ x y h, let ⟨U, hU, _, hx, hy⟩ := exists_clopen_upper_or_lower_of_ne h in + ⟨U, Uᶜ, hU.is_open, hU.compl.is_open, hx, hy, inter_compl_self _⟩⟩ + +end partial_order From 3d5e5ee18f2296753b5247c4c260592640324281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 26 Apr 2022 13:36:51 +0000 Subject: [PATCH 274/373] feat(data/list/*): Miscellaneous lemmas (#13577) A few lemmas about `list.chain`, `list.pairwise`. Also rename `list.chain_of_pairwise` to `list.pairwise.chain` for dot notation. --- src/data/list/basic.lean | 2 ++ src/data/list/chain.lean | 30 +++++++++++++++++++++--------- src/data/list/cycle.lean | 2 +- src/data/list/pairwise.lean | 18 +++++++++++++----- src/logic/basic.lean | 15 +++++++++++++++ src/logic/relation.lean | 6 ++++++ 6 files changed, 58 insertions(+), 15 deletions(-) diff --git a/src/data/list/basic.lean b/src/data/list/basic.lean index 422a28de0008c..10b224e536bfc 100644 --- a/src/data/list/basic.lean +++ b/src/data/list/basic.lean @@ -57,6 +57,8 @@ cons_injective.eq_iff theorem exists_cons_of_ne_nil {l : list α} (h : l ≠ nil) : ∃ b L, l = b :: L := by { induction l with c l', contradiction, use [c,l'], } +lemma set_of_mem_cons (l : list α) (a : α) : {x | x ∈ a :: l} = insert a {x | x ∈ l} := rfl + /-! ### mem -/ theorem mem_singleton_self (a : α) : a ∈ [a] := mem_cons_self _ _ diff --git a/src/data/list/chain.lean b/src/data/list/chain.lean index e37af09d95fe6..e676fc4b39dc1 100644 --- a/src/data/list/chain.lean +++ b/src/data/list/chain.lean @@ -22,7 +22,7 @@ open nat namespace list -variables {α : Type u} {β : Type v} {R : α → α → Prop} +variables {α : Type u} {β : Type v} {R r : α → α → Prop} {l l₁ l₂ : list α} {a b : α} mk_iff_of_inductive_prop list.chain list.chain_iff @@ -105,7 +105,7 @@ begin { simp [H _ _ _ _ (rel_of_chain_cons hl₂), l_ih _ _ (chain_of_chain_cons hl₂)] } end -theorem chain_of_pairwise {a : α} {l : list α} (p : pairwise R (a :: l)) : chain R a l := +protected lemma pairwise.chain (p : pairwise R (a :: l)) : chain R a l := begin cases pairwise_cons.1 p with r p', clear p, induction p' with b l r' p IH generalizing a, {exact chain.nil}, @@ -113,13 +113,23 @@ begin exact chain_cons.2 ⟨r.1, IH r'⟩ end +protected lemma chain.pairwise (tr : transitive R) : + ∀ {a : α} {l : list α}, chain R a l → pairwise R (a :: l) +| a [] chain.nil := pairwise_singleton _ _ +| a _ (@chain.cons _ _ _ b l h hb) := hb.pairwise.cons begin + simp only [mem_cons_iff, forall_eq_or_imp, h, true_and], + exact λ c hc, tr h (rel_of_pairwise_cons hb.pairwise hc), + end + theorem chain_iff_pairwise (tr : transitive R) {a : α} {l : list α} : chain R a l ↔ pairwise R (a :: l) := -⟨λ c, begin - induction c with b b c l r p IH, {exact pairwise_singleton _ _}, - apply IH.cons _, simp only [mem_cons_iff, forall_eq_or_imp, r, true_and], - show ∀ x ∈ l, R b x, from λ x m, (tr r (rel_of_pairwise_cons IH m)), -end, chain_of_pairwise⟩ +⟨chain.pairwise tr, pairwise.chain⟩ + +protected lemma chain.sublist [is_trans α R] (hl : l₂.chain R a) (h : l₁ <+ l₂) : l₁.chain R a := +by { rw chain_iff_pairwise (transitive_of_trans R) at ⊢ hl, exact hl.sublist (h.cons_cons a) } + +protected lemma chain.rel [is_trans α R] (hl : l.chain R a) (hb : b ∈ l) : R a b := +by { rw chain_iff_pairwise (transitive_of_trans R) at hl, exact rel_of_pairwise_cons hl hb } theorem chain_iff_nth_le {R} : ∀ {a : α} {l : list α}, chain R a l ↔ (∀ h : 0 < length l, R a (nth_le l 0 h)) ∧ (∀ i (h : i < length l - 1), @@ -192,13 +202,16 @@ theorem chain'_map_of_chain' {S : β → β → Prop} (f : α → β) theorem pairwise.chain' : ∀ {l : list α}, pairwise R l → chain' R l | [] _ := trivial -| (a :: l) h := chain_of_pairwise h +| (a :: l) h := pairwise.chain h theorem chain'_iff_pairwise (tr : transitive R) : ∀ {l : list α}, chain' R l ↔ pairwise R l | [] := (iff_true_intro pairwise.nil).symm | (a :: l) := chain_iff_pairwise tr +protected lemma chain'.sublist [is_trans α R] (hl : l₂.chain' R) (h : l₁ <+ l₂) : l₁.chain' R := +by { rw chain'_iff_pairwise (transitive_of_trans R) at ⊢ hl, exact hl.sublist h } + theorem chain'.cons {x y l} (h₁ : R x y) (h₂ : chain' R (y :: l)) : chain' R (x :: y :: l) := chain'_cons.2 ⟨h₁, h₂⟩ @@ -289,7 +302,6 @@ lemma chain'.append_overlap : ∀ {l₁ l₂ l₃ : list α} exact ⟨h₁.1, chain'.append_overlap h₁.2 h₂ (cons_ne_nil _ _)⟩ end -variables {r : α → α → Prop} {a b : α} /-- If `a` and `b` are related by the reflexive transitive closure of `r`, then there is a `r`-chain starting from `a` and ending on `b`. diff --git a/src/data/list/cycle.lean b/src/data/list/cycle.lean index db014480d2972..259637ee19d64 100644 --- a/src/data/list/cycle.lean +++ b/src/data/list/cycle.lean @@ -802,7 +802,7 @@ begin have Ha : a ∈ ((a :: l) : cycle α) := by simp, have Hl : ∀ {b} (hb : b ∈ l), b ∈ ((a :: l) : cycle α) := λ b hb, by simp [hb], rw cycle.chain_coe_cons, - apply chain_of_pairwise, + apply pairwise.chain, rw pairwise_cons, refine ⟨λ b hb, _, pairwise_append.2 ⟨pairwise_of_forall_mem_list (λ b hb c hc, hs b (Hl hb) c (Hl hc)), pairwise_singleton r a, λ b hb c hc, _⟩⟩, diff --git a/src/data/list/pairwise.lean b/src/data/list/pairwise.lean index 0007a381a5bf2..97f027b5ae803 100644 --- a/src/data/list/pairwise.lean +++ b/src/data/list/pairwise.lean @@ -104,16 +104,24 @@ protected lemma pairwise.sublist : Π {l₁ l₂ : list α}, l₁ <+ l₂ → pa | ._ ._ (sublist.cons2 l₁ l₂ a s) (pairwise.cons i h) := (h.sublist s).cons (ball.imp_left s.subset i) -lemma pairwise.forall_of_forall (H : symmetric R) (H₁ : ∀ x ∈ l, R x x) (H₂ : l.pairwise R) : +lemma pairwise.forall_of_forall_of_flip (h₁ : ∀ x ∈ l, R x x) (h₂ : l.pairwise R) + (h₃ : l.pairwise (flip R)) : ∀ ⦃x⦄, x ∈ l → ∀ ⦃y⦄, y ∈ l → R x y := begin - induction l with a l IH, { exact forall_mem_nil _ }, - cases forall_mem_cons.1 H₁ with H₁₁ H₁₂, - cases pairwise_cons.1 H₂ with H₂₁ H₂₂, + induction l with a l ih, + { exact forall_mem_nil _ }, + rw pairwise_cons at h₂ h₃, rintro x (rfl | hx) y (rfl | hy), - exacts [H₁₁, H₂₁ _ hy, H (H₂₁ _ hx), IH H₁₂ H₂₂ hx hy] + { exact h₁ _ (l.mem_cons_self _) }, + { exact h₂.1 _ hy }, + { exact h₃.1 _ hx }, + { exact ih (λ x hx, h₁ _ $ mem_cons_of_mem _ hx) h₂.2 h₃.2 hx hy } end +lemma pairwise.forall_of_forall (H : symmetric R) (H₁ : ∀ x ∈ l, R x x) (H₂ : l.pairwise R) : + ∀ ⦃x⦄, x ∈ l → ∀ ⦃y⦄, y ∈ l → R x y := +H₂.forall_of_forall_of_flip H₁ $ by rwa H.flip_eq + lemma pairwise.forall (hR : symmetric R) (hl : l.pairwise R) : ∀ ⦃a⦄, a ∈ l → ∀ ⦃b⦄, b ∈ l → a ≠ b → R a b := pairwise.forall_of_forall diff --git a/src/logic/basic.lean b/src/logic/basic.lean index fd821f5aee3ce..fe3d02aa4ae8c 100644 --- a/src/logic/basic.lean +++ b/src/logic/basic.lean @@ -907,6 +907,21 @@ lemma congr_arg2 {α β γ : Sort*} (f : α → β → γ) {x x' : α} {y y' : (hx : x = x') (hy : y = y') : f x y = f x' y' := by { subst hx, subst hy } +variables {β : α → Sort*} {γ : Π a, β a → Sort*} {δ : Π a b, γ a b → Sort*} + +lemma congr_fun₂ {f g : Π a b, γ a b} (h : f = g) (a : α) (b : β a) : f a b = g a b := +congr_fun (congr_fun h _) _ + +lemma congr_fun₃ {f g : Π a b c, δ a b c} (h : f = g) (a : α) (b : β a) (c : γ a b) : + f a b c = g a b c := +congr_fun₂ (congr_fun h _) _ _ + +lemma funext₂ {f g : Π a, β a → Prop} (h : ∀ a b, f a b = g a b) : f = g := +funext $ λ _, funext $ h _ + +lemma funext₃ {f g : Π a b, γ a b → Prop} (h : ∀ a b c, f a b c = g a b c) : f = g := +funext $ λ _, funext₂ $ h _ + end equality /-! ### Declarations about quantifiers -/ diff --git a/src/logic/relation.lean b/src/logic/relation.lean index 249e24aef2306..ff39369815cc1 100644 --- a/src/logic/relation.lean +++ b/src/logic/relation.lean @@ -71,6 +71,12 @@ is_refl.reflexive.ne_imp_iff protected lemma symmetric.iff (H : symmetric r) (x y : α) : r x y ↔ r y x := ⟨λ h, H h, λ h, H h⟩ +lemma symmetric.flip_eq (h : symmetric r) : flip r = r := funext₂ $ λ _ _, propext $ h.iff _ _ +lemma symmetric.swap_eq : symmetric r → swap r = r := symmetric.flip_eq + +lemma flip_eq_iff : flip r = r ↔ symmetric r := ⟨λ h x y, (congr_fun₂ h _ _).mp, symmetric.flip_eq⟩ +lemma swap_eq_iff : swap r = r ↔ symmetric r := flip_eq_iff + end ne_imp section comap From e6c6764df0cdf3ee8c4d1159a4f8ce75be91311b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Tue, 26 Apr 2022 13:36:52 +0000 Subject: [PATCH 275/373] feat(logic/relation): Add missing instances (#13704) Co-authored-by: Eric Wieser --- src/logic/relation.lean | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/logic/relation.lean b/src/logic/relation.lean index ff39369815cc1..708b9fe98669a 100644 --- a/src/logic/relation.lean +++ b/src/logic/relation.lean @@ -188,6 +188,9 @@ lemma mono {p : α → α → Prop} (hp : ∀ a b, r a b → p a b) : ∀ {a b}, | a _ refl_gen.refl := by refl | a b (single h) := single (hp a b h) +instance : is_refl α (refl_gen r) := +⟨@refl α r⟩ + end refl_gen namespace refl_trans_gen @@ -385,6 +388,9 @@ trans_gen.single⟩ lemma transitive_trans_gen : transitive (trans_gen r) := λ a b c, trans_gen.trans +instance : is_trans α (trans_gen r) := +⟨@trans_gen.trans α r⟩ + lemma trans_gen_idem : trans_gen (trans_gen r) = trans_gen r := trans_gen_eq_self transitive_trans_gen @@ -457,6 +463,12 @@ lemma reflexive_refl_trans_gen : reflexive (refl_trans_gen r) := lemma transitive_refl_trans_gen : transitive (refl_trans_gen r) := λ a b c, trans +instance : is_refl α (refl_trans_gen r) := +⟨@refl_trans_gen.refl α r⟩ + +instance : is_trans α (refl_trans_gen r) := +⟨@refl_trans_gen.trans α r⟩ + lemma refl_trans_gen_idem : refl_trans_gen (refl_trans_gen r) = refl_trans_gen r := refl_trans_gen_eq_self reflexive_refl_trans_gen transitive_refl_trans_gen From bfa0ba5b46ab222d056be276375b62be80d3b900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 26 Apr 2022 13:36:53 +0000 Subject: [PATCH 276/373] feat(analysis/normed_space/pointwise): The closure of a thickening (#13708) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prove `closure (thickening δ s) = cthickening δ s` and golf "thickening a thickening" lemmas. --- src/analysis/normed_space/pointwise.lean | 57 +++++++++--------------- 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/src/analysis/normed_space/pointwise.lean b/src/analysis/normed_space/pointwise.lean index 2b44a759d2d4e..23d089324c0e8 100644 --- a/src/analysis/normed_space/pointwise.lean +++ b/src/analysis/normed_space/pointwise.lean @@ -219,32 +219,6 @@ begin exact le_rfl, end -@[simp] lemma inf_edist_cthickening (δ : ℝ) (s : set E) (x : E) : - inf_edist x (cthickening δ s) = inf_edist x s - ennreal.of_real δ := -begin - obtain hδ | hδ := le_total δ 0, - { rw [cthickening_of_nonpos hδ, inf_edist_closure, of_real_of_nonpos hδ, tsub_zero] }, - obtain hs | hs := le_or_lt (inf_edist x s) (ennreal.of_real δ), - { rw [inf_edist_zero_of_mem (mem_cthickening_iff.2 hs), tsub_eq_zero_of_le hs] }, - refine (tsub_le_iff_right.2 inf_edist_le_inf_edist_cthickening_add).antisymm' _, - refine le_sub_of_add_le_right of_real_ne_top _, - refine le_inf_edist.2 (λ z hz, le_of_forall_lt' $ λ r h, _), - cases r, - { exact add_lt_top.2 ⟨lt_top_iff_ne_top.2 $ inf_edist_ne_top ⟨z, self_subset_cthickening _ hz⟩, - of_real_lt_top⟩ }, - have hr : 0 < ↑r - δ, - { refine sub_pos_of_lt _, - have := hs.trans ((inf_edist_le_edist_of_mem hz).trans_lt h), - rw [of_real_eq_coe_nnreal hδ, some_eq_coe] at this, - exact_mod_cast this }, - rw [some_eq_coe, edist_lt_coe, ←dist_lt_coe, ←add_sub_cancel'_right δ (↑r)] at h, - obtain ⟨y, hxy, hyz⟩ := exists_dist_lt_le hr hδ h, - refine (ennreal.add_lt_add_right of_real_ne_top $ inf_edist_lt_iff.2 - ⟨_, mem_cthickening_of_dist_le _ _ _ _ hz hyz, edist_lt_of_real.2 hxy⟩).trans_le _, - rw [←of_real_add hr.le hδ, sub_add_cancel, of_real_coe_nnreal], - exact le_rfl, -end - @[simp] lemma thickening_thickening (hε : 0 < ε) (hδ : 0 < δ) (s : set E) : thickening ε (thickening δ s) = thickening (ε + δ) s := (thickening_thickening_subset _ _ _).antisymm $ λ x, begin @@ -255,16 +229,6 @@ end exact ⟨y, ⟨_, hz, hyz⟩, hxy⟩, end -@[simp] lemma thickening_cthickening (hε : 0 < ε) (hδ : 0 ≤ δ) (s : set E) : - thickening ε (cthickening δ s) = thickening (ε + δ) s := -(thickening_cthickening_subset _ hδ _).antisymm $ λ x, begin - simp_rw mem_thickening_iff, - rintro ⟨z, hz, hxz⟩, - rw add_comm at hxz, - obtain ⟨y, hxy, hyz⟩ := exists_dist_lt_le hε hδ hxz, - exact ⟨y, mem_cthickening_of_dist_le _ _ _ _ hz hyz, hxy⟩, -end - @[simp] lemma cthickening_thickening (hε : 0 ≤ ε) (hδ : 0 < δ) (s : set E) : cthickening ε (thickening δ s) = cthickening (ε + δ) s := (cthickening_thickening_subset hε _ _).antisymm $ λ x, begin @@ -272,6 +236,27 @@ end exact tsub_le_iff_right.2, end +-- Note: `interior (cthickening δ s) ≠ thickening δ s` in general +@[simp] lemma closure_thickening (hδ : 0 < δ) (s : set E) : + closure (thickening δ s) = cthickening δ s := +by { rw [←cthickening_zero, cthickening_thickening le_rfl hδ, zero_add], apply_instance } + +@[simp] lemma inf_edist_cthickening (δ : ℝ) (s : set E) (x : E) : + inf_edist x (cthickening δ s) = inf_edist x s - ennreal.of_real δ := +begin + obtain hδ | hδ := le_or_lt δ 0, + { rw [cthickening_of_nonpos hδ, inf_edist_closure, of_real_of_nonpos hδ, tsub_zero] }, + { rw [←closure_thickening hδ, inf_edist_closure, inf_edist_thickening hδ]; apply_instance } +end + +@[simp] lemma thickening_cthickening (hε : 0 < ε) (hδ : 0 ≤ δ) (s : set E) : + thickening ε (cthickening δ s) = thickening (ε + δ) s := +begin + obtain rfl | hδ := hδ.eq_or_lt, + { rw [cthickening_zero, thickening_closure, add_zero] }, + { rw [←closure_thickening hδ, thickening_closure, thickening_thickening hε hδ]; apply_instance } +end + @[simp] lemma cthickening_cthickening (hε : 0 ≤ ε) (hδ : 0 ≤ δ) (s : set E) : cthickening ε (cthickening δ s) = cthickening (ε + δ) s := (cthickening_cthickening_subset hε hδ _).antisymm $ λ x, begin From e77dbe0c78a757807afba8158a6d828f36924cab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Tue, 26 Apr 2022 13:36:55 +0000 Subject: [PATCH 277/373] doc(data/list/*): Fix file links (#13711) They were linking to `data.list.data.list.defs`. --- src/data/list/count.lean | 2 +- src/data/list/join.lean | 2 +- src/data/list/prod_sigma.lean | 3 +-- src/order/category/BoundedDistribLattice.lean | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/data/list/count.lean b/src/data/list/count.lean index 97e47276f7632..e918fc3ef6aa9 100644 --- a/src/data/list/count.lean +++ b/src/data/list/count.lean @@ -10,7 +10,7 @@ import data.list.big_operators This file proves basic properties of `list.countp` and `list.count`, which count the number of elements of a list satisfying a predicate and equal to a given element respectively. Their -definitions can be found in [`data.list.defs`](./data/list/defs). +definitions can be found in [`data.list.defs`](./defs). -/ open nat diff --git a/src/data/list/join.lean b/src/data/list/join.lean index 5fff65d6c5ebe..ce40ff0e8c20c 100644 --- a/src/data/list/join.lean +++ b/src/data/list/join.lean @@ -9,7 +9,7 @@ import data.list.big_operators # Join of a list of lists This file proves basic properties of `list.join`, which concatenates a list of lists. It is defined -in [`data.list.defs`](./data/list/defs). +in [`data.list.defs`](./defs). -/ variables {α β : Type*} diff --git a/src/data/list/prod_sigma.lean b/src/data/list/prod_sigma.lean index fe6885d2f91c2..db8d50049aacb 100644 --- a/src/data/list/prod_sigma.lean +++ b/src/data/list/prod_sigma.lean @@ -10,8 +10,7 @@ import data.list.big_operators This file proves basic properties of `list.product` and `list.sigma`, which are list constructions living in `prod` and `sigma` types respectively. Their definitions can be found in -[`data.list.defs`](./data/list/defs). Beware, this is not about `list.prod`, the multiplicative -product. +[`data.list.defs`](./defs). Beware, this is not about `list.prod`, the multiplicative product. -/ variables {α β : Type*} diff --git a/src/order/category/BoundedDistribLattice.lean b/src/order/category/BoundedDistribLattice.lean index 3fa7f4fcdc68f..58e342ecbddf9 100644 --- a/src/order/category/BoundedDistribLattice.lean +++ b/src/order/category/BoundedDistribLattice.lean @@ -11,7 +11,7 @@ import order.category.DistribLattice This defines `BoundedDistribLattice`, the category of bounded distributive lattices. -Note that this category is sometimes called [`DistLat`][https://ncatlab.org/nlab/show/DistLat] when +Note that this category is sometimes called [`DistLat`](https://ncatlab.org/nlab/show/DistLat) when being a lattice is understood to entail having a bottom and a top element. -/ From 8b14d48f10ea27afd2e05b6f52be022bca36cd54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Tue, 26 Apr 2022 15:51:40 +0000 Subject: [PATCH 278/373] feat(logic/relation): Transitive closure of well-founded relation is well-founded (#13698) --- src/logic/relation.lean | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/logic/relation.lean b/src/logic/relation.lean index 708b9fe98669a..ea07434f1c40b 100644 --- a/src/logic/relation.lean +++ b/src/logic/relation.lean @@ -373,6 +373,14 @@ end end trans_gen +lemma well_founded.trans_gen {α} {r : α → α → Prop} (h : well_founded r) : + well_founded (trans_gen r) := +⟨λ a, h.induction a (λ x H, acc.intro x (λ y hy, begin + cases hy with _ hyx z _ hyz hzx, + { exact H y hyx }, + { exact acc.inv (H z hzx) hyz } +end))⟩ + section trans_gen lemma trans_gen_eq_self (trans : transitive r) : From 325dbc88802cb1b684a96cacd18f0ef7fcd35958 Mon Sep 17 00:00:00 2001 From: MichaelStollBayreuth Date: Tue, 26 Apr 2022 17:50:14 +0000 Subject: [PATCH 279/373] refactor(number_theory/legendre_symbol/quadratic_reciprocity.lean): change definition of legendre_sym, simplify proofs, add lemmas (#13667) This changes the definition of `legendre_sym` to use `quadratic_char`. The proof of some of the statements can then be simplified by using the corresponding statements for quadratic characters. Some new API lemmas are added, including the fact that the Legendre symbol is multiplicative, Also, a few `simps` are squeezed in `.../quadratic_char.lean`. --- src/data/zmod/basic.lean | 4 + .../legendre_symbol/quadratic_char.lean | 11 +- .../quadratic_reciprocity.lean | 189 +++++++++++------- 3 files changed, 123 insertions(+), 81 deletions(-) diff --git a/src/data/zmod/basic.lean b/src/data/zmod/basic.lean index 03cfd650ba189..af66333a4e8ad 100644 --- a/src/data/zmod/basic.lean +++ b/src/data/zmod/basic.lean @@ -151,6 +151,10 @@ instance (n : ℕ) : char_p (zmod n) n := rw [val_nat_cast, val_zero, nat.dvd_iff_mod_eq_zero], end } +/-- We have that `ring_char (zmod n) = n`. -/ +lemma ring_char_zmod_n (n : ℕ) : ring_char (zmod n) = n := +by { rw ring_char.eq_iff, exact zmod.char_p n, } + @[simp] lemma nat_cast_self (n : ℕ) : (n : zmod n) = 0 := char_p.cast_eq_zero (zmod n) n diff --git a/src/number_theory/legendre_symbol/quadratic_char.lean b/src/number_theory/legendre_symbol/quadratic_char.lean index c50770912b196..98ecd288f77c1 100644 --- a/src/number_theory/legendre_symbol/quadratic_char.lean +++ b/src/number_theory/legendre_symbol/quadratic_char.lean @@ -72,7 +72,7 @@ end /-- A unit `a` of a finite field `F` of odd characteristic is a square if and only if `a ^ (#F / 2) = 1`. -/ -lemma unit_is_sqare_iff (hF : ring_char F ≠ 2) (a : Fˣ) : +lemma unit_is_square_iff (hF : ring_char F ≠ 2) (a : Fˣ) : is_square a ↔ a ^ (fintype.card F / 2) = 1 := begin classical, @@ -102,7 +102,7 @@ lemma is_square_iff (hF : ring_char F ≠ 2) {a : F} (ha : a ≠ 0) : is_square a ↔ a ^ (fintype.card F / 2) = 1 := begin apply (iff_congr _ (by simp [units.ext_iff])).mp - (finite_field.unit_is_sqare_iff hF (units.mk0 a ha)), + (finite_field.unit_is_square_iff hF (units.mk0 a ha)), simp only [is_square, units.ext_iff, units.coe_mk0, units.coe_mul], split, { rintro ⟨y, hy⟩, exact ⟨y, hy⟩ }, { rintro ⟨y, rfl⟩, @@ -176,7 +176,7 @@ begin simp only [quadratic_char], by_cases ha : a = 0, { simp only [ha, eq_self_iff_true, if_true], }, - { simp [ha], + { simp only [ha, if_false, iff_false], split_ifs; simp only [neg_eq_zero, one_ne_zero, not_false_iff], }, end @@ -191,7 +191,8 @@ by simp only [quadratic_char, one_ne_zero, is_square_one, if_true, if_false, id. /-- For nonzero `a : F`, `quadratic_char F a = 1 ↔ is_square a`. -/ lemma quadratic_char_one_iff_is_square {a : F} (ha : a ≠ 0) : quadratic_char F a = 1 ↔ is_square a := -by { simp [quadratic_char, ha, (dec_trivial : (-1 : ℤ) ≠ 1)], tauto } +by { simp only [quadratic_char, ha, (dec_trivial : (-1 : ℤ) ≠ 1), if_false, ite_eq_left_iff], + tauto, } /-- The quadratic character takes the value `1` on nonzero squares. -/ lemma quadratic_char_sq_one' {a : F} (ha : a ≠ 0) : quadratic_char F (a ^ 2) = 1 := @@ -254,7 +255,7 @@ end map_mul' := quadratic_char_mul } /-- The square of the quadratic character on nonzero arguments is `1`. -/ -lemma quadratic_char_sq_one {a : F} (ha : a ≠ 0) : (quadratic_char F a)^2 = 1 := +lemma quadratic_char_sq_one {a : F} (ha : a ≠ 0) : (quadratic_char F a) ^ 2 = 1 := by rwa [pow_two, ← quadratic_char_mul, ← pow_two, quadratic_char_sq_one'] /-- The quadratic character is `1` or `-1` on nonzero arguments. -/ diff --git a/src/number_theory/legendre_symbol/quadratic_reciprocity.lean b/src/number_theory/legendre_symbol/quadratic_reciprocity.lean index 8b85e7576175a..0cefbb4b86f04 100644 --- a/src/number_theory/legendre_symbol/quadratic_reciprocity.lean +++ b/src/number_theory/legendre_symbol/quadratic_reciprocity.lean @@ -1,16 +1,13 @@ /- Copyright (c) 2018 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Chris Hughes +Authors: Chris Hughes, Michael Stoll -/ - -import field_theory.finite.basic -import data.zmod.basic -import data.nat.parity import number_theory.legendre_symbol.gauss_eisenstein_lemmas +import number_theory.legendre_symbol.quadratic_char /-! -# Quadratic reciprocity. +# Legendre symbol and quadratic reciprocity. This file contains results about quadratic residues modulo a prime number. @@ -32,8 +29,7 @@ Also proven are conditions for `-1` and `2` to be a square modulo a prime, The proof of quadratic reciprocity implemented uses Gauss' lemma and Eisenstein's lemma -/ -open function finset nat finite_field zmod -open_locale big_operators nat +open finset nat char namespace zmod @@ -43,21 +39,15 @@ variables (p q : ℕ) [fact p.prime] [fact q.prime] lemma euler_criterion_units (x : (zmod p)ˣ) : (∃ y : (zmod p)ˣ, y ^ 2 = x) ↔ x ^ (p / 2) = 1 := begin - cases nat.prime.eq_two_or_odd (fact.out p.prime) with hp2 hp_odd, - { substI p, refine iff_of_true ⟨1, _⟩ _; apply subsingleton.elim }, - obtain ⟨g, hg⟩ := is_cyclic.exists_generator (zmod p)ˣ, - obtain ⟨n, hn⟩ : x ∈ submonoid.powers g, { rw mem_powers_iff_mem_zpowers, apply hg }, - split, - { rintro ⟨y, rfl⟩, rw [← pow_mul, two_mul_odd_div_two hp_odd, units_pow_card_sub_one_eq_one], }, - { subst x, assume h, - have key : 2 * (p / 2) ∣ n * (p / 2), - { rw [← pow_mul] at h, - rw [two_mul_odd_div_two hp_odd, ← card_units, ← order_of_eq_card_of_forall_mem_zpowers hg], - apply order_of_dvd_of_pow_eq_one h }, - have : 0 < p / 2 := nat.div_pos (fact.out (1 < p)) dec_trivial, - obtain ⟨m, rfl⟩ := dvd_of_mul_dvd_mul_right this key, - refine ⟨g ^ m, _⟩, - rw [mul_comm, pow_mul], }, + by_cases hc : p = 2, + { substI hc, + simp only [eq_iff_true_of_subsingleton, exists_const], }, + { have h₀ := finite_field.unit_is_square_iff (by rwa ring_char_zmod_n) x, + have hs : (∃ y : (zmod p)ˣ, y ^ 2 = x) ↔ is_square(x) := + by { rw is_square_iff_exists_sq x, + simp_rw eq_comm, }, + rw hs, + rwa card p at h₀, }, end /-- Euler's Criterion: a nonzero `a : zmod p` is a square if and only if `x ^ (p / 2) = 1`. -/ @@ -116,62 +106,101 @@ lemma pow_div_two_eq_neg_one_or_one {a : zmod p} (ha : a ≠ 0) : a ^ (p / 2) = 1 ∨ a ^ (p / 2) = -1 := begin cases nat.prime.eq_two_or_odd (fact.out p.prime) with hp2 hp_odd, - { substI p, revert a ha, exact dec_trivial }, + { substI p, revert a ha, dec_trivial }, rw [← mul_self_eq_one_iff, ← pow_add, ← two_mul, two_mul_odd_div_two hp_odd], exact pow_card_sub_one_eq_one ha end -/-- The Legendre symbol of `a` and `p`, `legendre_sym p a`, is an integer defined as +/-- The Legendre symbol of `a : ℤ` and a prime `p`, `legendre_sym p a`, +is an integer defined as * `0` if `a` is `0` modulo `p`; -* `1` if `a ^ (p / 2)` is `1` modulo `p` - (by `euler_criterion` this is equivalent to “`a` is a square modulo `p`”); +* `1` if `a` is a square modulo `p` * `-1` otherwise. Note the order of the arguments! The advantage of the order chosen here is that `legendre_sym p` is a multiplicative function `ℤ → ℤ`. -/ -def legendre_sym (p : ℕ) (a : ℤ) : ℤ := -if (a : zmod p) = 0 then 0 -else if (a : zmod p) ^ (p / 2) = 1 then 1 - else -1 +def legendre_sym (p : ℕ) [fact p.prime] (a : ℤ) : ℤ := quadratic_char (zmod p) a +/-- We have the congruence `legendre_sym p a ≡ a ^ (p / 2) mod p`. -/ lemma legendre_sym_eq_pow (p : ℕ) (a : ℤ) [hp : fact p.prime] : (legendre_sym p a : zmod p) = (a ^ (p / 2)) := begin rw legendre_sym, by_cases ha : (a : zmod p) = 0, - { simp only [int.cast_coe_nat, if_pos, ha, - zero_pow (nat.div_pos (hp.1.two_le) (succ_pos 1)), int.cast_zero] }, - cases hp.1.eq_two_or_odd with hp2 hp_odd, + { simp only [ha, zero_pow (nat.div_pos (hp.1.two_le) (succ_pos 1)), quadratic_char_zero, + int.cast_zero], }, + by_cases hp₁ : p = 2, { substI p, generalize : (a : (zmod 2)) = b, revert b, dec_trivial, }, - { haveI := fact.mk hp_odd, - rw [if_neg ha], - have : (-1 : zmod p) ≠ 1, from (ne_neg_self p one_ne_zero).symm, + { have h₁ := quadratic_char_eq_pow_of_char_ne_two (by rwa ring_char_zmod_n p) ha, + rw card p at h₁, + rw h₁, + have h₂ := finite_field.neg_one_ne_one_of_char_ne_two (by rwa ring_char_zmod_n p), cases pow_div_two_eq_neg_one_or_one p ha with h h, { rw [if_pos h, h, int.cast_one], }, - { rw [h, if_neg this, int.cast_neg, int.cast_one], } } + { rw [h, if_neg h₂, int.cast_neg, int.cast_one], } } end -lemma legendre_sym_eq_one_or_neg_one (p : ℕ) (a : ℤ) (ha : (a : zmod p) ≠ 0) : - legendre_sym p a = -1 ∨ legendre_sym p a = 1 := +/-- If `p ∤ a`, then `legendre_sym p a` is `1` or `-1`. -/ +lemma legendre_sym_eq_one_or_neg_one (p : ℕ) [fact p.prime] (a : ℤ) (ha : (a : zmod p) ≠ 0) : + legendre_sym p a = 1 ∨ legendre_sym p a = -1 := +quadratic_char_dichotomy ha + +/-- The Legendre symbol of `p` and `a` is zero iff `p ∣ a`. -/ +lemma legendre_sym_eq_zero_iff (p : ℕ) [fact p.prime] (a : ℤ) : + legendre_sym p a = 0 ↔ (a : zmod p) = 0 := +quadratic_char_eq_zero_iff a + +@[simp] lemma legendre_sym_zero (p : ℕ) [fact p.prime] : legendre_sym p 0 = 0 := begin - unfold legendre_sym, - split_ifs; - simp only [*, eq_self_iff_true, or_true, true_or] at *, + rw legendre_sym, + exact quadratic_char_zero, end -lemma legendre_sym_eq_zero_iff (p : ℕ) (a : ℤ) : - legendre_sym p a = 0 ↔ (a : zmod p) = 0 := +@[simp] lemma legendre_sym_one (p : ℕ) [fact p.prime] : legendre_sym p 1 = 1 := +begin + rw [legendre_sym, (by norm_cast : ((1 : ℤ) : zmod p) = 1)], + exact quadratic_char_one, +end + +/-- The Legendre symbol is multiplicative in `a` for `p` fixed. -/ +lemma legendre_sym_mul (p : ℕ) [fact p.prime] (a b : ℤ) : + legendre_sym p (a * b) = legendre_sym p a * legendre_sym p b := begin - split, - { classical, contrapose, - assume ha, cases legendre_sym_eq_one_or_neg_one p a ha with h h, - all_goals { rw h, norm_num } }, - { assume ha, rw [legendre_sym, if_pos ha] } + rw [legendre_sym, legendre_sym, legendre_sym], + push_cast, + exact quadratic_char_mul (a : zmod p) b, end +/-- The Legendre symbol is a homomorphism of monoids with zero. -/ +@[simps] def legendre_sym_hom (p : ℕ) [fact p.prime] : ℤ →*₀ ℤ := +{ to_fun := legendre_sym p, + map_zero' := legendre_sym_zero p, + map_one' := legendre_sym_one p, + map_mul' := legendre_sym_mul p } + +/-- The square of the symbol is 1 if `p ∤ a`. -/ +theorem legendre_sym_sq_one (p : ℕ) [fact p.prime] (a : ℤ) (ha : (a : zmod p) ≠ 0) : + (legendre_sym p a)^2 = 1 := +quadratic_char_sq_one ha + +/-- The Legendre symbol of `a^2` at `p` is 1 if `p ∤ a`. -/ +theorem legendre_sym_sq_one' (p : ℕ) [fact p.prime] (a : ℤ) (ha : (a : zmod p) ≠ 0) : + legendre_sym p (a ^ 2) = 1 := +begin + rw [legendre_sym], + push_cast, + exact quadratic_char_sq_one' ha, +end + +/-- The Legendre symbol depends only on `a` mod `p`. -/ +theorem legendre_sym_mod (p : ℕ) [fact p.prime] (a : ℤ) : + legendre_sym p a = legendre_sym p (a % p) := +by simp only [legendre_sym, int_cast_mod] + + /-- Gauss' lemma. The legendre symbol can be computed by considering the number of naturals less than `p/2` such that `(a * x) % p > p / 2` -/ lemma gauss_lemma {a : ℤ} (hp : p ≠ 2) (ha0 : (a : zmod p) ≠ 0) : @@ -188,14 +217,12 @@ begin simp [*, ne_neg_self p one_ne_zero, (ne_neg_self p one_ne_zero).symm] at * end +/-- When `p ∤ a`, then `legendre_sym p a = 1` iff `a` is a square mod `p`. -/ lemma legendre_sym_eq_one_iff {a : ℤ} (ha0 : (a : zmod p) ≠ 0) : - legendre_sym p a = 1 ↔ (∃ b : zmod p, b ^ 2 = a) := -begin - rw [euler_criterion p ha0, legendre_sym, if_neg ha0], - split_ifs, - { simp only [h, eq_self_iff_true] }, - { simp only [h, iff_false], tauto } -end + legendre_sym p a = 1 ↔ is_square (a : zmod p) := +quadratic_char_one_iff_is_square ha0 + +open_locale big_operators lemma eisenstein_lemma (hp : p ≠ 2) {a : ℕ} (ha1 : a % 2 = 1) (ha0 : (a : zmod p) ≠ 0) : legendre_sym p a = (-1)^∑ x in Ico 1 (p / 2).succ, (x * a) / p := @@ -252,12 +279,12 @@ begin end lemma exists_sq_eq_two_iff (hp1 : p ≠ 2) : - (∃ a : zmod p, a ^ 2 = 2) ↔ p % 8 = 1 ∨ p % 8 = 7 := -have hp2 : ((2 : ℤ) : zmod p) ≠ 0, - from prime_ne_zero p 2 (λ h, by simpa [h] using hp1), -have hpm4 : p % 4 = p % 8 % 4, from (nat.mod_mul_left_mod p 2 4).symm, -have hpm2 : p % 2 = p % 8 % 2, from (nat.mod_mul_left_mod p 4 2).symm, + is_square (2 : zmod p) ↔ p % 8 = 1 ∨ p % 8 = 7 := begin + have hp2 : ((2 : ℤ) : zmod p) ≠ 0, + from prime_ne_zero p 2 (λ h, by simpa [h] using hp1), + have hpm4 : p % 4 = p % 8 % 4, from (nat.mod_mul_left_mod p 2 4).symm, + have hpm2 : p % 2 = p % 8 % 2, from (nat.mod_mul_left_mod p 4 2).symm, rw [show (2 : zmod p) = (2 : ℤ), by simp, ← legendre_sym_eq_one_iff p hp2], erw [legendre_sym_two p hp1, neg_one_pow_eq_one_iff_even (show (-1 : ℤ) ≠ 1, from dec_trivial), even_add, even_div, even_div], @@ -270,7 +297,7 @@ begin end lemma exists_sq_eq_prime_iff_of_mod_four_eq_one (hp1 : p % 4 = 1) (hq1 : q ≠ 2) : - (∃ a : zmod p, a ^ 2 = q) ↔ ∃ b : zmod q, b ^ 2 = p := + is_square (q : zmod p) ↔ is_square (p : zmod q) := if hpq : p = q then by substI hpq else have h1 : ((p / 2) * (q / 2)) % 2 = 0, from (dvd_iff_mod_eq_zero _ _).1 @@ -278,17 +305,21 @@ have h1 : ((p / 2) * (q / 2)) % 2 = 0, by rw [← mod_mul_right_div_self, show 2 * 2 = 4, from rfl, hp1]; refl) _), begin have hp_odd : p ≠ 2 := by { by_contra, simp [h] at hp1, norm_num at hp1, }, - have hpq0 : (p : zmod q) ≠ 0 := prime_ne_zero q p (ne.symm hpq), - have hqp0 : (q : zmod p) ≠ 0 := prime_ne_zero p q hpq, + have hpq0 : ((p : ℤ) : zmod q) ≠ 0 := prime_ne_zero q p (ne.symm hpq), + have hqp0 : ((q : ℤ) : zmod p) ≠ 0 := prime_ne_zero p q hpq, have := quadratic_reciprocity p q hp_odd hq1 hpq, - rw [neg_one_pow_eq_pow_mod_two, h1, legendre_sym, legendre_sym, int.cast_coe_nat, - int.cast_coe_nat, if_neg hqp0, if_neg hpq0] at this, - rw [euler_criterion q hpq0, euler_criterion p hqp0], - split_ifs at this; simp *; contradiction, + rw [neg_one_pow_eq_pow_mod_two, h1, pow_zero] at this, + rw [(by norm_cast : (p : zmod q) = (p : ℤ)), (by norm_cast : (q : zmod p) = (q : ℤ)), + ← legendre_sym_eq_one_iff _ hpq0, ← legendre_sym_eq_one_iff _ hqp0], + cases (legendre_sym_eq_one_or_neg_one p q hqp0) with h h, + { simp only [h, eq_self_iff_true, true_iff, mul_one] at this ⊢, + exact this, }, + { simp only [h, mul_neg, mul_one] at this ⊢, + rw eq_neg_of_eq_neg this.symm, }, end lemma exists_sq_eq_prime_iff_of_mod_four_eq_three (hp3 : p % 4 = 3) - (hq3 : q % 4 = 3) (hpq : p ≠ q) : (∃ a : zmod p, a ^ 2 = q) ↔ ¬∃ b : zmod q, b ^ 2 = p := + (hq3 : q % 4 = 3) (hpq : p ≠ q) : is_square (q : zmod p) ↔ ¬ is_square (p : zmod q) := have h1 : ((p / 2) * (q / 2)) % 2 = 1, from nat.odd_mul_odd (by rw [← mod_mul_right_div_self, show 2 * 2 = 4, from rfl, hp3]; refl) @@ -296,13 +327,19 @@ have h1 : ((p / 2) * (q / 2)) % 2 = 1, begin have hp_odd : p ≠ 2 := by { by_contra, simp [h] at hp3, norm_num at hp3, }, have hq_odd : q ≠ 2 := by { by_contra, simp [h] at hq3, norm_num at hq3, }, - have hpq0 : (p : zmod q) ≠ 0 := prime_ne_zero q p (ne.symm hpq), - have hqp0 : (q : zmod p) ≠ 0 := prime_ne_zero p q hpq, + have hpq0 : ((p : ℤ) : zmod q) ≠ 0 := prime_ne_zero q p (ne.symm hpq), + have hqp0 : ((q : ℤ) : zmod p) ≠ 0 := prime_ne_zero p q hpq, have := quadratic_reciprocity p q hp_odd hq_odd hpq, - rw [neg_one_pow_eq_pow_mod_two, h1, legendre_sym, legendre_sym, int.cast_coe_nat, - int.cast_coe_nat, if_neg hpq0, if_neg hqp0] at this, - rw [euler_criterion q hpq0, euler_criterion p hqp0], - split_ifs at this; simp *; contradiction + rw [neg_one_pow_eq_pow_mod_two, h1, pow_one] at this, + rw [(by norm_cast : (p : zmod q) = (p : ℤ)), (by norm_cast : (q : zmod p) = (q : ℤ)), + ← legendre_sym_eq_one_iff _ hpq0, ← legendre_sym_eq_one_iff _ hqp0], + cases (legendre_sym_eq_one_or_neg_one q p hpq0) with h h, + { simp only [h, eq_self_iff_true, not_true, iff_false, one_mul] at this ⊢, + simp only [this], + norm_num, }, + { simp only [h, neg_mul, one_mul, neg_inj] at this ⊢, + simp only [this, eq_self_iff_true, true_iff], + norm_num, }, end end zmod From 560d1a7175b509906f127287008c881e9198eb68 Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Tue, 26 Apr 2022 17:50:15 +0000 Subject: [PATCH 280/373] chore(topology/continuous_function/continuous_map): add missing instances for `continuous_map` (#13717) This adds instances related to the ring variants, i.e., non-unital, non-associative (semi)rings. To avoid introducing accidental diamonds, this also changes how the existing instances are constructed, such that they now go through the `function.injective.*` definitions. --- src/topology/continuous_function/algebra.lean | 55 +++++++++++++++---- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/src/topology/continuous_function/algebra.lean b/src/topology/continuous_function/algebra.lean index 4fd398d0214cf..982300e5bfeba 100644 --- a/src/topology/continuous_function/algebra.lean +++ b/src/topology/continuous_function/algebra.lean @@ -185,6 +185,10 @@ instance {α : Type*} {β : Type*} [topological_space α] [topological_space β] [mul_zero_class β] [has_continuous_mul β] : mul_zero_class C(α, β) := coe_injective.mul_zero_class _ coe_zero coe_mul +instance {α : Type*} {β : Type*} [topological_space α] [topological_space β] + [semigroup_with_zero β] [has_continuous_mul β] : semigroup_with_zero C(α, β) := +coe_injective.semigroup_with_zero _ coe_zero coe_mul + @[to_additive] instance {α : Type*} {β : Type*} [topological_space α] [topological_space β] [monoid β] [has_continuous_mul β] : monoid C(α, β) := @@ -318,27 +322,58 @@ end subtype namespace continuous_map +instance {α : Type*} {β : Type*} [topological_space α] [topological_space β] + [non_unital_non_assoc_semiring β] [topological_semiring β] : + non_unital_non_assoc_semiring C(α, β) := +coe_injective.non_unital_non_assoc_semiring _ coe_zero coe_add coe_mul coe_nsmul + +instance {α : Type*} {β : Type*} [topological_space α] [topological_space β] + [non_unital_semiring β] [topological_semiring β] : + non_unital_semiring C(α, β) := +coe_injective.non_unital_semiring _ coe_zero coe_add coe_mul coe_nsmul + +instance {α : Type*} {β : Type*} [topological_space α] [topological_space β] + [non_assoc_semiring β] [topological_semiring β] : + non_assoc_semiring C(α, β) := +coe_injective.non_assoc_semiring _ coe_zero coe_one coe_add coe_mul coe_nsmul + instance {α : Type*} {β : Type*} [topological_space α] [topological_space β] [semiring β] [topological_semiring β] : semiring C(α, β) := -{ left_distrib := λ a b c, by ext; exact left_distrib _ _ _, - right_distrib := λ a b c, by ext; exact right_distrib _ _ _, - ..continuous_map.add_comm_monoid, - ..continuous_map.monoid_with_zero } +coe_injective.semiring _ coe_zero coe_one coe_add coe_mul coe_nsmul coe_pow + +instance {α : Type*} {β : Type*} [topological_space α] [topological_space β] + [non_unital_non_assoc_ring β] [topological_ring β] : non_unital_non_assoc_ring C(α, β) := +coe_injective.non_unital_non_assoc_ring _ coe_zero coe_add coe_mul coe_neg coe_sub + coe_nsmul coe_zsmul + +instance {α : Type*} {β : Type*} [topological_space α] [topological_space β] + [non_unital_ring β] [topological_ring β] : non_unital_ring C(α, β) := +coe_injective.non_unital_ring _ coe_zero coe_add coe_mul coe_neg coe_sub coe_nsmul coe_zsmul + +instance {α : Type*} {β : Type*} [topological_space α] [topological_space β] + [non_assoc_ring β] [topological_ring β] : non_assoc_ring C(α, β) := +coe_injective.non_assoc_ring _ coe_zero coe_one coe_add coe_mul coe_neg coe_sub coe_nsmul coe_zsmul instance {α : Type*} {β : Type*} [topological_space α] [topological_space β] [ring β] [topological_ring β] : ring C(α, β) := -{ ..continuous_map.semiring, - ..continuous_map.add_comm_group, } +coe_injective.ring _ coe_zero coe_one coe_add coe_mul coe_neg coe_sub coe_nsmul coe_zsmul coe_pow + +instance {α : Type*} {β : Type*} [topological_space α] [topological_space β] + [non_unital_comm_semiring β] [topological_semiring β] : non_unital_comm_semiring C(α, β) := +coe_injective.non_unital_comm_semiring _ coe_zero coe_add coe_mul coe_nsmul instance {α : Type*} {β : Type*} [topological_space α] [topological_space β] [comm_semiring β] [topological_semiring β] : comm_semiring C(α, β) := -{ ..continuous_map.semiring, - ..continuous_map.comm_monoid, } +coe_injective.comm_semiring _ coe_zero coe_one coe_add coe_mul coe_nsmul coe_pow + +instance {α : Type*} {β : Type*} [topological_space α] [topological_space β] + [non_unital_comm_ring β] [topological_ring β] : non_unital_comm_ring C(α, β) := +coe_injective.non_unital_comm_ring _ coe_zero coe_add coe_mul coe_neg coe_sub coe_nsmul coe_zsmul instance {α : Type*} {β : Type*} [topological_space α] [topological_space β] [comm_ring β] [topological_ring β] : comm_ring C(α, β) := -{ ..continuous_map.comm_semiring, - ..continuous_map.ring, } +coe_injective.comm_ring _ coe_zero coe_one coe_add coe_mul coe_neg coe_sub coe_nsmul coe_zsmul + coe_pow /-- Composition on the left by a (continuous) homomorphism of topological semirings, as a `ring_hom`. Similar to `ring_hom.comp_left`. -/ From 76de6f75a1b091c074f870aa5d88c9f5c108164a Mon Sep 17 00:00:00 2001 From: Yakov Pechersky Date: Tue, 26 Apr 2022 18:41:43 +0000 Subject: [PATCH 281/373] feat(group_theory/subsemigroup/operations): port from submonoid (#12112) Taken from `group_theory.submonoid.operations`, trying to keep as much API as possible Co-authored-by: Jireh Loreaux Co-authored-by: Jireh Loreaux --- src/field_theory/intermediate_field.lean | 8 +- src/group_theory/submonoid/operations.lean | 10 +- src/group_theory/subsemigroup/operations.lean | 736 ++++++++++++++++++ 3 files changed, 741 insertions(+), 13 deletions(-) create mode 100644 src/group_theory/subsemigroup/operations.lean diff --git a/src/field_theory/intermediate_field.lean b/src/field_theory/intermediate_field.lean index ea88ad91f5247..cdb81f585706c 100644 --- a/src/field_theory/intermediate_field.lean +++ b/src/field_theory/intermediate_field.lean @@ -213,7 +213,7 @@ begin classical, induction finset.univ using finset.induction_on with i s hi H, { simp }, - { rw [finset.sum_insert hi, add_submonoid_class.coe_add, H, finset.sum_insert hi] } + { rw [finset.sum_insert hi, add_mem_class.coe_add, H, finset.sum_insert hi] } end @[simp, norm_cast] @@ -222,7 +222,7 @@ begin classical, induction finset.univ using finset.induction_on with i s hi H, { simp }, - { rw [finset.prod_insert hi, submonoid_class.coe_mul, H, finset.prod_insert hi] } + { rw [finset.prod_insert hi, mul_mem_class.coe_mul, H, finset.prod_insert hi] } end /-! `intermediate_field`s inherit structure from their `subalgebra` coercions. -/ @@ -299,8 +299,8 @@ lemma aeval_coe {R : Type*} [comm_ring R] [algebra R K] [algebra R L] [is_scalar_tower R K L] (x : S) (P : R[X]) : aeval (x : L) P = aeval x P := begin refine polynomial.induction_on' P (λ f g hf hg, _) (λ n r, _), - { rw [aeval_add, aeval_add, add_submonoid_class.coe_add, hf, hg] }, - { simp only [submonoid_class.coe_mul, aeval_monomial, submonoid_class.coe_pow, + { rw [aeval_add, aeval_add, add_mem_class.coe_add, hf, hg] }, + { simp only [mul_mem_class.coe_mul, aeval_monomial, submonoid_class.coe_pow, mul_eq_mul_right_iff], left, refl } end diff --git a/src/group_theory/submonoid/operations.lean b/src/group_theory/submonoid/operations.lean index 43646c13d52db..22b580214bbbb 100644 --- a/src/group_theory/submonoid/operations.lean +++ b/src/group_theory/submonoid/operations.lean @@ -6,6 +6,7 @@ Amelia Livingston, Yury Kudryashov -/ import group_theory.group_action.defs import group_theory.submonoid.basic +import group_theory.subsemigroup.operations /-! # Operations on `submonoid`s @@ -385,15 +386,10 @@ namespace submonoid_class variables {A : Type*} [set_like A M] [hA : submonoid_class A M] (S' : A) include hA -/-- A submonoid of a monoid inherits a multiplication. -/ -@[to_additive "An `add_submonoid` of an `add_monoid` inherits an addition."] -instance has_mul : has_mul S' := ⟨λ a b, ⟨a.1 * b.1, mul_mem a.2 b.2⟩⟩ - /-- A submonoid of a monoid inherits a 1. -/ @[to_additive "An `add_submonoid` of an `add_monoid` inherits a zero."] instance has_one : has_one S' := ⟨⟨_, one_mem S'⟩⟩ -@[simp, norm_cast, to_additive] lemma coe_mul (x y : S') : (↑(x * y) : M) = ↑x * ↑y := rfl @[simp, norm_cast, to_additive] lemma coe_one : ((1 : S') : M) = 1 := rfl variables {S'} @@ -401,10 +397,6 @@ variables {S'} (subtype.ext_iff.symm : (x : M) = (1 : S') ↔ x = 1) variables (S') -@[simp, to_additive] lemma mk_mul_mk (x y : M) (hx : x ∈ S') (hy : y ∈ S') : - (⟨x, hx⟩ : S') * ⟨y, hy⟩ = ⟨x * y, mul_mem hx hy⟩ := rfl - -@[to_additive] lemma mul_def (x y : S') : x * y = ⟨x * y, mul_mem x.2 y.2⟩ := rfl @[to_additive] lemma one_def : (1 : S') = ⟨1, one_mem S'⟩ := rfl omit hA diff --git a/src/group_theory/subsemigroup/operations.lean b/src/group_theory/subsemigroup/operations.lean new file mode 100644 index 0000000000000..bb6b6af81a710 --- /dev/null +++ b/src/group_theory/subsemigroup/operations.lean @@ -0,0 +1,736 @@ +/- +Copyright (c) 2022 Yakov Pechersky. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johannes Hölzl, Kenny Lau, Johan Commelin, Mario Carneiro, Kevin Buzzard, +Amelia Livingston, Yury Kudryashov, Yakov Pechersky, Jireh Loreaux +-/ +import group_theory.subsemigroup.basic + +/-! +# Operations on `subsemigroup`s + +In this file we define various operations on `subsemigroup`s and `mul_hom`s. + +## Main definitions + +### Conversion between multiplicative and additive definitions + +* `subsemigroup.to_add_subsemigroup`, `subsemigroup.to_add_subsemigroup'`, + `add_subsemigroup.to_subsemigroup`, `add_subsemigroup.to_subsemigroup'`: + convert between multiplicative and additive subsemigroups of `M`, + `multiplicative M`, and `additive M`. These are stated as `order_iso`s. + +### (Commutative) semigroup structure on a subsemigroup + +* `subsemigroup.to_semigroup`, `subsemigroup.to_comm_semigroup`: a subsemigroup inherits a + (commutative) semigroup structure. + +### Operations on subsemigroups + +* `subsemigroup.comap`: preimage of a subsemigroup under a semigroup homomorphism as a subsemigroup + of the domain; +* `subsemigroup.map`: image of a subsemigroup under a semigroup homomorphism as a subsemigroup of + the codomain; +* `subsemigroup.prod`: product of two subsemigroups `s : subsemigroup M` and `t : subsemigroup N` + as a subsemigroup of `M × N`; + +### Semigroup homomorphisms between subsemigroups + +* `subsemigroup.subtype`: embedding of a subsemigroup into the ambient semigroup. +* `subsemigroup.inclusion`: given two subsemigroups `S`, `T` such that `S ≤ T`, `S.inclusion T` is + the inclusion of `S` into `T` as a semigroup homomorphism; +* `mul_equiv.subsemigroup_congr`: converts a proof of `S = T` into a semigroup isomorphism between + `S` and `T`. +* `subsemigroup.prod_equiv`: semigroup isomorphism between `s.prod t` and `s × t`; + +### Operations on `mul_hom`s + +* `mul_hom.srange`: range of a semigroup homomorphism as a subsemigroup of the codomain; +* `mul_hom.srestrict`: restrict a semigroup homomorphism to a subsemigroup; +* `mul_hom.cod_srestrict`: restrict the codomain of a semigroup homomorphism to a subsemigroup; +* `mul_hom.srange_restrict`: restrict a semigroup homomorphism to its range; + +### Implementation notes + +This file follows closely `group_theory/submonoid/operations.lean`, omitting only that which is +necessary. + +## Tags + +subsemigroup, range, product, map, comap +-/ + +variables {M N P : Type*} + +/-! +### Conversion to/from `additive`/`multiplicative` +-/ + +section + +variables [has_mul M] + +/-- Subsemigroups of semigroup `M` are isomorphic to additive subsemigroups of `additive M`. -/ +@[simps] +def subsemigroup.to_add_subsemigroup : subsemigroup M ≃o add_subsemigroup (additive M) := +{ to_fun := λ S, + { carrier := additive.to_mul ⁻¹' S, + add_mem' := S.mul_mem' }, + inv_fun := λ S, + { carrier := additive.of_mul ⁻¹' S, + mul_mem' := S.add_mem' }, + left_inv := λ x, by cases x; refl, + right_inv := λ x, by cases x; refl, + map_rel_iff' := λ a b, iff.rfl, } + +/-- Additive subsemigroups of an additive semigroup `additive M` are isomorphic to subsemigroups +of `M`. -/ +abbreviation add_subsemigroup.to_subsemigroup' : add_subsemigroup (additive M) ≃o subsemigroup M := +subsemigroup.to_add_subsemigroup.symm + +lemma subsemigroup.to_add_subsemigroup_closure (S : set M) : + (subsemigroup.closure S).to_add_subsemigroup = add_subsemigroup.closure (additive.to_mul ⁻¹' S) := +le_antisymm + (subsemigroup.to_add_subsemigroup.le_symm_apply.1 $ + subsemigroup.closure_le.2 add_subsemigroup.subset_closure) + (add_subsemigroup.closure_le.2 subsemigroup.subset_closure) + +lemma add_subsemigroup.to_subsemigroup'_closure (S : set (additive M)) : + (add_subsemigroup.closure S).to_subsemigroup' = + subsemigroup.closure (multiplicative.of_add ⁻¹' S) := +le_antisymm + (add_subsemigroup.to_subsemigroup'.le_symm_apply.1 $ + add_subsemigroup.closure_le.2 subsemigroup.subset_closure) + (subsemigroup.closure_le.2 add_subsemigroup.subset_closure) + +end + +section + +variables {A : Type*} [has_add A] + +/-- Additive subsemigroups of an additive semigroup `A` are isomorphic to +multiplicative subsemigroups of `multiplicative A`. -/ +@[simps] +def add_subsemigroup.to_subsemigroup : add_subsemigroup A ≃o subsemigroup (multiplicative A) := +{ to_fun := λ S, + { carrier := multiplicative.to_add ⁻¹' S, + mul_mem' := S.add_mem' }, + inv_fun := λ S, + { carrier := multiplicative.of_add ⁻¹' S, + add_mem' := S.mul_mem' }, + left_inv := λ x, by cases x; refl, + right_inv := λ x, by cases x; refl, + map_rel_iff' := λ a b, iff.rfl, } + +/-- Subsemigroups of a semigroup `multiplicative A` are isomorphic to additive subsemigroups +of `A`. -/ +abbreviation subsemigroup.to_add_subsemigroup' : + subsemigroup (multiplicative A) ≃o add_subsemigroup A := +add_subsemigroup.to_subsemigroup.symm + +lemma add_subsemigroup.to_subsemigroup_closure (S : set A) : + (add_subsemigroup.closure S).to_subsemigroup = + subsemigroup.closure (multiplicative.to_add ⁻¹' S) := +le_antisymm + (add_subsemigroup.to_subsemigroup.to_galois_connection.l_le $ + add_subsemigroup.closure_le.2 subsemigroup.subset_closure) + (subsemigroup.closure_le.2 add_subsemigroup.subset_closure) + +lemma subsemigroup.to_add_subsemigroup'_closure (S : set (multiplicative A)) : + (subsemigroup.closure S).to_add_subsemigroup' = + add_subsemigroup.closure (additive.of_mul ⁻¹' S) := +le_antisymm + (subsemigroup.to_add_subsemigroup'.to_galois_connection.l_le $ + subsemigroup.closure_le.2 add_subsemigroup.subset_closure) + (add_subsemigroup.closure_le.2 subsemigroup.subset_closure) + +end + +namespace subsemigroup + +open set + +/-! +### `comap` and `map` +-/ + +variables [has_mul M] [has_mul N] [has_mul P] (S : subsemigroup M) + +/-- The preimage of a subsemigroup along a semigroup homomorphism is a subsemigroup. -/ +@[to_additive "The preimage of an `add_subsemigroup` along an `add_semigroup` homomorphism is an +`add_subsemigroup`."] +def comap (f : M →ₙ* N) (S : subsemigroup N) : subsemigroup M := +{ carrier := (f ⁻¹' S), + mul_mem' := λ a b ha hb, + show f (a * b) ∈ S, by rw map_mul; exact mul_mem ha hb } + +@[simp, to_additive] +lemma coe_comap (S : subsemigroup N) (f : M →ₙ* N) : (S.comap f : set M) = f ⁻¹' S := rfl + +@[simp, to_additive] +lemma mem_comap {S : subsemigroup N} {f : M →ₙ* N} {x : M} : x ∈ S.comap f ↔ f x ∈ S := iff.rfl + +@[to_additive] +lemma comap_comap (S : subsemigroup P) (g : N →ₙ* P) (f : M →ₙ* N) : + (S.comap g).comap f = S.comap (g.comp f) := +rfl + +@[simp, to_additive] +lemma comap_id (S : subsemigroup P) : S.comap (mul_hom.id _) = S := +ext (by simp) + +/-- The image of a subsemigroup along a semigroup homomorphism is a subsemigroup. -/ +@[to_additive "The image of an `add_subsemigroup` along an `add_semigroup` homomorphism is +an `add_subsemigroup`."] +def map (f : M →ₙ* N) (S : subsemigroup M) : subsemigroup N := +{ carrier := (f '' S), + mul_mem' := begin rintros _ _ ⟨x, hx, rfl⟩ ⟨y, hy, rfl⟩, + exact ⟨x * y, @mul_mem (subsemigroup M) M _ _ _ _ _ _ hx hy, by rw map_mul; refl⟩ end } + +@[simp, to_additive] +lemma coe_map (f : M →ₙ* N) (S : subsemigroup M) : + (S.map f : set N) = f '' S := rfl + +@[simp, to_additive] +lemma mem_map {f : M →ₙ* N} {S : subsemigroup M} {y : N} : + y ∈ S.map f ↔ ∃ x ∈ S, f x = y := +mem_image_iff_bex + +@[to_additive] +lemma mem_map_of_mem (f : M →ₙ* N) {S : subsemigroup M} {x : M} (hx : x ∈ S) : f x ∈ S.map f := +mem_image_of_mem f hx + +@[to_additive] +lemma apply_coe_mem_map (f : M →ₙ* N) (S : subsemigroup M) (x : S) : f x ∈ S.map f := +mem_map_of_mem f x.prop + +@[to_additive] +lemma map_map (g : N →ₙ* P) (f : M →ₙ* N) : (S.map f).map g = S.map (g.comp f) := +set_like.coe_injective $ image_image _ _ _ + +@[to_additive] +lemma mem_map_iff_mem {f : M →ₙ* N} (hf : function.injective f) {S : subsemigroup M} {x : M} : + f x ∈ S.map f ↔ x ∈ S := +hf.mem_set_image + +@[to_additive] +lemma map_le_iff_le_comap {f : M →ₙ* N} {S : subsemigroup M} {T : subsemigroup N} : + S.map f ≤ T ↔ S ≤ T.comap f := +image_subset_iff + +@[to_additive] +lemma gc_map_comap (f : M →ₙ* N) : galois_connection (map f) (comap f) := +λ S T, map_le_iff_le_comap + +@[to_additive] +lemma map_le_of_le_comap {T : subsemigroup N} {f : M →ₙ* N} : S ≤ T.comap f → S.map f ≤ T := +(gc_map_comap f).l_le + +@[to_additive] +lemma le_comap_of_map_le {T : subsemigroup N} {f : M →ₙ* N} : S.map f ≤ T → S ≤ T.comap f := +(gc_map_comap f).le_u + +@[to_additive] +lemma le_comap_map {f : M →ₙ* N} : S ≤ (S.map f).comap f := +(gc_map_comap f).le_u_l _ + +@[to_additive] +lemma map_comap_le {S : subsemigroup N} {f : M →ₙ* N} : (S.comap f).map f ≤ S := +(gc_map_comap f).l_u_le _ + +@[to_additive] +lemma monotone_map {f : M →ₙ* N} : monotone (map f) := +(gc_map_comap f).monotone_l + +@[to_additive] +lemma monotone_comap {f : M →ₙ* N} : monotone (comap f) := +(gc_map_comap f).monotone_u + +@[simp, to_additive] +lemma map_comap_map {f : M →ₙ* N} : ((S.map f).comap f).map f = S.map f := +(gc_map_comap f).l_u_l_eq_l _ + +@[simp, to_additive] +lemma comap_map_comap {S : subsemigroup N} {f : M →ₙ* N} : + ((S.comap f).map f).comap f = S.comap f := +(gc_map_comap f).u_l_u_eq_u _ + +@[to_additive] +lemma map_sup (S T : subsemigroup M) (f : M →ₙ* N) : (S ⊔ T).map f = S.map f ⊔ T.map f := +(gc_map_comap f).l_sup + +@[to_additive] +lemma map_supr {ι : Sort*} (f : M →ₙ* N) (s : ι → subsemigroup M) : + (supr s).map f = ⨆ i, (s i).map f := +(gc_map_comap f).l_supr + +@[to_additive] +lemma comap_inf (S T : subsemigroup N) (f : M →ₙ* N) : (S ⊓ T).comap f = S.comap f ⊓ T.comap f := +(gc_map_comap f).u_inf + +@[to_additive] +lemma comap_infi {ι : Sort*} (f : M →ₙ* N) (s : ι → subsemigroup N) : + (infi s).comap f = ⨅ i, (s i).comap f := +(gc_map_comap f).u_infi + +@[simp, to_additive] lemma map_bot (f : M →ₙ* N) : (⊥ : subsemigroup M).map f = ⊥ := +(gc_map_comap f).l_bot + +@[simp, to_additive] lemma comap_top (f : M →ₙ* N) : (⊤ : subsemigroup N).comap f = ⊤ := +(gc_map_comap f).u_top + +@[simp, to_additive] lemma map_id (S : subsemigroup M) : S.map (mul_hom.id M) = S := +ext (λ x, ⟨λ ⟨_, h, rfl⟩, h, λ h, ⟨_, h, rfl⟩⟩) + +section galois_coinsertion + +variables {ι : Type*} {f : M →ₙ* N} (hf : function.injective f) + +include hf + +/-- `map f` and `comap f` form a `galois_coinsertion` when `f` is injective. -/ +@[to_additive /-" `map f` and `comap f` form a `galois_coinsertion` when `f` is injective. "-/] +def gci_map_comap : galois_coinsertion (map f) (comap f) := +(gc_map_comap f).to_galois_coinsertion + (λ S x, by simp [mem_comap, mem_map, hf.eq_iff]) + +@[to_additive] +lemma comap_map_eq_of_injective (S : subsemigroup M) : (S.map f).comap f = S := +(gci_map_comap hf).u_l_eq _ + +@[to_additive] +lemma comap_surjective_of_injective : function.surjective (comap f) := +(gci_map_comap hf).u_surjective + +@[to_additive] +lemma map_injective_of_injective : function.injective (map f) := +(gci_map_comap hf).l_injective + +@[to_additive] +lemma comap_inf_map_of_injective (S T : subsemigroup M) : (S.map f ⊓ T.map f).comap f = S ⊓ T := +(gci_map_comap hf).u_inf_l _ _ + +@[to_additive] +lemma comap_infi_map_of_injective (S : ι → subsemigroup M) : (⨅ i, (S i).map f).comap f = infi S := +(gci_map_comap hf).u_infi_l _ + +@[to_additive] +lemma comap_sup_map_of_injective (S T : subsemigroup M) : (S.map f ⊔ T.map f).comap f = S ⊔ T := +(gci_map_comap hf).u_sup_l _ _ + +@[to_additive] +lemma comap_supr_map_of_injective (S : ι → subsemigroup M) : (⨆ i, (S i).map f).comap f = supr S := +(gci_map_comap hf).u_supr_l _ + +@[to_additive] +lemma map_le_map_iff_of_injective {S T : subsemigroup M} : S.map f ≤ T.map f ↔ S ≤ T := +(gci_map_comap hf).l_le_l_iff + +@[to_additive] +lemma map_strict_mono_of_injective : strict_mono (map f) := +(gci_map_comap hf).strict_mono_l + +end galois_coinsertion + +section galois_insertion + +variables {ι : Type*} {f : M →ₙ* N} (hf : function.surjective f) + +include hf + +/-- `map f` and `comap f` form a `galois_insertion` when `f` is surjective. -/ +@[to_additive /-" `map f` and `comap f` form a `galois_insertion` when `f` is surjective. "-/] +def gi_map_comap : galois_insertion (map f) (comap f) := +(gc_map_comap f).to_galois_insertion + (λ S x h, let ⟨y, hy⟩ := hf x in mem_map.2 ⟨y, by simp [hy, h]⟩) + +@[to_additive] +lemma map_comap_eq_of_surjective (S : subsemigroup N) : (S.comap f).map f = S := +(gi_map_comap hf).l_u_eq _ + +@[to_additive] +lemma map_surjective_of_surjective : function.surjective (map f) := +(gi_map_comap hf).l_surjective + +@[to_additive] +lemma comap_injective_of_surjective : function.injective (comap f) := +(gi_map_comap hf).u_injective + +@[to_additive] +lemma map_inf_comap_of_surjective (S T : subsemigroup N) : (S.comap f ⊓ T.comap f).map f = S ⊓ T := +(gi_map_comap hf).l_inf_u _ _ + +@[to_additive] +lemma map_infi_comap_of_surjective (S : ι → subsemigroup N) : (⨅ i, (S i).comap f).map f = infi S := +(gi_map_comap hf).l_infi_u _ + +@[to_additive] +lemma map_sup_comap_of_surjective (S T : subsemigroup N) : (S.comap f ⊔ T.comap f).map f = S ⊔ T := +(gi_map_comap hf).l_sup_u _ _ + +@[to_additive] +lemma map_supr_comap_of_surjective (S : ι → subsemigroup N) : (⨆ i, (S i).comap f).map f = supr S := +(gi_map_comap hf).l_supr_u _ + +@[to_additive] +lemma comap_le_comap_iff_of_surjective {S T : subsemigroup N} : S.comap f ≤ T.comap f ↔ S ≤ T := +(gi_map_comap hf).u_le_u_iff + +@[to_additive] +lemma comap_strict_mono_of_surjective : strict_mono (comap f) := +(gi_map_comap hf).strict_mono_u + +end galois_insertion + +end subsemigroup + +namespace mul_mem_class + +variables {A : Type*} [has_mul M] [set_like A M] [hA : mul_mem_class A M] (S' : A) +include hA + +/-- A submagma of a magma inherits a multiplication. -/ +@[to_additive "An additive submagma of an additive magma inherits an addition.", +priority 900] -- lower priority so other instances are found first +instance has_mul : has_mul S' := ⟨λ a b, ⟨a.1 * b.1, mul_mem a.2 b.2⟩⟩ + +@[simp, norm_cast, to_additive, priority 900] +-- lower priority so later simp lemmas are used first; to appease simp_nf +lemma coe_mul (x y : S') : (↑(x * y) : M) = ↑x * ↑y := rfl + +@[simp, to_additive, priority 900] +-- lower priority so later simp lemmas are used first; to appease simp_nf +lemma mk_mul_mk (x y : M) (hx : x ∈ S') (hy : y ∈ S') : + (⟨x, hx⟩ : S') * ⟨y, hy⟩ = ⟨x * y, mul_mem hx hy⟩ := rfl + +@[to_additive] lemma mul_def (x y : S') : x * y = ⟨x * y, mul_mem x.2 y.2⟩ := rfl + +omit hA + +/-- A subsemigroup of a semigroup inherits a semigroup structure. -/ +@[to_additive "An `add_subsemigroup` of an `add_semigroup` inherits an `add_semigroup` structure."] +instance to_semigroup {M : Type*} [semigroup M] {A : Type*} [set_like A M] [mul_mem_class A M] + (S : A) : semigroup S := +subtype.coe_injective.semigroup coe (λ _ _, rfl) + +/-- A subsemigroup of a `comm_semigroup` is a `comm_semigroup`. -/ +@[to_additive "An `add_subsemigroup` of an `add_comm_semigroup` is an `add_comm_semigroup`."] +instance to_comm_semigroup {M} [comm_semigroup M] {A : Type*} [set_like A M] [mul_mem_class A M] + (S : A) : comm_semigroup S := +subtype.coe_injective.comm_semigroup coe (λ _ _, rfl) + +include hA + +/-- The natural semigroup hom from a subsemigroup of semigroup `M` to `M`. -/ +@[to_additive "The natural semigroup hom from an `add_subsemigroup` of `add_semigroup` `M` to `M`."] +def subtype : S' →ₙ* M := ⟨coe, λ _ _, rfl⟩ + +@[simp, to_additive] theorem coe_subtype : (mul_mem_class.subtype S' : S' → M) = coe := rfl + +end mul_mem_class + +namespace subsemigroup + +variables [has_mul M] [has_mul N] [has_mul P] (S : subsemigroup M) + +/-- The top subsemigroup is isomorphic to the semigroup. -/ +@[to_additive "The top additive subsemigroup is isomorphic to the additive semigroup.", simps] +def top_equiv : (⊤ : subsemigroup M) ≃* M := +{ to_fun := λ x, x, + inv_fun := λ x, ⟨x, mem_top x⟩, + left_inv := λ x, x.eta _, + right_inv := λ _, rfl, + map_mul' := λ _ _, rfl } + +@[simp, to_additive] lemma top_equiv_to_mul_hom : + (top_equiv : _ ≃* M).to_mul_hom = mul_mem_class.subtype (⊤ : subsemigroup M) := +rfl + +/-- A subsemigroup is isomorphic to its image under an injective function -/ +@[to_additive "An additive subsemigroup is isomorphic to its image under an injective function"] +noncomputable def equiv_map_of_injective + (f : M →ₙ* N) (hf : function.injective f) : S ≃* S.map f := +{ map_mul' := λ _ _, subtype.ext (map_mul f _ _), ..equiv.set.image f S hf } + +@[simp, to_additive] lemma coe_equiv_map_of_injective_apply + (f : M →ₙ* N) (hf : function.injective f) (x : S) : + (equiv_map_of_injective S f hf x : N) = f x := rfl + +@[simp, to_additive] +lemma closure_closure_coe_preimage {s : set M} : closure ((coe : closure s → M) ⁻¹' s) = ⊤ := +eq_top_iff.2 $ λ x, subtype.rec_on x $ λ x hx _, begin + refine closure_induction' _ (λ g hg, _) (λ g₁ g₂ hg₁ hg₂, _) hx, + { exact subset_closure hg }, + { exact subsemigroup.mul_mem _ }, +end + +/-- Given `subsemigroup`s `s`, `t` of semigroups `M`, `N` respectively, `s × t` as a subsemigroup +of `M × N`. -/ +@[to_additive prod "Given `add_subsemigroup`s `s`, `t` of `add_semigroup`s `A`, `B` respectively, +`s × t` as an `add_subsemigroup` of `A × B`."] +def prod (s : subsemigroup M) (t : subsemigroup N) : subsemigroup (M × N) := +{ carrier := (s : set M) ×ˢ (t : set N), + mul_mem' := λ p q hp hq, ⟨s.mul_mem hp.1 hq.1, t.mul_mem hp.2 hq.2⟩ } + +@[to_additive coe_prod] +lemma coe_prod (s : subsemigroup M) (t : subsemigroup N) : + (s.prod t : set (M × N)) = (s : set M) ×ˢ (t : set N) := +rfl + +@[to_additive mem_prod] +lemma mem_prod {s : subsemigroup M} {t : subsemigroup N} {p : M × N} : + p ∈ s.prod t ↔ p.1 ∈ s ∧ p.2 ∈ t := iff.rfl + +@[to_additive prod_mono] +lemma prod_mono {s₁ s₂ : subsemigroup M} {t₁ t₂ : subsemigroup N} (hs : s₁ ≤ s₂) (ht : t₁ ≤ t₂) : + s₁.prod t₁ ≤ s₂.prod t₂ := +set.prod_mono hs ht + +@[to_additive prod_top] +lemma prod_top (s : subsemigroup M) : + s.prod (⊤ : subsemigroup N) = s.comap (mul_hom.fst M N) := +ext $ λ x, by simp [mem_prod, mul_hom.coe_fst] + +@[to_additive top_prod] +lemma top_prod (s : subsemigroup N) : + (⊤ : subsemigroup M).prod s = s.comap (mul_hom.snd M N) := +ext $ λ x, by simp [mem_prod, mul_hom.coe_snd] + +@[simp, to_additive top_prod_top] +lemma top_prod_top : (⊤ : subsemigroup M).prod (⊤ : subsemigroup N) = ⊤ := +(top_prod _).trans $ comap_top _ + +@[to_additive] lemma bot_prod_bot : (⊥ : subsemigroup M).prod (⊥ : subsemigroup N) = ⊥ := +set_like.coe_injective $ by simp [coe_prod, prod.one_eq_mk] + +/-- The product of subsemigroups is isomorphic to their product as semigroups. -/ +@[to_additive prod_equiv "The product of additive subsemigroups is isomorphic to their product +as additive semigroups"] +def prod_equiv (s : subsemigroup M) (t : subsemigroup N) : s.prod t ≃* s × t := +{ map_mul' := λ x y, rfl, .. equiv.set.prod ↑s ↑t } + +open mul_hom + +@[to_additive] +lemma mem_map_equiv {f : M ≃* N} {K : subsemigroup M} {x : N} : + x ∈ K.map f.to_mul_hom ↔ f.symm x ∈ K := +@set.mem_image_equiv _ _ ↑K f.to_equiv x + +@[to_additive] +lemma map_equiv_eq_comap_symm (f : M ≃* N) (K : subsemigroup M) : + K.map f.to_mul_hom = K.comap f.symm.to_mul_hom := +set_like.coe_injective (f.to_equiv.image_eq_preimage K) + +@[to_additive] +lemma comap_equiv_eq_map_symm (f : N ≃* M) (K : subsemigroup M) : + K.comap f.to_mul_hom = K.map f.symm.to_mul_hom := +(map_equiv_eq_comap_symm f.symm K).symm + +@[simp, to_additive] +lemma map_equiv_top (f : M ≃* N) : (⊤ : subsemigroup M).map f.to_mul_hom = ⊤ := +set_like.coe_injective $ set.image_univ.trans f.surjective.range_eq + +@[to_additive le_prod_iff] +lemma le_prod_iff {s : subsemigroup M} {t : subsemigroup N} {u : subsemigroup (M × N)} : + u ≤ s.prod t ↔ u.map (fst M N) ≤ s ∧ u.map (snd M N) ≤ t := +begin + split, + { intros h, + split, + { rintros x ⟨⟨y1,y2⟩, ⟨hy1,rfl⟩⟩, exact (h hy1).1 }, + { rintros x ⟨⟨y1,y2⟩, ⟨hy1,rfl⟩⟩, exact (h hy1).2 }, }, + { rintros ⟨hH, hK⟩ ⟨x1, x2⟩ h, exact ⟨hH ⟨_ , h, rfl⟩, hK ⟨ _, h, rfl⟩⟩, } +end + +end subsemigroup + +namespace mul_hom + +open subsemigroup + +variables [has_mul M] [has_mul N] [has_mul P] (S : subsemigroup M) + +/-- The range of a semigroup homomorphism is a subsemigroup. See Note [range copy pattern]. -/ +@[to_additive "The range of an `add_hom` is an `add_subsemigroup`."] +def srange (f : M →ₙ* N) : subsemigroup N := +((⊤ : subsemigroup M).map f).copy (set.range f) set.image_univ.symm + +@[simp, to_additive] +lemma coe_srange (f : M →ₙ* N) : + (f.srange : set N) = set.range f := +rfl + +@[simp, to_additive] lemma mem_srange {f : M →ₙ* N} {y : N} : + y ∈ f.srange ↔ ∃ x, f x = y := +iff.rfl + +@[to_additive] lemma srange_eq_map (f : M →ₙ* N) : f.srange = (⊤ : subsemigroup M).map f := +copy_eq _ + +@[to_additive] +lemma map_srange (g : N →ₙ* P) (f : M →ₙ* N) : f.srange.map g = (g.comp f).srange := +by simpa only [srange_eq_map] using (⊤ : subsemigroup M).map_map g f + +@[to_additive] +lemma srange_top_iff_surjective {N} [has_mul N] {f : M →ₙ* N} : + f.srange = (⊤ : subsemigroup N) ↔ function.surjective f := +set_like.ext'_iff.trans $ iff.trans (by rw [coe_srange, coe_top]) set.range_iff_surjective + +/-- The range of a surjective semigroup hom is the whole of the codomain. -/ +@[to_additive "The range of a surjective `add_semigroup` hom is the whole of the codomain."] +lemma srange_top_of_surjective {N} [has_mul N] (f : M →ₙ* N) (hf : function.surjective f) : + f.srange = (⊤ : subsemigroup N) := +srange_top_iff_surjective.2 hf + +@[to_additive] +lemma mclosure_preimage_le (f : M →ₙ* N) (s : set N) : + closure (f ⁻¹' s) ≤ (closure s).comap f := +closure_le.2 $ λ x hx, set_like.mem_coe.2 $ mem_comap.2 $ subset_closure hx + +/-- The image under a semigroup hom of the subsemigroup generated by a set equals the subsemigroup +generated by the image of the set. -/ +@[to_additive "The image under an `add_semigroup` hom of the `add_subsemigroup` generated by a set +equals the `add_subsemigroup` generated by the image of the set."] +lemma map_mclosure (f : M →ₙ* N) (s : set M) : + (closure s).map f = closure (f '' s) := +le_antisymm + (map_le_iff_le_comap.2 $ le_trans (closure_mono $ set.subset_preimage_image _ _) + (mclosure_preimage_le _ _)) + (closure_le.2 $ set.image_subset _ subset_closure) + +/-- Restriction of a semigroup hom to a subsemigroup of the domain. -/ +@[to_additive "Restriction of an add_semigroup hom to an `add_subsemigroup` of the domain."] +def srestrict {N : Type*} [has_mul N] (f : M →ₙ* N) (S : subsemigroup M) : S →ₙ* N := +f.comp (mul_mem_class.subtype S) + +@[simp, to_additive] +lemma srestrict_apply {N : Type*} [has_mul N] (f : M →ₙ* N) (x : S) : f.srestrict S x = f x := +rfl + +/-- Restriction of a semigroup hom to a subsemigroup of the codomain. -/ +@[to_additive "Restriction of an `add_semigroup` hom to an `add_subsemigroup` of the +codomain.", simps] +def cod_srestrict (f : M →ₙ* N) (S : subsemigroup N) (h : ∀ x, f x ∈ S) : M →ₙ* S := +{ to_fun := λ n, ⟨f n, h n⟩, + map_mul' := λ x y, subtype.eq (map_mul f x y) } + +/-- Restriction of a semigroup hom to its range interpreted as a subsemigroup. -/ +@[to_additive "Restriction of an `add_semigroup` hom to its range interpreted as a subsemigroup."] +def srange_restrict {N} [has_mul N] (f : M →ₙ* N) : M →ₙ* f.srange := +f.cod_srestrict f.srange $ λ x, ⟨x, rfl⟩ + +@[simp, to_additive] +lemma coe_srange_restrict {N} [has_mul N] (f : M →ₙ* N) (x : M) : + (f.srange_restrict x : N) = f x := +rfl + +@[to_additive] +lemma srange_restrict_surjective (f : M →ₙ* N) : function.surjective f.srange_restrict := +λ ⟨_, ⟨x, rfl⟩⟩, ⟨x, rfl⟩ + +@[to_additive] +lemma prod_map_comap_prod' {M' : Type*} {N' : Type*} [has_mul M'] [has_mul N'] + (f : M →ₙ* N) (g : M' →ₙ* N') (S : subsemigroup N) (S' : subsemigroup N') : + (S.prod S').comap (prod_map f g) = (S.comap f).prod (S'.comap g) := +set_like.coe_injective $ set.preimage_prod_map_prod f g _ _ + +/-- The `mul_hom` from the preimage of a subsemigroup to itself. -/ +@[to_additive "the `add_hom` from the preimage of an additive subsemigroup to itself.", simps] +def subsemigroup_comap (f : M →ₙ* N) (N' : subsemigroup N) : + N'.comap f →ₙ* N' := +{ to_fun := λ x, ⟨f x, x.prop⟩, + map_mul' := λ x y, subtype.eq (@map_mul M N _ _ _ _ f x y) } + +/-- The `mul_hom` from a subsemigroup to its image. +See `mul_equiv.subsemigroup_map` for a variant for `mul_equiv`s. -/ +@[to_additive "the `add_hom` from an additive subsemigroup to its image. See +`add_equiv.add_subsemigroup_map` for a variant for `add_equiv`s.", simps] +def subsemigroup_map (f : M →ₙ* N) (M' : subsemigroup M) : + M' →ₙ* M'.map f := +{ to_fun := λ x, ⟨f x, ⟨x, x.prop, rfl⟩⟩, + map_mul' := λ x y, subtype.eq $ @map_mul M N _ _ _ _ f x y } + +@[to_additive] +lemma subsemigroup_map_surjective (f : M →ₙ* N) (M' : subsemigroup M) : + function.surjective (f.subsemigroup_map M') := +by { rintro ⟨_, x, hx, rfl⟩, exact ⟨⟨x, hx⟩, rfl⟩ } + +end mul_hom + +namespace subsemigroup +open mul_hom + +variables [has_mul M] [has_mul N] [has_mul P] (S : subsemigroup M) + +@[simp, to_additive] +lemma srange_fst [nonempty N] : (fst M N).srange = ⊤ := +(fst M N).srange_top_of_surjective $ prod.fst_surjective + +@[simp, to_additive] +lemma srange_snd [nonempty M] : (snd M N).srange = ⊤ := +(snd M N).srange_top_of_surjective $ prod.snd_surjective + +@[to_additive] +lemma prod_eq_top_iff [nonempty M] [nonempty N] {s : subsemigroup M} {t : subsemigroup N} : + s.prod t = ⊤ ↔ s = ⊤ ∧ t = ⊤ := +by simp only [eq_top_iff, le_prod_iff, ← (gc_map_comap _).le_iff_le, ← srange_eq_map, + srange_fst, srange_snd] + +/-- The semigroup hom associated to an inclusion of subsemigroups. -/ +@[to_additive "The `add_semigroup` hom associated to an inclusion of subsemigroups."] +def inclusion {S T : subsemigroup M} (h : S ≤ T) : S →ₙ* T := +(mul_mem_class.subtype S).cod_srestrict _ (λ x, h x.2) + +@[simp, to_additive] +lemma range_subtype (s : subsemigroup M) : (mul_mem_class.subtype s).srange = s := +set_like.coe_injective $ (coe_srange _).trans $ subtype.range_coe + +@[to_additive] lemma eq_top_iff' : S = ⊤ ↔ ∀ x : M, x ∈ S := +eq_top_iff.trans ⟨λ h m, h $ mem_top m, λ h m _, h m⟩ + +end subsemigroup + +namespace mul_equiv + +variables [has_mul M] [has_mul N] {S T : subsemigroup M} + +/-- Makes the identity isomorphism from a proof that two subsemigroups of a multiplicative + semigroup are equal. -/ +@[to_additive "Makes the identity additive isomorphism from a proof two +subsemigroups of an additive semigroup are equal."] +def subsemigroup_congr (h : S = T) : S ≃* T := +{ map_mul' := λ _ _, rfl, ..equiv.set_congr $ congr_arg _ h } + +-- this name is primed so that the version to `f.range` instead of `f.srange` can be unprimed. +/-- A semigroup homomorphism `f : M →ₙ* N` with a left-inverse `g : N → M` defines a multiplicative +equivalence between `M` and `f.srange`. + +This is a bidirectional version of `mul_hom.srange_restrict`. -/ +@[to_additive /-" +An additive semigroup homomorphism `f : M →+ N` with a left-inverse `g : N → M` defines an additive +equivalence between `M` and `f.srange`. + +This is a bidirectional version of `add_hom.srange_restrict`. "-/, simps {simp_rhs := tt}] +def of_left_inverse (f : M →ₙ* N) {g : N → M} (h : function.left_inverse g f) : M ≃* f.srange := +{ to_fun := f.srange_restrict, + inv_fun := g ∘ (mul_mem_class.subtype f.srange), + left_inv := h, + right_inv := λ x, subtype.ext $ + let ⟨x', hx'⟩ := mul_hom.mem_srange.mp x.prop in + show f (g x) = x, by rw [←hx', h x'], + .. f.srange_restrict } + +/-- A `mul_equiv` `φ` between two semigroups `M` and `N` induces a `mul_equiv` between +a subsemigroup `S ≤ M` and the subsemigroup `φ(S) ≤ N`. +See `mul_hom.subsemigroup_map` for a variant for `mul_hom`s. -/ +@[to_additive "An `add_equiv` `φ` between two additive semigroups `M` and `N` induces an `add_equiv` +between a subsemigroup `S ≤ M` and the subsemigroup `φ(S) ≤ N`. See `add_hom.add_subsemigroup_map` +for a variant for `add_hom`s.", simps] +def subsemigroup_map (e : M ≃* N) (S : subsemigroup M) : S ≃* S.map e.to_mul_hom := +{ to_fun := λ x, ⟨e x, _⟩, + inv_fun := λ x, ⟨e.symm x, _⟩, -- we restate this for `simps` to avoid `⇑e.symm.to_equiv x` + ..e.to_mul_hom.subsemigroup_map S, + ..e.to_equiv.image S } + +end mul_equiv From de79a763b68ce417f0fb0d2e70ae728ebc386be1 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Tue, 26 Apr 2022 18:41:44 +0000 Subject: [PATCH 282/373] chore(topology/continuous_function/zero_at_infty): add `is_central_scalar` instance (#13710) --- src/topology/continuous_function/zero_at_infty.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/topology/continuous_function/zero_at_infty.lean b/src/topology/continuous_function/zero_at_infty.lean index 38d780ee2f4b3..0cddc40ff5813 100644 --- a/src/topology/continuous_function/zero_at_infty.lean +++ b/src/topology/continuous_function/zero_at_infty.lean @@ -211,6 +211,10 @@ instance [has_zero β] {R : Type*} [has_zero R] [smul_with_zero R β] lemma smul_apply [has_zero β] {R : Type*} [has_zero R] [smul_with_zero R β] [has_continuous_const_smul R β] (r : R) (f : C₀(α, β)) (x : α) : (r • f) x = r • f x := rfl +instance [has_zero β] {R : Type*} [has_zero R] [smul_with_zero R β] [smul_with_zero Rᵐᵒᵖ β] + [has_continuous_const_smul R β] [is_central_scalar R β] : is_central_scalar R C₀(α, β) := +⟨λ r f, ext $ λ x, op_smul_eq_smul _ _⟩ + instance [has_zero β] {R : Type*} [has_zero R] [smul_with_zero R β] [has_continuous_const_smul R β] : smul_with_zero R C₀(α, β) := function.injective.smul_with_zero ⟨_, coe_zero⟩ fun_like.coe_injective coe_smul From b00a7f8a2209a6c74a8401c87d3aad97adca508a Mon Sep 17 00:00:00 2001 From: Bolton Bailey Date: Tue, 26 Apr 2022 20:19:00 +0000 Subject: [PATCH 283/373] refactor(number_theory/padics/padic_norm): split file (#13576) This PR splits the initial part of the `padic_norm.lean` file that defines p-adic valuations into a new file called `padic_val.lean`. This split makes sense to me since it seems most files importing this don't actually use the norm, so those files can build more in parallel. It also seems like a good organizational change: This way people can look at the files in this directory and see immediately where the valuation is defined, and people looking for the definition of `padic_norm` in `padic_norm.lean` don't have to scroll. --- src/algebra/gcd_monoid/nat.lean | 2 +- src/group_theory/exponent.lean | 2 +- src/number_theory/padics/padic_norm.lean | 571 +---------------- src/number_theory/padics/padic_val.lean | 601 ++++++++++++++++++ .../polynomial/cyclotomic/eval.lean | 2 +- 5 files changed, 606 insertions(+), 572 deletions(-) create mode 100644 src/number_theory/padics/padic_val.lean diff --git a/src/algebra/gcd_monoid/nat.lean b/src/algebra/gcd_monoid/nat.lean index a76b075f41962..7517a52cfa614 100644 --- a/src/algebra/gcd_monoid/nat.lean +++ b/src/algebra/gcd_monoid/nat.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Rodriguez -/ import algebra.gcd_monoid.finset -import number_theory.padics.padic_norm +import number_theory.padics.padic_val /-! # Basic results about setwise gcds on ℕ diff --git a/src/group_theory/exponent.lean b/src/group_theory/exponent.lean index 55a442fd94475..7dbc8923e5e68 100644 --- a/src/group_theory/exponent.lean +++ b/src/group_theory/exponent.lean @@ -7,7 +7,7 @@ import group_theory.order_of_element import algebra.punit_instances import algebra.gcd_monoid.finset import tactic.by_contra -import number_theory.padics.padic_norm +import number_theory.padics.padic_val /-! # Exponent of a group diff --git a/src/number_theory/padics/padic_norm.lean b/src/number_theory/padics/padic_norm.lean index 872f7a03a1734..a405927ecfe66 100644 --- a/src/number_theory/padics/padic_norm.lean +++ b/src/number_theory/padics/padic_norm.lean @@ -3,18 +3,12 @@ Copyright (c) 2018 Robert Y. Lewis. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Robert Y. Lewis -/ -import algebra.order.absolute_value -import algebra.field_power -import ring_theory.int.basic -import tactic.basic -import tactic.ring_exp -import number_theory.divisors -import data.nat.factorization +import number_theory.padics.padic_val /-! # p-adic norm -This file defines the p-adic valuation and the p-adic norm on ℚ. +This file defines the p-adic norm on ℚ. The p-adic valuation on ℚ is the difference of the multiplicities of `p` in the numerator and denominator of `q`. This function obeys the standard properties of a valuation, with the appropriate @@ -43,567 +37,6 @@ by taking `[fact (prime p)]` as a type class argument. p-adic, p adic, padic, norm, valuation -/ -universe u - -open nat - -open_locale rat - -open multiplicity - -/-- -For `p ≠ 1`, the p-adic valuation of a natural `n ≠ 0` is the largest natural number `k` such that -p^k divides z. - -If `n = 0` or `p = 1`, then `padic_val_nat p q` defaults to 0. --/ -def padic_val_nat (p : ℕ) (n : ℕ) : ℕ := -if h : p ≠ 1 ∧ 0 < n -then (multiplicity p n).get (multiplicity.finite_nat_iff.2 h) -else 0 - -namespace padic_val_nat -open multiplicity -variables {p : ℕ} - -/-- `padic_val_nat p 0` is 0 for any `p`. -/ -@[simp] protected lemma zero : padic_val_nat p 0 = 0 := -by simp [padic_val_nat] - -/-- `padic_val_nat p 1` is 0 for any `p`. -/ -@[simp] protected lemma one : padic_val_nat p 1 = 0 := -by unfold padic_val_nat; split_ifs; simp * - -/-- For `p ≠ 0, p ≠ 1, `padic_val_rat p p` is 1. -/ -@[simp] lemma self (hp : 1 < p) : padic_val_nat p p = 1 := -begin - have neq_one : (¬ p = 1) ↔ true, - { exact iff_of_true ((ne_of_lt hp).symm) trivial, }, - have eq_zero_false : (p = 0) ↔ false, - { exact iff_false_intro ((ne_of_lt (trans zero_lt_one hp)).symm) }, - simp [padic_val_nat, neq_one, eq_zero_false], -end - -lemma eq_zero_of_not_dvd {n : ℕ} (h : ¬ p ∣ n) : padic_val_nat p n = 0 := -begin - rw padic_val_nat, - split_ifs, - { simp [multiplicity_eq_zero_of_not_dvd h], }, - refl, -end - -end padic_val_nat - -/-- -For `p ≠ 1`, the p-adic valuation of an integer `z ≠ 0` is the largest natural number `k` such that -p^k divides z. - -If `x = 0` or `p = 1`, then `padic_val_int p q` defaults to 0. --/ -def padic_val_int (p : ℕ) (z : ℤ) : ℕ := -padic_val_nat p (z.nat_abs) - -namespace padic_val_int -open multiplicity -variables {p : ℕ} - -lemma of_ne_one_ne_zero {z : ℤ} (hp : p ≠ 1) (hz : z ≠ 0) : padic_val_int p z = - (multiplicity (p : ℤ) z).get (by {apply multiplicity.finite_int_iff.2, simp [hp, hz]}) := -begin - rw [padic_val_int, padic_val_nat, dif_pos (and.intro hp (int.nat_abs_pos_of_ne_zero hz))], - simp_rw multiplicity.int.nat_abs p z, - refl, -end - -/-- `padic_val_int p 0` is 0 for any `p`. -/ -@[simp] protected lemma zero : padic_val_int p 0 = 0 := -by simp [padic_val_int] - -/-- `padic_val_int p 1` is 0 for any `p`. -/ -@[simp] protected lemma one : padic_val_int p 1 = 0 := -by simp [padic_val_int] - -/-- The p-adic value of an natural is its p-adic_value as an integer -/ -@[simp] lemma of_nat {n : ℕ} : padic_val_int p (n : ℤ) = padic_val_nat p n := -by simp [padic_val_int] - -/-- For `p ≠ 0, p ≠ 1, `padic_val_int p p` is 1. -/ -lemma self (hp : 1 < p) : padic_val_int p p = 1 := -by simp [padic_val_nat.self hp] - -lemma eq_zero_of_not_dvd {z : ℤ} (h : ¬ (p : ℤ) ∣ z) : padic_val_int p z = 0 := -begin - rw [padic_val_int, padic_val_nat], - split_ifs, - { simp_rw multiplicity.int.nat_abs, - simp [multiplicity_eq_zero_of_not_dvd h], }, - refl, -end - -end padic_val_int - -/-- -`padic_val_rat` defines the valuation of a rational `q` to be the valuation of `q.num` minus the -valuation of `q.denom`. -If `q = 0` or `p = 1`, then `padic_val_rat p q` defaults to 0. --/ -def padic_val_rat (p : ℕ) (q : ℚ) : ℤ := -padic_val_int p q.num - padic_val_nat p q.denom - -namespace padic_val_rat -open multiplicity -variables {p : ℕ} - -/-- `padic_val_rat p q` is symmetric in `q`. -/ -@[simp] protected lemma neg (q : ℚ) : padic_val_rat p (-q) = padic_val_rat p q := -by simp [padic_val_rat, padic_val_int] - -/-- `padic_val_rat p 0` is 0 for any `p`. -/ -@[simp] -protected lemma zero (m : nat) : padic_val_rat m 0 = 0 := by simp [padic_val_rat, padic_val_int] - -/-- `padic_val_rat p 1` is 0 for any `p`. -/ -@[simp] protected lemma one : padic_val_rat p 1 = 0 := by simp [padic_val_rat, padic_val_int] - -/-- The p-adic value of an integer `z ≠ 0` is its p-adic_value as a rational -/ -@[simp] lemma of_int {z : ℤ} : padic_val_rat p (z : ℚ) = padic_val_int p z := -by simp [padic_val_rat] - -/-- The p-adic value of an integer `z ≠ 0` is the multiplicity of `p` in `z`. -/ -lemma of_int_multiplicity (z : ℤ) (hp : p ≠ 1) (hz : z ≠ 0) : - padic_val_rat p (z : ℚ) = (multiplicity (p : ℤ) z).get - (finite_int_iff.2 ⟨hp, hz⟩) := -by rw [of_int, padic_val_int.of_ne_one_ne_zero hp hz] - -lemma multiplicity_sub_multiplicity {q : ℚ} (hp : p ≠ 1) (hq : q ≠ 0) : - padic_val_rat p q = - (multiplicity (p : ℤ) q.num).get (finite_int_iff.2 ⟨hp, rat.num_ne_zero_of_ne_zero hq⟩) - - (multiplicity p q.denom).get - (by { rw [←finite_iff_dom, finite_nat_iff, and_iff_right hp], exact q.pos }) := -begin - rw [padic_val_rat, padic_val_int.of_ne_one_ne_zero hp, padic_val_nat, dif_pos], - { refl }, - { exact ⟨hp, q.pos⟩ }, - { exact rat.num_ne_zero_of_ne_zero hq }, -end - -/-- The p-adic value of an integer `z ≠ 0` is its p-adic_value as a rational -/ -@[simp] lemma of_nat {n : ℕ} : padic_val_rat p (n : ℚ) = padic_val_nat p n := -by simp [padic_val_rat, padic_val_int] - -/-- For `p ≠ 0, p ≠ 1, `padic_val_rat p p` is 1. -/ -lemma self (hp : 1 < p) : padic_val_rat p p = 1 := by simp [of_nat, hp] - -end padic_val_rat - -section padic_val_nat - -lemma zero_le_padic_val_rat_of_nat (p n : ℕ) : 0 ≤ padic_val_rat p n := by simp - --- /-- `padic_val_rat` coincides with `padic_val_nat`. -/ -@[norm_cast] lemma padic_val_rat_of_nat (p n : ℕ) : - ↑(padic_val_nat p n) = padic_val_rat p n := -by simp [padic_val_rat, padic_val_int] - -/-- -A simplification of `padic_val_nat` when one input is prime, by analogy with `padic_val_rat_def`. --/ -lemma padic_val_nat_def {p : ℕ} [hp : fact p.prime] {n : ℕ} (hn : 0 < n) : - padic_val_nat p n = - (multiplicity p n).get - (multiplicity.finite_nat_iff.2 ⟨nat.prime.ne_one hp.1, hn⟩) := -begin - simp [padic_val_nat], - split_ifs, - { refl, }, - { exfalso, - apply h ⟨(hp.out).ne_one, hn⟩, } -end - -@[simp] lemma padic_val_nat_self (p : ℕ) [fact p.prime] : padic_val_nat p p = 1 := -by simp [padic_val_nat_def (fact.out p.prime).pos] - -lemma one_le_padic_val_nat_of_dvd - {n p : nat} [prime : fact p.prime] (n_pos : 0 < n) (div : p ∣ n) : - 1 ≤ padic_val_nat p n := -begin - rw @padic_val_nat_def _ prime _ n_pos, - let one_le_mul : _ ≤ multiplicity p n := - @multiplicity.le_multiplicity_of_pow_dvd _ _ _ p n 1 (begin norm_num, exact div end), - simp only [nat.cast_one] at one_le_mul, - rcases one_le_mul with ⟨_, q⟩, - dsimp at q, - solve_by_elim, -end - -end padic_val_nat - -namespace padic_val_rat -open multiplicity -variables (p : ℕ) [p_prime : fact p.prime] -include p_prime - -/-- The multiplicity of `p : ℕ` in `a : ℤ` is finite exactly when `a ≠ 0`. -/ -lemma finite_int_prime_iff {p : ℕ} [p_prime : fact p.prime] {a : ℤ} : finite (p : ℤ) a ↔ a ≠ 0 := -by simp [finite_int_iff, ne.symm (ne_of_lt (p_prime.1.one_lt))] - -/-- A rewrite lemma for `padic_val_rat p q` when `q` is expressed in terms of `rat.mk`. -/ -protected lemma defn {q : ℚ} {n d : ℤ} (hqz : q ≠ 0) (qdf : q = n /. d) : - padic_val_rat p q = (multiplicity (p : ℤ) n).get (finite_int_iff.2 - ⟨ne.symm $ ne_of_lt p_prime.1.one_lt, λ hn, by simp * at *⟩) - - (multiplicity (p : ℤ) d).get (finite_int_iff.2 ⟨ne.symm $ ne_of_lt p_prime.1.one_lt, - λ hd, by simp * at *⟩) := -have hd : d ≠ 0, from rat.mk_denom_ne_zero_of_ne_zero hqz qdf, -let ⟨c, hc1, hc2⟩ := rat.num_denom_mk hd qdf in -begin - rw [padic_val_rat.multiplicity_sub_multiplicity]; - simp [hc1, hc2, multiplicity.mul' (nat.prime_iff_prime_int.1 p_prime.1), - (ne.symm (ne_of_lt p_prime.1.one_lt)), hqz, pos_iff_ne_zero], - simp_rw [int.coe_nat_multiplicity p q.denom], -end - -/-- A rewrite lemma for `padic_val_rat p (q * r)` with conditions `q ≠ 0`, `r ≠ 0`. -/ -protected lemma mul {q r : ℚ} (hq : q ≠ 0) (hr : r ≠ 0) : - padic_val_rat p (q * r) = padic_val_rat p q + padic_val_rat p r := -have q*r = (q.num * r.num) /. (↑q.denom * ↑r.denom), by rw_mod_cast rat.mul_num_denom, -have hq' : q.num /. q.denom ≠ 0, by rw rat.num_denom; exact hq, -have hr' : r.num /. r.denom ≠ 0, by rw rat.num_denom; exact hr, -have hp' : _root_.prime (p : ℤ), from nat.prime_iff_prime_int.1 p_prime.1, -begin - rw [padic_val_rat.defn p (mul_ne_zero hq hr) this], - conv_rhs { rw [←(@rat.num_denom q), padic_val_rat.defn p hq', - ←(@rat.num_denom r), padic_val_rat.defn p hr'] }, - rw [multiplicity.mul' hp', multiplicity.mul' hp']; simp [add_comm, add_left_comm, sub_eq_add_neg] -end - -/-- A rewrite lemma for `padic_val_rat p (q^k)` with condition `q ≠ 0`. -/ -protected lemma pow {q : ℚ} (hq : q ≠ 0) {k : ℕ} : - padic_val_rat p (q ^ k) = k * padic_val_rat p q := -by induction k; simp [*, padic_val_rat.mul _ hq (pow_ne_zero _ hq), - pow_succ, add_mul, add_comm] - -/-- -A rewrite lemma for `padic_val_rat p (q⁻¹)` with condition `q ≠ 0`. --/ -protected lemma inv (q : ℚ) : - padic_val_rat p (q⁻¹) = -padic_val_rat p q := -begin - by_cases hq : q = 0, - { simp [hq], }, - { rw [eq_neg_iff_add_eq_zero, ← padic_val_rat.mul p (inv_ne_zero hq) hq, - inv_mul_cancel hq, padic_val_rat.one] }, -end - -/-- A rewrite lemma for `padic_val_rat p (q / r)` with conditions `q ≠ 0`, `r ≠ 0`. -/ -protected lemma div {q r : ℚ} (hq : q ≠ 0) (hr : r ≠ 0) : - padic_val_rat p (q / r) = padic_val_rat p q - padic_val_rat p r := -by rw [div_eq_mul_inv, padic_val_rat.mul p hq (inv_ne_zero hr), - padic_val_rat.inv p r, sub_eq_add_neg] - -/-- -A condition for `padic_val_rat p (n₁ / d₁) ≤ padic_val_rat p (n₂ / d₂), -in terms of divisibility by `p^n`. --/ -lemma padic_val_rat_le_padic_val_rat_iff {n₁ n₂ d₁ d₂ : ℤ} - (hn₁ : n₁ ≠ 0) (hn₂ : n₂ ≠ 0) (hd₁ : d₁ ≠ 0) (hd₂ : d₂ ≠ 0) : - padic_val_rat p (n₁ /. d₁) ≤ padic_val_rat p (n₂ /. d₂) ↔ - ∀ (n : ℕ), ↑p ^ n ∣ n₁ * d₂ → ↑p ^ n ∣ n₂ * d₁ := -have hf1 : finite (p : ℤ) (n₁ * d₂), - from finite_int_prime_iff.2 (mul_ne_zero hn₁ hd₂), -have hf2 : finite (p : ℤ) (n₂ * d₁), - from finite_int_prime_iff.2 (mul_ne_zero hn₂ hd₁), - by conv - { to_lhs, - rw [padic_val_rat.defn p (rat.mk_ne_zero_of_ne_zero hn₁ hd₁) rfl, - padic_val_rat.defn p (rat.mk_ne_zero_of_ne_zero hn₂ hd₂) rfl, - sub_le_iff_le_add', - ← add_sub_assoc, - le_sub_iff_add_le], - norm_cast, - rw [← multiplicity.mul' (nat.prime_iff_prime_int.1 p_prime.1) hf1, add_comm, - ← multiplicity.mul' (nat.prime_iff_prime_int.1 p_prime.1) hf2, - enat.get_le_get, multiplicity_le_multiplicity_iff] } - -/-- -Sufficient conditions to show that the p-adic valuation of `q` is less than or equal to the -p-adic vlauation of `q + r`. --/ -theorem le_padic_val_rat_add_of_le {q r : ℚ} - (hqr : q + r ≠ 0) - (h : padic_val_rat p q ≤ padic_val_rat p r) : - padic_val_rat p q ≤ padic_val_rat p (q + r) := -if hq : q = 0 then by simpa [hq] using h else -if hr : r = 0 then by simp [hr] else -have hqn : q.num ≠ 0, from rat.num_ne_zero_of_ne_zero hq, -have hqd : (q.denom : ℤ) ≠ 0, by exact_mod_cast rat.denom_ne_zero _, -have hrn : r.num ≠ 0, from rat.num_ne_zero_of_ne_zero hr, -have hrd : (r.denom : ℤ) ≠ 0, by exact_mod_cast rat.denom_ne_zero _, -have hqreq : q + r = (((q.num * r.denom + q.denom * r.num : ℤ)) /. (↑q.denom * ↑r.denom : ℤ)), - from rat.add_num_denom _ _, -have hqrd : q.num * ↑(r.denom) + ↑(q.denom) * r.num ≠ 0, - from rat.mk_num_ne_zero_of_ne_zero hqr hqreq, -begin - conv_lhs { rw ←(@rat.num_denom q) }, - rw [hqreq, padic_val_rat_le_padic_val_rat_iff p hqn hqrd hqd (mul_ne_zero hqd hrd), - ← multiplicity_le_multiplicity_iff, mul_left_comm, - multiplicity.mul (nat.prime_iff_prime_int.1 p_prime.1), add_mul], - rw [←(@rat.num_denom q), ←(@rat.num_denom r), - padic_val_rat_le_padic_val_rat_iff p hqn hrn hqd hrd, ← multiplicity_le_multiplicity_iff] at h, - calc _ ≤ min (multiplicity ↑p (q.num * ↑(r.denom) * ↑(q.denom))) - (multiplicity ↑p (↑(q.denom) * r.num * ↑(q.denom))) : (le_min - (by rw [@multiplicity.mul _ _ _ _ (_ * _) _ (nat.prime_iff_prime_int.1 p_prime.1), add_comm]) - (by rw [mul_assoc, @multiplicity.mul _ _ _ _ (q.denom : ℤ) - (_ * _) (nat.prime_iff_prime_int.1 p_prime.1)]; - exact add_le_add_left h _)) - ... ≤ _ : min_le_multiplicity_add -end - -/-- -The minimum of the valuations of `q` and `r` is less than or equal to the valuation of `q + r`. --/ -theorem min_le_padic_val_rat_add {q r : ℚ} (hqr : q + r ≠ 0) : - min (padic_val_rat p q) (padic_val_rat p r) ≤ padic_val_rat p (q + r) := -(le_total (padic_val_rat p q) (padic_val_rat p r)).elim - (λ h, by rw [min_eq_left h]; exact le_padic_val_rat_add_of_le _ hqr h) - (λ h, by rw [min_eq_right h, add_comm]; exact le_padic_val_rat_add_of_le _ - (by rwa add_comm) h) - -open_locale big_operators - -/-- A finite sum of rationals with positive p-adic valuation has positive p-adic valuation - (if the sum is non-zero). -/ -theorem sum_pos_of_pos {n : ℕ} {F : ℕ → ℚ} - (hF : ∀ i, i < n → 0 < padic_val_rat p (F i)) (hn0 : ∑ i in finset.range n, F i ≠ 0) : - 0 < padic_val_rat p (∑ i in finset.range n, F i) := -begin - induction n with d hd, - { exact false.elim (hn0 rfl) }, - { rw finset.sum_range_succ at hn0 ⊢, - by_cases h : ∑ (x : ℕ) in finset.range d, F x = 0, - { rw [h, zero_add], - exact hF d (lt_add_one _) }, - { refine lt_of_lt_of_le _ (min_le_padic_val_rat_add p hn0), - { refine lt_min (hd (λ i hi, _) h) (hF d (lt_add_one _)), - exact hF _ (lt_trans hi (lt_add_one _)) }, } } -end - -end padic_val_rat - -namespace padic_val_nat - -/-- A rewrite lemma for `padic_val_nat p (q * r)` with conditions `q ≠ 0`, `r ≠ 0`. -/ -protected lemma mul (p : ℕ) [p_prime : fact p.prime] {q r : ℕ} (hq : q ≠ 0) (hr : r ≠ 0) : - padic_val_nat p (q * r) = padic_val_nat p q + padic_val_nat p r := -begin - apply int.coe_nat_inj, - simp only [padic_val_rat_of_nat, nat.cast_mul], - rw padic_val_rat.mul, - norm_cast, - exact cast_ne_zero.mpr hq, - exact cast_ne_zero.mpr hr, -end - -protected lemma div_of_dvd (p : ℕ) [hp : fact p.prime] {a b : ℕ} (h : b ∣ a) : - padic_val_nat p (a / b) = padic_val_nat p a - padic_val_nat p b := -begin - rcases eq_or_ne a 0 with rfl | ha, - { simp }, - obtain ⟨k, rfl⟩ := h, - obtain ⟨hb, hk⟩ := mul_ne_zero_iff.mp ha, - rw [mul_comm, k.mul_div_cancel hb.bot_lt, padic_val_nat.mul p hk hb, nat.add_sub_cancel] -end - -/-- Dividing out by a prime factor reduces the padic_val_nat by 1. -/ -protected lemma div {p : ℕ} [p_prime : fact p.prime] {b : ℕ} (dvd : p ∣ b) : - (padic_val_nat p (b / p)) = (padic_val_nat p b) - 1 := -begin - convert padic_val_nat.div_of_dvd p dvd, - rw padic_val_nat_self p -end - -/-- A version of `padic_val_rat.pow` for `padic_val_nat` -/ -protected lemma pow (p q n : ℕ) [fact p.prime] (hq : q ≠ 0) : - padic_val_nat p (q ^ n) = n * padic_val_nat p q := -begin - apply @nat.cast_injective ℤ, - push_cast, - exact padic_val_rat.pow _ (cast_ne_zero.mpr hq), -end - -@[simp] protected lemma prime_pow (p n : ℕ) [fact p.prime] : padic_val_nat p (p ^ n) = n := -by rw [padic_val_nat.pow p _ _ (fact.out p.prime).ne_zero, padic_val_nat_self p, mul_one] - -protected lemma div_pow {p : ℕ} [p_prime : fact p.prime] {b k : ℕ} (dvd : p ^ k ∣ b) : - (padic_val_nat p (b / p ^ k)) = (padic_val_nat p b) - k := -begin - convert padic_val_nat.div_of_dvd p dvd, - rw padic_val_nat.prime_pow -end - -end padic_val_nat - -section padic_val_nat - -lemma dvd_of_one_le_padic_val_nat {n p : nat} (hp : 1 ≤ padic_val_nat p n) : - p ∣ n := -begin - by_contra h, - rw padic_val_nat.eq_zero_of_not_dvd h at hp, - exact lt_irrefl 0 (lt_of_lt_of_le zero_lt_one hp), -end - -lemma pow_padic_val_nat_dvd {p n : ℕ} [fact (nat.prime p)] : p ^ (padic_val_nat p n) ∣ n := -begin - cases nat.eq_zero_or_pos n with hn hn, - { rw hn, exact dvd_zero (p ^ padic_val_nat p 0) }, - { rw multiplicity.pow_dvd_iff_le_multiplicity, - apply le_of_eq, - rw padic_val_nat_def hn, - { apply enat.coe_get }, - { apply_instance } } -end - -lemma pow_succ_padic_val_nat_not_dvd {p n : ℕ} [hp : fact (nat.prime p)] (hn : 0 < n) : - ¬ p ^ (padic_val_nat p n + 1) ∣ n := -begin - rw multiplicity.pow_dvd_iff_le_multiplicity, - rw padic_val_nat_def hn, - { rw [nat.cast_add, enat.coe_get], - simp only [nat.cast_one, not_le], - exact enat.lt_add_one (ne_top_iff_finite.mpr - (finite_nat_iff.mpr ⟨(fact.elim hp).ne_one, hn⟩)), }, - { apply_instance } -end - -lemma padic_val_nat_dvd_iff (p : ℕ) [hp :fact p.prime] (n : ℕ) (a : ℕ) : - p^n ∣ a ↔ a = 0 ∨ n ≤ padic_val_nat p a := -begin - split, - { rw [pow_dvd_iff_le_multiplicity, padic_val_nat], - split_ifs, - { rw enat.coe_le_iff, - exact λ hn, or.inr (hn _) }, - { simp only [true_and, not_lt, ne.def, not_false_iff, nat.le_zero_iff, hp.out.ne_one] at h, - exact λ hn, or.inl h } }, - { rintro (rfl|h), - { exact dvd_zero (p ^ n) }, - { exact dvd_trans (pow_dvd_pow p h) pow_padic_val_nat_dvd } }, -end - -lemma padic_val_nat_primes {p q : ℕ} [p_prime : fact p.prime] [q_prime : fact q.prime] - (neq : p ≠ q) : padic_val_nat p q = 0 := -@padic_val_nat.eq_zero_of_not_dvd p q $ -(not_congr (iff.symm (prime_dvd_prime_iff_eq p_prime.1 q_prime.1))).mp neq - -protected lemma padic_val_nat.div' {p : ℕ} [p_prime : fact p.prime] : - ∀ {m : ℕ} (cpm : coprime p m) {b : ℕ} (dvd : m ∣ b), padic_val_nat p (b / m) = padic_val_nat p b -| 0 := λ cpm b dvd, by { rw zero_dvd_iff at dvd, rw [dvd, nat.zero_div], } -| (n + 1) := - λ cpm b dvd, - begin - rcases dvd with ⟨c, rfl⟩, - rw [mul_div_right c (nat.succ_pos _)],by_cases hc : c = 0, - { rw [hc, mul_zero] }, - { rw padic_val_nat.mul, - { suffices : ¬ p ∣ (n+1), - { rw [padic_val_nat.eq_zero_of_not_dvd this, zero_add] }, - contrapose! cpm, - exact p_prime.1.dvd_iff_not_coprime.mp cpm }, - { exact nat.succ_ne_zero _ }, - { exact hc } }, - end - -lemma padic_val_nat_eq_factorization (p n : ℕ) [hp : fact p.prime] : - padic_val_nat p n = n.factorization p := -begin - by_cases hn : n = 0, { subst hn, simp }, - rw @padic_val_nat_def p _ n (nat.pos_of_ne_zero hn), - simp [@multiplicity_eq_factorization n p hp.elim hn], -end - -open_locale big_operators - -lemma prod_pow_prime_padic_val_nat (n : nat) (hn : n ≠ 0) (m : nat) (pr : n < m) : - ∏ p in finset.filter nat.prime (finset.range m), p ^ (padic_val_nat p n) = n := -begin - nth_rewrite_rhs 0 ←factorization_prod_pow_eq_self hn, - rw eq_comm, - apply finset.prod_subset_one_on_sdiff, - { exact λ p hp, finset.mem_filter.mpr - ⟨finset.mem_range.mpr (gt_of_gt_of_ge pr (le_of_mem_factorization hp)), - prime_of_mem_factorization hp⟩ }, - { intros p hp, - cases finset.mem_sdiff.mp hp with hp1 hp2, - haveI := fact_iff.mpr (finset.mem_filter.mp hp1).2, - rw padic_val_nat_eq_factorization p n, - simp [finsupp.not_mem_support_iff.mp hp2] }, - { intros p hp, - haveI := fact_iff.mpr (prime_of_mem_factorization hp), - simp [padic_val_nat_eq_factorization] } -end - -lemma range_pow_padic_val_nat_subset_divisors {n : ℕ} (p : ℕ) [fact p.prime] (hn : n ≠ 0) : - (finset.range (padic_val_nat p n + 1)).image (pow p) ⊆ n.divisors := -begin - intros t ht, - simp only [exists_prop, finset.mem_image, finset.mem_range] at ht, - obtain ⟨k, hk, rfl⟩ := ht, - rw nat.mem_divisors, - exact ⟨(pow_dvd_pow p $ by linarith).trans pow_padic_val_nat_dvd, hn⟩ -end - -lemma range_pow_padic_val_nat_subset_divisors' {n : ℕ} (p : ℕ) [h : fact p.prime] : - (finset.range (padic_val_nat p n)).image (λ t, p ^ (t + 1)) ⊆ (n.divisors \ {1}) := -begin - rcases eq_or_ne n 0 with rfl | hn, - { simp }, - intros t ht, - simp only [exists_prop, finset.mem_image, finset.mem_range] at ht, - obtain ⟨k, hk, rfl⟩ := ht, - rw [finset.mem_sdiff, nat.mem_divisors], - refine ⟨⟨(pow_dvd_pow p $ by linarith).trans pow_padic_val_nat_dvd, hn⟩, _⟩, - rw [finset.mem_singleton], - nth_rewrite 1 ←one_pow (k + 1), - exact (nat.pow_lt_pow_of_lt_left h.1.one_lt $ nat.succ_pos k).ne', -end - -end padic_val_nat - -section padic_val_int -variables (p : ℕ) [p_prime : fact p.prime] - -lemma padic_val_int_dvd_iff (p : ℕ) [fact p.prime] (n : ℕ) (a : ℤ) : - ↑p^n ∣ a ↔ a = 0 ∨ n ≤ padic_val_int p a := -by rw [padic_val_int, ←int.nat_abs_eq_zero, ←padic_val_nat_dvd_iff, ←int.coe_nat_dvd_left, - int.coe_nat_pow] - -lemma padic_val_int_dvd (p : ℕ) [fact p.prime] (a : ℤ) : ↑p^(padic_val_int p a) ∣ a := -begin - rw padic_val_int_dvd_iff, - exact or.inr le_rfl, -end - -lemma padic_val_int_self (p : ℕ) [pp : fact p.prime] : padic_val_int p p = 1 := -padic_val_int.self pp.out.one_lt - -lemma padic_val_int.mul (p : ℕ) [fact p.prime] {a b : ℤ} (ha : a ≠ 0) (hb : b ≠ 0) : - padic_val_int p (a*b) = padic_val_int p a + padic_val_int p b := -begin - simp_rw padic_val_int, - rw [int.nat_abs_mul, padic_val_nat.mul]; - rwa int.nat_abs_ne_zero, -end - -lemma padic_val_int_mul_eq_succ (p : ℕ) [pp : fact p.prime] (a : ℤ) (ha : a ≠ 0) : - padic_val_int p (a * p) = (padic_val_int p a) + 1 := -begin - rw padic_val_int.mul p ha (int.coe_nat_ne_zero.mpr (pp.out).ne_zero), - simp only [eq_self_iff_true, padic_val_int.of_nat, padic_val_nat_self], -end - -end padic_val_int - - /-- If `q ≠ 0`, the p-adic norm of a rational `q` is `p ^ (-(padic_val_rat p q))`. If `q = 0`, the p-adic norm of `q` is 0. diff --git a/src/number_theory/padics/padic_val.lean b/src/number_theory/padics/padic_val.lean new file mode 100644 index 0000000000000..80fd6b1f19230 --- /dev/null +++ b/src/number_theory/padics/padic_val.lean @@ -0,0 +1,601 @@ +/- +Copyright (c) 2018 Robert Y. Lewis. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Robert Y. Lewis +-/ +import algebra.order.absolute_value +import algebra.field_power +import ring_theory.int.basic +import tactic.basic +import tactic.ring_exp +import number_theory.divisors +import data.nat.factorization + +/-! +# p-adic Valuation + +This file defines the p-adic valuation on ℕ, ℤ, and ℚ. + +The p-adic valuation on ℚ is the difference of the multiplicities of `p` in the numerator and +denominator of `q`. This function obeys the standard properties of a valuation, with the appropriate +assumptions on p. The p-adic valuations on ℕ and ℤ agree with that on ℚ. + +The valuation induces a norm on ℚ. This norm is defined in padic_norm.lean. + +## Notations + +This file uses the local notation `/.` for `rat.mk`. + +## Implementation notes + +Much, but not all, of this file assumes that `p` is prime. This assumption is inferred automatically +by taking `[fact (prime p)]` as a type class argument. + +## References + +* [F. Q. Gouvêa, *p-adic numbers*][gouvea1997] +* [R. Y. Lewis, *A formal proof of Hensel's lemma over the p-adic integers*][lewis2019] +* + +## Tags + +p-adic, p adic, padic, norm, valuation +-/ + +universe u + +open nat + +open_locale rat + +open multiplicity + +/-- +For `p ≠ 1`, the p-adic valuation of a natural `n ≠ 0` is the largest natural number `k` such that +p^k divides z. +If `n = 0` or `p = 1`, then `padic_val_nat p q` defaults to 0. +-/ +def padic_val_nat (p : ℕ) (n : ℕ) : ℕ := +if h : p ≠ 1 ∧ 0 < n +then (multiplicity p n).get (multiplicity.finite_nat_iff.2 h) +else 0 + +namespace padic_val_nat +open multiplicity +variables {p : ℕ} + +/-- `padic_val_nat p 0` is 0 for any `p`. -/ +@[simp] protected lemma zero : padic_val_nat p 0 = 0 := +by simp [padic_val_nat] + +/-- `padic_val_nat p 1` is 0 for any `p`. -/ +@[simp] protected lemma one : padic_val_nat p 1 = 0 := +by unfold padic_val_nat; split_ifs; simp * + +/-- For `p ≠ 0, p ≠ 1, `padic_val_rat p p` is 1. -/ +@[simp] lemma self (hp : 1 < p) : padic_val_nat p p = 1 := +begin + have neq_one : (¬ p = 1) ↔ true, + { exact iff_of_true ((ne_of_lt hp).symm) trivial, }, + have eq_zero_false : (p = 0) ↔ false, + { exact iff_false_intro ((ne_of_lt (trans zero_lt_one hp)).symm) }, + simp [padic_val_nat, neq_one, eq_zero_false], +end + +lemma eq_zero_of_not_dvd {n : ℕ} (h : ¬ p ∣ n) : padic_val_nat p n = 0 := +begin + rw padic_val_nat, + split_ifs, + { simp [multiplicity_eq_zero_of_not_dvd h], }, + refl, +end + +end padic_val_nat + +/-- +For `p ≠ 1`, the p-adic valuation of an integer `z ≠ 0` is the largest natural number `k` such that +p^k divides z. +If `x = 0` or `p = 1`, then `padic_val_int p q` defaults to 0. +-/ +def padic_val_int (p : ℕ) (z : ℤ) : ℕ := +padic_val_nat p (z.nat_abs) + +namespace padic_val_int +open multiplicity +variables {p : ℕ} + +lemma of_ne_one_ne_zero {z : ℤ} (hp : p ≠ 1) (hz : z ≠ 0) : padic_val_int p z = + (multiplicity (p : ℤ) z).get (by {apply multiplicity.finite_int_iff.2, simp [hp, hz]}) := +begin + rw [padic_val_int, padic_val_nat, dif_pos (and.intro hp (int.nat_abs_pos_of_ne_zero hz))], + simp_rw multiplicity.int.nat_abs p z, + refl, +end + +/-- `padic_val_int p 0` is 0 for any `p`. -/ +@[simp] protected lemma zero : padic_val_int p 0 = 0 := +by simp [padic_val_int] + +/-- `padic_val_int p 1` is 0 for any `p`. -/ +@[simp] protected lemma one : padic_val_int p 1 = 0 := +by simp [padic_val_int] + +/-- The p-adic value of an natural is its p-adic_value as an integer -/ +@[simp] lemma of_nat {n : ℕ} : padic_val_int p (n : ℤ) = padic_val_nat p n := +by simp [padic_val_int] + +/-- For `p ≠ 0, p ≠ 1, `padic_val_int p p` is 1. -/ +lemma self (hp : 1 < p) : padic_val_int p p = 1 := +by simp [padic_val_nat.self hp] + +lemma eq_zero_of_not_dvd {z : ℤ} (h : ¬ (p : ℤ) ∣ z) : padic_val_int p z = 0 := +begin + rw [padic_val_int, padic_val_nat], + split_ifs, + { simp_rw multiplicity.int.nat_abs, + simp [multiplicity_eq_zero_of_not_dvd h], }, + refl, +end + +end padic_val_int + +/-- +`padic_val_rat` defines the valuation of a rational `q` to be the valuation of `q.num` minus the +valuation of `q.denom`. +If `q = 0` or `p = 1`, then `padic_val_rat p q` defaults to 0. +-/ +def padic_val_rat (p : ℕ) (q : ℚ) : ℤ := +padic_val_int p q.num - padic_val_nat p q.denom + +namespace padic_val_rat +open multiplicity +variables {p : ℕ} + +/-- `padic_val_rat p q` is symmetric in `q`. -/ +@[simp] protected lemma neg (q : ℚ) : padic_val_rat p (-q) = padic_val_rat p q := +by simp [padic_val_rat, padic_val_int] + +/-- `padic_val_rat p 0` is 0 for any `p`. -/ +@[simp] +protected lemma zero (m : nat) : padic_val_rat m 0 = 0 := by simp [padic_val_rat, padic_val_int] + +/-- `padic_val_rat p 1` is 0 for any `p`. -/ +@[simp] protected lemma one : padic_val_rat p 1 = 0 := by simp [padic_val_rat, padic_val_int] + +/-- The p-adic value of an integer `z ≠ 0` is its p-adic_value as a rational -/ +@[simp] lemma of_int {z : ℤ} : padic_val_rat p (z : ℚ) = padic_val_int p z := +by simp [padic_val_rat] + +/-- The p-adic value of an integer `z ≠ 0` is the multiplicity of `p` in `z`. -/ +lemma of_int_multiplicity (z : ℤ) (hp : p ≠ 1) (hz : z ≠ 0) : + padic_val_rat p (z : ℚ) = (multiplicity (p : ℤ) z).get + (finite_int_iff.2 ⟨hp, hz⟩) := +by rw [of_int, padic_val_int.of_ne_one_ne_zero hp hz] + +lemma multiplicity_sub_multiplicity {q : ℚ} (hp : p ≠ 1) (hq : q ≠ 0) : + padic_val_rat p q = + (multiplicity (p : ℤ) q.num).get (finite_int_iff.2 ⟨hp, rat.num_ne_zero_of_ne_zero hq⟩) - + (multiplicity p q.denom).get + (by { rw [←finite_iff_dom, finite_nat_iff, and_iff_right hp], exact q.pos }) := +begin + rw [padic_val_rat, padic_val_int.of_ne_one_ne_zero hp, padic_val_nat, dif_pos], + { refl }, + { exact ⟨hp, q.pos⟩ }, + { exact rat.num_ne_zero_of_ne_zero hq }, +end + +/-- The p-adic value of an integer `z ≠ 0` is its p-adic_value as a rational -/ +@[simp] lemma of_nat {n : ℕ} : padic_val_rat p (n : ℚ) = padic_val_nat p n := +by simp [padic_val_rat, padic_val_int] + +/-- For `p ≠ 0, p ≠ 1, `padic_val_rat p p` is 1. -/ +lemma self (hp : 1 < p) : padic_val_rat p p = 1 := by simp [of_nat, hp] + +end padic_val_rat + +section padic_val_nat + +lemma zero_le_padic_val_rat_of_nat (p n : ℕ) : 0 ≤ padic_val_rat p n := by simp + +-- /-- `padic_val_rat` coincides with `padic_val_nat`. -/ +@[norm_cast] lemma padic_val_rat_of_nat (p n : ℕ) : + ↑(padic_val_nat p n) = padic_val_rat p n := +by simp [padic_val_rat, padic_val_int] + +/-- +A simplification of `padic_val_nat` when one input is prime, by analogy with `padic_val_rat_def`. +-/ +lemma padic_val_nat_def {p : ℕ} [hp : fact p.prime] {n : ℕ} (hn : 0 < n) : + padic_val_nat p n = + (multiplicity p n).get + (multiplicity.finite_nat_iff.2 ⟨nat.prime.ne_one hp.1, hn⟩) := +begin + simp [padic_val_nat], + split_ifs, + { refl, }, + { exfalso, + apply h ⟨(hp.out).ne_one, hn⟩, } +end + +@[simp] lemma padic_val_nat_self (p : ℕ) [fact p.prime] : padic_val_nat p p = 1 := +by simp [padic_val_nat_def (fact.out p.prime).pos] + +lemma one_le_padic_val_nat_of_dvd + {n p : nat} [prime : fact p.prime] (n_pos : 0 < n) (div : p ∣ n) : + 1 ≤ padic_val_nat p n := +begin + rw @padic_val_nat_def _ prime _ n_pos, + let one_le_mul : _ ≤ multiplicity p n := + @multiplicity.le_multiplicity_of_pow_dvd _ _ _ p n 1 (begin norm_num, exact div end), + simp only [nat.cast_one] at one_le_mul, + rcases one_le_mul with ⟨_, q⟩, + dsimp at q, + solve_by_elim, +end + +end padic_val_nat + +namespace padic_val_rat +open multiplicity +variables (p : ℕ) [p_prime : fact p.prime] +include p_prime + +/-- The multiplicity of `p : ℕ` in `a : ℤ` is finite exactly when `a ≠ 0`. -/ +lemma finite_int_prime_iff {p : ℕ} [p_prime : fact p.prime] {a : ℤ} : finite (p : ℤ) a ↔ a ≠ 0 := +by simp [finite_int_iff, ne.symm (ne_of_lt (p_prime.1.one_lt))] + +/-- A rewrite lemma for `padic_val_rat p q` when `q` is expressed in terms of `rat.mk`. -/ +protected lemma defn {q : ℚ} {n d : ℤ} (hqz : q ≠ 0) (qdf : q = n /. d) : + padic_val_rat p q = (multiplicity (p : ℤ) n).get (finite_int_iff.2 + ⟨ne.symm $ ne_of_lt p_prime.1.one_lt, λ hn, by simp * at *⟩) - + (multiplicity (p : ℤ) d).get (finite_int_iff.2 ⟨ne.symm $ ne_of_lt p_prime.1.one_lt, + λ hd, by simp * at *⟩) := +have hd : d ≠ 0, from rat.mk_denom_ne_zero_of_ne_zero hqz qdf, +let ⟨c, hc1, hc2⟩ := rat.num_denom_mk hd qdf in +begin + rw [padic_val_rat.multiplicity_sub_multiplicity]; + simp [hc1, hc2, multiplicity.mul' (nat.prime_iff_prime_int.1 p_prime.1), + (ne.symm (ne_of_lt p_prime.1.one_lt)), hqz, pos_iff_ne_zero], + simp_rw [int.coe_nat_multiplicity p q.denom], +end + +/-- A rewrite lemma for `padic_val_rat p (q * r)` with conditions `q ≠ 0`, `r ≠ 0`. -/ +protected lemma mul {q r : ℚ} (hq : q ≠ 0) (hr : r ≠ 0) : + padic_val_rat p (q * r) = padic_val_rat p q + padic_val_rat p r := +have q*r = (q.num * r.num) /. (↑q.denom * ↑r.denom), by rw_mod_cast rat.mul_num_denom, +have hq' : q.num /. q.denom ≠ 0, by rw rat.num_denom; exact hq, +have hr' : r.num /. r.denom ≠ 0, by rw rat.num_denom; exact hr, +have hp' : _root_.prime (p : ℤ), from nat.prime_iff_prime_int.1 p_prime.1, +begin + rw [padic_val_rat.defn p (mul_ne_zero hq hr) this], + conv_rhs { rw [←(@rat.num_denom q), padic_val_rat.defn p hq', + ←(@rat.num_denom r), padic_val_rat.defn p hr'] }, + rw [multiplicity.mul' hp', multiplicity.mul' hp']; simp [add_comm, add_left_comm, sub_eq_add_neg] +end + +/-- A rewrite lemma for `padic_val_rat p (q^k)` with condition `q ≠ 0`. -/ +protected lemma pow {q : ℚ} (hq : q ≠ 0) {k : ℕ} : + padic_val_rat p (q ^ k) = k * padic_val_rat p q := +by induction k; simp [*, padic_val_rat.mul _ hq (pow_ne_zero _ hq), + pow_succ, add_mul, add_comm] + +/-- +A rewrite lemma for `padic_val_rat p (q⁻¹)` with condition `q ≠ 0`. +-/ +protected lemma inv (q : ℚ) : + padic_val_rat p (q⁻¹) = -padic_val_rat p q := +begin + by_cases hq : q = 0, + { simp [hq], }, + { rw [eq_neg_iff_add_eq_zero, ← padic_val_rat.mul p (inv_ne_zero hq) hq, + inv_mul_cancel hq, padic_val_rat.one] }, +end + +/-- A rewrite lemma for `padic_val_rat p (q / r)` with conditions `q ≠ 0`, `r ≠ 0`. -/ +protected lemma div {q r : ℚ} (hq : q ≠ 0) (hr : r ≠ 0) : + padic_val_rat p (q / r) = padic_val_rat p q - padic_val_rat p r := +by rw [div_eq_mul_inv, padic_val_rat.mul p hq (inv_ne_zero hr), + padic_val_rat.inv p r, sub_eq_add_neg] + +/-- +A condition for `padic_val_rat p (n₁ / d₁) ≤ padic_val_rat p (n₂ / d₂), +in terms of divisibility by `p^n`. +-/ +lemma padic_val_rat_le_padic_val_rat_iff {n₁ n₂ d₁ d₂ : ℤ} + (hn₁ : n₁ ≠ 0) (hn₂ : n₂ ≠ 0) (hd₁ : d₁ ≠ 0) (hd₂ : d₂ ≠ 0) : + padic_val_rat p (n₁ /. d₁) ≤ padic_val_rat p (n₂ /. d₂) ↔ + ∀ (n : ℕ), ↑p ^ n ∣ n₁ * d₂ → ↑p ^ n ∣ n₂ * d₁ := +have hf1 : finite (p : ℤ) (n₁ * d₂), + from finite_int_prime_iff.2 (mul_ne_zero hn₁ hd₂), +have hf2 : finite (p : ℤ) (n₂ * d₁), + from finite_int_prime_iff.2 (mul_ne_zero hn₂ hd₁), + by conv + { to_lhs, + rw [padic_val_rat.defn p (rat.mk_ne_zero_of_ne_zero hn₁ hd₁) rfl, + padic_val_rat.defn p (rat.mk_ne_zero_of_ne_zero hn₂ hd₂) rfl, + sub_le_iff_le_add', + ← add_sub_assoc, + le_sub_iff_add_le], + norm_cast, + rw [← multiplicity.mul' (nat.prime_iff_prime_int.1 p_prime.1) hf1, add_comm, + ← multiplicity.mul' (nat.prime_iff_prime_int.1 p_prime.1) hf2, + enat.get_le_get, multiplicity_le_multiplicity_iff] } + +/-- +Sufficient conditions to show that the p-adic valuation of `q` is less than or equal to the +p-adic vlauation of `q + r`. +-/ +theorem le_padic_val_rat_add_of_le {q r : ℚ} + (hqr : q + r ≠ 0) + (h : padic_val_rat p q ≤ padic_val_rat p r) : + padic_val_rat p q ≤ padic_val_rat p (q + r) := +if hq : q = 0 then by simpa [hq] using h else +if hr : r = 0 then by simp [hr] else +have hqn : q.num ≠ 0, from rat.num_ne_zero_of_ne_zero hq, +have hqd : (q.denom : ℤ) ≠ 0, by exact_mod_cast rat.denom_ne_zero _, +have hrn : r.num ≠ 0, from rat.num_ne_zero_of_ne_zero hr, +have hrd : (r.denom : ℤ) ≠ 0, by exact_mod_cast rat.denom_ne_zero _, +have hqreq : q + r = (((q.num * r.denom + q.denom * r.num : ℤ)) /. (↑q.denom * ↑r.denom : ℤ)), + from rat.add_num_denom _ _, +have hqrd : q.num * ↑(r.denom) + ↑(q.denom) * r.num ≠ 0, + from rat.mk_num_ne_zero_of_ne_zero hqr hqreq, +begin + conv_lhs { rw ←(@rat.num_denom q) }, + rw [hqreq, padic_val_rat_le_padic_val_rat_iff p hqn hqrd hqd (mul_ne_zero hqd hrd), + ← multiplicity_le_multiplicity_iff, mul_left_comm, + multiplicity.mul (nat.prime_iff_prime_int.1 p_prime.1), add_mul], + rw [←(@rat.num_denom q), ←(@rat.num_denom r), + padic_val_rat_le_padic_val_rat_iff p hqn hrn hqd hrd, ← multiplicity_le_multiplicity_iff] at h, + calc _ ≤ min (multiplicity ↑p (q.num * ↑(r.denom) * ↑(q.denom))) + (multiplicity ↑p (↑(q.denom) * r.num * ↑(q.denom))) : (le_min + (by rw [@multiplicity.mul _ _ _ _ (_ * _) _ (nat.prime_iff_prime_int.1 p_prime.1), add_comm]) + (by rw [mul_assoc, @multiplicity.mul _ _ _ _ (q.denom : ℤ) + (_ * _) (nat.prime_iff_prime_int.1 p_prime.1)]; + exact add_le_add_left h _)) + ... ≤ _ : min_le_multiplicity_add +end + +/-- +The minimum of the valuations of `q` and `r` is less than or equal to the valuation of `q + r`. +-/ +theorem min_le_padic_val_rat_add {q r : ℚ} (hqr : q + r ≠ 0) : + min (padic_val_rat p q) (padic_val_rat p r) ≤ padic_val_rat p (q + r) := +(le_total (padic_val_rat p q) (padic_val_rat p r)).elim + (λ h, by rw [min_eq_left h]; exact le_padic_val_rat_add_of_le _ hqr h) + (λ h, by rw [min_eq_right h, add_comm]; exact le_padic_val_rat_add_of_le _ + (by rwa add_comm) h) + +open_locale big_operators + +/-- A finite sum of rationals with positive p-adic valuation has positive p-adic valuation + (if the sum is non-zero). -/ +theorem sum_pos_of_pos {n : ℕ} {F : ℕ → ℚ} + (hF : ∀ i, i < n → 0 < padic_val_rat p (F i)) (hn0 : ∑ i in finset.range n, F i ≠ 0) : + 0 < padic_val_rat p (∑ i in finset.range n, F i) := +begin + induction n with d hd, + { exact false.elim (hn0 rfl) }, + { rw finset.sum_range_succ at hn0 ⊢, + by_cases h : ∑ (x : ℕ) in finset.range d, F x = 0, + { rw [h, zero_add], + exact hF d (lt_add_one _) }, + { refine lt_of_lt_of_le _ (min_le_padic_val_rat_add p hn0), + { refine lt_min (hd (λ i hi, _) h) (hF d (lt_add_one _)), + exact hF _ (lt_trans hi (lt_add_one _)) }, } } +end + +end padic_val_rat + +namespace padic_val_nat + +/-- A rewrite lemma for `padic_val_nat p (q * r)` with conditions `q ≠ 0`, `r ≠ 0`. -/ +protected lemma mul (p : ℕ) [p_prime : fact p.prime] {q r : ℕ} (hq : q ≠ 0) (hr : r ≠ 0) : + padic_val_nat p (q * r) = padic_val_nat p q + padic_val_nat p r := +begin + apply int.coe_nat_inj, + simp only [padic_val_rat_of_nat, nat.cast_mul], + rw padic_val_rat.mul, + norm_cast, + exact cast_ne_zero.mpr hq, + exact cast_ne_zero.mpr hr, +end + +protected lemma div_of_dvd (p : ℕ) [hp : fact p.prime] {a b : ℕ} (h : b ∣ a) : + padic_val_nat p (a / b) = padic_val_nat p a - padic_val_nat p b := +begin + rcases eq_or_ne a 0 with rfl | ha, + { simp }, + obtain ⟨k, rfl⟩ := h, + obtain ⟨hb, hk⟩ := mul_ne_zero_iff.mp ha, + rw [mul_comm, k.mul_div_cancel hb.bot_lt, padic_val_nat.mul p hk hb, nat.add_sub_cancel] +end + +/-- Dividing out by a prime factor reduces the padic_val_nat by 1. -/ +protected lemma div {p : ℕ} [p_prime : fact p.prime] {b : ℕ} (dvd : p ∣ b) : + (padic_val_nat p (b / p)) = (padic_val_nat p b) - 1 := +begin + convert padic_val_nat.div_of_dvd p dvd, + rw padic_val_nat_self p +end + +/-- A version of `padic_val_rat.pow` for `padic_val_nat` -/ +protected lemma pow (p q n : ℕ) [fact p.prime] (hq : q ≠ 0) : + padic_val_nat p (q ^ n) = n * padic_val_nat p q := +begin + apply @nat.cast_injective ℤ, + push_cast, + exact padic_val_rat.pow _ (cast_ne_zero.mpr hq), +end + +@[simp] protected lemma prime_pow (p n : ℕ) [fact p.prime] : padic_val_nat p (p ^ n) = n := +by rw [padic_val_nat.pow p _ _ (fact.out p.prime).ne_zero, padic_val_nat_self p, mul_one] + +protected lemma div_pow {p : ℕ} [p_prime : fact p.prime] {b k : ℕ} (dvd : p ^ k ∣ b) : + (padic_val_nat p (b / p ^ k)) = (padic_val_nat p b) - k := +begin + convert padic_val_nat.div_of_dvd p dvd, + rw padic_val_nat.prime_pow +end + +end padic_val_nat + +section padic_val_nat + +lemma dvd_of_one_le_padic_val_nat {n p : nat} (hp : 1 ≤ padic_val_nat p n) : + p ∣ n := +begin + by_contra h, + rw padic_val_nat.eq_zero_of_not_dvd h at hp, + exact lt_irrefl 0 (lt_of_lt_of_le zero_lt_one hp), +end + +lemma pow_padic_val_nat_dvd {p n : ℕ} [fact (nat.prime p)] : p ^ (padic_val_nat p n) ∣ n := +begin + cases nat.eq_zero_or_pos n with hn hn, + { rw hn, exact dvd_zero (p ^ padic_val_nat p 0) }, + { rw multiplicity.pow_dvd_iff_le_multiplicity, + apply le_of_eq, + rw padic_val_nat_def hn, + { apply enat.coe_get }, + { apply_instance } } +end + +lemma pow_succ_padic_val_nat_not_dvd {p n : ℕ} [hp : fact (nat.prime p)] (hn : 0 < n) : + ¬ p ^ (padic_val_nat p n + 1) ∣ n := +begin + rw multiplicity.pow_dvd_iff_le_multiplicity, + rw padic_val_nat_def hn, + { rw [nat.cast_add, enat.coe_get], + simp only [nat.cast_one, not_le], + exact enat.lt_add_one (ne_top_iff_finite.mpr + (finite_nat_iff.mpr ⟨(fact.elim hp).ne_one, hn⟩)), }, + { apply_instance } +end + +lemma padic_val_nat_dvd_iff (p : ℕ) [hp :fact p.prime] (n : ℕ) (a : ℕ) : + p^n ∣ a ↔ a = 0 ∨ n ≤ padic_val_nat p a := +begin + split, + { rw [pow_dvd_iff_le_multiplicity, padic_val_nat], + split_ifs, + { rw enat.coe_le_iff, + exact λ hn, or.inr (hn _) }, + { simp only [true_and, not_lt, ne.def, not_false_iff, nat.le_zero_iff, hp.out.ne_one] at h, + exact λ hn, or.inl h } }, + { rintro (rfl|h), + { exact dvd_zero (p ^ n) }, + { exact dvd_trans (pow_dvd_pow p h) pow_padic_val_nat_dvd } }, +end + +lemma padic_val_nat_primes {p q : ℕ} [p_prime : fact p.prime] [q_prime : fact q.prime] + (neq : p ≠ q) : padic_val_nat p q = 0 := +@padic_val_nat.eq_zero_of_not_dvd p q $ +(not_congr (iff.symm (prime_dvd_prime_iff_eq p_prime.1 q_prime.1))).mp neq + +protected lemma padic_val_nat.div' {p : ℕ} [p_prime : fact p.prime] : + ∀ {m : ℕ} (cpm : coprime p m) {b : ℕ} (dvd : m ∣ b), padic_val_nat p (b / m) = padic_val_nat p b +| 0 := λ cpm b dvd, by { rw zero_dvd_iff at dvd, rw [dvd, nat.zero_div], } +| (n + 1) := + λ cpm b dvd, + begin + rcases dvd with ⟨c, rfl⟩, + rw [mul_div_right c (nat.succ_pos _)],by_cases hc : c = 0, + { rw [hc, mul_zero] }, + { rw padic_val_nat.mul, + { suffices : ¬ p ∣ (n+1), + { rw [padic_val_nat.eq_zero_of_not_dvd this, zero_add] }, + contrapose! cpm, + exact p_prime.1.dvd_iff_not_coprime.mp cpm }, + { exact nat.succ_ne_zero _ }, + { exact hc } }, + end + +lemma padic_val_nat_eq_factorization (p n : ℕ) [hp : fact p.prime] : + padic_val_nat p n = n.factorization p := +begin + by_cases hn : n = 0, { subst hn, simp }, + rw @padic_val_nat_def p _ n (nat.pos_of_ne_zero hn), + simp [@multiplicity_eq_factorization n p hp.elim hn], +end + +open_locale big_operators + +lemma prod_pow_prime_padic_val_nat (n : nat) (hn : n ≠ 0) (m : nat) (pr : n < m) : + ∏ p in finset.filter nat.prime (finset.range m), p ^ (padic_val_nat p n) = n := +begin + nth_rewrite_rhs 0 ←factorization_prod_pow_eq_self hn, + rw eq_comm, + apply finset.prod_subset_one_on_sdiff, + { exact λ p hp, finset.mem_filter.mpr + ⟨finset.mem_range.mpr (gt_of_gt_of_ge pr (le_of_mem_factorization hp)), + prime_of_mem_factorization hp⟩ }, + { intros p hp, + cases finset.mem_sdiff.mp hp with hp1 hp2, + haveI := fact_iff.mpr (finset.mem_filter.mp hp1).2, + rw padic_val_nat_eq_factorization p n, + simp [finsupp.not_mem_support_iff.mp hp2] }, + { intros p hp, + haveI := fact_iff.mpr (prime_of_mem_factorization hp), + simp [padic_val_nat_eq_factorization] } +end + +lemma range_pow_padic_val_nat_subset_divisors {n : ℕ} (p : ℕ) [fact p.prime] (hn : n ≠ 0) : + (finset.range (padic_val_nat p n + 1)).image (pow p) ⊆ n.divisors := +begin + intros t ht, + simp only [exists_prop, finset.mem_image, finset.mem_range] at ht, + obtain ⟨k, hk, rfl⟩ := ht, + rw nat.mem_divisors, + exact ⟨(pow_dvd_pow p $ by linarith).trans pow_padic_val_nat_dvd, hn⟩ +end + +lemma range_pow_padic_val_nat_subset_divisors' {n : ℕ} (p : ℕ) [h : fact p.prime] : + (finset.range (padic_val_nat p n)).image (λ t, p ^ (t + 1)) ⊆ (n.divisors \ {1}) := +begin + rcases eq_or_ne n 0 with rfl | hn, + { simp }, + intros t ht, + simp only [exists_prop, finset.mem_image, finset.mem_range] at ht, + obtain ⟨k, hk, rfl⟩ := ht, + rw [finset.mem_sdiff, nat.mem_divisors], + refine ⟨⟨(pow_dvd_pow p $ by linarith).trans pow_padic_val_nat_dvd, hn⟩, _⟩, + rw [finset.mem_singleton], + nth_rewrite 1 ←one_pow (k + 1), + exact (nat.pow_lt_pow_of_lt_left h.1.one_lt $ nat.succ_pos k).ne', +end + +end padic_val_nat + +section padic_val_int +variables (p : ℕ) [p_prime : fact p.prime] + +lemma padic_val_int_dvd_iff (p : ℕ) [fact p.prime] (n : ℕ) (a : ℤ) : + ↑p^n ∣ a ↔ a = 0 ∨ n ≤ padic_val_int p a := +by rw [padic_val_int, ←int.nat_abs_eq_zero, ←padic_val_nat_dvd_iff, ←int.coe_nat_dvd_left, + int.coe_nat_pow] + +lemma padic_val_int_dvd (p : ℕ) [fact p.prime] (a : ℤ) : ↑p^(padic_val_int p a) ∣ a := +begin + rw padic_val_int_dvd_iff, + exact or.inr le_rfl, +end + +lemma padic_val_int_self (p : ℕ) [pp : fact p.prime] : padic_val_int p p = 1 := +padic_val_int.self pp.out.one_lt + +lemma padic_val_int.mul (p : ℕ) [fact p.prime] {a b : ℤ} (ha : a ≠ 0) (hb : b ≠ 0) : + padic_val_int p (a*b) = padic_val_int p a + padic_val_int p b := +begin + simp_rw padic_val_int, + rw [int.nat_abs_mul, padic_val_nat.mul]; + rwa int.nat_abs_ne_zero, +end + +lemma padic_val_int_mul_eq_succ (p : ℕ) [pp : fact p.prime] (a : ℤ) (ha : a ≠ 0) : + padic_val_int p (a * p) = (padic_val_int p a) + 1 := +begin + rw padic_val_int.mul p ha (int.coe_nat_ne_zero.mpr (pp.out).ne_zero), + simp only [eq_self_iff_true, padic_val_int.of_nat, padic_val_nat_self], +end + +end padic_val_int diff --git a/src/ring_theory/polynomial/cyclotomic/eval.lean b/src/ring_theory/polynomial/cyclotomic/eval.lean index 5b4d1cc1e15e5..7c74115b9a11e 100644 --- a/src/ring_theory/polynomial/cyclotomic/eval.lean +++ b/src/ring_theory/polynomial/cyclotomic/eval.lean @@ -7,7 +7,7 @@ Authors: Eric Rodriguez import ring_theory.polynomial.cyclotomic.basic import tactic.by_contra import topology.algebra.polynomial -import number_theory.padics.padic_norm +import number_theory.padics.padic_val /-! # Evaluating cyclotomic polynomials From 48997d7ba1de201cc296ec17d0174c82d1c3074b Mon Sep 17 00:00:00 2001 From: Floris van Doorn Date: Tue, 26 Apr 2022 22:05:34 +0000 Subject: [PATCH 284/373] fix(data/set/basic): fix name of `has_mem.mem.out` (#13721) --- src/data/set/basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/set/basic.lean b/src/data/set/basic.lean index 570a443d8d70f..e3312c00521ab 100644 --- a/src/data/set/basic.lean +++ b/src/data/set/basic.lean @@ -192,7 +192,7 @@ lemma mem_set_of {a : α} {p : α → Prop} : a ∈ {x | p x} ↔ p a := iff.rfl /-- If `h : a ∈ {x | p x}` then `h.out : p x`. These are definitionally equal, but this can nevertheless be useful for various reasons, e.g. to apply further projection notation or in an argument to `simp`. -/ -lemma has_mem.mem.out {p : α → Prop} {a : α} (h : a ∈ {x | p x}) : p a := h +lemma _root_.has_mem.mem.out {p : α → Prop} {a : α} (h : a ∈ {x | p x}) : p a := h theorem nmem_set_of_eq {a : α} {p : α → Prop} : a ∉ {x | p x} = ¬ p a := rfl From 79e309b7ef5310fdc2e8956f40f879fdb6f39b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Wed, 27 Apr 2022 00:04:48 +0000 Subject: [PATCH 285/373] feat(set_theory/game/pgame): Define `is_option` relation (#13700) --- src/set_theory/game/pgame.lean | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/set_theory/game/pgame.lean b/src/set_theory/game/pgame.lean index aacf78cb5ec15..d924f5070ab2f 100644 --- a/src/set_theory/game/pgame.lean +++ b/src/set_theory/game/pgame.lean @@ -155,6 +155,26 @@ Both this and `pgame.rec_on` describe Conway induction on games. -/ (IH : ∀ (y : pgame), (∀ i, C (y.move_left i)) → (∀ j, C (y.move_right j)) → C y) : C x := x.rec_on $ λ yl yr yL yR, IH (mk yl yr yL yR) +/-- `is_option x y` means that `x` is either a left or right option for `y`. -/ +@[mk_iff] inductive is_option : pgame → pgame → Prop +| move_left {x : pgame} (i : x.left_moves) : is_option (x.move_left i) x +| move_right {x : pgame} (i : x.right_moves) : is_option (x.move_right i) x + +theorem is_option.mk_left {xl xr : Type u} (xL : xl → pgame) (xR : xr → pgame) (i : xl) : + (xL i).is_option (mk xl xr xL xR) := +@is_option.move_left (mk _ _ _ _) i + +theorem is_option.mk_right {xl xr : Type u} (xL : xl → pgame) (xR : xr → pgame) (i : xr) : + (xR i).is_option (mk xl xr xL xR) := +@is_option.move_right (mk _ _ _ _) i + +theorem wf_is_option : well_founded is_option := +⟨λ x, move_rec_on x $ λ x IHl IHr, acc.intro x $ λ y h, begin + induction h with _ i _ j, + { exact IHl i }, + { exact IHr j } +end⟩ + /-- `subsequent p q` says that `p` can be obtained by playing some nonempty sequence of moves from `q`. -/ inductive subsequent : pgame → pgame → Prop From cb2b02fff213ed6f65bebd64446baac64137dcda Mon Sep 17 00:00:00 2001 From: antoinelab01 Date: Wed, 27 Apr 2022 02:01:16 +0000 Subject: [PATCH 286/373] feat(representation_theory/basic): representation theory without scalar actions (#13573) This PR rewrites the files `representation_theory/basic` and `representation_theory/invariants` so that they avoid making use of scalar actions. It also includes the new definitions and lemmas of PR #13502 written with this new approach. Co-authored-by: antoinelab01 <66086247+antoinelab01@users.noreply.github.com> --- src/representation_theory/basic.lean | 180 ++++++++++++++++------ src/representation_theory/invariants.lean | 73 ++++----- 2 files changed, 169 insertions(+), 84 deletions(-) diff --git a/src/representation_theory/basic.lean b/src/representation_theory/basic.lean index 40b5c4b1af4dd..1706c1e86bfcf 100644 --- a/src/representation_theory/basic.lean +++ b/src/representation_theory/basic.lean @@ -7,105 +7,199 @@ import algebra.module.basic import algebra.module.linear_map import algebra.monoid_algebra.basic import linear_algebra.trace +import linear_algebra.dual +import linear_algebra.free_module.basic /-! # Monoid representations -This file introduces monoid representations and their characters and proves basic lemmas about them, -including equivalences between different definitions of representations. +This file introduces monoid representations and their characters and defines a few ways to construct +representations. ## Main definitions - * `representation.as_module` - * `representation.as_group_hom` - * `representation.character` + * representation.representation + * representation.character + * representation.tprod + * representation.lin_hom + * represensation.dual ## Implementation notes -A representation of a monoid `G` over a commutative semiring `k` is implemented as a `k`-module `V` -together with a `distrib_mul_action G V` instance and a `smul_comm_class G k V` instance. +Representations of a monoid `G` on a `k`-module `V` are implemented as +homomorphisms `G →* (V →ₗ[k] V)`. +-/ + +open monoid_algebra (lift) (of) +open linear_map + +section +variables (k G V : Type*) [comm_semiring k] [monoid G] [add_comm_monoid V] [module k V] -Alternatively, one can use a monoid homomorphism `G →* (V →ₗ[k] V)`. The definitions `as_monoid_hom` -and `rep_space` allow to go back and forth between these two definitions. +/-- +A representation of `G` on the `k`-module `V` is an homomorphism `G →* (V →ₗ[k] V)`. -/ +abbreviation representation := G →* (V →ₗ[k] V) -open monoid_algebra +end namespace representation -section -variables (k G V : Type*) [comm_semiring k] [monoid G] [add_comm_monoid V] -variables [module k V] [distrib_mul_action G V] [smul_comm_class G k V] +section trivial + +variables {k G V : Type*} [comm_semiring k] [monoid G] [add_comm_monoid V] [module k V] + +/-- +The trivial representation of `G` on the one-dimensional module `k`. +-/ +def trivial : representation k G k := 1 + +@[simp] +lemma trivial_def (g : G) (v : k) : trivial g v = v := rfl + +end trivial + +section monoid_algebra + +variables {k G V : Type*} [comm_semiring k] [monoid G] [add_comm_monoid V] [module k V] +variables (ρ : representation k G V) /-- A `k`-linear representation of `G` on `V` can be thought of as an algebra map from `monoid_algebra k G` into the `k`-linear endomorphisms of `V`. -/ noncomputable def as_algebra_hom : monoid_algebra k G →ₐ[k] (module.End k V) := - (lift k G _) (distrib_mul_action.to_module_End k V) + (lift k G _) ρ lemma as_algebra_hom_def : - as_algebra_hom k G V = (lift k G _) (distrib_mul_action.to_module_End k V) := rfl + as_algebra_hom ρ = (lift k G _) ρ := rfl @[simp] lemma as_algebra_hom_single (g : G): - (as_algebra_hom k G V (finsupp.single g 1)) = (distrib_mul_action.to_module_End k V) g := -by simp [as_algebra_hom_def] + (as_algebra_hom ρ (finsupp.single g 1)) = ρ g := +by simp only [as_algebra_hom_def, monoid_algebra.lift_single, one_smul] + +lemma as_algebra_hom_of (g : G): + (as_algebra_hom ρ (of k G g)) = ρ g := +by simp only [monoid_algebra.of_apply, as_algebra_hom_single] /-- A `k`-linear representation of `G` on `V` can be thought of as a module over `monoid_algebra k G`. -/ -noncomputable instance as_module : module (monoid_algebra k G) V := - module.comp_hom V (as_algebra_hom k G V).to_ring_hom - -lemma as_module_apply (a : monoid_algebra k G) (v : V): - a • v = (as_algebra_hom k G V a) v := rfl - -lemma of_smul (g : G) (v : V) : - (of k G g) • v = g • v := by simp [as_module_apply] - -instance as_module_scalar_tower : is_scalar_tower k (monoid_algebra k G) V := -{ smul_assoc := λ r a v, by simp [as_module_apply] } +noncomputable def as_module : module (monoid_algebra k G) V := + module.comp_hom V (as_algebra_hom ρ).to_ring_hom -instance as_module_smul_comm : smul_comm_class k (monoid_algebra k G) V := -{ smul_comm := λ r a v, by simp [as_module_apply] } - -end +end monoid_algebra section group -variables (k G V : Type*) [comm_semiring k] [group G] [add_comm_monoid V] -variables [module k V] [distrib_mul_action G V] [smul_comm_class G k V] + +variables {k G V : Type*} [comm_semiring k] [group G] [add_comm_monoid V] [module k V] +variables (ρ : representation k G V) /-- When `G` is a group, a `k`-linear representation of `G` on `V` can be thought of as a group homomorphism from `G` into the invertible `k`-linear endomorphisms of `V`. -/ def as_group_hom : G →* units (V →ₗ[k] V) := - monoid_hom.to_hom_units (distrib_mul_action.to_module_End k V) + monoid_hom.to_hom_units ρ + +lemma as_group_hom_apply (g : G) : ↑(as_group_hom ρ g) = ρ g := +by simp only [as_group_hom, monoid_hom.coe_to_hom_units] end group section character -variables (k G V : Type*) [field k] [group G] [add_comm_group V] -variables [module k V] [distrib_mul_action G V] [smul_comm_class G k V] +variables {k G V : Type*} [comm_ring k] [group G] [add_comm_group V] [module k V] +variables (ρ : representation k G V) /-- The character associated to a representation of `G`, which as a map `G → k` sends each element to the trace of the corresponding linear map. -/ @[simp] -noncomputable def character (g : G) : k := -linear_map.trace k V (as_group_hom k G V g) +noncomputable def character (g : G) : k := trace k V (ρ g) -/-- The evaluation of the character at the identity is the dimension of the representation. -/ -theorem char_one [finite_dimensional k V] : character k G V 1 = finite_dimensional.finrank k V := -by simp +theorem char_mul_comm (g : G) (h : G) : character ρ (h * g) = character ρ (g * h) := +by simp only [trace_mul_comm, character, map_mul] /-- The character of a representation is constant on conjugacy classes. -/ -theorem char_conj (g : G) (h : G) : (character k G V) (h * g * h⁻¹) = (character k G V) g := by simp +theorem char_conj (g : G) (h : G) : (character ρ) (h * g * h⁻¹) = (character ρ) g := +by simp only [character, ←as_group_hom_apply, map_mul, map_inv, trace_conj] + +variables [nontrivial k] [module.free k V] [module.finite k V] + +/-- The evaluation of the character at the identity is the dimension of the representation. -/ +theorem char_one : character ρ 1 = finite_dimensional.finrank k V := +by simp only [character, map_one, trace_one] end character +section tensor_product + +variables {k G V W : Type*} [comm_semiring k] [monoid G] +variables [add_comm_monoid V] [module k V] [add_comm_monoid W] [module k W] +variables (ρV : representation k G V) (ρW : representation k G W) + +open_locale tensor_product + +/-- +Given representations of `G` on `V` and `W`, there is a natural representation of `G` on their +tensor product `V ⊗[k] W`. +-/ +def tprod : representation k G (V ⊗[k] W) := +{ to_fun := λ g, tensor_product.map (ρV g) (ρW g), + map_one' := by simp only [map_one, tensor_product.map_one], + map_mul' := λ g h, by simp only [map_mul, tensor_product.map_mul] } + +notation ρV ` ⊗ ` ρW := tprod ρV ρW + +@[simp] +lemma tprod_apply (g : G) : (ρV ⊗ ρW) g = tensor_product.map (ρV g) (ρW g) := rfl + +end tensor_product + +section linear_hom + +variables {k G V W : Type*} [comm_semiring k] [group G] +variables [add_comm_monoid V] [module k V] [add_comm_monoid W] [module k W] +variables (ρV : representation k G V) (ρW : representation k G W) + +/-- +Given representations of `G` on `V` and `W`, there is a natural representation of `G` on the +module `V →ₗ[k] W`, where `G` acts by conjugation. +-/ +def lin_hom : representation k G (V →ₗ[k] W) := +{ to_fun := λ g, + { to_fun := λ f, (ρW g) ∘ₗ f ∘ₗ (ρV g⁻¹), + map_add' := λ f₁ f₂, by simp only [add_comp, comp_add], + map_smul' := λ r f, by {ext, simp only [coe_comp, function.comp_app, smul_apply, map_smulₛₗ]} }, + map_one' := + by {ext, simp only [coe_comp, function.comp_app, map_one, one_inv, coe_mk, one_apply]}, + map_mul' := λ g h, by {ext, simp}} + +@[simp] +lemma lin_hom_apply (g : G) (f : V →ₗ[k] W) : (lin_hom ρV ρW) g f = (ρW g) ∘ₗ f ∘ₗ (ρV g⁻¹) := rfl + +/-- +The dual of a representation `ρ` of `G` on a module `V`, given by `(dual ρ) g f = f ∘ₗ (ρ g⁻¹)`, +where `f : module.dual k V`. +-/ +def dual : representation k G (module.dual k V) := +{ to_fun := λ g, + { to_fun := λ f, f ∘ₗ (ρV g⁻¹), + map_add' := λ f₁ f₂, by simp only [add_comp], + map_smul' := λ r f, + by {ext, simp only [coe_comp, function.comp_app, smul_apply, ring_hom.id_apply]} }, + map_one' := + by {ext, simp only [coe_comp, function.comp_app, map_one, one_inv, coe_mk, one_apply]}, + map_mul' := λ g h, + by {ext, simp only [coe_comp, function.comp_app, mul_inv_rev, map_mul, coe_mk, mul_apply]}} + +@[simp] +lemma dual_apply (g : G) (f : module.dual k V) : (dual ρV) g f = f ∘ₗ (ρV g⁻¹) := rfl + +end linear_hom + end representation diff --git a/src/representation_theory/invariants.lean b/src/representation_theory/invariants.lean index e2242c42837a5..53aad38978876 100644 --- a/src/representation_theory/invariants.lean +++ b/src/representation_theory/invariants.lean @@ -8,21 +8,20 @@ import representation_theory.basic /-! # Subspace of invariants a group representation -This file introduce the subspace of invariants of a group representation -and proves basic result about it. +This file introduces the subspace of invariants of a group representation +and proves basic results about it. The main tool used is the average of all elements of the group, seen as an element of -`monoid_algebra k G`. Scalar multiplication by this special element gives a projection onto the +`monoid_algebra k G`. The action of this special element gives a projection onto the subspace of invariants. In order for the definition of the average element to make sense, we need to assume for most of the results that the order of `G` is invertible in `k` (e. g. `k` has characteristic `0`). -/ open_locale big_operators -open monoid_algebra finset finite_dimensional linear_map representation +open monoid_algebra +open representation -namespace representation - -section average +namespace group_algebra variables (k G : Type*) [comm_semiring k] [group G] variables [fintype G] [invertible (fintype.card G : k)] @@ -63,61 +62,53 @@ begin rw function.bijective.sum_comp (group.mul_right_bijective g) _, end -end average +end group_algebra + +namespace representation -section invariants +open group_algebra -variables (k G V : Type*) [comm_semiring k] [group G] [add_comm_group V] -variables [module k V] [distrib_mul_action G V] [smul_comm_class G k V] +variables {k G V : Type*} [comm_semiring k] [group G] [add_comm_monoid V] [module k V] +variables (ρ : representation k G V) /-- The subspace of invariants, consisting of the vectors fixed by all elements of `G`. -/ def invariants : submodule k V := -{ carrier := set_of (λ v, ∀ (g : G), g • v = v), - zero_mem' := by simp only [forall_const, set.mem_set_of_eq, smul_zero], - add_mem' := λ v w hv hw g, by simp only [smul_add, add_left_inj, eq_self_iff_true, hv g, hw g], - smul_mem' := λ r v hv g, by simp only [eq_self_iff_true, smul_comm, hv g]} +{ carrier := set_of (λ v, ∀ (g : G), ρ g v = v), + zero_mem' := λ g, by simp only [map_zero], + add_mem' := λ v w hv hw g, by simp only [hv g, hw g, map_add], + smul_mem' := λ r v hv g, by simp only [hv g, linear_map.map_smulₛₗ, ring_hom.id_apply]} @[simp] -lemma mem_invariants (v : V) : v ∈ (invariants k G V) ↔ ∀ (g: G), g • v = v := by refl +lemma mem_invariants (v : V) : v ∈ invariants ρ ↔ ∀ (g: G), ρ g v = v := by refl lemma invariants_eq_inter : - (invariants k G V).carrier = ⋂ g : G, function.fixed_points (has_scalar.smul g) := -by { ext, simp [function.is_fixed_pt] } - -/-- -The subspace of invariants, as a submodule over `monoid_algebra k G`. --/ -noncomputable def invariants' : submodule (monoid_algebra k G) V := - submodule_of_smul_mem (invariants k G V) (λ g v hv, by {rw [of_smul, hv g], exact hv}) - -@[simp] lemma invariants'_carrier : - (invariants' k G V).carrier = (invariants k G V).carrier := rfl + (invariants ρ).carrier = ⋂ g : G, function.fixed_points (ρ g) := +by {ext, simp [function.is_fixed_pt]} variables [fintype G] [invertible (fintype.card G : k)] /-- -Scalar multiplication by `average k G` sends elements of `V` to the subspace of invariants. +The action of `average k G` gives a projection map onto the subspace of invariants. -/ -theorem smul_average_invariant (v : V) : (average k G) • v ∈ invariants k G V := -λ g, by rw [←of_smul k, smul_smul, of_apply, mul_average_left] +@[simp] +noncomputable def average_map : V →ₗ[k] V := as_algebra_hom ρ (average k G) /-- -`average k G` acts as the identity on the subspace of invariants. +The `average_map` sends elements of `V` to the subspace of invariants. -/ -theorem smul_average_id (v : V) (H : v ∈ invariants k G V) : (average k G) • v = v := -begin - rw [representation.mem_invariants] at H, - simp_rw [average_def, smul_assoc, finset.sum_smul, representation.of_smul, H, finset.sum_const, - finset.card_univ, nsmul_eq_smul_cast k _ v, smul_smul, inv_of_mul_self, one_smul], -end +theorem average_map_invariant (v : V) : average_map ρ v ∈ invariants ρ := +λ g, by rw [average_map, ←as_algebra_hom_single, ←linear_map.mul_apply, ←map_mul (as_algebra_hom ρ), + mul_average_left] /-- -Scalar multiplication by `average k G` gives a projection map onto the subspace of invariants. +The `average_map` acts as the identity on the subspace of invariants. -/ -noncomputable def average_map : V →ₗ[k] V := (as_algebra_hom k G V) (average k G) - -end invariants +theorem average_map_id (v : V) (hv : v ∈ invariants ρ) : average_map ρ v = v := +begin + rw mem_invariants at hv, + simp [average_def, map_sum, hv, finset.card_univ, nsmul_eq_smul_cast k _ v, smul_smul], +end end representation From 5ac5c922d3f1488f3bfbb5b2fc8b5516093ec0d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Wed, 27 Apr 2022 07:01:45 +0000 Subject: [PATCH 287/373] feat(combinatorics/simple_graph/regularity/uniform): Witnesses of non-uniformity (#13155) Provide ways to pick witnesses of non-uniformity. Co-authored-by: Bhavik Mehta --- .../simple_graph/regularity/uniform.lean | 117 ++++++++++++++++-- 1 file changed, 110 insertions(+), 7 deletions(-) diff --git a/src/combinatorics/simple_graph/regularity/uniform.lean b/src/combinatorics/simple_graph/regularity/uniform.lean index 0783e42f574de..b20705022b884 100644 --- a/src/combinatorics/simple_graph/regularity/uniform.lean +++ b/src/combinatorics/simple_graph/regularity/uniform.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies, Bhavik Mehta -/ import combinatorics.simple_graph.density +import set_theory.ordinal.basic /-! # Graph uniformity and uniform partitions @@ -23,8 +24,12 @@ is less than `ε`. ## Main declarations * `simple_graph.is_uniform`: Graph uniformity of a pair of finsets of vertices. +* `simple_graph.nonuniform_witness`: `G.nonuniform_witness ε s t` and `G.nonuniform_witness ε t s` + together witness the non-uniformity of `s` and `t`. * `finpartition.non_uniforms`: Non uniform pairs of parts of a partition. * `finpartition.is_uniform`: Uniformity of a partition. +* `finpartition.nonuniform_witnesses`: For each non-uniform pair of parts of a partition, pick + witnesses of non-uniformity and dump them all together. -/ open finset @@ -80,11 +85,89 @@ begin exact zero_lt_one, end +variables {G} + +lemma not_is_uniform_iff : + ¬ G.is_uniform ε s t ↔ ∃ s', s' ⊆ s ∧ ∃ t', t' ⊆ t ∧ ↑s.card * ε ≤ s'.card ∧ + ↑t.card * ε ≤ t'.card ∧ ε ≤ |G.edge_density s' t' - G.edge_density s t| := +by { unfold is_uniform, simp only [not_forall, not_lt, exists_prop] } + +open_locale classical +variables (G) + +/-- An arbitrary pair of subsets witnessing the non-uniformity of `(s, t)`. If `(s, t)` is uniform, +returns `(s, t)`. Witnesses for `(s, t)` and `(t, s)` don't necessarily match. See +`simple_graph.nonuniform_witness`. -/ +noncomputable def nonuniform_witnesses (ε : 𝕜) (s t : finset α) : finset α × finset α := +if h : ¬ G.is_uniform ε s t + then ((not_is_uniform_iff.1 h).some, (not_is_uniform_iff.1 h).some_spec.2.some) + else (s, t) + +lemma left_nonuniform_witnesses_subset (h : ¬ G.is_uniform ε s t) : + (G.nonuniform_witnesses ε s t).1 ⊆ s := +by { rw [nonuniform_witnesses, dif_pos h], exact (not_is_uniform_iff.1 h).some_spec.1 } + +lemma left_nonuniform_witnesses_card (h : ¬ G.is_uniform ε s t) : + (s.card : 𝕜) * ε ≤ (G.nonuniform_witnesses ε s t).1.card := +by { rw [nonuniform_witnesses, dif_pos h], + exact (not_is_uniform_iff.1 h).some_spec.2.some_spec.2.1 } + +lemma right_nonuniform_witnesses_subset (h : ¬ G.is_uniform ε s t) : + (G.nonuniform_witnesses ε s t).2 ⊆ t := +by { rw [nonuniform_witnesses, dif_pos h], exact (not_is_uniform_iff.1 h).some_spec.2.some_spec.1 } + +lemma right_nonuniform_witnesses_card (h : ¬ G.is_uniform ε s t) : + (t.card : 𝕜) * ε ≤ (G.nonuniform_witnesses ε s t).2.card := +by { rw [nonuniform_witnesses, dif_pos h], + exact (not_is_uniform_iff.1 h).some_spec.2.some_spec.2.2.1 } + +lemma nonuniform_witnesses_spec (h : ¬ G.is_uniform ε s t) : + ε ≤ |G.edge_density (G.nonuniform_witnesses ε s t).1 (G.nonuniform_witnesses ε s t).2 + - G.edge_density s t| := +by { rw [nonuniform_witnesses, dif_pos h], + exact (not_is_uniform_iff.1 h).some_spec.2.some_spec.2.2.2 } + +/-- Arbitrary witness of non-uniformity. `G.nonuniform_witness ε s t` and +`G.nonuniform_witness ε t s` form a pair of subsets witnessing the non-uniformity of `(s, t)`. If +`(s, t)` is uniform, returns `s`. -/ +noncomputable def nonuniform_witness (ε : 𝕜) (s t : finset α) : finset α := +if well_ordering_rel s t then (G.nonuniform_witnesses ε s t).1 else (G.nonuniform_witnesses ε t s).2 + +lemma nonuniform_witness_subset (h : ¬ G.is_uniform ε s t) : G.nonuniform_witness ε s t ⊆ s := +begin + unfold nonuniform_witness, + split_ifs, + { exact G.left_nonuniform_witnesses_subset h }, + { exact G.right_nonuniform_witnesses_subset (λ i, h i.symm) } +end + +lemma nonuniform_witness_card_le (h : ¬ G.is_uniform ε s t) : + (s.card : 𝕜) * ε ≤ (G.nonuniform_witness ε s t).card := +begin + unfold nonuniform_witness, + split_ifs, + { exact G.left_nonuniform_witnesses_card h }, + { exact G.right_nonuniform_witnesses_card (λ i, h i.symm) } +end + +lemma nonuniform_witness_spec (h₁ : s ≠ t) (h₂ : ¬ G.is_uniform ε s t) : + ε ≤ |G.edge_density (G.nonuniform_witness ε s t) (G.nonuniform_witness ε t s) + - G.edge_density s t| := +begin + unfold nonuniform_witness, + rcases trichotomous_of well_ordering_rel s t with lt | rfl | gt, + { rw [if_pos lt, if_neg (asymm lt)], + exact G.nonuniform_witnesses_spec h₂ }, + { cases h₁ rfl }, + { rw [if_neg (asymm gt), if_pos gt, edge_density_comm, edge_density_comm _ s], + apply G.nonuniform_witnesses_spec (λ i, h₂ i.symm) } +end + end simple_graph /-! ### Uniform partitions -/ -variables [decidable_eq α] {s : finset α} (P : finpartition s) (G : simple_graph α) +variables [decidable_eq α] {A : finset α} (P : finpartition A) (G : simple_graph α) [decidable_rel G.adj] {ε : 𝕜} namespace finpartition @@ -99,12 +182,10 @@ lemma mk_mem_non_uniforms_iff (u v : finset α) (ε : 𝕜) : (u, v) ∈ P.non_uniforms G ε ↔ u ∈ P.parts ∧ v ∈ P.parts ∧ u ≠ v ∧ ¬G.is_uniform ε u v := by rw [non_uniforms, mem_filter, mem_off_diag, and_assoc, and_assoc] -/-- A finpartition is `ε`-uniform (aka `ε`-regular) iff at most a proportion of `ε` of its pairs of -parts are not `ε-uniform`. -/ -def is_uniform (ε : 𝕜) : Prop := -((P.non_uniforms G ε).card : 𝕜) ≤ (P.parts.card * (P.parts.card - 1) : ℕ) * ε +lemma non_uniforms_mono {ε ε' : 𝕜} (h : ε ≤ ε') : P.non_uniforms G ε' ⊆ P.non_uniforms G ε := +monotone_filter_right _ $ λ uv, mt $ simple_graph.is_uniform.mono h -lemma non_uniforms_bot (hε : 0 < ε) : (⊥ : finpartition s).non_uniforms G ε = ∅ := +lemma non_uniforms_bot (hε : 0 < ε) : (⊥ : finpartition A).non_uniforms G ε = ∅ := begin rw eq_empty_iff_forall_not_mem, rintro ⟨u, v⟩, @@ -114,7 +195,12 @@ begin exact G.is_uniform_singleton hε, end -lemma bot_is_uniform (hε : 0 < ε) : (⊥ : finpartition s).is_uniform G ε := +/-- A finpartition of a graph's vertex set is `ε`-uniform (aka `ε`-regular) iff the proportion of +its pairs of parts that are not `ε`-uniform is at most `ε`. -/ +def is_uniform (ε : 𝕜) : Prop := +((P.non_uniforms G ε).card : 𝕜) ≤ (P.parts.card * (P.parts.card - 1) : ℕ) * ε + +lemma bot_is_uniform (hε : 0 < ε) : (⊥ : finpartition A).is_uniform G ε := begin rw [finpartition.is_uniform, finpartition.card_bot, non_uniforms_bot _ hε, finset.card_empty, nat.cast_zero], @@ -130,10 +216,27 @@ end variables {P G} +lemma is_uniform.mono {ε ε' : 𝕜} (hP : P.is_uniform G ε) (h : ε ≤ ε') : P.is_uniform G ε' := +((nat.cast_le.2 $ card_le_of_subset $ P.non_uniforms_mono G h).trans hP).trans $ + mul_le_mul_of_nonneg_left h $ nat.cast_nonneg _ + lemma is_uniform_of_empty (hP : P.parts = ∅) : P.is_uniform G ε := by simp [is_uniform, hP, non_uniforms] lemma nonempty_of_not_uniform (h : ¬ P.is_uniform G ε) : P.parts.nonempty := nonempty_of_ne_empty $ λ h₁, h $ is_uniform_of_empty h₁ +variables (P G ε) (s : finset α) + +/-- A choice of witnesses of non-uniformity among the parts of a finpartition. -/ +noncomputable def nonuniform_witnesses : finset (finset α) := +(P.parts.filter $ λ t, s ≠ t ∧ ¬ G.is_uniform ε s t).image (G.nonuniform_witness ε s) + +variables {P G ε s} {t : finset α} + +lemma nonuniform_witness_mem_nonuniform_witnesses (h : ¬ G.is_uniform ε s t) (ht : t ∈ P.parts) + (hst : s ≠ t) : + G.nonuniform_witness ε s t ∈ P.nonuniform_witnesses G ε s := +mem_image_of_mem _ $ mem_filter.2 ⟨ht, hst, h⟩ + end finpartition From ccefda0766e9ea44e6d4f59e0dc857190900e425 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Wed, 27 Apr 2022 10:54:41 +0000 Subject: [PATCH 288/373] perf(representation_theory/basic): speed up `representation.lin_hom` by a factor of 20 (#13739) `ext` was over-expanding, and the `simp`s were not all squeezed. This is causing timeouts in other PRs. --- src/representation_theory/basic.lean | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/representation_theory/basic.lean b/src/representation_theory/basic.lean index 1706c1e86bfcf..a3c22e6f7e513 100644 --- a/src/representation_theory/basic.lean +++ b/src/representation_theory/basic.lean @@ -173,12 +173,13 @@ module `V →ₗ[k] W`, where `G` acts by conjugation. def lin_hom : representation k G (V →ₗ[k] W) := { to_fun := λ g, { to_fun := λ f, (ρW g) ∘ₗ f ∘ₗ (ρV g⁻¹), - map_add' := λ f₁ f₂, by simp only [add_comp, comp_add], - map_smul' := λ r f, by {ext, simp only [coe_comp, function.comp_app, smul_apply, map_smulₛₗ]} }, - map_one' := - by {ext, simp only [coe_comp, function.comp_app, map_one, one_inv, coe_mk, one_apply]}, - map_mul' := λ g h, by {ext, simp}} - + map_add' := λ f₁ f₂, by simp_rw [add_comp, comp_add], + map_smul' := λ r f, by simp_rw [ring_hom.id_apply, smul_comp, comp_smul]}, + map_one' := linear_map.ext $ λ x, + by simp_rw [coe_mk, one_inv, map_one, one_apply, one_eq_id, comp_id, id_comp], + map_mul' := λ g h, linear_map.ext $ λ x, + by simp_rw [coe_mul, coe_mk, function.comp_apply, mul_inv_rev, map_mul, mul_eq_comp, + comp_assoc ]} @[simp] lemma lin_hom_apply (g : G) (f : V →ₗ[k] W) : (lin_hom ρV ρW) g f = (ρW g) ∘ₗ f ∘ₗ (ρV g⁻¹) := rfl From d3997443e6fc4766e6275f1196b11131bf75f865 Mon Sep 17 00:00:00 2001 From: kkytola Date: Wed, 27 Apr 2022 14:57:36 +0000 Subject: [PATCH 289/373] feat(measure_theory/measure/finite_measure_weak_convergence): define the topology of weak convergence of measures and prove some lemmas about it. (#9943) This PR has the definition of the topology of weak convergence ("convergence in law" / "convergence in distribution") on `finite_measure _` and on `probability_measure _`. Co-authored-by: kkytola <39528102+kkytola@users.noreply.github.com> --- .../finite_measure_weak_convergence.lean | 158 ++++++++++++------ src/topology/algebra/module/weak_dual.lean | 6 + 2 files changed, 117 insertions(+), 47 deletions(-) diff --git a/src/measure_theory/measure/finite_measure_weak_convergence.lean b/src/measure_theory/measure/finite_measure_weak_convergence.lean index 08b3896ee96ea..af7c74d2b256c 100644 --- a/src/measure_theory/measure/finite_measure_weak_convergence.lean +++ b/src/measure_theory/measure/finite_measure_weak_convergence.lean @@ -11,14 +11,12 @@ import topology.algebra.module.weak_dual /-! # Weak convergence of (finite) measures -This file will define the topology of weak convergence of finite measures and probability measures +This file defines the topology of weak convergence of finite measures and probability measures on topological spaces. The topology of weak convergence is the coarsest topology w.r.t. which for every bounded continuous `ℝ≥0`-valued function `f`, the integration of `f` against the measure is continuous. TODOs: -* Define the topologies (the current version only defines the types) via - `weak_dual ℝ≥0 (α →ᵇ ℝ≥0)`. * Prove that an equivalent definition of the topologies is obtained requiring continuity of integration of bounded continuous `ℝ`-valued functions instead. * Include the portmanteau theorem on characterizations of weak convergence of (Borel) probability @@ -27,20 +25,21 @@ TODOs: ## Main definitions The main definitions are the - * types `finite_measure α` and `probability_measure α`; - * `to_weak_dual_bounded_continuous_nnreal : finite_measure α → (weak_dual ℝ≥0 (α →ᵇ ℝ≥0))` + * types `finite_measure α` and `probability_measure α` with topologies of weak convergence; + * `to_weak_dual_bcnn : finite_measure α → (weak_dual ℝ≥0 (α →ᵇ ℝ≥0))` allowing to interpret a finite measure as a continuous linear functional on the space of - bounded continuous nonnegative functions on `α`. This will be used for the definition of the + bounded continuous nonnegative functions on `α`. This is used for the definition of the topology of weak convergence. -TODO: -* Define the topologies on the above types. - ## Main results * Finite measures `μ` on `α` give rise to continuous linear functionals on the space of bounded continuous nonnegative functions on `α` via integration: - `to_weak_dual_of_bounded_continuous_nnreal : finite_measure α → (weak_dual ℝ≥0 (α →ᵇ ℝ≥0))`. + `to_weak_dual_bcnn : finite_measure α → (weak_dual ℝ≥0 (α →ᵇ ℝ≥0))`. + * `tendsto_iff_forall_lintegral_tendsto`: Convergence of finite measures and probability measures + is characterized by the convergence of integrals of all bounded continuous (nonnegative) + functions. This essentially shows that the given definition of topology corresponds to the + common textbook definition of weak convergence of measures. TODO: * Portmanteau theorem. @@ -230,7 +229,7 @@ begin simp only [←ennreal.coe_eq_coe, bounded_continuous_function.coe_smul, test_against_nn_coe_eq, ennreal.coe_smul], simp_rw [←smul_one_smul ℝ≥0∞ c (f _ : ℝ≥0∞), ←smul_one_smul ℝ≥0∞ c (lintegral _ _ : ℝ≥0∞), - smul_eq_mul], + smul_eq_mul], exact @lintegral_const_mul _ _ (μ : measure α) (c • 1) _ (bounded_continuous_function.nnreal.to_ennreal_comp_measurable f), end @@ -279,13 +278,57 @@ end /-- Finite measures yield elements of the `weak_dual` of bounded continuous nonnegative functions via `finite_measure.test_against_nn`, i.e., integration. -/ -def to_weak_dual_bounded_continuous_nnreal (μ : finite_measure α) : +def to_weak_dual_bcnn (μ : finite_measure α) : weak_dual ℝ≥0 (α →ᵇ ℝ≥0) := { to_fun := λ f, μ.test_against_nn f, map_add' := test_against_nn_add μ, map_smul' := test_against_nn_smul μ, cont := μ.test_against_nn_lipschitz.continuous, } +@[simp] lemma coe_to_weak_dual_bcnn (μ : finite_measure α) : + ⇑μ.to_weak_dual_bcnn = μ.test_against_nn := rfl + +@[simp] lemma to_weak_dual_bcnn_apply (μ : finite_measure α) (f : α →ᵇ ℝ≥0) : + μ.to_weak_dual_bcnn f = (∫⁻ x, f x ∂(μ : measure α)).to_nnreal := rfl + +/-- The topology of weak convergence on `finite_measures α` is inherited (induced) from the weak-* +topology on `weak_dual ℝ≥0 (α →ᵇ ℝ≥0)` via the function `finite_measures.to_weak_dual_bcnn`. -/ +instance : topological_space (finite_measure α) := +topological_space.induced to_weak_dual_bcnn infer_instance + +lemma to_weak_dual_bcnn_continuous : + continuous (@finite_measure.to_weak_dual_bcnn α _ _ _) := +continuous_induced_dom + +/- Integration of (nonnegative bounded continuous) test functions against finite Borel measures +depends continuously on the measure. -/ +lemma continuous_test_against_nn_eval (f : α →ᵇ ℝ≥0) : + continuous (λ (μ : finite_measure α), μ.test_against_nn f) := +(by apply (eval_continuous _ _).comp to_weak_dual_bcnn_continuous : + continuous ((λ φ : weak_dual ℝ≥0 (α →ᵇ ℝ≥0), φ f) ∘ to_weak_dual_bcnn)) + +lemma tendsto_iff_weak_star_tendsto {γ : Type*} {F : filter γ} + {μs : γ → finite_measure α} {μ : finite_measure α} : + tendsto μs F (𝓝 μ) ↔ tendsto (λ i, (μs(i)).to_weak_dual_bcnn) F (𝓝 μ.to_weak_dual_bcnn) := +inducing.tendsto_nhds_iff ⟨rfl⟩ + +theorem tendsto_iff_forall_test_against_nn_tendsto {γ : Type*} {F : filter γ} + {μs : γ → finite_measure α} {μ : finite_measure α} : + tendsto μs F (𝓝 μ) ↔ + ∀ (f : α →ᵇ ℝ≥0), tendsto (λ i, (μs(i)).to_weak_dual_bcnn f) F (𝓝 (μ.to_weak_dual_bcnn f)) := +by { rw [tendsto_iff_weak_star_tendsto, tendsto_iff_forall_eval_tendsto_top_dual_pairing], refl, } + +theorem tendsto_iff_forall_lintegral_tendsto {γ : Type*} {F : filter γ} + {μs : γ → finite_measure α} {μ : finite_measure α} : + tendsto μs F (𝓝 μ) ↔ + ∀ (f : α →ᵇ ℝ≥0), + tendsto (λ i, (∫⁻ x, (f x) ∂(μs(i) : measure α))) F (𝓝 ((∫⁻ x, (f x) ∂(μ : measure α)))) := +begin + rw tendsto_iff_forall_test_against_nn_tendsto, + simp_rw [to_weak_dual_bcnn_apply _ _, ←test_against_nn_coe_eq, + ennreal.tendsto_coe, ennreal.to_nnreal_coe], +end + end finite_measure /-- Probability measures are defined as the subtype of measures that have the property of being @@ -336,52 +379,73 @@ by { rw [← coe_fn_comp_to_finite_measure_eq_coe_fn, variables [topological_space α] -/-- The pairing of a (Borel) probability measure `μ` with a nonnegative bounded continuous -function is obtained by (Lebesgue) integrating the (test) function against the measure. This -is `probability_measure.test_against_nn`. -/ -def test_against_nn - (μ : probability_measure α) (f : α →ᵇ ℝ≥0) : ℝ≥0 := -(lintegral (μ : measure α) ((coe : ℝ≥0 → ℝ≥0∞) ∘ f)).to_nnreal - lemma lintegral_lt_top_of_bounded_continuous_to_nnreal (μ : probability_measure α) (f : α →ᵇ ℝ≥0) : ∫⁻ x, f x ∂(μ : measure α) < ∞ := μ.to_finite_measure.lintegral_lt_top_of_bounded_continuous_to_nnreal f -@[simp] lemma test_against_nn_coe_eq {μ : probability_measure α} {f : α →ᵇ ℝ≥0} : - (μ.test_against_nn f : ℝ≥0∞) = ∫⁻ x, f x ∂(μ : measure α) := -ennreal.coe_to_nnreal (lintegral_lt_top_of_bounded_continuous_to_nnreal μ f).ne - -@[simp] lemma to_finite_measure_test_against_nn_eq_test_against_nn - {μ : probability_measure α} {f : α →ᵇ nnreal} : - μ.to_finite_measure.test_against_nn f = μ.test_against_nn f := rfl +variables [opens_measurable_space α] -lemma test_against_nn_const (μ : probability_measure α) (c : ℝ≥0) : - μ.test_against_nn (bounded_continuous_function.const α c) = c := -by simp [← ennreal.coe_eq_coe, (measure_theory.is_probability_measure μ).measure_univ] +lemma test_against_nn_lipschitz (μ : probability_measure α) : + lipschitz_with 1 (λ (f : α →ᵇ ℝ≥0), μ.to_finite_measure.test_against_nn f) := +μ.mass_to_finite_measure ▸ μ.to_finite_measure.test_against_nn_lipschitz -lemma test_against_nn_mono (μ : probability_measure α) - {f g : α →ᵇ ℝ≥0} (f_le_g : (f : α → ℝ≥0) ≤ g) : - μ.test_against_nn f ≤ μ.test_against_nn g := -by simpa using μ.to_finite_measure.test_against_nn_mono f_le_g +/-- The topology of weak convergence on `probability_measures α`. This is inherited (induced) from +the weak-* topology on `weak_dual ℝ≥0 (α →ᵇ ℝ≥0)` via the function +`probability_measures.to_weak_dual_bcnn`. -/ +instance : topological_space (probability_measure α) := +topological_space.induced to_finite_measure infer_instance -variables [opens_measurable_space α] +lemma to_finite_measure_continuous : + continuous (to_finite_measure : probability_measure α → finite_measure α) := +continuous_induced_dom -lemma test_against_nn_lipschitz (μ : probability_measure α) : - lipschitz_with 1 (λ (f : α →ᵇ ℝ≥0), μ.test_against_nn f) := +/-- Probability measures yield elements of the `weak_dual` of bounded continuous nonnegative +functions via `finite_measure.test_against_nn`, i.e., integration. -/ +def to_weak_dual_bcnn : probability_measure α → weak_dual ℝ≥0 (α →ᵇ ℝ≥0) := +finite_measure.to_weak_dual_bcnn ∘ to_finite_measure + +@[simp] lemma coe_to_weak_dual_bcnn (μ : probability_measure α) : + ⇑μ.to_weak_dual_bcnn = μ.to_finite_measure.test_against_nn := rfl + +@[simp] lemma to_weak_dual_bcnn_apply (μ : probability_measure α) (f : α →ᵇ ℝ≥0) : + μ.to_weak_dual_bcnn f = (∫⁻ x, f x ∂(μ : measure α)).to_nnreal := rfl + +lemma to_weak_dual_bcnn_continuous : + continuous (λ (μ : probability_measure α), μ.to_weak_dual_bcnn) := +finite_measure.to_weak_dual_bcnn_continuous.comp to_finite_measure_continuous + +/- Integration of (nonnegative bounded continuous) test functions against Borel probability +measures depends continuously on the measure. -/ +lemma continuous_test_against_nn_eval (f : α →ᵇ ℝ≥0) : + continuous (λ (μ : probability_measure α), μ.to_finite_measure.test_against_nn f) := +(finite_measure.continuous_test_against_nn_eval f).comp to_finite_measure_continuous + +/- The canonical mapping from probability measures to finite measures is an embedding. -/ +lemma to_finite_measure_embedding (α : Type*) + [measurable_space α] [topological_space α] [opens_measurable_space α] : + embedding (to_finite_measure : probability_measure α → finite_measure α) := +{ induced := rfl, + inj := λ μ ν h, subtype.eq (by convert congr_arg coe h) } + +lemma tendsto_nhds_iff_to_finite_measures_tendsto_nhds {δ : Type*} + (F : filter δ) {μs : δ → probability_measure α} {μ₀ : probability_measure α} : + tendsto μs F (𝓝 μ₀) ↔ tendsto (to_finite_measure ∘ μs) F (𝓝 (μ₀.to_finite_measure)) := +embedding.tendsto_nhds_iff (probability_measure.to_finite_measure_embedding α) + +/-- The usual definition of weak convergence of probability measures is given in terms of sequences +of probability measures: it is the requirement that the integrals of all continuous bounded +functions against members of the sequence converge. This version is a characterization using +nonnegative bounded continuous functions. -/ +theorem tendsto_iff_forall_lintegral_tendsto {γ : Type*} {F : filter γ} + {μs : γ → probability_measure α} {μ : probability_measure α} : + tendsto μs F (𝓝 μ) ↔ + ∀ (f : α →ᵇ ℝ≥0), tendsto (λ i, (∫⁻ x, (f x) ∂(μs(i) : measure α))) F + (𝓝 ((∫⁻ x, (f x) ∂(μ : measure α)))) := begin - have key := μ.to_finite_measure.test_against_nn_lipschitz, - rwa μ.mass_to_finite_measure at key, + rw tendsto_nhds_iff_to_finite_measures_tendsto_nhds, + exact finite_measure.tendsto_iff_forall_lintegral_tendsto, end -/-- Probability measures yield elements of the `weak_dual` of bounded continuous nonnegative -functions via `probability_measure.test_against_nn`, i.e., integration. -/ -def to_weak_dual_bounded_continuous_nnreal (μ : probability_measure α) : - weak_dual ℝ≥0 (α →ᵇ ℝ≥0) := -{ to_fun := λ f, μ.test_against_nn f, - map_add' := μ.to_finite_measure.test_against_nn_add, - map_smul' := μ.to_finite_measure.test_against_nn_smul, - cont := μ.test_against_nn_lipschitz.continuous, } - end probability_measure end measure_theory diff --git a/src/topology/algebra/module/weak_dual.lean b/src/topology/algebra/module/weak_dual.lean index c96857adf1278..8adef9c5d0840 100644 --- a/src/topology/algebra/module/weak_dual.lean +++ b/src/topology/algebra/module/weak_dual.lean @@ -224,4 +224,10 @@ def weak_space (𝕜 E) [comm_semiring 𝕜] [topological_space 𝕜] [has_conti [has_continuous_const_smul 𝕜 𝕜] [add_comm_monoid E] [module 𝕜 E] [topological_space E] := weak_bilin (top_dual_pairing 𝕜 E).flip +theorem tendsto_iff_forall_eval_tendsto_top_dual_pairing + {l : filter α} {f : α → weak_dual 𝕜 E} {x : weak_dual 𝕜 E} : + tendsto f l (𝓝 x) ↔ + ∀ y, tendsto (λ i, top_dual_pairing 𝕜 E (f i) y) l (𝓝 (top_dual_pairing 𝕜 E x y)) := +tendsto_iff_forall_eval_tendsto _ continuous_linear_map.coe_injective + end weak_star_topology From dc589c890576488ae0df5d62a389aa49ca507938 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Wed, 27 Apr 2022 15:34:59 +0000 Subject: [PATCH 290/373] fix(topology/bornology): turn `bounded_space` into a `mixin` (#13615) Otherwise, we would need `bounded_pseudo_metric_space`, `bounded_metric_space` etc. Also add `set.finite.is_bounded`, `bornology.is_bounded.all`, and `bornology.is_bounded_univ`. --- src/topology/bornology/basic.lean | 34 +++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/topology/bornology/basic.lean b/src/topology/bornology/basic.lean index b24cfe09962a4..c3aeef4234909 100644 --- a/src/topology/bornology/basic.lean +++ b/src/topology/bornology/basic.lean @@ -99,10 +99,10 @@ lemma is_cobounded_def {s : set α} : is_cobounded s ↔ s ∈ cobounded α := i lemma is_bounded_def {s : set α} : is_bounded s ↔ sᶜ ∈ cobounded α := iff.rfl -@[simp] lemma is_bounded_compl_iff {s : set α} : is_bounded sᶜ ↔ is_cobounded s := +@[simp] lemma is_bounded_compl_iff : is_bounded sᶜ ↔ is_cobounded s := by rw [is_bounded_def, is_cobounded_def, compl_compl] -@[simp] lemma is_cobounded_compl_iff {s : set α} : is_cobounded sᶜ ↔ is_bounded s := iff.rfl +@[simp] lemma is_cobounded_compl_iff : is_cobounded sᶜ ↔ is_bounded s := iff.rfl alias is_bounded_compl_iff ↔ bornology.is_bounded.of_compl bornology.is_cobounded.compl alias is_cobounded_compl_iff ↔ bornology.is_cobounded.of_compl bornology.is_bounded.compl @@ -202,6 +202,11 @@ by rw [← sUnion_range, is_bounded_sUnion (finite_range s), forall_range_iff] end bornology +open bornology + +lemma set.finite.is_bounded [bornology α] {s : set α} (hs : s.finite) : is_bounded s := +bornology.le_cofinite α hs.compl_mem_cofinite + instance : bornology punit := ⟨⊥, bot_le⟩ /-- The cofinite filter as a bornology -/ @@ -209,6 +214,27 @@ instance : bornology punit := ⟨⊥, bot_le⟩ { cobounded := cofinite, le_cofinite := le_rfl } -/-- A **bounded space** is a `bornology α` such that `set.univ : set α` is bounded. -/ -class bounded_space extends bornology α := +/-- A space with a `bornology` is a **bounded space** if `set.univ : set α` is bounded. -/ +class bounded_space (α : Type*) [bornology α] : Prop := (bounded_univ : bornology.is_bounded (univ : set α)) + +namespace bornology + +variables [bornology α] + +lemma is_bounded_univ : is_bounded (univ : set α) ↔ bounded_space α := +⟨λ h, ⟨h⟩, λ h, h.1⟩ + +lemma cobounded_eq_bot_iff : cobounded α = ⊥ ↔ bounded_space α := +by rw [← is_bounded_univ, is_bounded_def, compl_univ, empty_mem_iff_bot] + +variables [bounded_space α] + +lemma is_bounded.all (s : set α) : is_bounded s := bounded_space.bounded_univ.subset s.subset_univ +lemma is_cobounded.all (s : set α) : is_cobounded s := compl_compl s ▸ is_bounded.all sᶜ + +variable (α) + +@[simp] lemma cobounded_eq_bot : cobounded α = ⊥ := cobounded_eq_bot_iff.2 ‹_› + +end bornology From 60bb07118896ff5d58e2e4332fcf2b4077024f5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Wed, 27 Apr 2022 20:32:15 +0000 Subject: [PATCH 291/373] feat(logic/unit): Make `punit.star` simp normal form of `default : punit` (#13741) --- src/logic/unique.lean | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/logic/unique.lean b/src/logic/unique.lean index 5fbb0306c86b5..bafbd62abe354 100644 --- a/src/logic/unique.lean +++ b/src/logic/unique.lean @@ -75,6 +75,8 @@ instance punit.unique : unique punit.{u} := { default := punit.star, uniq := λ x, punit_eq x _ } +@[simp] lemma punit.default_eq_star : (default : punit) = punit.star := rfl + /-- Every provable proposition is unique, as all proofs are equal. -/ def unique_prop {p : Prop} (h : p) : unique p := { default := h, uniq := λ x, rfl } From e89510c24deb6d9c5f9cb728cb3e599dcf93b104 Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Wed, 27 Apr 2022 23:52:26 +0000 Subject: [PATCH 292/373] fix(ring_theory/subsemiring/basic): make `inclusion` a `ring_hom`, not a `monoid_hom` (#13746) --- src/ring_theory/subsemiring/basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ring_theory/subsemiring/basic.lean b/src/ring_theory/subsemiring/basic.lean index 2812504064041..421d0d9bf962e 100644 --- a/src/ring_theory/subsemiring/basic.lean +++ b/src/ring_theory/subsemiring/basic.lean @@ -873,7 +873,7 @@ namespace subsemiring open ring_hom /-- The ring homomorphism associated to an inclusion of subsemirings. -/ -def inclusion {S T : subsemiring R} (h : S ≤ T) : S →* T := +def inclusion {S T : subsemiring R} (h : S ≤ T) : S →+* T := S.subtype.cod_srestrict _ (λ x, h x.2) @[simp] lemma srange_subtype (s : subsemiring R) : s.subtype.srange = s := From a0af1474a0b493b7104c6c02e56b4d83622b1eff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Thu, 28 Apr 2022 07:28:19 +0000 Subject: [PATCH 293/373] feat(set_theory/game/pgame): An empty game is a relabelling of `0` (#13753) --- src/set_theory/game/pgame.lean | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/set_theory/game/pgame.lean b/src/set_theory/game/pgame.lean index d924f5070ab2f..dbc868d18762e 100644 --- a/src/set_theory/game/pgame.lean +++ b/src/set_theory/game/pgame.lean @@ -619,6 +619,11 @@ begin { intro j, simpa using (R_relabelling₁ _).trans (R_relabelling₂ _) }, end +/-- Any game without left or right moves is a relabelling of 0. -/ +def relabelling.is_empty (x : pgame) [is_empty (x.left_moves)] [is_empty (x.right_moves)] : + relabelling x 0 := +⟨equiv.equiv_pempty _, equiv.equiv_pempty _, is_empty_elim, is_empty_elim⟩ + theorem relabelling.le {x y : pgame} (r : relabelling x y) : x ≤ y := r.restricted.le From 98e78488c37615ba756a0181e572dce51f79d64d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Thu, 28 Apr 2022 08:07:57 +0000 Subject: [PATCH 294/373] feat(set_theory/game/pgame): Right moves of nat game are empty (#13730) --- src/set_theory/game/pgame.lean | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/set_theory/game/pgame.lean b/src/set_theory/game/pgame.lean index dbc868d18762e..53439b3879226 100644 --- a/src/set_theory/game/pgame.lean +++ b/src/set_theory/game/pgame.lean @@ -862,6 +862,14 @@ rfl (x + y).move_right ((@right_moves_add x y).symm (sum.inr i)) = x + y.move_right i := by { cases x, cases y, refl, } +instance is_empty_nat_right_moves : ∀ n : ℕ, is_empty (right_moves n) +| 0 := pempty.is_empty +| (n + 1) := begin + haveI := is_empty_nat_right_moves n, + rw nat.cast_succ, + exact (right_moves_add _ _).is_empty +end + /-- If `w` has the same moves as `x` and `y` has the same moves as `z`, then `w + y` has the same moves as `x + z`. -/ def relabelling.add_congr : ∀ {w x y z : pgame.{u}}, From 0cb20fca1930098392174cd182c7618375b3a0ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Thu, 28 Apr 2022 08:07:58 +0000 Subject: [PATCH 295/373] feat(set_theory/ordinal/basic): `max a 0 = a` (#13734) --- src/set_theory/ordinal/basic.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/set_theory/ordinal/basic.lean b/src/set_theory/ordinal/basic.lean index 1ba23524f9173..75c0a7769f083 100644 --- a/src/set_theory/ordinal/basic.lean +++ b/src/set_theory/ordinal/basic.lean @@ -1203,6 +1203,10 @@ wf.conditionally_complete_linear_order_with_bot 0 $ le_antisymm (ordinal.zero_le @[simp] lemma bot_eq_zero : (⊥ : ordinal) = 0 := rfl +@[simp] lemma max_zero_left : ∀ a : ordinal, max 0 a = a := max_bot_left +@[simp] lemma max_zero_right : ∀ a : ordinal, max a 0 = a := max_bot_right +@[simp] lemma max_eq_zero {a b : ordinal} : max a b = 0 ↔ a = 0 ∧ b = 0 := max_eq_bot + protected theorem not_lt_zero (o : ordinal) : ¬ o < 0 := not_lt_bot From 1c92dfdf52e691ec9a871bf928803192b315237a Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 28 Apr 2022 13:52:30 +0000 Subject: [PATCH 296/373] chore(*/equiv): missing refl_symm lemmas (#13761) Co-authored-by: Scott Morrison --- src/algebra/algebra/basic.lean | 3 +++ src/algebra/hom/equiv.lean | 3 +++ src/algebra/lie/basic.lean | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/algebra/algebra/basic.lean b/src/algebra/algebra/basic.lean index 6ec8e263ce9c2..676961e670311 100644 --- a/src/algebra/algebra/basic.lean +++ b/src/algebra/algebra/basic.lean @@ -921,6 +921,9 @@ symm_bijective.injective $ ext $ λ x, rfl { to_fun := f', inv_fun := f, ..(⟨f, f', h₁, h₂, h₃, h₄, h₅⟩ : A₁ ≃ₐ[R] A₂).symm } := rfl +@[simp] +theorem refl_symm : (alg_equiv.refl : A₁ ≃ₐ[R] A₁).symm = alg_equiv.refl := rfl + /-- Algebra equivalences are transitive. -/ @[trans] def trans (e₁ : A₁ ≃ₐ[R] A₂) (e₂ : A₂ ≃ₐ[R] A₃) : A₁ ≃ₐ[R] A₃ := diff --git a/src/algebra/hom/equiv.lean b/src/algebra/hom/equiv.lean index 48439c847ab42..2e8bb24f3b5f8 100644 --- a/src/algebra/hom/equiv.lean +++ b/src/algebra/hom/equiv.lean @@ -229,6 +229,9 @@ theorem symm_mk (f : M → N) (g h₁ h₂ h₃) : (mul_equiv.mk f g h₁ h₂ h₃).symm = { to_fun := g, inv_fun := f, ..(mul_equiv.mk f g h₁ h₂ h₃).symm} := rfl +@[simp, to_additive] +theorem refl_symm : (refl M).symm = refl M := rfl + /-- Transitivity of multiplication-preserving isomorphisms -/ @[trans, to_additive "Transitivity of addition-preserving isomorphisms"] def trans (h1 : M ≃* N) (h2 : N ≃* P) : (M ≃* P) := diff --git a/src/algebra/lie/basic.lean b/src/algebra/lie/basic.lean index dce100af23032..edff21112ee4b 100644 --- a/src/algebra/lie/basic.lean +++ b/src/algebra/lie/basic.lean @@ -418,6 +418,9 @@ by { ext, refl } @[simp] lemma symm_apply_apply (e : L₁ ≃ₗ⁅R⁆ L₂) : ∀ x, e.symm (e x) = x := e.to_linear_equiv.symm_apply_apply +@[simp] +theorem refl_symm : (refl : L₁ ≃ₗ⁅R⁆ L₁).symm = refl := rfl + /-- Lie algebra equivalences are transitive. -/ @[trans] def trans (e₁ : L₁ ≃ₗ⁅R⁆ L₂) (e₂ : L₂ ≃ₗ⁅R⁆ L₃) : L₁ ≃ₗ⁅R⁆ L₃ := From c5bf4808289689195303a62b3d17912b92d235e9 Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Thu, 28 Apr 2022 15:47:51 +0000 Subject: [PATCH 297/373] fix(group_theory/subsemigroup/basic): change `mul_one_class` to `has_mul` (#13747) --- src/group_theory/subsemigroup/basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/group_theory/subsemigroup/basic.lean b/src/group_theory/subsemigroup/basic.lean index 54b1b5cc5c2b8..a454a84451711 100644 --- a/src/group_theory/subsemigroup/basic.lean +++ b/src/group_theory/subsemigroup/basic.lean @@ -359,7 +359,7 @@ end subsemigroup namespace mul_hom -variables [mul_one_class N] +variables [has_mul N] open subsemigroup From 0d3f8a71a1b8776774d6453cdaf9bef365e66a5b Mon Sep 17 00:00:00 2001 From: Jireh Loreaux Date: Thu, 28 Apr 2022 17:35:20 +0000 Subject: [PATCH 298/373] feat(ring_theory/submonoid/membership): generalize a few lemmas to `mul_mem_class` (#13748) This generalizes lemmas relating to the additive closure of a multiplicative monoid so that they also apply to multiplicative semigroups using `mul_mem_class` --- src/group_theory/submonoid/membership.lean | 19 ++++++++++++------- src/ring_theory/subsemiring/basic.lean | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/group_theory/submonoid/membership.lean b/src/group_theory/submonoid/membership.lean index b740035c5d85a..3d764781e5e1f 100644 --- a/src/group_theory/submonoid/membership.lean +++ b/src/group_theory/submonoid/membership.lean @@ -457,12 +457,13 @@ attribute [to_additive add_submonoid.multiples_subset] submonoid.powers_subset end add_submonoid -/-! Lemmas about additive closures of `submonoid`. -/ -namespace submonoid +/-! Lemmas about additive closures of `subsemigroup`. -/ +namespace mul_mem_class -variables {R : Type*} [non_assoc_semiring R] (S : submonoid R) {a b : R} +variables {R : Type*} [non_unital_non_assoc_semiring R] [set_like M R] [mul_mem_class M R] + {S : M} {a b : R} -/-- The product of an element of the additive closure of a multiplicative submonoid `M` +/-- The product of an element of the additive closure of a multiplicative subsemigroup `M` and an element of `M` is contained in the additive closure of `M`. -/ lemma mul_right_mem_add_closure (ha : a ∈ add_submonoid.closure (S : set R)) (hb : b ∈ S) : @@ -470,7 +471,7 @@ lemma mul_right_mem_add_closure begin revert b, refine add_submonoid.closure_induction ha _ _ _; clear ha a, - { exact λ r hr b hb, add_submonoid.mem_closure.mpr (λ y hy, hy (S.mul_mem hr hb)) }, + { exact λ r hr b hb, add_submonoid.mem_closure.mpr (λ y hy, hy (mul_mem hr hb)) }, { exact λ b hb, by simp only [zero_mul, (add_submonoid.closure (S : set R)).zero_mem] }, { simp_rw add_mul, exact λ r s hr hs b hb, (add_submonoid.closure (S : set R)).add_mem (hr hb) (hs hb) } @@ -484,7 +485,7 @@ lemma mul_mem_add_closure begin revert a, refine add_submonoid.closure_induction hb _ _ _; clear hb b, - { exact λ r hr b hb, S.mul_right_mem_add_closure hb hr }, + { exact λ r hr b hb, mul_mem_class.mul_right_mem_add_closure hb hr }, { exact λ b hb, by simp only [mul_zero, (add_submonoid.closure (S : set R)).zero_mem] }, { simp_rw mul_add, exact λ r s hr hs b hb, (add_submonoid.closure (S : set R)).add_mem (hr hb) (hs hb) } @@ -494,7 +495,11 @@ end submonoid `S` is contained in the additive closure of `S`. -/ lemma mul_left_mem_add_closure (ha : a ∈ S) (hb : b ∈ add_submonoid.closure (S : set R)) : a * b ∈ add_submonoid.closure (S : set R) := -S.mul_mem_add_closure (add_submonoid.mem_closure.mpr (λ sT hT, hT ha)) hb +mul_mem_add_closure (add_submonoid.mem_closure.mpr (λ sT hT, hT ha)) hb + +end mul_mem_class + +namespace submonoid /-- An element is in the closure of a two-element set if it is a linear combination of those two elements. -/ diff --git a/src/ring_theory/subsemiring/basic.lean b/src/ring_theory/subsemiring/basic.lean index 421d0d9bf962e..90dc42f73b607 100644 --- a/src/ring_theory/subsemiring/basic.lean +++ b/src/ring_theory/subsemiring/basic.lean @@ -582,7 +582,7 @@ namespace submonoid /-- The additive closure of a submonoid is a subsemiring. -/ def subsemiring_closure (M : submonoid R) : subsemiring R := { one_mem' := add_submonoid.mem_closure.mpr (λ y hy, hy M.one_mem), - mul_mem' := λ x y, M.mul_mem_add_closure, + mul_mem' := λ x y, mul_mem_class.mul_mem_add_closure, ..add_submonoid.closure (M : set R)} lemma subsemiring_closure_coe : From 8a32fdfde20f1bc8468ec6464a639f7de64f9e82 Mon Sep 17 00:00:00 2001 From: Eric Rodriguez Date: Thu, 28 Apr 2022 19:47:12 +0000 Subject: [PATCH 299/373] =?UTF-8?q?feat(cyclotomic/eval):=20(q=20-=201)=20?= =?UTF-8?q?^=20totient=20n=20<=20|=CF=95=E2=82=99(q)|=20(#12595)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Originally from the Wedderburn PR, but generalized to include an exponent. Co-authored-by: Alex J. Best Co-authored-by: Alex J. Best Co-authored-by: Johan Commelin Co-authored-by: Alex J Best --- .../polynomial/cyclotomic/eval.lean | 179 +++++++++++++++++- 1 file changed, 174 insertions(+), 5 deletions(-) diff --git a/src/ring_theory/polynomial/cyclotomic/eval.lean b/src/ring_theory/polynomial/cyclotomic/eval.lean index 7c74115b9a11e..88595c50e62bb 100644 --- a/src/ring_theory/polynomial/cyclotomic/eval.lean +++ b/src/ring_theory/polynomial/cyclotomic/eval.lean @@ -8,6 +8,7 @@ import ring_theory.polynomial.cyclotomic.basic import tactic.by_contra import topology.algebra.polynomial import number_theory.padics.padic_val +import analysis.complex.arg /-! # Evaluating cyclotomic polynomials @@ -111,19 +112,42 @@ begin { simpa only [eval_X, eval_one, cyclotomic_two, eval_add] using h.right.le } } end +lemma cyclotomic_pos_and_nonneg (n : ℕ) {R} [linear_ordered_comm_ring R] (x : R) : + (1 < x → 0 < eval x (cyclotomic n R)) ∧ (1 ≤ x → 0 ≤ eval x (cyclotomic n R)) := +begin + rcases n with _ | _ | _ | n; + simp only [cyclotomic_zero, cyclotomic_one, cyclotomic_two, succ_eq_add_one, + eval_X, eval_one, eval_add, eval_sub, sub_nonneg, sub_pos, + zero_lt_one, zero_le_one, implies_true_iff, imp_self, and_self], + { split; intro; linarith, }, + { have : 2 < n + 3 := dec_trivial, + split; intro; [skip, apply le_of_lt]; apply cyclotomic_pos this, }, +end + +/-- Cyclotomic polynomials are always positive on inputs larger than one. +Similar to `cyclotomic_pos` but with the condition on the input rather than index of the +cyclotomic polynomial. -/ +lemma cyclotomic_pos' (n : ℕ) {R} [linear_ordered_comm_ring R] {x : R} (hx : 1 < x) : + 0 < eval x (cyclotomic n R) := +(cyclotomic_pos_and_nonneg n x).1 hx + +/-- Cyclotomic polynomials are always nonnegative on inputs one or more. -/ +lemma cyclotomic_nonneg (n : ℕ) {R} [linear_ordered_comm_ring R] {x : R} (hx : 1 ≤ x) : + 0 ≤ eval x (cyclotomic n R) := +(cyclotomic_pos_and_nonneg n x).2 hx + lemma eval_one_cyclotomic_not_prime_pow {R : Type*} [comm_ring R] {n : ℕ} (h : ∀ {p : ℕ}, p.prime → ∀ k : ℕ, p ^ k ≠ n) : eval 1 (cyclotomic n R) = 1 := begin rcases n.eq_zero_or_pos with rfl | hn', { simp }, - have hn : 2 < n := two_lt_of_ne hn'.ne' (h nat.prime_two 0).symm (h nat.prime_two 1).symm, - have hn'' : 1 < n := by linarith, + have hn : 1 < n := one_lt_iff_ne_zero_and_ne_one.mpr ⟨hn'.ne', (h nat.prime_two 0).symm⟩, suffices : eval 1 (cyclotomic n ℤ) = 1 ∨ eval 1 (cyclotomic n ℤ) = -1, { cases this with h h, { have := eval_int_cast_map (int.cast_ring_hom R) (cyclotomic n ℤ) 1, simpa only [map_cyclotomic, int.cast_one, h, ring_hom.eq_int_cast] using this }, { exfalso, - linarith [cyclotomic_pos hn (1 : ℤ)] }, }, + linarith [cyclotomic_nonneg n (le_refl (1 : ℤ))] }, }, rw [←int.nat_abs_eq_nat_abs_iff, int.nat_abs_one, nat.eq_one_iff_not_exists_prime_dvd], intros p hp hpe, haveI := fact.mk hp, @@ -135,7 +159,7 @@ begin ←one_geom_sum, ←eval_geom_sum, ←prod_cyclotomic_eq_geom_sum hn'], apply eval_dvd, apply finset.dvd_prod_of_mem, - simpa using and.intro hn'.ne' hn''.ne' }, + simpa using and.intro hn'.ne' hn.ne' }, have := prod_cyclotomic_eq_geom_sum hn' ℤ, apply_fun eval 1 at this, @@ -147,7 +171,7 @@ begin swap, { simp only [not_exists, true_and, exists_prop, dvd_rfl, finset.mem_image, finset.mem_range, finset.mem_singleton, finset.singleton_subset_iff, finset.mem_sdiff, nat.mem_divisors, not_and], - exact ⟨⟨hn'.ne', hn''.ne'⟩, λ t _, h hp _⟩ }, + exact ⟨⟨hn'.ne', hn.ne'⟩, λ t _, h hp _⟩ }, rw [←int.nat_abs_of_nat p, int.nat_abs_dvd_iff_dvd] at hpe, obtain ⟨t, ht⟩ := hpe, rw [finset.prod_singleton, ht, mul_left_comm, mul_comm, ←mul_assoc, mul_assoc] at this, @@ -160,4 +184,149 @@ begin exact nat.pow_right_injective hp.two_le hxy } end +lemma sub_one_pow_totient_lt_cyclotomic_eval {n : ℕ} {q : ℝ} (hn' : 2 ≤ n) (hq' : 1 < q) : + (q - 1) ^ totient n < (cyclotomic n ℝ).eval q := +begin + have hn : 0 < n := pos_of_gt hn', + have hq := zero_lt_one.trans hq', + have hfor : ∀ ζ' ∈ primitive_roots n ℂ, q - 1 ≤ ∥↑q - ζ'∥, + { intros ζ' hζ', + rw mem_primitive_roots hn at hζ', + convert norm_sub_norm_le (↑q) ζ', + { rw [complex.norm_real, real.norm_of_nonneg hq.le], }, + { rw [hζ'.norm'_eq_one hn.ne'] } }, + let ζ := complex.exp (2 * ↑real.pi * complex.I / ↑n), + have hζ : is_primitive_root ζ n := complex.is_primitive_root_exp n hn.ne', + have hex : ∃ ζ' ∈ primitive_roots n ℂ, q - 1 < ∥↑q - ζ'∥, + { refine ⟨ζ, (mem_primitive_roots hn).mpr hζ, _⟩, + suffices : ¬ same_ray ℝ (q : ℂ) ζ, + { convert lt_norm_sub_of_not_same_ray this; + simp [real.norm_of_nonneg hq.le, hζ.norm'_eq_one hn.ne'] }, + rw complex.same_ray_iff, + push_neg, + refine ⟨by exact_mod_cast hq.ne', hζ.ne_zero hn.ne', _⟩, + rw [complex.arg_of_real_of_nonneg hq.le, ne.def, eq_comm, hζ.arg_eq_zero_iff hn.ne'], + clear_value ζ, + rintro rfl, + linarith [hζ.unique is_primitive_root.one] }, + have : ¬eval ↑q (cyclotomic n ℂ) = 0, + { erw cyclotomic.eval_apply q n (algebra_map ℝ ℂ), + simpa using (cyclotomic_pos' n hq').ne' }, + suffices : (units.mk0 (real.to_nnreal (q - 1)) (by simp [hq'])) ^ totient n + < units.mk0 (∥(cyclotomic n ℂ).eval q∥₊) (by simp [this]), + { simp only [←units.coe_lt_coe, units.coe_pow, units.coe_mk0, ← nnreal.coe_lt_coe, hq'.le, + real.to_nnreal_lt_to_nnreal_iff_of_nonneg, coe_nnnorm, complex.norm_eq_abs, + nnreal.coe_pow, real.coe_to_nnreal', max_eq_left, sub_nonneg] at this, + convert this, + erw [(cyclotomic.eval_apply q n (algebra_map ℝ ℂ)), eq_comm], + simp [cyclotomic_nonneg n hq'.le], }, + simp only [cyclotomic_eq_prod_X_sub_primitive_roots hζ, eval_prod, eval_C, + eval_X, eval_sub, nnnorm_prod, units.mk0_prod], + convert prod_lt_prod' _ _, + swap, { exact λ _, units.mk0 (real.to_nnreal (q - 1)) (by simp [hq']) }, + { simp [complex.card_primitive_roots] }, + { simp only [subtype.coe_mk, mem_attach, forall_true_left, subtype.forall, ←units.coe_le_coe, + ← nnreal.coe_le_coe, complex.abs_nonneg, hq'.le, units.coe_mk0, real.coe_to_nnreal', + coe_nnnorm, complex.norm_eq_abs, max_le_iff, tsub_le_iff_right], + intros x hx, + simpa using hfor x hx, }, + { simp only [subtype.coe_mk, mem_attach, exists_true_left, subtype.exists, + ← nnreal.coe_lt_coe, ← units.coe_lt_coe, units.coe_mk0 _, coe_nnnorm], + simpa [hq'.le] using hex, }, +end + +lemma cyclotomic_eval_lt_sub_one_pow_totient {n : ℕ} {q : ℝ} (hn' : 3 ≤ n) (hq' : 1 < q) : + (cyclotomic n ℝ).eval q < (q + 1) ^ totient n := +begin + have hn : 0 < n := pos_of_gt hn', + have hq := zero_lt_one.trans hq', + have hfor : ∀ ζ' ∈ primitive_roots n ℂ, ∥↑q - ζ'∥ ≤ q + 1, + { intros ζ' hζ', + rw mem_primitive_roots hn at hζ', + convert norm_sub_le (↑q) ζ', + { rw [complex.norm_real, real.norm_of_nonneg (zero_le_one.trans_lt hq').le], }, + { rw [hζ'.norm'_eq_one hn.ne'] }, }, + let ζ := complex.exp (2 * ↑real.pi * complex.I / ↑n), + have hζ : is_primitive_root ζ n := complex.is_primitive_root_exp n hn.ne', + have hex : ∃ ζ' ∈ primitive_roots n ℂ, ∥↑q - ζ'∥ < q + 1, + { refine ⟨ζ, (mem_primitive_roots hn).mpr hζ, _⟩, + suffices : ¬ same_ray ℝ (q : ℂ) (-ζ), + { convert norm_add_lt_of_not_same_ray this; + simp [real.norm_of_nonneg hq.le, hζ.norm'_eq_one hn.ne', -complex.norm_eq_abs] }, + rw complex.same_ray_iff, + push_neg, + refine ⟨by exact_mod_cast hq.ne', neg_ne_zero.mpr $ hζ.ne_zero hn.ne', _⟩, + rw [complex.arg_of_real_of_nonneg hq.le, ne.def, eq_comm], + intro h, + rw [complex.arg_eq_zero_iff, complex.neg_re, neg_nonneg, complex.neg_im, neg_eq_zero] at h, + have hζ₀ : ζ ≠ 0, + { clear_value ζ, + rintro rfl, + exact hn.ne' (hζ.unique is_primitive_root.zero) }, + have : ζ.re < 0 ∧ ζ.im = 0 := ⟨h.1.lt_of_ne _, h.2⟩, + rw [←complex.arg_eq_pi_iff, hζ.arg_eq_pi_iff hn.ne'] at this, + rw this at hζ, + linarith [hζ.unique $ is_primitive_root.neg_one 0 two_ne_zero.symm], + { contrapose! hζ₀, + ext; simp [hζ₀, h.2] } }, + have : ¬eval ↑q (cyclotomic n ℂ) = 0, + { erw cyclotomic.eval_apply q n (algebra_map ℝ ℂ), + simp only [complex.coe_algebra_map, complex.of_real_eq_zero], + exact (cyclotomic_pos' n hq').ne.symm, }, + suffices : units.mk0 (∥(cyclotomic n ℂ).eval q∥₊) (by simp [this]) + < (units.mk0 (real.to_nnreal (q + 1)) (by simp; linarith)) ^ totient n, + { simp only [←units.coe_lt_coe, units.coe_pow, units.coe_mk0, ← nnreal.coe_lt_coe, hq'.le, + real.to_nnreal_lt_to_nnreal_iff_of_nonneg, coe_nnnorm, complex.norm_eq_abs, + nnreal.coe_pow, real.coe_to_nnreal', max_eq_left, sub_nonneg] at this, + convert this, + { erw [(cyclotomic.eval_apply q n (algebra_map ℝ ℂ)), eq_comm], + simp [cyclotomic_nonneg n hq'.le] }, + rw [eq_comm, max_eq_left_iff], + linarith }, + simp only [cyclotomic_eq_prod_X_sub_primitive_roots hζ, eval_prod, eval_C, + eval_X, eval_sub, nnnorm_prod, units.mk0_prod], + convert prod_lt_prod' _ _, + swap, { exact λ _, units.mk0 (real.to_nnreal (q + 1)) (by simp; linarith only [hq']) }, + { simp [complex.card_primitive_roots], }, + { simp only [subtype.coe_mk, mem_attach, forall_true_left, subtype.forall, ←units.coe_le_coe, + ← nnreal.coe_le_coe, complex.abs_nonneg, hq'.le, units.coe_mk0, real.coe_to_nnreal, + coe_nnnorm, complex.norm_eq_abs, max_le_iff], + intros x hx, + have : complex.abs _ ≤ _ := hfor x hx, + simp [this], }, + { simp only [subtype.coe_mk, mem_attach, exists_true_left, subtype.exists, + ← nnreal.coe_lt_coe, ← units.coe_lt_coe, units.coe_mk0 _, coe_nnnorm], + obtain ⟨ζ, hζ, hhζ : complex.abs _ < _⟩ := hex, + exact ⟨ζ, hζ, by simp [hhζ]⟩ }, +end + +lemma sub_one_lt_nat_abs_cyclotomic_eval {n : ℕ} {q : ℕ} (hn' : 1 < n) (hq' : q ≠ 1) : + q - 1 < ((cyclotomic n ℤ).eval ↑q).nat_abs := +begin + rcases q with _ | _ | q, + iterate 2 + { rw [pos_iff_ne_zero, ne.def, int.nat_abs_eq_zero], + intro h, + have := degree_eq_one_of_irreducible_of_root (cyclotomic.irreducible (pos_of_gt hn')) h, + rw [degree_cyclotomic, with_top.coe_eq_one, totient_eq_one_iff] at this, + rcases this with rfl|rfl; simpa using h }, + suffices : (q.succ : ℝ) < (eval (↑q + 1 + 1) (cyclotomic n ℤ)).nat_abs, + { exact_mod_cast this }, + calc _ ≤ ((q + 2 - 1) ^ n.totient : ℝ) : _ + ... < _ : _, + { norm_num, + convert pow_mono (by simp : 1 ≤ (q : ℝ) + 1) (totient_pos (pos_of_gt hn') : 1 ≤ n.totient), + { simp }, + { ring }, }, + convert sub_one_pow_totient_lt_cyclotomic_eval (show 2 ≤ n, by linarith) + (show (1 : ℝ) < q + 2, by {norm_cast, linarith}), + norm_cast, + erw cyclotomic.eval_apply (q + 2 : ℤ) n (algebra_map ℤ ℝ), + simp only [int.coe_nat_succ, ring_hom.eq_int_cast], + norm_cast, + rw [int.coe_nat_abs_eq_normalize, int.normalize_of_nonneg], + simp only [int.coe_nat_succ], + exact cyclotomic_nonneg n (by linarith), +end + end polynomial From c096a33a5914f73c972a9ed9a783f0f523e77c54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Thu, 28 Apr 2022 20:49:01 +0000 Subject: [PATCH 300/373] feat(set_theory/game/birthday): Game birthday is zero iff empty (#13715) --- src/set_theory/game/birthday.lean | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/set_theory/game/birthday.lean b/src/set_theory/game/birthday.lean index 7a5bf4b51819b..db9434bf2d621 100644 --- a/src/set_theory/game/birthday.lean +++ b/src/set_theory/game/birthday.lean @@ -88,7 +88,11 @@ theorem relabelling.birthday_congr : ∀ {x y : pgame.{u}}, relabelling x y → end using_well_founded { dec_tac := pgame_wf_tac } +@[simp] theorem birthday_eq_zero (x : pgame) : + birthday x = 0 ↔ is_empty x.left_moves ∧ is_empty x.right_moves := +by rw [birthday_def, ordinal.max_eq_zero, ordinal.lsub_eq_zero_iff, ordinal.lsub_eq_zero_iff] + @[simp] theorem birthday_zero : birthday 0 = 0 := -by rw [birthday_def, ordinal.lsub_empty, ordinal.lsub_empty, max_self] +by { rw birthday_eq_zero, split; apply_instance } end pgame From 220d4b8901e454167ef71fa1ff2eca82cbcc57b1 Mon Sep 17 00:00:00 2001 From: Floris van Doorn Date: Thu, 28 Apr 2022 21:23:32 +0000 Subject: [PATCH 301/373] doc(order/filter/small_sets): fix in doc (#13648) --- src/order/filter/small_sets.lean | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/order/filter/small_sets.lean b/src/order/filter/small_sets.lean index a9b0446e840de..50e6fc17bf75a 100644 --- a/src/order/filter/small_sets.lean +++ b/src/order/filter/small_sets.lean @@ -13,9 +13,9 @@ containing all powersets of members of `f`. `g` converges to `f.small_sets` if for all `s ∈ f`, eventually we have `g x ⊆ s`. -An example usage is that if `f : ι → ℝ` is a family of nonnegative functions with integral 1, then -saying that `f` tendsto `(𝓝 0).small_sets` is a way of saying that `f` tends to the Dirac delta -distribution. +An example usage is that if `f : ι → E → ℝ` is a family of nonnegative functions with integral 1, +then saying that `λ i, support (f i)` tendsto `(𝓝 0).small_sets` is a way of saying that +`f` tends to the Dirac delta distribution. -/ open_locale filter From ccd377469f7d0de62c7fb42069bbed1a088ee0b8 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Thu, 28 Apr 2022 21:23:33 +0000 Subject: [PATCH 302/373] chore(ring_theory/*): dot notation for `submodule.fg` and `subalgebra.fg` (#13737) --- src/linear_algebra/finite_dimensional.lean | 2 +- src/ring_theory/adjoin/fg.lean | 6 +++--- src/ring_theory/finiteness.lean | 6 +++--- src/ring_theory/integral_closure.lean | 4 ++-- src/ring_theory/noetherian.lean | 14 +++++++------- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/linear_algebra/finite_dimensional.lean b/src/linear_algebra/finite_dimensional.lean index 72add4d218ede..117ea5baaaa7a 100644 --- a/src/linear_algebra/finite_dimensional.lean +++ b/src/linear_algebra/finite_dimensional.lean @@ -731,7 +731,7 @@ instance finite_dimensional_sup (S₁ S₂ : submodule K V) [h₁ : finite_dimen begin unfold finite_dimensional at *, rw [finite_def] at *, - exact (fg_top _).2 (submodule.fg_sup ((fg_top S₁).1 h₁) ((fg_top S₂).1 h₂)), + exact (fg_top _).2 (((fg_top S₁).1 h₁).sup ((fg_top S₂).1 h₂)), end /-- The submodule generated by a finite supremum of finite dimensional submodules is diff --git a/src/ring_theory/adjoin/fg.lean b/src/ring_theory/adjoin/fg.lean index 8765ea074d400..12e288469c2f4 100644 --- a/src/ring_theory/adjoin/fg.lean +++ b/src/ring_theory/adjoin/fg.lean @@ -108,7 +108,7 @@ lemma fg_of_submodule_fg (h : (⊤ : submodule R A).fg) : (⊤ : subalgebra R A) let ⟨s, hs⟩ := h in ⟨s, to_submodule_injective $ by { rw [algebra.top_to_submodule, eq_top_iff, ← hs, span_le], exact algebra.subset_adjoin }⟩ -lemma fg_prod {S : subalgebra R A} {T : subalgebra R B} (hS : S.fg) (hT : T.fg) : (S.prod T).fg := +lemma fg.prod {S : subalgebra R A} {T : subalgebra R B} (hS : S.fg) (hT : T.fg) : (S.prod T).fg := begin obtain ⟨s, hs⟩ := fg_def.1 hS, obtain ⟨t, ht⟩ := fg_def.1 hT, @@ -121,7 +121,7 @@ end section open_locale classical -lemma fg_map (S : subalgebra R A) (f : A →ₐ[R] B) (hs : S.fg) : (S.map f).fg := +lemma fg.map {S : subalgebra R A} (f : A →ₐ[R] B) (hs : S.fg) : (S.map f).fg := let ⟨s, hs⟩ := hs in ⟨s.image f, by rw [finset.coe_image, algebra.adjoin_image, hs]⟩ end @@ -132,7 +132,7 @@ by { rw [← algebra.adjoin_image, finset.coe_preimage, set.image_preimage_eq_of rw [← alg_hom.coe_range, ← algebra.adjoin_le_iff, hs, ← algebra.map_top], exact map_mono le_top }⟩ lemma fg_top (S : subalgebra R A) : (⊤ : subalgebra R S).fg ↔ S.fg := -⟨λ h, by { rw [← S.range_val, ← algebra.map_top], exact fg_map _ _ h }, +⟨λ h, by { rw [← S.range_val, ← algebra.map_top], exact fg.map _ h }, λ h, fg_of_fg_map _ S.val subtype.val_injective $ by { rw [algebra.map_top, range_val], exact h }⟩ lemma induction_on_adjoin [is_noetherian R A] (P : subalgebra R A → Prop) diff --git a/src/ring_theory/finiteness.lean b/src/ring_theory/finiteness.lean index bc2bf620e9310..2f6bd9051d508 100644 --- a/src/ring_theory/finiteness.lean +++ b/src/ring_theory/finiteness.lean @@ -109,7 +109,7 @@ variables {R M} instance prod [hM : finite R M] [hN : finite R N] : finite R (M × N) := ⟨begin rw ← submodule.prod_top, - exact submodule.fg_prod hM.1 hN.1 + exact hM.1.prod hN.1 end⟩ instance pi {ι : Type*} {M : ι → Type*} [fintype ι] [Π i, add_comm_monoid (M i)] @@ -186,7 +186,7 @@ variables {R A B} lemma of_surjective (hRA : finite_type R A) (f : A →ₐ[R] B) (hf : surjective f) : finite_type R B := ⟨begin - convert subalgebra.fg_map _ f hRA.1, + convert hRA.1.map f, simpa only [map_top f, @eq_comm _ ⊤, eq_top_iff, alg_hom.mem_range] using hf end⟩ @@ -255,7 +255,7 @@ end instance prod [hA : finite_type R A] [hB : finite_type R B] : finite_type R (A × B) := ⟨begin rw ← subalgebra.prod_top, - exact subalgebra.fg_prod hA.1 hB.1 + exact hA.1.prod hB.1 end⟩ end finite_type diff --git a/src/ring_theory/integral_closure.lean b/src/ring_theory/integral_closure.lean index 8f9bac7420111..792ee40e4076e 100644 --- a/src/ring_theory/integral_closure.lean +++ b/src/ring_theory/integral_closure.lean @@ -194,7 +194,7 @@ set.finite.induction_on hfs (λ _, ⟨{1}, submodule.ext $ λ x, by { erw [algebra.adjoin_empty, finset.coe_singleton, ← one_eq_span, one_eq_range, linear_map.mem_range, algebra.mem_bot], refl }⟩) (λ a s has hs ih his, by rw [← set.union_singleton, algebra.adjoin_union_coe_submodule]; exact - fg_mul _ _ (ih $ λ i hi, his i $ set.mem_insert_of_mem a hi) + fg.mul (ih $ λ i hi, his i $ set.mem_insert_of_mem a hi) (fg_adjoin_singleton_of_integral _ $ his a $ set.mem_insert a s)) his lemma is_noetherian_adjoin_finset [is_noetherian_ring R] (s : finset A) @@ -291,7 +291,7 @@ lemma ring_hom.is_integral_of_mem_closure {x y z : S} f.is_integral_elem z := begin letI : algebra R S := f.to_algebra, - have := fg_mul _ _ (fg_adjoin_singleton_of_integral x hx) (fg_adjoin_singleton_of_integral y hy), + have := (fg_adjoin_singleton_of_integral x hx).mul (fg_adjoin_singleton_of_integral y hy), rw [← algebra.adjoin_union_coe_submodule, set.singleton_union] at this, exact is_integral_of_mem_of_fg (algebra.adjoin R {x, y}) this z (algebra.mem_adjoin_iff.2 $ subring.closure_mono (set.subset_union_right _ _) hz), diff --git a/src/ring_theory/noetherian.lean b/src/ring_theory/noetherian.lean index d38413b7d0e6d..b66f0037f6514 100644 --- a/src/ring_theory/noetherian.lean +++ b/src/ring_theory/noetherian.lean @@ -149,7 +149,7 @@ theorem fg_span {s : set M} (hs : finite s) : fg (span R s) := theorem fg_span_singleton (x : M) : fg (R ∙ x) := fg_span (finite_singleton x) -theorem fg_sup {N₁ N₂ : submodule R M} +theorem fg.sup {N₁ N₂ : submodule R M} (hN₁ : N₁.fg) (hN₂ : N₂.fg) : (N₁ ⊔ N₂).fg := let ⟨t₁, ht₁⟩ := fg_def.1 hN₁, ⟨t₂, ht₂⟩ := fg_def.1 hN₂ in fg_def.2 ⟨t₁ ∪ t₂, ht₁.1.union ht₂.1, by rw [span_union, ht₁.2, ht₂.2]⟩ @@ -182,7 +182,7 @@ lemma fg_of_linear_equiv (e : M ≃ₗ[R] P) (h : (⊤ : submodule R P).fg) : (⊤ : submodule R M).fg := e.symm.range ▸ map_top (e.symm : P →ₗ[R] M) ▸ h.map _ -theorem fg_prod {sb : submodule R M} {sc : submodule R P} +theorem fg.prod {sb : submodule R M} {sc : submodule R P} (hsb : sb.fg) (hsc : sc.fg) : (sb.prod sc).fg := let ⟨tb, htb⟩ := fg_def.1 hsb, ⟨tc, htc⟩ := fg_def.1 hsc in fg_def.2 ⟨linear_map.inl R M P '' tb ∪ linear_map.inr R M P '' tc, @@ -775,15 +775,15 @@ is_noetherian_ring_of_surjective R S f.to_ring_hom f.to_equiv.surjective namespace submodule variables {R : Type*} {A : Type*} [comm_semiring R] [semiring A] [algebra R A] -variables (M N : submodule R A) +variables {M N : submodule R A} -theorem fg_mul (hm : M.fg) (hn : N.fg) : (M * N).fg := +theorem fg.mul (hm : M.fg) (hn : N.fg) : (M * N).fg := let ⟨m, hfm, hm⟩ := fg_def.1 hm, ⟨n, hfn, hn⟩ := fg_def.1 hn in fg_def.2 ⟨m * n, hfm.mul hfn, span_mul_span R m n ▸ hm ▸ hn ▸ rfl⟩ -lemma fg_pow (h : M.fg) (n : ℕ) : (M ^ n).fg := +lemma fg.pow (h : M.fg) (n : ℕ) : (M ^ n).fg := nat.rec_on n -(⟨{1}, by simp [one_eq_span]⟩) -(λ n ih, by simpa [pow_succ] using fg_mul _ _ h ih) + (⟨{1}, by simp [one_eq_span]⟩) + (λ n ih, by simpa [pow_succ] using h.mul ih) end submodule From 214e2f1c8c6cfc5c83ed0b4c603f0d9b121a58fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Thu, 28 Apr 2022 22:42:55 +0000 Subject: [PATCH 303/373] chore(set_theory/surreal/basic): Allow dot notation on `pgame.numeric` (#13768) Rename `numeric_neg`/`numeric_add` to `numeric.add`/`numeric.neg`. Prove `numeric.sub` in passing. --- src/set_theory/surreal/basic.lean | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/set_theory/surreal/basic.lean b/src/set_theory/surreal/basic.lean index 3747ee534742f..8ab282b9d0795 100644 --- a/src/set_theory/surreal/basic.lean +++ b/src/set_theory/surreal/basic.lean @@ -103,10 +103,8 @@ theorem numeric_zero : numeric 0 := theorem numeric_one : numeric 1 := ⟨by rintros ⟨⟩ ⟨⟩, ⟨λ x, numeric_zero, by rintros ⟨⟩⟩⟩ -theorem numeric_neg : Π {x : pgame} (o : numeric x), numeric (-x) -| ⟨l, r, L, R⟩ o := -⟨λ j i, lt_iff_neg_gt.1 (o.1 i j), - ⟨λ j, numeric_neg (o.2.2 j), λ i, numeric_neg (o.2.1 i)⟩⟩ +theorem numeric.neg : Π {x : pgame} (o : numeric x), numeric (-x) +| ⟨l, r, L, R⟩ o := ⟨λ j i, lt_iff_neg_gt.1 (o.1 i j), λ j, (o.2.2 j).neg, λ i, (o.2.1 i).neg⟩ /-- For the `<` version, see `pgame.move_left_lt`. -/ theorem numeric.move_left_le {x : pgame} (o : numeric x) (i : x.left_moves) : @@ -151,7 +149,7 @@ begin ... ≤ x + z : add_le_add_left hjy _ }, end -theorem numeric_add : Π {x y : pgame} (ox : numeric x) (oy : numeric y), numeric (x + y) +theorem numeric.add : Π {x y : pgame} (ox : numeric x) (oy : numeric y), numeric (x + y) | ⟨xl, xr, xL, xR⟩ ⟨yl, yr, yL, yR⟩ ox oy := ⟨begin rintros (ix|iy) (jx|jy), @@ -167,18 +165,20 @@ theorem numeric_add : Π {x y : pgame} (ox : numeric x) (oy : numeric y), numeri begin split, { rintros (ix|iy), - { apply numeric_add (ox.move_left ix) oy, }, - { apply numeric_add ox (oy.move_left iy), }, }, + { exact (ox.move_left ix).add oy }, + { exact ox.add (oy.move_left iy) } }, { rintros (jx|jy), - { apply numeric_add (ox.move_right jx) oy, }, - { apply numeric_add ox (oy.move_right jy), }, }, + { apply (ox.move_right jx).add oy }, + { apply ox.add (oy.move_right jy) } } end⟩ using_well_founded { dec_tac := pgame_wf_tac } +lemma numeric.sub {x y : pgame} (ox : numeric x) (oy : numeric y) : numeric (x - y) := ox.add oy.neg + /-- Pre-games defined by natural numbers are numeric. -/ theorem numeric_nat : Π (n : ℕ), numeric n | 0 := numeric_zero -| (n + 1) := numeric_add (numeric_nat n) numeric_one +| (n + 1) := (numeric_nat n).add numeric_one /-- The pre-game omega is numeric. -/ theorem numeric_omega : numeric omega := @@ -281,14 +281,14 @@ by rintro ⟨⟨x, ox⟩⟩ ⟨⟨y, oy⟩⟩; exact not_le the sum of `x = {xL | xR}` and `y = {yL | yR}` is `{xL + y, x + yL | xR + y, x + yR}`. -/ def add : surreal → surreal → surreal := surreal.lift₂ - (λ (x y : pgame) (ox) (oy), ⟦⟨x + y, numeric_add ox oy⟩⟧) + (λ (x y : pgame) (ox) (oy), ⟦⟨x + y, ox.add oy⟩⟧) (λ x₁ y₁ x₂ y₂ _ _ _ _ hx hy, quotient.sound (pgame.add_congr hx hy)) /-- Negation for surreal numbers is inherited from pre-game negation: the negation of `{L | R}` is `{-R | -L}`. -/ def neg : surreal → surreal := surreal.lift - (λ x ox, ⟦⟨-x, pgame.numeric_neg ox⟩⟧) + (λ x ox, ⟦⟨-x, ox.neg⟩⟧) (λ _ _ _ _ a, quotient.sound (pgame.neg_congr a)) instance : has_le surreal := ⟨le⟩ From 11a4a745a13c56135e1292e598b421601cbc59ab Mon Sep 17 00:00:00 2001 From: Yuma Mizuno Date: Fri, 29 Apr 2022 00:29:56 +0000 Subject: [PATCH 304/373] feat(ring_theory/localization/basic): generalize to semiring (#13459) The main ingredient of this PR is the definition of `is_localization.lift` that works for semirings. The previous definition uses `ring_hom.mk'` that essentially states that `f 0 = 0` follows from other conditions. This does not holds for semirings. Instead, this PR defines the localization of monoid with zero, and uses this to define `is_localization.lift`. - I think definitions around `localization_with_zero_map` might be ad hoc, and any suggestions for improvement are welcome! - I plan to further generalize the localization API for semirings. This needs generalization of other ring theory stuff such as `local_ring` and `is_domain` (generalizing `local_ring` is partially done in #13341). --- src/group_theory/monoid_localization.lean | 101 +++++++++- src/ring_theory/jacobson.lean | 4 +- src/ring_theory/localization/basic.lean | 226 +++++++++++++--------- 3 files changed, 234 insertions(+), 97 deletions(-) diff --git a/src/group_theory/monoid_localization.lean b/src/group_theory/monoid_localization.lean index ae74991e7a7e7..3b374a52e6ee8 100644 --- a/src/group_theory/monoid_localization.lean +++ b/src/group_theory/monoid_localization.lean @@ -79,6 +79,8 @@ add_decl_doc localization_map.to_add_monoid_hom end add_submonoid +section comm_monoid + variables {M : Type*} [comm_monoid M] (S : submonoid M) (N : Type*) [comm_monoid N] {P : Type*} [comm_monoid P] @@ -788,7 +790,10 @@ monoid_hom.ext_iff.1 (f.lift_of_comp $ monoid_hom.id N) x /-- Given two localization maps `f : M →* N, k : M →* P` for a submonoid `S ⊆ M`, the hom from `P` to `N` induced by `f` is left inverse to the hom from `N` to `P` induced by `k`. -/ -@[simp, to_additive] lemma lift_left_inverse {k : localization_map S P} (z : N) : +@[simp, to_additive "Given two localization maps `f : M →+ N, k : M →+ P` for a submonoid `S ⊆ M`, +the hom from `P` to `N` induced by `f` is left inverse to the hom from `N` to `P` +induced by `k`."] +lemma lift_left_inverse {k : localization_map S P} (z : N) : k.lift f.map_units (f.lift k.map_units z) = z := begin rw lift_spec, @@ -1315,3 +1320,97 @@ mul_equiv_of_quotient f end away end localization + +end comm_monoid + +section comm_monoid_with_zero + +variables {M : Type*} [comm_monoid_with_zero M] (S : submonoid M) + (N : Type*) [comm_monoid_with_zero N] + {P : Type*} [comm_monoid_with_zero P] + +namespace submonoid + +/-- The type of homomorphisms between monoids with zero satisfying the characteristic predicate: +if `f : M →*₀ N` satisfies this predicate, then `N` is isomorphic to the localization of `M` at +`S`. -/ +@[nolint has_inhabited_instance] structure localization_with_zero_map + extends localization_map S N := +(map_zero' : to_fun 0 = 0) + +attribute [nolint doc_blame] localization_with_zero_map.to_localization_map + +variables {S N} + +/-- The monoid with zero hom underlying a `localization_map`. -/ +def localization_with_zero_map.to_monoid_with_zero_hom (f : localization_with_zero_map S N) : + M →*₀ N := +{ .. f } + +end submonoid + +namespace localization + +local attribute [semireducible] localization + +/-- The zero element in a localization is defined as `(0, 1)`. + +Should not be confused with `add_localization.zero` which is `(0, 0)`. -/ +@[irreducible] protected def zero : localization S := +mk 0 1 + +instance : has_zero (localization S) :=⟨localization.zero S⟩ + +local attribute [semireducible] localization.zero localization.mul + +instance : comm_monoid_with_zero (localization S) := +by refine_struct +{ zero := 0, .. localization.comm_monoid S }; + exact λ x, localization.induction_on x $ by + { intros, + refine mk_eq_mk_iff.mpr (r_of_eq _), + simp only [zero_mul, mul_zero] } + +attribute [irreducible] localization + +variables {S} + +lemma mk_zero (x : S) : mk 0 (x : S) = 0 := +calc mk 0 x = mk 0 1 : mk_eq_mk_iff.mpr (r_of_eq (by simp)) + ... = 0 : rfl + +lemma lift_on_zero {p : Type*} (f : ∀ (x : M) (y : S), p) (H) : lift_on 0 f H = f 0 1 := +by rw [← mk_zero 1, lift_on_mk] + +end localization + +variables {S N} + +namespace submonoid + +@[simp] lemma localization_map.sec_zero_fst {f : localization_map S N} : + f.to_map (f.sec 0).fst = 0 := +by rw [localization_map.sec_spec', mul_zero] + +namespace localization_with_zero_map + +/-- Given a localization map `f : M →*₀ N` for a submonoid `S ⊆ M` and a map of +`comm_monoid_with_zero`s `g : M →*₀ P` such that `g y` is invertible for all `y : S`, the +homomorphism induced from `N` to `P` sending `z : N` to `g x * (g y)⁻¹`, where `(x, y) : M × S` +are such that `z = f x * (f y)⁻¹`. -/ +noncomputable def lift (f : localization_with_zero_map S N) + (g : M →*₀ P) (hg : ∀ y : S, is_unit (g y)) : N →*₀ P := +{ map_zero' := + begin + rw [monoid_hom.to_fun_eq_coe, localization_map.lift_spec, mul_zero, + ←map_zero g, ←g.to_monoid_hom_coe], + refine f.to_localization_map.eq_of_eq hg _, + rw localization_map.sec_zero_fst, + exact f.to_monoid_with_zero_hom.map_zero.symm + end + .. @localization_map.lift _ _ _ _ _ _ _ f.to_localization_map g.to_monoid_hom hg } + +end localization_with_zero_map +end submonoid + +end comm_monoid_with_zero diff --git a/src/ring_theory/jacobson.lean b/src/ring_theory/jacobson.lean index e1b15c79b4b3f..9edb5dd598b61 100644 --- a/src/ring_theory/jacobson.lean +++ b/src/ring_theory/jacobson.lean @@ -289,7 +289,7 @@ begin let M' : submonoid (R[X] ⧸ P) := (submonoid.powers (pX.map (quotient.mk (P.comap C))).leading_coeff).map (quotient_map P C le_rfl), let φ : R ⧸ P' →+* R[X] ⧸ P := quotient_map P C le_rfl, - let φ' := is_localization.map Sₘ φ M.le_comap_map, + let φ' : Rₘ →+* Sₘ := is_localization.map Sₘ φ M.le_comap_map, have hφ' : φ.comp (quotient.mk P') = (quotient.mk P).comp C := rfl, intro p, obtain ⟨⟨p', ⟨q, hq⟩⟩, hp⟩ := is_localization.surj M' p, @@ -502,7 +502,7 @@ begin exact (let ⟨z, zM, z0⟩ := hM' in (quotient_map_injective (trans z0 φ.map_zero.symm)) ▸ zM) }, { rw ← is_localization.map_comp M.le_comap_map, refine ring_hom.is_integral_trans (algebra_map (R ⧸ P') (localization M)) - (is_localization.map _ _ M.le_comap_map) _ _, + (is_localization.map (localization M') _ M.le_comap_map) _ _, { exact (algebra_map (R ⧸ P') (localization M)).is_integral_of_surjective (is_field.localization_map_bijective hM ((quotient.maximal_ideal_iff_is_field_quotient _).mp (is_maximal_comap_C_of_is_maximal P hP'))).2 }, diff --git a/src/ring_theory/localization/basic.lean b/src/ring_theory/localization/basic.lean index 43135298e9550..bd6dcb212d573 100644 --- a/src/ring_theory/localization/basic.lean +++ b/src/ring_theory/localization/basic.lean @@ -80,12 +80,14 @@ fractions `K`, assume `[field K]` instead of just `[comm_ring K]`. localization, ring localization, commutative ring localization, characteristic predicate, commutative ring, field of fractions -/ -variables {R : Type*} [comm_ring R] (M : submonoid R) (S : Type*) [comm_ring S] -variables [algebra R S] {P : Type*} [comm_ring P] open function open_locale big_operators +section comm_semiring +variables {R : Type*} [comm_semiring R] (M : submonoid R) (S : Type*) [comm_semiring S] +variables [algebra R S] {P : Type*} [comm_semiring P] + /-- The typeclass `is_localization (M : submodule R) S` where `S` is an `R`-algebra expresses that `S` is isomorphic to the localization of `R` at `M`. -/ class is_localization : Prop := @@ -121,18 +123,23 @@ lemma of_le (N : submonoid R) (h₁ : M ≤ N) variables (S) -/-- `is_localization.to_localization_map M S` shows `S` is the monoid localization of `R` at `M`. -/ +/-- `is_localization.to_localization_with_zero_map M S` shows `S` is the monoid localization of +`R` at `M`. -/ @[simps] -def to_localization_map : submonoid.localization_map M S := +def to_localization_with_zero_map : submonoid.localization_with_zero_map M S := { to_fun := algebra_map R S, map_units' := is_localization.map_units _, surj' := is_localization.surj _, eq_iff_exists' := λ _ _, is_localization.eq_iff_exists _ _, .. algebra_map R S } +/-- `is_localization.to_localization_map M S` shows `S` is the monoid localization of `R` at `M`. -/ +abbreviation to_localization_map : submonoid.localization_map M S := +(to_localization_with_zero_map M S).to_localization_map + @[simp] lemma to_localization_map_to_map : - (to_localization_map M S).to_map = (algebra_map R S : R →* S) := rfl + (to_localization_map M S).to_map = (algebra_map R S : R →*₀ S) := rfl lemma to_localization_map_to_map_apply (x) : (to_localization_map M S).to_map x = algebra_map R S x := rfl @@ -240,6 +247,10 @@ theorem mk'_eq_iff_eq_mul {x} {y : M} {z} : mk' S x y = z ↔ algebra_map R S x = z * algebra_map R S y := (to_localization_map M S).mk'_eq_iff_eq_mul +theorem mk'_add_eq_iff_add_mul_eq_mul {x} {y : M} {z₁ z₂} : + mk' S x y + z₁ = z₂ ↔ algebra_map R S x + z₁ * algebra_map R S y = z₂ * algebra_map R S y := +by rw [←mk'_spec S x y, ←is_unit.mul_left_inj (is_localization.map_units S y), right_distrib] + variables (M) lemma mk'_surjective (z : S) : ∃ x (y : M), mk' S x y = z := @@ -359,7 +370,7 @@ lemma is_unit_comp (j : S →+* P) (y : M) : end -/-- Given a localization map `f : R →+* S` for a submonoid `M ⊆ R` and a map of `comm_ring`s +/-- Given a localization map `f : R →+* S` for a submonoid `M ⊆ R` and a map of `comm_semiring`s `g : R →+* P` such that `g(M) ⊆ units P`, `f x = f y → g x = g y` for all `x y : R`. -/ lemma eq_of_eq {g : R →+* P} (hg : ∀ y : M, is_unit (g y)) {x y} (h : (algebra_map R S) x = (algebra_map R S) y) : @@ -371,37 +382,56 @@ lemma mk'_add (x₁ x₂ : R) (y₁ y₂ : M) : mk' S (x₁ * y₂ + x₂ * y₁) (y₁ * y₂) = mk' S x₁ y₁ + mk' S x₂ y₂ := mk'_eq_iff_eq_mul.2 $ eq.symm begin - rw [mul_comm (_ + _), mul_add, mul_mk'_eq_mk'_of_mul, ←eq_sub_iff_add_eq, mk'_eq_iff_eq_mul, - mul_comm _ ((algebra_map R S) _), mul_sub, eq_sub_iff_add_eq, ←eq_sub_iff_add_eq', ←mul_assoc, - ←(algebra_map R S).map_mul, mul_mk'_eq_mk'_of_mul, mk'_eq_iff_eq_mul], - simp only [(algebra_map R S).map_add, submonoid.coe_mul, (algebra_map R S).map_mul], - ring_exp, + rw [mul_comm (_ + _), mul_add, mul_mk'_eq_mk'_of_mul, mk'_add_eq_iff_add_mul_eq_mul, + mul_comm (_ * _), ←mul_assoc, add_comm, ←map_mul, mul_mk'_eq_mk'_of_mul, + mk'_add_eq_iff_add_mul_eq_mul], + simp only [map_add, submonoid.coe_mul, map_mul], + ring +end + +lemma mul_add_inv_left {g : R →+* P} (h : ∀ y : M, is_unit (g y)) (y : M) (w z₁ z₂ : P) : + w * ↑(is_unit.lift_right (g.to_monoid_hom.mrestrict M) h y)⁻¹ + z₁ = z₂ + ↔ w + g y * z₁ = g y * z₂ := +begin + rw [mul_comm, ←one_mul z₁, ←units.inv_mul (is_unit.lift_right (g.to_monoid_hom.mrestrict M) h y), + mul_assoc, ←mul_add, units.inv_mul_eq_iff_eq_mul, units.inv_mul_cancel_left, + is_unit.coe_lift_right], + simp only [ring_hom.to_monoid_hom_eq_coe, monoid_hom.mrestrict_apply, ring_hom.coe_monoid_hom] end -/-- Given a localization map `f : R →+* S` for a submonoid `M ⊆ R` and a map of `comm_ring`s +lemma lift_spec_mul_add {g : R →+* P} (hg : ∀ y : M, is_unit (g y)) (z w w' v) : + ((to_localization_with_zero_map M S).lift g.to_monoid_with_zero_hom hg) z * w + w' = v + ↔ g ((to_localization_map M S).sec z).1 * w + g ((to_localization_map M S).sec z).2 * w' + = g ((to_localization_map M S).sec z).2 * v := +begin + show (_ * _) * _ + _ = _ ↔ _ = _, + erw [mul_comm, ←mul_assoc, mul_add_inv_left hg, mul_comm], + refl +end + +/-- Given a localization map `f : R →+* S` for a submonoid `M ⊆ R` and a map of `comm_semiring`s `g : R →+* P` such that `g y` is invertible for all `y : M`, the homomorphism induced from `S` to `P` sending `z : S` to `g x * (g y)⁻¹`, where `(x, y) : R × M` are such that `z = f x * (f y)⁻¹`. -/ noncomputable def lift {g : R →+* P} (hg : ∀ y : M, is_unit (g y)) : S →+* P := -ring_hom.mk' (@submonoid.localization_map.lift _ _ _ _ _ _ _ - (to_localization_map M S) g.to_monoid_hom hg) $ -begin - intros x y, - rw [(to_localization_map M S).lift_spec, mul_comm, add_mul, ←sub_eq_iff_eq_add, eq_comm, - (to_localization_map M S).lift_spec_mul, mul_comm _ (_ - _), sub_mul, eq_sub_iff_add_eq', - ←eq_sub_iff_add_eq, mul_assoc, (to_localization_map M S).lift_spec_mul], - show g _ * (g _ * g _) = g _ * (g _ * g _ - g _ * g _), - simp only [← g.map_sub, ← g.map_mul, to_localization_map_sec], - apply eq_of_eq hg, - rw [(algebra_map R S).map_mul, sec_spec', mul_sub, (algebra_map R S).map_sub], - simp only [ring_hom.map_mul, sec_spec'], - ring, - assumption -end +{ map_add' := + begin + intros x y, + erw [(to_localization_map M S).lift_spec, mul_add, mul_comm, eq_comm, lift_spec_mul_add, + add_comm, mul_comm,mul_assoc,mul_comm,mul_assoc, lift_spec_mul_add], + simp_rw ←mul_assoc, + show g _ * g _ * g _ + g _ * g _ * g _ = g _ * g _ * g _, + simp_rw [←map_mul g, ←map_add g], + apply @eq_of_eq _ _ _ S _ _ _ _ _ g hg, + simp only [sec_spec', to_localization_map_sec, map_add, map_mul], + ring + end, + .. @submonoid.localization_with_zero_map.lift _ _ _ _ _ _ _ + (to_localization_with_zero_map M S) g.to_monoid_with_zero_hom hg } variables {g : R →+* P} (hg : ∀ y : M, is_unit (g y)) -/-- Given a localization map `f : R →+* S` for a submonoid `M ⊆ R` and a map of `comm_ring`s +/-- Given a localization map `f : R →+* S` for a submonoid `M ⊆ R` and a map of `comm_semiring`s `g : R →* P` such that `g y` is invertible for all `y : M`, the homomorphism induced from `S` to `P` maps `f x * (f y)⁻¹` to `g x * (g y)⁻¹` for all `x : R, y ∈ M`. -/ lemma lift_mk' (x y) : @@ -466,7 +496,7 @@ lemma lift_injective_iff : section map -variables {T : submonoid P} {Q : Type*} [comm_ring Q] (hy : M ≤ T.comap g) +variables {T : submonoid P} {Q : Type*} [comm_semiring Q] (hy : M ≤ T.comap g) variables [algebra P Q] [is_localization T Q] section @@ -505,17 +535,17 @@ lemma map_unique (j : S →+* Q) (hj : ∀ x : R, j (algebra_map R S x) = algebra_map P Q (g x)) : map Q g hy = j := lift_unique (λ y, map_units _ ⟨g y, hy y.2⟩) hj -/-- If `comm_ring` homs `g : R →+* P, l : P →+* A` induce maps of localizations, the composition +/-- If `comm_semiring` homs `g : R →+* P, l : P →+* A` induce maps of localizations, the composition of the induced maps equals the map of localizations induced by `l ∘ g`. -/ -lemma map_comp_map {A : Type*} [comm_ring A] {U : submonoid A} {W} [comm_ring W] +lemma map_comp_map {A : Type*} [comm_semiring A] {U : submonoid A} {W} [comm_semiring W] [algebra A W] [is_localization U W] {l : P →+* A} (hl : T ≤ U.comap l) : (map W l hl).comp (map Q g hy : S →+* _) = map W (l.comp g) (λ x hx, hl (hy hx)) := ring_hom.ext $ λ x, @submonoid.localization_map.map_map _ _ _ _ _ P _ (to_localization_map M S) g _ _ _ _ _ _ _ _ _ _ (to_localization_map U W) l _ x -/-- If `comm_ring` homs `g : R →+* P, l : P →+* A` induce maps of localizations, the composition +/-- If `comm_semiring` homs `g : R →+* P, l : P →+* A` induce maps of localizations, the composition of the induced maps equals the map of localizations induced by `l ∘ g`. -/ -lemma map_map {A : Type*} [comm_ring A] {U : submonoid A} {W} [comm_ring W] +lemma map_map {A : Type*} [comm_semiring A] {U : submonoid A} {W} [comm_semiring W] [algebra A W] [is_localization U W] {l : P →+* A} (hl : T ≤ U.comap l) (x : S) : map W l hl (map Q g hy x) = map W (l.comp g) (λ x hx, hl (hy hx)) x := by rw ←map_comp_map hy hl; refl @@ -563,7 +593,7 @@ end map section alg_equiv -variables {Q : Type*} [comm_ring Q] [algebra R Q] [is_localization M Q] +variables {Q : Type*} [comm_semiring Q] [algebra R Q] [is_localization M Q] section @@ -737,46 +767,14 @@ begin ring end -/-- Negation in a ring localization is defined as `-⟨a, b⟩ = ⟨-a, b⟩`. -/ -@[irreducible] protected def neg (z : localization M) : localization M := -localization.lift_on z (λ a b, mk (-a) b) $ - λ a b c d h, mk_eq_mk_iff.2 -begin - rw r_eq_r' at h ⊢, - cases h with t ht, - use t, - rw [neg_mul, neg_mul, ht], - ring_nf, -end - -instance : has_neg (localization M) := ⟨localization.neg⟩ - -lemma neg_mk (a b) : -(mk a b : localization M) = mk (-a) b := -by { unfold has_neg.neg localization.neg, apply lift_on_mk } - -/-- The zero element in a ring localization is defined as `⟨0, 1⟩`. - -Should not be confused with `add_localization.zero` which is `⟨0, 0⟩`. -/ -@[irreducible] protected def zero : localization M := -mk 0 1 - -instance : has_zero (localization M) := ⟨localization.zero⟩ - -lemma mk_zero (b) : (mk 0 b : localization M) = 0 := -calc mk 0 b = mk 0 1 : mk_eq_mk_iff.mpr (r_of_eq (by simp)) -... = 0 : by unfold has_zero.zero localization.zero - -lemma lift_on_zero {p : Type*} (f : ∀ (a : R) (b : M), p) (H) : lift_on 0 f H = f 0 1 := -by rw [← mk_zero 1, lift_on_mk] - private meta def tac := `[ { intros, - simp only [add_mk, localization.mk_mul, neg_mk, ← mk_zero 1], + simp only [add_mk, localization.mk_mul, ← localization.mk_zero 1], refine mk_eq_mk_iff.mpr (r_of_eq _), - simp only [submonoid.coe_mul, prod.fst_mul, prod.snd_mul], + simp only [submonoid.coe_mul], ring }] -instance : comm_ring (localization M) := +instance : comm_semiring (localization M) := { zero := 0, one := 1, add := (+), @@ -787,31 +785,13 @@ instance : comm_ring (localization M) := (λ x, by simp only [smul_mk, zero_nsmul, mk_zero]), nsmul_succ' := λ n x, localization.induction_on x (λ x, by simp only [smul_mk, succ_nsmul, add_mk_self]), - zsmul := (•), - zsmul_zero' := λ x, localization.induction_on x - (λ x, by simp only [smul_mk, zero_zsmul, mk_zero]), - zsmul_succ' := λ n x, localization.induction_on x - (λ x, by simp [smul_mk, add_mk_self, -mk_eq_monoid_of_mk', add_comm (n : ℤ) 1, add_smul]), - zsmul_neg' := λ n x, localization.induction_on x - (λ x, by { rw [smul_mk, smul_mk, neg_mk, ← neg_smul], refl }), add_assoc := λ m n k, localization.induction_on₃ m n k (by tac), zero_add := λ y, localization.induction_on y (by tac), add_zero := λ y, localization.induction_on y (by tac), - neg := has_neg.neg, - sub := λ x y, x + -y, - sub_eq_add_neg := λ x y, rfl, - add_left_neg := λ y, by exact localization.induction_on y (by tac), add_comm := λ y z, localization.induction_on₂ z y (by tac), left_distrib := λ m n k, localization.induction_on₃ m n k (by tac), right_distrib := λ m n k, localization.induction_on₃ m n k (by tac), - ..localization.comm_monoid M } - -lemma sub_mk (a c) (b d) : (mk a b : localization M) - mk c d = mk (d * a - b * c) (b * d) := -calc mk a b - mk c d - = mk a b + (- mk c d) : sub_eq_add_neg _ _ -... = mk a b + (mk (-c) d) : by rw neg_mk -... = mk (b * (-c) + d * a) (b * d) : add_mk _ _ _ _ -... = mk (d * a - b * c) (b * d) : by congr'; ring + .. localization.comm_monoid_with_zero M } instance {S : Type*} [monoid S] [distrib_mul_action S R] [is_scalar_tower S R R] : distrib_mul_action S (localization M) := @@ -879,10 +859,8 @@ lemma mk_algebra_map {A : Type*} [comm_semiring A] [algebra A R] (m : A) : mk (algebra_map A R m) 1 = algebra_map A (localization M) m := by rw [mk_eq_mk', mk'_eq_iff_eq_mul, submonoid.coe_one, map_one, mul_one]; refl -lemma mk_int_cast (m : ℤ) : (mk m 1 : localization M) = m := -by simpa using @mk_algebra_map R _ M ℤ _ _ m - -lemma mk_nat_cast (m : ℕ) : (mk m 1 : localization M) = m := mk_int_cast m +lemma mk_nat_cast (m : ℕ) : (mk m 1 : localization M) = m := +by simpa using @mk_algebra_map R _ M ℕ _ _ m variables [is_localization M S] @@ -896,7 +874,7 @@ noncomputable def alg_equiv : localization M ≃ₐ[R] S := is_localization.alg_equiv M _ _ /-- The localization of a singleton is a singleton. Cannot be an instance due to metavariables. -/ -noncomputable def _root_.is_localization.unique (R Rₘ) [comm_ring R] [comm_ring Rₘ] +noncomputable def _root_.is_localization.unique (R Rₘ) [comm_semiring R] [comm_semiring Rₘ] (M : submonoid R) [subsingleton R] [algebra R Rₘ] [is_localization M Rₘ] : unique Rₘ := have inhabited Rₘ := ⟨1⟩, by exactI (alg_equiv M Rₘ).symm.injective.unique @@ -921,6 +899,64 @@ by rw [mk_eq_mk', alg_equiv_symm_mk'] end localization +end comm_semiring + +section comm_ring +variables {R : Type*} [comm_ring R] {M : submonoid R} (S : Type*) [comm_ring S] +variables [algebra R S] {P : Type*} [comm_ring P] + +namespace localization + +/-- Negation in a ring localization is defined as `-⟨a, b⟩ = ⟨-a, b⟩`. -/ +@[irreducible] protected def neg (z : localization M) : localization M := +localization.lift_on z (λ a b, mk (-a) b) $ + λ a b c d h, mk_eq_mk_iff.2 +begin + rw r_eq_r' at h ⊢, + cases h with t ht, + use t, + rw [neg_mul, neg_mul, ht], + ring_nf, +end + +instance : has_neg (localization M) := ⟨localization.neg⟩ + +lemma neg_mk (a b) : -(mk a b : localization M) = mk (-a) b := +by { unfold has_neg.neg localization.neg, apply lift_on_mk } + +instance : comm_ring (localization M) := +{ zsmul := (•), + zsmul_zero' := λ x, localization.induction_on x + (λ x, by simp only [smul_mk, zero_zsmul, mk_zero]), + zsmul_succ' := λ n x, localization.induction_on x + (λ x, by simp [smul_mk, add_mk_self, -mk_eq_monoid_of_mk', add_comm (n : ℤ) 1, add_smul]), + zsmul_neg' := λ n x, localization.induction_on x + (λ x, by { rw [smul_mk, smul_mk, neg_mk, ← neg_smul], refl }), + neg := has_neg.neg, + sub := λ x y, x + -y, + sub_eq_add_neg := λ x y, rfl, + add_left_neg := λ y, by exact localization.induction_on y + begin + intros, + simp only [add_mk, localization.mk_mul, neg_mk, ← mk_zero 1], + refine mk_eq_mk_iff.mpr (r_of_eq _), + simp only [submonoid.coe_mul], + ring + end, + .. localization.comm_semiring } + +lemma sub_mk (a c) (b d) : (mk a b : localization M) - mk c d = mk (d * a - b * c) (b * d) := +calc mk a b - mk c d + = mk a b + (- mk c d) : sub_eq_add_neg _ _ +... = mk a b + (mk (-c) d) : by rw neg_mk +... = mk (b * (-c) + d * a) (b * d) : add_mk _ _ _ _ +... = mk (d * a - b * c) (b * d) : by congr'; ring + +lemma mk_int_cast (m : ℤ) : (mk m 1 : localization M) = m := +by simpa using @mk_algebra_map R _ M ℤ _ _ m + +end localization + namespace is_localization variables {R M} (S) {K : Type*} [is_localization M S] @@ -983,7 +1019,7 @@ theorem is_domain_of_le_non_zero_divisors cases surj M w with y hy, have : z * w * algebra_map A S y.2 * algebra_map A S x.2 = algebra_map A S x.1 * algebra_map A S y.1, - by rw [mul_assoc z, hy, ←hx]; ac_refl, + by rw [mul_assoc z, hy, ←hx]; ring, rw [h, zero_mul, zero_mul, ← (algebra_map A S).map_mul] at this, cases eq_zero_or_eq_zero_of_mul_eq_zero ((to_map_eq_zero_iff S hM).mp this.symm) with H H, { exact or.inl (eq_zero_of_fst_eq_zero hx H) }, @@ -1063,3 +1099,5 @@ lemma localization_algebra_injective (hRS : function.injective (algebra_map R S) is_localization.map_injective_of_injective M Rₘ Sₘ hRS hM end algebra + +end comm_ring From 8edb3d16685c496558e9797fb894adb0c6af3306 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Fri, 29 Apr 2022 03:48:10 +0000 Subject: [PATCH 305/373] feat(representation_theory/Rep): the category of representations (#13683) We define `Rep k G`, the category of `k`-linear representations of a monoid `G`. Happily, by abstract nonsense we get that this has (co)limits and a monoidal structure for free. This should play well with the new design for representations in #13573. Co-authored-by: Scott Morrison --- src/representation_theory/Action.lean | 323 ++++++++++++++++++++++++++ src/representation_theory/Rep.lean | 68 ++++++ 2 files changed, 391 insertions(+) create mode 100644 src/representation_theory/Action.lean create mode 100644 src/representation_theory/Rep.lean diff --git a/src/representation_theory/Action.lean b/src/representation_theory/Action.lean new file mode 100644 index 0000000000000..8b2ac37b7a33a --- /dev/null +++ b/src/representation_theory/Action.lean @@ -0,0 +1,323 @@ +/- +Copyright (c) 2020 Scott Morrison. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Scott Morrison +-/ +import algebra.category.Group.basic +import category_theory.single_obj +import category_theory.limits.functor_category +import category_theory.limits.preserves.basic +import category_theory.adjunction.limits +import category_theory.monoidal.functor_category +import category_theory.monoidal.transport + +/-! +# `Action V G`, the category of actions of a monoid `G` inside some category `V`. + +The prototypical example is `V = Module R`, +where `Action (Module R) G` is the category of `R`-linear representations of `G`. + +We check `Action V G ≌ (single_obj G ⥤ V)`, +and construct the restriction functors `res {G H : Mon} (f : G ⟶ H) : Action V H ⥤ Action V G`. + +When `V` has (co)limits so does `Action V G`. When `V` is monoidal so is `Action V G`. +-/ + +universes u + +open category_theory +open category_theory.limits + +variables (V : Type (u+1)) [large_category V] + +/-- +An `Action V G` represents a bundled action of +the monoid `G` on an object of some category `V`. + +As an example, when `V = Module R`, this is an `R`-linear representation of `G`, +while when `V = Type` this is a `G`-action. +-/ +-- Note: this is _not_ a categorical action of `G` on `V`. +structure Action (G : Mon.{u}) := +(V : V) +(ρ : G ⟶ Mon.of (End V)) + +namespace Action +variable {V} + +@[simp] +lemma ρ_one {G : Mon.{u}} (A : Action V G) : A.ρ 1 = 𝟙 A.V := +by { rw [monoid_hom.map_one], refl, } + +/-- When a group acts, we can lift the action to the group of automorphisms. -/ +@[simps] +def ρ_Aut {G : Group.{u}} (A : Action V (Mon.of G)) : G ⟶ Group.of (Aut A.V) := +{ to_fun := λ g, + { hom := A.ρ g, + inv := A.ρ (g⁻¹ : G), + hom_inv_id' := ((A.ρ).map_mul (g⁻¹ : G) g).symm.trans (by rw [inv_mul_self, ρ_one]), + inv_hom_id' := ((A.ρ).map_mul g (g⁻¹ : G)).symm.trans (by rw [mul_inv_self, ρ_one]), }, + map_one' := by { ext, exact A.ρ.map_one }, + map_mul' := λ x y, by { ext, exact A.ρ.map_mul x y }, } + +variable (G : Mon.{u}) + +section + +/-- The trivial representation of a group. -/ +def trivial : Action AddCommGroup G := +{ V := AddCommGroup.of punit, + ρ := 1, } + +instance : inhabited (Action AddCommGroup G) := ⟨trivial G⟩ +end + +variables {G V} + +/-- +A homomorphism of `Action V G`s is a morphism between the underlying objects, +commuting with the action of `G`. +-/ +@[ext] +structure hom (M N : Action V G) := +(hom : M.V ⟶ N.V) +(comm' : ∀ g : G, M.ρ g ≫ hom = hom ≫ N.ρ g . obviously) + +restate_axiom hom.comm' + +namespace hom + +/-- The identity morphism on a `Action V G`. -/ +@[simps] +def id (M : Action V G) : Action.hom M M := +{ hom := 𝟙 M.V } + +instance (M : Action V G) : inhabited (Action.hom M M) := ⟨id M⟩ + +/-- +The composition of two `Action V G` homomorphisms is the composition of the underlying maps. +-/ +@[simps] +def comp {M N K : Action V G} (p : Action.hom M N) (q : Action.hom N K) : + Action.hom M K := +{ hom := p.hom ≫ q.hom, + comm' := λ g, by rw [←category.assoc, p.comm, category.assoc, q.comm, ←category.assoc] } + +end hom + +instance : category (Action V G) := +{ hom := λ M N, hom M N, + id := λ M, hom.id M, + comp := λ M N K f g, hom.comp f g, } + +@[simp] +lemma id_hom (M : Action V G) : (𝟙 M : hom M M).hom = 𝟙 M.V := rfl +@[simp] +lemma comp_hom {M N K : Action V G} (f : M ⟶ N) (g : N ⟶ K) : + (f ≫ g : hom M K).hom = f.hom ≫ g.hom := +rfl + +/-- Construct an isomorphism of `G` actions/representations +from an isomorphism of the the underlying objects, +where the forward direction commutes with the group action. -/ +@[simps] +def mk_iso {M N : Action V G} (f : M.V ≅ N.V) (comm : ∀ g : G, M.ρ g ≫ f.hom = f.hom ≫ N.ρ g) : + M ≅ N := +{ hom := + { hom := f.hom, + comm' := comm, }, + inv := + { hom := f.inv, + comm' := λ g, by { have w := comm g =≫ f.inv, simp at w, simp [w], }, }} + +namespace functor_category_equivalence + +/-- Auxilliary definition for `functor_category_equivalence`. -/ +@[simps] +def functor : Action V G ⥤ (single_obj G ⥤ V) := +{ obj := λ M, + { obj := λ _, M.V, + map := λ _ _ g, M.ρ g, + map_id' := λ _, M.ρ.map_one, + map_comp' := λ _ _ _ g h, M.ρ.map_mul h g, }, + map := λ M N f, + { app := λ _, f.hom, + naturality' := λ _ _ g, f.comm g, } } + +/-- Auxilliary definition for `functor_category_equivalence`. -/ +@[simps] +def inverse : (single_obj G ⥤ V) ⥤ Action V G := +{ obj := λ F, + { V := F.obj punit.star, + ρ := + { to_fun := λ g, F.map g, + map_one' := F.map_id punit.star, + map_mul' := λ g h, F.map_comp h g, } }, + map := λ M N f, + { hom := f.app punit.star, + comm' := λ g, f.naturality g, } }. + +/-- Auxilliary definition for `functor_category_equivalence`. -/ +@[simps] +def unit_iso : 𝟭 (Action V G) ≅ functor ⋙ inverse := +nat_iso.of_components (λ M, mk_iso ((iso.refl _)) (by tidy)) (by tidy). + +/-- Auxilliary definition for `functor_category_equivalence`. -/ +@[simps] +def counit_iso : inverse ⋙ functor ≅ 𝟭 (single_obj G ⥤ V) := +nat_iso.of_components (λ M, nat_iso.of_components (by tidy) (by tidy)) (by tidy). + +end functor_category_equivalence + +section +open functor_category_equivalence + +variables (V G) + +/-- +The category of actions of `G` in the category `V` +is equivalent to the functor category `single_obj G ⥤ V`. +-/ +def functor_category_equivalence : Action V G ≌ (single_obj G ⥤ V) := +{ functor := functor, + inverse := inverse, + unit_iso := unit_iso, + counit_iso := counit_iso, } + +attribute [simps] functor_category_equivalence + +instance [has_limits V] : has_limits (Action V G) := +adjunction.has_limits_of_equivalence (Action.functor_category_equivalence _ _).functor + +instance [has_colimits V] : has_colimits (Action V G) := +adjunction.has_colimits_of_equivalence (Action.functor_category_equivalence _ _).functor + +end + +section forget + +variables (V G) + +/-- (implementation) The forgetful functor from bundled actions to the underlying objects. + +Use the `category_theory.forget` API provided by the `concrete_category` instance below, +rather than using this directly. +-/ +@[simps] +def forget : Action V G ⥤ V := +{ obj := λ M, M.V, + map := λ M N f, f.hom, } + +instance [concrete_category V] : concrete_category (Action V G) := +{ forget := forget V G ⋙ (concrete_category.forget V), + forget_faithful := + { map_injective' := λ M N f g w, + hom.ext _ _ (faithful.map_injective (concrete_category.forget V) w), } } + +instance has_forget_to_V [concrete_category V] : has_forget₂ (Action V G) V := +{ forget₂ := forget V G } + +/-- The forgetful functor is intertwined by `functor_category_equivalence` with +evaluation at `punit.star`. -/ +def functor_category_equivalence_comp_evaluation : + (functor_category_equivalence V G).functor ⋙ (evaluation _ _).obj punit.star ≅ forget V G := +iso.refl _ + +noncomputable instance [has_limits V] : limits.preserves_limits (forget V G) := +limits.preserves_limits_of_nat_iso + (Action.functor_category_equivalence_comp_evaluation V G) + +noncomputable instance [has_colimits V] : preserves_colimits (forget V G) := +preserves_colimits_of_nat_iso + (Action.functor_category_equivalence_comp_evaluation V G) + +-- TODO construct categorical images? + +end forget + +section monoidal + +instance [monoidal_category V] : monoidal_category (Action V G) := +monoidal.transport (Action.functor_category_equivalence _ _).symm + +/-- When `V` is monoidal the forgetful functor `Action V G` to `V` is monoidal. -/ +@[simps] +def forget_monoidal [monoidal_category V] : monoidal_functor (Action V G) V := +{ ε := 𝟙 _, + μ := λ X Y, 𝟙 _, + ..Action.forget _ _, } + +-- TODO braiding and symmetry + +end monoidal + +/-- Actions/representations of the trivial group are just objects in the ambient category. -/ +def Action_punit_equivalence : Action V (Mon.of punit) ≌ V := +{ functor := forget V _, + inverse := + { obj := λ X, ⟨X, 1⟩, + map := λ X Y f, ⟨f, λ ⟨⟩, by simp⟩, }, + unit_iso := nat_iso.of_components (λ X, mk_iso (iso.refl _) (λ ⟨⟩, by simpa using ρ_one X)) + (by tidy), + counit_iso := nat_iso.of_components (λ X, iso.refl _) (by tidy), } + +variables (V) +/-- +The "restriction" functor along a monoid homomorphism `f : G ⟶ H`, +taking actions of `H` to actions of `G`. + +(This makes sense for any homomorphism, but the name is natural when `f` is a monomorphism.) +-/ +@[simps] +def res {G H : Mon} (f : G ⟶ H) : Action V H ⥤ Action V G := +{ obj := λ M, + { V := M.V, + ρ := f ≫ M.ρ }, + map := λ M N p, + { hom := p.hom, + comm' := λ g, p.comm (f g) } } + +/-- +The natural isomorphism from restriction along the identity homomorphism to +the identity functor on `Action V G`. +-/ +def res_id {G : Mon} : res V (𝟙 G) ≅ 𝟭 (Action V G) := +nat_iso.of_components (λ M, mk_iso (iso.refl _) (by tidy)) (by tidy) + +attribute [simps] res_id + +/-- +The natural isomorphism from the composition of restrictions along homomorphisms +to the restriction along the composition of homomorphism. +-/ +def res_comp {G H K : Mon} (f : G ⟶ H) (g : H ⟶ K) : res V g ⋙ res V f ≅ res V (f ≫ g) := +nat_iso.of_components (λ M, mk_iso (iso.refl _) (by tidy)) (by tidy) + +attribute [simps] res_comp + +-- TODO promote `res` to a pseudofunctor from +-- the locally discrete bicategory constructed from `Monᵒᵖ` to `Cat`, sending `G` to `Action V G`. + +end Action + +namespace category_theory.functor + +variables {V} {W : Type (u+1)} [large_category W] + +/-- A functor between categories induces a functor between +the categories of `G`-actions within those categories. -/ +@[simps] +def map_Action (F : V ⥤ W) (G : Mon.{u}) : Action V G ⥤ Action W G := +{ obj := λ M, + { V := F.obj M.V, + ρ := + { to_fun := λ g, F.map (M.ρ g), + map_one' := by simp only [End.one_def, Action.ρ_one, F.map_id], + map_mul' := λ g h, by simp only [End.mul_def, F.map_comp, map_mul], }, }, + map := λ M N f, + { hom := F.map f.hom, + comm' := λ g, by { dsimp, rw [←F.map_comp, f.comm, F.map_comp], }, }, + map_id' := λ M, by { ext, simp only [Action.id_hom, F.map_id], }, + map_comp' := λ M N P f g, by { ext, simp only [Action.comp_hom, F.map_comp], }, } + +end category_theory.functor diff --git a/src/representation_theory/Rep.lean b/src/representation_theory/Rep.lean new file mode 100644 index 0000000000000..b6a26aa1bedfb --- /dev/null +++ b/src/representation_theory/Rep.lean @@ -0,0 +1,68 @@ +/- +Copyright (c) 2020 Scott Morrison. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Scott Morrison +-/ +import representation_theory.Action +import algebra.category.Module.limits +import algebra.category.Module.colimits +import algebra.category.Module.monoidal + +/-! +# `Rep k G` is the category of `k`-linear representations of `G`. + +If `V : Rep k G`, there is a coercion that allows you to treat `V` as a type, +and this type comes equipped with a `module k V` instance. +Also `V.ρ` gives the homomorphism `G →* (V →ₗ[k] V)`. + +Conversely, given a homomorphism `ρ : G →* (V →ₗ[k] V)`, +you can construct the bundled representation as `Rep.of ρ`. + +We verify that `Rep k G` has all limits and colimits, and is a monoidal category. +-/ + +universes u + +open category_theory +open category_theory.limits + +/-- The category of `k`-linear representations of a monoid `G`. -/ +@[derive [large_category, concrete_category, has_limits, has_colimits]] +abbreviation Rep (k G : Type u) [ring k] [monoid G] := +Action (Module.{u} k) (Mon.of G) + +namespace Rep + +variables {k G : Type u} [ring k] [monoid G] + +instance : has_coe_to_sort (Rep k G) (Type u) := concrete_category.has_coe_to_sort _ + +instance (V : Rep k G) : add_comm_monoid V := +by { change add_comm_monoid ((forget₂ (Rep k G) (Module k)).obj V), apply_instance, } + +instance (V : Rep k G) : module k V := +by { change module k ((forget₂ (Rep k G) (Module k)).obj V), apply_instance, } + +-- This works well with the new design for representations: +example (V : Rep k G) : G →* (V →ₗ[k] V) := V.ρ + +/-- Lift an unbundled representation to `Rep`. -/ +@[simps ρ] +def of {V : Type u} [add_comm_group V] [module k V] (ρ : G →* (V →ₗ[k] V)) : Rep k G := +⟨Module.of k V, ρ⟩ + +-- Verify that limits are calculated correctly. +noncomputable example : preserves_limits (forget₂ (Rep k G) (Module.{u} k)) := +by apply_instance +noncomputable example : preserves_colimits (forget₂ (Rep k G) (Module.{u} k)) := +by apply_instance + +end Rep + +namespace Rep +variables {k G : Type u} [comm_ring k] [monoid G] + +-- Verify that the monoidal structure is available. +example : monoidal_category (Rep k G) := by apply_instance + +end Rep From ccb9d64b28b39473d67e9c244e5653e7a0ec0139 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Fri, 29 Apr 2022 04:24:23 +0000 Subject: [PATCH 306/373] feat(category_theory/braiding): pull back a braiding along a faithful functor (#13684) I intend to use this to define the braiding/symmetry on `Rep k G` using the existing braiding/symmetry on `Module k`. Co-authored-by: Scott Morrison --- src/algebraic_geometry/open_immersion.lean | 6 +- src/algebraic_geometry/sheafed_space.lean | 4 +- src/category_theory/equivalence.lean | 2 +- .../functor/fully_faithful.lean | 29 ++++++---- src/category_theory/monoidal/braided.lean | 58 +++++++++++++++++++ src/category_theory/subobject/mono_over.lean | 2 +- src/category_theory/yoneda.lean | 3 +- 7 files changed, 82 insertions(+), 22 deletions(-) diff --git a/src/algebraic_geometry/open_immersion.lean b/src/algebraic_geometry/open_immersion.lean index 194de629f2da3..cfd68e0f51f0d 100644 --- a/src/algebraic_geometry/open_immersion.lean +++ b/src/algebraic_geometry/open_immersion.lean @@ -1066,12 +1066,12 @@ def iso_restrict {X Y : LocallyRingedSpace} {f : X ⟶ Y} (H : LocallyRingedSpace.is_open_immersion f) : X ≅ Y.restrict H.base_open := begin apply LocallyRingedSpace.iso_of_SheafedSpace_iso, - apply @preimage_iso _ _ _ _ SheafedSpace.forget_to_PresheafedSpace, + refine SheafedSpace.forget_to_PresheafedSpace.preimage_iso _, exact H.iso_restrict end /-- To show that a locally ringed space is a scheme, it suffices to show that it has a jointly -sujective family of open immersions from affine schemes. -/ +surjective family of open immersions from affine schemes. -/ protected def Scheme (X : LocallyRingedSpace) (h : ∀ (x : X), ∃ (R : CommRing) (f : Spec.to_LocallyRingedSpace.obj (op R) ⟶ X), (x ∈ set.range f.1.base : _) ∧ LocallyRingedSpace.is_open_immersion f) : Scheme := @@ -1082,7 +1082,7 @@ protected def Scheme (X : LocallyRingedSpace) obtain ⟨R, f, h₁, h₂⟩ := h x, refine ⟨⟨⟨_, h₂.base_open.open_range⟩, h₁⟩, R, ⟨_⟩⟩, apply LocallyRingedSpace.iso_of_SheafedSpace_iso, - apply @preimage_iso _ _ _ _ SheafedSpace.forget_to_PresheafedSpace, + refine SheafedSpace.forget_to_PresheafedSpace.preimage_iso _, resetI, apply PresheafedSpace.is_open_immersion.iso_of_range_eq (PresheafedSpace.of_restrict _ _) f.1, { exact subtype.range_coe_subtype }, diff --git a/src/algebraic_geometry/sheafed_space.lean b/src/algebraic_geometry/sheafed_space.lean index 884b4b8dc3d2a..c7e77102ec00a 100644 --- a/src/algebraic_geometry/sheafed_space.lean +++ b/src/algebraic_geometry/sheafed_space.lean @@ -129,9 +129,7 @@ The restriction of a sheafed space `X` to the top subspace is isomorphic to `X` -/ def restrict_top_iso (X : SheafedSpace C) : X.restrict (opens.open_embedding ⊤) ≅ X := -@preimage_iso _ _ _ _ forget_to_PresheafedSpace _ _ - (X.restrict (opens.open_embedding ⊤)) _ - X.to_PresheafedSpace.restrict_top_iso +forget_to_PresheafedSpace.preimage_iso X.to_PresheafedSpace.restrict_top_iso /-- The global sections, notated Gamma. diff --git a/src/category_theory/equivalence.lean b/src/category_theory/equivalence.lean index ba7e2d15dc1b7..d6ad677798952 100644 --- a/src/category_theory/equivalence.lean +++ b/src/category_theory/equivalence.lean @@ -603,7 +603,7 @@ noncomputable def of_fully_faithfully_ess_surj (F : C ⥤ D) [full F] [faithful F] [ess_surj F] : is_equivalence F := is_equivalence.mk (equivalence_inverse F) (nat_iso.of_components - (λ X, (preimage_iso $ F.obj_obj_preimage_iso $ F.obj X).symm) + (λ X, (F.preimage_iso $ F.obj_obj_preimage_iso $ F.obj X).symm) (λ X Y f, by { apply F.map_injective, obviously })) (nat_iso.of_components F.obj_obj_preimage_iso (by tidy)) diff --git a/src/category_theory/functor/fully_faithful.lean b/src/category_theory/functor/fully_faithful.lean index 91c964a370871..dfd7f853ab5cc 100644 --- a/src/category_theory/functor/fully_faithful.lean +++ b/src/category_theory/functor/fully_faithful.lean @@ -53,20 +53,23 @@ class faithful (F : C ⥤ D) : Prop := restate_axiom faithful.map_injective' namespace functor -lemma map_injective (F : C ⥤ D) [faithful F] {X Y : C} : +variables {X Y : C} + +lemma map_injective (F : C ⥤ D) [faithful F] : function.injective $ @functor.map _ _ _ _ F X Y := faithful.map_injective F -lemma map_iso_injective (F : C ⥤ D) [faithful F] {X Y : C} : +lemma map_iso_injective (F : C ⥤ D) [faithful F] : function.injective $ @functor.map_iso _ _ _ _ F X Y := λ i j h, iso.ext (map_injective F (congr_arg iso.hom h : _)) /-- The specified preimage of a morphism under a full functor. -/ -def preimage (F : C ⥤ D) [full F] {X Y : C} (f : F.obj X ⟶ F.obj Y) : X ⟶ Y := +def preimage (F : C ⥤ D) [full F] (f : F.obj X ⟶ F.obj Y) : X ⟶ Y := full.preimage.{v₁ v₂} f @[simp] lemma image_preimage (F : C ⥤ D) [full F] {X Y : C} (f : F.obj X ⟶ F.obj Y) : F.map (preimage F f) = f := by unfold preimage; obviously + end functor section @@ -81,21 +84,23 @@ F.map_injective (by simp) F.preimage (F.map f) = f := F.map_injective (by simp) +variables (F) + +namespace functor + /-- If `F : C ⥤ D` is fully faithful, every isomorphism `F.obj X ≅ F.obj Y` has a preimage. -/ +@[simps] def preimage_iso (f : (F.obj X) ≅ (F.obj Y)) : X ≅ Y := { hom := F.preimage f.hom, inv := F.preimage f.inv, hom_inv_id' := F.map_injective (by simp), inv_hom_id' := F.map_injective (by simp), } -@[simp] lemma preimage_iso_hom (f : (F.obj X) ≅ (F.obj Y)) : - (preimage_iso f).hom = F.preimage f.hom := rfl -@[simp] lemma preimage_iso_inv (f : (F.obj X) ≅ (F.obj Y)) : - (preimage_iso f).inv = F.preimage (f.inv) := rfl -@[simp] lemma preimage_iso_map_iso (f : X ≅ Y) : preimage_iso (F.map_iso f) = f := -by tidy +@[simp] lemma preimage_iso_map_iso (f : X ≅ Y) : + F.preimage_iso (F.map_iso f) = f := +by { ext, simp, } -variables (F) +end functor /-- If the image of a morphism under a fully faithful functor in an isomorphism, @@ -117,7 +122,7 @@ def equiv_of_fully_faithful {X Y} : (X ⟶ Y) ≃ (F.obj X ⟶ F.obj Y) := @[simps] def iso_equiv_of_fully_faithful {X Y} : (X ≅ Y) ≃ (F.obj X ≅ F.obj Y) := { to_fun := λ f, F.map_iso f, - inv_fun := λ f, preimage_iso f, + inv_fun := λ f, F.preimage_iso f, left_inv := λ f, by simp, right_inv := λ f, by { ext, simp, } } @@ -275,7 +280,7 @@ can 'cancel' it to give a natural iso between `F` and `G`. def fully_faithful_cancel_right {F G : C ⥤ D} (H : D ⥤ E) [full H] [faithful H] (comp_iso: F ⋙ H ≅ G ⋙ H) : F ≅ G := nat_iso.of_components - (λ X, preimage_iso (comp_iso.app X)) + (λ X, H.preimage_iso (comp_iso.app X)) (λ X Y f, H.map_injective (by simpa using comp_iso.hom.naturality f)) @[simp] diff --git a/src/category_theory/monoidal/braided.lean b/src/category_theory/monoidal/braided.lean index f9e0c6d9f857a..2f50077581659 100644 --- a/src/category_theory/monoidal/braided.lean +++ b/src/category_theory/monoidal/braided.lean @@ -57,6 +57,7 @@ restate_axiom braided_category.braiding_naturality' attribute [simp,reassoc] braided_category.braiding_naturality restate_axiom braided_category.hexagon_forward' restate_axiom braided_category.hexagon_reverse' +attribute [reassoc] braided_category.hexagon_forward braided_category.hexagon_reverse open category open monoidal_category @@ -64,6 +65,57 @@ open braided_category notation `β_` := braiding +/-- +Verifying the axioms for a braiding by checking that the candidate braiding is sent to a braiding +by a faithful monoidal functor. +-/ +def braided_category_of_faithful {C D : Type*} [category C] [category D] + [monoidal_category C] [monoidal_category D] (F : monoidal_functor C D) [faithful F.to_functor] + [braided_category D] (β : Π X Y : C, X ⊗ Y ≅ Y ⊗ X) + (w : ∀ X Y, F.μ _ _ ≫ F.map (β X Y).hom = (β_ _ _).hom ≫ F.μ _ _) : braided_category C := +{ braiding := β, + braiding_naturality' := begin + intros, + apply F.to_functor.map_injective, + refine (cancel_epi (F.μ _ _)).1 _, + rw [functor.map_comp, ←lax_monoidal_functor.μ_natural_assoc, w, functor.map_comp, reassoc_of w, + braiding_naturality_assoc, lax_monoidal_functor.μ_natural], + end, + hexagon_forward' := begin + intros, + apply F.to_functor.map_injective, + refine (cancel_epi (F.μ _ _)).1 _, + refine (cancel_epi (F.μ _ _ ⊗ 𝟙 _)).1 _, + rw [functor.map_comp, functor.map_comp, functor.map_comp, functor.map_comp, + ←lax_monoidal_functor.μ_natural_assoc, functor.map_id, ←comp_tensor_id_assoc, w, + comp_tensor_id, category.assoc, lax_monoidal_functor.associativity_assoc, + lax_monoidal_functor.associativity_assoc, ←lax_monoidal_functor.μ_natural, functor.map_id, + ←id_tensor_comp_assoc, w, id_tensor_comp_assoc, reassoc_of w, braiding_naturality_assoc, + lax_monoidal_functor.associativity, hexagon_forward_assoc], + end, + hexagon_reverse' := begin + intros, + apply F.to_functor.map_injective, + refine (cancel_epi (F.μ _ _)).1 _, + refine (cancel_epi (𝟙 _ ⊗ F.μ _ _)).1 _, + rw [functor.map_comp, functor.map_comp, functor.map_comp, functor.map_comp, + ←lax_monoidal_functor.μ_natural_assoc, functor.map_id, ←id_tensor_comp_assoc, w, + id_tensor_comp_assoc, lax_monoidal_functor.associativity_inv_assoc, + lax_monoidal_functor.associativity_inv_assoc, ←lax_monoidal_functor.μ_natural, functor.map_id, + ←comp_tensor_id_assoc, w, comp_tensor_id_assoc, reassoc_of w, braiding_naturality_assoc, + lax_monoidal_functor.associativity_inv, hexagon_reverse_assoc], + end, } + +/-- Pull back a braiding along a fully faithful monoidal functor. -/ +noncomputable +def braided_category_of_fully_faithful {C D : Type*} [category C] [category D] + [monoidal_category C] [monoidal_category D] (F : monoidal_functor C D) + [full F.to_functor] [faithful F.to_functor] + [braided_category D] : braided_category C := +braided_category_of_faithful F (λ X Y, F.to_functor.preimage_iso + ((as_iso (F.μ _ _)).symm ≪≫ β_ (F.obj X) (F.obj Y) ≪≫ (as_iso (F.μ _ _)))) + (by tidy) + section /-! We now establish how the braiding interacts with the unitors. @@ -237,6 +289,12 @@ structure braided_functor extends monoidal_functor C D := restate_axiom braided_functor.braided' attribute [simp] braided_functor.braided +/-- A braided category with a braided functor to a symmetric category is itself symmetric. -/ +def symmetric_category_of_faithful {C D : Type*} [category C] [category D] + [monoidal_category C] [monoidal_category D] [braided_category C] [symmetric_category D] + (F : braided_functor C D) [faithful F.to_functor] : symmetric_category C := +{ symmetry' := λ X Y, F.to_functor.map_injective (by simp), } + namespace braided_functor /-- Turn a braided functor into a lax braided functor. -/ diff --git a/src/category_theory/subobject/mono_over.lean b/src/category_theory/subobject/mono_over.lean index 82736fdc2342c..4e60fe012c2db 100644 --- a/src/category_theory/subobject/mono_over.lean +++ b/src/category_theory/subobject/mono_over.lean @@ -370,7 +370,7 @@ nat_iso.of_components begin intro Z, suffices : (forget _).obj ((«exists» f).obj Z) ≅ (forget _).obj ((map f).obj Z), - apply preimage_iso this, + apply (forget _).preimage_iso this, apply over.iso_mk _ _, apply image_mono_iso_source (Z.arrow ≫ f), apply image_mono_iso_source_hom_self, diff --git a/src/category_theory/yoneda.lean b/src/category_theory/yoneda.lean index f0979847bc611..d87d09bac70d0 100644 --- a/src/category_theory/yoneda.lean +++ b/src/category_theory/yoneda.lean @@ -87,8 +87,7 @@ def ext (X Y : C) (p : Π {Z : C}, (Z ⟶ X) → (Z ⟶ Y)) (q : Π {Z : C}, (Z ⟶ Y) → (Z ⟶ X)) (h₁ : Π {Z : C} (f : Z ⟶ X), q (p f) = f) (h₂ : Π {Z : C} (f : Z ⟶ Y), p (q f) = f) (n : Π {Z Z' : C} (f : Z' ⟶ Z) (g : Z ⟶ X), p (f ≫ g) = f ≫ p g) : X ≅ Y := -@preimage_iso _ _ _ _ yoneda _ _ _ _ - (nat_iso.of_components (λ Z, { hom := p, inv := q, }) (by tidy)) +yoneda.preimage_iso (nat_iso.of_components (λ Z, { hom := p, inv := q, }) (by tidy)) /-- If `yoneda.map f` is an isomorphism, so was `f`. From e294500eabc804ed642de575684a5b8652870b18 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Fri, 29 Apr 2022 04:24:24 +0000 Subject: [PATCH 307/373] feat(category_theory/monoidal): transport rigid structure over an equivalence (#13736) Co-authored-by: Scott Morrison --- src/category_theory/monoidal/category.lean | 20 +++++ src/category_theory/monoidal/rigid.lean | 58 ++++++++++++- .../monoidal/rigid/of_equivalence.lean | 83 +++++++++++++++++++ 3 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 src/category_theory/monoidal/rigid/of_equivalence.lean diff --git a/src/category_theory/monoidal/category.lean b/src/category_theory/monoidal/category.lean index 2c0b9f1f9f5c7..f114b0ec245cb 100644 --- a/src/category_theory/monoidal/category.lean +++ b/src/category_theory/monoidal/category.lean @@ -300,6 +300,26 @@ lemma tensor_inv_hom_id {V W X Y Z : C} (f : V ≅ W) (g : X ⟶ Y) (h : Y ⟶ Z (g ⊗ f.inv) ≫ (h ⊗ f.hom) = (g ⊗ 𝟙 W) ≫ (h ⊗ 𝟙 W) := by rw [←tensor_comp, f.inv_hom_id, comp_tensor_id] +@[simp, reassoc] +lemma hom_inv_id_tensor' {V W X Y Z : C} (f : V ⟶ W) [is_iso f] (g : X ⟶ Y) (h : Y ⟶ Z) : + (f ⊗ g) ≫ (inv f ⊗ h) = (𝟙 V ⊗ g) ≫ (𝟙 V ⊗ h) := +by rw [←tensor_comp, is_iso.hom_inv_id, id_tensor_comp] + +@[simp, reassoc] +lemma inv_hom_id_tensor' {V W X Y Z : C} (f : V ⟶ W) [is_iso f] (g : X ⟶ Y) (h : Y ⟶ Z) : + (inv f ⊗ g) ≫ (f ⊗ h) = (𝟙 W ⊗ g) ≫ (𝟙 W ⊗ h) := +by rw [←tensor_comp, is_iso.inv_hom_id, id_tensor_comp] + +@[simp, reassoc] +lemma tensor_hom_inv_id' {V W X Y Z : C} (f : V ⟶ W) [is_iso f] (g : X ⟶ Y) (h : Y ⟶ Z) : + (g ⊗ f) ≫ (h ⊗ inv f) = (g ⊗ 𝟙 V) ≫ (h ⊗ 𝟙 V) := +by rw [←tensor_comp, is_iso.hom_inv_id, comp_tensor_id] + +@[simp, reassoc] +lemma tensor_inv_hom_id' {V W X Y Z : C} (f : V ⟶ W) [is_iso f] (g : X ⟶ Y) (h : Y ⟶ Z) : + (g ⊗ inv f) ≫ (h ⊗ f) = (g ⊗ 𝟙 W) ≫ (h ⊗ 𝟙 W) := +by rw [←tensor_comp, is_iso.inv_hom_id, comp_tensor_id] + end section diff --git a/src/category_theory/monoidal/rigid.lean b/src/category_theory/monoidal/rigid.lean index 8d4d32fcd4ac1..ea296f09dde89 100644 --- a/src/category_theory/monoidal/rigid.lean +++ b/src/category_theory/monoidal/rigid.lean @@ -75,9 +75,9 @@ notation `η_` := exact_pairing.coevaluation notation `ε_` := exact_pairing.evaluation restate_axiom coevaluation_evaluation' -attribute [reassoc, simp] exact_pairing.coevaluation_evaluation +attribute [simp, reassoc] exact_pairing.coevaluation_evaluation restate_axiom evaluation_coevaluation' -attribute [reassoc, simp] exact_pairing.evaluation_coevaluation +attribute [simp, reassoc] exact_pairing.evaluation_coevaluation instance exact_pairing_unit : exact_pairing (𝟙_ C) (𝟙_ C) := { coevaluation := (ρ_ _).inv, @@ -227,6 +227,60 @@ begin right_unitor_naturality_assoc, ←unitors_equal, ←category.assoc, ←category.assoc], simp end +/-- Transport an exact pairing across an isomorphism in the first argument. -/ +def exact_pairing_congr_left {X X' Y : C} [exact_pairing X' Y] (i : X ≅ X') : exact_pairing X Y := +{ evaluation := (𝟙 Y ⊗ i.hom) ≫ ε_ _ _, + coevaluation := η_ _ _ ≫ (i.inv ⊗ 𝟙 Y), + evaluation_coevaluation' := begin + rw [id_tensor_comp, comp_tensor_id], + slice_lhs 2 3 { rw [associator_naturality], }, + slice_lhs 3 4 { rw [tensor_id, tensor_id_comp_id_tensor, ←id_tensor_comp_tensor_id], }, + slice_lhs 4 5 { rw [tensor_id_comp_id_tensor, ←id_tensor_comp_tensor_id], }, + slice_lhs 2 3 { rw [←associator_naturality], }, + slice_lhs 1 2 { rw [tensor_id, tensor_id_comp_id_tensor, ←id_tensor_comp_tensor_id], }, + slice_lhs 2 4 { rw [evaluation_coevaluation], }, + slice_lhs 1 2 { rw [left_unitor_naturality], }, + slice_lhs 3 4 { rw [←right_unitor_inv_naturality], }, + simp, + end, + coevaluation_evaluation' := begin + rw [id_tensor_comp, comp_tensor_id], + simp only [iso.inv_hom_id_assoc, associator_conjugation, category.assoc], + slice_lhs 2 3 { rw [←tensor_comp], simp, }, + simp, + end, } + +/-- Transport an exact pairing across an isomorphism in the second argument. -/ +def exact_pairing_congr_right {X Y Y' : C} [exact_pairing X Y'] (i : Y ≅ Y') : exact_pairing X Y := +{ evaluation := (i.hom ⊗ 𝟙 X) ≫ ε_ _ _, + coevaluation := η_ _ _ ≫ (𝟙 X ⊗ i.inv), + evaluation_coevaluation' := begin + rw [id_tensor_comp, comp_tensor_id], + simp only [iso.inv_hom_id_assoc, associator_conjugation, category.assoc], + slice_lhs 3 4 { rw [←tensor_comp], simp, }, + simp, + end, + coevaluation_evaluation' := begin + rw [id_tensor_comp, comp_tensor_id], + slice_lhs 3 4 { rw [←associator_inv_naturality], }, + slice_lhs 2 3 { rw [tensor_id, id_tensor_comp_tensor_id, ←tensor_id_comp_id_tensor], }, + slice_lhs 1 2 { rw [id_tensor_comp_tensor_id, ←tensor_id_comp_id_tensor], }, + slice_lhs 3 4 { rw [associator_inv_naturality], }, + slice_lhs 4 5 { rw [tensor_id, id_tensor_comp_tensor_id, ←tensor_id_comp_id_tensor], }, + slice_lhs 2 4 { rw [coevaluation_evaluation], }, + slice_lhs 1 2 { rw [right_unitor_naturality], }, + slice_lhs 3 4 { rw [←left_unitor_inv_naturality], }, + simp, + end, } + +/-- Transport an exact pairing across isomorphisms. -/ +def exact_pairing_congr {X X' Y Y' : C} [exact_pairing X' Y'] (i : X ≅ X') (j : Y ≅ Y') : + exact_pairing X Y := +begin + haveI : exact_pairing X' Y := exact_pairing_congr_right j, + exact exact_pairing_congr_left i, +end + /-- Right duals are isomorphic. -/ def right_dual_iso {X Y₁ Y₂ : C} (_ : exact_pairing X Y₁) (_ : exact_pairing X Y₂) : Y₁ ≅ Y₂ := diff --git a/src/category_theory/monoidal/rigid/of_equivalence.lean b/src/category_theory/monoidal/rigid/of_equivalence.lean new file mode 100644 index 0000000000000..4a67599bd27d3 --- /dev/null +++ b/src/category_theory/monoidal/rigid/of_equivalence.lean @@ -0,0 +1,83 @@ +/- +Copyright (c) 2022 Scott Morrison. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Scott Morrison +-/ +import category_theory.monoidal.rigid + +/-! +# Transport rigid structures over a monoidal equivalence. +-/ + +noncomputable theory + +namespace category_theory + +variables {C D : Type*} [category C] [category D] [monoidal_category C] [monoidal_category D] +variables (F : monoidal_functor C D) + +/-- Given candidate data for an exact pairing, +which is sent by a faithful monoidal functor to an exact pairing, +the equations holds automatically. -/ +def exact_pairing_of_faithful [faithful F.to_functor] + {X Y : C} (eval : Y ⊗ X ⟶ 𝟙_ C) (coeval : 𝟙_ C ⟶ X ⊗ Y) + [exact_pairing (F.obj X) (F.obj Y)] + (map_eval : F.map eval = inv (F.μ _ _) ≫ ε_ _ _ ≫ F.ε) + (map_coeval : F.map coeval = inv F.ε ≫ η_ _ _ ≫ F.μ _ _) : exact_pairing X Y := +{ evaluation := eval, + coevaluation := coeval, + evaluation_coevaluation' := F.to_functor.map_injective + (by simp [map_eval, map_coeval, monoidal_functor.map_tensor]), + coevaluation_evaluation' := F.to_functor.map_injective + (by simp [map_eval, map_coeval, monoidal_functor.map_tensor]), } + +/-- +Given a pair of objects which are sent by a fully faithful functor to a pair of objects +with an exact pairing, we get an exact pairing. +-/ +def exact_pairing_of_fully_faithful [full F.to_functor] [faithful F.to_functor] (X Y : C) + [exact_pairing (F.obj X) (F.obj Y)] : exact_pairing X Y := +exact_pairing_of_faithful F + (F.to_functor.preimage (inv (F.μ _ _) ≫ ε_ _ _ ≫ F.ε)) + (F.to_functor.preimage (inv F.ε ≫ η_ _ _ ≫ F.μ _ _)) + (by simp) (by simp) + +/-- Pull back a left dual along an equivalence. -/ +def has_left_dual_of_equivalence [is_equivalence F.to_functor] (X : C) [has_left_dual (F.obj X)] : + has_left_dual X := +{ left_dual := F.to_functor.inv.obj (ᘁ(F.obj X)), + exact := begin + apply exact_pairing_of_fully_faithful F _ _, + apply exact_pairing_congr_left (F.to_functor.as_equivalence.counit_iso.app _), + dsimp, + apply_instance, + end } + +/-- Pull back a right dual along an equivalence. -/ +def has_right_dual_of_equivalence [is_equivalence F.to_functor] (X : C) [has_right_dual (F.obj X)] : + has_right_dual X := +{ right_dual := F.to_functor.inv.obj (F.obj X)ᘁ, + exact := begin + apply exact_pairing_of_fully_faithful F _ _, + apply exact_pairing_congr_right (F.to_functor.as_equivalence.counit_iso.app _), + dsimp, + apply_instance, + end } + +/-- Pull back a left rigid structure along an equivalence. -/ +def left_rigid_category_of_equivalence [is_equivalence F.to_functor] + [left_rigid_category D] : left_rigid_category C := +{ left_dual := λ X, has_left_dual_of_equivalence F X, } + +/-- Pull back a right rigid structure along an equivalence. -/ +def right_rigid_category_of_equivalence [is_equivalence F.to_functor] + [right_rigid_category D] : right_rigid_category C := +{ right_dual := λ X, has_right_dual_of_equivalence F X, } + +/-- Pull back a rigid structure along an equivalence. -/ +def rigid_category_of_equivalence [is_equivalence F.to_functor] + [rigid_category D] : rigid_category C := +{ left_dual := λ X, has_left_dual_of_equivalence F X, + right_dual := λ X, has_right_dual_of_equivalence F X, } + +end category_theory From ead85e618173c496ca63000df1c69add1e1b5412 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Fri, 29 Apr 2022 04:24:25 +0000 Subject: [PATCH 308/373] chore(*/equiv): add simp to refl_apply and trans_apply where missing (#13760) Co-authored-by: Scott Morrison --- src/algebra/algebra/basic.lean | 2 +- src/algebra/hom/equiv.lean | 4 ++-- src/linear_algebra/affine_space/affine_equiv.lean | 3 ++- src/order/hom/basic.lean | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/algebra/algebra/basic.lean b/src/algebra/algebra/basic.lean index 676961e670311..1e88986dbbc47 100644 --- a/src/algebra/algebra/basic.lean +++ b/src/algebra/algebra/basic.lean @@ -942,7 +942,7 @@ def trans (e₁ : A₁ ≃ₐ[R] A₂) (e₂ : A₂ ≃ₐ[R] A₃) : A₁ ≃ @[simp] lemma coe_trans (e₁ : A₁ ≃ₐ[R] A₂) (e₂ : A₂ ≃ₐ[R] A₃) : ⇑(e₁.trans e₂) = e₂ ∘ e₁ := rfl -lemma trans_apply (e₁ : A₁ ≃ₐ[R] A₂) (e₂ : A₂ ≃ₐ[R] A₃) (x : A₁) : +@[simp] lemma trans_apply (e₁ : A₁ ≃ₐ[R] A₂) (e₂ : A₂ ≃ₐ[R] A₃) (x : A₁) : (e₁.trans e₂) x = e₂ (e₁ x) := rfl @[simp] lemma comp_symm (e : A₁ ≃ₐ[R] A₂) : diff --git a/src/algebra/hom/equiv.lean b/src/algebra/hom/equiv.lean index 2e8bb24f3b5f8..856e1be3d76f9 100644 --- a/src/algebra/hom/equiv.lean +++ b/src/algebra/hom/equiv.lean @@ -258,13 +258,13 @@ theorem self_comp_symm (e : M ≃* N) : e ∘ e.symm = id := funext e.apply_symm @[simp, to_additive] theorem coe_refl : ⇑(refl M) = id := rfl -@[to_additive] +@[simp, to_additive] theorem refl_apply (m : M) : refl M m = m := rfl @[simp, to_additive] theorem coe_trans (e₁ : M ≃* N) (e₂ : N ≃* P) : ⇑(e₁.trans e₂) = e₂ ∘ e₁ := rfl -@[to_additive] +@[simp, to_additive] theorem trans_apply (e₁ : M ≃* N) (e₂ : N ≃* P) (m : M) : e₁.trans e₂ m = e₂ (e₁ m) := rfl @[simp, to_additive] theorem symm_trans_apply (e₁ : M ≃* N) (e₂ : N ≃* P) (p : P) : diff --git a/src/linear_algebra/affine_space/affine_equiv.lean b/src/linear_algebra/affine_space/affine_equiv.lean index 91b8905414174..2024106fa25d9 100644 --- a/src/linear_algebra/affine_space/affine_equiv.lean +++ b/src/linear_algebra/affine_space/affine_equiv.lean @@ -74,7 +74,7 @@ omit V₂ @[simp] lemma coe_refl : ⇑(refl k P₁) = id := rfl -lemma refl_apply (x : P₁) : refl k P₁ x = x := rfl +@[simp] lemma refl_apply (x : P₁) : refl k P₁ x = x := rfl @[simp] lemma to_equiv_refl : (refl k P₁).to_equiv = equiv.refl P₁ := rfl @@ -207,6 +207,7 @@ include V₂ V₃ @[simp] lemma coe_trans (e : P₁ ≃ᵃ[k] P₂) (e' : P₂ ≃ᵃ[k] P₃) : ⇑(e.trans e') = e' ∘ e := rfl +@[simp] lemma trans_apply (e : P₁ ≃ᵃ[k] P₂) (e' : P₂ ≃ᵃ[k] P₃) (p : P₁) : e.trans e' p = e' (e p) := rfl include V₄ diff --git a/src/order/hom/basic.lean b/src/order/hom/basic.lean index d95dfac61d161..1c646e6b3e071 100644 --- a/src/order/hom/basic.lean +++ b/src/order/hom/basic.lean @@ -508,7 +508,7 @@ def refl (α : Type*) [has_le α] : α ≃o α := rel_iso.refl (≤) @[simp] lemma coe_refl : ⇑(refl α) = id := rfl -lemma refl_apply (x : α) : refl α x = x := rfl +@[simp] lemma refl_apply (x : α) : refl α x = x := rfl @[simp] lemma refl_to_equiv : (refl α).to_equiv = equiv.refl α := rfl @@ -562,7 +562,7 @@ e.to_equiv.preimage_image s @[simp] lemma coe_trans (e : α ≃o β) (e' : β ≃o γ) : ⇑(e.trans e') = e' ∘ e := rfl -lemma trans_apply (e : α ≃o β) (e' : β ≃o γ) (x : α) : e.trans e' x = e' (e x) := rfl +@[simp] lemma trans_apply (e : α ≃o β) (e' : β ≃o γ) (x : α) : e.trans e' x = e' (e x) := rfl @[simp] lemma refl_trans (e : α ≃o β) : (refl α).trans e = e := by { ext x, refl } From 7170b66ccbc9a0a28403171777f8a4cdc1c77173 Mon Sep 17 00:00:00 2001 From: leanprover-community-bot Date: Fri, 29 Apr 2022 04:24:26 +0000 Subject: [PATCH 309/373] chore(scripts): update nolints.txt (#13775) I am happy to remove some nolints for you! --- scripts/nolints.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/nolints.txt b/scripts/nolints.txt index 1fee0899ec65c..1a3a7e67505f9 100644 --- a/scripts/nolints.txt +++ b/scripts/nolints.txt @@ -471,9 +471,6 @@ apply_nolint pi.has_faithful_scalar_at to_additive_doc -- group_theory/group_action/sub_mul_action.lean apply_nolint sub_mul_action.has_zero fails_quickly --- group_theory/monoid_localization.lean -apply_nolint submonoid.localization_map.lift_left_inverse to_additive_doc - -- group_theory/order_of_element.lean apply_nolint image_range_order_of to_additive_doc apply_nolint is_of_fin_order_iff_coe to_additive_doc From 5c1ee3526704121adc0eb918481ea72883d2bf42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Fri, 29 Apr 2022 06:35:24 +0000 Subject: [PATCH 310/373] feat(set_theory/game/pgame): `x - 0 = x + 0` (#13731) --- src/set_theory/game/pgame.lean | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/set_theory/game/pgame.lean b/src/set_theory/game/pgame.lean index 53439b3879226..9def04ac006a2 100644 --- a/src/set_theory/game/pgame.lean +++ b/src/set_theory/game/pgame.lean @@ -898,6 +898,9 @@ using_well_founded { dec_tac := pgame_wf_tac } instance : has_sub pgame := ⟨λ x y, x + -y⟩ +@[simp] theorem sub_zero (x : pgame) : x - 0 = x + 0 := +show x + -0 = x + 0, by rw pgame.neg_zero + /-- If `w` has the same moves as `x` and `y` has the same moves as `z`, then `w - y` has the same moves as `x - z`. -/ def relabelling.sub_congr {w x y z : pgame} From b4cad37932a9475ae1cd1f014ea6e00a0d1848d5 Mon Sep 17 00:00:00 2001 From: negiizhao Date: Fri, 29 Apr 2022 06:35:25 +0000 Subject: [PATCH 311/373] chore(ring_theory/mv_polynomial/basic): golf (#13765) --- src/ring_theory/mv_polynomial/basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ring_theory/mv_polynomial/basic.lean b/src/ring_theory/mv_polynomial/basic.lean index 96d2d3134a810..1bd49bdd30719 100644 --- a/src/ring_theory/mv_polynomial/basic.lean +++ b/src/ring_theory/mv_polynomial/basic.lean @@ -125,7 +125,7 @@ namespace polynomial /-- The monomials form a basis on `polynomial R`. -/ noncomputable def basis_monomials : basis ℕ R R[X] := -finsupp.basis_single_one.map (to_finsupp_iso_alg R).to_linear_equiv.symm +basis.of_repr (to_finsupp_iso_alg R).to_linear_equiv @[simp] lemma coe_basis_monomials : (basis_monomials R : ℕ → R[X]) = λ s, monomial s 1 := From 992e26faf97aed5519a73a6a47dcb6fd9b5530a9 Mon Sep 17 00:00:00 2001 From: Oliver Nash Date: Fri, 29 Apr 2022 06:35:26 +0000 Subject: [PATCH 312/373] feat(topology/algebra/affine): a sufficiently small dilation of a point in the interior of a set lands in the interior (#13766) Formalized as part of the Sphere Eversion project. --- src/algebra/add_torsor.lean | 6 +++ src/analysis/normed/group/basic.lean | 17 ++++++++ src/analysis/normed_space/add_torsor.lean | 49 ++++++++++++++++++----- 3 files changed, 61 insertions(+), 11 deletions(-) diff --git a/src/algebra/add_torsor.lean b/src/algebra/add_torsor.lean index 0aabd62f4251d..305ab5b51135e 100644 --- a/src/algebra/add_torsor.lean +++ b/src/algebra/add_torsor.lean @@ -114,6 +114,9 @@ equal. -/ @[simp] lemma vsub_eq_zero_iff_eq {p1 p2 : P} : p1 -ᵥ p2 = (0 : G) ↔ p1 = p2 := iff.intro eq_of_vsub_eq_zero (λ h, h ▸ vsub_self _) +lemma vsub_ne_zero {p q : P} : p -ᵥ q ≠ (0 : G) ↔ p ≠ q := +not_congr vsub_eq_zero_iff_eq + /-- Cancellation adding the results of two subtractions. -/ @[simp] lemma vsub_add_vsub_cancel (p1 p2 p3 : P) : p1 -ᵥ p2 + (p2 -ᵥ p3) = (p1 -ᵥ p3) := begin @@ -129,6 +132,9 @@ begin rw [vsub_add_vsub_cancel, vsub_self], end +lemma vadd_vsub_eq_sub_vsub (g : G) (p q : P) : g +ᵥ p -ᵥ q = g - (q -ᵥ p) := +by rw [vadd_vsub_assoc, sub_eq_add_neg, neg_vsub_eq_vsub_rev] + /-- Subtracting the result of adding a group element produces the same result as subtracting the points and subtracting that group element. -/ lemma vsub_vadd_eq_vsub_sub (p1 p2 : P) (g : G) : p1 -ᵥ (g +ᵥ p2) = (p1 -ᵥ p2) - g := diff --git a/src/analysis/normed/group/basic.lean b/src/analysis/normed/group/basic.lean index 00a094416dda8..a34f62164d5dc 100644 --- a/src/analysis/normed/group/basic.lean +++ b/src/analysis/normed/group/basic.lean @@ -256,6 +256,9 @@ lemma norm_le_add_norm_add (u v : E) : calc ∥u∥ = ∥u + v - v∥ : by rw add_sub_cancel ... ≤ ∥u + v∥ + ∥v∥ : norm_sub_le _ _ +lemma ball_eq (y : E) (ε : ℝ) : metric.ball y ε = { x | ∥x - y∥ < ε} := +by { ext, simp [dist_eq_norm], } + lemma ball_zero_eq (ε : ℝ) : ball (0 : E) ε = {x | ∥x∥ < ε} := set.ext $ assume a, by simp @@ -425,6 +428,20 @@ lemma normed_group.cauchy_seq_iff [nonempty α] [semilattice_sup α] {u : α → cauchy_seq u ↔ ∀ ε > 0, ∃ N, ∀ m, N ≤ m → ∀ n, N ≤ n → ∥u m - u n∥ < ε := by simp [metric.cauchy_seq_iff, dist_eq_norm] +lemma normed_group.nhds_basis_norm_lt (x : E) : + (𝓝 x).has_basis (λ (ε : ℝ), 0 < ε) (λ (ε : ℝ), { y | ∥y - x∥ < ε }) := +begin + simp_rw ← ball_eq, + exact metric.nhds_basis_ball, +end + +lemma normed_group.nhds_zero_basis_norm_lt : + (𝓝 (0 : E)).has_basis (λ (ε : ℝ), 0 < ε) (λ (ε : ℝ), { y | ∥y∥ < ε }) := +begin + convert normed_group.nhds_basis_norm_lt (0 : E), + simp, +end + lemma normed_group.uniformity_basis_dist : (𝓤 E).has_basis (λ (ε : ℝ), 0 < ε) (λ ε, {p : E × E | ∥p.fst - p.snd∥ < ε}) := begin diff --git a/src/analysis/normed_space/add_torsor.lean b/src/analysis/normed_space/add_torsor.lean index 3d57b8dd8422e..3d45e713ff013 100644 --- a/src/analysis/normed_space/add_torsor.lean +++ b/src/analysis/normed_space/add_torsor.lean @@ -24,11 +24,11 @@ variables {W Q : Type*} [normed_group W] [metric_space Q] [normed_add_torsor W Q section normed_space -variables {𝕜 : Type*} [normed_field 𝕜] [normed_space 𝕜 V] +variables {𝕜 : Type*} [normed_field 𝕜] [normed_space 𝕜 V] [normed_space 𝕜 W] open affine_map -lemma affine_subspace.is_closed_direction_iff [normed_space 𝕜 W] (s : affine_subspace 𝕜 Q) : +lemma affine_subspace.is_closed_direction_iff (s : affine_subspace 𝕜 Q) : is_closed (s.direction : set W) ↔ is_closed (s : set Q) := begin rcases s.eq_bot_or_nonempty with rfl|⟨x, hx⟩, { simp [is_closed_singleton] }, @@ -60,15 +60,6 @@ lemma lipschitz_with_line_map (p₁ p₂ : P) : lipschitz_with.of_dist_le_mul $ λ c₁ c₂, ((dist_line_map_line_map p₁ p₂ c₁ c₂).trans (mul_comm _ _)).le -omit V - -lemma antilipschitz_with_line_map [normed_space 𝕜 W] {p₁ p₂ : Q} (h : p₁ ≠ p₂) : - antilipschitz_with (nndist p₁ p₂)⁻¹ (line_map p₁ p₂ : 𝕜 → Q) := -antilipschitz_with.of_le_mul_dist $ λ c₁ c₂, by rw [dist_line_map_line_map, nnreal.coe_inv, - ← dist_nndist, mul_left_comm, inv_mul_cancel (dist_ne_zero.2 h), mul_one] - -include V - @[simp] lemma dist_line_map_left (p₁ p₂ : P) (c : 𝕜) : dist (line_map p₁ p₂ c) p₁ = ∥c∥ * dist p₁ p₂ := by simpa only [line_map_apply_zero, dist_zero_right] using dist_line_map_line_map p₁ p₂ c 0 @@ -93,6 +84,8 @@ by rw [homothety_eq_line_map, dist_line_map_right] dist p₂ (homothety p₁ c p₂) = ∥1 - c∥ * dist p₁ p₂ := by rw [dist_comm, dist_homothety_self] +section invertible_two + variables [invertible (2:𝕜)] @[simp] lemma dist_left_midpoint (p₁ p₂ : P) : @@ -120,6 +113,40 @@ begin exact div_le_div_of_le_of_nonneg (norm_add_le _ _) (norm_nonneg _), end +end invertible_two + +omit V +include W + +lemma antilipschitz_with_line_map {p₁ p₂ : Q} (h : p₁ ≠ p₂) : + antilipschitz_with (nndist p₁ p₂)⁻¹ (line_map p₁ p₂ : 𝕜 → Q) := +antilipschitz_with.of_le_mul_dist $ λ c₁ c₂, by rw [dist_line_map_line_map, nnreal.coe_inv, + ← dist_nndist, mul_left_comm, inv_mul_cancel (dist_ne_zero.2 h), mul_one] + +lemma eventually_homothety_mem_of_mem_interior (x : Q) {s : set Q} {y : Q} (hy : y ∈ interior s) : + ∀ᶠ δ in 𝓝 (1 : 𝕜), homothety x δ y ∈ s := +begin + rw (normed_group.nhds_basis_norm_lt (1 : 𝕜)).eventually_iff, + cases eq_or_ne y x with h h, { use 1, simp [h.symm, interior_subset hy], }, + have hxy : 0 < ∥y -ᵥ x∥, { rwa [norm_pos_iff, vsub_ne_zero], }, + obtain ⟨u, hu₁, hu₂, hu₃⟩ := mem_interior.mp hy, + obtain ⟨ε, hε, hyε⟩ := metric.is_open_iff.mp hu₂ y hu₃, + refine ⟨ε / ∥y -ᵥ x∥, div_pos hε hxy, λ δ (hδ : ∥δ - 1∥ < ε / ∥y -ᵥ x∥), hu₁ (hyε _)⟩, + rw [lt_div_iff hxy, ← norm_smul, sub_smul, one_smul] at hδ, + rwa [homothety_apply, metric.mem_ball, dist_eq_norm_vsub W, vadd_vsub_eq_sub_vsub], +end + +lemma eventually_homothety_image_subset_of_finite_subset_interior + (x : Q) {s : set Q} {t : set Q} (ht : t.finite) (h : t ⊆ interior s) : + ∀ᶠ δ in 𝓝 (1 : 𝕜), homothety x δ '' t ⊆ s := +begin + suffices : ∀ y ∈ t, ∀ᶠ δ in 𝓝 (1 : 𝕜), homothety x δ y ∈ s, + { simp_rw set.image_subset_iff, + exact (filter.eventually_all_finite ht).mpr this, }, + intros y hy, + exact eventually_homothety_mem_of_mem_interior x (h hy), +end + end normed_space variables [normed_space ℝ V] [normed_space ℝ W] From bc65b7cd3793065168dccbcd718f0a391acb1c8a Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 29 Apr 2022 06:35:27 +0000 Subject: [PATCH 313/373] feat(data/list/basic): add `list.range_map` (#13777) * add `list.range_map` and `list.range_map_coe`; * add `submonoid.closure_eq_image_prod` and `add_submonoid.closure_eq_image_prod`. --- src/data/list/basic.lean | 19 +++++++++++++++---- src/group_theory/submonoid/membership.lean | 13 ++++++++----- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/data/list/basic.lean b/src/data/list/basic.lean index 10b224e536bfc..9c20e1a7bec5f 100644 --- a/src/data/list/basic.lean +++ b/src/data/list/basic.lean @@ -185,6 +185,19 @@ lemma map_bind (g : β → list γ) (f : α → β) : | [] := rfl | (a::l) := by simp only [cons_bind, map_cons, map_bind l] +lemma range_map (f : α → β) : set.range (map f) = {l | ∀ x ∈ l, x ∈ set.range f} := +begin + refine set.subset.antisymm (set.range_subset_iff.2 $ + λ l, forall_mem_map_iff.2 $ λ y _, set.mem_range_self _) (λ l hl, _), + induction l with a l ihl, { exact ⟨[], rfl⟩ }, + rcases ihl (λ x hx, hl x $ subset_cons _ _ hx) with ⟨l, rfl⟩, + rcases hl a (mem_cons_self _ _) with ⟨a, rfl⟩, + exact ⟨a :: l, map_cons _ _ _⟩ +end + +lemma range_map_coe (s : set α) : set.range (map (coe : s → α)) = {l | ∀ x ∈ l, x ∈ s} := +by rw [range_map, subtype.range_coe] + /-- If each element of a list can be lifted to some type, then the whole list can be lifted to this type. -/ instance [h : can_lift α β] : can_lift (list α) (list β) := @@ -192,10 +205,8 @@ instance [h : can_lift α β] : can_lift (list α) (list β) := cond := λ l, ∀ x ∈ l, can_lift.cond β x, prf := λ l H, begin - induction l with a l ihl, { exact ⟨[], rfl⟩ }, - rcases ihl (λ x hx, H x (or.inr hx)) with ⟨l, rfl⟩, - rcases can_lift.prf a (H a (or.inl rfl)) with ⟨a, rfl⟩, - exact ⟨a :: l, rfl⟩ + rw [← set.mem_range, range_map], + exact λ a ha, can_lift.prf a (H a ha), end} /-! ### length -/ diff --git a/src/group_theory/submonoid/membership.lean b/src/group_theory/submonoid/membership.lean index 3d764781e5e1f..b0cf537610c25 100644 --- a/src/group_theory/submonoid/membership.lean +++ b/src/group_theory/submonoid/membership.lean @@ -285,14 +285,17 @@ lemma closure_eq_mrange (s : set M) : closure s = (free_monoid.lift (coe : s → by rw [mrange_eq_map, ← free_monoid.closure_range_of, map_mclosure, ← set.range_comp, free_monoid.lift_comp_of, subtype.range_coe] +@[to_additive] lemma closure_eq_image_prod (s : set M) : + (closure s : set M) = list.prod '' {l : list M | ∀ x ∈ l, x ∈ s} := +begin + rw [closure_eq_mrange, coe_mrange, ← list.range_map_coe, ← set.range_comp], + refl +end + @[to_additive] lemma exists_list_of_mem_closure {s : set M} {x : M} (hx : x ∈ closure s) : ∃ (l : list M) (hl : ∀ y ∈ l, y ∈ s), l.prod = x := -begin - rw [closure_eq_mrange, mem_mrange] at hx, - rcases hx with ⟨l, hx⟩, - exact ⟨list.map coe l, λ y hy, let ⟨z, hz, hy⟩ := list.mem_map.1 hy in hy ▸ z.2, hx⟩ -end +by rwa [← set_like.mem_coe, closure_eq_image_prod, set.mem_image_iff_bex] at hx @[to_additive] lemma exists_multiset_of_mem_closure {M : Type*} [comm_monoid M] {s : set M} From 8abfb3ba5e211d8376b855dab5d67f9eba9e0774 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Fri, 29 Apr 2022 08:26:15 +0000 Subject: [PATCH 314/373] feat(representation_theory/Rep): Rep k G is abelian (#13689) Co-authored-by: Scott Morrison --- .../abelian/functor_category.lean | 31 ++++++++---- src/category_theory/abelian/transfer.lean | 11 ++++ .../limits/shapes/functor_category.lean | 4 +- src/representation_theory/Action.lean | 50 ++++++++++++++++++- src/representation_theory/Rep.lean | 6 +-- 5 files changed, 87 insertions(+), 15 deletions(-) diff --git a/src/category_theory/abelian/functor_category.lean b/src/category_theory/abelian/functor_category.lean index 5ec19afb4b070..c8804931f2963 100644 --- a/src/category_theory/abelian/functor_category.lean +++ b/src/category_theory/abelian/functor_category.lean @@ -18,17 +18,17 @@ noncomputable theory namespace category_theory open category_theory.limits -universes w v u -variables {C : Type (max v u)} [category.{v} C] -variables {D : Type w} [category.{max v u} D] [abelian D] - namespace abelian +section +universes z w v u +variables {C : Type (max v u)} [category.{v} C] +variables {D : Type w} [category.{max z v u} D] [abelian D] + namespace functor_category variables {F G : C ⥤ D} (α : F ⟶ G) (X : C) -/-- The evaluation of the abelian coimage in a functor category is -the abelian coimage of the corresponding component. -/ +/-- The abelian coimage in a functor category can be calculated componentwise. -/ @[simps] def coimage_obj_iso : (abelian.coimage α).obj X ≅ abelian.coimage (α.app X) := preserves_cokernel.iso ((evaluation C D).obj X) _ ≪≫ @@ -39,8 +39,7 @@ preserves_cokernel.iso ((evaluation C D).obj X) _ ≪≫ exact (kernel_comparison_comp_ι _ ((evaluation C D).obj X)).symm, end -/-- The evaluation of the abelian image in a functor category is -the abelian image of the corresponding component. -/ +/-- The abelian image in a functor category can be calculated componentwise. -/ @[simps] def image_obj_iso : (abelian.image α).obj X ≅ abelian.image (α.app X) := preserves_kernel.iso ((evaluation C D).obj X) _ ≪≫ @@ -84,9 +83,23 @@ end end functor_category -noncomputable instance : abelian (C ⥤ D) := +noncomputable instance functor_category_abelian : abelian (C ⥤ D) := abelian.of_coimage_image_comparison_is_iso +end + +section + +universes u +variables {C : Type u} [small_category C] +variables {D : Type (u+1)} [large_category D] [abelian D] + +/-- A variant with specialized universes for a common case. -/ +noncomputable instance functor_category_abelian' : abelian (C ⥤ D) := +abelian.functor_category_abelian.{u u+1 u u} + +end + end abelian end category_theory diff --git a/src/category_theory/abelian/transfer.lean b/src/category_theory/abelian/transfer.lean index 94fb9ed792bc4..433fca2d8a7ad 100644 --- a/src/category_theory/abelian/transfer.lean +++ b/src/category_theory/abelian/transfer.lean @@ -168,4 +168,15 @@ begin apply abelian.of_coimage_image_comparison_is_iso, end +/-- +If `C` is an additive category equivalent to an abelian category `D` +via a functor that preserves zero morphisms, +then `C` is also abelian. +-/ +def abelian_of_equivalence + {C : Type u₁} [category.{v} C] [preadditive C] [has_finite_products C] + {D : Type u₂} [category.{v} D] [abelian D] + (F : C ⥤ D) [functor.preserves_zero_morphisms F] [is_equivalence F] : abelian C := +abelian_of_adjunction F F.inv F.as_equivalence.unit_iso.symm F.as_equivalence.symm.to_adjunction + end category_theory diff --git a/src/category_theory/limits/shapes/functor_category.lean b/src/category_theory/limits/shapes/functor_category.lean index 46fcedd223700..0b056b578ea5f 100644 --- a/src/category_theory/limits/shapes/functor_category.lean +++ b/src/category_theory/limits/shapes/functor_category.lean @@ -16,9 +16,9 @@ open category_theory namespace category_theory.limits -universes w v u +universes z w v u variables {C : Type (max v u)} [category.{v} C] -variables {D : Type w} [category.{max v u} D] +variables {D : Type w} [category.{max z v u} D] instance functor_category_has_finite_limits [has_finite_limits D] : has_finite_limits (C ⥤ D) := diff --git a/src/representation_theory/Action.lean b/src/representation_theory/Action.lean index 8b2ac37b7a33a..3d1a64d536d5a 100644 --- a/src/representation_theory/Action.lean +++ b/src/representation_theory/Action.lean @@ -10,6 +10,8 @@ import category_theory.limits.preserves.basic import category_theory.adjunction.limits import category_theory.monoidal.functor_category import category_theory.monoidal.transport +import category_theory.abelian.functor_category +import category_theory.abelian.transfer /-! # `Action V G`, the category of actions of a monoid `G` inside some category `V`. @@ -20,7 +22,9 @@ where `Action (Module R) G` is the category of `R`-linear representations of `G` We check `Action V G ≌ (single_obj G ⥤ V)`, and construct the restriction functors `res {G H : Mon} (f : G ⟶ H) : Action V H ⥤ Action V G`. -When `V` has (co)limits so does `Action V G`. When `V` is monoidal so is `Action V G`. +* When `V` has (co)limits so does `Action V G`. +* When `V` is monoidal so is `Action V G`. +* When `V` is preadditive or abelian so is `Action V G`. -/ universes u @@ -186,6 +190,10 @@ def functor_category_equivalence : Action V G ≌ (single_obj G ⥤ V) := attribute [simps] functor_category_equivalence +instance [has_finite_products V] : has_finite_products (Action V G) := +{ out := λ J _ _, by exactI + adjunction.has_limits_of_shape_of_equivalence (Action.functor_category_equivalence _ _).functor } + instance [has_limits V] : has_limits (Action V G) := adjunction.has_limits_of_equivalence (Action.functor_category_equivalence _ _).functor @@ -235,6 +243,46 @@ preserves_colimits_of_nat_iso end forget +section has_zero_morphisms +variables [has_zero_morphisms V] + +instance : has_zero_morphisms (Action V G) := +{ has_zero := λ X Y, ⟨⟨0, by tidy⟩⟩, } + +instance : functor.preserves_zero_morphisms (functor_category_equivalence V G).functor := {} + +end has_zero_morphisms + +section preadditive +variables [preadditive V] + +instance : preadditive (Action V G) := +{ hom_group := λ X Y, + { zero := ⟨0, by simp⟩, + add := λ f g, ⟨f.hom + g.hom, by simp [f.comm, g.comm]⟩, + neg := λ f, ⟨-f.hom, by simp [f.comm]⟩, + zero_add := by { intros, ext, exact zero_add _, }, + add_zero := by { intros, ext, exact add_zero _, }, + add_assoc := by { intros, ext, exact add_assoc _ _ _, }, + add_left_neg := by { intros, ext, exact add_left_neg _, }, + add_comm := by { intros, ext, exact add_comm _ _, }, }, + add_comp' := by { intros, ext, exact preadditive.add_comp _ _ _ _ _ _, }, + comp_add' := by { intros, ext, exact preadditive.comp_add _ _ _ _ _ _, }, } + +instance : functor.additive (functor_category_equivalence V G).functor := {} + +end preadditive + +section abelian +/-- Auxilliary construction for the `abelian (Action V G)` instance. -/ +def abelian_aux : Action V G ≌ (ulift.{u} (single_obj G) ⥤ V) := +(functor_category_equivalence V G).trans (equivalence.congr_left ulift.equivalence) + +noncomputable instance [abelian V] : abelian (Action V G) := +abelian_of_equivalence abelian_aux.functor + +end abelian + section monoidal instance [monoidal_category V] : monoidal_category (Action V G) := diff --git a/src/representation_theory/Rep.lean b/src/representation_theory/Rep.lean index b6a26aa1bedfb..8bb0c293e5a96 100644 --- a/src/representation_theory/Rep.lean +++ b/src/representation_theory/Rep.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Scott Morrison -/ import representation_theory.Action -import algebra.category.Module.limits +import algebra.category.Module.abelian import algebra.category.Module.colimits import algebra.category.Module.monoidal @@ -18,7 +18,7 @@ Also `V.ρ` gives the homomorphism `G →* (V →ₗ[k] V)`. Conversely, given a homomorphism `ρ : G →* (V →ₗ[k] V)`, you can construct the bundled representation as `Rep.of ρ`. -We verify that `Rep k G` has all limits and colimits, and is a monoidal category. +We verify that `Rep k G` is an abelian monoidal category with all (co)limits. -/ universes u @@ -27,7 +27,7 @@ open category_theory open category_theory.limits /-- The category of `k`-linear representations of a monoid `G`. -/ -@[derive [large_category, concrete_category, has_limits, has_colimits]] +@[derive [large_category, concrete_category, has_limits, has_colimits, abelian]] abbreviation Rep (k G : Type u) [ring k] [monoid G] := Action (Module.{u} k) (Mon.of G) From aab0b2dfe501fcfe4c9ff6aa3e0a1df0e2e7e697 Mon Sep 17 00:00:00 2001 From: negiizhao Date: Fri, 29 Apr 2022 09:31:57 +0000 Subject: [PATCH 315/373] feat(algebra/algebra/basic): add some lemmas about `subsemiring` and `algebra_map` (#13767) These are analogs of `algebra_map_of_subring`, `coe_algebra_map_of_subring` and `algebra_map_of_subring_apply`. --- src/algebra/algebra/basic.lean | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/algebra/algebra/basic.lean b/src/algebra/algebra/basic.lean index 1e88986dbbc47..1b2127603a6e8 100644 --- a/src/algebra/algebra/basic.lean +++ b/src/algebra/algebra/basic.lean @@ -348,6 +348,15 @@ instance of_subsemiring (S : subsemiring R) : algebra S A := smul_def' := λ r x, algebra.smul_def r x, .. (algebra_map R A).comp S.subtype } +lemma algebra_map_of_subsemiring (S : subsemiring R) : + (algebra_map S R : S →+* R) = subsemiring.subtype S := rfl + +lemma coe_algebra_map_of_subsemiring (S : subsemiring R) : + (algebra_map S R : S → R) = subtype.val := rfl + +lemma algebra_map_of_subsemiring_apply (S : subsemiring R) (x : S) : + algebra_map S R x = x := rfl + /-- Algebra over a subring. This builds upon `subring.module`. -/ instance of_subring {R A : Type*} [comm_ring R] [ring A] [algebra R A] (S : subring R) : algebra S A := From 889e9564b572d795f53c1aa6c67a66c98051336a Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Fri, 29 Apr 2022 11:14:10 +0000 Subject: [PATCH 316/373] chore(analysis/asymptotics/asymptotics): relax `normed_group` to `semi_normed_group` in lemmas (#13642) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This file already uses `E` vs `E'` for `has_norm` vs `normed_group`. This adds an `E''` to this naming scheme for `normed_group`, and repurposes `E'` to `semi_normed_group`. The majority of the lemmas in this file generalize without any additional work. I've not attempted to relax the assumptions on lemmas where any proofs would have to change. Most of them would need their assumptions changing from `c ≠ 0` to `∥c∥ ≠ 0`, which is likely to be annoying. In one place this results in dot notation breaking as the typeclass can no longer be found by unification. --- src/analysis/asymptotics/asymptotics.lean | 121 ++++++++++++---------- src/analysis/normed_space/units.lean | 5 +- 2 files changed, 66 insertions(+), 60 deletions(-) diff --git a/src/analysis/asymptotics/asymptotics.lean b/src/analysis/asymptotics/asymptotics.lean index 2f44f58fbb289..df83006a0c9f3 100644 --- a/src/analysis/asymptotics/asymptotics.lean +++ b/src/analysis/asymptotics/asymptotics.lean @@ -49,12 +49,19 @@ open_locale topological_space big_operators classical filter nnreal namespace asymptotics variables {α : Type*} {β : Type*} {E : Type*} {F : Type*} {G : Type*} - {E' : Type*} {F' : Type*} {G' : Type*} {R : Type*} {R' : Type*} {𝕜 : Type*} {𝕜' : Type*} - -variables [has_norm E] [has_norm F] [has_norm G] [normed_group E'] [normed_group F'] - [normed_group G'] [normed_ring R] [normed_ring R'] [normed_field 𝕜] [normed_field 𝕜'] - {c c' : ℝ} {f : α → E} {g : α → F} {k : α → G} {f' : α → E'} {g' : α → F'} {k' : α → G'} - {l l' : filter α} + {E' : Type*} {F' : Type*} {G' : Type*} + {E'' : Type*} {F'' : Type*} {G'' : Type*} + {R : Type*} {R' : Type*} {𝕜 : Type*} {𝕜' : Type*} + +variables [has_norm E] [has_norm F] [has_norm G] +variables [semi_normed_group E'] [semi_normed_group F'] [semi_normed_group G'] +variables [normed_group E''] [normed_group F''] [normed_group G''] +variables [semi_normed_ring R] [semi_normed_ring R'] +variables [normed_field 𝕜] [normed_field 𝕜'] +variables {c c' : ℝ} {f : α → E} {g : α → F} {k : α → G} +variables {f' : α → E'} {g' : α → F'} {k' : α → G'} +variables {f'' : α → E''} {g'' : α → F''} {k'' : α → G''} +variables {l l' : filter α} section defs @@ -580,10 +587,10 @@ is_O_snd_prod.trans_is_o h is_o (λ x, (f' x, g' x)) k' l ↔ is_o f' k' l ∧ is_o g' k' l := ⟨λ h, ⟨h.prod_left_fst, h.prod_left_snd⟩, λ h, h.1.prod_left h.2⟩ -lemma is_O_with.eq_zero_imp (h : is_O_with c f' g' l) : ∀ᶠ x in l, g' x = 0 → f' x = 0 := +lemma is_O_with.eq_zero_imp (h : is_O_with c f'' g'' l) : ∀ᶠ x in l, g'' x = 0 → f'' x = 0 := eventually.mono h.bound $ λ x hx hg, norm_le_zero_iff.1 $ by simpa [hg] using hx -lemma is_O.eq_zero_imp (h : is_O f' g' l) : ∀ᶠ x in l, g' x = 0 → f' x = 0 := +lemma is_O.eq_zero_imp (h : is_O f'' g'' l) : ∀ᶠ x in l, g'' x = 0 → f'' x = 0 := let ⟨C, hC⟩ := h.is_O_with in hC.eq_zero_imp /-! ### Addition and subtraction -/ @@ -719,19 +726,19 @@ theorem is_o_refl_left : is_o (λ x, f' x - f' x) g' l := variables {g g' l} @[simp] theorem is_O_with_zero_right_iff : - is_O_with c f' (λ x, (0 : F')) l ↔ ∀ᶠ x in l, f' x = 0 := + is_O_with c f'' (λ x, (0 : F'')) l ↔ ∀ᶠ x in l, f'' x = 0 := by simp only [is_O_with, exists_prop, true_and, norm_zero, mul_zero, norm_le_zero_iff] -@[simp] theorem is_O_zero_right_iff : is_O f' (λ x, (0 : F')) l ↔ ∀ᶠ x in l, f' x = 0 := +@[simp] theorem is_O_zero_right_iff : is_O f'' (λ x, (0 : F'')) l ↔ ∀ᶠ x in l, f'' x = 0 := ⟨λ h, let ⟨c, hc⟩ := h.is_O_with in is_O_with_zero_right_iff.1 hc, λ h, (is_O_with_zero_right_iff.2 h : is_O_with 1 _ _ _).is_O⟩ @[simp] theorem is_o_zero_right_iff : - is_o f' (λ x, (0 : F')) l ↔ ∀ᶠ x in l, f' x = 0 := + is_o f'' (λ x, (0 : F'')) l ↔ ∀ᶠ x in l, f'' x = 0 := ⟨λ h, is_O_zero_right_iff.1 h.is_O, λ h, is_o.of_is_O_with $ λ c hc, is_O_with_zero_right_iff.2 h⟩ -theorem is_O_with_const_const (c : E) {c' : F'} (hc' : c' ≠ 0) (l : filter α) : +theorem is_O_with_const_const (c : E) {c' : F''} (hc' : c' ≠ 0) (l : filter α) : is_O_with (∥c∥ / ∥c'∥) (λ x : α, c) (λ x, c') l := begin unfold is_O_with, @@ -741,11 +748,11 @@ begin rwa [ne.def, norm_eq_zero] end -theorem is_O_const_const (c : E) {c' : F'} (hc' : c' ≠ 0) (l : filter α) : +theorem is_O_const_const (c : E) {c' : F''} (hc' : c' ≠ 0) (l : filter α) : is_O (λ x : α, c) (λ x, c') l := (is_O_with_const_const c hc' l).is_O -@[simp] theorem is_O_const_const_iff {c : E'} {c' : F'} (l : filter α) [l.ne_bot] : +@[simp] theorem is_O_const_const_iff {c : E''} {c' : F''} (l : filter α) [l.ne_bot] : is_O (λ x : α, c) (λ x, c') l ↔ (c' = 0 → c = 0) := begin rcases eq_or_ne c' 0 with rfl|hc', @@ -753,9 +760,9 @@ begin { simp [hc', is_O_const_const _ hc'] } end -@[simp] lemma is_O_pure {x} : is_O f' g' (pure x) ↔ (g' x = 0 → f' x = 0) := -calc is_O f' g' (pure x) ↔ is_O (λ y : α, f' x) (λ _, g' x) (pure x) : is_O_congr rfl rfl - ... ↔ g' x = 0 → f' x = 0 : is_O_const_const_iff _ +@[simp] lemma is_O_pure {x} : is_O f'' g'' (pure x) ↔ (g'' x = 0 → f'' x = 0) := +calc is_O f'' g'' (pure x) ↔ is_O (λ y : α, f'' x) (λ _, g'' x) (pure x) : is_O_congr rfl rfl + ... ↔ g'' x = 0 → f'' x = 0 : is_O_const_const_iff _ end zero_const @@ -763,12 +770,12 @@ end zero_const @[simp] lemma is_O_top : is_O f g ⊤ ↔ ∃ C, ∀ x, ∥f x∥ ≤ C * ∥g x∥ := by rw is_O_iff; refl -@[simp] lemma is_o_top : is_o f' g' ⊤ ↔ ∀ x, f' x = 0 := +@[simp] lemma is_o_top : is_o f'' g'' ⊤ ↔ ∀ x, f'' x = 0 := begin - refine ⟨_, λ h, (is_o_zero g' ⊤).congr (λ x, (h x).symm) (λ x, rfl)⟩, + refine ⟨_, λ h, (is_o_zero g'' ⊤).congr (λ x, (h x).symm) (λ x, rfl)⟩, simp only [is_o_iff, eventually_top], refine λ h x, norm_le_zero_iff.1 _, - have : tendsto (λ c : ℝ, c * ∥g' x∥) (𝓝[>] 0) (𝓝 0) := + have : tendsto (λ c : ℝ, c * ∥g'' x∥) (𝓝[>] 0) (𝓝 0) := ((continuous_id.mul continuous_const).tendsto' _ _ (zero_mul _)).mono_left inf_le_left, exact le_of_tendsto_of_tendsto tendsto_const_nhds this (eventually_nhds_within_iff.2 $ eventually_of_forall $ λ c hc, h hc x) @@ -796,14 +803,14 @@ section variable (𝕜) -theorem is_o_const_iff_is_o_one {c : F'} (hc : c ≠ 0) : +theorem is_o_const_iff_is_o_one {c : F''} (hc : c ≠ 0) : is_o f (λ x, c) l ↔ is_o f (λ x, (1:𝕜)) l := ⟨λ h, h.trans_is_O $ is_O_const_one c l, λ h, h.trans_is_O $ is_O_const_const _ hc _⟩ end -theorem is_o_const_iff {c : F'} (hc : c ≠ 0) : - is_o f' (λ x, c) l ↔ tendsto f' l (𝓝 0) := +theorem is_o_const_iff {c : F''} (hc : c ≠ 0) : + is_o f'' (λ x, c) l ↔ tendsto f'' l (𝓝 0) := (is_o_const_iff_is_o_one ℝ hc).trans begin clear hc c, @@ -811,12 +818,12 @@ begin metric.mem_closed_ball, dist_zero_right] end -lemma is_o_id_const {c : F'} (hc : c ≠ 0) : - is_o (λ (x : E'), x) (λ x, c) (𝓝 0) := +lemma is_o_id_const {c : F''} (hc : c ≠ 0) : + is_o (λ (x : E''), x) (λ x, c) (𝓝 0) := (is_o_const_iff hc).mpr (continuous_id.tendsto 0) theorem _root_.filter.is_bounded_under.is_O_const (h : is_bounded_under (≤) l (norm ∘ f)) - {c : F'} (hc : c ≠ 0) : is_O f (λ x, c) l := + {c : F''} (hc : c ≠ 0) : is_O f (λ x, c) l := begin rcases h with ⟨C, hC⟩, refine (is_O.of_bound 1 _).trans (is_O_const_const C hc l), @@ -826,33 +833,33 @@ begin ... = 1 * ∥C∥ : (one_mul _).symm end -theorem is_O_const_of_tendsto {y : E'} (h : tendsto f' l (𝓝 y)) {c : F'} (hc : c ≠ 0) : - is_O f' (λ x, c) l := +theorem is_O_const_of_tendsto {y : E''} (h : tendsto f'' l (𝓝 y)) {c : F''} (hc : c ≠ 0) : + is_O f'' (λ x, c) l := h.norm.is_bounded_under_le.is_O_const hc section variable (𝕜) -theorem is_o_one_iff : is_o f' (λ x, (1 : 𝕜)) l ↔ tendsto f' l (𝓝 0) := +theorem is_o_one_iff : is_o f'' (λ x, (1 : 𝕜)) l ↔ tendsto f'' l (𝓝 0) := is_o_const_iff one_ne_zero -theorem is_O_one_of_tendsto {y : E'} (h : tendsto f' l (𝓝 y)) : - is_O f' (λ x, (1:𝕜)) l := +theorem is_O_one_of_tendsto {y : E''} (h : tendsto f'' l (𝓝 y)) : + is_O f'' (λ x, (1:𝕜)) l := is_O_const_of_tendsto h one_ne_zero -theorem is_O.trans_tendsto_nhds (hfg : is_O f g' l) {y : F'} (hg : tendsto g' l (𝓝 y)) : +theorem is_O.trans_tendsto_nhds (hfg : is_O f g'' l) {y : F''} (hg : tendsto g'' l (𝓝 y)) : is_O f (λ x, (1:𝕜)) l := hfg.trans $ is_O_one_of_tendsto 𝕜 hg end -theorem is_O.trans_tendsto (hfg : is_O f' g' l) (hg : tendsto g' l (𝓝 0)) : - tendsto f' l (𝓝 0) := +theorem is_O.trans_tendsto (hfg : is_O f'' g'' l) (hg : tendsto g'' l (𝓝 0)) : + tendsto f'' l (𝓝 0) := (is_o_one_iff ℝ).1 $ hfg.trans_is_o $ (is_o_one_iff ℝ).2 hg -theorem is_o.trans_tendsto (hfg : is_o f' g' l) (hg : tendsto g' l (𝓝 0)) : - tendsto f' l (𝓝 0) := +theorem is_o.trans_tendsto (hfg : is_o f'' g'' l) (hg : tendsto g'' l (𝓝 0)) : + tendsto f'' l (𝓝 0) := hfg.is_O.trans_tendsto hg /-! ### Multiplication by a constant -/ @@ -1199,7 +1206,7 @@ is_o_iff_tendsto' (eventually_of_forall hgf) alias is_o_iff_tendsto' ↔ _ asymptotics.is_o_of_tendsto' alias is_o_iff_tendsto ↔ _ asymptotics.is_o_of_tendsto -lemma is_o_const_left_of_ne {c : E'} (hc : c ≠ 0) : +lemma is_o_const_left_of_ne {c : E''} (hc : c ≠ 0) : is_o (λ x, c) g l ↔ tendsto (norm ∘ g) l at_top := begin split; intro h, @@ -1214,31 +1221,31 @@ begin rwa [norm_one, ← inv_inv ε, ← div_eq_inv_mul, one_le_div (inv_pos.2 ε0)] } end -@[simp] lemma is_o_const_left {c : E'} : - is_o (λ x, c) g' l ↔ c = 0 ∨ tendsto (norm ∘ g') l at_top := +@[simp] lemma is_o_const_left {c : E''} : + is_o (λ x, c) g'' l ↔ c = 0 ∨ tendsto (norm ∘ g'') l at_top := begin rcases eq_or_ne c 0 with rfl | hc, { simp only [is_o_zero, eq_self_iff_true, true_or] }, { simp only [hc, false_or, is_o_const_left_of_ne hc] } end -@[simp] theorem is_o_const_const_iff [ne_bot l] {d : E'} {c : F'} : +@[simp] theorem is_o_const_const_iff [ne_bot l] {d : E''} {c : F''} : is_o (λ x, d) (λ x, c) l ↔ d = 0 := have ¬tendsto (function.const α ∥c∥) l at_top, from not_tendsto_at_top_of_tendsto_nhds tendsto_const_nhds, by simp [function.const, this] -@[simp] lemma is_o_pure {x} : is_o f' g' (pure x) ↔ f' x = 0 := -calc is_o f' g' (pure x) ↔ is_o (λ y : α, f' x) (λ _, g' x) (pure x) : is_o_congr rfl rfl - ... ↔ f' x = 0 : is_o_const_const_iff +@[simp] lemma is_o_pure {x} : is_o f'' g'' (pure x) ↔ f'' x = 0 := +calc is_o f'' g'' (pure x) ↔ is_o (λ y : α, f'' x) (λ _, g'' x) (pure x) : is_o_congr rfl rfl + ... ↔ f'' x = 0 : is_o_const_const_iff -lemma is_o_const_id_comap_norm_at_top (c : F') : is_o (λ x : E', c) id (comap norm at_top) := +lemma is_o_const_id_comap_norm_at_top (c : F'') : is_o (λ x : E'', c) id (comap norm at_top) := is_o_const_left.2 $ or.inr tendsto_comap -lemma is_o_const_id_at_top (c : E') : is_o (λ x : ℝ, c) id at_top := +lemma is_o_const_id_at_top (c : E'') : is_o (λ x : ℝ, c) id at_top := is_o_const_left.2 $ or.inr tendsto_abs_at_top_at_top -lemma is_o_const_id_at_bot (c : E') : is_o (λ x : ℝ, c) id at_bot := +lemma is_o_const_id_at_bot (c : E'') : is_o (λ x : ℝ, c) id at_bot := is_o_const_left.2 $ or.inr tendsto_abs_at_bot_at_top /-! @@ -1421,33 +1428,33 @@ theorem is_o.right_is_O_add {f₁ f₂ : α → E'} (h : is_o f₁ f₂ l) : /-- If `f x = O(g x)` along `cofinite`, then there exists a positive constant `C` such that `∥f x∥ ≤ C * ∥g x∥` whenever `g x ≠ 0`. -/ -theorem bound_of_is_O_cofinite (h : is_O f g' cofinite) : - ∃ C > 0, ∀ ⦃x⦄, g' x ≠ 0 → ∥f x∥ ≤ C * ∥g' x∥ := +theorem bound_of_is_O_cofinite (h : is_O f g'' cofinite) : + ∃ C > 0, ∀ ⦃x⦄, g'' x ≠ 0 → ∥f x∥ ≤ C * ∥g'' x∥ := begin rcases h.exists_pos with ⟨C, C₀, hC⟩, rw [is_O_with, eventually_cofinite] at hC, - rcases (hC.to_finset.image (λ x, ∥f x∥ / ∥g' x∥)).exists_le with ⟨C', hC'⟩, - have : ∀ x, C * ∥g' x∥ < ∥f x∥ → ∥f x∥ / ∥g' x∥ ≤ C', by simpa using hC', + rcases (hC.to_finset.image (λ x, ∥f x∥ / ∥g'' x∥)).exists_le with ⟨C', hC'⟩, + have : ∀ x, C * ∥g'' x∥ < ∥f x∥ → ∥f x∥ / ∥g'' x∥ ≤ C', by simpa using hC', refine ⟨max C C', lt_max_iff.2 (or.inl C₀), λ x h₀, _⟩, rw [max_mul_of_nonneg _ _ (norm_nonneg _), le_max_iff, or_iff_not_imp_left, not_le], exact λ hx, (div_le_iff (norm_pos_iff.2 h₀)).1 (this _ hx) end -theorem is_O_cofinite_iff (h : ∀ x, g' x = 0 → f' x = 0) : - is_O f' g' cofinite ↔ ∃ C, ∀ x, ∥f' x∥ ≤ C * ∥g' x∥ := +theorem is_O_cofinite_iff (h : ∀ x, g'' x = 0 → f'' x = 0) : + is_O f'' g'' cofinite ↔ ∃ C, ∀ x, ∥f'' x∥ ≤ C * ∥g'' x∥ := ⟨λ h', let ⟨C, C₀, hC⟩ := bound_of_is_O_cofinite h' in - ⟨C, λ x, if hx : g' x = 0 then by simp [h _ hx, hx] else hC hx⟩, + ⟨C, λ x, if hx : g'' x = 0 then by simp [h _ hx, hx] else hC hx⟩, λ h, (is_O_top.2 h).mono le_top⟩ -theorem bound_of_is_O_nat_at_top {f : ℕ → E} {g' : ℕ → E'} (h : is_O f g' at_top) : - ∃ C > 0, ∀ ⦃x⦄, g' x ≠ 0 → ∥f x∥ ≤ C * ∥g' x∥ := +theorem bound_of_is_O_nat_at_top {f : ℕ → E} {g'' : ℕ → E''} (h : is_O f g'' at_top) : + ∃ C > 0, ∀ ⦃x⦄, g'' x ≠ 0 → ∥f x∥ ≤ C * ∥g'' x∥ := bound_of_is_O_cofinite $ by rwa nat.cofinite_eq_at_top -theorem is_O_nat_at_top_iff {f : ℕ → E'} {g : ℕ → F'} (h : ∀ x, g x = 0 → f x = 0) : +theorem is_O_nat_at_top_iff {f : ℕ → E''} {g : ℕ → F''} (h : ∀ x, g x = 0 → f x = 0) : is_O f g at_top ↔ ∃ C, ∀ x, ∥f x∥ ≤ C * ∥g x∥ := by rw [← nat.cofinite_eq_at_top, is_O_cofinite_iff h] -theorem is_O_one_nat_at_top_iff {f : ℕ → E'} : +theorem is_O_one_nat_at_top_iff {f : ℕ → E''} : is_O f (λ n, 1 : ℕ → ℝ) at_top ↔ ∃ C, ∀ n, ∥f n∥ ≤ C := iff.trans (is_O_nat_at_top_iff (λ n h, (one_ne_zero h).elim)) $ by simp only [norm_one, mul_one] diff --git a/src/analysis/normed_space/units.lean b/src/analysis/normed_space/units.lean index ec96dee863bd9..2115426c1fa3c 100644 --- a/src/analysis/normed_space/units.lean +++ b/src/analysis/normed_space/units.lean @@ -247,9 +247,8 @@ end /-- The function `inverse` is continuous at each unit of `R`. -/ lemma inverse_continuous_at (x : Rˣ) : continuous_at inverse (x : R) := begin - have h_is_o : is_o (λ (t : R), inverse (↑x + t) - ↑x⁻¹) (λ _, 1 : R → ℝ) (𝓝 0), - from ((inverse_add_norm_diff_first_order x).trans_is_o - (is_o_id_const (@one_ne_zero ℝ _ _)).norm_left), + have h_is_o : is_o (λ (t : R), inverse (↑x + t) - ↑x⁻¹) (λ _, 1 : R → ℝ) (𝓝 0) := + (inverse_add_norm_diff_first_order x).trans_is_o (is_o.norm_left $ is_o_id_const one_ne_zero), have h_lim : tendsto (λ (y:R), y - x) (𝓝 x) (𝓝 0), { refine tendsto_zero_iff_norm_tendsto_zero.mpr _, exact tendsto_iff_norm_tendsto_zero.mp tendsto_id }, From 8eb256410d66d34107732773bb5fa236aaeb48ee Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Fri, 29 Apr 2022 12:25:30 +0000 Subject: [PATCH 317/373] feat(topology/instances/matrix): add `matrix` lemmas about `tsum` (#13677) This adds lemmas about how `tsum` interacts with `diagonal` and `transpose`, along with the helper `summable` and `has_sum` lemmas. This also moves `topology/algebra/matrix` to `topology/instances/matrix`, since that seems to align better with how other types are handled. --- .../normed_space/finite_dimension.lean | 2 +- src/topology/algebra/infinite_sum.lean | 16 +++ .../{algebra => instances}/matrix.lean | 114 +++++++++++++++++- 3 files changed, 126 insertions(+), 6 deletions(-) rename src/topology/{algebra => instances}/matrix.lean (66%) diff --git a/src/analysis/normed_space/finite_dimension.lean b/src/analysis/normed_space/finite_dimension.lean index 7b5bb0b2f5906..2214125306c1a 100644 --- a/src/analysis/normed_space/finite_dimension.lean +++ b/src/analysis/normed_space/finite_dimension.lean @@ -8,7 +8,7 @@ import analysis.normed_space.affine_isometry import analysis.normed_space.operator_norm import analysis.normed_space.riesz_lemma import linear_algebra.matrix.to_lin -import topology.algebra.matrix +import topology.instances.matrix /-! # Finite dimensional normed spaces over complete fields diff --git a/src/topology/algebra/infinite_sum.lean b/src/topology/algebra/infinite_sum.lean index 4cd81375e5a8f..dfedbec0240aa 100644 --- a/src/topology/algebra/infinite_sum.lean +++ b/src/topology/algebra/infinite_sum.lean @@ -208,6 +208,22 @@ protected lemma summable.map [add_comm_monoid γ] [topological_space γ] (hf : s summable (g ∘ f) := (hf.has_sum.map g hg).summable +protected lemma summable.map_iff_of_left_inverse [add_comm_monoid γ] [topological_space γ] + {G G'} [add_monoid_hom_class G α γ] [add_monoid_hom_class G' γ α] (g : G) (g' : G') + (hg : continuous g) (hg' : continuous g') (hinv : function.left_inverse g' g) : + summable (g ∘ f) ↔ summable f := +⟨λ h, begin + have := h.map _ hg', + rwa [←function.comp.assoc, hinv.id] at this, +end, λ h, h.map _ hg⟩ + +/-- A special case of `summable.map_iff_of_left_inverse` for convenience -/ +protected lemma summable.map_iff_of_equiv [add_comm_monoid γ] [topological_space γ] + {G} [add_equiv_class G α γ] (g : G) + (hg : continuous g) (hg' : continuous (add_equiv_class.inv g : γ → α)) : + summable (g ∘ f) ↔ summable f := +summable.map_iff_of_left_inverse g (g : α ≃+ γ).symm hg hg' (add_equiv_class.left_inv g) + /-- If `f : ℕ → α` has sum `a`, then the partial sums `∑_{i=0}^{n-1} f i` converge to `a`. -/ lemma has_sum.tendsto_sum_nat {f : ℕ → α} (h : has_sum f a) : tendsto (λn:ℕ, ∑ i in range n, f i) at_top (𝓝 a) := diff --git a/src/topology/algebra/matrix.lean b/src/topology/instances/matrix.lean similarity index 66% rename from src/topology/algebra/matrix.lean rename to src/topology/instances/matrix.lean index 73278a09aeb42..e6d49b1850428 100644 --- a/src/topology/algebra/matrix.lean +++ b/src/topology/instances/matrix.lean @@ -5,6 +5,7 @@ Authors: Oliver Nash, Eric Wieser -/ import linear_algebra.determinant import topology.algebra.ring +import topology.algebra.infinite_sum /-! # Topological properties of matrices @@ -13,18 +14,30 @@ This file is a place to collect topological results about matrices. ## Main definitions: - * `matrix.topological_ring`: square matrices form a topological ring - * `continuous.matrix_det`: the determinant is continuous over a topological ring. - * `continuous.matrix_adjugate`: the adjugate is continuous over a topological ring. +* `matrix.topological_ring`: square matrices form a topological ring + +## Main results + +* Continuity: + * `continuous.matrix_det`: the determinant is continuous over a topological ring. + * `continuous.matrix_adjugate`: the adjugate is continuous over a topological ring. +* Infinite sums + * `matrix.transpose_tsum`: transpose commutes with infinite sums + * `matrix.diagonal_tsum`: diagonal commutes with infinite sums -/ open matrix open_locale matrix variables {X α l m n p S R : Type*} {m' n' : l → Type*} -variables [topological_space X] [topological_space R] -instance : topological_space (matrix m n R) := Pi.topological_space +instance [topological_space R] : topological_space (matrix m n R) := Pi.topological_space + +instance [topological_space R] [t2_space R] : t2_space (matrix m n R) := Pi.t2_space + +/-! ### Lemmas about continuity of operations -/ +section continuity +variables [topological_space X] [topological_space R] instance [has_scalar α R] [has_continuous_const_smul α R] : has_continuous_const_smul α (matrix n n R) := @@ -141,6 +154,10 @@ lemma continuous.matrix_diag {A : X → matrix n n R} (hA : continuous A) : continuous (λ x, matrix.diag (A x)) := continuous_pi $ λ _, hA.matrix_elem _ _ +-- note this doesn't elaborate well from the above +lemma continuous_matrix_diag : continuous (matrix.diag : matrix n n R → n → R) := +show continuous (λ x : matrix n n R, matrix.diag x), from continuous_id.matrix_diag + @[continuity] lemma continuous.matrix_trace [fintype n] [semiring S] [add_comm_monoid R] [has_continuous_add R] [module S R] {A : X → matrix n n R} (hA : continuous A) : @@ -220,3 +237,90 @@ continuous_matrix $ λ ⟨i₁, i₂⟩ ⟨j₁, j₂⟩, begin end end block_matrices + +end continuity + +/-! ### Lemmas about infinite sums -/ +section tsum +variables [semiring α] [add_comm_monoid R] [topological_space R] [module α R] + +lemma has_sum.matrix_transpose {f : X → matrix m n R} {a : matrix m n R} (hf : has_sum f a) : + has_sum (λ x, (f x)ᵀ) aᵀ := +(hf.map (@matrix.transpose_add_equiv m n R _) continuous_id.matrix_transpose : _) + +lemma summable.matrix_transpose {f : X → matrix m n R} (hf : summable f) : + summable (λ x, (f x)ᵀ) := +hf.has_sum.matrix_transpose.summable + +@[simp] lemma summable_matrix_transpose {f : X → matrix m n R} : + summable (λ x, (f x)ᵀ) ↔ summable f := +(summable.map_iff_of_equiv (@matrix.transpose_add_equiv m n R _) + (@continuous_id (matrix m n R) _).matrix_transpose (continuous_id.matrix_transpose) : _) + +lemma matrix.transpose_tsum [t2_space R] {f : X → matrix m n R} : (∑' x, f x)ᵀ = ∑' x, (f x)ᵀ := +begin + by_cases hf : summable f, + { exact hf.has_sum.matrix_transpose.tsum_eq.symm }, + { have hft := summable_matrix_transpose.not.mpr hf, + rw [tsum_eq_zero_of_not_summable hf, tsum_eq_zero_of_not_summable hft, transpose_zero] }, +end + +lemma has_sum.matrix_diagonal [decidable_eq n] {f : X → n → R} {a : n → R} (hf : has_sum f a) : + has_sum (λ x, diagonal (f x)) (diagonal a) := +(hf.map (diagonal_add_monoid_hom n R) $ continuous.matrix_diagonal $ by exact continuous_id : _) + +lemma summable.matrix_diagonal [decidable_eq n] {f : X → n → R} (hf : summable f) : + summable (λ x, diagonal (f x)) := +hf.has_sum.matrix_diagonal.summable + +@[simp] lemma summable_matrix_diagonal [decidable_eq n] {f : X → n → R} : + summable (λ x, diagonal (f x)) ↔ summable f := +(summable.map_iff_of_left_inverse + (@matrix.diagonal_add_monoid_hom n R _ _) (matrix.diag_add_monoid_hom n R) + (by exact continuous.matrix_diagonal continuous_id) + continuous_matrix_diag + (λ A, diag_diagonal A) : _) + +lemma matrix.diagonal_tsum [decidable_eq n] [t2_space R] {f : X → n → R} : + diagonal (∑' x, f x) = ∑' x, diagonal (f x) := +begin + by_cases hf : summable f, + { exact hf.has_sum.matrix_diagonal.tsum_eq.symm }, + { have hft := summable_matrix_diagonal.not.mpr hf, + rw [tsum_eq_zero_of_not_summable hf, tsum_eq_zero_of_not_summable hft], + exact diagonal_zero }, +end + +lemma has_sum.matrix_diag {f : X → matrix n n R} {a : matrix n n R} (hf : has_sum f a) : + has_sum (λ x, diag (f x)) (diag a) := +(hf.map (diag_add_monoid_hom n R) continuous_matrix_diag : _) + +lemma summable.matrix_diag {f : X → matrix n n R} (hf : summable f) : summable (λ x, diag (f x)) := +hf.has_sum.matrix_diag.summable + +section block_matrices + +lemma has_sum.matrix_block_diagonal [decidable_eq p] + {f : X → p → matrix m n R} {a : p → matrix m n R} (hf : has_sum f a) : + has_sum (λ x, block_diagonal (f x)) (block_diagonal a) := +(hf.map (block_diagonal_add_monoid_hom m n p R) $ + continuous.matrix_block_diagonal $ by exact continuous_id : _) + +lemma summable.matrix_block_diagonal [decidable_eq p] {f : X → p → matrix m n R} (hf : summable f) : + summable (λ x, block_diagonal (f x)) := +hf.has_sum.matrix_block_diagonal.summable + +lemma has_sum.matrix_block_diagonal' [decidable_eq l] + {f : X → Π i, matrix (m' i) (n' i) R} {a : Π i, matrix (m' i) (n' i) R} (hf : has_sum f a) : + has_sum (λ x, block_diagonal' (f x)) (block_diagonal' a) := +(hf.map (block_diagonal'_add_monoid_hom m' n' R) $ + continuous.matrix_block_diagonal' $ by exact continuous_id : _) + +lemma summable.matrix_block_diagonal' [decidable_eq l] {f : X → Π i, matrix (m' i) (n' i) R} + (hf : summable f) : + summable (λ x, block_diagonal' (f x)) := +hf.has_sum.matrix_block_diagonal'.summable + +end block_matrices + +end tsum From b2e0a2d0cd0ae990064d893146002acb664f6ee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Fri, 29 Apr 2022 12:25:31 +0000 Subject: [PATCH 318/373] feat(group_theory/subgroup/basic): `inclusion` lemmas (#13754) A few lemmas for `set.inclusion`, `subgroup.inclusion`, `subalgebra.inclusion`. --- src/algebra/algebra/subalgebra/basic.lean | 5 ++++- src/data/set/basic.lean | 25 ++++++++++------------- src/group_theory/subgroup/basic.lean | 12 +++++++++++ 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/algebra/algebra/subalgebra/basic.lean b/src/algebra/algebra/subalgebra/basic.lean index 11db8db83deaf..39a8100e37574 100644 --- a/src/algebra/algebra/subalgebra/basic.lean +++ b/src/algebra/algebra/subalgebra/basic.lean @@ -762,7 +762,10 @@ lemma inclusion_injective {S T : subalgebra R A} (h : S ≤ T) : inclusion (le_refl S) = alg_hom.id R S := alg_hom.ext $ λ x, subtype.ext rfl -@[simp] lemma inclusion_right {S T : subalgebra R A} (h : S ≤ T) (x : T) +@[simp] lemma inclusion_mk {S T : subalgebra R A} (h : S ≤ T) (x : A) (hx : x ∈ S) : + inclusion h ⟨x, hx⟩ = ⟨x, h hx⟩ := rfl + +lemma inclusion_right {S T : subalgebra R A} (h : S ≤ T) (x : T) (m : (x : A) ∈ S) : inclusion h ⟨x, m⟩ = x := subtype.ext rfl @[simp] lemma inclusion_inclusion {S T U : subalgebra R A} (hst : S ≤ T) (htu : T ≤ U) diff --git a/src/data/set/basic.lean b/src/data/set/basic.lean index e3312c00521ab..f89814854c229 100644 --- a/src/data/set/basic.lean +++ b/src/data/set/basic.lean @@ -2227,32 +2227,29 @@ namespace set /-! ### Lemmas about `inclusion`, the injection of subtypes induced by `⊆` -/ section inclusion -variable {α : Type*} +variables {α : Type*} {s t u : set α} /-- `inclusion` is the "identity" function between two subsets `s` and `t`, where `s ⊆ t` -/ -def inclusion {s t : set α} (h : s ⊆ t) : s → t := +def inclusion (h : s ⊆ t) : s → t := λ x : s, (⟨x, h x.2⟩ : t) -@[simp] lemma inclusion_self {s : set α} (x : s) : inclusion subset.rfl x = x := -by { cases x, refl } +@[simp] lemma inclusion_self (x : s) : inclusion subset.rfl x = x := by { cases x, refl } + +@[simp] lemma inclusion_mk {h : s ⊆ t} (a : α) (ha : a ∈ s) : inclusion h ⟨a, ha⟩ = ⟨a, h ha⟩ := rfl -@[simp] lemma inclusion_right {s t : set α} (h : s ⊆ t) (x : t) (m : (x : α) ∈ s) : - inclusion h ⟨x, m⟩ = x := +lemma inclusion_right (h : s ⊆ t) (x : t) (m : (x : α) ∈ s) : inclusion h ⟨x, m⟩ = x := by { cases x, refl } -@[simp] lemma inclusion_inclusion {s t u : set α} (hst : s ⊆ t) (htu : t ⊆ u) - (x : s) : inclusion htu (inclusion hst x) = inclusion (set.subset.trans hst htu) x := +@[simp] lemma inclusion_inclusion (hst : s ⊆ t) (htu : t ⊆ u) (x : s) : + inclusion htu (inclusion hst x) = inclusion (hst.trans htu) x := by { cases x, refl } -@[simp] lemma coe_inclusion {s t : set α} (h : s ⊆ t) (x : s) : - (inclusion h x : α) = (x : α) := rfl +@[simp] lemma coe_inclusion (h : s ⊆ t) (x : s) : (inclusion h x : α) = (x : α) := rfl -lemma inclusion_injective {s t : set α} (h : s ⊆ t) : - function.injective (inclusion h) +lemma inclusion_injective (h : s ⊆ t) : injective (inclusion h) | ⟨_, _⟩ ⟨_, _⟩ := subtype.ext_iff_val.2 ∘ subtype.ext_iff_val.1 -@[simp] lemma range_inclusion {s t : set α} (h : s ⊆ t) : - range (inclusion h) = {x : t | (x:α) ∈ s} := +@[simp] lemma range_inclusion (h : s ⊆ t) : range (inclusion h) = {x : t | (x:α) ∈ s} := by { ext ⟨x, hx⟩, simp [inclusion] } lemma eq_of_inclusion_surjective {s t : set α} {h : s ⊆ t} diff --git a/src/group_theory/subgroup/basic.lean b/src/group_theory/subgroup/basic.lean index d09154d73c2d1..50088d9db5624 100644 --- a/src/group_theory/subgroup/basic.lean +++ b/src/group_theory/subgroup/basic.lean @@ -247,6 +247,18 @@ lemma coe_pow (x : H) (n : ℕ) : ((x ^ n : H) : G) = x ^ n := def inclusion {H K : S} (h : H ≤ K) : H →* K := monoid_hom.mk' (λ x, ⟨x, h x.prop⟩) (λ ⟨a, ha⟩ ⟨b, hb⟩, rfl) +@[simp, to_additive] lemma inclusion_self (x : H) : inclusion le_rfl x = x := by { cases x, refl } +@[simp, to_additive] lemma inclusion_mk {h : H ≤ K} (x : G) (hx : x ∈ H) : + inclusion h ⟨x, hx⟩ = ⟨x, h hx⟩ := rfl + +@[to_additive] +lemma inclusion_right (h : H ≤ K) (x : K) (hx : (x : G) ∈ H) : inclusion h ⟨x, hx⟩ = x := +by { cases x, refl } + +@[simp] lemma inclusion_inclusion {L : S} (hHK : H ≤ K) (hKL : K ≤ L) (x : H) : + inclusion hKL (inclusion hHK x) = inclusion (hHK.trans hKL) x := +by { cases x, refl } + @[simp, to_additive] lemma coe_inclusion {H K : S} {h : H ≤ K} (a : H) : (inclusion h a : G) = a := by { cases a, simp only [inclusion, set_like.coe_mk, monoid_hom.mk'_apply] } From 58552fe0860f199d68c6a9cf2330d5d68f8895ef Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Fri, 29 Apr 2022 12:25:32 +0000 Subject: [PATCH 319/373] feat(set_theory/cardinal/basic): cardinality of a powerset (#13786) --- src/set_theory/cardinal/basic.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/set_theory/cardinal/basic.lean b/src/set_theory/cardinal/basic.lean index 40b65a2edd1df..82d617ba876f9 100644 --- a/src/set_theory/cardinal/basic.lean +++ b/src/set_theory/cardinal/basic.lean @@ -435,6 +435,10 @@ theorem lift_two : lift.{u v} 2 = 2 := by simp @[simp] theorem mk_set {α : Type u} : #(set α) = 2 ^ #α := by simp [set, mk_arrow] +/-- A variant of `cardinal.mk_set` expressed in terms of a `set` instead of a `Type`. -/ +@[simp] theorem mk_powerset {α : Type u} (s : set α) : #↥(𝒫 s) = 2 ^ #↥s := +(mk_congr (equiv.set.powerset s)).trans mk_set + theorem lift_two_power (a) : lift (2 ^ a) = 2 ^ lift a := by simp section order_properties From e56126404f9ab5e3349dab6fa4eac11353af4717 Mon Sep 17 00:00:00 2001 From: negiizhao Date: Fri, 29 Apr 2022 14:39:14 +0000 Subject: [PATCH 320/373] feat(algebra/order/monoid_lemmas_zero_lt): add instances (#13376) --- src/algebra/order/monoid_lemmas_zero_lt.lean | 34 ++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/algebra/order/monoid_lemmas_zero_lt.lean b/src/algebra/order/monoid_lemmas_zero_lt.lean index 71019940d21f4..ead2c8afba55a 100644 --- a/src/algebra/order/monoid_lemmas_zero_lt.lean +++ b/src/algebra/order/monoid_lemmas_zero_lt.lean @@ -202,6 +202,40 @@ lemma mul_le_mul_iff_right [mul_pos_mono α] [mul_pos_mono_rev α] end preorder +section partial_order +variables [partial_order α] + +@[priority 100] -- see Note [lower instance priority] +instance pos_mul_strict_mono.to_pos_mul_mono [pos_mul_strict_mono α] : pos_mul_mono α := +⟨λ x a b h, h.eq_or_lt.elim (λ h', h' ▸ le_rfl) (λ h', (mul_lt_mul_left' h' x.prop).le)⟩ + +@[priority 100] -- see Note [lower instance priority] +instance mul_pos_strict_mono.to_mul_pos_mono [mul_pos_strict_mono α] : mul_pos_mono α := +⟨λ x a b h, h.eq_or_lt.elim (λ h', h' ▸ le_rfl) (λ h', (mul_lt_mul_right' h' x.prop).le)⟩ + +@[priority 100] -- see Note [lower instance priority] +instance pos_mul_mono_rev.to_pos_mul_reflect_lt [pos_mul_mono_rev α] : pos_mul_reflect_lt α := +⟨λ x a b h, lt_of_le_of_ne (le_of_mul_le_mul_left' h.le x.prop) (λ h', by simpa [h'] using h)⟩ + +@[priority 100] -- see Note [lower instance priority] +instance mul_pos_mono_rev.to_mul_pos_reflect_lt [mul_pos_mono_rev α] : mul_pos_reflect_lt α := +⟨λ x a b h, lt_of_le_of_ne (le_of_mul_le_mul_right' h.le x.prop) (λ h', by simpa [h'] using h)⟩ + +end partial_order + +section linear_order +variables [linear_order α] + +@[priority 100] -- see Note [lower instance priority] +instance pos_mul_strict_mono.to_pos_mul_mono_rev [pos_mul_strict_mono α] : pos_mul_mono_rev α := +⟨λ x a b h, le_of_not_lt $ λ h', h.not_lt (mul_lt_mul_left' h' x.prop)⟩ + +@[priority 100] -- see Note [lower instance priority] +instance mul_pos_strict_mono.to_mul_pos_mono_rev [mul_pos_strict_mono α] : mul_pos_mono_rev α := +⟨λ x a b h, le_of_not_lt $ λ h', h.not_lt (mul_lt_mul_right' h' x.prop)⟩ + +end linear_order + end has_mul_zero section mul_zero_class From ce79a27be6e65ca0590c177558dd9c9b019e263b Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Fri, 29 Apr 2022 14:39:15 +0000 Subject: [PATCH 321/373] feat(analysis/normed_space/pi_Lp): add lemmas about `pi_Lp.equiv` (#13569) Most of these are trivial `dsimp` lemmas, but they also let us talk about the norm of constant vectors. --- src/analysis/normed_space/pi_Lp.lean | 48 ++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/src/analysis/normed_space/pi_Lp.lean b/src/analysis/normed_space/pi_Lp.lean index e6a0b78cc11e6..888405d93df83 100644 --- a/src/analysis/normed_space/pi_Lp.lean +++ b/src/analysis/normed_space/pi_Lp.lean @@ -83,6 +83,9 @@ to compare the `L^p` and `L^∞` distances through it. -/ protected def equiv : pi_Lp p α ≃ Π (i : ι), α i := equiv.refl _ +@[simp] lemma equiv_apply (x : pi_Lp p α) (i : ι) : pi_Lp.equiv p α x i = x i := rfl +@[simp] lemma equiv_symm_apply (x : Π i, α i) (i : ι) : (pi_Lp.equiv p α).symm x i = x i := rfl + section /-! ### The uniformity on finite `L^p` products is the product uniformity @@ -314,12 +317,53 @@ instance normed_space [∀i, semi_normed_group (β i)] [∀i, normed_space 𝕜 /- Register simplification lemmas for the applications of `pi_Lp` elements, as the usual lemmas for Pi types will not trigger. -/ -variables {𝕜 p α} -[∀i, semi_normed_group (β i)] [∀i, normed_space 𝕜 (β i)] (c : 𝕜) (x y : pi_Lp p β) (i : ι) +variables {𝕜 p α} [Π i, semi_normed_group (β i)] [Π i, normed_space 𝕜 (β i)] (c : 𝕜) +variables (x y : pi_Lp p β) (x' y' : Π i, β i) (i : ι) +@[simp] lemma zero_apply : (0 : pi_Lp p β) i = 0 := rfl @[simp] lemma add_apply : (x + y) i = x i + y i := rfl @[simp] lemma sub_apply : (x - y) i = x i - y i := rfl @[simp] lemma smul_apply : (c • x) i = c • x i := rfl @[simp] lemma neg_apply : (-x) i = - (x i) := rfl +@[simp] lemma equiv_zero : pi_Lp.equiv p β 0 = 0 := rfl +@[simp] lemma equiv_symm_zero : (pi_Lp.equiv p β).symm 0 = 0 := rfl + +@[simp] lemma equiv_add : + pi_Lp.equiv p β (x + y) = pi_Lp.equiv p β x + pi_Lp.equiv p β y := rfl +@[simp] lemma equiv_symm_add : + (pi_Lp.equiv p β).symm (x' + y') = (pi_Lp.equiv p β).symm x' + (pi_Lp.equiv p β).symm y' := rfl + +@[simp] lemma equiv_sub : pi_Lp.equiv p β (x - y) = pi_Lp.equiv p β x - pi_Lp.equiv p β y := rfl +@[simp] lemma equiv_symm_sub : + (pi_Lp.equiv p β).symm (x' - y') = (pi_Lp.equiv p β).symm x' - (pi_Lp.equiv p β).symm y' := rfl + +@[simp] lemma equiv_neg : pi_Lp.equiv p β (-x) = -pi_Lp.equiv p β x := rfl +@[simp] lemma equiv_symm_neg : (pi_Lp.equiv p β).symm (-x') = -(pi_Lp.equiv p β).symm x' := rfl + +@[simp] lemma equiv_smul : pi_Lp.equiv p β (c • x) = c • pi_Lp.equiv p β x := rfl +@[simp] lemma equiv_symm_smul : + (pi_Lp.equiv p β).symm (c • x') = c • (pi_Lp.equiv p β).symm x' := rfl + +lemma nnnorm_equiv_symm_const {β} [semi_normed_group β] (b : β) : + ∥(pi_Lp.equiv p (λ _ : ι, β)).symm (function.const _ b)∥₊ = fintype.card ι ^ (1 / p) * ∥b∥₊ := +begin + have : p ≠ 0 := (zero_lt_one.trans_le (fact.out $ 1 ≤ p)).ne', + simp_rw [pi_Lp.nnnorm_eq, equiv_symm_apply, function.const_apply, finset.sum_const, + finset.card_univ, nsmul_eq_mul, nnreal.mul_rpow, ←nnreal.rpow_mul, mul_one_div_cancel this, + nnreal.rpow_one], +end + +lemma norm_equiv_symm_const {β} [semi_normed_group β] (b : β) : + ∥(pi_Lp.equiv p (λ _ : ι, β)).symm (function.const _ b)∥ = fintype.card ι ^ (1 / p) * ∥b∥ := +(congr_arg coe $ nnnorm_equiv_symm_const b).trans $ by simp + +lemma nnnorm_equiv_symm_one {β} [semi_normed_group β] [has_one β] : + ∥(pi_Lp.equiv p (λ _ : ι, β)).symm 1∥₊ = fintype.card ι ^ (1 / p) * ∥(1 : β)∥₊ := +(nnnorm_equiv_symm_const (1 : β)).trans rfl + +lemma norm_equiv_symm_one {β} [semi_normed_group β] [has_one β] : + ∥(pi_Lp.equiv p (λ _ : ι, β)).symm 1∥ = fintype.card ι ^ (1 / p) * ∥(1 : β)∥ := +(norm_equiv_symm_const (1 : β)).trans rfl + end pi_Lp From 7373832e4b966d89c8f91f2b343d47ecd5ebf956 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Fri, 29 Apr 2022 14:39:17 +0000 Subject: [PATCH 322/373] chore(analysis/convex): move `convex_on_norm`, change API (#13631) * Move `convex_on_norm` from `specific_functions` to `topology`, use it to golf the proof of `convex_on_dist`. * The old `convex_on_norm` is now called `convex_on_univ_norm`. The new `convex_on_norm` is about convexity on any convex set. * Add `convex_on_univ_dist` and make `s : set E` an implicit argument in `convex_on_dist`. This way APIs about convexity of norm and distance agree. --- src/analysis/convex/specific_functions.lean | 8 ---- src/analysis/convex/topology.lean | 48 ++++++++++++--------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/analysis/convex/specific_functions.lean b/src/analysis/convex/specific_functions.lean index 563b84fabe249..d5c55c7f462ae 100644 --- a/src/analysis/convex/specific_functions.lean +++ b/src/analysis/convex/specific_functions.lean @@ -32,14 +32,6 @@ For `p : ℝ`, prove that `λ x, x ^ p` is concave when `0 ≤ p ≤ 1` and stri open real set open_locale big_operators -/-- The norm of a real normed space is convex. Also see `seminorm.convex_on`. -/ -lemma convex_on_norm {E : Type*} [normed_group E] [normed_space ℝ E] : - convex_on ℝ univ (norm : E → ℝ) := -⟨convex_univ, λ x y hx hy a b ha hb hab, - calc ∥a • x + b • y∥ ≤ ∥a • x∥ + ∥b • y∥ : norm_add_le _ _ - ... = a * ∥x∥ + b * ∥y∥ - : by rw [norm_smul, norm_smul, real.norm_of_nonneg ha, real.norm_of_nonneg hb]⟩ - /-- `exp` is strictly convex on the whole real line. -/ lemma strict_convex_on_exp : strict_convex_on ℝ univ exp := strict_convex_on_univ_of_deriv2_pos differentiable_exp (λ x, (iter_deriv_exp 2).symm ▸ exp_pos x) diff --git a/src/analysis/convex/topology.lean b/src/analysis/convex/topology.lean index 33a69f779603a..5caddce64ffd5 100644 --- a/src/analysis/convex/topology.lean +++ b/src/analysis/convex/topology.lean @@ -18,7 +18,10 @@ We prove the following facts: * `convex.closure` : closure of a convex set is convex; * `set.finite.compact_convex_hull` : convex hull of a finite set is compact; * `set.finite.is_closed_convex_hull` : convex hull of a finite set is closed; -* `convex_on_dist` : distance to a fixed point is convex on any convex set; +* `convex_on_norm`, `convex_on_dist` : norm and distance to a fixed point is convex on any convex + set; +* `convex_on_univ_norm`, `convex_on_univ_dist` : norm and distance to a fixed point is convex on + the whole space; * `convex_hull_ediam`, `convex_hull_diam` : convex hull of a set has the same (e)metric diameter as the original set; * `bounded_convex_hull` : convex hull of a set is bounded if and only if the original set @@ -285,34 +288,39 @@ end has_continuous_smul /-! ### Normed vector space -/ section normed_space -variables [normed_group E] [normed_space ℝ E] - -lemma convex_on_dist (z : E) (s : set E) (hs : convex ℝ s) : - convex_on ℝ s (λz', dist z' z) := -and.intro hs $ -assume x y hx hy a b ha hb hab, -calc - dist (a • x + b • y) z = ∥ (a • x + b • y) - (a + b) • z ∥ : - by rw [hab, one_smul, normed_group.dist_eq] - ... = ∥a • (x - z) + b • (y - z)∥ : - by rw [add_smul, smul_sub, smul_sub, sub_eq_add_neg, sub_eq_add_neg, sub_eq_add_neg, neg_add, - ←add_assoc, add_assoc (a • x), add_comm (b • y)]; simp only [add_assoc] - ... ≤ ∥a • (x - z)∥ + ∥b • (y - z)∥ : - norm_add_le (a • (x - z)) (b • (y - z)) - ... = a * dist x z + b * dist y z : - by simp [norm_smul, normed_group.dist_eq, real.norm_eq_abs, abs_of_nonneg ha, abs_of_nonneg hb] +variables [semi_normed_group E] [normed_space ℝ E] + +/-- The norm on a real normed space is convex on any convex set. See also `seminorm.convex_on` +and `convex_on_univ_norm`. -/ +lemma convex_on_norm {s : set E} (hs : convex ℝ s) : convex_on ℝ s norm := +⟨hs, λ x y hx hy a b ha hb hab, + calc ∥a • x + b • y∥ ≤ ∥a • x∥ + ∥b • y∥ : norm_add_le _ _ + ... = a * ∥x∥ + b * ∥y∥ + : by rw [norm_smul, norm_smul, real.norm_of_nonneg ha, real.norm_of_nonneg hb]⟩ + +/-- The norm on a real normed space is convex on the whole space. See also `seminorm.convex_on` +and `convex_on_norm`. -/ +lemma convex_on_univ_norm : convex_on ℝ univ (norm : E → ℝ) := convex_on_norm convex_univ + +lemma convex_on_dist (z : E) {s : set E} (hs : convex ℝ s) : convex_on ℝ s (λz', dist z' z) := +by simpa [dist_eq_norm, preimage_preimage] + using (convex_on_norm (hs.translate (-z))).comp_affine_map + (affine_map.id ℝ E - affine_map.const ℝ E z) + +lemma convex_on_univ_dist (z : E) : convex_on ℝ univ (λz', dist z' z) := +convex_on_dist z convex_univ lemma convex_ball (a : E) (r : ℝ) : convex ℝ (metric.ball a r) := -by simpa only [metric.ball, sep_univ] using (convex_on_dist a _ convex_univ).convex_lt r +by simpa only [metric.ball, sep_univ] using (convex_on_univ_dist a).convex_lt r lemma convex_closed_ball (a : E) (r : ℝ) : convex ℝ (metric.closed_ball a r) := -by simpa only [metric.closed_ball, sep_univ] using (convex_on_dist a _ convex_univ).convex_le r +by simpa only [metric.closed_ball, sep_univ] using (convex_on_univ_dist a).convex_le r /-- Given a point `x` in the convex hull of `s` and a point `y`, there exists a point of `s` at distance at least `dist x y` from `y`. -/ lemma convex_hull_exists_dist_ge {s : set E} {x : E} (hx : x ∈ convex_hull ℝ s) (y : E) : ∃ x' ∈ s, dist x y ≤ dist x' y := -(convex_on_dist y _ (convex_convex_hull ℝ _)).exists_ge_of_mem_convex_hull hx +(convex_on_dist y (convex_convex_hull ℝ _)).exists_ge_of_mem_convex_hull hx /-- Given a point `x` in the convex hull of `s` and a point `y` in the convex hull of `t`, there exist points `x' ∈ s` and `y' ∈ t` at distance at least `dist x y`. -/ From a3beb6282deccf44f3f07746ce8390ff6305d410 Mon Sep 17 00:00:00 2001 From: sgouezel Date: Fri, 29 Apr 2022 14:39:18 +0000 Subject: [PATCH 323/373] feat(analysis/*): a sample of easy useful lemmas (#13697) Lemmas needed for #13690 --- src/analysis/inner_product_space/pi_L2.lean | 17 +++++------------ src/analysis/special_functions/pow.lean | 16 ++++++++++++++-- src/analysis/specific_limits/basic.lean | 12 ++++++++++++ src/data/real/ennreal.lean | 1 + src/topology/algebra/group.lean | 9 +++++++++ 5 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/analysis/inner_product_space/pi_L2.lean b/src/analysis/inner_product_space/pi_L2.lean index e02c49dda1d93..774acfea5dc85 100644 --- a/src/analysis/inner_product_space/pi_L2.lean +++ b/src/analysis/inner_product_space/pi_L2.lean @@ -57,17 +57,11 @@ instance pi_Lp.inner_product_space {ι : Type*} [fintype ι] (f : ι → Type*) norm_sq_eq_inner := begin intro x, - have h₁ : ∑ (i : ι), ∥x i∥ ^ (2 : ℕ) = ∑ (i : ι), ∥x i∥ ^ (2 : ℝ), - { apply finset.sum_congr rfl, - intros j hj, - simp [←rpow_nat_cast] }, - have h₂ : 0 ≤ ∑ (i : ι), ∥x i∥ ^ (2 : ℝ), - { rw [←h₁], - exact finset.sum_nonneg (λ j (hj : j ∈ finset.univ), pow_nonneg (norm_nonneg (x j)) 2) }, - simp [norm, add_monoid_hom.map_sum, ←norm_sq_eq_inner], - rw [←rpow_nat_cast ((∑ (i : ι), ∥x i∥ ^ (2 : ℝ)) ^ (2 : ℝ)⁻¹) 2], - rw [←rpow_mul h₂], - norm_num [h₁], + have h₂ : 0 ≤ ∑ (i : ι), ∥x i∥ ^ (2 : ℝ) := + finset.sum_nonneg (λ j hj, rpow_nonneg_of_nonneg (norm_nonneg (x j)) 2), + simp only [norm, add_monoid_hom.map_sum, ← norm_sq_eq_inner, one_div], + rw [← rpow_nat_cast ((∑ (i : ι), ∥x i∥ ^ (2 : ℝ)) ^ (2 : ℝ)⁻¹) 2, ← rpow_mul h₂], + norm_num, end, conj_sym := begin @@ -483,4 +477,3 @@ lemma inner_matrix_col_col (A B : matrix (fin n) (fin m) 𝕜) (i j : (fin m)) : ⟪Aᵀ i, Bᵀ j⟫ₙ = (Aᴴ ⬝ B) i j := rfl end matrix - diff --git a/src/analysis/special_functions/pow.lean b/src/analysis/special_functions/pow.lean index 916c3db4e14f6..f24b1db182652 100644 --- a/src/analysis/special_functions/pow.lean +++ b/src/analysis/special_functions/pow.lean @@ -99,13 +99,16 @@ by rw [sub_eq_add_neg, cpow_add _ _ hx, cpow_neg, div_eq_mul_inv] lemma cpow_neg_one (x : ℂ) : x ^ (-1 : ℂ) = x⁻¹ := by simpa using cpow_neg x 1 -@[simp] lemma cpow_nat_cast (x : ℂ) : ∀ (n : ℕ), x ^ (n : ℂ) = x ^ n +@[simp, norm_cast] lemma cpow_nat_cast (x : ℂ) : ∀ (n : ℕ), x ^ (n : ℂ) = x ^ n | 0 := by simp | (n + 1) := if hx : x = 0 then by simp only [hx, pow_succ, complex.zero_cpow (nat.cast_ne_zero.2 (nat.succ_ne_zero _)), zero_mul] else by simp [cpow_add, hx, pow_add, cpow_nat_cast n] -@[simp] lemma cpow_int_cast (x : ℂ) : ∀ (n : ℤ), x ^ (n : ℂ) = x ^ n +@[simp] lemma cpow_two (x : ℂ) : x ^ (2 : ℂ) = x ^ 2 := +by { rw ← cpow_nat_cast, simp only [nat.cast_bit0, nat.cast_one] } + +@[simp, norm_cast] lemma cpow_int_cast (x : ℂ) : ∀ (n : ℤ), x ^ (n : ℂ) = x ^ n | (n : ℕ) := by simp; refl | -[1+ n] := by rw zpow_neg_succ_of_nat; simp only [int.neg_succ_of_nat_coe, int.cast_neg, complex.cpow_neg, inv_eq_one_div, @@ -529,6 +532,9 @@ by simp only [rpow_def, ← complex.of_real_zpow, complex.cpow_int_cast, @[simp, norm_cast] lemma rpow_nat_cast (x : ℝ) (n : ℕ) : x ^ (n : ℝ) = x ^ n := rpow_int_cast x n +@[simp] lemma rpow_two (x : ℝ) : x ^ (2 : ℝ) = x ^ 2 := +by { rw ← rpow_nat_cast, simp only [nat.cast_bit0, nat.cast_one] } + lemma rpow_neg_one (x : ℝ) : x ^ (-1 : ℝ) = x⁻¹ := begin suffices H : x ^ ((-1 : ℤ) : ℝ) = x⁻¹, by exact_mod_cast H, @@ -1109,6 +1115,9 @@ end @[simp, norm_cast] lemma rpow_nat_cast (x : ℝ≥0) (n : ℕ) : x ^ (n : ℝ) = x ^ n := nnreal.eq $ by simpa only [coe_rpow, coe_pow] using real.rpow_nat_cast x n +@[simp] lemma rpow_two (x : ℝ≥0) : x ^ (2 : ℝ) = x ^ 2 := +by { rw ← rpow_nat_cast, simp only [nat.cast_bit0, nat.cast_one] } + lemma mul_rpow {x y : ℝ≥0} {z : ℝ} : (x*y)^z = x^z * y^z := nnreal.eq $ real.mul_rpow x.2 y.2 @@ -1445,6 +1454,9 @@ begin { simp [coe_rpow_of_nonneg _ (nat.cast_nonneg n)] } end +@[simp] lemma rpow_two (x : ℝ≥0∞) : x ^ (2 : ℝ) = x ^ 2 := +by { rw ← rpow_nat_cast, simp only [nat.cast_bit0, nat.cast_one] } + lemma mul_rpow_eq_ite (x y : ℝ≥0∞) (z : ℝ) : (x * y) ^ z = if (x = 0 ∧ y = ⊤ ∨ x = ⊤ ∧ y = 0) ∧ z < 0 then ⊤ else x ^ z * y ^ z := begin diff --git a/src/analysis/specific_limits/basic.lean b/src/analysis/specific_limits/basic.lean index 9da442f36a75d..1753382c4a033 100644 --- a/src/analysis/specific_limits/basic.lean +++ b/src/analysis/specific_limits/basic.lean @@ -514,6 +514,10 @@ tendsto_of_tendsto_of_tendsto_of_le_of_le' section +lemma tendsto_nat_floor_at_top {α : Type*} [linear_ordered_semiring α] [floor_semiring α] : + tendsto (λ (x : α), ⌊x⌋₊) at_top at_top := +nat.floor_mono.tendsto_at_top_at_top (λ x, ⟨max 0 (x + 1), by simp [nat.le_floor_iff]⟩) + variables {R : Type*} [topological_space R] [linear_ordered_field R] [order_topology R] [floor_ring R] @@ -534,6 +538,10 @@ begin simp [nat.floor_le (mul_nonneg ha (zero_le_one.trans hx))] } end +lemma tendsto_nat_floor_div_at_top : + tendsto (λ x, (⌊x⌋₊ : R) / x) at_top (𝓝 1) := +by simpa using tendsto_nat_floor_mul_div_at_top (@zero_le_one R _) + lemma tendsto_nat_ceil_mul_div_at_top {a : R} (ha : 0 ≤ a) : tendsto (λ x, (⌈a * x⌉₊ : R) / x) at_top (𝓝 a) := begin @@ -549,4 +557,8 @@ begin (nat.ceil_lt_add_one ((mul_nonneg ha (zero_le_one.trans hx)))).le, add_mul] } end +lemma tendsto_nat_ceil_div_at_top : + tendsto (λ x, (⌈x⌉₊ : R) / x) at_top (𝓝 1) := +by simpa using tendsto_nat_ceil_mul_div_at_top (@zero_le_one R _) + end diff --git a/src/data/real/ennreal.lean b/src/data/real/ennreal.lean index 344c3bb088bc4..446b17bb3b5c3 100644 --- a/src/data/real/ennreal.lean +++ b/src/data/real/ennreal.lean @@ -224,6 +224,7 @@ protected lemma zero_lt_one : 0 < (1 : ℝ≥0∞) := @[simp] lemma one_lt_two : (1 : ℝ≥0∞) < 2 := coe_one ▸ coe_two ▸ by exact_mod_cast (@one_lt_two ℕ _ _) +lemma one_le_two : (1 : ℝ≥0∞) ≤ 2 := one_lt_two.le @[simp] lemma zero_lt_two : (0:ℝ≥0∞) < 2 := lt_trans ennreal.zero_lt_one one_lt_two lemma two_ne_zero : (2:ℝ≥0∞) ≠ 0 := (ne_of_lt zero_lt_two).symm lemma two_ne_top : (2:ℝ≥0∞) ≠ ∞ := coe_two ▸ coe_ne_top diff --git a/src/topology/algebra/group.lean b/src/topology/algebra/group.lean index 6321a138971f0..c966322f5f58c 100644 --- a/src/topology/algebra/group.lean +++ b/src/topology/algebra/group.lean @@ -894,6 +894,15 @@ lemma is_open_map_div_right (a : G) : is_open_map (λ x, x / a) := lemma is_closed_map_div_right (a : G) : is_closed_map (λ x, x / a) := (homeomorph.div_right a).is_closed_map +@[to_additive] +lemma tendsto_div_nhds_one_iff + {α : Type*} {l : filter α} {x : G} {u : α → G} : + tendsto (λ n, u n / x) l (𝓝 1) ↔ tendsto u l (𝓝 x) := +begin + have A : tendsto (λ (n : α), x) l (𝓝 x) := tendsto_const_nhds, + exact ⟨λ h, by simpa using h.mul A, λ h, by simpa using h.div' A⟩ +end + end div_in_topological_group @[to_additive] From fe2917a41611736870b2564aa41ca2bb4d1f8df0 Mon Sep 17 00:00:00 2001 From: Alex J Best Date: Fri, 29 Apr 2022 14:39:20 +0000 Subject: [PATCH 324/373] feat(number_theory/primes_congruent_one): attempt to golf (#13787) As suggested in the reviews of #12595 we try to golf the proof using the bound proved there. This doesn't end up being as much of a golf as hoped due to annoying edge cases, but seems conceptually simpler. --- archive/imo/imo2008_q3.lean | 2 +- src/number_theory/primes_congruent_one.lean | 51 +++++++++------------ 2 files changed, 23 insertions(+), 30 deletions(-) diff --git a/archive/imo/imo2008_q3.lean b/archive/imo/imo2008_q3.lean index 5c929bf992742..bed862662a60c 100644 --- a/archive/imo/imo2008_q3.lean +++ b/archive/imo/imo2008_q3.lean @@ -81,7 +81,7 @@ theorem imo2008_q3 : ∀ N : ℕ, ∃ n : ℕ, n ≥ N ∧ ∃ p : ℕ, nat.prime p ∧ p ∣ n ^ 2 + 1 ∧ (p : ℝ) > 2 * n + sqrt(2 * n) := begin intro N, - obtain ⟨p, hpp, hineq₁, hpmod4⟩ := nat.exists_prime_ge_modeq_one 4 (N ^ 2 + 21) zero_lt_four, + obtain ⟨p, hpp, hineq₁, hpmod4⟩ := nat.exists_prime_ge_modeq_one (N ^ 2 + 21) zero_lt_four, obtain ⟨n, hnat, hreal⟩ := p_lemma p hpp hpmod4 (by linarith [hineq₁, nat.zero_le (N ^ 2)]), have hineq₂ : n ^ 2 + 1 ≥ p := nat.le_of_dvd (n ^ 2).succ_pos hnat, diff --git a/src/number_theory/primes_congruent_one.lean b/src/number_theory/primes_congruent_one.lean index ebbb44cae95a0..213f45cc3b483 100644 --- a/src/number_theory/primes_congruent_one.lean +++ b/src/number_theory/primes_congruent_one.lean @@ -4,9 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Riccardo Brasca -/ -import ring_theory.polynomial.cyclotomic.basic -import topology.algebra.polynomial -import field_theory.finite.basic +import ring_theory.polynomial.cyclotomic.eval /-! # Primes congruent to one @@ -20,30 +18,25 @@ namespace nat open polynomial nat filter /-- For any positive `k : ℕ` there are infinitely many primes `p` such that `p ≡ 1 [MOD k]`. -/ -lemma exists_prime_ge_modeq_one (k n : ℕ) (hpos : 0 < k) : +lemma exists_prime_ge_modeq_one {k : ℕ} (n : ℕ) (hpos : 0 < k) : ∃ (p : ℕ), nat.prime p ∧ n ≤ p ∧ p ≡ 1 [MOD k] := begin - have hli : tendsto (abs ∘ (λ (a : ℕ), |(a : ℚ)|)) at_top at_top, - { simp only [(∘), abs_cast], - exact nat.strict_mono_cast.monotone.tendsto_at_top_at_top exists_nat_ge }, - have hcff : int.cast_ring_hom ℚ (cyclotomic k ℤ).leading_coeff ≠ 0, - { simp only [cyclotomic.monic, ring_hom.eq_int_cast, monic.leading_coeff, int.cast_one, ne.def, - not_false_iff, one_ne_zero] }, - obtain ⟨a, ha⟩ := tendsto_at_top_at_top.1 (tendsto_abv_eval₂_at_top (int.cast_ring_hom ℚ) - abs (cyclotomic k ℤ) (degree_cyclotomic_pos k ℤ hpos) hcff hli) 2, - let b := a * (k * n.factorial), - have hgt : 1 < (eval ↑(a * (k * n.factorial)) (cyclotomic k ℤ)).nat_abs, - { suffices hgtabs : 1 < |eval ↑b (cyclotomic k ℤ)|, - { rw [int.abs_eq_nat_abs] at hgtabs, - exact_mod_cast hgtabs }, - suffices hgtrat : 1 < |eval ↑b (cyclotomic k ℚ)|, - { rw [← map_cyclotomic_int k ℚ, ← int.cast_coe_nat, ← int.coe_cast_ring_hom, eval_map, - eval₂_hom, int.coe_cast_ring_hom] at hgtrat, - assumption_mod_cast }, - suffices hleab : a ≤ b, - { replace ha := lt_of_lt_of_le one_lt_two (ha b hleab), - rwa [← eval_map, map_cyclotomic_int k ℚ, abs_cast] at ha }, - exact le_mul_of_pos_right (mul_pos hpos (factorial_pos n)) }, + let b := 3 * (k * n.factorial), + have hgt : 1 < (eval ↑b (cyclotomic k ℤ)).nat_abs, + { have hkey : ∀ l : ℕ, 2 < 3 * (l.succ * n.factorial) := λ l, lt_mul_of_lt_of_one_le + (2 : ℕ).lt_succ_self (le_mul_of_le_of_le_one (nat.succ_pos _) n.factorial_pos), + rcases k with _ | _ | k, + { simpa using hpos, }, + { simp only [one_mul, int.coe_nat_mul, int.coe_nat_succ, int.coe_nat_zero, zero_add, + cyclotomic_one, eval_sub, eval_X, eval_one], + convert int.nat_abs_lt_nat_abs_of_nonneg_of_lt int.one_nonneg _, + rw lt_sub_iff_add_lt, + specialize hkey 0, + norm_cast, + rwa one_mul at hkey, }, + calc 1 ≤ _ : by { rw le_tsub_iff_left (one_le_two.trans (hkey _).le), exact (hkey _).le, } + ... < _ : sub_one_lt_nat_abs_cyclotomic_eval (one_lt_succ_succ k) + (one_lt_two.trans (hkey k.succ)).ne.symm, }, let p := min_fac (eval ↑b (cyclotomic k ℤ)).nat_abs, haveI hprime : fact p.prime := ⟨min_fac_prime (ne_of_lt hgt).symm⟩, have hroot : is_root (cyclotomic k (zmod p)) (cast_ring_hom (zmod p) b), @@ -67,16 +60,16 @@ begin exact ((modeq_iff_dvd' hprime.1.pos).2 hdiv).symm } end -lemma frequently_at_top_modeq_one (k : ℕ) (hpos : 0 < k) : +lemma frequently_at_top_modeq_one {k : ℕ} (hpos : 0 < k) : ∃ᶠ p in at_top, nat.prime p ∧ p ≡ 1 [MOD k] := begin refine frequently_at_top.2 (λ n, _), - obtain ⟨p, hp⟩ := exists_prime_ge_modeq_one k n hpos, + obtain ⟨p, hp⟩ := exists_prime_ge_modeq_one n hpos, exact ⟨p, ⟨hp.2.1, hp.1, hp.2.2⟩⟩ end -lemma infinite_set_of_prime_modeq_one (k : ℕ) (hpos : 0 < k) : +lemma infinite_set_of_prime_modeq_one {k : ℕ} (hpos : 0 < k) : set.infinite {p : ℕ | nat.prime p ∧ p ≡ 1 [MOD k]} := -frequently_at_top_iff_infinite.1 (frequently_at_top_modeq_one k hpos) +frequently_at_top_iff_infinite.1 (frequently_at_top_modeq_one hpos) end nat From 64b3576ff5bbac1387223e93988368644fcbcd7e Mon Sep 17 00:00:00 2001 From: Adam Topaz Date: Fri, 29 Apr 2022 15:58:59 +0000 Subject: [PATCH 325/373] feat(ring_theory/valuation/extend_to_localization): Extending valuations to localizations. (#13610) Co-authored-by: Junyan Xu --- src/ring_theory/valuation/basic.lean | 4 ++ .../valuation/extend_to_localization.lean | 49 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 src/ring_theory/valuation/extend_to_localization.lean diff --git a/src/ring_theory/valuation/basic.lean b/src/ring_theory/valuation/basic.lean index db6116e59e3ad..bb11122d6cee0 100644 --- a/src/ring_theory/valuation/basic.lean +++ b/src/ring_theory/valuation/basic.lean @@ -181,6 +181,10 @@ def comap {S : Type*} [ring S] (f : S →+* R) (v : valuation R Γ₀) : map_add_le_max' := λ x y, by simp only [comp_app, map_add, f.map_add], .. v.to_monoid_with_zero_hom.comp f.to_monoid_with_zero_hom, } +@[simp] +lemma comap_apply {S : Type*} [ring S] (f : S →+* R) (v : valuation R Γ₀) (s : S) : + v.comap f s = v (f s) := rfl + @[simp] lemma comap_id : v.comap (ring_hom.id R) = v := ext $ λ r, rfl lemma comap_comp {S₁ : Type*} {S₂ : Type*} [ring S₁] [ring S₂] (f : S₁ →+* S₂) (g : S₂ →+* R) : diff --git a/src/ring_theory/valuation/extend_to_localization.lean b/src/ring_theory/valuation/extend_to_localization.lean new file mode 100644 index 0000000000000..03c7c8674849d --- /dev/null +++ b/src/ring_theory/valuation/extend_to_localization.lean @@ -0,0 +1,49 @@ +/- +Copyright (c) 2022 Adam Topaz. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adam Topaz +-/ +import ring_theory.localization.at_prime +import ring_theory.valuation.basic + +/-! + +# Extending valuations to a localization + +We show that, given a valuation `v` taking values in a linearly ordered commutative *group* +with zero `Γ`, and a submonoid `S` of `v.supp.prime_compl`, the valuation `v` can be naturally +extended to the localization `S⁻¹A`. + +-/ + +variables + {A : Type*} [comm_ring A] + {Γ : Type*} [linear_ordered_comm_group_with_zero Γ] (v : valuation A Γ) + {S : submonoid A} (hS : S ≤ v.supp.prime_compl) + (B : Type*) [comm_ring B] [algebra A B] [is_localization S B] + +/-- We can extend a valuation `v` on a ring to a localization at a submonoid of +the complement of `v.supp`. -/ +noncomputable +def valuation.extend_to_localization : valuation B Γ := +let f := is_localization.to_localization_map S B, + h : ∀ s : S, is_unit (v.1.to_monoid_hom s) := λ s, is_unit_iff_ne_zero.2 (hS s.2) in +{ map_zero' := by convert f.lift_eq _ 0; simp, + map_add_le_max' := λ x y, begin + obtain ⟨a,b,s,rfl,rfl⟩ : ∃ (a b : A) (s : S), f.mk' a s = x ∧ f.mk' b s = y, + { obtain ⟨a,s,rfl⟩ := f.mk'_surjective x, + obtain ⟨b,t,rfl⟩ := f.mk'_surjective y, + use [a * t, b * s, s * t], split; + { rw [f.mk'_eq_iff_eq, submonoid.coe_mul], ring_nf } }, + convert_to f.lift h (f.mk' (a+b) s) ≤ max (f.lift h _) (f.lift h _), + { refine congr_arg (f.lift h) (is_localization.eq_mk'_iff_mul_eq.2 _), + rw [add_mul, map_add], iterate 2 { erw is_localization.mk'_spec } }, + iterate 3 { rw f.lift_mk' }, rw max_mul_mul_right, + apply mul_le_mul_right' (v.map_add a b), + end, +..f.lift h } + +@[simp] +lemma valuation.extend_to_localization_apply_map_apply (a : A) : + v.extend_to_localization hS B (algebra_map A B a) = v a := +submonoid.localization_map.lift_eq _ _ a From 50c30283a05ef81505edddaa01c4cf30a89e1005 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Fri, 29 Apr 2022 15:59:00 +0000 Subject: [PATCH 326/373] chore(analysis/normed_space/operator_norm): move `continuous_linear_map.op_norm_lsmul` into the correct section (#13790) This was in the "seminorm" section but was about regular norms. Also relaxes some other typeclasses in the file. This file is still a mess with regards to assuming `nondiscrete_normed_field` when `normed_field` is enough, but that would require substantially more movement within the file. This cleans up after #13165 and #13538 --- src/analysis/normed_space/operator_norm.lean | 58 ++++++++++++-------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/src/analysis/normed_space/operator_norm.lean b/src/analysis/normed_space/operator_norm.lean index 032ef50f35ea3..8f0a962823a4d 100644 --- a/src/analysis/normed_space/operator_norm.lean +++ b/src/analysis/normed_space/operator_norm.lean @@ -215,7 +215,7 @@ lemma to_span_singleton_add (x y : E) : to_span_singleton 𝕜 (x + y) = to_span_singleton 𝕜 x + to_span_singleton 𝕜 y := by { ext1, simp [to_span_singleton_apply], } -lemma to_span_singleton_smul' (𝕜') [nondiscrete_normed_field 𝕜'] [normed_space 𝕜' E] +lemma to_span_singleton_smul' (𝕜') [normed_field 𝕜'] [normed_space 𝕜' E] [smul_comm_class 𝕜 𝕜' E] (c : 𝕜') (x : E) : to_span_singleton 𝕜 (c • x) = c • to_span_singleton 𝕜 x := by { ext1, rw [to_span_singleton_apply, smul_apply, to_span_singleton_apply, smul_comm], } @@ -731,11 +731,13 @@ def compL : (Fₗ →L[𝕜] Gₗ) →L[𝕜] (E →L[𝕜] Fₗ) →L[𝕜] (E @[simp] lemma compL_apply (f : Fₗ →L[𝕜] Gₗ) (g : E →L[𝕜] Fₗ) : compL 𝕜 E Fₗ Gₗ f g = f.comp g := rfl +section prod + universes u₁ u₂ u₃ u₄ -variables (M₁ : Type u₁) [normed_group M₁] [normed_space 𝕜 M₁] - (M₂ : Type u₂) [normed_group M₂] [normed_space 𝕜 M₂] - (M₃ : Type u₃) [normed_group M₃] [normed_space 𝕜 M₃] - (M₄ : Type u₄) [normed_group M₄] [normed_space 𝕜 M₄] +variables (M₁ : Type u₁) [semi_normed_group M₁] [normed_space 𝕜 M₁] + (M₂ : Type u₂) [semi_normed_group M₂] [normed_space 𝕜 M₂] + (M₃ : Type u₃) [semi_normed_group M₃] [normed_space 𝕜 M₃] + (M₄ : Type u₄) [semi_normed_group M₄] [normed_space 𝕜 M₄] /-- `continuous_linear_map.prod_map` as a continuous linear map. -/ def prod_mapL : ((M₁ →L[𝕜] M₂) × (M₃ →L[𝕜] M₄)) →L[𝕜] ((M₁ × M₃) →L[𝕜] (M₂ × M₄)) := @@ -792,6 +794,8 @@ lemma _root_.continuous_on.prod_map_equivL {f : X → M₁ ≃L[𝕜] M₂} {g : continuous_on (λ x, ((f x).prod (g x) : M₁ × M₃ →L[𝕜] M₂ × M₄)) s := (prod_mapL 𝕜 M₁ M₂ M₃ M₄).continuous.comp_continuous_on (hf.prod hg) +end prod + variables {𝕜 E Fₗ Gₗ} section multiplication_linear @@ -870,7 +874,6 @@ section smul_linear variables (𝕜) (𝕜' : Type*) [normed_field 𝕜'] [normed_algebra 𝕜 𝕜'] [normed_space 𝕜' E] [is_scalar_tower 𝕜 𝕜' E] - [normed_space 𝕜' M₁] [is_scalar_tower 𝕜 𝕜' M₁] /-- Scalar multiplication as a continuous bilinear map. -/ def lsmul : 𝕜' →L[𝕜] E →L[𝕜] E := @@ -892,27 +895,15 @@ end variables {𝕜} +lemma op_norm_lsmul_apply_le (x : 𝕜') : ∥(lsmul 𝕜 𝕜' x : E →L[𝕜] E)∥ ≤ ∥x∥ := +continuous_linear_map.op_norm_le_bound _ (norm_nonneg x) $ λ y, (norm_smul x y).le + /-- The norm of `lsmul` is at most 1 in any semi-normed group. -/ lemma op_norm_lsmul_le : ∥(lsmul 𝕜 𝕜' : 𝕜' →L[𝕜] E →L[𝕜] E)∥ ≤ 1 := begin refine continuous_linear_map.op_norm_le_bound _ zero_le_one (λ x, _), simp_rw [one_mul], - refine continuous_linear_map.op_norm_le_bound _ (norm_nonneg x) (λ y, _), - simp_rw [lsmul_apply, norm_smul], -end - -/-- The norm of `lsmul` equals 1 in any nontrivial normed group. -/ -@[simp] lemma op_norm_lsmul [nontrivial M₁] : ∥(lsmul 𝕜 𝕜' : 𝕜' →L[𝕜] M₁ →L[𝕜] M₁)∥ = 1 := -begin - refine continuous_linear_map.op_norm_eq_of_bounds zero_le_one (λ x, _) (λ N hN h, _), - { simp_rw [one_mul], - refine continuous_linear_map.op_norm_le_bound _ (norm_nonneg x) (λ y, _), - simp_rw [lsmul_apply, norm_smul] }, - obtain ⟨y, hy⟩ := exists_ne (0 : M₁), - have := le_of_op_norm_le _ (h 1) y, - simp_rw [lsmul_apply, one_smul, norm_one, mul_one] at this, - refine le_of_mul_le_mul_right _ (norm_pos_iff.mpr hy), - simp_rw [one_mul, this] + exact op_norm_lsmul_apply_le _, end end smul_linear @@ -1612,13 +1603,34 @@ norm_smul_right_apply c f ∥smul_rightL 𝕜 E Fₗ c∥ = ∥c∥ := continuous_linear_map.homothety_norm _ c.norm_smul_right_apply -variables (𝕜) (𝕜' : Type*) [normed_ring 𝕜'] [normed_algebra 𝕜 𝕜'] +variables (𝕜) (𝕜' : Type*) + +section +variables [normed_ring 𝕜'] [normed_algebra 𝕜 𝕜'] @[simp] lemma op_norm_lmul [norm_one_class 𝕜'] : ∥lmul 𝕜 𝕜'∥ = 1 := by haveI := norm_one_class.nontrivial 𝕜'; exact (lmulₗᵢ 𝕜 𝕜').norm_to_continuous_linear_map @[simp] lemma op_norm_lmul_right [norm_one_class 𝕜'] : ∥lmul_right 𝕜 𝕜'∥ = 1 := (op_norm_flip (@lmul 𝕜 _ 𝕜' _ _)).trans (op_norm_lmul _ _) +end + +/-- The norm of `lsmul` equals 1 in any nontrivial normed group. + +This is `continuous_linear_map.op_norm_lsmul_le` as an equality. -/ +@[simp] lemma op_norm_lsmul [normed_field 𝕜'] [normed_algebra 𝕜 𝕜'] + [normed_space 𝕜' E] [is_scalar_tower 𝕜 𝕜' E] [nontrivial E] : + ∥(lsmul 𝕜 𝕜' : 𝕜' →L[𝕜] E →L[𝕜] E)∥ = 1 := +begin + refine continuous_linear_map.op_norm_eq_of_bounds zero_le_one (λ x, _) (λ N hN h, _), + { rw one_mul, + exact op_norm_lsmul_apply_le _, }, + obtain ⟨y, hy⟩ := exists_ne (0 : E), + have := le_of_op_norm_le _ (h 1) y, + simp_rw [lsmul_apply, one_smul, norm_one, mul_one] at this, + refine le_of_mul_le_mul_right _ (norm_pos_iff.mpr hy), + simp_rw [one_mul, this] +end end continuous_linear_map From 8360f2c87767a49d4e34b9325b9bb9d609d902b6 Mon Sep 17 00:00:00 2001 From: Aaron Anderson Date: Fri, 29 Apr 2022 17:28:03 +0000 Subject: [PATCH 327/373] feat(model_theory/language_map, bundled): Reducts of structures (#13745) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Defines `first_order.language.Lhom.reduct` which pulls a structure back along a language map. Defines `first_order.language.Theory.Model.reduct` which sends a model of `(φ.on_Theory T)` to its reduct as a model of `T`. --- src/model_theory/bundled.lean | 8 ++++++++ src/model_theory/language_map.lean | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/model_theory/bundled.lean b/src/model_theory/bundled.lean index 85d48a2a09cee..a9c09ee89b1f2 100644 --- a/src/model_theory/bundled.lean +++ b/src/model_theory/bundled.lean @@ -91,6 +91,14 @@ noncomputable def shrink (M : Model.{u v w} T) [small.{w'} M] : def ulift (M : Model.{u v w} T) : Model.{u v (max w w')} T := equiv_induced (equiv.ulift.symm : M ≃ _) +/-- The reduct of any model of `φ.on_Theory T` is a model of `T`. -/ +@[simps] def reduct {L' : language} {φ : L →ᴸ L'} (M : (φ.on_Theory T).Model) : + T.Model := +{ carrier := M, + struc := φ.reduct M, + nonempty' := M.nonempty', + is_model := (@Lhom.on_Theory_model L L' M (φ.reduct M) _ φ _ T).1 M.is_model, } + end Model variables {T} diff --git a/src/model_theory/language_map.lean b/src/model_theory/language_map.lean index 3e5fadf355954..966687335630f 100644 --- a/src/model_theory/language_map.lean +++ b/src/model_theory/language_map.lean @@ -57,6 +57,11 @@ protected def mk₂ {c f₁ f₂ : Type u} {r₁ r₂ : Type v} variables (ϕ : L →ᴸ L') +/-- Pulls a structure back along a language map. -/ +def reduct (M : Type*) [L'.Structure M] : L.Structure M := +{ fun_map := λ n f xs, fun_map (ϕ.on_function f) xs, + rel_map := λ n r xs, rel_map (ϕ.on_relation r) xs } + /-- The identity language homomorphism. -/ @[simps] protected def id (L : language) : L →ᴸ L := ⟨λn, id, λ n, id⟩ @@ -205,6 +210,13 @@ instance sum_inr_is_expansion_on (M : Type*) (Lhom.sum_inr : L' →ᴸ L.sum L').is_expansion_on M := ⟨λ _ f _, rfl, λ _ R _, rfl⟩ +@[priority 100] instance is_expansion_on_reduct (ϕ : L →ᴸ L') (M : Type*) [L'.Structure M] : + @is_expansion_on L L' ϕ M (ϕ.reduct M) _ := +begin + letI := ϕ.reduct M, + exact ⟨λ _ f _, rfl, λ _ R _, rfl⟩, +end + end Lhom /-- A language equivalence maps the symbols of one language to symbols of another bijectively. -/ From 8624f6db6b62d239668a60164de8fa0d543636e9 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Fri, 29 Apr 2022 17:28:05 +0000 Subject: [PATCH 328/373] chore(analysis/normed/group/basic): add `nnnorm_sum_le_of_le` (#13795) This is to match `norm_sum_le_of_le`. Also tidies up the coercion syntax a little in `pi.semi_normed_group`. The definition is syntactically identical, just with fewer unecessary type annotations. --- src/analysis/normed/group/basic.lean | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/analysis/normed/group/basic.lean b/src/analysis/normed/group/basic.lean index a34f62164d5dc..74e8c2f33785e 100644 --- a/src/analysis/normed/group/basic.lean +++ b/src/analysis/normed/group/basic.lean @@ -641,6 +641,10 @@ lemma nnnorm_sum_le (s : finset ι) (f : ι → E) : ∥∑ a in s, f a∥₊ ≤ ∑ a in s, ∥f a∥₊ := s.le_sum_of_subadditive nnnorm nnnorm_zero nnnorm_add_le f +lemma nnnorm_sum_le_of_le (s : finset ι) {f : ι → E} {n : ι → ℝ≥0} (h : ∀ b ∈ s, ∥f b∥₊ ≤ n b) : + ∥∑ b in s, f b∥₊ ≤ ∑ b in s, n b := +(norm_sum_le_of_le s h).trans_eq nnreal.coe_sum.symm + lemma add_monoid_hom.lipschitz_of_bound_nnnorm (f : E →+ F) (C : ℝ≥0) (h : ∀ x, ∥f x∥₊ ≤ C * ∥x∥₊) : lipschitz_with C f := @real.to_nnreal_coe C ▸ f.lipschitz_of_bound C h @@ -783,7 +787,7 @@ max_le_iff using the sup norm. -/ noncomputable instance pi.semi_normed_group {π : ι → Type*} [fintype ι] [Π i, semi_normed_group (π i)] : semi_normed_group (Π i, π i) := -{ norm := λf, ((finset.sup finset.univ (λ b, ∥f b∥₊) : ℝ≥0) : ℝ), +{ norm := λ f, ↑(finset.univ.sup (λ b, ∥f b∥₊)), dist_eq := assume x y, congr_arg (coe : ℝ≥0 → ℝ) $ congr_arg (finset.sup finset.univ) $ funext $ assume a, show nndist (x a) (y a) = ∥x a - y a∥₊, from nndist_eq_nnnorm _ _ } From a54db9a4d12d6a89158d6cac037bfc5738ff5b47 Mon Sep 17 00:00:00 2001 From: Aaron Anderson Date: Fri, 29 Apr 2022 18:38:48 +0000 Subject: [PATCH 329/373] feat(data/finset/basic): A finset that's a subset of a `directed` union is contained in one element (#13727) Proves `directed.exists_mem_subset_of_finset_subset_bUnion` Renames `finset.exists_mem_subset_of_subset_bUnion_of_directed_on` to `directed_on.exists_mem_subset_of_finset_subset_bUnion` --- src/data/finset/basic.lean | 30 ++++++++++++++-------- src/linear_algebra/linear_independent.lean | 4 +-- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/data/finset/basic.lean b/src/data/finset/basic.lean index 6d97192ef9ea4..093d89db59223 100644 --- a/src/data/finset/basic.lean +++ b/src/data/finset/basic.lean @@ -835,27 +835,37 @@ begin exact union_of singletons (symm hi), end -lemma exists_mem_subset_of_subset_bUnion_of_directed_on {α ι : Type*} - {f : ι → set α} {c : set ι} {a : ι} (hac : a ∈ c) (hc : directed_on (λ i j, f i ⊆ f j) c) - {s : finset α} (hs : (s : set α) ⊆ ⋃ i ∈ c, f i) : ∃ i ∈ c, (s : set α) ⊆ f i := +lemma _root_.directed.exists_mem_subset_of_finset_subset_bUnion {α ι : Type*} [hn : nonempty ι] + {f : ι → set α} (h : directed (⊆) f) + {s : finset α} (hs : (s : set α) ⊆ ⋃ i, f i) : ∃ i, (s : set α) ⊆ f i := begin classical, revert hs, apply s.induction_on, - { intros, - use [a, hac], - simp }, + { refine λ _, ⟨hn.some, _⟩, + simp only [coe_empty, set.empty_subset], }, { intros b t hbt htc hbtc, - obtain ⟨i : ι , hic : i ∈ c, hti : (t : set α) ⊆ f i⟩ := + obtain ⟨i : ι , hti : (t : set α) ⊆ f i⟩ := htc (set.subset.trans (t.subset_insert b) hbtc), - obtain ⟨j, hjc, hbj⟩ : ∃ j ∈ c, b ∈ f j, + obtain ⟨j, hbj⟩ : ∃ j, b ∈ f j, by simpa [set.mem_Union₂] using hbtc (t.mem_insert_self b), - rcases hc j hjc i hic with ⟨k, hkc, hk, hk'⟩, - use [k, hkc], + rcases h j i with ⟨k, hk, hk'⟩, + use k, rw [coe_insert, set.insert_subset], exact ⟨hk hbj, trans hti hk'⟩ } end +lemma _root_.directed_on.exists_mem_subset_of_finset_subset_bUnion {α ι : Type*} + {f : ι → set α} {c : set ι} (hn : c.nonempty) (hc : directed_on (λ i j, f i ⊆ f j) c) + {s : finset α} (hs : (s : set α) ⊆ ⋃ i ∈ c, f i) : ∃ i ∈ c, (s : set α) ⊆ f i := +begin + rw set.bUnion_eq_Union at hs, + haveI := c.nonempty_coe_sort.2 hn, + obtain ⟨⟨i, hic⟩, hi⟩ := + (directed_comp.2 hc.directed_coe).exists_mem_subset_of_finset_subset_bUnion hs, + exact ⟨i, hic, hi⟩ +end + /-! #### inter -/ theorem inter_val_nd (s₁ s₂ : finset α) : (s₁ ∩ s₂).1 = ndinter s₁.1 s₂.1 := rfl diff --git a/src/linear_algebra/linear_independent.lean b/src/linear_algebra/linear_independent.lean index a680248b08521..6909aa5e94a1d 100644 --- a/src/linear_algebra/linear_independent.lean +++ b/src/linear_algebra/linear_independent.lean @@ -811,11 +811,11 @@ begin dsimp [indep], rw [linear_independent_comp_subtype], intros f hsupport hsum, - rcases eq_empty_or_nonempty c with rfl | ⟨a, hac⟩, + rcases eq_empty_or_nonempty c with rfl | hn, { simpa using hsupport }, haveI : is_refl X r := ⟨λ _, set.subset.refl _⟩, obtain ⟨I, I_mem, hI⟩ : ∃ I ∈ c, (f.support : set ι) ⊆ I := - finset.exists_mem_subset_of_subset_bUnion_of_directed_on hac hc.directed_on hsupport, + hc.directed_on.exists_mem_subset_of_finset_subset_bUnion hn hsupport, exact linear_independent_comp_subtype.mp I.2 f hI hsum }, have trans : transitive r := λ I J K, set.subset.trans, obtain ⟨⟨I, hli : indep I⟩, hmax : ∀ a, r ⟨I, hli⟩ a → r a ⟨I, hli⟩⟩ := From 812e17f8de2ad3b199d0deb315278ea4267f246c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Fri, 29 Apr 2022 20:31:19 +0000 Subject: [PATCH 330/373] feat(analysis/normed_space/pointwise): Addition of balls (#13381) Adding two balls yields another ball. --- src/analysis/normed/group/basic.lean | 10 +- src/analysis/normed/group/pointwise.lean | 150 +++++++++++++++++----- src/analysis/normed_space/pointwise.lean | 62 +++++++-- src/data/set/pointwise.lean | 2 +- src/measure_theory/function/jacobian.lean | 2 +- 5 files changed, 175 insertions(+), 51 deletions(-) diff --git a/src/analysis/normed/group/basic.lean b/src/analysis/normed/group/basic.lean index 74e8c2f33785e..fe3da3b684567 100644 --- a/src/analysis/normed/group/basic.lean +++ b/src/analysis/normed/group/basic.lean @@ -143,8 +143,10 @@ by simp [dist_eq_norm] @[simp] lemma dist_add_right (g₁ g₂ h : E) : dist (g₁ + h) (g₂ + h) = dist g₁ g₂ := by simp [dist_eq_norm] -@[simp] lemma dist_neg_neg (g h : E) : dist (-g) (-h) = dist g h := -by simp only [dist_eq_norm, neg_sub_neg, norm_sub_rev] +lemma dist_neg (x y : E) : dist (-x) y = dist x (-y) := +by simp_rw [dist_eq_norm, ←norm_neg (-x - y), neg_sub, sub_neg_eq_add, add_comm] + +@[simp] lemma dist_neg_neg (g h : E) : dist (-g) (-h) = dist g h := by rw [dist_neg, neg_neg] @[simp] lemma dist_sub_left (g h₁ h₂ : E) : dist (g - h₁) (g - h₂) = dist h₁ h₂ := by simp only [sub_eq_add_neg, dist_add_left, dist_neg_neg] @@ -628,8 +630,8 @@ by simp [edist_dist] @[simp] lemma edist_add_right (g₁ g₂ h : E) : edist (g₁ + h) (g₂ + h) = edist g₁ g₂ := by simp [edist_dist] -@[simp] lemma edist_neg_neg (x y : E) : edist (-x) (-y) = edist x y := -by rw [edist_dist, dist_neg_neg, edist_dist] +lemma edist_neg (x y : E) : edist (-x) y = edist x (-y) := by simp_rw [edist_dist, dist_neg] +@[simp] lemma edist_neg_neg (x y : E) : edist (-x) (-y) = edist x y := by rw [edist_neg, neg_neg] @[simp] lemma edist_sub_left (g h₁ h₂ : E) : edist (g - h₁) (g - h₂) = edist h₁ h₂ := by simp only [sub_eq_add_neg, edist_add_left, edist_neg_neg] diff --git a/src/analysis/normed/group/pointwise.lean b/src/analysis/normed/group/pointwise.lean index 33a11f7bf38a9..d355e95c1835c 100644 --- a/src/analysis/normed/group/pointwise.lean +++ b/src/analysis/normed/group/pointwise.lean @@ -3,11 +3,11 @@ Copyright (c) 2021 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ -import analysis.normed.group.basic +import analysis.normed.group.add_torsor import topology.metric_space.hausdorff_distance /-! -# Properties of pointwise addition of sets in normed groups. +# Properties of pointwise addition of sets in normed groups We explore the relationships between pointwise addition of sets in normed groups, and the norm. Notably, we show that the sum of bounded sets remain bounded. @@ -18,16 +18,14 @@ open_locale pointwise topological_space section semi_normed_group -variables {E : Type*} [semi_normed_group E] +variables {E : Type*} [semi_normed_group E] {ε δ : ℝ} {s t : set E} {x y : E} -lemma bounded_iff_exists_norm_le {s : set E} : - bounded s ↔ ∃ R, ∀ x ∈ s, ∥x∥ ≤ R := +lemma bounded_iff_exists_norm_le : bounded s ↔ ∃ R, ∀ x ∈ s, ∥x∥ ≤ R := by simp [subset_def, bounded_iff_subset_ball (0 : E)] alias bounded_iff_exists_norm_le ↔ metric.bounded.exists_norm_le _ -lemma metric.bounded.exists_pos_norm_le {s : set E} (hs : metric.bounded s) : - ∃ R > 0, ∀ x ∈ s, ∥x∥ ≤ R := +lemma metric.bounded.exists_pos_norm_le (hs : metric.bounded s) : ∃ R > 0, ∀ x ∈ s, ∥x∥ ≤ R := begin obtain ⟨R₀, hR₀⟩ := hs.exists_norm_le, refine ⟨max R₀ 1, _, _⟩, @@ -36,9 +34,7 @@ begin exact (hR₀ x hx).trans (le_max_left _ _), end -lemma metric.bounded.add - {s t : set E} (hs : bounded s) (ht : bounded t) : - bounded (s + t) := +lemma metric.bounded.add (hs : bounded s) (ht : bounded t) : bounded (s + t) := begin obtain ⟨Rs, hRs⟩ : ∃ (R : ℝ), ∀ x ∈ s, ∥x∥ ≤ R := hs.exists_norm_le, obtain ⟨Rt, hRt⟩ : ∃ (R : ℝ), ∀ x ∈ t, ∥x∥ ≤ R := ht.exists_norm_le, @@ -48,46 +44,130 @@ begin ... ≤ Rs + Rt : add_le_add (hRs x hx) (hRt y hy) end -@[simp] lemma singleton_add_ball (x y : E) (r : ℝ) : - {x} + ball y r = ball (x + y) r := +lemma metric.bounded.neg : bounded s → bounded (-s) := +by { simp_rw [bounded_iff_exists_norm_le, ←image_neg, ball_image_iff, norm_neg], exact id } + +lemma metric.bounded.sub (hs : bounded s) (ht : bounded t) : bounded (s - t) := +(sub_eq_add_neg _ _).symm.subst $ hs.add ht.neg + +section emetric +open emetric + +lemma inf_edist_neg (x : E) (s : set E) : inf_edist (-x) s = inf_edist x (-s) := +eq_of_forall_le_iff $ λ r, by simp_rw [le_inf_edist, ←image_neg, ball_image_iff, edist_neg] + +@[simp] lemma inf_edist_neg_neg (x : E) (s : set E) : inf_edist (-x) (-s) = inf_edist x s := +by rw [inf_edist_neg, neg_neg] + +end emetric + +variables (ε δ s t x y) + +@[simp] lemma neg_thickening : -thickening δ s = thickening δ (-s) := +by { unfold thickening, simp_rw ←inf_edist_neg, refl } + +@[simp] lemma neg_cthickening : -cthickening δ s = cthickening δ (-s) := +by { unfold cthickening, simp_rw ←inf_edist_neg, refl } + +@[simp] lemma neg_ball : -ball x δ = ball (-x) δ := +by { unfold metric.ball, simp_rw ←dist_neg, refl } + +@[simp] lemma neg_closed_ball : -closed_ball x δ = closed_ball (-x) δ := +by { unfold metric.closed_ball, simp_rw ←dist_neg, refl } + +lemma singleton_add_ball : {x} + ball y δ = ball (x + y) δ := by simp only [preimage_add_ball, image_add_left, singleton_add, sub_neg_eq_add, add_comm y x] -@[simp] lemma ball_add_singleton (x y : E) (r : ℝ) : - ball x r + {y} = ball (x + y) r := -by simp [add_comm _ {y}, add_comm y] +lemma singleton_sub_ball : {x} - ball y δ = ball (x - y) δ := +by simp_rw [sub_eq_add_neg, neg_ball, singleton_add_ball] + +lemma ball_add_singleton : ball x δ + {y} = ball (x + y) δ := +by rw [add_comm, singleton_add_ball, add_comm y] -lemma singleton_add_ball_zero (x : E) (r : ℝ) : - {x} + ball 0 r = ball x r := -by simp +lemma ball_sub_singleton : ball x δ - {y} = ball (x - y) δ := +by simp_rw [sub_eq_add_neg, neg_singleton, ball_add_singleton] -lemma ball_zero_add_singleton (x : E) (r : ℝ) : - ball 0 r + {x} = ball x r := -by simp +lemma singleton_add_ball_zero : {x} + ball 0 δ = ball x δ := by simp +lemma singleton_sub_ball_zero : {x} - ball 0 δ = ball x δ := by simp [singleton_sub_ball] +lemma ball_zero_add_singleton : ball 0 δ + {x} = ball x δ := by simp [ball_add_singleton] +lemma ball_zero_sub_singleton : ball 0 δ - {x} = ball (-x) δ := by simp [ball_sub_singleton] +lemma vadd_ball_zero : x +ᵥ ball 0 δ = ball x δ := by simp -@[simp] lemma singleton_add_closed_ball (x y : E) (r : ℝ) : - {x} + closed_ball y r = closed_ball (x + y) r := +@[simp] lemma singleton_add_closed_ball : {x} + closed_ball y δ = closed_ball (x + y) δ := by simp only [add_comm y x, preimage_add_closed_ball, image_add_left, singleton_add, sub_neg_eq_add] -@[simp] lemma closed_ball_add_singleton (x y : E) (r : ℝ) : - closed_ball x r + {y} = closed_ball (x + y) r := +@[simp] lemma singleton_sub_closed_ball : {x} - closed_ball y δ = closed_ball (x - y) δ := +by simp_rw [sub_eq_add_neg, neg_closed_ball, singleton_add_closed_ball] + +@[simp] lemma closed_ball_add_singleton : closed_ball x δ + {y} = closed_ball (x + y) δ := by simp [add_comm _ {y}, add_comm y] -lemma singleton_add_closed_ball_zero (x : E) (r : ℝ) : - {x} + closed_ball 0 r = closed_ball x r := -by simp +@[simp] lemma closed_ball_sub_singleton : closed_ball x δ - {y} = closed_ball (x - y) δ := +by simp [sub_eq_add_neg] -lemma closed_ball_zero_add_singleton (x : E) (r : ℝ) : - closed_ball 0 r + {x} = closed_ball x r := -by simp +lemma singleton_add_closed_ball_zero : {x} + closed_ball 0 δ = closed_ball x δ := by simp +lemma singleton_sub_closed_ball_zero : {x} - closed_ball 0 δ = closed_ball x δ := by simp +lemma closed_ball_zero_add_singleton : closed_ball 0 δ + {x} = closed_ball x δ := by simp +lemma closed_ball_zero_sub_singleton : closed_ball 0 δ - {x} = closed_ball (-x) δ := by simp +@[simp] lemma vadd_closed_ball_zero : x +ᵥ closed_ball 0 δ = closed_ball x δ := by simp -lemma is_compact.cthickening_eq_add_closed_ball - {s : set E} (hs : is_compact s) {r : ℝ} (hr : 0 ≤ r) : - cthickening r s = s + closed_ball 0 r := +lemma add_ball_zero : s + ball 0 δ = thickening δ s := begin - rw hs.cthickening_eq_bUnion_closed_ball hr, + rw thickening_eq_bUnion_ball, + convert Union₂_add (λ x (_ : x ∈ s), {x}) (ball (0 : E) δ), + exact s.bUnion_of_singleton.symm, + ext x y, + simp_rw [singleton_add_ball, add_zero], +end + +lemma sub_ball_zero : s - ball 0 δ = thickening δ s := by simp [sub_eq_add_neg, add_ball_zero] +lemma ball_add_zero : ball 0 δ + s = thickening δ s := by rw [add_comm, add_ball_zero] +lemma ball_sub_zero : ball 0 δ - s = thickening δ (-s) := by simp [sub_eq_add_neg, ball_add_zero] + +@[simp] lemma add_ball : s + ball x δ = x +ᵥ thickening δ s := +by rw [←vadd_ball_zero, add_vadd_comm, add_ball_zero] + +@[simp] lemma sub_ball : s - ball x δ = -x +ᵥ thickening δ s := by simp [sub_eq_add_neg] +@[simp] lemma ball_add : ball x δ + s = x +ᵥ thickening δ s := by rw [add_comm, add_ball] +@[simp] lemma ball_sub : ball x δ - s = x +ᵥ thickening δ (-s) := by simp [sub_eq_add_neg] + +variables {ε δ s t x y} + +lemma is_compact.add_closed_ball_zero (hs : is_compact s) (hδ : 0 ≤ δ) : + s + closed_ball 0 δ = cthickening δ s := +begin + rw hs.cthickening_eq_bUnion_closed_ball hδ, ext x, simp only [mem_add, dist_eq_norm, exists_prop, mem_Union, mem_closed_ball, exists_and_distrib_left, mem_closed_ball_zero_iff, ← eq_sub_iff_add_eq', exists_eq_right], end +lemma is_compact.sub_closed_ball_zero (hs : is_compact s) (hδ : 0 ≤ δ) : + s - closed_ball 0 δ = cthickening δ s := +by simp [sub_eq_add_neg, hs.add_closed_ball_zero hδ] + +lemma is_compact.closed_ball_zero_add (hs : is_compact s) (hδ : 0 ≤ δ) : + closed_ball 0 δ + s = cthickening δ s := +by rw [add_comm, hs.add_closed_ball_zero hδ] + +lemma is_compact.closed_ball_zero_sub (hs : is_compact s) (hδ : 0 ≤ δ) : + closed_ball 0 δ - s = cthickening δ (-s) := +by simp [sub_eq_add_neg, add_comm, hs.neg.add_closed_ball_zero hδ] + +lemma is_compact.add_closed_ball (hs : is_compact s) (hδ : 0 ≤ δ) (x : E) : + s + closed_ball x δ = x +ᵥ cthickening δ s := +by rw [←vadd_closed_ball_zero, add_vadd_comm, hs.add_closed_ball_zero hδ] + +lemma is_compact.sub_closed_ball (hs : is_compact s) (hδ : 0 ≤ δ) (x : E) : + s - closed_ball x δ = -x +ᵥ cthickening δ s := +by simp [sub_eq_add_neg, add_comm, hs.add_closed_ball hδ] + +lemma is_compact.closed_ball_add (hs : is_compact s) (hδ : 0 ≤ δ) (x : E) : + closed_ball x δ + s = x +ᵥ cthickening δ s := +by rw [add_comm, hs.add_closed_ball hδ] + +lemma is_compact.closed_ball_sub (hs : is_compact s) (hδ : 0 ≤ δ) (x : E) : + closed_ball x δ + s = x +ᵥ cthickening δ s := +by simp [sub_eq_add_neg, add_comm, hs.closed_ball_add hδ] + end semi_normed_group diff --git a/src/analysis/normed_space/pointwise.lean b/src/analysis/normed_space/pointwise.lean index 23d089324c0e8..7d755191a43de 100644 --- a/src/analysis/normed_space/pointwise.lean +++ b/src/analysis/normed_space/pointwise.lean @@ -4,9 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel, Yaël Dillies -/ import analysis.normed.group.pointwise -import analysis.normed.group.add_torsor import analysis.normed_space.basic -import topology.metric_space.hausdorff_distance /-! # Properties of pointwise scalar multiplication of sets in normed spaces. @@ -87,14 +85,6 @@ begin simpa only [this, dist_eq_norm, add_sub_cancel', mem_closed_ball] using I, end -/-- Any ball is the image of a ball centered at the origin under a shift. -/ -lemma vadd_ball_zero (x : E) (r : ℝ) : x +ᵥ ball 0 r = ball x r := -by rw [vadd_ball, vadd_eq_add, add_zero] - -/-- Any closed ball is the image of a closed ball centered at the origin under a shift. -/ -lemma vadd_closed_ball_zero (x : E) (r : ℝ) : x +ᵥ closed_ball 0 r = closed_ball x r := -by rw [vadd_closed_ball, vadd_eq_add, add_zero] - variables [normed_space ℝ E] {x y z : E} {δ ε : ℝ} /-- In a real normed space, the image of the unit ball under scalar multiplication by a positive @@ -264,6 +254,58 @@ end exact tsub_le_iff_right.2, end +@[simp] lemma thickening_ball (hε : 0 < ε) (hδ : 0 < δ) (x : E) : + thickening ε (ball x δ) = ball x (ε + δ) := +by rw [←thickening_singleton, thickening_thickening hε hδ, thickening_singleton]; apply_instance + +@[simp] lemma thickening_closed_ball (hε : 0 < ε) (hδ : 0 ≤ δ) (x : E) : + thickening ε (closed_ball x δ) = ball x (ε + δ) := +by rw [←cthickening_singleton _ hδ, thickening_cthickening hε hδ, thickening_singleton]; + apply_instance + +@[simp] lemma cthickening_ball (hε : 0 ≤ ε) (hδ : 0 < δ) (x : E) : + cthickening ε (ball x δ) = closed_ball x (ε + δ) := +by rw [←thickening_singleton, cthickening_thickening hε hδ, + cthickening_singleton _ (add_nonneg hε hδ.le)]; apply_instance + +@[simp] lemma cthickening_closed_ball (hε : 0 ≤ ε) (hδ : 0 ≤ δ) (x : E) : + cthickening ε (closed_ball x δ) = closed_ball x (ε + δ) := +by rw [←cthickening_singleton _ hδ, cthickening_cthickening hε hδ, + cthickening_singleton _ (add_nonneg hε hδ)]; apply_instance + +lemma ball_add_ball (hε : 0 < ε) (hδ : 0 < δ) (a b : E) : + ball a ε + ball b δ = ball (a + b) (ε + δ) := +by rw [ball_add, thickening_ball hε hδ, vadd_ball, vadd_eq_add]; apply_instance + +lemma ball_sub_ball (hε : 0 < ε) (hδ : 0 < δ) (a b : E) : + ball a ε - ball b δ = ball (a - b) (ε + δ) := +by simp_rw [sub_eq_add_neg, neg_ball, ball_add_ball hε hδ] + +lemma ball_add_closed_ball (hε : 0 < ε) (hδ : 0 ≤ δ) (a b : E) : + ball a ε + closed_ball b δ = ball (a + b) (ε + δ) := +by rw [ball_add, thickening_closed_ball hε hδ, vadd_ball, vadd_eq_add]; apply_instance + +lemma ball_sub_closed_ball (hε : 0 < ε) (hδ : 0 ≤ δ) (a b : E) : + ball a ε - closed_ball b δ = ball (a - b) (ε + δ) := +by simp_rw [sub_eq_add_neg, neg_closed_ball, ball_add_closed_ball hε hδ] + +lemma closed_ball_add_ball (hε : 0 ≤ ε) (hδ : 0 < δ) (a b : E) : + closed_ball a ε + ball b δ = ball (a + b) (ε + δ) := +by rw [add_comm, ball_add_closed_ball hδ hε, add_comm, add_comm δ]; apply_instance + +lemma closed_ball_sub_ball (hε : 0 ≤ ε) (hδ : 0 < δ) (a b : E) : + closed_ball a ε - ball b δ = ball (a - b) (ε + δ) := +by simp_rw [sub_eq_add_neg, neg_ball, closed_ball_add_ball hε hδ] + +lemma closed_ball_add_closed_ball [proper_space E] (hε : 0 ≤ ε) (hδ : 0 ≤ δ) (a b : E) : + closed_ball a ε + closed_ball b δ = closed_ball (a + b) (ε + δ) := +by rw [(is_compact_closed_ball _ _).add_closed_ball hδ, cthickening_closed_ball hδ hε, + vadd_closed_ball, vadd_eq_add, add_comm, add_comm δ]; apply_instance + +lemma closed_ball_sub_closed_ball [proper_space E] (hε : 0 ≤ ε) (hδ : 0 ≤ δ) (a b : E) : + closed_ball a ε - closed_ball b δ = closed_ball (a - b) (ε + δ) := +by simp_rw [sub_eq_add_neg, neg_closed_ball, closed_ball_add_closed_ball hε hδ] + end semi_normed_group section normed_group diff --git a/src/data/set/pointwise.lean b/src/data/set/pointwise.lean index da6cd0863be49..ee48dce8436dd 100644 --- a/src/data/set/pointwise.lean +++ b/src/data/set/pointwise.lean @@ -503,7 +503,7 @@ lemma inv_subset_inv : s⁻¹ ⊆ t⁻¹ ↔ s ⊆ t := @[to_additive] lemma inv_subset : s⁻¹ ⊆ t ↔ s ⊆ t⁻¹ := by { rw [← inv_subset_inv, inv_inv] } -@[to_additive] lemma inv_singleton (a : α) : ({a} : set α)⁻¹ = {a⁻¹} := +@[simp, to_additive] lemma inv_singleton (a : α) : ({a} : set α)⁻¹ = {a⁻¹} := by rw [←image_inv, image_singleton] open mul_opposite diff --git a/src/measure_theory/function/jacobian.lean b/src/measure_theory/function/jacobian.lean index 8800cdd023c41..9a85c2426f01f 100644 --- a/src/measure_theory/function/jacobian.lean +++ b/src/measure_theory/function/jacobian.lean @@ -297,7 +297,7 @@ begin (𝓝[>] 0) (𝓝 (μ (A '' (closed_ball 0 1)))), { apply L0.congr' _, filter_upwards [self_mem_nhds_within] with r hr, - rw [HC.cthickening_eq_add_closed_ball (le_of_lt hr), add_comm] }, + rw [←HC.add_closed_ball_zero (le_of_lt hr), add_comm] }, have L2 : tendsto (λ ε, μ (closed_ball 0 ε + A '' (closed_ball 0 1))) (𝓝[>] 0) (𝓝 (d * μ (closed_ball 0 1))), { convert L1, From 812518d90ef246e57ff59555c6a035eff78c89d7 Mon Sep 17 00:00:00 2001 From: Aaron Anderson Date: Fri, 29 Apr 2022 20:31:20 +0000 Subject: [PATCH 331/373] feat(model_theory/semantics, satisfiability): Complete Theories (#13558) Defines `first_order.language.Theory.is_complete`, indicating that a theory is complete. Defines `first_order.language.complete_theory`, the complete theory of a structure. Shows that the complete theory of a structure is complete. --- src/model_theory/satisfiability.lean | 32 ++++++++++++++++++++++++++-- src/model_theory/semantics.lean | 31 +++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/model_theory/satisfiability.lean b/src/model_theory/satisfiability.lean index 73be35b1914ff..0f0b8745d9433 100644 --- a/src/model_theory/satisfiability.lean +++ b/src/model_theory/satisfiability.lean @@ -16,17 +16,20 @@ This file deals with the satisfiability of first-order theories, as well as equi model. * `first_order.language.Theory.is_finitely_satisfiable`: `T.is_finitely_satisfiable` indicates that every finite subset of `T` is satisfiable. +* `first_order.language.Theory.is_complete`: `T.is_complete` indicates that `T` is satisfiable and +models each sentence or its negation. * `first_order.language.Theory.semantically_equivalent`: `T.semantically_equivalent φ ψ` indicates that `φ` and `ψ` are equivalent formulas or sentences in models of `T`. ## Main Results * The Compactness Theorem, `first_order.language.Theory.is_satisfiable_iff_is_finitely_satisfiable`, shows that a theory is satisfiable iff it is finitely satisfiable. +* `first_order.language.complete_theory.is_complete`: The complete theory of a structure is +complete. ## Implementation Details * Satisfiability of an `L.Theory` `T` is defined in the minimal universe containing all the symbols -of `L`. By Löwenheim-Skolem, this is equivalent to satisfiability in any universe, but this is not -yet proven in mathlib. +of `L`. By Löwenheim-Skolem, this is equivalent to satisfiability in any universe. -/ @@ -103,6 +106,14 @@ lemma models_sentence_iff {φ : L.sentence} : T ⊨ φ ↔ ∀ (M : Model.{u v (max u v)} T), M ⊨ φ := models_formula_iff.trans (forall_congr (λ M, unique.forall_iff)) +lemma models_sentence_of_mem {φ : L.sentence} (h : φ ∈ T) : + T ⊨ φ := +models_sentence_iff.2 (λ _, realize_sentence_of_mem T h) + +/-- A theory is complete when it is satisfiable and models each sentence or its negation. -/ +def is_complete (T : L.Theory) : Prop := +T.is_satisfiable ∧ ∀ (φ : L.sentence), (T ⊨ φ) ∨ (T ⊨ φ.not) + /-- Two (bounded) formulas are semantically equivalent over a theory `T` when they have the same interpretation in every model of `T`. (This is also known as logical equivalence, which also has a proof-theoretic definition.) -/ @@ -186,6 +197,23 @@ end end Theory +namespace complete_theory + +variables (L) (M : Type w) [L.Structure M] + +lemma is_satisfiable [nonempty M] : (L.complete_theory M).is_satisfiable := +Theory.model.is_satisfiable M + +lemma mem_or_not_mem (φ : L.sentence) : + φ ∈ L.complete_theory M ∨ φ.not ∈ L.complete_theory M := +by simp_rw [complete_theory, set.mem_set_of_eq, sentence.realize, formula.realize_not, or_not] + +lemma is_complete [nonempty M] : (L.complete_theory M).is_complete := +⟨is_satisfiable L M, + λ φ, ((mem_or_not_mem L M φ).imp Theory.models_sentence_of_mem Theory.models_sentence_of_mem)⟩ + +end complete_theory + namespace bounded_formula variables (φ ψ : L.bounded_formula α n) diff --git a/src/model_theory/semantics.lean b/src/model_theory/semantics.lean index 6af58349d3bbf..911705e4954f7 100644 --- a/src/model_theory/semantics.lean +++ b/src/model_theory/semantics.lean @@ -509,11 +509,22 @@ def sentence.realize (φ : L.sentence) : Prop := infix ` ⊨ `:51 := sentence.realize -- input using \|= or \vDash, but not using \models +@[simp] lemma sentence.realize_not {φ : L.sentence} : + M ⊨ φ.not ↔ ¬ M ⊨ φ := +iff.rfl + @[simp] lemma Lhom.realize_on_sentence [L'.Structure M] (φ : L →ᴸ L') [φ.is_expansion_on M] (ψ : L.sentence) : M ⊨ φ.on_sentence ψ ↔ M ⊨ ψ := φ.realize_on_formula ψ +variables (L) + +/-- The complete theory of a structure `M` is the set of all sentences `M` satisfies. -/ +def complete_theory : L.Theory := { φ | M ⊨ φ } + +variables {L} + /-- A model of a theory is a structure in which every sentence is realized as true. -/ class Theory.model (T : L.Theory) : Prop := (realize_of_mem : ∀ φ ∈ T, M ⊨ φ) @@ -545,6 +556,26 @@ lemma Theory.model_singleton_iff {φ : L.sentence} : M ⊨ ({φ} : L.Theory) ↔ M ⊨ φ := by simp +theorem Theory.model_iff_subset_complete_theory : + M ⊨ T ↔ T ⊆ L.complete_theory M := +T.model_iff + +instance model_complete_theory : M ⊨ L.complete_theory M := +Theory.model_iff_subset_complete_theory.2 (subset_refl _) + +variables (M N) + +theorem realize_iff_of_model_complete_theory [N ⊨ L.complete_theory M] (φ : L.sentence) : + N ⊨ φ ↔ M ⊨ φ := +begin + refine ⟨λ h, _, Theory.realize_sentence_of_mem (L.complete_theory M)⟩, + contrapose! h, + rw [← sentence.realize_not] at *, + exact Theory.realize_sentence_of_mem (L.complete_theory M) h, +end + +variables {M N} + namespace bounded_formula @[simp] lemma realize_alls {φ : L.bounded_formula α n} {v : α → M} : From 9ce5e95a9b9e1e8df002182baeeff5d2162fb119 Mon Sep 17 00:00:00 2001 From: Aaron Anderson Date: Fri, 29 Apr 2022 20:31:21 +0000 Subject: [PATCH 332/373] feat(model_theory/syntax, semantics): A theory of infinite structures (#13580) Defines `first_order.language.infinite_theory`, a theory of infinite structures Adjusts the API of the theory of nonempty structures to match --- src/model_theory/elementary_maps.lean | 2 +- src/model_theory/semantics.lean | 64 ++++++++++++++++++++++----- src/model_theory/syntax.lean | 16 ++++--- 3 files changed, 65 insertions(+), 17 deletions(-) diff --git a/src/model_theory/elementary_maps.lean b/src/model_theory/elementary_maps.lean index e062e5492afd1..1516f47a25dd8 100644 --- a/src/model_theory/elementary_maps.lean +++ b/src/model_theory/elementary_maps.lean @@ -301,7 +301,7 @@ instance Theory_model {T : L.Theory} [h : M ⊨ T] {S : L.elementary_substructur (Theory_model_iff S T).2 h instance [h : nonempty M] {S : L.elementary_substructure M} : nonempty S := -(Theory.model_nonempty_iff L).1 infer_instance +(model_nonempty_theory_iff L).1 infer_instance end elementary_substructure diff --git a/src/model_theory/semantics.lean b/src/model_theory/semantics.lean index 911705e4954f7..e6e615f192048 100644 --- a/src/model_theory/semantics.lean +++ b/src/model_theory/semantics.lean @@ -176,6 +176,15 @@ by simp [has_top.top] @[simp] lemma realize_inf : (φ ⊓ ψ).realize v xs ↔ (φ.realize v xs ∧ ψ.realize v xs) := by simp [has_inf.inf, realize] +@[simp] lemma realize_foldr_inf (l : list (L.bounded_formula α n)) + (v : α → M) (xs : fin n → M) : + (l.foldr (⊓) ⊤).realize v xs ↔ ∀ φ ∈ l, bounded_formula.realize φ v xs := +begin + induction l with φ l ih, + { simp }, + { simp [ih] } +end + @[simp] lemma realize_imp : (φ.imp ψ).realize v xs ↔ (φ.realize v xs → ψ.realize v xs) := by simp only [realize] @@ -207,6 +216,16 @@ begin tauto, end +@[simp] lemma realize_foldr_sup (l : list (L.bounded_formula α n)) + (v : α → M) (xs : fin n → M) : + (l.foldr (⊔) ⊥).realize v xs ↔ ∃ φ ∈ l, bounded_formula.realize φ v xs := +begin + induction l with φ l ih, + { simp }, + { simp_rw [list.foldr_cons, realize_sup, ih, exists_prop, list.mem_cons_iff, + or_and_distrib_right, exists_or_distrib, exists_eq_left] } +end + @[simp] lemma realize_all : (all θ).realize v xs ↔ ∀ (a : M), (θ.realize v (fin.snoc xs a)) := iff.rfl @@ -679,23 +698,46 @@ forall_congr (λ _, forall_congr (λ _, realize_sup.trans (or_congr realize_rel end relations -section nonempty +section cardinality variable (L) -@[simp] lemma sentence.realize_nonempty : - M ⊨ (sentence.nonempty L) ↔ nonempty M := -bounded_formula.realize_ex.trans (trans (exists_congr eq_self_iff_true) exists_true_iff_nonempty) +@[simp] lemma sentence.realize_card_ge (n) : M ⊨ (sentence.card_ge L n) ↔ ↑n ≤ (# M) := +begin + rw [← lift_mk_fin, ← lift_le, lift_lift, lift_mk_le, sentence.card_ge, sentence.realize, + bounded_formula.realize_exs], + simp_rw [bounded_formula.realize_foldr_inf], + simp only [function.comp_app, list.mem_map, prod.exists, ne.def, list.mem_product, + list.mem_fin_range, forall_exists_index, and_imp, list.mem_filter, true_and], + refine ⟨_, λ xs, ⟨xs.some, _⟩⟩, + { rintro ⟨xs, h⟩, + refine ⟨⟨xs, λ i j ij, _⟩⟩, + contrapose! ij, + have hij := h _ i j ij rfl, + simp only [bounded_formula.realize_not, term.realize, bounded_formula.realize_bd_equal, + sum.elim_inr] at hij, + exact hij }, + { rintro _ i j ij rfl, + simp [ij] } +end + +@[simp] lemma model_infinite_theory_iff : M ⊨ L.infinite_theory ↔ infinite M := +by simp [infinite_theory, infinite_iff, omega_le] + +instance model_infinite_theory [h : infinite M] : + M ⊨ L.infinite_theory := +L.model_infinite_theory_iff.2 h -@[simp] lemma Theory.model_nonempty_iff : - M ⊨ (Theory.nonempty L) ↔ nonempty M := -Theory.model_singleton_iff.trans (sentence.realize_nonempty L) +@[simp] lemma model_nonempty_theory_iff : + M ⊨ L.nonempty_theory ↔ nonempty M := +by simp only [nonempty_theory, Theory.model_iff, set.mem_singleton_iff, forall_eq, + sentence.realize_card_ge, nat.cast_one, one_le_iff_ne_zero, mk_ne_zero_iff] -instance Theory.model_nonempty [h : nonempty M] : - M ⊨ (Theory.nonempty L) := -(Theory.model_nonempty_iff L).2 h +instance model_nonempty [h : nonempty M] : + M ⊨ L.nonempty_theory := +L.model_nonempty_theory_iff.2 h -end nonempty +end cardinality end language end first_order diff --git a/src/model_theory/syntax.lean b/src/model_theory/syntax.lean index 50e891bbfee80..6dd2e2e65a9f2 100644 --- a/src/model_theory/syntax.lean +++ b/src/model_theory/syntax.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Aaron Anderson, Jesse Michael Han, Floris van Doorn. All righ Released under Apache 2.0 license as described in the file LICENSE. Authors: Aaron Anderson, Jesse Michael Han, Floris van Doorn -/ +import data.list.prod_sigma import logic.equiv.fin import model_theory.language_map @@ -621,17 +622,22 @@ protected def total : L.sentence := end relations -section nonempty +section cardinality variable (L) -/-- A sentence that indicates a structure is nonempty. -/ -protected def sentence.nonempty : L.sentence := ∃' (&0 =' &0) +/-- A sentence indicating that a structure has `n` distinct elements. -/ +protected def sentence.card_ge (n) : L.sentence := +(((((list.fin_range n).product (list.fin_range n)).filter (λ ij : _ × _, ij.1 ≠ ij.2)).map + (λ (ij : _ × _), ∼ ((& ij.1).bd_equal (& ij.2)))).foldr (⊓) ⊤).exs + +/-- A theory indicating that a structure is infinite. -/ +def infinite_theory : L.Theory := set.range (sentence.card_ge L) /-- A theory that indicates a structure is nonempty. -/ -protected def Theory.nonempty : L.Theory := {sentence.nonempty L} +def nonempty_theory : L.Theory := {sentence.card_ge L 1} -end nonempty +end cardinality end language end first_order From 90bd6f54466d6957694d8adfee68531f4247fe10 Mon Sep 17 00:00:00 2001 From: Aaron Anderson Date: Fri, 29 Apr 2022 20:31:22 +0000 Subject: [PATCH 333/373] feat(model_theory/encoding): A bound on the number of bounded formulas (#13616) Gives an encoding `first_order.language.bounded_formula.encoding` of bounded formulas as lists. Uses the encoding to bound the number of bounded formulas with `first_order.language.bounded_formula.card_le`. --- src/data/list/basic.lean | 9 ++ src/model_theory/encoding.lean | 189 ++++++++++++++++++++++++++++++++- 2 files changed, 194 insertions(+), 4 deletions(-) diff --git a/src/data/list/basic.lean b/src/data/list/basic.lean index 9c20e1a7bec5f..78aa37d0c289f 100644 --- a/src/data/list/basic.lean +++ b/src/data/list/basic.lean @@ -1995,6 +1995,15 @@ lemma drop_append {l₁ l₂ : list α} (i : ℕ) : drop (l₁.length + i) (l₁ ++ l₂) = drop i l₂ := by simp [drop_append_eq_append_drop, take_all_of_le le_self_add] +lemma drop_sizeof_le [has_sizeof α] (l : list α) : ∀ (n : ℕ), (l.drop n).sizeof ≤ l.sizeof := +begin + induction l with _ _ lih; intro n, + { rw [drop_nil] }, + { induction n with n nih, + { refl, }, + { exact trans (lih _) le_add_self } } +end + /-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by dropping the first `i` elements. Version designed to rewrite from the big list to the small list. -/ lemma nth_le_drop (L : list α) {i j : ℕ} (h : i + j < L.length) : diff --git a/src/model_theory/encoding.lean b/src/model_theory/encoding.lean index c04120c934e55..131d479944f9c 100644 --- a/src/model_theory/encoding.lean +++ b/src/model_theory/encoding.lean @@ -11,15 +11,17 @@ import set_theory.cardinal.ordinal /-! # Encodings and Cardinality of First-Order Syntax ## Main Definitions -* Terms can be encoded as lists with `first_order.language.term.list_encode` and -`first_order.language.term.list_decode`. +* `first_order.language.term.encoding` encodes terms as lists. +* `first_order.language.bounded_formula.encoding` encodes bounded formulas as lists. ## Main Results * `first_order.language.term.card_le` shows that the number of terms in `L.term α` is at most -`# (α ⊕ Σ i, L.functions i) + ω`. +`max ω # (α ⊕ Σ i, L.functions i)`. +* `first_order.language.bounded_formula.card_le` shows that the number of bounded formulas in +`Σ n, L.bounded_formula α n` is at most +`max ω (cardinal.lift.{max u v} (#α) + cardinal.lift.{u'} L.card)`. ## TODO -* An encoding for formulas * `primcodable` instances for terms and formulas, based on the `encoding`s * Computability facts about term and formula operations, to set up a computability approach to incompleteness @@ -107,6 +109,42 @@ term.encoding.encode_injective theorem card_le : # (L.term α) ≤ max ω (# (α ⊕ Σ i, L.functions i)) := lift_le.1 (trans term.encoding.card_le_card_list (lift_le.2 (mk_list_le_max _))) +theorem card_sigma : # (Σ n, (L.term (α ⊕ fin n))) = max ω (# (α ⊕ Σ i, L.functions i)) := +begin + refine le_antisymm _ _, + { rw [mk_sigma], + refine (sum_le_sup_lift _).trans _, + rw [mk_nat, lift_omega, mul_eq_max_of_omega_le_left le_rfl, max_le_iff, cardinal.sup_le_iff], + { refine ⟨le_max_left _ _, λ i, card_le.trans _⟩, + rw max_le_iff, + refine ⟨le_max_left _ _, _⟩, + rw [← add_eq_max le_rfl, mk_sum, mk_sum, mk_sum, add_comm (cardinal.lift (#α)), lift_add, + add_assoc, lift_lift, lift_lift], + refine add_le_add_right _ _, + rw [lift_le_omega, ← encodable_iff], + exact ⟨infer_instance⟩ }, + { rw [← one_le_iff_ne_zero], + refine trans _ (le_sup _ 1), + rw [one_le_iff_ne_zero, mk_ne_zero_iff], + exact ⟨var (sum.inr 0)⟩ } }, + { rw [max_le_iff, ← infinite_iff], + refine ⟨infinite.of_injective (λ i, ⟨i + 1, var (sum.inr i)⟩) (λ i j ij, _), _⟩, + { cases ij, + refl }, + { rw [cardinal.le_def], + refine ⟨⟨sum.elim (λ i, ⟨0, var (sum.inl i)⟩) + (λ F, ⟨1, func F.2 (λ _, var (sum.inr 0))⟩), _⟩⟩, + { rintros (a | a) (b | b) h, + { simp only [sum.elim_inl, eq_self_iff_true, heq_iff_eq, true_and] at h, + rw h }, + { simp only [sum.elim_inl, sum.elim_inr, nat.zero_ne_one, false_and] at h, + exact h.elim }, + { simp only [sum.elim_inr, sum.elim_inl, nat.one_ne_zero, false_and] at h, + exact h.elim }, + { simp only [sum.elim_inr, eq_self_iff_true, heq_iff_eq, true_and] at h, + rw sigma.ext_iff.2 ⟨h.1, h.2.1⟩, } } } } +end + instance [encodable α] [encodable ((Σ i, L.functions i))] : encodable (L.term α) := encodable.of_left_injection list_encode (λ l, (list_decode l).head'.join) @@ -130,5 +168,148 @@ small_of_injective list_encode_injective end term +namespace bounded_formula + +/-- Encodes a bounded formula as a list of symbols. -/ +def list_encode : ∀ {n : ℕ}, L.bounded_formula α n → + list ((Σ k, L.term (α ⊕ fin k)) ⊕ (Σ n, L.relations n) ⊕ ℕ) +| n falsum := [sum.inr (sum.inr (n + 2))] +| n (equal t₁ t₂) := [sum.inl ⟨_, t₁⟩, sum.inl ⟨_, t₂⟩] +| n (rel R ts) := [sum.inr (sum.inl ⟨_, R⟩), sum.inr (sum.inr n)] ++ + ((list.fin_range _).map (λ i, sum.inl ⟨n, (ts i)⟩)) +| n (imp φ₁ φ₂) := (sum.inr (sum.inr 0)) :: φ₁.list_encode ++ φ₂.list_encode +| n (all φ) := (sum.inr (sum.inr 1)) :: φ.list_encode + +/-- Applies the `forall` quantifier to an element of `(Σ n, L.bounded_formula α n)`, +or returns `default` if not possible. -/ +def sigma_all : (Σ n, L.bounded_formula α n) → Σ n, L.bounded_formula α n +| ⟨(n + 1), φ⟩ := ⟨n, φ.all⟩ +| _ := default + +/-- Applies `imp` to two elements of `(Σ n, L.bounded_formula α n)`, +or returns `default` if not possible. -/ +def sigma_imp : + (Σ n, L.bounded_formula α n) → (Σ n, L.bounded_formula α n) → (Σ n, L.bounded_formula α n) +| ⟨m, φ⟩ ⟨n, ψ⟩ := if h : m = n then ⟨m, φ.imp (eq.mp (by rw h) ψ)⟩ else default + +/-- Decodes a list of symbols as a list of formulas. -/ +@[simp] def list_decode : + Π (l : list ((Σ k, L.term (α ⊕ fin k)) ⊕ (Σ n, L.relations n) ⊕ ℕ)), + (Σ n, L.bounded_formula α n) × + { l' : list ((Σ k, L.term (α ⊕ fin k)) ⊕ (Σ n, L.relations n) ⊕ ℕ) + // l'.sizeof ≤ max 1 l.sizeof } +| ((sum.inr (sum.inr (n + 2))) :: l) := ⟨⟨n, falsum⟩, l, le_max_of_le_right le_add_self⟩ +| ((sum.inl ⟨n₁, t₁⟩) :: sum.inl ⟨n₂, t₂⟩ :: l) := + ⟨if h : n₁ = n₂ then ⟨n₁, equal t₁ (eq.mp (by rw h) t₂)⟩ else default, l, begin + simp only [list.sizeof, ← add_assoc], + exact le_max_of_le_right le_add_self, + end⟩ +| (sum.inr (sum.inl ⟨n, R⟩) :: (sum.inr (sum.inr k)) :: l) := ⟨ + if h : ∀ (i : fin n), ((l.map sum.get_left).nth i).join.is_some + then if h' : ∀ i, (option.get (h i)).1 = k + then ⟨k, bounded_formula.rel R (λ i, eq.mp (by rw h' i) (option.get (h i)).2)⟩ + else default + else default, + l.drop n, le_max_of_le_right (le_add_left (le_add_left (list.drop_sizeof_le _ _)))⟩ +| ((sum.inr (sum.inr 0)) :: l) := + have (↑((list_decode l).2) : list ((Σ k, L.term (α ⊕ fin k)) ⊕ (Σ n, L.relations n) ⊕ ℕ)).sizeof + < 1 + (1 + 1) + l.sizeof, from begin + refine lt_of_le_of_lt (list_decode l).2.2 (max_lt _ (nat.lt_add_of_pos_left dec_trivial)), + rw [add_assoc, add_comm, nat.lt_succ_iff, add_assoc], + exact le_self_add, + end, + ⟨sigma_imp (list_decode l).1 (list_decode (list_decode l).2).1, + (list_decode (list_decode l).2).2, le_max_of_le_right (trans (list_decode _).2.2 (max_le + (le_add_right le_self_add) (trans (list_decode _).2.2 + (max_le (le_add_right le_self_add) le_add_self))))⟩ +| ((sum.inr (sum.inr 1)) :: l) := ⟨sigma_all (list_decode l).1, (list_decode l).2, + (list_decode l).2.2.trans (max_le_max le_rfl le_add_self)⟩ +| _ := ⟨default, [], le_max_left _ _⟩ + +@[simp] theorem list_decode_encode_list (l : list (Σ n, L.bounded_formula α n)) : + (list_decode (l.bind (λ φ, φ.2.list_encode))).1 = l.head := +begin + suffices h : ∀ (φ : (Σ n, L.bounded_formula α n)) l, + (list_decode (list_encode φ.2 ++ l)).1 = φ ∧ (list_decode (list_encode φ.2 ++ l)).2.1 = l, + { induction l with φ l lih, + { rw [list.nil_bind], + simp [list_decode], }, + { rw [cons_bind, (h φ _).1, head_cons] } }, + { rintro ⟨n, φ⟩, + induction φ with _ _ _ _ _ _ _ ts _ _ _ ih1 ih2 _ _ ih; intro l, + { rw [list_encode, singleton_append, list_decode], + simp only [eq_self_iff_true, heq_iff_eq, and_self], }, + { rw [list_encode, cons_append, cons_append, list_decode, dif_pos], + { simp only [eq_mp_eq_cast, cast_eq, eq_self_iff_true, heq_iff_eq, and_self, nil_append], }, + { simp only [eq_self_iff_true, heq_iff_eq, and_self], } }, + { rw [list_encode, cons_append, cons_append, singleton_append, cons_append, list_decode], + { have h : ∀ (i : fin φ_l), ((list.map sum.get_left (list.map (λ (i : fin φ_l), + sum.inl (⟨(⟨φ_n, rel φ_R ts⟩ : Σ n, L.bounded_formula α n).fst, ts i⟩ : + Σ n, L.term (α ⊕ fin n))) (fin_range φ_l) ++ l)).nth ↑i).join = some ⟨_, ts i⟩, + { intro i, + simp only [option.join, map_append, map_map, option.bind_eq_some, id.def, exists_eq_right, + nth_eq_some, length_append, length_map, length_fin_range], + refine ⟨lt_of_lt_of_le i.2 le_self_add, _⟩, + rw [nth_le_append, nth_le_map], + { simp only [sum.get_left, nth_le_fin_range, fin.eta, function.comp_app, eq_self_iff_true, + heq_iff_eq, and_self] }, + { exact lt_of_lt_of_le i.is_lt (ge_of_eq (length_fin_range _)) }, + { rw [length_map, length_fin_range], + exact i.2 } }, + rw dif_pos, swap, + { exact λ i, option.is_some_iff_exists.2 ⟨⟨_, ts i⟩, h i⟩ }, + rw dif_pos, swap, + { intro i, + obtain ⟨h1, h2⟩ := option.eq_some_iff_get_eq.1 (h i), + rw h2 }, + simp only [eq_self_iff_true, heq_iff_eq, true_and], + refine ⟨funext (λ i, _), _⟩, + { obtain ⟨h1, h2⟩ := option.eq_some_iff_get_eq.1 (h i), + rw [eq_mp_eq_cast, cast_eq_iff_heq], + exact (sigma.ext_iff.1 ((sigma.eta (option.get h1)).trans h2)).2 }, + rw [list.drop_append_eq_append_drop, length_map, length_fin_range, nat.sub_self, drop, + drop_eq_nil_of_le, nil_append], + rw [length_map, length_fin_range], }, }, + { rw [list_encode, append_assoc, cons_append, list_decode], + simp only [subtype.val_eq_coe] at *, + rw [(ih1 _).1, (ih1 _).2, (ih2 _).1, (ih2 _).2, sigma_imp, dif_pos rfl], + exact ⟨rfl, rfl⟩, }, + { rw [list_encode, cons_append, list_decode], + simp only, + simp only [subtype.val_eq_coe] at *, + rw [(ih _).1, (ih _).2, sigma_all], + exact ⟨rfl, rfl⟩ } } +end + +/-- An encoding of bounded formulas as lists. -/ +@[simps] protected def encoding : encoding (Σ n, L.bounded_formula α n) := +{ Γ := (Σ k, L.term (α ⊕ fin k)) ⊕ (Σ n, L.relations n) ⊕ ℕ, + encode := λ φ, φ.2.list_encode, + decode := λ l, (list_decode l).1, + decode_encode := λ φ, begin + have h := list_decode_encode_list [φ], + rw [bind_singleton] at h, + rw h, + refl, + end } + +lemma list_encode_sigma_injective : + function.injective (λ (φ : Σ n, L.bounded_formula α n), φ.2.list_encode) := +bounded_formula.encoding.encode_injective + +theorem card_le : # (Σ n, L.bounded_formula α n) ≤ + max ω (cardinal.lift.{max u v} (#α) + cardinal.lift.{u'} L.card) := +begin + refine lift_le.1 ((bounded_formula.encoding.card_le_card_list).trans _), + rw [encoding_Γ, mk_list_eq_max_mk_omega, lift_max',lift_omega, lift_max', lift_omega, max_le_iff], + refine ⟨_, le_max_left _ _⟩, + rw [mk_sum, term.card_sigma, mk_sum, ← add_eq_max le_rfl, mk_sum, mk_nat], + simp only [lift_add, lift_lift, lift_omega], + rw [← add_assoc, add_comm, ← add_assoc, ← add_assoc, omega_add_omega, add_assoc, + add_eq_max le_rfl, add_assoc, card, symbols, mk_sum, lift_add, lift_lift, lift_lift], +end + +end bounded_formula + end language end first_order From 1d4ed4a58c744ab74d211f55eaf1ee9cbb42773a Mon Sep 17 00:00:00 2001 From: Oliver Nash Date: Fri, 29 Apr 2022 20:31:23 +0000 Subject: [PATCH 334/373] chore(topology/algebra/valuation): use forgetful inheritance pattern for valued fields (#13691) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows us to solve a `uniform_space` diamond problem that arises when extending valuations to the completion of a valued field. More precisely, the main goal of this PR is to make the following work: ```lean import topology.algebra.valued_field example {K Γ₀ : Type*} [field K] [linear_ordered_comm_group_with_zero Γ₀] [valued K Γ₀] : uniform_space.completion.uniform_space K = valued.to_uniform_space := rfl ``` Co-authored-by: Patrick Massot --- src/number_theory/function_field.lean | 60 ++--------- src/topology/algebra/uniform_group.lean | 15 ++- src/topology/algebra/valuation.lean | 103 ++++++++++++------- src/topology/algebra/valued_field.lean | 60 ++++++++--- src/topology/algebra/with_zero_topology.lean | 6 ++ src/topology/dense_embedding.lean | 23 +++++ 6 files changed, 160 insertions(+), 107 deletions(-) diff --git a/src/number_theory/function_field.lean b/src/number_theory/function_field.lean index 6746b06e8c525..02bb4888a386d 100644 --- a/src/number_theory/function_field.lean +++ b/src/number_theory/function_field.lean @@ -229,70 +229,28 @@ end /-- The valued field `Fq(t)` with the valuation at infinity. -/ def infty_valued_Fqt : valued (ratfunc Fq) (with_zero (multiplicative ℤ)) := -⟨infty_valuation Fq⟩ +valued.mk' $ infty_valuation Fq lemma infty_valued_Fqt.def {x : ratfunc Fq} : - @valued.v (ratfunc Fq) _ _ _ (infty_valued_Fqt Fq) (x) = infty_valuation_def Fq x := rfl - -namespace infty_valued_Fqt - -/-- The topology structure on `Fq(t)` induced by the valuation at infinity. -/ -def topological_space : topological_space (ratfunc Fq) := -@valued.topological_space (ratfunc Fq) _ _ _ (infty_valued_Fqt Fq) - -lemma topological_division_ring : - @topological_division_ring (ratfunc Fq) _ (topological_space Fq) := -@valued.topological_division_ring (ratfunc Fq) _ _ _ (infty_valued_Fqt Fq) - -/-- The uniform structure on `k(t)` induced by the valuation at infinity. -/ -def uniform_space : uniform_space (ratfunc Fq) := -@topological_add_group.to_uniform_space (ratfunc Fq) _ (topological_space Fq) _ - -lemma uniform_add_group : @uniform_add_group (ratfunc Fq) (uniform_space Fq) _ := -@topological_add_group_is_uniform (ratfunc Fq) _ (topological_space Fq) _ - -lemma completable_top_field : @completable_top_field (ratfunc Fq) _ (uniform_space Fq) := -@valued.completable (ratfunc Fq) _ _ _ (infty_valued_Fqt Fq) - -lemma separated_space : @separated_space (ratfunc Fq) (uniform_space Fq) := -@valued_ring.separated (ratfunc Fq) _ _ _ (infty_valued_Fqt Fq) - -end infty_valued_Fqt - -open infty_valued_Fqt + @valued.v (ratfunc Fq) _ _ _ (infty_valued_Fqt Fq) x = infty_valuation_def Fq x := rfl /-- The completion `Fq((t⁻¹))` of `Fq(t)` with respect to the valuation at infinity. -/ -def Fqt_infty := @uniform_space.completion (ratfunc Fq) (uniform_space Fq) +def Fqt_infty := @uniform_space.completion (ratfunc Fq) $ (infty_valued_Fqt Fq).to_uniform_space instance : field (Fqt_infty Fq) := -@field_completion (ratfunc Fq) _ (uniform_space Fq) (topological_division_ring Fq) _ - (uniform_add_group Fq) +begin + letI := infty_valued_Fqt Fq, + exact field_completion, +end instance : inhabited (Fqt_infty Fq) := ⟨(0 : Fqt_infty Fq)⟩ /-- The valuation at infinity on `k(t)` extends to a valuation on `Fqt_infty`. -/ instance valued_Fqt_infty : valued (Fqt_infty Fq) (with_zero (multiplicative ℤ)) := -⟨@valued.extension_valuation (ratfunc Fq) _ _ _ (infty_valued_Fqt Fq)⟩ +@valued.valued_completion _ _ _ _ (infty_valued_Fqt Fq) lemma valued_Fqt_infty.def {x : Fqt_infty Fq} : - valued.v (x) = @valued.extension (ratfunc Fq) _ _ _ (infty_valued_Fqt Fq) x := rfl - -instance Fqt_infty.topological_space : topological_space (Fqt_infty Fq) := -valued.topological_space (with_zero (multiplicative ℤ)) - -instance Fqt_infty.topological_division_ring : topological_division_ring (Fqt_infty Fq) := -valued.topological_division_ring - -instance : topological_ring (Fqt_infty Fq) := -(Fqt_infty.topological_division_ring Fq).to_topological_ring - -instance : topological_add_group (Fqt_infty Fq) := topological_ring.to_topological_add_group - -instance Fqt_infty.uniform_space : uniform_space (Fqt_infty Fq) := -topological_add_group.to_uniform_space (Fqt_infty Fq) - -instance Fqt_infty.uniform_add_group : uniform_add_group (Fqt_infty Fq) := -topological_add_group_is_uniform + valued.v x = @valued.extension (ratfunc Fq) _ _ _ (infty_valued_Fqt Fq) x := rfl end infty_valuation diff --git a/src/topology/algebra/uniform_group.lean b/src/topology/algebra/uniform_group.lean index 820d8e3a27566..04eb3f27aad2b 100644 --- a/src/topology/algebra/uniform_group.lean +++ b/src/topology/algebra/uniform_group.lean @@ -372,14 +372,13 @@ begin simpa [(∘), div_eq_mul_inv, mul_comm, mul_left_comm] using this end -local attribute [instance] topological_group_is_uniform - open set -@[to_additive] lemma topological_group.separated_iff_one_closed : - separated_space G ↔ is_closed ({1} : set G) := +@[to_additive] lemma topological_group.t2_space_iff_one_closed : + t2_space G ↔ is_closed ({1} : set G) := begin - rw [separated_space_iff, ← closure_eq_iff_is_closed], + haveI : uniform_group G := topological_group_is_uniform, + rw [← separated_iff_t2, separated_space_iff, ← closure_eq_iff_is_closed], split; intro h, { apply subset.antisymm, { intros x x_in, @@ -395,10 +394,10 @@ begin refl } end -@[to_additive] lemma topological_group.separated_of_one_sep - (H : ∀ x : G, x ≠ 1 → ∃ U ∈ nhds (1 : G), x ∉ U) : separated_space G:= +@[to_additive] lemma topological_group.t2_space_of_one_sep + (H : ∀ x : G, x ≠ 1 → ∃ U ∈ nhds (1 : G), x ∉ U) : t2_space G := begin - rw [topological_group.separated_iff_one_closed, ← is_open_compl_iff, is_open_iff_mem_nhds], + rw [topological_group.t2_space_iff_one_closed, ← is_open_compl_iff, is_open_iff_mem_nhds], intros x x_not, have : x ≠ 1, from mem_compl_singleton_iff.mp x_not, rcases H x this with ⟨U, U_in, xU⟩, diff --git a/src/topology/algebra/valuation.lean b/src/topology/algebra/valuation.lean index 1078b6ed66f60..ee3fdd9f7cba4 100644 --- a/src/topology/algebra/valuation.lean +++ b/src/topology/algebra/valuation.lean @@ -16,31 +16,21 @@ The main definition is a `valued` type class which equips a ring with a valuatio values in a group with zero. Other instances are then deduced from this. -/ -open_locale classical topological_space +open_locale classical topological_space uniformity open set valuation noncomputable theory universes v u -/-- A valued ring is a ring that comes equipped with a distinguished valuation. The class `valued` -is designed for the situation that there is a canonical valuation on the ring. It allows such a -valuation to be registered as a typeclass; this is used for instance by `valued.topological_space`. +variables {R : Type u} [ring R] {Γ₀ : Type v} [linear_ordered_comm_group_with_zero Γ₀] -TODO: show that there always exists an equivalent valuation taking values in a type belonging to -the same universe as the ring. -/ -class valued (R : Type u) [ring R] (Γ₀ : out_param (Type v)) - [linear_ordered_comm_group_with_zero Γ₀] := -(v : valuation R Γ₀) +namespace valuation -namespace valued -variables {R : Type u} [ring R] (Γ₀ : Type v) [linear_ordered_comm_group_with_zero Γ₀] - [hv : valued R Γ₀] - -include hv +variables (v : valuation R Γ₀) -/-- The basis of open subgroups for the topology on a valued ring.-/ +/-- The basis of open subgroups for the topology on a ring determined by a valuation. -/ lemma subgroups_basis : - ring_subgroups_basis (λ γ : Γ₀ˣ, (valued.v.lt_add_subgroup γ : add_subgroup R)) := + ring_subgroups_basis (λ γ : Γ₀ˣ, (v.lt_add_subgroup γ : add_subgroup R)) := { inter := begin rintros γ₀ γ₁, use min γ₀ γ₁, @@ -87,26 +77,73 @@ lemma subgroups_basis : simpa using mul_inv_lt_of_lt_mul₀ vy_lt } end } -/-- The topological space structure on a valued ring. +end valuation + +/-- A valued ring is a ring that comes equipped with a distinguished valuation. The class `valued` +is designed for the situation that there is a canonical valuation on the ring. + +TODO: show that there always exists an equivalent valuation taking values in a type belonging to +the same universe as the ring. + +See Note [forgetful inheritance] for why we extend `uniform_space`, `uniform_add_group`. -/ +class valued (R : Type u) [ring R] (Γ₀ : out_param (Type v)) + [linear_ordered_comm_group_with_zero Γ₀] extends uniform_space R, uniform_add_group R := +(v : valuation R Γ₀) +(is_topological_valuation : ∀ s, s ∈ 𝓝 (0 : R) ↔ ∃ (γ : Γ₀ˣ), { x : R | v x < γ } ⊆ s) -NOTE: The `dangerous_instance` linter does not check whether the metavariables only occur in +/-- The `dangerous_instance` linter does not check whether the metavariables only occur in arguments marked with `out_param`, so in this instance it gives a false positive. -/ -@[nolint dangerous_instance, priority 100] -instance : topological_space R := (subgroups_basis Γ₀).topology +attribute [nolint dangerous_instance] valued.to_uniform_space -variable {Γ₀} +namespace valued + +/-- Alternative `valued` constructor for use when there is no preferred `uniform_space` +structure. -/ +def mk' (v : valuation R Γ₀) : valued R Γ₀ := +{ v := v, + to_uniform_space := @topological_add_group.to_uniform_space R _ v.subgroups_basis.topology _, + to_uniform_add_group := @topological_add_group_is_uniform _ _ v.subgroups_basis.topology _, + is_topological_valuation := + begin + letI := @topological_add_group.to_uniform_space R _ v.subgroups_basis.topology _, + intros s, + rw filter.has_basis_iff.mp v.subgroups_basis.has_basis_nhds_zero s, + exact exists_congr (λ γ, by simpa), + end } + +variables (R Γ₀) [_i : valued R Γ₀] +include _i + +lemma has_basis_nhds_zero : + (𝓝 (0 : R)).has_basis (λ _, true) (λ (γ : Γ₀ˣ), { x | v x < (γ : Γ₀) }) := +by simp [filter.has_basis_iff, is_topological_valuation] + +lemma has_basis_uniformity : + (𝓤 R).has_basis (λ _, true) (λ (γ : Γ₀ˣ), { p : R × R | v (p.2 - p.1) < (γ : Γ₀) }) := +begin + rw uniformity_eq_comap_nhds_zero, + exact (has_basis_nhds_zero R Γ₀).comap _, +end + +lemma to_uniform_space_eq : + to_uniform_space = @topological_add_group.to_uniform_space R _ v.subgroups_basis.topology _ := +uniform_space_eq + ((has_basis_uniformity R Γ₀).eq_of_same_basis $ v.subgroups_basis.has_basis_nhds_zero.comap _) + +variables {R Γ₀} lemma mem_nhds {s : set R} {x : R} : (s ∈ 𝓝 x) ↔ ∃ (γ : Γ₀ˣ), {y | (v (y - x) : Γ₀) < γ } ⊆ s := -by simpa [((subgroups_basis Γ₀).has_basis_nhds x).mem_iff] +by simp only [← nhds_translation_add_neg x, ← sub_eq_add_neg, preimage_set_of_eq, exists_true_left, + ((has_basis_nhds_zero R Γ₀).comap (λ y, y - x)).mem_iff] lemma mem_nhds_zero {s : set R} : (s ∈ 𝓝 (0 : R)) ↔ ∃ γ : Γ₀ˣ, {x | v x < (γ : Γ₀) } ⊆ s := -by simp [valued.mem_nhds, sub_zero] +by simp only [mem_nhds, sub_zero] lemma loc_const {x : R} (h : (v x : Γ₀) ≠ 0) : {y : R | v y = v x} ∈ 𝓝 x := begin - rw valued.mem_nhds, + rw mem_nhds, rcases units.exists_iff_ne_zero.mpr h with ⟨γ, hx⟩, use γ, rw hx, @@ -114,27 +151,21 @@ begin exact valuation.map_eq_of_sub_lt _ y_in end -/-- The uniform structure on a valued ring. - -NOTE: The `dangerous_instance` linter does not check whether the metavariables only occur in -arguments marked with `out_param`, so in this instance it gives a false positive.-/ -@[nolint dangerous_instance, priority 100] -instance uniform_space : uniform_space R := topological_add_group.to_uniform_space R - -/-- A valued ring is a uniform additive group.-/ @[priority 100] -instance uniform_add_group : uniform_add_group R := topological_add_group_is_uniform +instance : topological_ring R := +(to_uniform_space_eq R Γ₀).symm ▸ v.subgroups_basis.to_ring_filter_basis.is_topological_ring lemma cauchy_iff {F : filter R} : cauchy F ↔ F.ne_bot ∧ ∀ γ : Γ₀ˣ, ∃ M ∈ F, ∀ x y ∈ M, (v (y - x) : Γ₀) < γ := begin - rw add_group_filter_basis.cauchy_iff, + rw [to_uniform_space_eq, add_group_filter_basis.cauchy_iff], apply and_congr iff.rfl, - simp_rw (subgroups_basis Γ₀).mem_add_group_filter_basis_iff, + simp_rw valued.v.subgroups_basis.mem_add_group_filter_basis_iff, split, { intros h γ, - exact h _ ((subgroups_basis Γ₀).mem_add_group_filter_basis _) }, + exact h _ (valued.v.subgroups_basis.mem_add_group_filter_basis _) }, { rintros h - ⟨γ, rfl⟩, exact h γ } end + end valued diff --git a/src/topology/algebra/valued_field.lean b/src/topology/algebra/valued_field.lean index 4b632f1b80262..f7623214b6efb 100644 --- a/src/topology/algebra/valued_field.lean +++ b/src/topology/algebra/valued_field.lean @@ -28,7 +28,6 @@ separated, so the map from `K` to `hat K` is injective. Then we extend the valuation given on `K` to a valuation on `hat K`. -/ - open filter set open_locale topological_space @@ -104,7 +103,8 @@ instance valued.topological_division_ring [valued K Γ₀] : topological_divisio @[priority 100] instance valued_ring.separated [valued K Γ₀] : separated_space K := begin - apply topological_add_group.separated_of_zero_sep, + rw separated_iff_t2, + apply topological_add_group.t2_space_of_zero_sep, intros x x_ne, refine ⟨{k | v k < v x}, _, λ h, lt_irrefl _ h⟩, rw valued.mem_nhds, @@ -142,7 +142,7 @@ end valuation_topological_division_ring end division_ring -section valuation_on_valued_field_completion +namespace valued open uniform_space variables {K : Type*} [field K] {Γ₀ : Type*} [linear_ordered_comm_group_with_zero Γ₀] @@ -150,13 +150,11 @@ variables {K : Type*} [field K] {Γ₀ : Type*} [linear_ordered_comm_group_with_ include hv -open valued uniform_space - local notation `hat ` := completion /-- A valued field is completable. -/ @[priority 100] -instance valued.completable : completable_top_field K := +instance completable : completable_top_field K := { nice := begin rintros F hF h0, have : ∃ (γ₀ : Γ₀ˣ) (M ∈ F), ∀ x ∈ M, (γ₀ : Γ₀) ≤ v x, @@ -203,10 +201,10 @@ instance valued.completable : completable_top_field K := local attribute [instance] linear_ordered_comm_group_with_zero.topological_space /-- The extension of the valuation of a valued field to the completion of the field. -/ -noncomputable def valued.extension : hat K → Γ₀ := +noncomputable def extension : hat K → Γ₀ := completion.dense_inducing_coe.extend (v : K → Γ₀) -lemma valued.continuous_extension : continuous (valued.extension : hat K → Γ₀) := +lemma continuous_extension : continuous (valued.extension : hat K → Γ₀) := begin refine completion.dense_inducing_coe.continuous_extend _, intro x₀, @@ -282,8 +280,8 @@ lemma valued.continuous_extension : continuous (valued.extension : hat K → Γ ... = v z₀ : by rw [this, one_mul] }, end -@[norm_cast] -lemma valued.extension_extends (x : K) : (valued.extension (x : hat K) : Γ₀) = v x := +@[simp, norm_cast] +lemma extension_extends (x : K) : extension (x : hat K) = v x := begin haveI : t2_space Γ₀ := regular_space.t2_space _, refine completion.dense_inducing_coe.extend_eq_of_tendsto _, @@ -292,7 +290,7 @@ begin end /-- the extension of a valuation on a division ring to its completion. -/ -noncomputable def valued.extension_valuation : +noncomputable def extension_valuation : valuation (hat K) Γ₀ := { to_fun := valued.extension, map_zero' := by { rw [← v.map_zero, ← valued.extension_extends (0 : K)], refl, }, @@ -324,4 +322,42 @@ noncomputable def valued.extension_valuation : exact v.map_add x y, }, end } -end valuation_on_valued_field_completion +-- Bourbaki CA VI §5 no.3 Proposition 5 (d) +lemma closure_coe_completion_v_lt {γ : Γ₀ˣ} : + closure (coe '' { x : K | v x < (γ : Γ₀) }) = { x : hat K | extension_valuation x < (γ : Γ₀) } := +begin + ext x, + let γ₀ := extension_valuation x, + suffices : γ₀ ≠ 0 → (x ∈ closure (coe '' { x : K | v x < (γ : Γ₀) }) ↔ γ₀ < (γ : Γ₀)), + { cases eq_or_ne γ₀ 0, + { simp only [h, (valuation.zero_iff _).mp h, mem_set_of_eq, valuation.map_zero, units.zero_lt, + iff_true], + apply subset_closure, + exact ⟨0, by simpa only [mem_set_of_eq, valuation.map_zero, units.zero_lt, true_and]⟩, }, + { exact this h, }, }, + intros h, + have hγ₀ : extension ⁻¹' {γ₀} ∈ 𝓝 x := continuous_extension.continuous_at.preimage_mem_nhds + (linear_ordered_comm_group_with_zero.singleton_mem_nhds_of_ne_zero h), + rw mem_closure_iff_nhds', + refine ⟨λ hx, _, λ hx s hs, _⟩, + { obtain ⟨⟨-, y, hy₁ : v y < (γ : Γ₀), rfl⟩, hy₂⟩ := hx _ hγ₀, + replace hy₂ : v y = γ₀, { simpa using hy₂, }, + rwa ← hy₂, }, + { obtain ⟨y, hy₁, hy₂ : ↑y ∈ s⟩ := completion.dense_range_coe.mem_nhds (inter_mem hγ₀ hs), + replace hy₁ : v y = γ₀, { simpa using hy₁, }, + rw ← hy₁ at hx, + exact ⟨⟨y, ⟨y, hx, rfl⟩⟩, hy₂⟩, }, +end + +noncomputable instance valued_completion : valued (hat K) Γ₀ := +{ v := extension_valuation, + is_topological_valuation := λ s, + begin + suffices : has_basis (𝓝 (0 : hat K)) (λ _, true) (λ γ : Γ₀ˣ, { x | extension_valuation x < γ }), + { rw this.mem_iff, + exact exists_congr (λ γ, by simp), }, + simp_rw ← closure_coe_completion_v_lt, + exact (has_basis_nhds_zero K Γ₀).has_basis_of_dense_inducing completion.dense_inducing_coe, + end } + +end valued diff --git a/src/topology/algebra/with_zero_topology.lean b/src/topology/algebra/with_zero_topology.lean index ecc392ccc08d8..a7589975c91ae 100644 --- a/src/topology/algebra/with_zero_topology.lean +++ b/src/topology/algebra/with_zero_topology.lean @@ -160,6 +160,12 @@ lemma has_basis_nhds_of_ne_zero {x : Γ₀} (h : x ≠ 0) : has_basis (𝓝 x) (λ i : unit, true) (λ i, {x}) := has_basis_nhds_units (units.mk0 x h) +lemma singleton_mem_nhds_of_ne_zero {x : Γ₀} (h : x ≠ 0) : {x} ∈ 𝓝 x := +begin + apply (has_basis_nhds_of_ne_zero h).mem_of_mem true.intro, + exact unit.star, +end + lemma tendsto_units {α : Type*} {F : filter α} {f : α → Γ₀} {γ₀ : Γ₀ˣ} : tendsto f F (𝓝 (γ₀ : Γ₀)) ↔ { x : α | f x = γ₀ } ∈ F := begin diff --git a/src/topology/dense_embedding.lean b/src/topology/dense_embedding.lean index 7068eca6f574a..acd08bbc565d4 100644 --- a/src/topology/dense_embedding.lean +++ b/src/topology/dense_embedding.lean @@ -337,3 +337,26 @@ lemma dense_range.equalizer (hfd : dense_range f) g = h := funext $ λ y, hfd.induction_on y (is_closed_eq hg hh) $ congr_fun H end + +-- Bourbaki GT III §3 no.4 Proposition 7 (generalised to any dense-inducing map to a regular space) +lemma filter.has_basis.has_basis_of_dense_inducing + [topological_space α] [topological_space β] [regular_space β] + {ι : Type*} {s : ι → set α} {p : ι → Prop} {x : α} (h : (𝓝 x).has_basis p s) + {f : α → β} (hf : dense_inducing f) : + (𝓝 (f x)).has_basis p $ λ i, closure $ f '' (s i) := +begin + rw filter.has_basis_iff at h ⊢, + intros T, + refine ⟨λ hT, _, λ hT, _⟩, + { obtain ⟨T', hT₁, hT₂, hT₃⟩ := nhds_is_closed hT, + have hT₄ : f⁻¹' T' ∈ 𝓝 x, + { rw hf.to_inducing.nhds_eq_comap x, + exact ⟨T', hT₁, subset.rfl⟩, }, + obtain ⟨i, hi, hi'⟩ := (h _).mp hT₄, + exact ⟨i, hi, (closure_mono (image_subset f hi')).trans (subset.trans (closure_minimal + (image_subset_iff.mpr subset.rfl) hT₃) hT₂)⟩, }, + { obtain ⟨i, hi, hi'⟩ := hT, + suffices : closure (f '' s i) ∈ 𝓝 (f x), { filter_upwards [this] using hi', }, + replace h := (h (s i)).mpr ⟨i, hi, subset.rfl⟩, + exact hf.closure_image_mem_nhds h, }, +end From e56b8fea84d60fe434632b9d3b829ee685fb0c8f Mon Sep 17 00:00:00 2001 From: Aaron Anderson Date: Fri, 29 Apr 2022 20:31:25 +0000 Subject: [PATCH 335/373] feat(model_theory/graph): First-order language and theory of graphs (#13720) Defines `first_order.language.graph`, the language of graphs Defines `first_order.Theory.simple_graph`, the theory of simple graphs Produces models of the theory of simple graphs from simple graphs and vice versa. --- src/model_theory/graph.lean | 113 ++++++++++++++++++++++++++++++++++++ src/model_theory/order.lean | 6 +- 2 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 src/model_theory/graph.lean diff --git a/src/model_theory/graph.lean b/src/model_theory/graph.lean new file mode 100644 index 0000000000000..e5d2763808457 --- /dev/null +++ b/src/model_theory/graph.lean @@ -0,0 +1,113 @@ +/- +Copyright (c) 2022 Aaron Anderson. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Aaron Anderson +-/ +import model_theory.satisfiability +import combinatorics.simple_graph.basic + +/-! +# First-Ordered Structures in Graph Theory +This file defines first-order languages, structures, and theories in graph theory. + +## Main Definitions +* `first_order.language.graph` is the language consisting of a single relation representing +adjacency. +* `simple_graph.Structure` is the first-order structure corresponding to a given simple graph. +* `first_order.language.Theory.simple_graph` is the theory of simple graphs. +* `first_order.language.simple_graph_of_structure` gives the simple graph corresponding to a model +of the theory of simple graphs. + +-/ + +universes u v w w' + +namespace first_order +namespace language +open_locale first_order +open Structure + +variables {L : language.{u v}} {α : Type w} {V : Type w'} {n : ℕ} + +/-! ### Simple Graphs -/ + +/-- The language consisting of a single relation representing adjacency. -/ +protected def graph : language := +language.mk₂ empty empty empty empty unit + +/-- The symbol representing the adjacency relation. -/ +def adj : language.graph.relations 2 := unit.star + +/-- Any simple graph can be thought of as a structure in the language of graphs. -/ +def _root_.simple_graph.Structure (G : simple_graph V) : + language.graph.Structure V := +Structure.mk₂ empty.elim empty.elim empty.elim empty.elim (λ _, G.adj) + +namespace graph + +instance : is_relational (language.graph) := language.is_relational_mk₂ + +instance : subsingleton (language.graph.relations n) := +language.subsingleton_mk₂_relations + +end graph + +/-- The theory of simple graphs. -/ +protected def Theory.simple_graph : language.graph.Theory := +{adj.irreflexive, adj.symmetric} + +@[simp] lemma Theory.simple_graph_model_iff [language.graph.Structure V] : + V ⊨ Theory.simple_graph ↔ + irreflexive (λ x y : V, rel_map adj ![x,y]) ∧ symmetric (λ x y : V, rel_map adj ![x,y]) := +by simp [Theory.simple_graph] + +instance simple_graph_model (G : simple_graph V) : + @Theory.model _ V G.Structure Theory.simple_graph := +begin + simp only [Theory.simple_graph_model_iff, rel_map_apply₂], + exact ⟨G.loopless, G.symm⟩, +end + +variables (V) + +/-- Any model of the theory of simple graphs represents a simple graph. -/ +@[simps] def simple_graph_of_structure [language.graph.Structure V] [V ⊨ Theory.simple_graph] : + simple_graph V := +{ adj := λ x y, rel_map adj ![x,y], + symm := relations.realize_symmetric.1 (Theory.realize_sentence_of_mem Theory.simple_graph + (set.mem_insert_of_mem _ (set.mem_singleton _))), + loopless := relations.realize_irreflexive.1 (Theory.realize_sentence_of_mem Theory.simple_graph + (set.mem_insert _ _)) } + +variables {V} + +@[simp] lemma _root_.simple_graph.simple_graph_of_structure (G : simple_graph V) : + @simple_graph_of_structure V G.Structure _ = G := +by { ext, refl } + +@[simp] lemma Structure_simple_graph_of_structure + [S : language.graph.Structure V] [V ⊨ Theory.simple_graph] : + (simple_graph_of_structure V).Structure = S := +begin + ext n f xs, + { exact (is_relational.empty_functions n).elim f }, + { ext n r xs, + rw iff_eq_eq, + cases n, + { exact r.elim }, + { cases n, + { exact r.elim }, + { cases n, + { cases r, + change rel_map adj ![xs 0, xs 1] = _, + refine congr rfl (funext _), + simp [fin.forall_fin_two], }, + { exact r.elim } } } } +end + +theorem Theory.simple_graph_is_satisfiable : + Theory.is_satisfiable Theory.simple_graph := +⟨@Theory.Model.of _ _ unit (simple_graph.Structure ⊥) _ _⟩ + +end language +end first_order diff --git a/src/model_theory/order.lean b/src/model_theory/order.lean index 0eeff59b2aad4..f483e7782e196 100644 --- a/src/model_theory/order.lean +++ b/src/model_theory/order.lean @@ -40,7 +40,9 @@ variables {L : language.{u v}} {α : Type w} {M : Type w'} {n : ℕ} protected def order : language := language.mk₂ empty empty empty empty unit -instance order.Structure [has_le M] : language.order.Structure M := +namespace order + +instance Structure [has_le M] : language.order.Structure M := Structure.mk₂ empty.elim empty.elim empty.elim empty.elim (λ _, (≤)) instance : is_relational (language.order) := language.is_relational_mk₂ @@ -48,6 +50,8 @@ instance : is_relational (language.order) := language.is_relational_mk₂ instance : subsingleton (language.order.relations n) := language.subsingleton_mk₂_relations +end order + /-- A language is ordered if it has a symbol representing `≤`. -/ class is_ordered (L : language.{u v}) := (le_symb : L.relations 2) From 89102286dfe7d3587d1e9ae7173fdbc261da23e9 Mon Sep 17 00:00:00 2001 From: Alex J Best Date: Fri, 29 Apr 2022 20:31:26 +0000 Subject: [PATCH 336/373] chore(data/polynomial): use dot notation for sub lemmas (#13799) To match the additive versions --- src/data/polynomial/monic.lean | 4 ++-- src/ring_theory/power_basis.lean | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/data/polynomial/monic.lean b/src/data/polynomial/monic.lean index e7b2c97a39360..360d21a747eba 100644 --- a/src/data/polynomial/monic.lean +++ b/src/data/polynomial/monic.lean @@ -376,11 +376,11 @@ begin nat_degree_one] end -lemma monic_sub_of_left {p q : R[X]} (hp : monic p) (hpq : degree q < degree p) : +lemma monic.sub_of_left {p q : R[X]} (hp : monic p) (hpq : degree q < degree p) : monic (p - q) := by { rw sub_eq_add_neg, apply hp.add_of_left, rwa degree_neg } -lemma monic_sub_of_right {p q : R[X]} +lemma monic.sub_of_right {p q : R[X]} (hq : q.leading_coeff = -1) (hpq : degree p < degree q) : monic (p - q) := have (-q).coeff (-q).nat_degree = 1 := by rw [nat_degree_neg, coeff_neg, show q.coeff q.nat_degree = -1, from hq, neg_neg], diff --git a/src/ring_theory/power_basis.lean b/src/ring_theory/power_basis.lean index fc4e3d17b4e0d..65d72d8a8f874 100644 --- a/src/ring_theory/power_basis.lean +++ b/src/ring_theory/power_basis.lean @@ -209,7 +209,7 @@ nat_degree_eq_of_degree_eq_some pb.degree_minpoly_gen lemma minpoly_gen_monic (pb : power_basis A S) : monic (minpoly_gen pb) := begin - apply monic_sub_of_left (monic_X_pow _) _, + apply (monic_X_pow _).sub_of_left _, rw degree_X_pow, exact degree_sum_fin_lt _ end From 059c8eb7deb4351b03b4dd6974e9a70d92059297 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Fri, 29 Apr 2022 20:31:27 +0000 Subject: [PATCH 337/373] chore(set_theory/game/basic): fix a single space (#13806) --- src/set_theory/game/basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/set_theory/game/basic.lean b/src/set_theory/game/basic.lean index 2c2691ecea4fe..68452d8f53f1a 100644 --- a/src/set_theory/game/basic.lean +++ b/src/set_theory/game/basic.lean @@ -232,7 +232,7 @@ by { cases x, cases y, refl, } @[simp] lemma mk_mul_move_left_inl {xl xr yl yr} {xL xR yL yR} {i j} : (mk xl xr xL xR * mk yl yr yL yR).move_left (sum.inl (i, j)) = xL i * (mk yl yr yL yR) + (mk xl xr xL xR) * yL j - xL i * yL j := - rfl +rfl @[simp] lemma mul_move_left_inl {x y : pgame} {i j} : (x * y).move_left ((left_moves_mul x y).symm (sum.inl (i, j))) From a70166a39978e2b977907d4e9ddf33adcae9139b Mon Sep 17 00:00:00 2001 From: Junyan Xu Date: Fri, 29 Apr 2022 22:22:47 +0000 Subject: [PATCH 338/373] feat(ring_theory): factorize a non-unit into irreducible factors without multiplying a unit (#13682) Used in https://proofassistants.stackexchange.com/a/1312/93. Also adds simp lemma `multiset.prod_erase` used in the main proof and the auto-generated additive version, which is immediately analogous to [list.prod_erase](https://leanprover-community.github.io/mathlib_docs/data/list/big_operators.html#list.prod_erase). Also removes some extraneous namespace prefix. --- src/algebra/big_operators/multiset.lean | 6 +++- .../unique_factorization_domain.lean | 29 ++++++++++++++----- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/algebra/big_operators/multiset.lean b/src/algebra/big_operators/multiset.lean index e9a011c13650e..19a9cf026dff9 100644 --- a/src/algebra/big_operators/multiset.lean +++ b/src/algebra/big_operators/multiset.lean @@ -33,7 +33,7 @@ variables [comm_monoid α] {s t : multiset α} {a : α} {m : multiset ι} {f g : def prod : multiset α → α := foldr (*) (λ x y z, by simp [mul_left_comm]) 1 @[to_additive] -lemma prod_eq_foldr (s : multiset α) : prod s = foldr (*) (λ x y z, by simp [mul_left_comm]) 1 s := +lemma prod_eq_foldr (s : multiset α) : prod s = foldr (*) (λ x y z, by simp [mul_left_comm]) 1 s := rfl @[to_additive] @@ -54,6 +54,10 @@ end @[simp, to_additive] lemma prod_cons (a : α) (s) : prod (a ::ₘ s) = a * prod s := foldr_cons _ _ _ _ _ +@[simp, to_additive] +lemma prod_erase [decidable_eq α] (h : a ∈ s) : a * (s.erase a).prod = s.prod := +by rw [← s.coe_to_list, coe_erase, coe_prod, coe_prod, list.prod_erase ((s.mem_to_list a).2 h)] + @[simp, to_additive] lemma prod_singleton (a : α) : prod {a} = a := by simp only [mul_one, prod_cons, singleton_eq_cons, eq_self_iff_true, prod_zero] diff --git a/src/ring_theory/unique_factorization_domain.lean b/src/ring_theory/unique_factorization_domain.lean index 7121d0da1b4dd..a14c36192d98a 100644 --- a/src/ring_theory/unique_factorization_domain.lean +++ b/src/ring_theory/unique_factorization_domain.lean @@ -52,7 +52,7 @@ open associates nat theorem of_wf_dvd_monoid_associates (h : wf_dvd_monoid (associates α)): wf_dvd_monoid α := ⟨begin haveI := h, - refine (surjective.well_founded_iff mk_surjective _).2 wf_dvd_monoid.well_founded_dvd_not_unit, + refine (surjective.well_founded_iff mk_surjective _).2 well_founded_dvd_not_unit, intros, rw mk_dvd_not_unit_mk_iff end⟩ @@ -60,12 +60,12 @@ variables [wf_dvd_monoid α] instance wf_dvd_monoid_associates : wf_dvd_monoid (associates α) := ⟨begin - refine (surjective.well_founded_iff mk_surjective _).1 wf_dvd_monoid.well_founded_dvd_not_unit, + refine (surjective.well_founded_iff mk_surjective _).1 well_founded_dvd_not_unit, intros, rw mk_dvd_not_unit_mk_iff end⟩ theorem well_founded_associates : well_founded ((<) : associates α → associates α → Prop) := -subrelation.wf (λ x y, dvd_not_unit_of_lt) wf_dvd_monoid.well_founded_dvd_not_unit +subrelation.wf (λ x y, dvd_not_unit_of_lt) well_founded_dvd_not_unit local attribute [elab_as_eliminator] well_founded.fix @@ -73,7 +73,7 @@ lemma exists_irreducible_factor {a : α} (ha : ¬ is_unit a) (ha0 : a ≠ 0) : ∃ i, irreducible i ∧ i ∣ a := (irreducible_or_factor a ha).elim (λ hai, ⟨a, hai, dvd_rfl⟩) (well_founded.fix - wf_dvd_monoid.well_founded_dvd_not_unit + well_founded_dvd_not_unit (λ a ih ha ha0 ⟨x, y, hx, hy, hxy⟩, have hx0 : x ≠ 0, from λ hx0, ha0 (by rw [← hxy, hx0, zero_mul]), (irreducible_or_factor x hx).elim @@ -86,7 +86,7 @@ lemma exists_irreducible_factor {a : α} (ha : ¬ is_unit a) (ha0 : a ≠ 0) : (hi : ∀ a i : α, a ≠ 0 → irreducible i → P a → P (i * a)) : P a := by haveI := classical.dec; exact -well_founded.fix wf_dvd_monoid.well_founded_dvd_not_unit +well_founded.fix well_founded_dvd_not_unit (λ a ih, if ha0 : a = 0 then ha0.symm ▸ h0 else if hau : is_unit a then hu a hau else let ⟨i, hii, ⟨b, hb⟩⟩ := exists_irreducible_factor hau ha0 in @@ -96,8 +96,8 @@ well_founded.fix wf_dvd_monoid.well_founded_dvd_not_unit a lemma exists_factors (a : α) : a ≠ 0 → - ∃f : multiset α, (∀b ∈ f, irreducible b) ∧ associated f.prod a := -wf_dvd_monoid.induction_on_irreducible a + ∃ f : multiset α, (∀ b ∈ f, irreducible b) ∧ associated f.prod a := +induction_on_irreducible a (λ h, (h rfl).elim) (λ u hu _, ⟨0, ⟨by simp [hu], associated.symm (by simp [hu, associated_one_iff_is_unit])⟩⟩) (λ a i ha0 hii ih hia0, @@ -107,6 +107,19 @@ wf_dvd_monoid.induction_on_irreducible a by { rw multiset.prod_cons, exact hs.2.mul_left _ }⟩⟩) +lemma not_unit_iff_exists_factors_eq (a : α) (hn0 : a ≠ 0) : + ¬ is_unit a ↔ ∃ f : multiset α, (∀ b ∈ f, irreducible b) ∧ f.prod = a ∧ f ≠ ∅ := +⟨λ hnu, begin + obtain ⟨f, hi, u, rfl⟩ := exists_factors a hn0, + obtain ⟨b, h⟩ := multiset.exists_mem_of_ne_zero (λ h : f = 0, hnu $ by simp [h]), + classical, refine ⟨(f.erase b).cons (b * u), λ a ha, _, _, multiset.cons_ne_zero⟩, + { obtain (rfl|ha) := multiset.mem_cons.1 ha, + exacts [associated.irreducible ⟨u,rfl⟩ (hi b h), hi a (multiset.mem_of_mem_erase ha)] }, + { rw [multiset.prod_cons, mul_comm b, mul_assoc, multiset.prod_erase h, mul_comm] }, +end, +λ ⟨f,hi,he,hne⟩, let ⟨b, h⟩ := multiset.exists_mem_of_ne_zero hne in + not_is_unit_of_not_is_unit_dvd (hi b h).not_unit (he.subst $ multiset.dvd_prod h)⟩ + end wf_dvd_monoid theorem wf_dvd_monoid.of_well_founded_associates [cancel_comm_monoid_with_zero α] @@ -227,7 +240,7 @@ by haveI := classical.dec_eq α; exact /-- If an irreducible has a prime factorization, then it is an associate of one of its prime factors. -/ lemma prime_factors_irreducible [cancel_comm_monoid_with_zero α] {a : α} {f : multiset α} - (ha : irreducible a) (pfa : (∀b ∈ f, prime b) ∧ f.prod ~ᵤ a) : + (ha : irreducible a) (pfa : (∀ b ∈ f, prime b) ∧ f.prod ~ᵤ a) : ∃ p, a ~ᵤ p ∧ f = {p} := begin haveI := classical.dec_eq α, From 24bc2e1c58098bb1716d27bb920e84db414c05dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Fri, 29 Apr 2022 22:22:48 +0000 Subject: [PATCH 339/373] feat(set_theory/surreal/basic): add `pgame.numeric.left_lt_right` (#13809) Also compress some trivial proofs into a single line --- src/set_theory/surreal/basic.lean | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/set_theory/surreal/basic.lean b/src/set_theory/surreal/basic.lean index 8ab282b9d0795..7d996859c180c 100644 --- a/src/set_theory/surreal/basic.lean +++ b/src/set_theory/surreal/basic.lean @@ -56,18 +56,15 @@ lemma numeric_def (x : pgame) : numeric x ↔ (∀ i j, x.move_left i < x.move_r (∀ i, numeric (x.move_left i)) ∧ (∀ i, numeric (x.move_right i)) := by { cases x, refl } +lemma numeric.left_lt_right {x : pgame} (o : numeric x) (i : x.left_moves) (j : x.right_moves) : + x.move_left i < x.move_right j := +by { cases x with xl xr xL xR, exact o.1 i j } lemma numeric.move_left {x : pgame} (o : numeric x) (i : x.left_moves) : numeric (x.move_left i) := -begin - cases x with xl xr xL xR, - exact o.2.1 i, -end +by { cases x with xl xr xL xR, exact o.2.1 i } lemma numeric.move_right {x : pgame} (o : numeric x) (j : x.right_moves) : numeric (x.move_right j) := -begin - cases x with xl xr xL xR, - exact o.2.2 j, -end +by { cases x with xl xr xL xR, exact o.2.2 j } @[elab_as_eliminator] theorem numeric_rec {C : pgame → Prop} From a34ee7b7499dbfe65ef87e2973cce5b98b1d00cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Fri, 29 Apr 2022 22:22:48 +0000 Subject: [PATCH 340/373] chore(set_theory/game/basic): golf proof (#13810) --- src/set_theory/game/basic.lean | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/src/set_theory/game/basic.lean b/src/set_theory/game/basic.lean index 68452d8f53f1a..ae163628b2e02 100644 --- a/src/set_theory/game/basic.lean +++ b/src/set_theory/game/basic.lean @@ -272,25 +272,14 @@ by {cases x, cases y, refl} theorem quot_mul_comm : Π (x y : pgame.{u}), ⟦x * y⟧ = ⟦y * x⟧ | (mk xl xr xL xR) (mk yl yr yL yR) := begin - let x := mk xl xr xL xR, - let y := mk yl yr yL yR, - refine quot_eq_of_mk_quot_eq _ _ _ _, - apply equiv.sum_congr (equiv.prod_comm _ _) (equiv.prod_comm _ _), - calc - xl × yr ⊕ xr × yl - ≃ xr × yl ⊕ xl × yr : equiv.sum_comm _ _ - ... ≃ yl × xr ⊕ yr × xl : equiv.sum_congr (equiv.prod_comm _ _) (equiv.prod_comm _ _), - { rintro (⟨i, j⟩ | ⟨i, j⟩), - { change ⟦xL i * y⟧ + ⟦x * yL j⟧ - ⟦xL i * yL j⟧ = ⟦yL j * x⟧ + ⟦y * xL i⟧ - ⟦yL j * xL i⟧, - rw [quot_mul_comm (xL i) y, quot_mul_comm x (yL j), quot_mul_comm (xL i) (yL j), add_comm] }, - { change ⟦xR i * y⟧ + ⟦x * yR j⟧ - ⟦xR i * yR j⟧ = ⟦yR j * x⟧ + ⟦y * xR i⟧ - ⟦yR j * xR i⟧, - rw [quot_mul_comm (xR i) y, quot_mul_comm x (yR j), quot_mul_comm (xR i) (yR j), - add_comm] } }, - { rintro (⟨j, i⟩ | ⟨j, i⟩), - { change ⟦xR i * y⟧ + ⟦x * yL j⟧ - ⟦xR i * yL j⟧ = ⟦yL j * x⟧ + ⟦y * xR i⟧ - ⟦yL j * xR i⟧, - rw [quot_mul_comm (xR i) y, quot_mul_comm x (yL j), quot_mul_comm (xR i) (yL j), add_comm] }, - { change ⟦xL i * y⟧ + ⟦x * yR j⟧ - ⟦xL i * yR j⟧ = ⟦yR j * x⟧ + ⟦y * xL i⟧ - ⟦yR j * xL i⟧, - rw [quot_mul_comm (xL i) y, quot_mul_comm x (yR j), quot_mul_comm (xL i) (yR j), add_comm] } } + refine quot_eq_of_mk_quot_eq + (equiv.sum_congr (equiv.prod_comm _ _) (equiv.prod_comm _ _)) + ((equiv.sum_comm _ _).trans (equiv.sum_congr (equiv.prod_comm _ _) (equiv.prod_comm _ _))) _ _, + all_goals { rintro (⟨i, j⟩ | ⟨i, j⟩); dsimp; rw [quot_mul_comm, quot_mul_comm (mk xl xr xL xR)] }, + { rw [quot_mul_comm (xL i), add_comm] }, + { rw [quot_mul_comm (xR i), add_comm] }, + { rw [quot_mul_comm (xR j), add_comm] }, + { rw [quot_mul_comm (xL j), add_comm] } end using_well_founded { dec_tac := pgame_wf_tac } From bb45687b639c38e5b5243d89b3eda1fb72a6fa6f Mon Sep 17 00:00:00 2001 From: Aaron Anderson Date: Sat, 30 Apr 2022 02:26:48 +0000 Subject: [PATCH 341/373] feat(model_theory/syntax, semantics): Substitution of variables in terms and formulas (#13632) Defines `first_order.language.term.subst` and `first_order.language.bounded_formula.subst`, which substitute free variables in terms and formulas with terms. --- src/model_theory/semantics.lean | 35 ++++++++++++++++++++++++++++----- src/model_theory/syntax.lean | 17 ++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/model_theory/semantics.lean b/src/model_theory/semantics.lean index e6e615f192048..7c2977737578e 100644 --- a/src/model_theory/semantics.lean +++ b/src/model_theory/semantics.lean @@ -27,8 +27,8 @@ sentence of `T` is realized in `M`. Also denoted `T ⊨ φ`. * `first_order.language.bounded_formula.realize_to_prenex` shows that the prenex normal form of a formula has the same realization as the original formula. * Several results in this file show that syntactic constructions such as `relabel`, `cast_le`, -`lift_at`, and the actions of language maps commute with realization of terms, formulas, sentences, -and theories. +`lift_at`, `subst`, and the actions of language maps commute with realization of terms, formulas, +sentences, and theories. ## Implementation Notes * Formulas use a modified version of de Bruijn variables. Specifically, a `L.bounded_formula α n` @@ -103,6 +103,14 @@ end lemma realize_con {A : set M} {a : A} {v : α → M} : (L.con a).term.realize v = a := rfl +@[simp] lemma realize_subst {t : L.term α} {tf : α → L.term β} {v : β → M} : + (t.subst tf).realize v = t.realize (λ a, (tf a).realize v) := +begin + induction t with _ _ _ _ ih, + { refl }, + { simp [ih] } +end + end term namespace Lhom @@ -323,7 +331,26 @@ begin rw [if_pos i.is_lt], end -lemma realize_all_lift_at_one_self [nonempty M] {n : ℕ} {φ : L.bounded_formula α n} +@[simp] lemma realize_subst_aux {tf : α → L.term β} {v : β → M} {xs : fin n → M} : + (λ x, term.realize (sum.elim v xs) (sum.elim (term.relabel sum.inl ∘ tf) (var ∘ sum.inr) x)) = + sum.elim (λ (a : α), term.realize v (tf a)) xs := +funext (λ x, sum.cases_on x (λ x, + by simp only [sum.elim_inl, term.realize_relabel, sum.elim_comp_inl]) (λ x, rfl)) + +lemma realize_subst {φ : L.bounded_formula α n} {tf : α → L.term β} {v : β → M} {xs : fin n → M} : + (φ.subst tf).realize v xs ↔ φ.realize (λ a, (tf a).realize v) xs := +begin + induction φ with _ _ _ _ _ _ _ _ _ _ _ ih1 ih2 _ _ ih, + { refl }, + { simp only [subst, bounded_formula.realize, realize_subst, realize_subst_aux] }, + { simp only [subst, bounded_formula.realize, realize_subst, realize_subst_aux] }, + { simp only [subst, realize_imp, ih1, ih2] }, + { simp only [ih, subst, realize_all] } +end + +variables [nonempty M] + +lemma realize_all_lift_at_one_self {n : ℕ} {φ : L.bounded_formula α n} {v : α → M} {xs : fin n → M} : (φ.lift_at 1 n).all.realize v xs ↔ φ.realize v xs := begin @@ -336,8 +363,6 @@ begin simp } end -variables [nonempty M] - lemma realize_to_prenex_imp_right {φ ψ : L.bounded_formula α n} (hφ : is_qf φ) (hψ : is_prenex ψ) {v : α → M} {xs : fin n → M} : (φ.to_prenex_imp_right ψ).realize v xs ↔ (φ.imp ψ).realize v xs := diff --git a/src/model_theory/syntax.lean b/src/model_theory/syntax.lean index 6dd2e2e65a9f2..625846f4fc914 100644 --- a/src/model_theory/syntax.lean +++ b/src/model_theory/syntax.lean @@ -24,6 +24,8 @@ This file defines first-order terms, formulas, sentences, and theories in a styl * `first_order.language.bounded_formula.cast_le` adds more `fin`-indexed variables. * `first_order.language.bounded_formula.lift_at` raises the indexes of the `fin`-indexed variables above a particular index. +* `first_order.language.term.subst` and `first_order.language.bounded_formula.subst` substitute +variables with given terms. * Language maps can act on syntactic objects with functions such as `first_order.language.Lhom.on_formula`. @@ -96,6 +98,11 @@ instance inhabited_of_constant [inhabited L.constants] : inhabited (L.term α) : def lift_at {n : ℕ} (n' m : ℕ) : L.term (α ⊕ fin n) → L.term (α ⊕ fin (n + n')) := relabel (sum.map id (λ i, if ↑i < m then fin.cast_add n' i else fin.add_nat n' i)) +/-- Substitutes the variables in a given term with terms. -/ +@[simp] def subst : L.term α → (α → L.term β) → L.term β +| (var a) tf := tf a +| (func f ts) tf := (func f (λ i, (ts i).subst tf)) + end term localized "prefix `&`:max := first_order.language.term.var ∘ sum.inr" in first_order @@ -272,6 +279,16 @@ def lift_at : ∀ {n : ℕ} (n' m : ℕ), L.bounded_formula α n → L.bounded_f | n n' m (imp f₁ f₂) := (f₁.lift_at n' m).imp (f₂.lift_at n' m) | n n' m (all f) := ((f.lift_at n' m).cast_le (by rw [add_assoc, add_comm 1, ← add_assoc])).all +/-- Substitutes the variables in a given formula with terms. -/ +@[simp] def subst : ∀ {n : ℕ}, L.bounded_formula α n → (α → L.term β) → L.bounded_formula β n +| n falsum tf := falsum +| n (equal t₁ t₂) tf := equal (t₁.subst (sum.elim (term.relabel sum.inl ∘ tf) (var ∘ sum.inr))) + (t₂.subst (sum.elim (term.relabel sum.inl ∘ tf) (var ∘ sum.inr))) +| n (rel R ts) tf := rel R + (λ i, (ts i).subst (sum.elim (term.relabel sum.inl ∘ tf) (var ∘ sum.inr))) +| n (imp φ₁ φ₂) tf := (φ₁.subst tf).imp (φ₂.subst tf) +| n (all φ) tf := (φ.subst tf).all + variables {l : ℕ} {φ ψ : L.bounded_formula α l} {θ : L.bounded_formula α l.succ} variables {v : α → M} {xs : fin l → M} From 91419608bea241451e7b47d83bd07431bdfcf595 Mon Sep 17 00:00:00 2001 From: Aaron Anderson Date: Sat, 30 Apr 2022 05:24:54 +0000 Subject: [PATCH 342/373] feat(model_theory/syntax): Free variables (#13529) Defines `term.var_finset` and `bounded_formula.free_var_finset` to consist of all (free) variables used in a term or formula. Defines `term.restrict_var` and `bounded_formula.restrict_free_var` to restrict formulas to sets of their variables. --- src/model_theory/syntax.lean | 53 ++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/src/model_theory/syntax.lean b/src/model_theory/syntax.lean index 625846f4fc914..2e7f756661939 100644 --- a/src/model_theory/syntax.lean +++ b/src/model_theory/syntax.lean @@ -67,15 +67,37 @@ variable {L} namespace term -open list +open finset + +/-- The `finset` of variables used in a given term. -/ +@[simp] def var_finset [decidable_eq α] : L.term α → finset α +| (var i) := {i} +| (func f ts) := univ.bUnion (λ i, (ts i).var_finset) + +/-- The `finset` of variables from the left side of a sum used in a given term. -/ +@[simp] def var_finset_left [decidable_eq α] : L.term (α ⊕ β) → finset α +| (var (sum.inl i)) := {i} +| (var (sum.inr i)) := ∅ +| (func f ts) := univ.bUnion (λ i, (ts i).var_finset_left) /-- Relabels a term's variables along a particular function. -/ @[simp] def relabel (g : α → β) : L.term α → L.term β | (var i) := var (g i) | (func f ts) := func f (λ i, (ts i).relabel) -instance inhabited_of_var [inhabited α] : inhabited (L.term α) := -⟨var default⟩ +/-- Restricts a term to use only a set of the given variables. -/ +def restrict_var [decidable_eq α] : Π (t : L.term α) (f : t.var_finset → β), L.term β +| (var a) f := var (f ⟨a, mem_singleton_self a⟩) +| (func F ts) f := func F (λ i, (ts i).restrict_var + (f ∘ (set.inclusion (subset_bUnion_of_mem _ (mem_univ i))))) + +/-- Restricts a term to use only a set of the given variables on the left side of a sum. -/ +def restrict_var_left [decidable_eq α] {γ : Type*} : + Π (t : L.term (α ⊕ γ)) (f : t.var_finset_left → β), L.term (β ⊕ γ) +| (var (sum.inl a)) f := var (sum.inl (f ⟨a, mem_singleton_self a⟩)) +| (var (sum.inr a)) f := var (sum.inr a) +| (func F ts) f := func F (λ i, (ts i).restrict_var_left + (f ∘ (set.inclusion (subset_bUnion_of_mem _ (mem_univ i))))) end term @@ -225,6 +247,17 @@ instance : has_sup (L.bounded_formula α n) := ⟨λ f g, f.not.imp g⟩ /-- The biimplication between two bounded formulas. -/ protected def iff (φ ψ : L.bounded_formula α n) := φ.imp ψ ⊓ ψ.imp φ +open finset + +/-- The `finset` of variables used in a given formula. -/ +@[simp] def free_var_finset [decidable_eq α] : + ∀ {n}, L.bounded_formula α n → finset α +| n falsum := ∅ +| n (equal t₁ t₂) := t₁.var_finset_left ∪ t₂.var_finset_left +| n (rel R ts) := univ.bUnion (λ i, (ts i).var_finset_left) +| n (imp f₁ f₂) := f₁.free_var_finset ∪ f₂.free_var_finset +| n (all f) := f.free_var_finset + /-- Casts `L.bounded_formula α m` as `L.bounded_formula α n`, where `m ≤ n`. -/ def cast_le : ∀ {m n : ℕ} (h : m ≤ n), L.bounded_formula α m → L.bounded_formula α n | m n h falsum := falsum @@ -261,6 +294,20 @@ def relabel (g : α → (β ⊕ fin n)) : | k (imp f₁ f₂) := f₁.relabel.imp f₂.relabel | k (all f) := f.relabel.all +/-- Restricts a bounded formula to only use a particular set of free variables. -/ +def restrict_free_var [decidable_eq α] : Π {n : ℕ} (φ : L.bounded_formula α n) + (f : φ.free_var_finset → β), L.bounded_formula β n +| n falsum f := falsum +| n (equal t₁ t₂) f := equal + (t₁.restrict_var_left (f ∘ (set.inclusion (subset_union_left _ _)))) + (t₂.restrict_var_left (f ∘ (set.inclusion (subset_union_right _ _)))) +| n (rel R ts) f := rel R (λ i, (ts i).restrict_var_left + (f ∘ set.inclusion (subset_bUnion_of_mem _ (mem_univ i)))) +| n (imp φ₁ φ₂) f := + (φ₁.restrict_free_var (f ∘ (set.inclusion (subset_union_left _ _)))).imp + (φ₂.restrict_free_var (f ∘ (set.inclusion (subset_union_right _ _)))) +| n (all φ) f := (φ.restrict_free_var f).all + /-- Places universal quantifiers on all extra variables of a bounded formula. -/ def alls : ∀ {n}, L.bounded_formula α n → L.formula α | 0 φ := φ From 1c3ab8cdf0de083a8673cfcb7c2206c9f9c35eea Mon Sep 17 00:00:00 2001 From: sgouezel Date: Sat, 30 Apr 2022 10:51:30 +0000 Subject: [PATCH 343/373] feat(probability/notations): fix some notations, add a new one (#13828) --- src/probability/notation.lean | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/probability/notation.lean b/src/probability/notation.lean index 45b03c3e4ff8f..1be9c52af33d5 100644 --- a/src/probability/notation.lean +++ b/src/probability/notation.lean @@ -21,8 +21,7 @@ We note that the notation `∂P/∂Q` applies to three different cases, namely, `measure_theory.measure.rn_deriv`, `measure_theory.signed_measure.rn_deriv` and `measure_theory.complex_measure.rn_deriv`. -TODO: define the notation `ℙ s` for the probability of a set `s`, and decide whether it should be a -value in `ℝ`, `ℝ≥0` or `ℝ≥0∞`. +- `ℙ` is a notation for `volume` on a measured space. -/ open measure_theory @@ -33,16 +32,20 @@ open measure_theory -- one ensures that `m` stays visible in the goal view: when `hm` is complicated, it gets rendered -- as `_` and the measurable space would not be visible in `𝔼[f|_]`, but is clear in `𝔼[f|m,_]`. localized "notation `𝔼[` X `|` hm `]` := - measure_theory.condexp _ hm measure_theory.measure.volume X" in probability_theory + measure_theory.condexp _ hm measure_theory.measure_space.volume X" in probability_theory localized "notation `𝔼[` X `|` m `,` hm `]` := - measure_theory.condexp m hm measure_theory.measure.volume X" in probability_theory + measure_theory.condexp m hm measure_theory.measure_space.volume X" in probability_theory localized "notation P `[` X `]` := ∫ x, X x ∂P" in probability_theory localized "notation `𝔼[` X `]` := ∫ a, X a" in probability_theory -localized "notation X `=ₐₛ`:50 Y:50 := X =ᵐ[measure_theory.measure.volume] Y" in probability_theory +localized "notation X `=ₐₛ`:50 Y:50 := X =ᵐ[measure_theory.measure_space.volume] Y" + in probability_theory -localized "notation X `≤ₐₛ`:50 Y:50 := X ≤ᵐ[measure_theory.measure.volume] Y" in probability_theory +localized "notation X `≤ₐₛ`:50 Y:50 := X ≤ᵐ[measure_theory.measure_space.volume] Y" + in probability_theory localized "notation `∂` P `/∂`:50 Q:50 := P.rn_deriv Q" in probability_theory + +localized "notation `ℙ` := measure_theory.measure_space.volume" in probability_theory From 26310e7182164a258e8cd220a730bd1febdf8cb0 Mon Sep 17 00:00:00 2001 From: sgouezel Date: Sat, 30 Apr 2022 11:26:15 +0000 Subject: [PATCH 344/373] feat(algebra/*): a sample of easy useful lemmas (#13696) Lemmas needed for #13690 --- src/algebra/big_operators/intervals.lean | 14 ++++++++++++++ src/algebra/geom_sum.lean | 14 ++++++++++++++ src/algebra/group_power/basic.lean | 6 ++++++ src/algebra/order/floor.lean | 3 +++ src/algebra/order/group.lean | 3 +++ src/data/finset/locally_finite.lean | 4 ++++ src/data/nat/interval.lean | 3 +++ 7 files changed, 47 insertions(+) diff --git a/src/algebra/big_operators/intervals.lean b/src/algebra/big_operators/intervals.lean index 9a7f5128c7a34..8a500766ee19a 100644 --- a/src/algebra/big_operators/intervals.lean +++ b/src/algebra/big_operators/intervals.lean @@ -71,6 +71,20 @@ lemma prod_Ico_consecutive (f : ℕ → β) {m n k : ℕ} (hmn : m ≤ n) (hnk : (∏ i in Ico m n, f i) * (∏ i in Ico n k, f i) = (∏ i in Ico m k, f i) := Ico_union_Ico_eq_Ico hmn hnk ▸ eq.symm $ prod_union $ Ico_disjoint_Ico_consecutive m n k +@[to_additive] +lemma prod_Ioc_consecutive (f : ℕ → β) {m n k : ℕ} (hmn : m ≤ n) (hnk : n ≤ k) : + (∏ i in Ioc m n, f i) * (∏ i in Ioc n k, f i) = (∏ i in Ioc m k, f i) := +begin + rw [← Ioc_union_Ioc_eq_Ioc hmn hnk, prod_union], + apply disjoint_left.2 (λ x hx h'x, _), + exact lt_irrefl _ ((mem_Ioc.1 h'x).1.trans_le (mem_Ioc.1 hx).2), +end + +@[to_additive] +lemma prod_Ioc_succ_top {a b : ℕ} (hab : a ≤ b) (f : ℕ → β) : + (∏ k in Ioc a (b + 1), f k) = (∏ k in Ioc a b, f k) * f (b + 1) := +by rw [← prod_Ioc_consecutive _ hab (nat.le_succ b), nat.Ioc_succ_singleton, prod_singleton] + @[to_additive] lemma prod_range_mul_prod_Ico (f : ℕ → β) {m n : ℕ} (h : m ≤ n) : (∏ k in range m, f k) * (∏ k in Ico m n, f k) = (∏ k in range n, f k) := diff --git a/src/algebra/geom_sum.lean b/src/algebra/geom_sum.lean index e1d680ff49ca6..97beb92eecca8 100644 --- a/src/algebra/geom_sum.lean +++ b/src/algebra/geom_sum.lean @@ -322,6 +322,20 @@ theorem geom_sum_Ico' [division_ring α] {x : α} (hx : x ≠ 1) {m n : ℕ} (hm ∑ i in finset.Ico m n, x ^ i = (x ^ m - x ^ n) / (1 - x) := by { simp only [geom_sum_Ico hx hmn], convert neg_div_neg_eq (x^m - x^n) (1-x); abel } +lemma geom_sum_Ico_le_of_lt_one [linear_ordered_field α] + {x : α} (hx : 0 ≤ x) (h'x : x < 1) {m n : ℕ} : + ∑ i in Ico m n, x ^ i ≤ x ^ m / (1 - x) := +begin + rcases le_or_lt m n with hmn | hmn, + { rw geom_sum_Ico' h'x.ne hmn, + apply div_le_div (pow_nonneg hx _) _ (sub_pos.2 h'x) le_rfl, + simpa using pow_nonneg hx _ }, + { rw [Ico_eq_empty, sum_empty], + { apply div_nonneg (pow_nonneg hx _), + simpa using h'x.le }, + { simpa using hmn.le } }, +end + lemma geom_sum_inv [division_ring α] {x : α} (hx1 : x ≠ 1) (hx0 : x ≠ 0) (n : ℕ) : (geom_sum x⁻¹ n) = (x - 1)⁻¹ * (x - x⁻¹ ^ n * x) := have h₁ : x⁻¹ ≠ 1, by rwa [inv_eq_one_div, ne.def, div_eq_iff_mul_eq hx0, one_mul], diff --git a/src/algebra/group_power/basic.lean b/src/algebra/group_power/basic.lean index d1367eef908e2..090a1761bcd98 100644 --- a/src/algebra/group_power/basic.lean +++ b/src/algebra/group_power/basic.lean @@ -364,6 +364,9 @@ variables [comm_semiring R] lemma add_sq (a b : R) : (a + b) ^ 2 = a ^ 2 + 2 * a * b + b ^ 2 := by simp only [sq, add_mul_self_eq] +lemma add_sq' (a b : R) : (a + b) ^ 2 = a ^ 2 + b ^ 2 + 2 * a * b := +by rw [add_sq, add_assoc, add_comm _ (b ^ 2), add_assoc] + alias add_sq ← add_pow_two end comm_semiring @@ -427,6 +430,9 @@ by rw [sub_eq_add_neg, add_sq, neg_sq, mul_neg, ← sub_eq_add_neg] alias sub_sq ← sub_pow_two +lemma sub_sq' (a b : R) : (a - b) ^ 2 = a ^ 2 + b ^ 2 - 2 * a * b := +by rw [sub_eq_add_neg, add_sq', neg_sq, mul_neg, ← sub_eq_add_neg] + /- Copies of the above comm_ring lemmas for `units R`. -/ namespace units diff --git a/src/algebra/order/floor.lean b/src/algebra/order/floor.lean index a0fc7fcb5026b..d3e49d8fe92a4 100644 --- a/src/algebra/order/floor.lean +++ b/src/algebra/order/floor.lean @@ -127,6 +127,9 @@ begin { exact le_floor_iff ha } end +@[simp] lemma one_le_floor_iff (x : α) : 1 ≤ ⌊x⌋₊ ↔ 1 ≤ x := +by exact_mod_cast (@le_floor_iff' α _ _ x 1 one_ne_zero) + lemma floor_lt' (hn : n ≠ 0) : ⌊a⌋₊ < n ↔ a < n := lt_iff_lt_of_le_iff_le $ le_floor_iff' hn lemma floor_pos : 0 < ⌊a⌋₊ ↔ 1 ≤ a := diff --git a/src/algebra/order/group.lean b/src/algebra/order/group.lean index 9d8eb627db075..ef151b9840a5d 100644 --- a/src/algebra/order/group.lean +++ b/src/algebra/order/group.lean @@ -1091,6 +1091,9 @@ begin ... ≤ a : (neg_neg a).le } end +lemma neg_abs_le_neg (a : α) : -|a| ≤ -a := +by simpa using neg_abs_le_self (-a) + lemma abs_nonneg (a : α) : 0 ≤ |a| := (le_total 0 a).elim (λ h, h.trans (le_abs_self a)) (λ h, (neg_nonneg.2 h).trans $ neg_le_abs_self a) diff --git a/src/data/finset/locally_finite.lean b/src/data/finset/locally_finite.lean index d27ce710a0f4b..462782b038ba2 100644 --- a/src/data/finset/locally_finite.lean +++ b/src/data/finset/locally_finite.lean @@ -373,6 +373,10 @@ lemma Ico_union_Ico_eq_Ico {a b c : α} (hab : a ≤ b) (hbc : b ≤ c) : Ico a b ∪ Ico b c = Ico a c := by rw [←coe_inj, coe_union, coe_Ico, coe_Ico, coe_Ico, set.Ico_union_Ico_eq_Ico hab hbc] +@[simp] lemma Ioc_union_Ioc_eq_Ioc {a b c : α} (h₁ : a ≤ b) (h₂ : b ≤ c) : + Ioc a b ∪ Ioc b c = Ioc a c := +by rw [←coe_inj, coe_union, coe_Ioc, coe_Ioc, coe_Ioc, set.Ioc_union_Ioc_eq_Ioc h₁ h₂] + lemma Ico_subset_Ico_union_Ico {a b c : α} : Ico a c ⊆ Ico a b ∪ Ico b c := by { rw [←coe_subset, coe_union, coe_Ico, coe_Ico, coe_Ico], exact set.Ico_subset_Ico_union_Ico } diff --git a/src/data/nat/interval.lean b/src/data/nat/interval.lean index fa5fa41db7229..4c78cfffd66ed 100644 --- a/src/data/nat/interval.lean +++ b/src/data/nat/interval.lean @@ -121,6 +121,9 @@ by { ext x, rw [mem_Ico, mem_Ioc, succ_le_iff, lt_succ_iff] } @[simp] lemma Ico_pred_singleton {a : ℕ} (h : 0 < a) : Ico (a - 1) a = {a - 1} := by rw [←Icc_pred_right _ h, Icc_self] +@[simp] lemma Ioc_succ_singleton : Ioc b (b + 1) = {b+1} := +by rw [← nat.Icc_succ_left, Icc_self] + variables {a b c} lemma Ico_succ_right_eq_insert_Ico (h : a ≤ b) : Ico a (b + 1) = insert b (Ico a b) := From 0420dd88ddad1db7840cf1b68f72211ba0818a50 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sat, 30 Apr 2022 16:49:17 +0000 Subject: [PATCH 345/373] chore(measure_theory/measurable_space_def): make measurable_space arguments implicit (#13832) --- src/measure_theory/measurable_space.lean | 8 ++++---- src/measure_theory/measurable_space_def.lean | 14 +++++++------- src/probability/stopping.lean | 11 +++++------ 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/measure_theory/measurable_space.lean b/src/measure_theory/measurable_space.lean index 669c6da6ce487..8f41f84ede036 100644 --- a/src/measure_theory/measurable_space.lean +++ b/src/measure_theory/measurable_space.lean @@ -484,11 +484,11 @@ m₁.comap prod.fst ⊔ m₂.comap prod.snd instance {α β} [m₁ : measurable_space α] [m₂ : measurable_space β] : measurable_space (α × β) := m₁.prod m₂ -@[measurability] lemma measurable_fst [measurable_space α] [measurable_space β] : +@[measurability] lemma measurable_fst {ma : measurable_space α} {mb : measurable_space β} : measurable (prod.fst : α × β → α) := measurable.of_comap_le le_sup_left -@[measurability] lemma measurable_snd [measurable_space α] [measurable_space β] : +@[measurability] lemma measurable_snd {ma : measurable_space α} {mb : measurable_space β} : measurable (prod.snd : α × β → β) := measurable.of_comap_le le_sup_right @@ -561,8 +561,8 @@ lemma measurable_set_prod_of_nonempty {s : set α} {t : set β} (h : (s ×ˢ t : begin rcases h with ⟨⟨x, y⟩, hx, hy⟩, refine ⟨λ hst, _, λ h, h.1.prod h.2⟩, - have : measurable_set ((λ x, (x, y)) ⁻¹' s ×ˢ t) := measurable_id.prod_mk measurable_const hst, - have : measurable_set (prod.mk x ⁻¹' s ×ˢ t) := measurable_const.prod_mk measurable_id hst, + have : measurable_set ((λ x, (x, y)) ⁻¹' s ×ˢ t) := measurable_prod_mk_right hst, + have : measurable_set (prod.mk x ⁻¹' s ×ˢ t) := measurable_prod_mk_left hst, simp * at * end diff --git a/src/measure_theory/measurable_space_def.lean b/src/measure_theory/measurable_space_def.lean index f554b603bf85f..c136d5f854c29 100644 --- a/src/measure_theory/measurable_space_def.lean +++ b/src/measure_theory/measurable_space_def.lean @@ -413,21 +413,21 @@ def measurable [measurable_space α] [measurable_space β] (f : α → β) : Pro localized "notation `measurable[` m `]` := @measurable _ _ m _" in measure_theory -variables [measurable_space α] [measurable_space β] [measurable_space γ] +lemma measurable_id {ma : measurable_space α} : measurable (@id α) := λ t, id -lemma measurable_id : measurable (@id α) := λ t, id +lemma measurable_id' {ma : measurable_space α} : measurable (λ a : α, a) := measurable_id -lemma measurable_id' : measurable (λ a : α, a) := measurable_id - -lemma measurable.comp {α β γ} {mα : measurable_space α} {mβ : measurable_space β} +lemma measurable.comp {mα : measurable_space α} {mβ : measurable_space β} {mγ : measurable_space γ} {g : β → γ} {f : α → β} (hg : measurable g) (hf : measurable f) : measurable (g ∘ f) := λ t ht, hf (hg ht) -@[simp] lemma measurable_const {a : α} : measurable (λ b : β, a) := +@[simp] lemma measurable_const {ma : measurable_space α} {mb : measurable_space β} {a : α} : + measurable (λ b : β, a) := assume s hs, measurable_set.const (a ∈ s) -lemma measurable.le {α} {m m0 : measurable_space α} (hm : m ≤ m0) {f : α → β} +lemma measurable.le {α} {m m0 : measurable_space α} {mb : measurable_space β} (hm : m ≤ m0) + {f : α → β} (hf : measurable[m] f) : measurable[m0] f := λ s hs, hm _ (hf hs) diff --git a/src/probability/stopping.lean b/src/probability/stopping.lean index 7b01e38ef3a41..97497ec283991 100644 --- a/src/probability/stopping.lean +++ b/src/probability/stopping.lean @@ -267,7 +267,7 @@ begin intro i, have : u i = (λ p : set.Iic i × α, u p.1 p.2) ∘ (λ x, (⟨i, set.mem_Iic.mpr le_rfl⟩, x)) := rfl, rw this, - exact (h i).comp_measurable ((@measurable_const _ _ _ (f i) _).prod_mk (@measurable_id _ (f i))), + exact (h i).comp_measurable measurable_prod_mk_left, end protected lemma comp {t : ι → α → ι} [topological_space ι] [borel_space ι] [metrizable_space ι] @@ -280,7 +280,7 @@ begin = (λ p : ↥(set.Iic i) × α, u (p.fst : ι) p.snd) ∘ (λ p : ↥(set.Iic i) × α, (⟨t (p.fst : ι) p.snd, set.mem_Iic.mpr ((ht_le _ _).trans p.fst.prop)⟩, p.snd)) := rfl, rw this, - exact (h i).comp_measurable ((ht i).measurable.subtype_mk.prod_mk (@measurable_snd _ _ _ (f i))), + exact (h i).comp_measurable ((ht i).measurable.subtype_mk.prod_mk measurable_snd), end section arithmetic @@ -715,7 +715,7 @@ begin rw h_set_eq, suffices h_meas : @measurable _ _ (m_set s) (f i) (λ x : s, (x : set.Iic i × α).snd), from h_meas (f.mono (min_le_left _ _) _ (hτ.measurable_set_le (min i j))), - exact (@measurable_snd _ _ _ (f i)).comp (@measurable_subtype_coe _ m_prod _), }, + exact measurable_snd.comp (@measurable_subtype_coe _ m_prod _), }, { suffices h_min_eq_left : (λ x : sᶜ, min ↑((x : set.Iic i × α).fst) (τ (x : set.Iic i × α).snd)) = λ x : sᶜ, ↑((x : set.Iic i × α).fst), { rw [set.restrict, h_min_eq_left], @@ -798,10 +798,9 @@ begin { suffices h_meas : measurable[measurable_space.prod _ (f i)] (λ a : ↥(set.Iic i) × α, (a.fst : ℕ)), from h_meas (measurable_set_singleton j), - exact (@measurable_fst _ α _ (f i)).subtype_coe, }, + exact measurable_fst.subtype_coe, }, { have h_le : j ≤ i, from finset.mem_range_succ_iff.mp hj, - exact (strongly_measurable.mono (h j) (f.mono h_le)).comp_measurable - (@measurable_snd _ α _ (f i)), }, + exact (strongly_measurable.mono (h j) (f.mono h_le)).comp_measurable measurable_snd, }, { exact strongly_measurable_const, }, end From 49342e3d19939aff27974fccc0b84b5e6cf053ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Sat, 30 Apr 2022 20:50:46 +0000 Subject: [PATCH 346/373] feat(set_theory/cardinal/basic): Add `simp` lemmas on `cardinal.sum` (#13838) --- src/set_theory/cardinal/basic.lean | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/set_theory/cardinal/basic.lean b/src/set_theory/cardinal/basic.lean index 82d617ba876f9..b805d1ef2fffc 100644 --- a/src/set_theory/cardinal/basic.lean +++ b/src/set_theory/cardinal/basic.lean @@ -621,6 +621,15 @@ theorem sum_const' (ι : Type u) (a : cardinal.{u}) : sum (λ _:ι, a) = #ι * a by simpa only [mk_sigma, mk_sum, mk_out, lift_id] using mk_congr (equiv.sigma_sum_distrib (quotient.out ∘ f) (quotient.out ∘ g)) +@[simp] theorem sum_add_distrib' {ι} (f g : ι → cardinal) : + cardinal.sum (λ i, f i + g i) = sum f + sum g := +sum_add_distrib f g + +@[simp] theorem lift_sum {ι : Type u} (f : ι → cardinal.{v}) : + cardinal.lift.{w} (cardinal.sum f) = cardinal.sum (λ i, cardinal.lift.{w} (f i)) := +equiv.cardinal_eq $ equiv.ulift.trans $ equiv.sigma_congr_right $ λ a, nonempty.some $ + by rw [←lift_mk_eq, mk_out, mk_out, lift_lift] + theorem sum_le_sum {ι} (f g : ι → cardinal) (H : ∀ i, f i ≤ g i) : sum f ≤ sum g := ⟨(embedding.refl _).sigma_map $ λ i, classical.choice $ by have := H i; rwa [← quot.out_eq (f i), ← quot.out_eq (g i)] at this⟩ From 4b92515b992fd2f7a7d68daece84fe5c2cfdc5a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Sun, 1 May 2022 03:00:28 +0000 Subject: [PATCH 347/373] chore(set_theory/game/impartial): golf (#13841) --- src/set_theory/game/impartial.lean | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/set_theory/game/impartial.lean b/src/set_theory/game/impartial.lean index dc978fcf3594c..995875c1bfe8a 100644 --- a/src/set_theory/game/impartial.lean +++ b/src/set_theory/game/impartial.lean @@ -24,20 +24,12 @@ local infix ` ≈ ` := equiv /-- The definition for a impartial game, defined using Conway induction -/ def impartial_aux : pgame → Prop -| G := G ≈ -G ∧ (∀ i, impartial_aux (G.move_left i)) ∧ (∀ j, impartial_aux (G.move_right j)) +| G := G ≈ -G ∧ (∀ i, impartial_aux (G.move_left i)) ∧ ∀ j, impartial_aux (G.move_right j) using_well_founded { dec_tac := pgame_wf_tac } lemma impartial_aux_def {G : pgame} : G.impartial_aux ↔ G ≈ -G ∧ - (∀ i, impartial_aux (G.move_left i)) ∧ (∀ j, impartial_aux (G.move_right j)) := -begin - split, - { intro hi, - unfold1 impartial_aux at hi, - exact hi }, - { intro hi, - unfold1 impartial_aux, - exact hi } -end + (∀ i, impartial_aux (G.move_left i)) ∧ ∀ j, impartial_aux (G.move_right j) := +by rw impartial_aux /-- A typeclass on impartial games. -/ class impartial (G : pgame) : Prop := (out : impartial_aux G) @@ -46,7 +38,7 @@ lemma impartial_iff_aux {G : pgame} : G.impartial ↔ G.impartial_aux := ⟨λ h, h.1, λ h, ⟨h⟩⟩ lemma impartial_def {G : pgame} : G.impartial ↔ G ≈ -G ∧ - (∀ i, impartial (G.move_left i)) ∧ (∀ j, impartial (G.move_right j)) := + (∀ i, impartial (G.move_left i)) ∧ ∀ j, impartial (G.move_right j) := by simpa only [impartial_iff_aux] using impartial_aux_def namespace impartial From 51b1e1187e4b9d32c9155d89933eaff978632c25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Sun, 1 May 2022 03:35:34 +0000 Subject: [PATCH 348/373] feat(set_theory/game/impartial): Relabelling of impartial game is impartial (#13843) --- src/set_theory/game/impartial.lean | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/set_theory/game/impartial.lean b/src/set_theory/game/impartial.lean index 995875c1bfe8a..caabd4e82dbc4 100644 --- a/src/set_theory/game/impartial.lean +++ b/src/set_theory/game/impartial.lean @@ -56,6 +56,19 @@ instance move_right_impartial {G : pgame} [h : G.impartial] (j : G.right_moves) (G.move_right j).impartial := (impartial_def.1 h).2.2 j +theorem impartial_congr : ∀ {G H : pgame} (e : relabelling G H) [G.impartial], H.impartial +| G H e := begin + introI h, + rw impartial_def, + refine ⟨equiv_trans e.symm.equiv (equiv_trans (neg_equiv_self G) (neg_congr e.equiv)), + λ i, _, λ j, _⟩; + cases e with _ _ L R hL hR, + { convert impartial_congr (hL (L.symm i)), + rw equiv.apply_symm_apply }, + { exact impartial_congr (hR j) } +end +using_well_founded { dec_tac := pgame_wf_tac } + instance impartial_add : ∀ (G H : pgame) [G.impartial] [H.impartial], (G + H).impartial | G H := begin From 232c15e53f32964e5a05ccaa3bec80cebef66ad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Sun, 1 May 2022 05:59:37 +0000 Subject: [PATCH 349/373] feat(set_theory/game/pgame): Add missing basic API (#13744) --- src/set_theory/game/pgame.lean | 151 +++++++++++++++++++-------------- 1 file changed, 87 insertions(+), 64 deletions(-) diff --git a/src/set_theory/game/pgame.lean b/src/set_theory/game/pgame.lean index 9def04ac006a2..9a276e4101443 100644 --- a/src/set_theory/game/pgame.lean +++ b/src/set_theory/game/pgame.lean @@ -120,15 +120,6 @@ inductive pgame : Type (u+1) namespace pgame -/-- -Construct a pre-game from list of pre-games describing the available moves for Left and Right. --/ --- TODO provide some API describing the interaction with --- `left_moves`, `right_moves`, `move_left` and `move_right` below. --- TODO define this at the level of games, as well, and perhaps also for finsets of games. -def of_lists (L R : list pgame.{0}) : pgame.{0} := -pgame.mk (fin L.length) (fin R.length) (λ i, L.nth_le i i.is_lt) (λ j, R.nth_le j.val j.is_lt) - /-- The indexing type for allowable moves by Left. -/ def left_moves : pgame → Type u | (mk l _ _ _) := l @@ -148,6 +139,45 @@ def move_right : Π (g : pgame), right_moves g → pgame @[simp] lemma right_moves_mk {xl xr xL xR} : (⟨xl, xr, xL, xR⟩ : pgame).right_moves = xr := rfl @[simp] lemma move_right_mk {xl xr xL xR} : (⟨xl, xr, xL, xR⟩ : pgame).move_right = xR := rfl +/-- +Construct a pre-game from list of pre-games describing the available moves for Left and Right. +-/ +-- TODO define this at the level of games, as well, and perhaps also for finsets of games. +def of_lists (L R : list pgame.{u}) : pgame.{u} := +mk (ulift (fin L.length)) (ulift (fin R.length)) + (λ i, L.nth_le i.down i.down.is_lt) (λ j, R.nth_le j.down.val j.down.is_lt) + +lemma left_moves_of_lists (L R : list pgame) : (of_lists L R).left_moves = ulift (fin L.length) := +rfl +lemma right_moves_of_lists (L R : list pgame) : (of_lists L R).right_moves = ulift (fin R.length) := +rfl + +/-- Converts a number into a left move for `of_lists`. -/ +def to_of_lists_left_moves {L R : list pgame} : fin L.length ≃ (of_lists L R).left_moves := +((equiv.cast (left_moves_of_lists L R).symm).trans equiv.ulift).symm + +/-- Converts a number into a right move for `of_lists`. -/ +def to_of_lists_right_moves {L R : list pgame} : fin R.length ≃ (of_lists L R).right_moves := +((equiv.cast (right_moves_of_lists L R).symm).trans equiv.ulift).symm + +theorem of_lists_move_left {L R : list pgame} (i : fin L.length) : + (of_lists L R).move_left (to_of_lists_left_moves i) = L.nth_le i i.is_lt := +rfl + +@[simp] theorem of_lists_move_left' {L R : list pgame} (i : (of_lists L R).left_moves) : + (of_lists L R).move_left i = + L.nth_le (to_of_lists_left_moves.symm i) (to_of_lists_left_moves.symm i).is_lt := +rfl + +theorem of_lists_move_right {L R : list pgame} (i : fin R.length) : + (of_lists L R).move_right (to_of_lists_right_moves i) = R.nth_le i i.is_lt := +rfl + +@[simp] theorem of_lists_move_right' {L R : list pgame} (i : (of_lists L R).right_moves) : + (of_lists L R).move_right i = + R.nth_le (to_of_lists_right_moves.symm i) (to_of_lists_right_moves.symm i).is_lt := +rfl + /-- A variant of `pgame.rec_on` expressed in terms of `pgame.move_left` and `pgame.move_right`. Both this and `pgame.rec_on` describe Conway induction on games. -/ @@ -217,22 +247,23 @@ meta def pgame_wf_tac := /-- The pre-game `zero` is defined by `0 = { | }`. -/ instance : has_zero pgame := ⟨⟨pempty, pempty, pempty.elim, pempty.elim⟩⟩ -@[simp] lemma zero_left_moves : (0 : pgame).left_moves = pempty := rfl -@[simp] lemma zero_right_moves : (0 : pgame).right_moves = pempty := rfl +@[simp] lemma zero_left_moves : left_moves 0 = pempty := rfl +@[simp] lemma zero_right_moves : right_moves 0 = pempty := rfl -instance is_empty_zero_left_moves : is_empty (0 : pgame).left_moves := pempty.is_empty -instance is_empty_zero_right_moves : is_empty (0 : pgame).right_moves := pempty.is_empty +instance is_empty_zero_left_moves : is_empty (left_moves 0) := pempty.is_empty +instance is_empty_zero_right_moves : is_empty (right_moves 0) := pempty.is_empty instance : inhabited pgame := ⟨0⟩ /-- The pre-game `one` is defined by `1 = { 0 | }`. -/ instance : has_one pgame := ⟨⟨punit, pempty, λ _, 0, pempty.elim⟩⟩ -@[simp] lemma one_left_moves : (1 : pgame).left_moves = punit := rfl -@[simp] lemma one_move_left : (1 : pgame).move_left punit.star = 0 := rfl -@[simp] lemma one_right_moves : (1 : pgame).right_moves = pempty := rfl +@[simp] lemma one_left_moves : left_moves 1 = punit := rfl +@[simp] lemma one_move_left (x) : move_left 1 x = 0 := rfl +@[simp] lemma one_right_moves : right_moves 1 = pempty := rfl -instance is_empty_one_right_moves : is_empty (1 : pgame).right_moves := pempty.is_empty +instance unique_one_left_moves : unique (left_moves 1) := punit.unique +instance is_empty_one_right_moves : is_empty (right_moves 1) := pempty.is_empty /-- Define simultaneously by mutual induction the `<=` and `<` relation on pre-games. The ZFC definition says that `x = {xL | xR}` @@ -308,38 +339,28 @@ end /-- The definition of `x ≤ 0` on pre-games, in terms of `≤ 0` two moves later. -/ theorem le_zero {x : pgame} : x ≤ 0 ↔ ∀ i : x.left_moves, ∃ j : (x.move_left i).right_moves, (x.move_left i).move_right j ≤ 0 := -begin - rw le_def, - dsimp, - simp [forall_pempty, exists_pempty] -end +by { rw le_def, dsimp, simp [forall_pempty, exists_pempty] } /-- The definition of `0 ≤ x` on pre-games, in terms of `0 ≤` two moves later. -/ theorem zero_le {x : pgame} : 0 ≤ x ↔ ∀ j : x.right_moves, ∃ i : (x.move_right j).left_moves, 0 ≤ (x.move_right j).move_left i := -begin - rw le_def, - dsimp, - simp [forall_pempty, exists_pempty] -end +by { rw le_def, dsimp, simp [forall_pempty, exists_pempty] } /-- The definition of `x < 0` on pre-games, in terms of `< 0` two moves later. -/ theorem lt_zero {x : pgame} : x < 0 ↔ ∃ j : x.right_moves, ∀ i : (x.move_right j).left_moves, (x.move_right j).move_left i < 0 := -begin - rw lt_def, - dsimp, - simp [forall_pempty, exists_pempty] -end +by { rw lt_def, dsimp, simp [forall_pempty, exists_pempty] } /-- The definition of `0 < x` on pre-games, in terms of `< x` two moves later. -/ theorem zero_lt {x : pgame} : 0 < x ↔ ∃ i : x.left_moves, ∀ j : (x.move_left i).right_moves, 0 < (x.move_left i).move_right j := -begin - rw lt_def, - dsimp, - simp [forall_pempty, exists_pempty] -end +by { rw lt_def, dsimp, simp [forall_pempty, exists_pempty] } + +@[simp] theorem le_zero_of_is_empty_left_moves (x : pgame) [is_empty x.left_moves] : x ≤ 0 := +le_zero.2 is_empty_elim + +@[simp] theorem zero_le_of_is_empty_right_moves (x : pgame) [is_empty x.right_moves] : 0 ≤ x := +zero_le.2 is_empty_elim /-- Given a right-player-wins game, provide a response to any move by left. -/ noncomputable def right_response {x : pgame} (h : x ≤ 0) (i : x.left_moves) : @@ -1105,54 +1126,56 @@ theorem lt_iff_sub_pos {x y : pgame} : x < y ↔ 0 < y - x := ... ≤ y : (add_zero_relabelling y).le⟩ /-- The pre-game `star`, which is fuzzy/confused with zero. -/ -def star : pgame := pgame.of_lists [0] [0] +def star : pgame.{u} := of_lists [0] [0] -instance inhabited_star_left_moves : inhabited star.left_moves := -show (inhabited (fin 1)), by apply_instance +@[simp] theorem star_left_moves : star.left_moves = ulift (fin 1) := rfl +@[simp] theorem star_right_moves : star.right_moves = ulift (fin 1) := rfl -instance inhabited_star_right_moves : inhabited star.right_moves := -show (inhabited (fin 1)), by apply_instance +@[simp] theorem star_move_left (x) : star.move_left x = 0 := +show (of_lists _ _).move_left x = 0, by simp +@[simp] theorem star_move_right (x) : star.move_right x = 0 := +show (of_lists _ _).move_right x = 0, by simp -theorem star_lt_zero : star < 0 := -by rw lt_def; exact -or.inr ⟨⟨0, zero_lt_one⟩, (by split; rintros ⟨⟩)⟩ +instance unique_star_left_moves : unique star.left_moves := +@equiv.unique _ (fin 1) _ equiv.ulift +instance unique_star_right_moves : unique star.right_moves := +@equiv.unique _ (fin 1) _ equiv.ulift +theorem star_lt_zero : star < 0 := +by { rw lt_zero, use default, rintros ⟨⟩ } theorem zero_lt_star : 0 < star := -by rw lt_def; exact -or.inl ⟨⟨0, zero_lt_one⟩, (by split; rintros ⟨⟩)⟩ +by { rw zero_lt, use default, rintros ⟨⟩ } /-- The pre-game `ω`. (In fact all ordinals have game and surreal representatives.) -/ def omega : pgame := ⟨ulift ℕ, pempty, λ n, ↑n.1, pempty.elim⟩ -theorem zero_lt_one : (0 : pgame) < 1 := -begin - rw lt_def, - left, - use ⟨punit.star, by split; rintro ⟨ ⟩⟩, -end +@[simp] theorem zero_lt_one : (0 : pgame) < 1 := +by { rw zero_lt, use default, rintro ⟨⟩ } + +theorem zero_le_one : (0 : pgame) ≤ 1 := +zero_le_of_is_empty_right_moves 1 /-- The pre-game `half` is defined as `{0 | 1}`. -/ def half : pgame := ⟨punit, punit, 0, 1⟩ -@[simp] lemma half_move_left : half.move_left punit.star = 0 := rfl +@[simp] theorem half_left_moves : half.left_moves = punit := rfl +@[simp] theorem half_right_moves : half.right_moves = punit := rfl +@[simp] lemma half_move_left (x) : half.move_left x = 0 := rfl +@[simp] lemma half_move_right (x) : half.move_right x = 1 := rfl -@[simp] lemma half_move_right : half.move_right punit.star = 1 := rfl +instance unique_half_left_moves : unique half.left_moves := punit.unique +instance unique_half_right_moves : unique half.right_moves := punit.unique protected theorem zero_lt_half : 0 < half := -begin - rw lt_def, - left, - use punit.star, - split; rintro ⟨ ⟩, -end +by { rw zero_lt, use default, rintro ⟨⟩ } theorem half_lt_one : half < 1 := begin rw lt_def, right, - use punit.star, - split; rintro ⟨ ⟩, - exact zero_lt_one, + use default, + split; rintro ⟨⟩, + exact zero_lt_one end end pgame From 9e7c80f638149bfb3504ba8ff48dfdbfc949fb1a Mon Sep 17 00:00:00 2001 From: Joachim Breitner Date: Sun, 1 May 2022 12:36:26 +0000 Subject: [PATCH 350/373] =?UTF-8?q?docs(*):=20Wrap=20some=20links=20in=20=20(#13852)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I noticed that many docs say See https://stacks.math.columbia.edu/tag/001T. and the our documentation will include the final `.` in the URL, causing the URL to not work. This tries to fix some of these instances. I intentionally applied this to some URLs ending with a space, because it does not hurt to be explicit, and the next contributor cargo-culting the URL is more likely to get this right. Obligatory xkcd reference: https://xkcd.com/208/ --- CODE_OF_CONDUCT.md | 4 ++-- src/algebraic_geometry/ringed_space.lean | 2 +- src/category_theory/abelian/basic.lean | 2 +- src/category_theory/abelian/images.lean | 2 +- src/category_theory/abelian/transfer.lean | 4 ++-- src/category_theory/additive/basic.lean | 2 +- src/category_theory/adjunction/basic.lean | 4 ++-- src/category_theory/adjunction/fully_faithful.lean | 2 +- src/category_theory/adjunction/limits.lean | 4 ++-- src/category_theory/category/basic.lean | 6 +++--- src/category_theory/category/preorder.lean | 2 +- src/category_theory/discrete_category.lean | 2 +- src/category_theory/equivalence.lean | 10 +++++----- src/category_theory/essential_image.lean | 2 +- src/category_theory/filtered.lean | 4 ++-- src/category_theory/full_subcategory.lean | 2 +- src/category_theory/functor/basic.lean | 2 +- src/category_theory/functor/fully_faithful.lean | 4 ++-- src/category_theory/is_connected.lean | 2 +- src/category_theory/isomorphism.lean | 2 +- .../limits_of_products_and_equalizers.lean | 8 ++++---- src/category_theory/limits/final.lean | 2 +- src/category_theory/limits/is_limit.lean | 4 ++-- src/category_theory/limits/presheaf.lean | 2 +- .../limits/shapes/binary_products.lean | 4 ++-- src/category_theory/limits/shapes/pullbacks.lean | 2 +- src/category_theory/limits/types.lean | 4 ++-- src/category_theory/monoidal/braided.lean | 2 +- src/category_theory/monoidal/category.lean | 4 ++-- src/category_theory/monoidal/functor.lean | 4 ++-- src/category_theory/opposites.lean | 2 +- src/category_theory/over.lean | 6 +++--- src/category_theory/products/basic.lean | 2 +- src/category_theory/single_obj.lean | 4 ++-- src/category_theory/sites/canonical.lean | 4 ++-- src/category_theory/sites/cover_lifting.lean | 2 +- src/category_theory/sites/cover_preserving.lean | 2 +- src/category_theory/sites/grothendieck.lean | 14 +++++++------- src/category_theory/sites/plus.lean | 2 +- src/category_theory/sites/pretopology.lean | 4 ++-- src/category_theory/sites/sheaf.lean | 10 +++++----- src/category_theory/sites/sheaf_of_types.lean | 14 +++++++------- src/category_theory/triangulated/basic.lean | 4 ++-- .../triangulated/pretriangulated.lean | 10 +++++----- src/category_theory/types.lean | 4 ++-- src/category_theory/yoneda.lean | 12 ++++++------ src/topology/category/Top/limits.lean | 2 +- src/topology/sheaves/forget.lean | 2 +- src/topology/sheaves/sheafify.lean | 2 +- src/topology/tietze_extension.lean | 2 +- 50 files changed, 102 insertions(+), 102 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index bae66ebfcf6e4..a12ebc6fe6930 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -126,5 +126,5 @@ enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. +. Translations are available at +. diff --git a/src/algebraic_geometry/ringed_space.lean b/src/algebraic_geometry/ringed_space.lean index 5160fbe37e580..fc0c6a260b7eb 100644 --- a/src/algebraic_geometry/ringed_space.lean +++ b/src/algebraic_geometry/ringed_space.lean @@ -15,7 +15,7 @@ import algebra.category.CommRing.limits We introduce the category of ringed spaces, as an alias for `SheafedSpace CommRing`. The facts collected in this file are typically stated for locally ringed spaces, but never actually -make use of the locality of stalks. See for instance https://stacks.math.columbia.edu/tag/01HZ. +make use of the locality of stalks. See for instance . -/ diff --git a/src/category_theory/abelian/basic.lean b/src/category_theory/abelian/basic.lean index 3e9216d0c35ea..053e568b72859 100644 --- a/src/category_theory/abelian/basic.lean +++ b/src/category_theory/abelian/basic.lean @@ -244,7 +244,7 @@ in which the coimage-image comparison morphism is always an isomorphism, is an abelian category. The Stacks project uses this characterisation at the definition of an abelian category. -See https://stacks.math.columbia.edu/tag/0109. +See . -/ def of_coimage_image_comparison_is_iso : abelian C := {} diff --git a/src/category_theory/abelian/images.lean b/src/category_theory/abelian/images.lean index 5c840a792222a..5e2d2a2bf1c46 100644 --- a/src/category_theory/abelian/images.lean +++ b/src/category_theory/abelian/images.lean @@ -85,7 +85,7 @@ In any abelian category this is an isomorphism. Conversely, any additive category with kernels and cokernels and in which this is always an isomorphism, is abelian. -See https://stacks.math.columbia.edu/tag/0107 +See -/ def coimage_image_comparison : abelian.coimage f ⟶ abelian.image f := cokernel.desc (kernel.ι f) (kernel.lift (cokernel.π f) f (by simp)) $ (by { ext, simp, }) diff --git a/src/category_theory/abelian/transfer.lean b/src/category_theory/abelian/transfer.lean index 433fca2d8a7ad..80335de073b91 100644 --- a/src/category_theory/abelian/transfer.lean +++ b/src/category_theory/abelian/transfer.lean @@ -17,7 +17,7 @@ we have `F : C ⥤ D` `G : D ⥤ C` (both preserving zero morphisms), and further we have `adj : G ⊣ F` and `i : F ⋙ G ≅ 𝟭 C`, then `C` is also abelian. -See https://stacks.math.columbia.edu/tag/03A3 +See ## Notes The hypotheses, following the statement from the Stacks project, @@ -153,7 +153,7 @@ we have `F : C ⥤ D` `G : D ⥤ C` (both preserving zero morphisms), and further we have `adj : G ⊣ F` and `i : F ⋙ G ≅ 𝟭 C`, then `C` is also abelian. -See https://stacks.math.columbia.edu/tag/03A3 +See -/ def abelian_of_adjunction {C : Type u₁} [category.{v} C] [preadditive C] [has_finite_products C] diff --git a/src/category_theory/additive/basic.lean b/src/category_theory/additive/basic.lean index 0180be4aef429..c232f535f81d7 100644 --- a/src/category_theory/additive/basic.lean +++ b/src/category_theory/additive/basic.lean @@ -30,7 +30,7 @@ variables (C : Type u) [category C] /-- A preadditive category `C` is called additive if it has all finite biproducts. -See https://stacks.math.columbia.edu/tag/0104. +See . -/ class additive_category extends preadditive C, has_finite_biproducts C diff --git a/src/category_theory/adjunction/basic.lean b/src/category_theory/adjunction/basic.lean index eecbf938c42fd..ed35f987c3e54 100644 --- a/src/category_theory/adjunction/basic.lean +++ b/src/category_theory/adjunction/basic.lean @@ -52,7 +52,7 @@ well as their duals) which can be simpler in practice. Uniqueness of adjoints is shown in `category_theory.adjunction.opposites`. -See https://stacks.math.columbia.edu/tag/0037. +See . -/ structure adjunction (F : C ⥤ D) (G : D ⥤ C) := (hom_equiv : Π (X Y), (F.obj X ⟶ Y) ≃ (X ⟶ G.obj Y)) @@ -331,7 +331,7 @@ variables {E : Type u₃} [ℰ : category.{v₃} E] (H : D ⥤ E) (I : E ⥤ D) /-- Composition of adjunctions. -See https://stacks.math.columbia.edu/tag/0DV0. +See . -/ def comp (adj₁ : F ⊣ G) (adj₂ : H ⊣ I) : F ⋙ H ⊣ I ⋙ G := { hom_equiv := λ X Z, equiv.trans (adj₂.hom_equiv _ _) (adj₁.hom_equiv _ _), diff --git a/src/category_theory/adjunction/fully_faithful.lean b/src/category_theory/adjunction/fully_faithful.lean index 138bb6f679d0a..ca29238caf89b 100644 --- a/src/category_theory/adjunction/fully_faithful.lean +++ b/src/category_theory/adjunction/fully_faithful.lean @@ -59,7 +59,7 @@ instance unit_is_iso_of_L_fully_faithful [full L] [faithful L] : is_iso (adjunct /-- If the right adjoint is fully faithful, then the counit is an isomorphism. -See https://stacks.math.columbia.edu/tag/07RB (we only prove the forward direction!) +See (we only prove the forward direction!) -/ instance counit_is_iso_of_R_fully_faithful [full R] [faithful R] : is_iso (adjunction.counit h) := @nat_iso.is_iso_of_is_iso_app _ _ _ _ _ _ (adjunction.counit h) $ λ X, diff --git a/src/category_theory/adjunction/limits.lean b/src/category_theory/adjunction/limits.lean index 3e6e4438e2693..686648ef0b180 100644 --- a/src/category_theory/adjunction/limits.lean +++ b/src/category_theory/adjunction/limits.lean @@ -84,7 +84,7 @@ def functoriality_is_left_adjoint : /-- A left adjoint preserves colimits. -See https://stacks.math.columbia.edu/tag/0038. +See . -/ def left_adjoint_preserves_colimits : preserves_colimits_of_size.{v u} F := { preserves_colimits_of_shape := λ J 𝒥, @@ -194,7 +194,7 @@ def functoriality_is_right_adjoint : /-- A right adjoint preserves limits. -See https://stacks.math.columbia.edu/tag/0038. +See . -/ def right_adjoint_preserves_limits : preserves_limits_of_size.{v u} G := { preserves_limits_of_shape := λ J 𝒥, diff --git a/src/category_theory/category/basic.lean b/src/category_theory/category/basic.lean index 0462f0410fe96..dce140c3e53cb 100644 --- a/src/category_theory/category/basic.lean +++ b/src/category_theory/category/basic.lean @@ -87,7 +87,7 @@ The typeclass `category C` describes morphisms associated to objects of type `C` The universe levels of the objects and morphisms are unconstrained, and will often need to be specified explicitly, as `category.{v} C`. (See also `large_category` and `small_category`.) -See https://stacks.math.columbia.edu/tag/0014. +See . -/ class category (obj : Type u) extends category_struct.{v} obj : Type (max u (v+1)) := @@ -163,7 +163,7 @@ by { split_ifs; refl } A morphism `f` is an epimorphism if it can be "cancelled" when precomposed: `f ≫ g = f ≫ h` implies `g = h`. -See https://stacks.math.columbia.edu/tag/003B. +See . -/ class epi (f : X ⟶ Y) : Prop := (left_cancellation : Π {Z : C} (g h : Y ⟶ Z) (w : f ≫ g = f ≫ h), g = h) @@ -172,7 +172,7 @@ class epi (f : X ⟶ Y) : Prop := A morphism `f` is a monomorphism if it can be "cancelled" when postcomposed: `g ≫ f = h ≫ f` implies `g = h`. -See https://stacks.math.columbia.edu/tag/003B. +See . -/ class mono (f : X ⟶ Y) : Prop := (right_cancellation : Π {Z : C} (g h : Z ⟶ X) (w : g ≫ f = h ≫ f), g = h) diff --git a/src/category_theory/category/preorder.lean b/src/category_theory/category/preorder.lean index 2013da60208c6..b5ce286ec3106 100644 --- a/src/category_theory/category/preorder.lean +++ b/src/category_theory/category/preorder.lean @@ -39,7 +39,7 @@ Because we don't allow morphisms to live in `Prop`, we have to define `X ⟶ Y` as `ulift (plift (X ≤ Y))`. See `category_theory.hom_of_le` and `category_theory.le_of_hom`. -See https://stacks.math.columbia.edu/tag/00D3. +See . -/ @[priority 100] -- see Note [lower instance priority] instance small_category (α : Type u) [preorder α] : small_category α := diff --git a/src/category_theory/discrete_category.lean b/src/category_theory/discrete_category.lean index 25fcb1617bc72..f5278f965861a 100644 --- a/src/category_theory/discrete_category.lean +++ b/src/category_theory/discrete_category.lean @@ -47,7 +47,7 @@ The "discrete" category on a type, whose morphisms are equalities. Because we do not allow morphisms in `Prop` (only in `Type`), somewhat annoyingly we have to define `X ⟶ Y` as `ulift (plift (X = Y))`. -See https://stacks.math.columbia.edu/tag/001A +See -/ instance discrete_category (α : Type u₁) : small_category (discrete α) := { hom := λ X Y, ulift (plift (X = Y)), diff --git a/src/category_theory/equivalence.lean b/src/category_theory/equivalence.lean index d6ad677798952..fec19f77119b8 100644 --- a/src/category_theory/equivalence.lean +++ b/src/category_theory/equivalence.lean @@ -71,7 +71,7 @@ universes v₁ v₂ v₃ u₁ u₂ u₃ complicated if we write it as an equality of natural transformations, because then we would have to insert natural transformations like `F ⟶ F1`. -See https://stacks.math.columbia.edu/tag/001J +See -/ structure equivalence (C : Type u₁) [category.{v₁} C] (D : Type u₂) [category.{v₂} D] := mk' :: @@ -557,7 +557,7 @@ namespace equivalence /-- An equivalence is essentially surjective. -See https://stacks.math.columbia.edu/tag/02C3. +See . -/ lemma ess_surj_of_equivalence (F : C ⥤ D) [is_equivalence F] : ess_surj F := ⟨λ Y, ⟨F.inv.obj Y, ⟨F.as_equivalence.counit_iso.app Y⟩⟩⟩ @@ -565,7 +565,7 @@ lemma ess_surj_of_equivalence (F : C ⥤ D) [is_equivalence F] : ess_surj F := /-- An equivalence is faithful. -See https://stacks.math.columbia.edu/tag/02C3. +See . -/ @[priority 100] -- see Note [lower instance priority] instance faithful_of_equivalence (F : C ⥤ D) [is_equivalence F] : faithful F := @@ -578,7 +578,7 @@ instance faithful_of_equivalence (F : C ⥤ D) [is_equivalence F] : faithful F : /-- An equivalence is full. -See https://stacks.math.columbia.edu/tag/02C3. +See . -/ @[priority 100] -- see Note [lower instance priority] instance full_of_equivalence (F : C ⥤ D) [is_equivalence F] : full F := @@ -597,7 +597,7 @@ instance full_of_equivalence (F : C ⥤ D) [is_equivalence F] : full F := /-- A functor which is full, faithful, and essentially surjective is an equivalence. -See https://stacks.math.columbia.edu/tag/02C3. +See . -/ noncomputable def of_fully_faithfully_ess_surj (F : C ⥤ D) [full F] [faithful F] [ess_surj F] : is_equivalence F := diff --git a/src/category_theory/essential_image.lean b/src/category_theory/essential_image.lean index e53f482d68e63..7a832885783c3 100644 --- a/src/category_theory/essential_image.lean +++ b/src/category_theory/essential_image.lean @@ -97,7 +97,7 @@ end functor A functor `F : C ⥤ D` is essentially surjective if every object of `D` is in the essential image of `F`. In other words, for every `Y : D`, there is some `X : C` with `F.obj X ≅ Y`. -See https://stacks.math.columbia.edu/tag/001C. +See . -/ class ess_surj (F : C ⥤ D) : Prop := (mem_ess_image [] (Y : D) : Y ∈ F.ess_image) diff --git a/src/category_theory/filtered.lean b/src/category_theory/filtered.lean index f4b139432d209..72cadd5325b45 100644 --- a/src/category_theory/filtered.lean +++ b/src/category_theory/filtered.lean @@ -74,7 +74,7 @@ A category `is_filtered` if are equal, and 3. there exists some object. -See https://stacks.math.columbia.edu/tag/002V. (They also define a diagram being filtered.) +See . (They also define a diagram being filtered.) -/ class is_filtered extends is_filtered_or_empty C : Prop := [nonempty : nonempty C] @@ -464,7 +464,7 @@ A category `is_cofiltered` if are equal, and 3. there exists some object. -See https://stacks.math.columbia.edu/tag/04AZ. +See . -/ class is_cofiltered extends is_cofiltered_or_empty C : Prop := [nonempty : nonempty C] diff --git a/src/category_theory/full_subcategory.lean b/src/category_theory/full_subcategory.lean index 968d9298212b5..8bbbfda80519a 100644 --- a/src/category_theory/full_subcategory.lean +++ b/src/category_theory/full_subcategory.lean @@ -83,7 +83,7 @@ variables (Z : C → Prop) /-- The category structure on a subtype; morphisms just ignore the property. -See https://stacks.math.columbia.edu/tag/001D. We do not define 'strictly full' subcategories. +See . We do not define 'strictly full' subcategories. -/ instance full_subcategory : category.{v} {X : C // Z X} := induced_category.category subtype.val diff --git a/src/category_theory/functor/basic.lean b/src/category_theory/functor/basic.lean index abdaeb300b6b4..377e00e5936bf 100644 --- a/src/category_theory/functor/basic.lean +++ b/src/category_theory/functor/basic.lean @@ -33,7 +33,7 @@ To apply a functor `F` to an object use `F.obj X`, and to a morphism use `F.map The axiom `map_id` expresses preservation of identities, and `map_comp` expresses functoriality. -See https://stacks.math.columbia.edu/tag/001B. +See . -/ structure functor (C : Type u₁) [category.{v₁} C] (D : Type u₂) [category.{v₂} D] extends prefunctor C D : Type (max v₁ v₂ u₁ u₂) := diff --git a/src/category_theory/functor/fully_faithful.lean b/src/category_theory/functor/fully_faithful.lean index dfd7f853ab5cc..085ad8da71383 100644 --- a/src/category_theory/functor/fully_faithful.lean +++ b/src/category_theory/functor/fully_faithful.lean @@ -33,7 +33,7 @@ A functor `F : C ⥤ D` is full if for each `X Y : C`, `F.map` is surjective. In fact, we use a constructive definition, so the `full F` typeclass contains data, specifying a particular preimage of each `f : F.obj X ⟶ F.obj Y`. -See https://stacks.math.columbia.edu/tag/001C. +See . -/ class full (F : C ⥤ D) := (preimage : ∀ {X Y : C} (f : (F.obj X) ⟶ (F.obj Y)), X ⟶ Y) @@ -45,7 +45,7 @@ attribute [simp] full.witness /-- A functor `F : C ⥤ D` is faithful if for each `X Y : C`, `F.map` is injective. -See https://stacks.math.columbia.edu/tag/001C. +See . -/ class faithful (F : C ⥤ D) : Prop := (map_injective' [] : ∀ {X Y : C}, function.injective (@functor.map _ _ _ _ F X Y) . obviously) diff --git a/src/category_theory/is_connected.lean b/src/category_theory/is_connected.lean index 651c26884b19f..72d75ff9dfad0 100644 --- a/src/category_theory/is_connected.lean +++ b/src/category_theory/is_connected.lean @@ -66,7 +66,7 @@ component'. This allows us to show that the functor X ⨯ - preserves connected limits. -See https://stacks.math.columbia.edu/tag/002S +See -/ class is_connected (J : Type u₁) [category.{v₁} J] extends is_preconnected J : Prop := [is_nonempty : nonempty J] diff --git a/src/category_theory/isomorphism.lean b/src/category_theory/isomorphism.lean index 4a2b4c9d50f13..8d3cea33103aa 100644 --- a/src/category_theory/isomorphism.lean +++ b/src/category_theory/isomorphism.lean @@ -43,7 +43,7 @@ The inverse morphism is bundled. See also `category_theory.core` for the category with the same objects and isomorphisms playing the role of morphisms. -See https://stacks.math.columbia.edu/tag/0017. +See . -/ structure iso {C : Type u} [category.{v} C] (X Y : C) := (hom : X ⟶ Y) diff --git a/src/category_theory/limits/constructions/limits_of_products_and_equalizers.lean b/src/category_theory/limits/constructions/limits_of_products_and_equalizers.lean index e78de497fcaa4..eebdabe7770a3 100644 --- a/src/category_theory/limits/constructions/limits_of_products_and_equalizers.lean +++ b/src/category_theory/limits/constructions/limits_of_products_and_equalizers.lean @@ -105,7 +105,7 @@ has_limit.mk /-- Any category with products and equalizers has all limits. -See https://stacks.math.columbia.edu/tag/002N. +See . -/ lemma limits_from_equalizers_and_products [has_products C] [has_equalizers C] : has_limits C := @@ -115,7 +115,7 @@ lemma limits_from_equalizers_and_products /-- Any category with finite products and equalizers has all finite limits. -See https://stacks.math.columbia.edu/tag/002O. +See . -/ lemma finite_limits_from_equalizers_and_finite_products [has_finite_products C] [has_equalizers C] : has_finite_limits C := @@ -266,7 +266,7 @@ has_colimit.mk /-- Any category with coproducts and coequalizers has all colimits. -See https://stacks.math.columbia.edu/tag/002P. +See . -/ lemma colimits_from_coequalizers_and_coproducts [has_coproducts C] [has_coequalizers C] : has_colimits C := @@ -276,7 +276,7 @@ lemma colimits_from_coequalizers_and_coproducts /-- Any category with finite coproducts and coequalizers has all finite colimits. -See https://stacks.math.columbia.edu/tag/002Q. +See . -/ lemma finite_colimits_from_coequalizers_and_finite_coproducts [has_finite_coproducts C] [has_coequalizers C] : has_finite_colimits C := diff --git a/src/category_theory/limits/final.lean b/src/category_theory/limits/final.lean index 058c9d6e88d70..62b3e46f33669 100644 --- a/src/category_theory/limits/final.lean +++ b/src/category_theory/limits/final.lean @@ -73,7 +73,7 @@ variables {D : Type v} [small_category D] A functor `F : C ⥤ D` is final if for every `d : D`, the comma category of morphisms `d ⟶ F.obj c` is connected. -See https://stacks.math.columbia.edu/tag/04E6 +See -/ class final (F : C ⥤ D) : Prop := (out (d : D) : is_connected (structured_arrow d F)) diff --git a/src/category_theory/limits/is_limit.lean b/src/category_theory/limits/is_limit.lean index eef6b6ed46d1a..9b220c75b965f 100644 --- a/src/category_theory/limits/is_limit.lean +++ b/src/category_theory/limits/is_limit.lean @@ -48,7 +48,7 @@ variables {F : J ⥤ C} A cone `t` on `F` is a limit cone if each cone on `F` admits a unique cone morphism to `t`. -See https://stacks.math.columbia.edu/tag/002E. +See . -/ @[nolint has_inhabited_instance] structure is_limit (t : cone F) := @@ -502,7 +502,7 @@ end is_limit A cocone `t` on `F` is a colimit cocone if each cocone on `F` admits a unique cocone morphism from `t`. -See https://stacks.math.columbia.edu/tag/002F. +See . -/ @[nolint has_inhabited_instance] structure is_colimit (t : cocone F) := diff --git a/src/category_theory/limits/presheaf.lean b/src/category_theory/limits/presheaf.lean index 8551db179e293..9139a4069e2cb 100644 --- a/src/category_theory/limits/presheaf.lean +++ b/src/category_theory/limits/presheaf.lean @@ -186,7 +186,7 @@ def is_initial (A : C) : is_initial (elements.initial A) := property (up to isomorphism). The first part of [MM92], Chapter I, Section 5, Corollary 4. -See Property 1 of https://ncatlab.org/nlab/show/Yoneda+extension#properties. +See Property 1 of . -/ def is_extension_along_yoneda : (yoneda : C ⥤ Cᵒᵖ ⥤ Type u₁) ⋙ extend_along_yoneda A ≅ A := nat_iso.of_components diff --git a/src/category_theory/limits/shapes/binary_products.lean b/src/category_theory/limits/shapes/binary_products.lean index c0e5902c4fa9b..2acc45e42b173 100644 --- a/src/category_theory/limits/shapes/binary_products.lean +++ b/src/category_theory/limits/shapes/binary_products.lean @@ -552,14 +552,14 @@ variables (C) /-- `has_binary_products` represents a choice of product for every pair of objects. -See https://stacks.math.columbia.edu/tag/001T. +See . -/ abbreviation has_binary_products := has_limits_of_shape (discrete walking_pair.{v}) C /-- `has_binary_coproducts` represents a choice of coproduct for every pair of objects. -See https://stacks.math.columbia.edu/tag/04AP. +See . -/ abbreviation has_binary_coproducts := has_colimits_of_shape (discrete walking_pair.{v}) C diff --git a/src/category_theory/limits/shapes/pullbacks.lean b/src/category_theory/limits/shapes/pullbacks.lean index c295cde288723..615ed787333fc 100644 --- a/src/category_theory/limits/shapes/pullbacks.lean +++ b/src/category_theory/limits/shapes/pullbacks.lean @@ -2138,7 +2138,7 @@ variables (C) /-- `has_pullbacks` represents a choice of pullback for every pair of morphisms -See https://stacks.math.columbia.edu/tag/001W +See -/ abbreviation has_pullbacks := has_limits_of_shape walking_cospan.{v} C diff --git a/src/category_theory/limits/types.lean b/src/category_theory/limits/types.lean index 86de37bd9c76b..52205fe28709e 100644 --- a/src/category_theory/limits/types.lean +++ b/src/category_theory/limits/types.lean @@ -33,7 +33,7 @@ def limit_cone_is_limit (F : J ⥤ Type u) : is_limit (limit_cone F) := /-- The category of types has all limits. -See https://stacks.math.columbia.edu/tag/002U. +See . -/ instance : has_limits (Type u) := { has_limits_of_shape := λ J 𝒥, by exactI @@ -166,7 +166,7 @@ def colimit_cocone_is_colimit (F : J ⥤ Type u) : is_colimit (colimit_cocone F) /-- The category of types has all colimits. -See https://stacks.math.columbia.edu/tag/002U. +See . -/ instance : has_colimits (Type u) := { has_colimits_of_shape := λ J 𝒥, by exactI diff --git a/src/category_theory/monoidal/braided.lean b/src/category_theory/monoidal/braided.lean index 2f50077581659..bec4e75332dae 100644 --- a/src/category_theory/monoidal/braided.lean +++ b/src/category_theory/monoidal/braided.lean @@ -211,7 +211,7 @@ end /-- A symmetric monoidal category is a braided monoidal category for which the braiding is symmetric. -See https://stacks.math.columbia.edu/tag/0FFW. +See . -/ class symmetric_category (C : Type u) [category.{v} C] [monoidal_category.{v} C] extends braided_category.{v} C := diff --git a/src/category_theory/monoidal/category.lean b/src/category_theory/monoidal/category.lean index f114b0ec245cb..7dcc5f6d38b04 100644 --- a/src/category_theory/monoidal/category.lean +++ b/src/category_theory/monoidal/category.lean @@ -42,7 +42,7 @@ This is far from completely effective, but seems to prove a useful principle. ## References * Tensor categories, Etingof, Gelaki, Nikshych, Ostrik, http://www-math.mit.edu/~etingof/egnobookfinal.pdf -* https://stacks.math.columbia.edu/tag/0FFK. +* . -/ open category_theory @@ -62,7 +62,7 @@ specified associator, `α_ X Y Z : (X ⊗ Y) ⊗ Z ≅ X ⊗ (Y ⊗ Z)`. There i with specified left and right unitor isomorphisms `λ_ X : 𝟙_ C ⊗ X ≅ X` and `ρ_ X : X ⊗ 𝟙_ C ≅ X`. These associators and unitors satisfy the pentagon and triangle equations. -See https://stacks.math.columbia.edu/tag/0FFK. +See . -/ class monoidal_category (C : Type u) [𝒞 : category.{v} C] := -- curried tensor product of objects: diff --git a/src/category_theory/monoidal/functor.lean b/src/category_theory/monoidal/functor.lean index 8b3b066da2a51..06d83b0860f67 100644 --- a/src/category_theory/monoidal/functor.lean +++ b/src/category_theory/monoidal/functor.lean @@ -34,7 +34,7 @@ to monoid objects. ## References -See https://stacks.math.columbia.edu/tag/0FFL. +See . -/ open category_theory @@ -130,7 +130,7 @@ end /-- A monoidal functor is a lax monoidal functor for which the tensorator and unitor as isomorphisms. -See https://stacks.math.columbia.edu/tag/0FFL. +See . -/ structure monoidal_functor extends lax_monoidal_functor.{v₁ v₂} C D := diff --git a/src/category_theory/opposites.lean b/src/category_theory/opposites.lean index 024ebbf6276f0..e5981c0bb7bf6 100644 --- a/src/category_theory/opposites.lean +++ b/src/category_theory/opposites.lean @@ -51,7 +51,7 @@ variables [category.{v₁} C] /-- The opposite category. -See https://stacks.math.columbia.edu/tag/001M. +See . -/ instance category.opposite : category.{v₁} Cᵒᵖ := { comp := λ _ _ _ f g, (g.unop ≫ f.unop).op, diff --git a/src/category_theory/over.lean b/src/category_theory/over.lean index 942edf3fee3da..fdd8918063f6c 100644 --- a/src/category_theory/over.lean +++ b/src/category_theory/over.lean @@ -31,7 +31,7 @@ variables {T : Type u₁} [category.{v₁} T] The over category has as objects arrows in `T` with codomain `X` and as morphisms commutative triangles. -See https://stacks.math.columbia.edu/tag/001G. +See . -/ @[derive category] def over (X : T) := costructured_arrow (𝟭 T) X @@ -96,7 +96,7 @@ variable (X) /-- The forgetful functor mapping an arrow to its domain. -See https://stacks.math.columbia.edu/tag/001G. +See . -/ def forget : over X ⥤ T := comma.fst _ _ @@ -112,7 +112,7 @@ end /-- A morphism `f : X ⟶ Y` induces a functor `over X ⥤ over Y` in the obvious way. -See https://stacks.math.columbia.edu/tag/001G. +See . -/ def map {Y : T} (f : X ⟶ Y) : over X ⥤ over Y := comma.map_right _ $ discrete.nat_trans (λ _, f) diff --git a/src/category_theory/products/basic.lean b/src/category_theory/products/basic.lean index c04ed48c87490..5bd7e8228e7e8 100644 --- a/src/category_theory/products/basic.lean +++ b/src/category_theory/products/basic.lean @@ -33,7 +33,7 @@ variables (C : Type u₁) [category.{v₁} C] (D : Type u₂) [category.{v₂} D /-- `prod C D` gives the cartesian product of two categories. -See https://stacks.math.columbia.edu/tag/001K. +See . -/ @[simps {not_recursive := []}] -- the generates simp lemmas like `id_fst` and `comp_snd` instance prod : category.{max v₁ v₂} (C × D) := diff --git a/src/category_theory/single_obj.lean b/src/category_theory/single_obj.lean index 7e162e8edbaf1..033642514465a 100644 --- a/src/category_theory/single_obj.lean +++ b/src/category_theory/single_obj.lean @@ -65,7 +65,7 @@ lemma comp_as_mul [monoid α] {x y z : single_obj α} (f : x ⟶ y) (g : y ⟶ z /-- Groupoid structure on `single_obj α`. -See https://stacks.math.columbia.edu/tag/0019. +See . -/ instance groupoid [group α] : groupoid (single_obj α) := { inv := λ _ _ x, x⁻¹, @@ -90,7 +90,7 @@ lemma to_End_def [monoid α] (x : α) : to_End α x = x := rfl corresponding single-object categories. It means that `single_obj` is a fully faithful functor. -See https://stacks.math.columbia.edu/tag/001F -- +See -- although we do not characterize when the functor is full or faithful. -/ def map_hom (α : Type u) (β : Type v) [monoid α] [monoid β] : diff --git a/src/category_theory/sites/canonical.lean b/src/category_theory/sites/canonical.lean index 3d6a3a311a745..cd8ea2aa40f57 100644 --- a/src/category_theory/sites/canonical.lean +++ b/src/category_theory/sites/canonical.lean @@ -180,7 +180,7 @@ def finest_topology_single (P : Cᵒᵖ ⥤ Type v) : grothendieck_topology C := /-- Construct the finest (largest) Grothendieck topology for which all the given presheaves are sheaves. -This is equal to the construction of https://stacks.math.columbia.edu/tag/00Z9. +This is equal to the construction of . -/ def finest_topology (Ps : set (Cᵒᵖ ⥤ Type v)) : grothendieck_topology C := Inf (finest_topology_single '' Ps) @@ -205,7 +205,7 @@ end The `canonical_topology` on a category is the finest (largest) topology for which every representable presheaf is a sheaf. -See https://stacks.math.columbia.edu/tag/00ZA +See -/ def canonical_topology (C : Type u) [category.{v} C] : grothendieck_topology C := finest_topology (set.range yoneda.obj) diff --git a/src/category_theory/sites/cover_lifting.lean b/src/category_theory/sites/cover_lifting.lean index a8b08d32fd678..6e3eb8f840867 100644 --- a/src/category_theory/sites/cover_lifting.lean +++ b/src/category_theory/sites/cover_lifting.lean @@ -78,7 +78,7 @@ end cover_lifting /-! We will now prove that `Ran G.op` (`ₚu`) maps sheaves to sheaves if `G` is cover-lifting. This can -be found in https://stacks.math.columbia.edu/tag/00XK. However, the proof given here uses the +be found in . However, the proof given here uses the amalgamation definition of sheaves, and thus does not require that `C` or `D` has categorical pullbacks. diff --git a/src/category_theory/sites/cover_preserving.lean b/src/category_theory/sites/cover_preserving.lean index 0749ad33cab4d..0d0eb57677afd 100644 --- a/src/category_theory/sites/cover_preserving.lean +++ b/src/category_theory/sites/cover_preserving.lean @@ -166,7 +166,7 @@ end If `G` is cover-preserving and compatible-preserving, then `G.op ⋙ _` pulls sheaves back to sheaves. -This result is basically https://stacks.math.columbia.edu/tag/00WW. +This result is basically . -/ theorem pullback_is_sheaf_of_cover_preserving {G : C ⥤ D} (hG₁ : compatible_preserving.{v₃} K G) (hG₂ : cover_preserving J K G) (ℱ : Sheaf K A) : diff --git a/src/category_theory/sites/grothendieck.lean b/src/category_theory/sites/grothendieck.lean index 66e7a10af60b3..ebba468fb34db 100644 --- a/src/category_theory/sites/grothendieck.lean +++ b/src/category_theory/sites/grothendieck.lean @@ -65,7 +65,7 @@ three axioms: A sieve `S` on `X` is referred to as `J`-covering, (or just covering), if `S ∈ J X`. -See https://stacks.math.columbia.edu/tag/00Z4, or [nlab], or [MM92][] Chapter III, Section 2, +See , or [nlab], or [MM92][] Chapter III, Section 2, Definition 1. -/ structure grothendieck_topology := @@ -108,7 +108,7 @@ lemma covering_of_eq_top : S = ⊤ → S ∈ J X := λ h, h.symm ▸ J.top_mem X /-- If `S` is a subset of `R`, and `S` is covering, then `R` is covering as well. -See https://stacks.math.columbia.edu/tag/00Z5 (2), or discussion after [MM92] Chapter III, +See (2), or discussion after [MM92] Chapter III, Section 2, Definition 1. -/ lemma superset_covering (Hss : S ≤ R) (sjx : S ∈ J X) : R ∈ J X := @@ -122,7 +122,7 @@ end /-- The intersection of two covering sieves is covering. -See https://stacks.math.columbia.edu/tag/00Z5 (1), or [MM92] Chapter III, +See (1), or [MM92] Chapter III, Section 2, Definition 1 (iv). -/ lemma intersection_covering (rj : R ∈ J X) (sj : S ∈ J X) : R ⊓ S ∈ J X := @@ -223,21 +223,21 @@ variable {C} lemma trivial_covering : S ∈ trivial C X ↔ S = ⊤ := set.mem_singleton_iff -/-- See https://stacks.math.columbia.edu/tag/00Z6 -/ +/-- See -/ instance : has_le (grothendieck_topology C) := { le := λ J₁ J₂, (J₁ : Π (X : C), set (sieve X)) ≤ (J₂ : Π (X : C), set (sieve X)) } lemma le_def {J₁ J₂ : grothendieck_topology C} : J₁ ≤ J₂ ↔ (J₁ : Π (X : C), set (sieve X)) ≤ J₂ := iff.rfl -/-- See https://stacks.math.columbia.edu/tag/00Z6 -/ +/-- See -/ instance : partial_order (grothendieck_topology C) := { le_refl := λ J₁, le_def.mpr le_rfl, le_trans := λ J₁ J₂ J₃ h₁₂ h₂₃, le_def.mpr (le_trans h₁₂ h₂₃), le_antisymm := λ J₁ J₂ h₁₂ h₂₁, grothendieck_topology.ext (le_antisymm h₁₂ h₂₁), ..grothendieck_topology.has_le } -/-- See https://stacks.math.columbia.edu/tag/00Z7 -/ +/-- See -/ instance : has_Inf (grothendieck_topology C) := { Inf := λ T, { sieves := Inf (sieves '' T), @@ -257,7 +257,7 @@ instance : has_Inf (grothendieck_topology C) := apply J.transitive (hS _ ⟨⟨_, _, hJ, rfl⟩, rfl⟩) _ (λ Y f hf, h hf _ ⟨⟨_, _, hJ, rfl⟩, rfl⟩), end } } -/-- See https://stacks.math.columbia.edu/tag/00Z7 -/ +/-- See -/ lemma is_glb_Inf (s : set (grothendieck_topology C)) : is_glb s (Inf s) := begin refine @is_glb.of_image _ _ _ _ sieves _ _ _ _, diff --git a/src/category_theory/sites/plus.lean b/src/category_theory/sites/plus.lean index b096027856ede..0520c3b1c40aa 100644 --- a/src/category_theory/sites/plus.lean +++ b/src/category_theory/sites/plus.lean @@ -12,7 +12,7 @@ import category_theory.sites.sheaf This file contains the construction of `P⁺`, for a presheaf `P : Cᵒᵖ ⥤ D` where `C` is endowed with a grothendieck topology `J`. -See https://stacks.math.columbia.edu/tag/00W1 for details. +See for details. -/ diff --git a/src/category_theory/sites/pretopology.lean b/src/category_theory/sites/pretopology.lean index 15961483ea9c0..b8d0f9f3fa741 100644 --- a/src/category_theory/sites/pretopology.lean +++ b/src/category_theory/sites/pretopology.lean @@ -99,7 +99,7 @@ instance : inhabited (pretopology C) := ⟨⊤⟩ A pretopology `K` can be completed to a Grothendieck topology `J` by declaring a sieve to be `J`-covering if it contains a family in `K`. -See https://stacks.math.columbia.edu/tag/00ZC, or [MM92] Chapter III, Section 2, Equation (2). +See , or [MM92] Chapter III, Section 2, Equation (2). -/ def to_grothendieck (K : pretopology C) : grothendieck_topology C := { sieves := λ X S, ∃ R ∈ K X, R ≤ (S : presieve _), @@ -170,7 +170,7 @@ def gi : galois_insertion (to_grothendieck C) (of_grothendieck C) := The trivial pretopology, in which the coverings are exactly singleton isomorphisms. This topology is also known as the indiscrete, coarse, or chaotic topology. -See https://stacks.math.columbia.edu/tag/07GE +See -/ def trivial : pretopology C := { coverings := λ X S, ∃ Y (f : Y ⟶ X) (h : is_iso f), S = presieve.singleton f, diff --git a/src/category_theory/sites/sheaf.lean b/src/category_theory/sites/sheaf.lean index 75045308bddd5..c2983cbe2a316 100644 --- a/src/category_theory/sites/sheaf.lean +++ b/src/category_theory/sites/sheaf.lean @@ -15,7 +15,7 @@ import category_theory.sites.sheaf_of_types If C is a category with a Grothendieck topology, we define the notion of a sheaf taking values in an arbitrary category `A`. We follow the definition in https://stacks.math.columbia.edu/tag/00VR, noting that the presheaf of sets "defined above" can be seen in the comments between tags 00VQ and -00VR on the page https://stacks.math.columbia.edu/tag/00VL. The advantage of this definition is +00VR on the page . The advantage of this definition is that we need no assumptions whatsoever on `A` other than the assumption that the morphisms in `C` and `A` live in the same universe. @@ -400,14 +400,14 @@ variables [has_products A] /-- The middle object of the fork diagram given in Equation (3) of [MM92], as well as the fork diagram -of https://stacks.math.columbia.edu/tag/00VM. +of . -/ def first_obj : A := ∏ (λ (f : Σ V, {f : V ⟶ U // R f}), P.obj (op f.1)) /-- The left morphism of the fork diagram given in Equation (3) of [MM92], as well as the fork diagram -of https://stacks.math.columbia.edu/tag/00VM. +of . -/ def fork_map : P.obj (op U) ⟶ first_obj R P := pi.lift (λ f, P.map f.2.1.op) @@ -422,11 +422,11 @@ def second_obj : A := ∏ (λ (fg : (Σ V, {f : V ⟶ U // R f}) × (Σ W, {g : W ⟶ U // R g})), P.obj (op (pullback fg.1.2.1 fg.2.2.1))) -/-- The map `pr₀*` of https://stacks.math.columbia.edu/tag/00VM. -/ +/-- The map `pr₀*` of . -/ def first_map : first_obj R P ⟶ second_obj R P := pi.lift (λ fg, pi.π _ _ ≫ P.map pullback.fst.op) -/-- The map `pr₁*` of https://stacks.math.columbia.edu/tag/00VM. -/ +/-- The map `pr₁*` of . -/ def second_map : first_obj R P ⟶ second_obj R P := pi.lift (λ fg, pi.π _ _ ≫ P.map pullback.snd.op) diff --git a/src/category_theory/sites/sheaf_of_types.lean b/src/category_theory/sites/sheaf_of_types.lean index 739d9e26129c9..37fa6d371ecc8 100644 --- a/src/category_theory/sites/sheaf_of_types.lean +++ b/src/category_theory/sites/sheaf_of_types.lean @@ -444,7 +444,7 @@ This version is also useful to establish that being a sheaf is preserved under i presheaves. See the discussion before Equation (3) of [MM92], Chapter III, Section 4. See also C2.1.4 of -[Elephant]. This is also a direct reformulation of https://stacks.math.columbia.edu/tag/00Z8. +[Elephant]. This is also a direct reformulation of . -/ def yoneda_sheaf_condition (P : Cᵒᵖ ⥤ Type v₁) (S : sieve X) : Prop := ∀ (f : S.functor ⟶ P), ∃! g, S.functor_inclusion ≫ g = f @@ -456,7 +456,7 @@ def yoneda_sheaf_condition (P : Cᵒᵖ ⥤ Type v₁) (S : sieve X) : Prop := (Implementation). This is a (primarily internal) equivalence between natural transformations and compatible families. -Cf the discussion after Lemma 7.47.10 in https://stacks.math.columbia.edu/tag/00YW. See also +Cf the discussion after Lemma 7.47.10 in . See also the proof of C2.1.4 of [Elephant], and the discussion in [MM92], Chapter III, Section 4. -/ def nat_trans_equiv_compatible_family {P : Cᵒᵖ ⥤ Type v₁} : @@ -799,7 +799,7 @@ noncomputable theory /-- The middle object of the fork diagram given in Equation (3) of [MM92], as well as the fork diagram -of https://stacks.math.columbia.edu/tag/00VM. +of . -/ def first_obj : Type (max v₁ u₁) := ∏ (λ (f : Σ Y, {f : Y ⟶ X // R f}), P.obj (op f.1)) @@ -825,7 +825,7 @@ instance : inhabited (first_obj P (⊥ : presieve X)) := /-- The left morphism of the fork diagram given in Equation (3) of [MM92], as well as the fork diagram -of https://stacks.math.columbia.edu/tag/00VM. +of . -/ def fork_map : P.obj (op X) ⟶ first_obj P R := pi.lift (λ f, P.map f.2.1.op) @@ -918,13 +918,13 @@ def second_obj : Type (max v₁ u₁) := ∏ (λ (fg : (Σ Y, {f : Y ⟶ X // R f}) × (Σ Z, {g : Z ⟶ X // R g})), P.obj (op (pullback fg.1.2.1 fg.2.2.1))) -/-- The map `pr₀*` of https://stacks.math.columbia.edu/tag/00VL. -/ +/-- The map `pr₀*` of . -/ def first_map : first_obj P R ⟶ second_obj P R := pi.lift (λ fg, pi.π _ _ ≫ P.map pullback.fst.op) instance : inhabited (second_obj P (⊥ : presieve X)) := ⟨first_map _ _ default⟩ -/-- The map `pr₁*` of https://stacks.math.columbia.edu/tag/00VL. -/ +/-- The map `pr₁*` of . -/ def second_map : first_obj P R ⟶ second_obj P R := pi.lift (λ fg, pi.π _ _ ≫ P.map pullback.snd.op) @@ -958,7 +958,7 @@ end /-- `P` is a sheaf for `R`, iff the fork given by `w` is an equalizer. -See https://stacks.math.columbia.edu/tag/00VM. +See . -/ lemma sheaf_condition : R.is_sheaf_for P ↔ nonempty (is_limit (fork.of_ι _ (w P R))) := diff --git a/src/category_theory/triangulated/basic.lean b/src/category_theory/triangulated/basic.lean index 5fc085cc9759f..fb6ce12029b9d 100644 --- a/src/category_theory/triangulated/basic.lean +++ b/src/category_theory/triangulated/basic.lean @@ -33,7 +33,7 @@ variables (C : Type u) [category.{v} C] [has_shift C ℤ] /-- A triangle in `C` is a sextuple `(X,Y,Z,f,g,h)` where `X,Y,Z` are objects of `C`, and `f : X ⟶ Y`, `g : Y ⟶ Z`, `h : Z ⟶ X⟦1⟧` are morphisms in `C`. -See https://stacks.math.columbia.edu/tag/0144. +See . -/ structure triangle := mk' :: (obj₁ : C) @@ -87,7 +87,7 @@ In other words, we have a commutative diagram: X' ───> Y' ───> Z' ───> X'⟦1⟧ f' g' h' ``` -See https://stacks.math.columbia.edu/tag/0144. +See . -/ @[ext] structure triangle_morphism (T₁ : triangle C) (T₂ : triangle C) := diff --git a/src/category_theory/triangulated/pretriangulated.lean b/src/category_theory/triangulated/pretriangulated.lean index 005b60f9b02ee..e8fe2256ea2a3 100644 --- a/src/category_theory/triangulated/pretriangulated.lean +++ b/src/category_theory/triangulated/pretriangulated.lean @@ -58,7 +58,7 @@ relative to that shift is called pretriangulated if the following hold: where the left square commutes, and whose rows are distinguished triangles, there exists a morphism `c : Z ⟶ Z'` such that `(a,b,c)` is a triangle morphism. -See https://stacks.math.columbia.edu/tag/0145 +See -/ class pretriangulated := (distinguished_triangles [] : set (triangle C)) @@ -99,7 +99,7 @@ Given any distinguished triangle X ───> Y ───> Z ───> X⟦1⟧ ``` the composition `f ≫ g = 0`. -See https://stacks.math.columbia.edu/tag/0146 +See -/ lemma comp_dist_triangle_mor_zero₁₂ (T ∈ dist_triang C) : T.mor₁ ≫ T.mor₂ = 0 := begin @@ -121,7 +121,7 @@ Given any distinguished triangle X ───> Y ───> Z ───> X⟦1⟧ ``` the composition `g ≫ h = 0`. -See https://stacks.math.columbia.edu/tag/0146 +See -/ lemma comp_dist_triangle_mor_zero₂₃ (T ∈ dist_triang C) : T.mor₂ ≫ T.mor₃ = 0 := comp_dist_triangle_mor_zero₁₂ C T.rotate (rot_of_dist_triangle C T H) @@ -133,7 +133,7 @@ Given any distinguished triangle X ───> Y ───> Z ───> X⟦1⟧ ``` the composition `h ≫ f⟦1⟧ = 0`. -See https://stacks.math.columbia.edu/tag/0146 +See -/ lemma comp_dist_triangle_mor_zero₃₁ (T ∈ dist_triang C) : T.mor₃ ≫ ((shift_equiv C 1).functor.map T.mor₁) = 0 := @@ -201,7 +201,7 @@ A triangulated functor between pretriangulated categories `C` and `D` is a funct together with given functorial isomorphisms `ξ X : F(X⟦1⟧) ⟶ F(X)⟦1⟧` such that for every distinguished triangle `(X,Y,Z,f,g,h)` of `C`, the triangle `(F(X), F(Y), F(Z), F(f), F(g), F(h) ≫ (ξ X))` is a distinguished triangle of `D`. -See https://stacks.math.columbia.edu/tag/014V +See -/ structure triangulated_functor [pretriangulated C] [pretriangulated D] extends triangulated_functor_struct C D := diff --git a/src/category_theory/types.lean b/src/category_theory/types.lean index 3747a1d3c0661..e1074994e2618 100644 --- a/src/category_theory/types.lean +++ b/src/category_theory/types.lean @@ -163,7 +163,7 @@ lemma hom_of_element_eq_iff {X : Type u} (x y : X) : /-- A morphism in `Type` is a monomorphism if and only if it is injective. -See https://stacks.math.columbia.edu/tag/003C. +See . -/ lemma mono_iff_injective {X Y : Type u} (f : X ⟶ Y) : mono f ↔ function.injective f := begin @@ -181,7 +181,7 @@ lemma injective_of_mono {X Y : Type u} (f : X ⟶ Y) [hf : mono f] : function.in /-- A morphism in `Type` is an epimorphism if and only if it is surjective. -See https://stacks.math.columbia.edu/tag/003C. +See . -/ lemma epi_iff_surjective {X Y : Type u} (f : X ⟶ Y) : epi f ↔ function.surjective f := begin diff --git a/src/category_theory/yoneda.lean b/src/category_theory/yoneda.lean index d87d09bac70d0..58c67b3ada75a 100644 --- a/src/category_theory/yoneda.lean +++ b/src/category_theory/yoneda.lean @@ -29,7 +29,7 @@ variables {C : Type u₁} [category.{v₁} C] /-- The Yoneda embedding, as a functor from `C` into presheaves on `C`. -See https://stacks.math.columbia.edu/tag/001O. +See . -/ @[simps] def yoneda : C ⥤ (Cᵒᵖ ⥤ Type v₁) := @@ -62,7 +62,7 @@ by { dsimp, simp } /-- The Yoneda embedding is full. -See https://stacks.math.columbia.edu/tag/001P. +See . -/ instance yoneda_full : full (yoneda : C ⥤ Cᵒᵖ ⥤ Type v₁) := { preimage := λ X Y f, f.app (op X) (𝟙 X) } @@ -70,7 +70,7 @@ instance yoneda_full : full (yoneda : C ⥤ Cᵒᵖ ⥤ Type v₁) := /-- The Yoneda embedding is faithful. -See https://stacks.math.columbia.edu/tag/001P. +See . -/ instance yoneda_faithful : faithful (yoneda : C ⥤ Cᵒᵖ ⥤ Type v₁) := { map_injective' := λ X Y f g p, by convert (congr_fun (congr_app p (op X)) (𝟙 X)); dsimp; simp } @@ -133,7 +133,7 @@ namespace functor /-- A functor `F : Cᵒᵖ ⥤ Type v₁` is representable if there is object `X` so `F ≅ yoneda.obj X`. -See https://stacks.math.columbia.edu/tag/001Q. +See . -/ class representable (F : Cᵒᵖ ⥤ Type v₁) : Prop := (has_representation : ∃ X (f : yoneda.obj X ⟶ F), is_iso f) @@ -144,7 +144,7 @@ instance {X : C} : representable (yoneda.obj X) := /-- A functor `F : C ⥤ Type v₁` is corepresentable if there is object `X` so `F ≅ coyoneda.obj X`. -See https://stacks.math.columbia.edu/tag/001Q. +See . -/ class corepresentable (F : C ⥤ Type v₁) : Prop := (has_corepresentation : ∃ X (f : coyoneda.obj X ⟶ F), is_iso f) @@ -289,7 +289,7 @@ The Yoneda lemma asserts that that the Yoneda pairing `(X : Cᵒᵖ, F : Cᵒᵖ ⥤ Type) ↦ (yoneda.obj (unop X) ⟶ F)` is naturally isomorphic to the evaluation `(X, F) ↦ F.obj X`. -See https://stacks.math.columbia.edu/tag/001P. +See . -/ def yoneda_lemma : yoneda_pairing C ≅ yoneda_evaluation C := { hom := diff --git a/src/topology/category/Top/limits.lean b/src/topology/category/Top/limits.lean index d59cd11dfa5bd..f9a03edff86c2 100644 --- a/src/topology/category/Top/limits.lean +++ b/src/topology/category/Top/limits.lean @@ -823,7 +823,7 @@ The theorem is specialized to nonempty finite types (which are compact Hausdorff discrete topology) in `nonempty_sections_of_fintype_cofiltered_system` and `nonempty_sections_of_fintype_inverse_system`. -(See https://stacks.math.columbia.edu/tag/086J for the Set version.) +(See for the Set version.) -/ variables {J : Type u} [small_category J] diff --git a/src/topology/sheaves/forget.lean b/src/topology/sheaves/forget.lean index 3bafd8544aaaa..255145043d058 100644 --- a/src/topology/sheaves/forget.lean +++ b/src/topology/sheaves/forget.lean @@ -123,7 +123,7 @@ Then to check the sheaf condition it suffices to check it on the underlying shea Another useful example is the forgetful functor `TopCommRing ⥤ Top`. -See https://stacks.math.columbia.edu/tag/0073. +See . In fact we prove a stronger version with arbitrary complete target category. -/ lemma is_sheaf_iff_is_sheaf_comp : diff --git a/src/topology/sheaves/sheafify.lean b/src/topology/sheaves/sheafify.lean index 9b7f8594f1b29..acc3b40344654 100644 --- a/src/topology/sheaves/sheafify.lean +++ b/src/topology/sheaves/sheafify.lean @@ -24,7 +24,7 @@ Show that the map induced on stalks by `to_sheafify` is the inverse of `stalk_to Show sheafification is a functor from presheaves to sheaves, and that it is the left adjoint of the forgetful functor, -following https://stacks.math.columbia.edu/tag/007X. +following . -/ universes v diff --git a/src/topology/tietze_extension.lean b/src/topology/tietze_extension.lean index 36d6afbe7cb4e..7fda729bf52a9 100644 --- a/src/topology/tietze_extension.lean +++ b/src/topology/tietze_extension.lean @@ -17,7 +17,7 @@ function belong to some (finite or infinite, open or closed) interval, then the chosen so that it takes values in the same interval. In particular, if the original function is a bounded function, then there exists a bounded extension of the same norm. -The proof mostly follows https://ncatlab.org/nlab/show/Tietze+extension+theorem. We patch a small +The proof mostly follows . We patch a small gap in the proof for unbounded functions, see `exists_extension_forall_exists_le_ge_of_closed_embedding`. From 071cb550412bd76fa38a54fbca40a5088a928c81 Mon Sep 17 00:00:00 2001 From: sgouezel Date: Sun, 1 May 2022 18:53:38 +0000 Subject: [PATCH 351/373] feat(data/set/function): missing mono lemmas (#13863) --- src/data/set/function.lean | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/data/set/function.lean b/src/data/set/function.lean index 846ea1a7b647d..40a99087faaa1 100644 --- a/src/data/set/function.lean +++ b/src/data/set/function.lean @@ -202,6 +202,26 @@ lemma eq_on.congr_strict_anti_on (h : s.eq_on f₁ f₂) : strict_anti_on f₁ s end order +/-! ### Mono lemmas-/ + +section mono + +variables [preorder α] [preorder β] + +lemma _root_.monotone_on.mono (h : monotone_on f s) (h' : s₂ ⊆ s) : monotone_on f s₂ := +λ x hx y hy, h (h' hx) (h' hy) + +lemma _root_.antitone_on.mono (h : antitone_on f s) (h' : s₂ ⊆ s) : antitone_on f s₂ := +λ x hx y hy, h (h' hx) (h' hy) + +lemma _root_.strict_mono_on.mono (h : strict_mono_on f s) (h' : s₂ ⊆ s) : strict_mono_on f s₂ := +λ x hx y hy, h (h' hx) (h' hy) + +lemma _root_.strict_anti_on.mono (h : strict_anti_on f s) (h' : s₂ ⊆ s) : strict_anti_on f s₂ := +λ x hx y hy, h (h' hx) (h' hy) + +end mono + /-! ### maps to -/ /-- `maps_to f a b` means that the image of `a` is contained in `b`. -/ From f0930c822ca29980df4218d85c2e5dc7cbe089d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Sun, 1 May 2022 21:16:30 +0000 Subject: [PATCH 352/373] feat(set_theory/pgame/impartial): `star` is impartial (#13842) --- src/set_theory/game/impartial.lean | 3 +++ src/set_theory/game/pgame.lean | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/set_theory/game/impartial.lean b/src/set_theory/game/impartial.lean index caabd4e82dbc4..da579866c0bec 100644 --- a/src/set_theory/game/impartial.lean +++ b/src/set_theory/game/impartial.lean @@ -46,6 +46,9 @@ namespace impartial instance impartial_zero : impartial 0 := by { rw impartial_def, dsimp, simp } +instance impartial_star : impartial star := +by { rw impartial_def, simpa using impartial.impartial_zero } + lemma neg_equiv_self (G : pgame) [h : G.impartial] : G ≈ -G := (impartial_def.1 h).1 instance move_left_impartial {G : pgame} [h : G.impartial] (i : G.left_moves) : diff --git a/src/set_theory/game/pgame.lean b/src/set_theory/game/pgame.lean index 9a276e4101443..81add49fbaeb1 100644 --- a/src/set_theory/game/pgame.lean +++ b/src/set_theory/game/pgame.lean @@ -1146,6 +1146,9 @@ by { rw lt_zero, use default, rintros ⟨⟩ } theorem zero_lt_star : 0 < star := by { rw zero_lt, use default, rintros ⟨⟩ } +@[simp] theorem neg_star : -star = star := +by { rw [star, of_lists], simp } + /-- The pre-game `ω`. (In fact all ordinals have game and surreal representatives.) -/ def omega : pgame := ⟨ulift ℕ, pempty, λ n, ↑n.1, pempty.elim⟩ From b236cb20560c9558495065903fd31287201bcb61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Sun, 1 May 2022 21:51:02 +0000 Subject: [PATCH 353/373] chore(set_theory/surreal/basic): Inline instances (#13811) We inline various definitions used only for instances. We also remove the redundant lemma `not_le` (which is more generally true on preorders). --- src/set_theory/surreal/basic.lean | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/set_theory/surreal/basic.lean b/src/set_theory/surreal/basic.lean index 7d996859c180c..fbbab73dbe191 100644 --- a/src/set_theory/surreal/basic.lean +++ b/src/set_theory/surreal/basic.lean @@ -263,35 +263,25 @@ def lift₂ {α} (f : ∀ x y, numeric x → numeric y → α) lift (λ x ox, lift (λ y oy, f x y ox oy) (λ y₁ y₂ oy₁ oy₂ h, H _ _ _ _ (equiv_refl _) h)) (λ x₁ x₂ ox₁ ox₂ h, funext $ quotient.ind $ by exact λ ⟨y, oy⟩, H _ _ _ _ h (equiv_refl _)) -/-- The relation `x ≤ y` on surreals. -/ -def le : surreal → surreal → Prop := -lift₂ (λ x y _ _, x ≤ y) (λ x₁ y₁ x₂ y₂ _ _ _ _ hx hy, propext (le_congr hx hy)) +instance : has_le surreal := +⟨lift₂ (λ x y _ _, x ≤ y) (λ x₁ y₁ x₂ y₂ _ _ _ _ hx hy, propext (le_congr hx hy))⟩ -/-- The relation `x < y` on surreals. -/ -def lt : surreal → surreal → Prop := -lift₂ (λ x y _ _, x < y) (λ x₁ y₁ x₂ y₂ _ _ _ _ hx hy, propext (lt_congr hx hy)) - -theorem not_le : ∀ {x y : surreal}, ¬ le x y ↔ lt y x := -by rintro ⟨⟨x, ox⟩⟩ ⟨⟨y, oy⟩⟩; exact not_le +instance : has_lt surreal := +⟨lift₂ (λ x y _ _, x < y) (λ x₁ y₁ x₂ y₂ _ _ _ _ hx hy, propext (lt_congr hx hy))⟩ /-- Addition on surreals is inherited from pre-game addition: the sum of `x = {xL | xR}` and `y = {yL | yR}` is `{xL + y, x + yL | xR + y, x + yR}`. -/ -def add : surreal → surreal → surreal := -surreal.lift₂ +instance : has_add surreal := +⟨surreal.lift₂ (λ (x y : pgame) (ox) (oy), ⟦⟨x + y, ox.add oy⟩⟧) - (λ x₁ y₁ x₂ y₂ _ _ _ _ hx hy, quotient.sound (pgame.add_congr hx hy)) + (λ x₁ y₁ x₂ y₂ _ _ _ _ hx hy, quotient.sound (pgame.add_congr hx hy))⟩ /-- Negation for surreal numbers is inherited from pre-game negation: the negation of `{L | R}` is `{-R | -L}`. -/ -def neg : surreal → surreal := -surreal.lift +instance : has_neg surreal := +⟨surreal.lift (λ x ox, ⟦⟨-x, ox.neg⟩⟧) - (λ _ _ _ _ a, quotient.sound (pgame.neg_congr a)) - -instance : has_le surreal := ⟨le⟩ -instance : has_lt surreal := ⟨lt⟩ -instance : has_add surreal := ⟨add⟩ -instance : has_neg surreal := ⟨neg⟩ + (λ _ _ _ _ a, quotient.sound (pgame.neg_congr a))⟩ instance : ordered_add_comm_group surreal := { add := (+), From afc0700e00f12c0346200e2db4bb501e4fea4c4d Mon Sep 17 00:00:00 2001 From: antoinelab01 Date: Mon, 2 May 2022 01:07:34 +0000 Subject: [PATCH 354/373] feat(linear_algebra/tensor_product): define tensor_tensor_tensor_assoc (#13864) --- src/linear_algebra/tensor_product.lean | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/linear_algebra/tensor_product.lean b/src/linear_algebra/tensor_product.lean index 2f4d06decab0c..c0f36a871fb90 100644 --- a/src/linear_algebra/tensor_product.lean +++ b/src/linear_algebra/tensor_product.lean @@ -723,6 +723,29 @@ rfl (tensor_tensor_tensor_comm R M N P Q).symm ((m ⊗ₜ p) ⊗ₜ (n ⊗ₜ q)) = (m ⊗ₜ n) ⊗ₜ (p ⊗ₜ q) := rfl +variables (M N P Q) + +/-- This special case is useful for describing the interplay between `dual_tensor_hom_equiv` and +composition of linear maps. + +E.g., composition of linear maps gives a map `(M → N) ⊗ (N → P) → (M → P)`, and applying +`dual_tensor_hom_equiv.symm` to the three hom-modules gives a map +`(M.dual ⊗ N) ⊗ (N.dual ⊗ P) → (M.dual ⊗ P)`, which agrees with the application of `contract_right` +on `N ⊗ N.dual` after the suitable rebracketting. +-/ +def tensor_tensor_tensor_assoc : (M ⊗[R] N) ⊗[R] (P ⊗[R] Q) ≃ₗ[R] M ⊗[R] (N ⊗[R] P) ⊗[R] Q := +(tensor_product.assoc R (M ⊗[R] N) P Q).symm ≪≫ₗ +congr (tensor_product.assoc R M N P) (1 : Q ≃ₗ[R] Q) + +variables {M N P Q} + +@[simp] lemma tensor_tensor_tensor_assoc_tmul (m : M) (n : N) (p : P) (q : Q) : + tensor_tensor_tensor_assoc R M N P Q ((m ⊗ₜ n) ⊗ₜ (p ⊗ₜ q)) = m ⊗ₜ (n ⊗ₜ p) ⊗ₜ q := rfl + +@[simp] lemma tensor_tensor_tensor_assoc_symm_tmul (m : M) (n : N) (p : P) (q : Q) : + (tensor_tensor_tensor_assoc R M N P Q).symm (m ⊗ₜ (n ⊗ₜ p) ⊗ₜ q) = (m ⊗ₜ n) ⊗ₜ (p ⊗ₜ q) := +rfl + end tensor_product namespace linear_map From 922717e8c7fbbd2230265b576a4504b9be28039d Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Mon, 2 May 2022 02:37:54 +0000 Subject: [PATCH 355/373] chore(logic/function/basic): don't unfold set in cantor (#13822) This uses `set_of` and `mem` consistently instead of using application everywhere, since `f` has type `A -> set A` instead of `A -> A -> Prop`. (Arguably, it could just be stated for `A -> A -> Prop` instead though.) --- src/logic/function/basic.lean | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/logic/function/basic.lean b/src/logic/function/basic.lean index ca8c07f67fe91..1e1ff8e494854 100644 --- a/src/logic/function/basic.lean +++ b/src/logic/function/basic.lean @@ -206,14 +206,13 @@ and_congr (injective.of_comp_iff hf.injective _) (surjective.of_comp_iff' hf _) /-- **Cantor's diagonal argument** implies that there are no surjective functions from `α` to `set α`. -/ theorem cantor_surjective {α} (f : α → set α) : ¬ function.surjective f | h := -let ⟨D, e⟩ := h (λ a, ¬ f a a) in -(iff_not_self (f D D)).1 $ iff_of_eq (congr_fun e D) +let ⟨D, e⟩ := h {a | ¬ a ∈ f a} in +(iff_not_self (D ∈ f D)).1 $ iff_of_eq (congr_arg ((∈) D) e) /-- **Cantor's diagonal argument** implies that there are no injective functions from `set α` to `α`. -/ -theorem cantor_injective {α : Type*} (f : (set α) → α) : - ¬ function.injective f | i := -cantor_surjective (λ a b, ∀ U, a = f U → U b) $ +theorem cantor_injective {α : Type*} (f : set α → α) : ¬ function.injective f | i := +cantor_surjective (λ a, {b | ∀ U, a = f U → b ∈ U}) $ right_inverse.surjective (λ U, funext $ λ a, propext ⟨λ h, h U rfl, λ h' U' e, i e ▸ h'⟩) /-- There is no surjection from `α : Type u` into `Type u`. This theorem From 26e24c7593fc9dd5ac8639f131581fe06b3281eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Mon, 2 May 2022 04:39:56 +0000 Subject: [PATCH 356/373] feat(set_theory/surreal/basic): `<` is transitive on numeric games (#13812) --- src/set_theory/surreal/basic.lean | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/set_theory/surreal/basic.lean b/src/set_theory/surreal/basic.lean index fbbab73dbe191..d49ecea334c4d 100644 --- a/src/set_theory/surreal/basic.lean +++ b/src/set_theory/surreal/basic.lean @@ -89,6 +89,16 @@ end theorem le_of_lt {x y : pgame} (ox : numeric x) (oy : numeric y) (h : x < y) : x ≤ y := not_lt.1 (lt_asymm ox oy h) +/-- `<` is transitive when both sides of the left inequality are numeric -/ +theorem lt_trans {x y z : pgame} (ox : numeric x) (oy : numeric y) (h₁ : x < y) + (h₂ : y < z) : x < z := +lt_of_le_of_lt (le_of_lt ox oy h₁) h₂ + +/-- `<` is transitive when both sides of the right inequality are numeric -/ +theorem lt_trans' {x y z : pgame} (oy : numeric y) (oz : numeric z) (h₁ : x < y) + (h₂ : y < z) : x < z := +lt_of_lt_of_le h₁ (le_of_lt oy oz h₂) + /-- On numeric pre-games, `<` and `≤` satisfy the axioms of a partial order (even though they don't on all pre-games). -/ theorem lt_iff_le_not_le {x y : pgame} (ox : numeric x) (oy : numeric y) : From 039543c21a65b935775f9f8a545a1b43c968cf44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Mon, 2 May 2022 04:39:57 +0000 Subject: [PATCH 357/373] refactor(set_theory/game/pgame): Simpler definition for `star` (#13869) This new definition gives marginally easier proofs for the basic lemmas, and avoids use of the quite incomplete `of_lists` API. --- src/set_theory/game/pgame.lean | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/set_theory/game/pgame.lean b/src/set_theory/game/pgame.lean index 81add49fbaeb1..717fd1bed65b1 100644 --- a/src/set_theory/game/pgame.lean +++ b/src/set_theory/game/pgame.lean @@ -1126,20 +1126,16 @@ theorem lt_iff_sub_pos {x y : pgame} : x < y ↔ 0 < y - x := ... ≤ y : (add_zero_relabelling y).le⟩ /-- The pre-game `star`, which is fuzzy/confused with zero. -/ -def star : pgame.{u} := of_lists [0] [0] +def star : pgame.{u} := ⟨punit, punit, λ _, 0, λ _, 0⟩ -@[simp] theorem star_left_moves : star.left_moves = ulift (fin 1) := rfl -@[simp] theorem star_right_moves : star.right_moves = ulift (fin 1) := rfl +@[simp] theorem star_left_moves : star.left_moves = punit := rfl +@[simp] theorem star_right_moves : star.right_moves = punit := rfl -@[simp] theorem star_move_left (x) : star.move_left x = 0 := -show (of_lists _ _).move_left x = 0, by simp -@[simp] theorem star_move_right (x) : star.move_right x = 0 := -show (of_lists _ _).move_right x = 0, by simp +@[simp] theorem star_move_left (x) : star.move_left x = 0 := rfl +@[simp] theorem star_move_right (x) : star.move_right x = 0 := rfl -instance unique_star_left_moves : unique star.left_moves := -@equiv.unique _ (fin 1) _ equiv.ulift -instance unique_star_right_moves : unique star.right_moves := -@equiv.unique _ (fin 1) _ equiv.ulift +instance unique_star_left_moves : unique star.left_moves := punit.unique +instance unique_star_right_moves : unique star.right_moves := punit.unique theorem star_lt_zero : star < 0 := by { rw lt_zero, use default, rintros ⟨⟩ } @@ -1147,7 +1143,7 @@ theorem zero_lt_star : 0 < star := by { rw zero_lt, use default, rintros ⟨⟩ } @[simp] theorem neg_star : -star = star := -by { rw [star, of_lists], simp } +by simp [star] /-- The pre-game `ω`. (In fact all ordinals have game and surreal representatives.) -/ def omega : pgame := ⟨ulift ℕ, pempty, λ n, ↑n.1, pempty.elim⟩ From 523adb387a5265f8c30610d365ce7b19163e9f82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Violeta=20Hern=C3=A1ndez?= Date: Mon, 2 May 2022 04:39:58 +0000 Subject: [PATCH 358/373] feat(set_theory/game/nim): Birthday of `nim` (#13873) --- src/set_theory/game/nim.lean | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/set_theory/game/nim.lean b/src/set_theory/game/nim.lean index 8ceabff8e17af..e2d6b5099b84c 100644 --- a/src/set_theory/game/nim.lean +++ b/src/set_theory/game/nim.lean @@ -4,9 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Fox Thomson, Markus Himmel -/ import data.nat.bitwise +import set_theory.game.birthday import set_theory.game.impartial -import set_theory.ordinal.arithmetic - /-! # Nim and the Sprague-Grundy theorem @@ -58,6 +57,16 @@ lemma nim_def (O : ordinal) : nim O = pgame.mk O.out.α O.out.α (λ O₂, nim (ordinal.typein (<) O₂)) := by { rw nim, refl } +@[simp] lemma nim_birthday (O : ordinal) : (nim O).birthday = O := +begin + induction O using ordinal.induction with O IH, + rw [nim_def, birthday_def], + dsimp, + rw max_eq_right le_rfl, + convert lsub_typein O, + exact funext (λ i, IH _ (typein_lt_self i)) +end + instance nim_impartial : ∀ (O : ordinal), impartial (nim O) | O := begin From 3d946a3d7b4d1b88eb09b21020c9fc88b80f23c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Mon, 2 May 2022 05:27:14 +0000 Subject: [PATCH 359/373] chore(algebraic_geometry/AffineScheme): Speed up `Spec` (#13866) `simps` take 38s in local and does not seem to generate any useful lemma. --- src/algebraic_geometry/AffineScheme.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algebraic_geometry/AffineScheme.lean b/src/algebraic_geometry/AffineScheme.lean index f952d34938893..5d5b52cc7c56c 100644 --- a/src/algebraic_geometry/AffineScheme.lean +++ b/src/algebraic_geometry/AffineScheme.lean @@ -69,7 +69,7 @@ by { rw [← mem_AffineScheme] at h ⊢, exact functor.ess_image.of_iso (as_iso namespace AffineScheme /-- The `Spec` functor into the category of affine schemes. -/ -@[derive [full, faithful, ess_surj], simps] +@[derive [full, faithful, ess_surj]] def Spec : CommRingᵒᵖ ⥤ AffineScheme := Scheme.Spec.to_ess_image /-- The forgetful functor `AffineScheme ⥤ Scheme`. -/ From 1e385494da03fdc19eb2d90ac8658223e1f72294 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 2 May 2022 06:04:04 +0000 Subject: [PATCH 360/373] feat(analysis/matrix): define the frobenius norm on matrices (#13497) --- src/analysis/matrix.lean | 151 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 2 deletions(-) diff --git a/src/analysis/matrix.lean b/src/analysis/matrix.lean index 9b1898d5aa263..34ec40dadf1e9 100644 --- a/src/analysis/matrix.lean +++ b/src/analysis/matrix.lean @@ -4,6 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Heather Macbeth -/ import analysis.normed_space.basic +import analysis.normed_space.pi_Lp +import analysis.inner_product_space.pi_L2 /-! # Matrices as a normed space @@ -16,6 +18,14 @@ In this file we provide the following non-instances on matrices, using the eleme These are not declared as instances because there are several natural choices for defining the norm of a matrix. + +We also provide definitions of the frobenius norm, again not declared as instances: + +* `matrix.frobenius_semi_normed_group` +* `matrix.frobenius_normed_group` +* `matrix.frobenius_normed_space` +* `matrix.frobenius_normed_ring` +* `matrix.frobenius_normed_algebra` -/ noncomputable theory @@ -24,7 +34,7 @@ open_locale nnreal matrix namespace matrix -variables {R m n α β : Type*} [fintype m] [fintype n] +variables {R l m n α β : Type*} [fintype l] [fintype m] [fintype n] section semi_normed_group variables [semi_normed_group α] [semi_normed_group β] @@ -57,7 +67,7 @@ lemma norm_entry_le_entrywise_sup_norm (A : matrix m n α) {i : m} {j : n} : ∥A i j∥ ≤ ∥A∥ := (norm_le_pi_norm (A i) j).trans (norm_le_pi_norm A i) -lemma nnnorm_entry_le_entrywise_sup_nnorm (A : matrix m n α) {i : m} {j : n} : +lemma nnnorm_entry_le_entrywise_sup_nnnorm (A : matrix m n α) {i : m} {j : n} : ∥A i j∥₊ ≤ ∥A∥₊ := (nnnorm_le_pi_nnnorm (A i) j).trans (nnnorm_le_pi_nnnorm A i) @@ -120,4 +130,141 @@ pi.normed_space end normed_space +/-! ### The Frobenius norm on matrices + +This is defined as $\|A\| = \sqrt{\sum_ij \|A_ij\|^2}$. +When the matrix is over the real or complex numbers, this norm is submultiplicative. +-/ + +section frobenius + +open_locale matrix big_operators + +/-- Seminormed group instance (using frobenius norm) for matrices over a seminormed group. Not +declared as an instance because there are several natural choices for defining the norm of a +matrix. -/ +local attribute [instance] +def frobenius_semi_normed_group [semi_normed_group α] : + semi_normed_group (matrix m n α) := +(by apply_instance : semi_normed_group (pi_Lp 2 (λ i : m, pi_Lp 2 (λ j : n, α)))) + +/-- Normed group instance (using frobenius norm) for matrices over a normed group. Not +declared as an instance because there are several natural choices for defining the norm of a +matrix. -/ +local attribute [instance] +def frobenius_normed_group [normed_group α] : + normed_group (matrix m n α) := +(by apply_instance : normed_group (pi_Lp 2 (λ i : m, pi_Lp 2 (λ j : n, α)))) + +/-- Normed space instance (using frobenius norm) for matrices over a normed space. Not +declared as an instance because there are several natural choices for defining the norm of a +matrix. -/ +local attribute [instance] +def frobenius_normed_space [normed_field R] [semi_normed_group α] [normed_space R α] : + normed_space R (matrix m n α) := +(by apply_instance : normed_space R (pi_Lp 2 (λ i : m, pi_Lp 2 (λ j : n, α)))) + +section semi_normed_group +variables [semi_normed_group α] [semi_normed_group β] + +lemma frobenius_nnnorm_def (A : matrix m n α) : + ∥A∥₊ = (∑ i j, ∥A i j∥₊ ^ (2 : ℝ)) ^ (1/2 : ℝ) := +by simp_rw [pi_Lp.nnnorm_eq, ←nnreal.rpow_mul, div_mul_cancel (1 : ℝ) two_ne_zero, nnreal.rpow_one] + +lemma frobenius_norm_def (A : matrix m n α) : + ∥A∥ = (∑ i j, ∥A i j∥ ^ (2 : ℝ)) ^ (1/2 : ℝ) := +(congr_arg coe (frobenius_nnnorm_def A)).trans $ by simp [nnreal.coe_sum] + +@[simp] lemma frobenius_nnnorm_transpose (A : matrix m n α) : ∥Aᵀ∥₊ = ∥A∥₊ := +by { rw [frobenius_nnnorm_def, frobenius_nnnorm_def, finset.sum_comm], refl } +@[simp] lemma frobenius_norm_transpose (A : matrix m n α) : ∥Aᵀ∥ = ∥A∥ := +congr_arg coe $ frobenius_nnnorm_transpose A + +@[simp] lemma frobenius_nnnorm_map_eq (A : matrix m n α) (f : α → β) (hf : ∀ a, ∥f a∥₊ = ∥a∥₊) : + ∥A.map f∥₊ = ∥A∥₊ := +by simp_rw [frobenius_nnnorm_def, matrix.map, hf] +@[simp] lemma frobenius_norm_map_eq (A : matrix m n α) (f : α → β) (hf : ∀ a, ∥f a∥ = ∥a∥) : + ∥A.map f∥ = ∥A∥ := +(congr_arg (coe : ℝ≥0 → ℝ) $ frobenius_nnnorm_map_eq A f $ λ a, subtype.ext $ hf a : _) + +@[simp] lemma frobenius_norm_row (v : m → α) : ∥row v∥ = ∥(pi_Lp.equiv 2 _).symm v∥ := +by { rw [frobenius_norm_def, fintype.sum_unique], refl } +@[simp] lemma frobenius_nnnorm_row (v : m → α) : ∥row v∥₊ = ∥(pi_Lp.equiv 2 _).symm v∥₊ := +subtype.ext $ frobenius_norm_row v + +@[simp] lemma frobenius_norm_col (v : n → α) : ∥col v∥ = ∥(pi_Lp.equiv 2 _).symm v∥ := +by { simp_rw [frobenius_norm_def, fintype.sum_unique], refl } +@[simp] lemma frobenius_nnnorm_col (v : n → α) : ∥col v∥₊ = ∥(pi_Lp.equiv 2 _).symm v∥₊ := +subtype.ext $ frobenius_norm_col v + +@[simp] lemma frobenius_nnnorm_diagonal [decidable_eq n] (v : n → α) : + ∥diagonal v∥₊ = ∥(pi_Lp.equiv 2 _).symm v∥₊ := +begin + simp_rw [frobenius_nnnorm_def, ←finset.sum_product', finset.univ_product_univ, pi_Lp.nnnorm_eq], + let s := (finset.univ : finset n).map ⟨λ i : n, (i, i), λ i j h, congr_arg prod.fst h⟩, + rw ←finset.sum_subset (finset.subset_univ s) (λ i hi his, _), + { rw finset.sum_map, + dsimp, + simp_rw diagonal_apply_eq }, + { suffices : i.1 ≠ i.2, + { rw [diagonal_apply_ne _ this, nnnorm_zero, nnreal.zero_rpow two_ne_zero], }, + intro h, + exact finset.mem_map.not.mp his ⟨i.1, finset.mem_univ _, prod.ext rfl h⟩ } +end +@[simp] lemma frobenius_norm_diagonal [decidable_eq n] (v : n → α) : + ∥diagonal v∥ = ∥(pi_Lp.equiv 2 _).symm v∥ := +(congr_arg coe $ frobenius_nnnorm_diagonal v : _).trans rfl + +end semi_normed_group + +lemma frobenius_nnnorm_one [decidable_eq n] [semi_normed_group α] [has_one α] : + ∥(1 : matrix n n α)∥₊ = nnreal.sqrt (fintype.card n) * ∥(1 : α)∥₊:= +begin + refine (frobenius_nnnorm_diagonal _).trans _, + simp_rw [pi_Lp.nnnorm_equiv_symm_const, nnreal.sqrt_eq_rpow], +end + +section is_R_or_C +variables [is_R_or_C α] + +lemma frobenius_nnnorm_mul (A : matrix l m α) (B : matrix m n α) : ∥A ⬝ B∥₊ ≤ ∥A∥₊ * ∥B∥₊ := +begin + simp_rw [frobenius_nnnorm_def, matrix.mul_apply], + rw [←nnreal.mul_rpow, @finset.sum_comm _ n m, finset.sum_mul_sum, finset.sum_product], + refine nnreal.rpow_le_rpow _ one_half_pos.le, + refine finset.sum_le_sum (λ i hi, finset.sum_le_sum $ λ j hj, _), + rw [← nnreal.rpow_le_rpow_iff one_half_pos, ← nnreal.rpow_mul, + mul_div_cancel' (1 : ℝ) two_ne_zero, nnreal.rpow_one, nnreal.mul_rpow], + dsimp only, + have := @nnnorm_inner_le_nnnorm α _ _ _ + ((pi_Lp.equiv 2 (λ i, α)).symm (λ j, star (A i j))) + ((pi_Lp.equiv 2 (λ i, α)).symm (λ k, B k j)), + simpa only [pi_Lp.equiv_symm_apply, pi_Lp.inner_apply, + is_R_or_C.inner_apply, star_ring_end_apply, pi.nnnorm_def, pi_Lp.nnnorm_eq, + star_star, nnnorm_star] using this, +end + +lemma frobenius_norm_mul (A : matrix l m α) (B : matrix m n α) : ∥A ⬝ B∥ ≤ ∥A∥ * ∥B∥ := +frobenius_nnnorm_mul A B + +/-- Normed ring instance (using frobenius norm) for matrices over `ℝ` or `ℂ`. Not +declared as an instance because there are several natural choices for defining the norm of a +matrix. -/ +local attribute [instance] +def frobenius_normed_ring [decidable_eq m] : normed_ring (matrix m m α) := +{ norm := has_norm.norm, + norm_mul := frobenius_norm_mul, + ..matrix.frobenius_semi_normed_group } + +/-- Normed algebra instance (using frobenius norm) for matrices over `ℝ` or `ℂ`. Not +declared as an instance because there are several natural choices for defining the norm of a +matrix. -/ +local attribute [instance] +def frobenius_normed_algebra [decidable_eq m] [normed_field R] [normed_algebra R α] : + normed_algebra R (matrix m m α) := +{ ..matrix.frobenius_normed_space } + +end is_R_or_C + +end frobenius end matrix From 000cae16bf1ca478259c70a2afa0811d687bc941 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Mon, 2 May 2022 06:04:05 +0000 Subject: [PATCH 361/373] feat(representation_theory): Rep k G is symmetric monoidal (#13685) Co-authored-by: Scott Morrison --- src/representation_theory/Action.lean | 35 +++++++++++++++++++++------ src/representation_theory/Rep.lean | 6 ++--- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/representation_theory/Action.lean b/src/representation_theory/Action.lean index 3d1a64d536d5a..6e39809bb4fff 100644 --- a/src/representation_theory/Action.lean +++ b/src/representation_theory/Action.lean @@ -10,6 +10,7 @@ import category_theory.limits.preserves.basic import category_theory.adjunction.limits import category_theory.monoidal.functor_category import category_theory.monoidal.transport +import category_theory.monoidal.braided import category_theory.abelian.functor_category import category_theory.abelian.transfer @@ -23,7 +24,7 @@ We check `Action V G ≌ (single_obj G ⥤ V)`, and construct the restriction functors `res {G H : Mon} (f : G ⟶ H) : Action V H ⥤ Action V G`. * When `V` has (co)limits so does `Action V G`. -* When `V` is monoidal so is `Action V G`. +* When `V` is monoidal, braided, or symmetric, so is `Action V G`. * When `V` is preadditive or abelian so is `Action V G`. -/ @@ -216,11 +217,11 @@ def forget : Action V G ⥤ V := { obj := λ M, M.V, map := λ M N f, f.hom, } +instance : faithful (forget V G) := +{ map_injective' := λ X Y f g w, hom.ext _ _ w, } + instance [concrete_category V] : concrete_category (Action V G) := -{ forget := forget V G ⋙ (concrete_category.forget V), - forget_faithful := - { map_injective' := λ M N f g w, - hom.ext _ _ (faithful.map_injective (concrete_category.forget V) w), } } +{ forget := forget V G ⋙ (concrete_category.forget V), } instance has_forget_to_V [concrete_category V] : has_forget₂ (Action V G) V := { forget₂ := forget V G } @@ -284,18 +285,36 @@ abelian_of_equivalence abelian_aux.functor end abelian section monoidal +variables [monoidal_category V] -instance [monoidal_category V] : monoidal_category (Action V G) := +instance : monoidal_category (Action V G) := monoidal.transport (Action.functor_category_equivalence _ _).symm +variables (V G) + /-- When `V` is monoidal the forgetful functor `Action V G` to `V` is monoidal. -/ @[simps] -def forget_monoidal [monoidal_category V] : monoidal_functor (Action V G) V := +def forget_monoidal : monoidal_functor (Action V G) V := { ε := 𝟙 _, μ := λ X Y, 𝟙 _, ..Action.forget _ _, } --- TODO braiding and symmetry +instance forget_monoidal_faithful : faithful (forget_monoidal V G).to_functor := +by { change faithful (forget V G), apply_instance, } + +instance [braided_category V] : braided_category (Action V G) := +braided_category_of_faithful (forget_monoidal V G) (λ X Y, mk_iso (β_ _ _) (by tidy)) (by tidy) + +/-- When `V` is braided the forgetful functor `Action V G` to `V` is braided. -/ +@[simps] +def forget_braided [braided_category V] : braided_functor (Action V G) V := +{ ..forget_monoidal _ _, } + +instance forget_braided_faithful [braided_category V] : faithful (forget_braided V G).to_functor := +by { change faithful (forget V G), apply_instance, } + +instance [symmetric_category V] : symmetric_category (Action V G) := +symmetric_category_of_faithful (forget_braided V G) end monoidal diff --git a/src/representation_theory/Rep.lean b/src/representation_theory/Rep.lean index 8bb0c293e5a96..c9c46702f7114 100644 --- a/src/representation_theory/Rep.lean +++ b/src/representation_theory/Rep.lean @@ -18,7 +18,7 @@ Also `V.ρ` gives the homomorphism `G →* (V →ₗ[k] V)`. Conversely, given a homomorphism `ρ : G →* (V →ₗ[k] V)`, you can construct the bundled representation as `Rep.of ρ`. -We verify that `Rep k G` is an abelian monoidal category with all (co)limits. +We verify that `Rep k G` is an abelian symmetric monoidal category with all (co)limits. -/ universes u @@ -62,7 +62,7 @@ end Rep namespace Rep variables {k G : Type u} [comm_ring k] [monoid G] --- Verify that the monoidal structure is available. -example : monoidal_category (Rep k G) := by apply_instance +-- Verify that the symmetric monoidal structure is available. +example : symmetric_category (Rep k G) := by apply_instance end Rep From 5c914907eedd469fc355ad864a10130ad86618cd Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Mon, 2 May 2022 06:04:06 +0000 Subject: [PATCH 362/373] refactor(field_theory/separable): move content about polynomial.expand earlier (#13776) There were some definitions about polynomial.expand buried in the middle of `field_theory.separable` for no good reason. No changes to content, just moves stuff to an earlier file. Co-authored-by: Scott Morrison --- src/data/polynomial/expand.lean | 252 +++++++++++++++++++++++++++++ src/field_theory/finite/basic.lean | 1 - src/field_theory/separable.lean | 225 +------------------------- src/ring_theory/algebraic.lean | 12 +- 4 files changed, 262 insertions(+), 228 deletions(-) create mode 100644 src/data/polynomial/expand.lean diff --git a/src/data/polynomial/expand.lean b/src/data/polynomial/expand.lean new file mode 100644 index 0000000000000..c5d4f12bd692d --- /dev/null +++ b/src/data/polynomial/expand.lean @@ -0,0 +1,252 @@ +/- +Copyright (c) 2020 Kenny Lau. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kenny Lau +-/ +import ring_theory.polynomial.basic +import ring_theory.ideal.local_ring +import tactic.ring_exp + +/-! +# Expand a polynomial by a factor of p, so `∑ aₙ xⁿ` becomes `∑ aₙ xⁿᵖ`. +-/ + +universes u v w +open_locale classical big_operators polynomial +open finset + +namespace polynomial + +section comm_semiring + +variables (R : Type u) [comm_semiring R] {S : Type v} [comm_semiring S] (p q : ℕ) + +/-- Expand the polynomial by a factor of p, so `∑ aₙ xⁿ` becomes `∑ aₙ xⁿᵖ`. -/ +noncomputable def expand : R[X] →ₐ[R] R[X] := +{ commutes' := λ r, eval₂_C _ _, + .. (eval₂_ring_hom C (X ^ p) : R[X] →+* R[X]) } + +lemma coe_expand : (expand R p : R[X] → R[X]) = eval₂ C (X ^ p) := rfl + +variables {R} + +lemma expand_eq_sum {f : R[X]} : + expand R p f = f.sum (λ e a, C a * (X ^ p) ^ e) := +by { dsimp [expand, eval₂], refl, } + +@[simp] lemma expand_C (r : R) : expand R p (C r) = C r := eval₂_C _ _ +@[simp] lemma expand_X : expand R p X = X ^ p := eval₂_X _ _ +@[simp] lemma expand_monomial (r : R) : expand R p (monomial q r) = monomial (q * p) r := +by simp_rw [monomial_eq_smul_X, alg_hom.map_smul, alg_hom.map_pow, expand_X, mul_comm, pow_mul] + +theorem expand_expand (f : R[X]) : expand R p (expand R q f) = expand R (p * q) f := +polynomial.induction_on f (λ r, by simp_rw expand_C) + (λ f g ihf ihg, by simp_rw [alg_hom.map_add, ihf, ihg]) + (λ n r ih, by simp_rw [alg_hom.map_mul, expand_C, alg_hom.map_pow, expand_X, + alg_hom.map_pow, expand_X, pow_mul]) + +theorem expand_mul (f : R[X]) : expand R (p * q) f = expand R p (expand R q f) := +(expand_expand p q f).symm + +@[simp] theorem expand_zero (f : R[X]) : expand R 0 f = C (eval 1 f) := +by simp [expand] + +@[simp] theorem expand_one (f : R[X]) : expand R 1 f = f := +polynomial.induction_on f + (λ r, by rw expand_C) + (λ f g ihf ihg, by rw [alg_hom.map_add, ihf, ihg]) + (λ n r ih, by rw [alg_hom.map_mul, expand_C, alg_hom.map_pow, expand_X, pow_one]) + +theorem expand_pow (f : R[X]) : expand R (p ^ q) f = (expand R p ^[q] f) := +nat.rec_on q (by rw [pow_zero, expand_one, function.iterate_zero, id]) $ λ n ih, +by rw [function.iterate_succ_apply', pow_succ, expand_mul, ih] + +theorem derivative_expand (f : R[X]) : + (expand R p f).derivative = expand R p f.derivative * (p * X ^ (p - 1)) := +by rw [coe_expand, derivative_eval₂_C, derivative_pow, derivative_X, mul_one] + +theorem coeff_expand {p : ℕ} (hp : 0 < p) (f : R[X]) (n : ℕ) : + (expand R p f).coeff n = if p ∣ n then f.coeff (n / p) else 0 := +begin + simp only [expand_eq_sum], + simp_rw [coeff_sum, ← pow_mul, C_mul_X_pow_eq_monomial, coeff_monomial, sum], + split_ifs with h, + { rw [finset.sum_eq_single (n/p), nat.mul_div_cancel' h, if_pos rfl], + { intros b hb1 hb2, rw if_neg, intro hb3, apply hb2, rw [← hb3, nat.mul_div_cancel_left b hp] }, + { intro hn, rw not_mem_support_iff.1 hn, split_ifs; refl } }, + { rw finset.sum_eq_zero, intros k hk, rw if_neg, exact λ hkn, h ⟨k, hkn.symm⟩, }, +end + +@[simp] theorem coeff_expand_mul {p : ℕ} (hp : 0 < p) (f : R[X]) (n : ℕ) : + (expand R p f).coeff (n * p) = f.coeff n := +by rw [coeff_expand hp, if_pos (dvd_mul_left _ _), nat.mul_div_cancel _ hp] + +@[simp] theorem coeff_expand_mul' {p : ℕ} (hp : 0 < p) (f : R[X]) (n : ℕ) : + (expand R p f).coeff (p * n) = f.coeff n := +by rw [mul_comm, coeff_expand_mul hp] + +theorem expand_inj {p : ℕ} (hp : 0 < p) {f g : R[X]} : + expand R p f = expand R p g ↔ f = g := +⟨λ H, ext $ λ n, by rw [← coeff_expand_mul hp, H, coeff_expand_mul hp], congr_arg _⟩ + +theorem expand_eq_zero {p : ℕ} (hp : 0 < p) {f : R[X]} : expand R p f = 0 ↔ f = 0 := +by rw [← (expand R p).map_zero, expand_inj hp, alg_hom.map_zero] + +theorem expand_eq_C {p : ℕ} (hp : 0 < p) {f : R[X]} {r : R} : + expand R p f = C r ↔ f = C r := +by rw [← expand_C, expand_inj hp, expand_C] + +theorem nat_degree_expand (p : ℕ) (f : R[X]) : + (expand R p f).nat_degree = f.nat_degree * p := +begin + cases p.eq_zero_or_pos with hp hp, + { rw [hp, coe_expand, pow_zero, mul_zero, ← C_1, eval₂_hom, nat_degree_C] }, + by_cases hf : f = 0, + { rw [hf, alg_hom.map_zero, nat_degree_zero, zero_mul] }, + have hf1 : expand R p f ≠ 0 := mt (expand_eq_zero hp).1 hf, + rw [← with_bot.coe_eq_coe, ← degree_eq_nat_degree hf1], + refine le_antisymm ((degree_le_iff_coeff_zero _ _).2 $ λ n hn, _) _, + { rw coeff_expand hp, split_ifs with hpn, + { rw coeff_eq_zero_of_nat_degree_lt, contrapose! hn, + rw [with_bot.coe_le_coe, ← nat.div_mul_cancel hpn], exact nat.mul_le_mul_right p hn }, + { refl } }, + { refine le_degree_of_ne_zero _, + rw [coeff_expand_mul hp, ← leading_coeff], exact mt leading_coeff_eq_zero.1 hf } +end + +lemma monic.expand {p : ℕ} {f : R[X]} (hp : 0 < p) (h : f.monic) : (expand R p f).monic := +begin + rw [monic.def, leading_coeff, nat_degree_expand, coeff_expand hp], + simp [hp, h], +end + +theorem map_expand {p : ℕ} {f : R →+* S} {q : R[X]} : + map f (expand R p q) = expand S p (map f q) := +begin + by_cases hp : p = 0, + { simp [hp] }, + ext, + rw [coeff_map, coeff_expand (nat.pos_of_ne_zero hp), coeff_expand (nat.pos_of_ne_zero hp)], + split_ifs; simp, +end + +/-- Expansion is injective. -/ +lemma expand_injective {n : ℕ} (hn : 0 < n) : + function.injective (expand R n) := +λ g g' h, begin + ext, + have h' : (expand R n g).coeff (n * n_1) = (expand R n g').coeff (n * n_1) := + begin + apply polynomial.ext_iff.1, + exact h, + end, + + rw [polynomial.coeff_expand hn g (n * n_1), polynomial.coeff_expand hn g' (n * n_1)] at h', + simp only [if_true, dvd_mul_right] at h', + rw (nat.mul_div_right n_1 hn) at h', + exact h', +end + +@[simp] +lemma expand_eval (p : ℕ) (P : R[X]) (r : R) : eval r (expand R p P) = eval (r ^ p) P := +begin + refine polynomial.induction_on P (λ a, by simp) (λ f g hf hg, _) (λ n a h, by simp), + rw [alg_hom.map_add, eval_add, eval_add, hf, hg] +end + +/-- The opposite of `expand`: sends `∑ aₙ xⁿᵖ` to `∑ aₙ xⁿ`. -/ +noncomputable def contract (p : ℕ) (f : R[X]) : R[X] := +∑ n in range (f.nat_degree + 1), monomial n (f.coeff (n * p)) + +theorem coeff_contract {p : ℕ} (hp : p ≠ 0) (f : R[X]) (n : ℕ) : + (contract p f).coeff n = f.coeff (n * p) := +begin + simp only [contract, coeff_monomial, sum_ite_eq', finset_sum_coeff, mem_range, not_lt, + ite_eq_left_iff], + assume hn, + apply (coeff_eq_zero_of_nat_degree_lt _).symm, + calc f.nat_degree < f.nat_degree + 1 : nat.lt_succ_self _ + ... ≤ n * 1 : by simpa only [mul_one] using hn + ... ≤ n * p : mul_le_mul_of_nonneg_left (show 1 ≤ p, from hp.bot_lt) (zero_le n) +end + +theorem contract_expand {f : R[X]} (hp : p ≠ 0) : contract p (expand R p f) = f := +begin + ext, + simp [coeff_contract hp, coeff_expand hp.bot_lt, nat.mul_div_cancel _ hp.bot_lt] +end + +section char_p + +variable [char_p R p] + +theorem expand_contract [no_zero_divisors R] {f : R[X]} (hf : f.derivative = 0) + (hp : p ≠ 0) : expand R p (contract p f) = f := +begin + ext n, + rw [coeff_expand hp.bot_lt, coeff_contract hp], + split_ifs with h, + { rw nat.div_mul_cancel h }, + { cases n, + { exact absurd (dvd_zero p) h }, + have := coeff_derivative f n, + rw [hf, coeff_zero, zero_eq_mul] at this, + cases this, + { rw this }, + rw [← nat.cast_succ, char_p.cast_eq_zero_iff R p] at this, + exact absurd this h } +end + +variable [hp : fact p.prime] +include hp + +theorem expand_char (f : R[X]) : map (frobenius R p) (expand R p f) = f ^ p := +begin + refine f.induction_on' (λ a b ha hb, _) (λ n a, _), + { rw [alg_hom.map_add, polynomial.map_add, ha, hb, add_pow_char], }, + { rw [expand_monomial, map_monomial, monomial_eq_C_mul_X, monomial_eq_C_mul_X, + mul_pow, ← C.map_pow, frobenius_def], + ring_exp } +end + +theorem map_expand_pow_char (f : R[X]) (n : ℕ) : + map ((frobenius R p) ^ n) (expand R (p ^ n) f) = f ^ (p ^ n) := +begin + induction n, + { simp [ring_hom.one_def] }, + symmetry, + rw [pow_succ', pow_mul, ← n_ih, ← expand_char, pow_succ, ring_hom.mul_def, + ← map_map, mul_comm, expand_mul, ← map_expand] +end + +end char_p + +end comm_semiring + +section is_domain + +variables (R : Type u) [comm_ring R] [is_domain R] + +theorem is_local_ring_hom_expand {p : ℕ} (hp : 0 < p) : + is_local_ring_hom (↑(expand R p) : R[X] →+* R[X]) := +begin + refine ⟨λ f hf1, _⟩, rw ← coe_fn_coe_base at hf1, + have hf2 := eq_C_of_degree_eq_zero (degree_eq_zero_of_is_unit hf1), + rw [coeff_expand hp, if_pos (dvd_zero _), p.zero_div] at hf2, + rw [hf2, is_unit_C] at hf1, rw expand_eq_C hp at hf2, rwa [hf2, is_unit_C] +end + +variable {R} + +theorem of_irreducible_expand {p : ℕ} (hp : p ≠ 0) {f : R[X]} + (hf : irreducible (expand R p f)) : irreducible f := +@@of_irreducible_map _ _ _ (is_local_ring_hom_expand R hp.bot_lt) hf + +theorem of_irreducible_expand_pow {p : ℕ} (hp : p ≠ 0) {f : R[X]} {n : ℕ} : + irreducible (expand R (p ^ n) f) → irreducible f := +nat.rec_on n (λ hf, by rwa [pow_zero, expand_one] at hf) $ λ n ih hf, +ih $ of_irreducible_expand hp $ by { rw pow_succ at hf, rwa [expand_expand] } + +end is_domain + +end polynomial diff --git a/src/field_theory/finite/basic.lean b/src/field_theory/finite/basic.lean index 91822663a88af..d1494e70e2aef 100644 --- a/src/field_theory/finite/basic.lean +++ b/src/field_theory/finite/basic.lean @@ -9,7 +9,6 @@ import data.zmod.algebra import linear_algebra.finite_dimensional import ring_theory.integral_domain import field_theory.separable -import field_theory.splitting_field /-! # Finite fields diff --git a/src/field_theory/separable.lean b/src/field_theory/separable.lean index b48f18be4aebd..a1dd56957cd6b 100644 --- a/src/field_theory/separable.lean +++ b/src/field_theory/separable.lean @@ -8,6 +8,7 @@ import algebra.polynomial.big_operators import algebra.squarefree import field_theory.minpoly import field_theory.splitting_field +import data.polynomial.expand /-! @@ -111,140 +112,7 @@ let ⟨a, b, H⟩ := h in ⟨a.map f, b.map f, by rw [derivative_map, ← polynomial.map_mul, ← polynomial.map_mul, ← polynomial.map_add, H, polynomial.map_one]⟩ -variables (R) (p q : ℕ) - -/-- Expand the polynomial by a factor of p, so `∑ aₙ xⁿ` becomes `∑ aₙ xⁿᵖ`. -/ -noncomputable def expand : R[X] →ₐ[R] R[X] := -{ commutes' := λ r, eval₂_C _ _, - .. (eval₂_ring_hom C (X ^ p) : R[X] →+* R[X]) } - -lemma coe_expand : (expand R p : R[X] → R[X]) = eval₂ C (X ^ p) := rfl - -variables {R} - -lemma expand_eq_sum {f : R[X]} : - expand R p f = f.sum (λ e a, C a * (X ^ p) ^ e) := -by { dsimp [expand, eval₂], refl, } - -@[simp] lemma expand_C (r : R) : expand R p (C r) = C r := eval₂_C _ _ -@[simp] lemma expand_X : expand R p X = X ^ p := eval₂_X _ _ -@[simp] lemma expand_monomial (r : R) : expand R p (monomial q r) = monomial (q * p) r := -by simp_rw [monomial_eq_smul_X, alg_hom.map_smul, alg_hom.map_pow, expand_X, mul_comm, pow_mul] - -theorem expand_expand (f : R[X]) : expand R p (expand R q f) = expand R (p * q) f := -polynomial.induction_on f (λ r, by simp_rw expand_C) - (λ f g ihf ihg, by simp_rw [alg_hom.map_add, ihf, ihg]) - (λ n r ih, by simp_rw [alg_hom.map_mul, expand_C, alg_hom.map_pow, expand_X, - alg_hom.map_pow, expand_X, pow_mul]) - -theorem expand_mul (f : R[X]) : expand R (p * q) f = expand R p (expand R q f) := -(expand_expand p q f).symm - -@[simp] theorem expand_zero (f : R[X]) : expand R 0 f = C (eval 1 f) := -by simp [expand] - -@[simp] theorem expand_one (f : R[X]) : expand R 1 f = f := -polynomial.induction_on f - (λ r, by rw expand_C) - (λ f g ihf ihg, by rw [alg_hom.map_add, ihf, ihg]) - (λ n r ih, by rw [alg_hom.map_mul, expand_C, alg_hom.map_pow, expand_X, pow_one]) - -theorem expand_pow (f : R[X]) : expand R (p ^ q) f = (expand R p ^[q] f) := -nat.rec_on q (by rw [pow_zero, expand_one, function.iterate_zero, id]) $ λ n ih, -by rw [function.iterate_succ_apply', pow_succ, expand_mul, ih] - -theorem derivative_expand (f : R[X]) : - (expand R p f).derivative = expand R p f.derivative * (p * X ^ (p - 1)) := -by rw [coe_expand, derivative_eval₂_C, derivative_pow, derivative_X, mul_one] - -theorem coeff_expand {p : ℕ} (hp : 0 < p) (f : R[X]) (n : ℕ) : - (expand R p f).coeff n = if p ∣ n then f.coeff (n / p) else 0 := -begin - simp only [expand_eq_sum], - simp_rw [coeff_sum, ← pow_mul, C_mul_X_pow_eq_monomial, coeff_monomial, sum], - split_ifs with h, - { rw [finset.sum_eq_single (n/p), nat.mul_div_cancel' h, if_pos rfl], - { intros b hb1 hb2, rw if_neg, intro hb3, apply hb2, rw [← hb3, nat.mul_div_cancel_left b hp] }, - { intro hn, rw not_mem_support_iff.1 hn, split_ifs; refl } }, - { rw finset.sum_eq_zero, intros k hk, rw if_neg, exact λ hkn, h ⟨k, hkn.symm⟩, }, -end - -@[simp] theorem coeff_expand_mul {p : ℕ} (hp : 0 < p) (f : R[X]) (n : ℕ) : - (expand R p f).coeff (n * p) = f.coeff n := -by rw [coeff_expand hp, if_pos (dvd_mul_left _ _), nat.mul_div_cancel _ hp] - -@[simp] theorem coeff_expand_mul' {p : ℕ} (hp : 0 < p) (f : R[X]) (n : ℕ) : - (expand R p f).coeff (p * n) = f.coeff n := -by rw [mul_comm, coeff_expand_mul hp] - -theorem expand_inj {p : ℕ} (hp : 0 < p) {f g : R[X]} : - expand R p f = expand R p g ↔ f = g := -⟨λ H, ext $ λ n, by rw [← coeff_expand_mul hp, H, coeff_expand_mul hp], congr_arg _⟩ - -theorem expand_eq_zero {p : ℕ} (hp : 0 < p) {f : R[X]} : expand R p f = 0 ↔ f = 0 := -by rw [← (expand R p).map_zero, expand_inj hp, alg_hom.map_zero] - -theorem expand_eq_C {p : ℕ} (hp : 0 < p) {f : R[X]} {r : R} : - expand R p f = C r ↔ f = C r := -by rw [← expand_C, expand_inj hp, expand_C] - -theorem nat_degree_expand (p : ℕ) (f : R[X]) : - (expand R p f).nat_degree = f.nat_degree * p := -begin - cases p.eq_zero_or_pos with hp hp, - { rw [hp, coe_expand, pow_zero, mul_zero, ← C_1, eval₂_hom, nat_degree_C] }, - by_cases hf : f = 0, - { rw [hf, alg_hom.map_zero, nat_degree_zero, zero_mul] }, - have hf1 : expand R p f ≠ 0 := mt (expand_eq_zero hp).1 hf, - rw [← with_bot.coe_eq_coe, ← degree_eq_nat_degree hf1], - refine le_antisymm ((degree_le_iff_coeff_zero _ _).2 $ λ n hn, _) _, - { rw coeff_expand hp, split_ifs with hpn, - { rw coeff_eq_zero_of_nat_degree_lt, contrapose! hn, - rw [with_bot.coe_le_coe, ← nat.div_mul_cancel hpn], exact nat.mul_le_mul_right p hn }, - { refl } }, - { refine le_degree_of_ne_zero _, - rw [coeff_expand_mul hp, ← leading_coeff], exact mt leading_coeff_eq_zero.1 hf } -end - -lemma monic.expand {p : ℕ} {f : R[X]} (hp : 0 < p) (h : f.monic) : (expand R p f).monic := -begin - rw [monic.def, leading_coeff, nat_degree_expand, coeff_expand hp], - simp [hp, h], -end - -theorem map_expand {p : ℕ} {f : R →+* S} {q : R[X]} : - map f (expand R p q) = expand S p (map f q) := -begin - by_cases hp : p = 0, - { simp [hp] }, - ext, - rw [coeff_map, coeff_expand (nat.pos_of_ne_zero hp), coeff_expand (nat.pos_of_ne_zero hp)], - split_ifs; simp, -end - -/-- Expansion is injective. -/ -lemma expand_injective {n : ℕ} (hn : 0 < n) : - function.injective (expand R n) := -λ g g' h, begin - ext, - have h' : (expand R n g).coeff (n * n_1) = (expand R n g').coeff (n * n_1) := - begin - apply polynomial.ext_iff.1, - exact h, - end, - - rw [polynomial.coeff_expand hn g (n * n_1), polynomial.coeff_expand hn g' (n * n_1)] at h', - simp only [if_true, dvd_mul_right] at h', - rw (nat.mul_div_right n_1 hn) at h', - exact h', -end - -@[simp] -lemma expand_eval (p : ℕ) (P : R[X]) (r : R) : eval r (expand R p P) = eval (r ^ p) P := -begin - refine polynomial.induction_on P (λ a, by simp) (λ f g hf hg, _) (λ n a h, by simp), - rw [alg_hom.map_add, eval_add, eval_add, hf, hg] -end +variables (p q : ℕ) lemma is_unit_of_self_mul_dvd_separable {p q : R[X]} (hp : p.separable) (hq : q * q ∣ p) : is_unit q := @@ -259,73 +127,6 @@ begin exact is_coprime.of_mul_right_left (is_coprime.of_mul_left_left this) end -/-- The opposite of `expand`: sends `∑ aₙ xⁿᵖ` to `∑ aₙ xⁿ`. -/ -noncomputable def contract (p : ℕ) (f : R[X]) : R[X] := -∑ n in range (f.nat_degree + 1), monomial n (f.coeff (n * p)) - -theorem coeff_contract {p : ℕ} (hp : p ≠ 0) (f : R[X]) (n : ℕ) : - (contract p f).coeff n = f.coeff (n * p) := -begin - simp only [contract, coeff_monomial, sum_ite_eq', finset_sum_coeff, mem_range, not_lt, - ite_eq_left_iff], - assume hn, - apply (coeff_eq_zero_of_nat_degree_lt _).symm, - calc f.nat_degree < f.nat_degree + 1 : nat.lt_succ_self _ - ... ≤ n * 1 : by simpa only [mul_one] using hn - ... ≤ n * p : mul_le_mul_of_nonneg_left (show 1 ≤ p, from hp.bot_lt) (zero_le n) -end - -theorem contract_expand {f : R[X]} (hp : p ≠ 0) : contract p (expand R p f) = f := -begin - ext, - simp [coeff_contract hp, coeff_expand hp.bot_lt, nat.mul_div_cancel _ hp.bot_lt] -end - -section char_p - -variable [char_p R p] - -theorem expand_contract [no_zero_divisors R] {f : R[X]} (hf : f.derivative = 0) - (hp : p ≠ 0) : expand R p (contract p f) = f := -begin - ext n, - rw [coeff_expand hp.bot_lt, coeff_contract hp], - split_ifs with h, - { rw nat.div_mul_cancel h }, - { cases n, - { exact absurd (dvd_zero p) h }, - have := coeff_derivative f n, - rw [hf, coeff_zero, zero_eq_mul] at this, - cases this, - { rw this }, - rw [← nat.cast_succ, char_p.cast_eq_zero_iff R p] at this, - exact absurd this h } -end - -variable [hp : fact p.prime] -include hp - -theorem expand_char (f : R[X]) : map (frobenius R p) (expand R p f) = f ^ p := -begin - refine f.induction_on' (λ a b ha hb, _) (λ n a, _), - { rw [alg_hom.map_add, polynomial.map_add, ha, hb, add_pow_char], }, - { rw [expand_monomial, map_monomial, monomial_eq_C_mul_X, monomial_eq_C_mul_X, - mul_pow, ← C.map_pow, frobenius_def], - ring_exp } -end - -theorem map_expand_pow_char (f : R[X]) (n : ℕ) : - map ((frobenius R p) ^ n) (expand R (p ^ n) f) = f ^ (p ^ n) := -begin - induction n, - { simp [ring_hom.one_def] }, - symmetry, - rw [pow_succ', pow_mul, ← n_ih, ← expand_char, pow_succ, ring_hom.mul_def, - ← map_map, mul_comm, expand_mul, ← map_expand] -end - -end char_p - lemma multiplicity_le_one_of_separable {p q : R[X]} (hq : ¬ is_unit q) (hsep : separable p) : multiplicity q p ≤ 1 := begin @@ -427,27 +228,7 @@ end comm_ring section is_domain -variables (R : Type u) [comm_ring R] [is_domain R] - -theorem is_local_ring_hom_expand {p : ℕ} (hp : 0 < p) : - is_local_ring_hom (↑(expand R p) : R[X] →+* R[X]) := -begin - refine ⟨λ f hf1, _⟩, rw ← coe_fn_coe_base at hf1, - have hf2 := eq_C_of_degree_eq_zero (degree_eq_zero_of_is_unit hf1), - rw [coeff_expand hp, if_pos (dvd_zero _), p.zero_div] at hf2, - rw [hf2, is_unit_C] at hf1, rw expand_eq_C hp at hf2, rwa [hf2, is_unit_C] -end - -variable {R} - -theorem of_irreducible_expand {p : ℕ} (hp : p ≠ 0) {f : R[X]} - (hf : irreducible (expand R p f)) : irreducible f := -@@of_irreducible_map _ _ _ (is_local_ring_hom_expand R hp.bot_lt) hf - -theorem of_irreducible_expand_pow {p : ℕ} (hp : p ≠ 0) {f : R[X]} {n : ℕ} : - irreducible (expand R (p ^ n) f) → irreducible f := -nat.rec_on n (λ hf, by rwa [pow_zero, expand_one] at hf) $ λ n ih hf, -ih $ of_irreducible_expand hp $ by { rw pow_succ at hf, rwa [expand_expand] } +variables {R : Type u} [comm_ring R] [is_domain R] lemma count_roots_le_one {p : R[X]} (hsep : separable p) (x : R) : p.roots.count x ≤ 1 := diff --git a/src/ring_theory/algebraic.lean b/src/ring_theory/algebraic.lean index fb1e19c6d3816..0156da504a91a 100644 --- a/src/ring_theory/algebraic.lean +++ b/src/ring_theory/algebraic.lean @@ -324,12 +324,14 @@ variables [comm_semiring R'] [comm_semiring S'] [comm_semiring T'] [algebra R' S noncomputable def polynomial.algebra_pi : algebra (R'[X]) (S' → T') := { to_fun := λ p z, algebra_map S' T' (aeval z p), - map_one' := funext $ λ z, by simp, - map_mul' := λ f g, funext $ λ z, by simp, - map_zero' := funext $ λ z, by simp, - map_add' := λ f g, funext $ λ z, by simp, + map_one' := funext $ λ z, by simp only [polynomial.aeval_one, pi.one_apply, map_one], + map_mul' := λ f g, funext $ λ z, by simp only [pi.mul_apply, map_mul], + map_zero' := funext $ λ z, by simp only [polynomial.aeval_zero, pi.zero_apply, map_zero], + map_add' := λ f g, funext $ λ z, by simp only [polynomial.aeval_add, pi.add_apply, map_add], commutes' := λ p f, funext $ λ z, mul_comm _ _, - smul_def' := λ p f, funext $ λ z, by simp [algebra.algebra_map_eq_smul_one], + smul_def' := λ p f, funext $ λ z, by + simp only [algebra.algebra_map_eq_smul_one, polynomial_smul_apply', one_mul, + pi.mul_apply, algebra.smul_mul_assoc], ..polynomial.has_scalar_pi' R' S' T' } local attribute [instance] polynomial.algebra_pi From fd4188d7fb31507e570074482b8cda1e71067966 Mon Sep 17 00:00:00 2001 From: tb65536 Date: Mon, 2 May 2022 06:04:07 +0000 Subject: [PATCH 363/373] feat(data/zmod/basic): `zmod 0` is infinite (#13779) This PR adds an instance stating that `zmod 0` is infinite. --- src/data/zmod/basic.lean | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/data/zmod/basic.lean b/src/data/zmod/basic.lean index af66333a4e8ad..9c9153ac28662 100644 --- a/src/data/zmod/basic.lean +++ b/src/data/zmod/basic.lean @@ -81,6 +81,9 @@ instance fintype : Π (n : ℕ) [fact (0 < n)], fintype (zmod n) | 0 h := false.elim $ nat.not_lt_zero 0 h.1 | (n+1) _ := fin.fintype (n+1) +instance infinite : infinite (zmod 0) := +int.infinite + @[simp] lemma card (n : ℕ) [fact (0 < n)] : fintype.card (zmod n) = n := begin casesI n, From 0587eb186a483ce1224481bb5e06b188f669ea19 Mon Sep 17 00:00:00 2001 From: tb65536 Date: Mon, 2 May 2022 06:04:08 +0000 Subject: [PATCH 364/373] feat(data/zmod/basic): Variant of `zmod.val_int_cast` (#13781) This PR adds a variant of `zmod.val_int_cast` avoiding the characteristic assumption. --- src/data/zmod/basic.lean | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/data/zmod/basic.lean b/src/data/zmod/basic.lean index 9c9153ac28662..c083d660d6e79 100644 --- a/src/data/zmod/basic.lean +++ b/src/data/zmod/basic.lean @@ -450,6 +450,13 @@ begin rw [←zmod.int_coe_eq_int_coe_iff', int.cast_coe_nat, zmod.nat_cast_val, zmod.cast_id], end +lemma coe_int_cast {n : ℕ} (a : ℤ) : ↑(a : zmod n) = a % n := +begin + cases n, + { rw [int.coe_nat_zero, int.mod_zero, int.cast_id, int.cast_id] }, + { rw [←val_int_cast, ←int.nat_cast_eq_coe_nat, val, coe_coe] }, +end + @[simp] lemma val_neg_one (n : ℕ) : (-1 : zmod n.succ).val = n := begin rw [val, fin.coe_neg], From 90b1ddba883f18ede7403e95947827fb9e1789d8 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Mon, 2 May 2022 06:04:09 +0000 Subject: [PATCH 365/373] feat(linear_algebra/finite_dimensional): of_injective (#13792) Co-authored-by: Scott Morrison --- src/analysis/normed_space/finite_dimension.lean | 8 +++----- src/linear_algebra/finite_dimensional.lean | 12 +++++++++++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/analysis/normed_space/finite_dimension.lean b/src/analysis/normed_space/finite_dimension.lean index 2214125306c1a..def5128210aae 100644 --- a/src/analysis/normed_space/finite_dimension.lean +++ b/src/analysis/normed_space/finite_dimension.lean @@ -130,11 +130,9 @@ instance {𝕜 E F : Type*} [field 𝕜] [topological_space 𝕜] [topological_space F] [add_comm_group F] [module 𝕜 F] [topological_add_group F] [has_continuous_smul 𝕜 F] [finite_dimensional 𝕜 F] : finite_dimensional 𝕜 (E →L[𝕜] F) := -begin - haveI : is_noetherian 𝕜 (E →ₗ[𝕜] F) := is_noetherian.iff_fg.mpr (by apply_instance), - let I : (E →L[𝕜] F) →ₗ[𝕜] (E →ₗ[𝕜] F) := continuous_linear_map.coe_lm 𝕜, - exact module.finite.of_injective I continuous_linear_map.coe_injective -end +finite_dimensional.of_injective + (continuous_linear_map.coe_lm 𝕜 : (E →L[𝕜] F) →ₗ[𝕜] (E →ₗ[𝕜] F)) + continuous_linear_map.coe_injective section complete_field diff --git a/src/linear_algebra/finite_dimensional.lean b/src/linear_algebra/finite_dimensional.lean index 117ea5baaaa7a..bc69e4e9e9ba5 100644 --- a/src/linear_algebra/finite_dimensional.lean +++ b/src/linear_algebra/finite_dimensional.lean @@ -88,9 +88,19 @@ open is_noetherian section division_ring -variables (K : Type u) (V : Type v) [division_ring K] [add_comm_group V] [module K V] +variables {K : Type u} {V : Type v} [division_ring K] [add_comm_group V] [module K V] {V₂ : Type v'} [add_comm_group V₂] [module K V₂] +/-- If the codomain of an injective linear map is finite dimensional, the domain must be as well. -/ +lemma of_injective (f : V →ₗ[K] V₂) (w : function.injective f) + [finite_dimensional K V₂] : finite_dimensional K V := +have is_noetherian K V₂ := is_noetherian.iff_fg.mpr ‹_›, by exactI module.finite.of_injective f w + +/-- If the domain of a surjective linear map is finite dimensional, the codomain must be as well. -/ +lemma of_surjective (f : V →ₗ[K] V₂) (w : function.surjective f) + [finite_dimensional K V] : finite_dimensional K V₂ := +module.finite.of_surjective f w + variables (K V) instance finite_dimensional_pi {ι} [fintype ι] : finite_dimensional K (ι → K) := From 925c4738dd9df03469a0d065babfdfaea7d7d30e Mon Sep 17 00:00:00 2001 From: Oliver Nash Date: Mon, 2 May 2022 06:04:10 +0000 Subject: [PATCH 366/373] chore(analysis/normed_space/add_torsor): make coefficients explicit in lemmas about eventual dilations (#13796) For an example of why we should do this, see: https://github.com/leanprover-community/sphere-eversion/blob/19c461c9fba484090ff0af6f0c0204c623f63713/src/loops/surrounding.lean#L176 --- src/analysis/normed_space/add_torsor.lean | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/analysis/normed_space/add_torsor.lean b/src/analysis/normed_space/add_torsor.lean index 3d45e713ff013..340c15bbe84f4 100644 --- a/src/analysis/normed_space/add_torsor.lean +++ b/src/analysis/normed_space/add_torsor.lean @@ -123,6 +123,8 @@ lemma antilipschitz_with_line_map {p₁ p₂ : Q} (h : p₁ ≠ p₂) : antilipschitz_with.of_le_mul_dist $ λ c₁ c₂, by rw [dist_line_map_line_map, nnreal.coe_inv, ← dist_nndist, mul_left_comm, inv_mul_cancel (dist_ne_zero.2 h), mul_one] +variables (𝕜) + lemma eventually_homothety_mem_of_mem_interior (x : Q) {s : set Q} {y : Q} (hy : y ∈ interior s) : ∀ᶠ δ in 𝓝 (1 : 𝕜), homothety x δ y ∈ s := begin @@ -144,7 +146,7 @@ begin { simp_rw set.image_subset_iff, exact (filter.eventually_all_finite ht).mpr this, }, intros y hy, - exact eventually_homothety_mem_of_mem_interior x (h hy), + exact eventually_homothety_mem_of_mem_interior 𝕜 x (h hy), end end normed_space From c1f8ac50998e43d01bba1f0e5de2f75651dd1b49 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Mon, 2 May 2022 06:04:11 +0000 Subject: [PATCH 367/373] feat(order/zorn): add Zorn lemma on a preorder (#13803) --- src/order/chain.lean | 4 +++ src/order/zorn.lean | 71 ++++++++++++++++++++++++++++---------------- 2 files changed, 50 insertions(+), 25 deletions(-) diff --git a/src/order/chain.lean b/src/order/chain.lean index df3d51bae1d6e..45a8e7f8e9fc3 100644 --- a/src/order/chain.lean +++ b/src/order/chain.lean @@ -53,6 +53,10 @@ lemma set.subsingleton.is_chain (hs : s.subsingleton) : is_chain r s := hs.pairw lemma is_chain.mono : s ⊆ t → is_chain r t → is_chain r s := set.pairwise.mono +lemma is_chain.mono_rel {r' : α → α → Prop} (h : is_chain r s) + (h_imp : ∀ x y, r x y → r' x y) : is_chain r' s := +h.mono' $ λ x y, or.imp (h_imp x y) (h_imp y x) + /-- This can be used to turn `is_chain (≥)` into `is_chain (≤)` and vice-versa. -/ lemma is_chain.symm (h : is_chain r s) : is_chain (flip r) s := h.mono' $ λ _ _, or.symm diff --git a/src/order/zorn.lean b/src/order/zorn.lean index c500a04929c33..ac7aa1ffe64b5 100644 --- a/src/order/zorn.lean +++ b/src/order/zorn.lean @@ -94,44 +94,65 @@ exists_maximal_of_chains_bounded (h c hc)) (λ a b c, trans) -section partial_order -variables [partial_order α] +section preorder +variables [preorder α] -lemma zorn_partial_order (h : ∀ c : set α, is_chain (≤) c → ∃ ub, ∀ a ∈ c, a ≤ ub) : - ∃ m : α, ∀ a, m ≤ a → a = m := -let ⟨m, hm⟩ := @exists_maximal_of_chains_bounded α (≤) h (λ a b c, le_trans) in -⟨m, λ a ha, le_antisymm (hm a ha) ha⟩ +theorem zorn_preorder (h : ∀ c : set α, is_chain (≤) c → bdd_above c) : + ∃ m : α, ∀ a, m ≤ a → a ≤ m := +exists_maximal_of_chains_bounded h (λ a b c, le_trans) -lemma zorn_nonempty_partial_order [nonempty α] - (h : ∀ c : set α, is_chain (≤) c → c.nonempty → ∃ ub, ∀ a ∈ c, a ≤ ub) : - ∃ (m : α), ∀ a, m ≤ a → a = m := -let ⟨m, hm⟩ := @exists_maximal_of_nonempty_chains_bounded α (≤) _ h (λ a b c, le_trans) in -⟨m, λ a ha, le_antisymm (hm a ha) ha⟩ +theorem zorn_nonempty_preorder [nonempty α] + (h : ∀ (c : set α), is_chain (≤) c → c.nonempty → bdd_above c) : + ∃ (m : α), ∀ a, m ≤ a → a ≤ m := +exists_maximal_of_nonempty_chains_bounded h (λ a b c, le_trans) -lemma zorn_partial_order₀ (s : set α) +theorem zorn_preorder₀ (s : set α) (ih : ∀ c ⊆ s, is_chain (≤) c → ∃ ub ∈ s, ∀ z ∈ c, z ≤ ub) : - ∃ m ∈ s, ∀ z ∈ s, m ≤ z → z = m := -let ⟨⟨m, hms⟩, h⟩ := @zorn_partial_order {m // m ∈ s} _ + ∃ m ∈ s, ∀ z ∈ s, m ≤ z → z ≤ m := +let ⟨⟨m, hms⟩, h⟩ := @zorn_preorder s _ (λ c hc, let ⟨ub, hubs, hub⟩ := ih (subtype.val '' c) (λ _ ⟨⟨x, hx⟩, _, h⟩, h ▸ hx) (by { rintro _ ⟨p, hpc, rfl⟩ _ ⟨q, hqc, rfl⟩ hpq; refine hc hpc hqc (λ t, hpq (subtype.ext_iff.1 t)) }) in ⟨⟨ub, hubs⟩, λ ⟨y, hy⟩ hc, hub _ ⟨_, hc, rfl⟩⟩) -in ⟨m, hms, λ z hzs hmz, congr_arg subtype.val (h ⟨z, hzs⟩ hmz)⟩ +in ⟨m, hms, λ z hzs hmz, h ⟨z, hzs⟩ hmz⟩ + +theorem zorn_nonempty_preorder₀ (s : set α) + (ih : ∀ c ⊆ s, is_chain (≤) c → ∀ y ∈ c, ∃ ub ∈ s, ∀ z ∈ c, z ≤ ub) (x : α) (hxs : x ∈ s) : + ∃ m ∈ s, x ≤ m ∧ ∀ z ∈ s, m ≤ z → z ≤ m := +begin + rcases zorn_preorder₀ {y ∈ s | x ≤ y} (λ c hcs hc, _) with ⟨m, ⟨hms, hxm⟩, hm⟩, + { exact ⟨m, hms, hxm, λ z hzs hmz, hm _ ⟨hzs, (hxm.trans hmz)⟩ hmz⟩ }, + { rcases c.eq_empty_or_nonempty with rfl|⟨y, hy⟩, + { exact ⟨x, ⟨hxs, le_rfl⟩, λ z, false.elim⟩ }, + { rcases ih c (λ z hz, (hcs hz).1) hc y hy with ⟨z, hzs, hz⟩, + exact ⟨z, ⟨hzs, (hcs hy).2.trans $ hz _ hy⟩, hz⟩ } } +end + +end preorder + +section partial_order +variables [partial_order α] + +lemma zorn_partial_order (h : ∀ c : set α, is_chain (≤) c → bdd_above c) : + ∃ m : α, ∀ a, m ≤ a → a = m := +let ⟨m, hm⟩ := zorn_preorder h in ⟨m, λ a ha, le_antisymm (hm a ha) ha⟩ + +theorem zorn_nonempty_partial_order [nonempty α] + (h : ∀ (c : set α), is_chain (≤) c → c.nonempty → bdd_above c) : + ∃ (m : α), ∀ a, m ≤ a → a = m := +let ⟨m, hm⟩ := zorn_nonempty_preorder h in ⟨m, λ a ha, le_antisymm (hm a ha) ha⟩ + +theorem zorn_partial_order₀ (s : set α) + (ih : ∀ c ⊆ s, is_chain (≤) c → ∃ ub ∈ s, ∀ z ∈ c, z ≤ ub) : + ∃ m ∈ s, ∀ z ∈ s, m ≤ z → z = m := +let ⟨m, hms, hm⟩ := zorn_preorder₀ s ih in ⟨m, hms, λ z hzs hmz, (hm z hzs hmz).antisymm hmz⟩ lemma zorn_nonempty_partial_order₀ (s : set α) (ih : ∀ c ⊆ s, is_chain (≤) c → ∀ y ∈ c, ∃ ub ∈ s, ∀ z ∈ c, z ≤ ub) (x : α) (hxs : x ∈ s) : ∃ m ∈ s, x ≤ m ∧ ∀ z ∈ s, m ≤ z → z = m := -let ⟨⟨m, hms, hxm⟩, h⟩ := @zorn_partial_order {m // m ∈ s ∧ x ≤ m} _ - (λ c hc, c.eq_empty_or_nonempty.elim - (λ hce, hce.symm ▸ ⟨⟨x, hxs, le_rfl⟩, λ _, false.elim⟩) - (λ ⟨m, hmc⟩, - let ⟨ub, hubs, hub⟩ := ih (subtype.val '' c) (image_subset_iff.2 $ λ z hzc, z.2.1) - (by rintro _ ⟨p, hpc, rfl⟩ _ ⟨q, hqc, rfl⟩ hpq; - exact hc hpc hqc (ne_of_apply_ne _ hpq)) m.1 (mem_image_of_mem _ hmc) in - ⟨⟨ub, hubs, le_trans m.2.2 $ hub m.1 $ mem_image_of_mem _ hmc⟩, - λ a hac, hub a.1 ⟨a, hac, rfl⟩⟩)) in -⟨m, hms, hxm, λ z hzs hmz, congr_arg subtype.val $ h ⟨z, hzs, le_trans hxm hmz⟩ hmz⟩ +let ⟨m, hms, hxm, hm⟩ := zorn_nonempty_preorder₀ s ih x hxs +in ⟨m, hms, hxm, λ z hzs hmz, (hm z hzs hmz).antisymm hmz⟩ end partial_order From 179b6c02ecc613ebe62a83cf8fd442260b78ddde Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Mon, 2 May 2022 06:04:12 +0000 Subject: [PATCH 368/373] feat(logic/equiv/local_equiv): add inhabited instances (#13804) --- src/logic/equiv/local_equiv.lean | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/logic/equiv/local_equiv.lean b/src/logic/equiv/local_equiv.lean index a2205b1d99d0d..0b4451d015877 100644 --- a/src/logic/equiv/local_equiv.lean +++ b/src/logic/equiv/local_equiv.lean @@ -121,7 +121,6 @@ variables {α : Type*} {β : Type*} {γ : Type*} {δ : Type*} maps `to_fun : α → β` and `inv_fun : β → α` map `source` to `target` and conversely, and are inverse to each other there. The values of `to_fun` outside of `source` and of `inv_fun` outside of `target` are irrelevant. -/ -@[nolint has_inhabited_instance] structure local_equiv (α : Type*) (β : Type*) := (to_fun : α → β) (inv_fun : β → α) @@ -147,6 +146,13 @@ namespace local_equiv variables (e : local_equiv α β) (e' : local_equiv β γ) +instance [inhabited α] [inhabited β] : inhabited (local_equiv α β) := +⟨⟨const α default, const β default, ∅, ∅, maps_to_empty _ _, maps_to_empty _ _, + eq_on_empty _ _, eq_on_empty _ _⟩⟩ + +instance inhabited_of_empty [is_empty α] [is_empty β] : inhabited (local_equiv α β) := +⟨((equiv.equiv_empty α).trans (equiv.equiv_empty β).symm).to_local_equiv⟩ + /-- The inverse of a local equiv -/ protected def symm : local_equiv β α := { to_fun := e.inv_fun, From 34bbec610006e3df231f143b55fb7f30ac10aca7 Mon Sep 17 00:00:00 2001 From: "Yury G. Kudryashov" Date: Mon, 2 May 2022 06:04:13 +0000 Subject: [PATCH 369/373] feat(logic/equiv/local_equiv): add `forall_mem_target`/`exists_mem_target` (#13805) --- src/logic/equiv/local_equiv.lean | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/logic/equiv/local_equiv.lean b/src/logic/equiv/local_equiv.lean index 0b4451d015877..b6bed0f350ce1 100644 --- a/src/logic/equiv/local_equiv.lean +++ b/src/logic/equiv/local_equiv.lean @@ -233,6 +233,12 @@ protected def to_equiv : equiv (e.source) (e.target) := lemma image_source_eq_target : e '' e.source = e.target := e.bij_on.image_eq +lemma forall_mem_target {p : β → Prop} : (∀ y ∈ e.target, p y) ↔ ∀ x ∈ e.source, p (e x) := +by rw [← image_source_eq_target, ball_image_iff] + +lemma exists_mem_target {p : β → Prop} : (∃ y ∈ e.target, p y) ↔ ∃ x ∈ e.source, p (e x) := +by rw [← image_source_eq_target, bex_image_iff] + /-- We say that `t : set β` is an image of `s : set α` under a local equivalence if any of the following equivalent conditions hold: @@ -249,7 +255,7 @@ variables {e} {s : set α} {t : set β} {x : α} {y : β} lemma apply_mem_iff (h : e.is_image s t) (hx : x ∈ e.source) : e x ∈ t ↔ x ∈ s := h hx lemma symm_apply_mem_iff (h : e.is_image s t) : ∀ ⦃y⦄, y ∈ e.target → (e.symm y ∈ s ↔ y ∈ t) := -by { rw [← e.image_source_eq_target, ball_image_iff], intros x hx, rw [e.left_inv hx, h hx] } +e.forall_mem_target.mpr $ λ x hx, by rw [e.left_inv hx, h hx] protected lemma symm (h : e.is_image s t) : e.symm.is_image t s := h.symm_apply_mem_iff From aaa167cd8798aaf0d0d7bb6ffa79f52b6d3497bb Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 2 May 2022 06:04:14 +0000 Subject: [PATCH 370/373] feat(linear_algebra/matrix/adjugate): `adjugate` of a diagonal matrix is diagonal (#13818) This proof is a bit ugly... --- src/data/matrix/basic.lean | 23 +++++++++++++++++++++-- src/linear_algebra/matrix/adjugate.lean | 14 ++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/data/matrix/basic.lean b/src/data/matrix/basic.lean index f7b8a6cb3da67..31f6f6b2cd021 100644 --- a/src/data/matrix/basic.lean +++ b/src/data/matrix/basic.lean @@ -1746,15 +1746,34 @@ begin end @[simp] lemma update_row_eq_self [decidable_eq m] - (A : matrix m n α) {i : m} : + (A : matrix m n α) (i : m) : A.update_row i (A i) = A := function.update_eq_self i A @[simp] lemma update_column_eq_self [decidable_eq n] - (A : matrix m n α) {i : n} : + (A : matrix m n α) (i : n) : A.update_column i (λ j, A j i) = A := funext $ λ j, function.update_eq_self i (A j) +lemma diagonal_update_column_single [decidable_eq n] [has_zero α] (v : n → α) (i : n) (x : α): + (diagonal v).update_column i (pi.single i x) = diagonal (function.update v i x) := +begin + ext j k, + obtain rfl | hjk := eq_or_ne j k, + { rw [diagonal_apply_eq], + obtain rfl | hji := eq_or_ne j i, + { rw [update_column_self, pi.single_eq_same, function.update_same], }, + { rw [update_column_ne hji, diagonal_apply_eq, function.update_noteq hji], } }, + { rw [diagonal_apply_ne _ hjk], + obtain rfl | hki := eq_or_ne k i, + { rw [update_column_self, pi.single_eq_of_ne hjk] }, + { rw [update_column_ne hki, diagonal_apply_ne _ hjk] } } +end + +lemma diagonal_update_row_single [decidable_eq n] [has_zero α] (v : n → α) (i : n) (x : α): + (diagonal v).update_row i (pi.single i x) = diagonal (function.update v i x) := +by rw [←diagonal_transpose, update_row_transpose, diagonal_update_column_single, diagonal_transpose] + end update end matrix diff --git a/src/linear_algebra/matrix/adjugate.lean b/src/linear_algebra/matrix/adjugate.lean index 3f6249b753d48..bb95ae9e35f13 100644 --- a/src/linear_algebra/matrix/adjugate.lean +++ b/src/linear_algebra/matrix/adjugate.lean @@ -281,6 +281,20 @@ end @[simp] lemma adjugate_one : adjugate (1 : matrix n n α) = 1 := by { ext, simp [adjugate_def, matrix.one_apply, pi.single_apply, eq_comm] } +@[simp] lemma adjugate_diagonal (v : n → α) : + adjugate (diagonal v) = diagonal (λ i, ∏ j in finset.univ.erase i, v j) := +begin + ext, + simp only [adjugate_def, cramer_apply, diagonal_transpose], + obtain rfl | hij := eq_or_ne i j, + { rw [diagonal_apply_eq, diagonal_update_column_single, det_diagonal, + prod_update_of_mem (finset.mem_univ _), sdiff_singleton_eq_erase, one_mul] }, + { rw diagonal_apply_ne _ hij, + refine det_eq_zero_of_row_eq_zero j (λ k, _), + obtain rfl | hjk := eq_or_ne k j, + { rw [update_column_self, pi.single_eq_of_ne' hij] }, + { rw [update_column_ne hjk, diagonal_apply_ne' _ hjk]} }, +end lemma _root_.ring_hom.map_adjugate {R S : Type*} [comm_ring R] [comm_ring S] (f : R →+* S) (M : matrix n n R) : f.map_matrix M.adjugate = matrix.adjugate (f.map_matrix M) := From 03ed4c7858757aee7b2651ac27380ac87bcd4855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Dillies?= Date: Mon, 2 May 2022 06:04:15 +0000 Subject: [PATCH 371/373] =?UTF-8?q?move(topology/algebra/floor=5Fring=20?= =?UTF-8?q?=E2=86=92=20order/floor):=20Move=20topological=20properties=20o?= =?UTF-8?q?f=20`=E2=8C=8Ax=E2=8C=8B`=20and=20`=E2=8C=88x=E2=8C=89`=20(#138?= =?UTF-8?q?24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Those belong in an order folder. --- src/measure_theory/integral/periodic.lean | 2 +- src/topology/algebra/{floor_ring.lean => order/floor.lean} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/topology/algebra/{floor_ring.lean => order/floor.lean} (100%) diff --git a/src/measure_theory/integral/periodic.lean b/src/measure_theory/integral/periodic.lean index e757bb8f775d6..48f6c027dede1 100644 --- a/src/measure_theory/integral/periodic.lean +++ b/src/measure_theory/integral/periodic.lean @@ -5,7 +5,7 @@ Authors: Yury Kudryashov -/ import measure_theory.group.fundamental_domain import measure_theory.integral.interval_integral -import topology.algebra.floor_ring +import topology.algebra.order.floor /-! # Integrals of periodic functions diff --git a/src/topology/algebra/floor_ring.lean b/src/topology/algebra/order/floor.lean similarity index 100% rename from src/topology/algebra/floor_ring.lean rename to src/topology/algebra/order/floor.lean From 67c0e13754a9cf0758833739296d5de67bd472c2 Mon Sep 17 00:00:00 2001 From: tb65536 Date: Mon, 2 May 2022 06:04:16 +0000 Subject: [PATCH 372/373] doc(data/polynomial/basic): Remove references to `polynomial.norm2` (#13847) `polynomial.norm2` was never added to mathlib. --- src/data/polynomial/mirror.lean | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/data/polynomial/mirror.lean b/src/data/polynomial/mirror.lean index 8025b5c6c92a8..80ef0a75e5483 100644 --- a/src/data/polynomial/mirror.lean +++ b/src/data/polynomial/mirror.lean @@ -11,19 +11,16 @@ import data.polynomial.ring_division In this file we define `polynomial.mirror`, a variant of `polynomial.reverse`. The difference between `reverse` and `mirror` is that `reverse` will decrease the degree if the polynomial is -divisible by `X`. We also define `polynomial.norm2`, which is the sum of the squares of the -coefficients of a polynomial. It is also a coefficient of `p * p.mirror`. +divisible by `X`. ## Main definitions - `polynomial.mirror` -- `polynomial.norm2` ## Main results - `polynomial.mirror_mul_of_domain`: `mirror` preserves multiplication. - `polynomial.irreducible_of_mirror`: an irreducibility criterion involving `mirror` -- `polynomial.norm2_eq_mul_reverse_coeff`: `norm2` is a coefficient of `p * p.mirror` -/ From db0b495b3bdbea3e0fae1643c9d5b5eeefb30c60 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Mon, 2 May 2022 06:04:17 +0000 Subject: [PATCH 373/373] chore(category_theory/limits/cones): avoid a timeout from @[simps] (#13877) This was causing a timeout on another branch. Co-authored-by: Scott Morrison --- src/category_theory/limits/cones.lean | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/category_theory/limits/cones.lean b/src/category_theory/limits/cones.lean index ed0999cb388bf..f1ab170bc7ca7 100644 --- a/src/category_theory/limits/cones.lean +++ b/src/category_theory/limits/cones.lean @@ -670,7 +670,6 @@ The category of cocones on `F` is equivalent to the opposite category of the category of cones on the opposite of `F`. -/ -@[simps] def cocone_equivalence_op_cone_op : cocone F ≌ (cone F.op)ᵒᵖ := { functor := { obj := λ c, op (cocone.op c), @@ -689,6 +688,8 @@ def cocone_equivalence_op_cone_op : cocone F ≌ (cone F.op)ᵒᵖ := (λ X Y f, quiver.hom.unop_inj (cone_morphism.ext _ _ (by { dsimp, simp }))), functor_unit_iso_comp' := λ c, begin apply quiver.hom.unop_inj, ext, dsimp, simp, end } +attribute [simps] cocone_equivalence_op_cone_op + end section